}
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;
}
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 1;
}
-int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_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 = netlink_call_async(link->manager->rtnl, NULL, 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;
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;
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->invert_rule = r;
+
+ n = NULL;
+
+ return 0;
+}
+
static int routing_policy_rule_read_full_file(const char *state_file, char **ret) {
_cleanup_free_ char *s = NULL;
size_t size;
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, NULL);
- 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. */
+
+ /* Existing links do not have the saved rule. Let's drop the rule now, and re-configure it
+ * later when it is requested. */
- link->routing_policy_rule_remove_messages++;
+ 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);
}
}