}
if (rule->manager) {
- set_remove(rule->manager->rules, rule);
- set_remove(rule->manager->rules_foreign, rule);
+ if (set_get(rule->manager->rules, rule) == rule)
+ set_remove(rule->manager->rules, rule);
+ if (set_get(rule->manager->rules_foreign, rule) == rule)
+ set_remove(rule->manager->rules_foreign, rule);
}
network_config_section_free(rule->section);
free(rule);
}
-static void routing_policy_rule_hash_func(const void *b, struct siphash *state) {
- const RoutingPolicyRule *rule = b;
-
+static void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash *state) {
assert(rule);
siphash24_compress(&rule->family, sizeof(rule->family), state);
}
}
-static int routing_policy_rule_compare_func(const void *_a, const void *_b) {
- const RoutingPolicyRule *a = _a, *b = _b;
+static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const RoutingPolicyRule *b) {
int r;
r = CMP(a->family, b->family);
}
}
-const struct hash_ops routing_policy_rule_hash_ops = {
- .hash = routing_policy_rule_hash_func,
- .compare = routing_policy_rule_compare_func
-};
+DEFINE_PRIVATE_HASH_OPS(routing_policy_rule_hash_ops, RoutingPolicyRule, routing_policy_rule_hash_func, routing_policy_rule_compare_func);
int routing_policy_rule_get(Manager *m,
int family,
rule->tos = tos;
rule->fwmark = fwmark;
rule->table = table;
- rule->iif = iif;
- rule->oif = oif;
+ rule->iif = TAKE_PTR(iif);
+ rule->oif = TAKE_PTR(oif);
rule->protocol = protocol;
rule->sport = *sport;
rule->dport = *dport;
if (ret)
*ret = rule;
- rule = NULL;
- iif = oif = NULL;
-
+ TAKE_PTR(rule);
return 0;
}
return routing_policy_rule_add_internal(m, &m->rules_foreign, family, from, from_prefixlen, to, to_prefixlen, tos, fwmark, table, iif, oif, protocol, sport, dport, ret);
}
-static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
- Link *link = userdata;
+static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(m);
return 1;
}
-int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, sd_netlink_message_handler_t callback) {
+int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, link_netlink_message_handler_t callback) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
if (r < 0)
return log_error_errno(r, "Could not allocate RTM_DELRULE message: %m");
- if (!in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->from)) {
- if (routing_policy_rule->family == AF_INET)
- r = sd_netlink_message_append_in_addr(m, FRA_SRC, &routing_policy_rule->from.in);
- else
- r = sd_netlink_message_append_in6_addr(m, FRA_SRC, &routing_policy_rule->from.in6);
-
+ if (in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->from) == 0) {
+ r = netlink_message_append_in_addr_union(m, FRA_SRC, routing_policy_rule->family, &routing_policy_rule->from);
if (r < 0)
return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
return log_error_errno(r, "Could not set source prefix length: %m");
}
- if (!in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->to)) {
- if (routing_policy_rule->family == AF_INET)
- r = sd_netlink_message_append_in_addr(m, FRA_DST, &routing_policy_rule->to.in);
- else
- r = sd_netlink_message_append_in6_addr(m, FRA_DST, &routing_policy_rule->to.in6);
-
+ if (in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->to) == 0) {
+ r = netlink_message_append_in_addr_union(m, FRA_DST, routing_policy_rule->family, &routing_policy_rule->to);
if (r < 0)
return log_error_errno(r, "Could not append FRA_DST attribute: %m");
return log_error_errno(r, "Could not set destination prefix length: %m");
}
- r = sd_netlink_call_async(link->manager->rtnl, NULL, m, callback,
- link_netlink_destroy_callback, link, 0, __func__);
+ r = netlink_call_async(link->manager->rtnl, NULL, m,
+ callback ?: routing_policy_rule_remove_handler,
+ link_netlink_destroy_callback, link);
if (r < 0)
return log_error_errno(r, "Could not send rtnetlink message: %m");
return 0;
}
-int link_routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
- Link *link = userdata;
+static int routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(rtnl);
return 1;
}
-int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, sd_netlink_message_handler_t callback, bool update) {
+int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netlink_message_handler_t callback) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
assert(link->manager);
assert(link->manager->rtnl);
+ if (rule->family == AF_INET6 && manager_sysctl_ipv6_enabled(link->manager) == 0) {
+ log_link_warning(link, "An IPv6 routing policy rule is requested, but IPv6 is disabled by sysctl, ignoring.");
+ return 0;
+ }
+
r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family);
if (r < 0)
return log_error_errno(r, "Could not allocate RTM_NEWRULE message: %m");
- if (!in_addr_is_null(rule->family, &rule->from)) {
- if (rule->family == AF_INET)
- r = sd_netlink_message_append_in_addr(m, FRA_SRC, &rule->from.in);
- else
- r = sd_netlink_message_append_in6_addr(m, FRA_SRC, &rule->from.in6);
-
+ if (in_addr_is_null(rule->family, &rule->from) == 0) {
+ r = netlink_message_append_in_addr_union(m, FRA_SRC, rule->family, &rule->from);
if (r < 0)
return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
return log_error_errno(r, "Could not set source prefix length: %m");
}
- if (!in_addr_is_null(rule->family, &rule->to)) {
- if (rule->family == AF_INET)
- r = sd_netlink_message_append_in_addr(m, FRA_DST, &rule->to.in);
- else
- r = sd_netlink_message_append_in6_addr(m, FRA_DST, &rule->to.in6);
-
+ if (in_addr_is_null(rule->family, &rule->to) == 0) {
+ r = netlink_message_append_in_addr_union(m, FRA_DST, rule->family, &rule->to);
if (r < 0)
return log_error_errno(r, "Could not append FRA_DST attribute: %m");
return log_error_errno(r, "Could not append FRA_DPORT_RANGE attribute: %m");
}
+ if (rule->invert_rule) {
+ r = sd_rtnl_message_routing_policy_rule_set_flags(m, FIB_RULE_INVERT);
+ if (r < 0)
+ return log_error_errno(r, "Could not append FIB_RULE_INVERT attribute: %m");
+ }
+
rule->link = link;
- r = sd_netlink_call_async(link->manager->rtnl, NULL, m, callback,
- link_netlink_destroy_callback, link, 0, __func__);
+ r = netlink_call_async(link->manager->rtnl, NULL, m,
+ callback ?: routing_policy_rule_handler,
+ link_netlink_destroy_callback, link);
if (r < 0)
return log_error_errno(r, "Could not send rtnetlink message: %m");
if (r < 0)
return log_error_errno(r, "Could not add rule: %m");
- return 0;
+ return 1;
}
static int parse_fwmark_fwmask(const char *s, uint32_t *fwmark, uint32_t *fwmask) {
void *data,
void *userdata) {
- _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
+ _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
Network *network = userdata;
int r;
void *data,
void *userdata) {
- _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
+ _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
Network *network = userdata;
int r;
void *data,
void *userdata) {
- _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
+ _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
Network *network = userdata;
int r;
void *data,
void *userdata) {
- _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
+ _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
Network *network = userdata;
int r;
void *data,
void *userdata) {
- _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
+ _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
Network *network = userdata;
- union in_addr_union buffer;
- uint8_t prefixlen;
+ union in_addr_union *buffer;
+ uint8_t *prefixlen;
int r;
assert(filename);
if (r < 0)
return r;
- r = in_addr_prefix_from_string(rvalue, AF_INET, &buffer, &prefixlen);
- if (r < 0) {
- r = in_addr_prefix_from_string(rvalue, AF_INET6, &buffer, &prefixlen);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "RPDB rule prefix is invalid, ignoring assignment: %s", rvalue);
- return 0;
- }
-
- n->family = AF_INET6;
- } else
- n->family = AF_INET;
-
if (streq(lvalue, "To")) {
- n->to = buffer;
- n->to_prefixlen = prefixlen;
+ buffer = &n->to;
+ prefixlen = &n->to_prefixlen;
} else {
- n->from = buffer;
- n->from_prefixlen = prefixlen;
+ buffer = &n->from;
+ prefixlen = &n->from_prefixlen;
+ }
+
+ r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "RPDB rule prefix is invalid, ignoring assignment: %s", rvalue);
+ return 0;
}
n = NULL;
void *data,
void *userdata) {
- _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
+ _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
Network *network = userdata;
int r;
const char *rvalue,
void *data,
void *userdata) {
- _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
+ _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
Network *network = userdata;
uint16_t low, high;
int r;
void *data,
void *userdata) {
- _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
+ _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
Network *network = userdata;
int r;
if (r < 0)
return r;
- r = ip_protocol_from_name(rvalue);
+ r = parse_ip_protocol(rvalue);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse routing policy rule protocol, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IP protocol '%s' for routing policy rule, ignoring: %m", rvalue);
return 0;
}
- if (!IN_SET(r, IPPROTO_TCP, IPPROTO_UDP, IPPROTO_SCTP)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid protocol '%s'. Protocol should be tcp/udp/sctp, ignoring", rvalue);
+ n->protocol = r;
+
+ n = NULL;
+
+ return 0;
+}
+
+int config_parse_routing_policy_rule_invert(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
+ Network *network = userdata;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = routing_policy_rule_new_static(network, filename, section_line, &n);
+ if (r < 0)
+ return r;
+
+ r = parse_boolean(rvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule invert, ignoring: %s", rvalue);
return 0;
}
- n->protocol = r;
+ n->invert_rule = r;
n = NULL;
for (;;) {
_cleanup_free_ char *word = NULL, *a = NULL, *b = NULL;
- union in_addr_union buffer;
- uint8_t prefixlen;
r = extract_first_word(&p, &word, NULL, 0);
if (r < 0)
continue;
if (STR_IN_SET(a, "from", "to")) {
-
- r = in_addr_prefix_from_string(b, AF_INET, &buffer, &prefixlen);
- if (r < 0) {
- r = in_addr_prefix_from_string(b, AF_INET6, &buffer, &prefixlen);
- if (r < 0) {
- log_error_errno(r, "RPDB rule prefix is invalid, ignoring assignment: %s", b);
- continue;
- }
-
- rule->family = AF_INET6;
- } else
- rule->family = AF_INET;
+ union in_addr_union *buffer;
+ uint8_t *prefixlen;
if (streq(a, "to")) {
- rule->to = buffer;
- rule->to_prefixlen = prefixlen;
+ buffer = &rule->to;
+ prefixlen = &rule->to_prefixlen;
} else {
- rule->from = buffer;
- rule->from_prefixlen = prefixlen;
+ buffer = &rule->from;
+ prefixlen = &rule->from_prefixlen;
}
+
+ r = in_addr_prefix_from_string_auto(b, &rule->family, buffer, prefixlen);
+ if (r < 0) {
+ log_error_errno(r, "RPDB rule prefix is invalid, ignoring assignment: %s", b);
+ continue;
+ }
+
} else if (streq(a, "tos")) {
r = safe_atou8(b, &rule->tos);
if (r < 0) {
return 0;
}
+static bool manager_links_have_routing_policy_rule(Manager *m, RoutingPolicyRule *rule) {
+ RoutingPolicyRule *link_rule;
+ Iterator i;
+ Link *link;
+
+ assert(m);
+ assert(rule);
+
+ HASHMAP_FOREACH(link, m->links, i) {
+ if (!link->network)
+ continue;
+
+ LIST_FOREACH(rules, link_rule, link->network->rules)
+ if (routing_policy_rule_compare_func(link_rule, rule) == 0)
+ return true;
+ }
+
+ return false;
+}
+
void routing_policy_rule_purge(Manager *m, Link *link) {
RoutingPolicyRule *rule, *existing;
Iterator i;
SET_FOREACH(rule, m->rules_saved, i) {
existing = set_get(m->rules_foreign, rule);
- if (existing) {
+ if (!existing)
+ continue; /* Saved rule does not exist anymore. */
- r = routing_policy_rule_remove(rule, link, routing_policy_rule_remove_handler);
- if (r < 0) {
- log_warning_errno(r, "Could not remove routing policy rules: %m");
- continue;
- }
+ if (manager_links_have_routing_policy_rule(m, existing))
+ continue; /* Existing links have the saved rule. */
- link->routing_policy_rule_remove_messages++;
+ /* Existing links do not have the saved rule. Let's drop the rule now, and re-configure it
+ * later when it is requested. */
+
+ r = routing_policy_rule_remove(existing, link, NULL);
+ if (r < 0) {
+ log_warning_errno(r, "Could not remove routing policy rules: %m");
+ continue;
}
+
+ link->routing_policy_rule_remove_messages++;
+
+ assert_se(set_remove(m->rules_foreign, existing) == existing);
+ routing_policy_rule_free(existing);
}
}