]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: use NetworkConfigSource/State to manage routing policy rules
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 31 Aug 2021 08:24:07 +0000 (17:24 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 15 Sep 2021 07:50:23 +0000 (16:50 +0900)
This also changes the logic when Priority= is not specified.
Previously, we request without FRA_PRIORITY attribute and kernel picks
the highest unused priority for the rule.
This makes networkd picks the highest unused priority and always request
FRA_PRIORITY attribute.

src/network/networkd-manager.c
src/network/networkd-manager.h
src/network/networkd-routing-policy-rule.c
src/network/networkd-routing-policy-rule.h

index e7aa804f096581e43308d574c740dc939c1b4c43..d70f5c72196f685cf66c95c2eef6fe28379b8603 100644 (file)
@@ -473,10 +473,7 @@ Manager* manager_free(Manager *m) {
         hashmap_free(m->route_table_names_by_number);
         hashmap_free(m->route_table_numbers_by_name);
 
-        /* routing_policy_rule_free() access m->rules and m->rules_foreign.
-         * So, it is necessary to set NULL after the sets are freed. */
-        m->rules = set_free(m->rules);
-        m->rules_foreign = set_free(m->rules_foreign);
+        set_free(m->rules);
 
         sd_netlink_unref(m->rtnl);
         sd_netlink_unref(m->genl);
index 4e789045380d5fb1e6dcfc7a28b4db628438c2de..0147df17cdc48d988930bf5c299cfc112d84db35 100644 (file)
@@ -64,9 +64,7 @@ struct Manager {
         char* dynamic_hostname;
         char* dynamic_timezone;
 
-        unsigned routing_policy_rule_remove_messages;
         Set *rules;
-        Set *rules_foreign;
 
         /* Manage nexthops by id. */
         Hashmap *nexthops_by_id;
index e388881e0e43a7257173c85f1189925d2d58df3a..e3b57814f50cc66cf63eef0740ee6faa5ffb6d71 100644 (file)
@@ -41,10 +41,8 @@ RoutingPolicyRule *routing_policy_rule_free(RoutingPolicyRule *rule) {
                 hashmap_remove(rule->network->rules_by_section, rule->section);
         }
 
-        if (rule->manager) {
+        if (rule->manager)
                 set_remove(rule->manager->rules, rule);
-                set_remove(rule->manager->rules_foreign, rule);
-        }
 
         network_config_section_free(rule->section);
         free(rule->iif);
@@ -101,6 +99,7 @@ static int routing_policy_rule_new_static(Network *network, const char *filename
 
         rule->network = network;
         rule->section = TAKE_PTR(n);
+        rule->source = NETWORK_CONFIG_SOURCE_STATIC;
         rule->protocol = RTPROT_STATIC;
 
         r = hashmap_ensure_put(&network->rules_by_section, &network_config_hash_ops, rule->section, rule);
@@ -163,9 +162,7 @@ void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash
                 siphash24_compress(&rule->type, sizeof(rule->type), state);
                 siphash24_compress(&rule->fwmark, sizeof(rule->fwmark), state);
                 siphash24_compress(&rule->fwmask, sizeof(rule->fwmask), state);
-                siphash24_compress_boolean(rule->priority_set, state);
-                if (rule->priority_set)
-                        siphash24_compress(&rule->priority, sizeof(rule->priority), state);
+                siphash24_compress(&rule->priority, sizeof(rule->priority), state);
                 siphash24_compress(&rule->table, sizeof(rule->table), state);
                 siphash24_compress(&rule->suppress_prefixlen, sizeof(rule->suppress_prefixlen), state);
 
@@ -231,16 +228,10 @@ int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const RoutingPo
                 if (r != 0)
                         return r;
 
-                r = CMP(a->priority_set, b->priority_set);
+                r = CMP(a->priority, b->priority);
                 if (r != 0)
                         return r;
 
-                if (a->priority_set) {
-                        r = CMP(a->priority, b->priority);
-                        if (r != 0)
-                                return r;
-                }
-
                 r = CMP(a->table, b->table);
                 if (r != 0)
                         return r;
@@ -301,130 +292,113 @@ DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
                 routing_policy_rule_compare_func,
                 routing_policy_rule_free);
 
-static int routing_policy_rule_get(Manager *m, const RoutingPolicyRule *rule, bool require_priority, RoutingPolicyRule **ret) {
-        RoutingPolicyRule *existing;
-        int r;
+static int routing_policy_rule_get(Manager *m, const RoutingPolicyRule *in, RoutingPolicyRule **ret) {
+        RoutingPolicyRule *rule;
 
         assert(m);
+        assert(in);
 
-        existing = set_get(m->rules, rule);
-        if (existing) {
-                if (ret)
-                        *ret = existing;
-                return 1;
-        }
-
-        existing = set_get(m->rules_foreign, rule);
-        if (existing) {
+        rule = set_get(m->rules, in);
+        if (rule) {
                 if (ret)
-                        *ret = existing;
+                        *ret = rule;
                 return 0;
         }
 
-        if (!require_priority && rule->priority_set) {
-                _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
+        if (in->priority_set)
+                return -ENOENT;
 
-                r = routing_policy_rule_dup(rule, &tmp);
-                if (r < 0)
-                        return r;
+        /* Also find rules configured without priority. */
+        SET_FOREACH(rule, m->rules) {
+                uint32_t priority;
+                bool found;
 
-                tmp->priority_set = false;
+                if (rule->priority_set)
+                        /* The rule is configured with priority. */
+                        continue;
 
-                existing = set_get(m->rules, tmp);
-                if (existing) {
+                priority = rule->priority;
+                rule->priority = 0;
+                found = routing_policy_rule_equal(rule, in);
+                rule->priority = priority;
+
+                if (found) {
                         if (ret)
-                                *ret = existing;
-                        return 1;
+                                *ret = rule;
+                        return 0;
                 }
         }
 
         return -ENOENT;
 }
 
-static int routing_policy_rule_add(Manager *m, const RoutingPolicyRule *in, RoutingPolicyRule **ret) {
-        _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
-        RoutingPolicyRule *existing;
-        int r;
-
-        assert(m);
-        assert(in);
-        assert(IN_SET(in->family, AF_INET, AF_INET6));
-
-        r = routing_policy_rule_dup(in, &rule);
-        if (r < 0)
-                return r;
-
-        r = routing_policy_rule_get(m, rule, true, &existing);
-        if (r == -ENOENT) {
-                /* Rule does not exist, use a new one. */
-                r = set_ensure_put(&m->rules, &routing_policy_rule_hash_ops, rule);
-                if (r < 0)
-                        return r;
-                assert(r > 0);
-
-                rule->manager = m;
-                existing = TAKE_PTR(rule);
-        } else if (r < 0)
-                return r;
-        else if (r == 0) {
-                /* Take over a foreign rule. */
-                r = set_ensure_put(&m->rules, &routing_policy_rule_hash_ops, existing);
-                if (r < 0)
-                        return r;
-                assert(r > 0);
-
-                set_remove(m->rules_foreign, existing);
-        } /* else r > 0: already exists, do nothing. */
-
-        if (ret)
-                *ret = existing;
-        return 0;
-}
-
-static int routing_policy_rule_consume_foreign(Manager *m, RoutingPolicyRule *rule) {
+static int routing_policy_rule_add(Manager *m, RoutingPolicyRule *rule) {
         int r;
 
         assert(m);
         assert(rule);
         assert(IN_SET(rule->family, AF_INET, AF_INET6));
 
-        r = set_ensure_consume(&m->rules_foreign, &routing_policy_rule_hash_ops, rule);
-        if (r <= 0)
+        r = set_ensure_put(&m->rules, &routing_policy_rule_hash_ops, rule);
+        if (r < 0)
                 return r;
+        if (r == 0)
+                return -EEXIST;
 
         rule->manager = m;
-
-        return 1;
+        return 0;
 }
 
-static int routing_policy_rule_update_priority(RoutingPolicyRule *rule, uint32_t priority) {
+static int routing_policy_rule_acquire_priority(Manager *manager, RoutingPolicyRule *rule) {
+        _cleanup_set_free_ Set *priorities = NULL;
+        RoutingPolicyRule *tmp;
+        uint32_t priority;
+        Network *network;
         int r;
 
+        assert(manager);
         assert(rule);
-        assert(rule->manager);
+        assert(IN_SET(rule->family, AF_INET, AF_INET6));
 
         if (rule->priority_set)
                 return 0;
 
-        if (!set_remove(rule->manager->rules, rule))
-                return -ENOENT;
+        /* Find the highest unused priority. Note that 32766 is already used by kernel.
+         * See kernel_rules[] below. */
 
-        rule->priority = priority;
-        rule->priority_set = true;
-
-        r = set_put(rule->manager->rules, rule);
-        if (r <= 0) {
-                /* Undo */
-                rule->priority_set = false;
-                assert_se(set_put(rule->manager->rules, rule) > 0);
-                return r == 0 ? -EEXIST : r;
+        SET_FOREACH(tmp, manager->rules) {
+                if (tmp->family != rule->family)
+                        continue;
+                if (tmp->priority == 0 || tmp->priority > 32765)
+                        continue;
+                r = set_ensure_put(&priorities, NULL, UINT32_TO_PTR(tmp->priority));
+                if (r < 0)
+                        return r;
         }
 
-        return 1;
+        ORDERED_HASHMAP_FOREACH(network, manager->networks)
+                HASHMAP_FOREACH(tmp, network->rules_by_section) {
+                        if (tmp->family != AF_UNSPEC && tmp->family != rule->family)
+                                continue;
+                        if (!tmp->priority_set)
+                                continue;
+                        if (tmp->priority == 0 || tmp->priority > 32765)
+                                continue;
+                        r = set_ensure_put(&priorities, NULL, UINT32_TO_PTR(tmp->priority));
+                        if (r < 0)
+                                return r;
+                }
+
+        for (priority = 32765; priority > 0; priority--)
+                if (!set_contains(priorities, UINT32_TO_PTR(priority)))
+                        break;
+
+        rule->priority = priority;
+        return 0;
 }
 
 static void log_routing_policy_rule_debug(const RoutingPolicyRule *rule, const char *str, const Link *link, const Manager *m) {
-        _cleanup_free_ char *from = NULL, *to = NULL, *table = NULL;
+        _cleanup_free_ char *state = NULL, *from = NULL, *to = NULL, *table = NULL;
 
         assert(rule);
         assert(IN_SET(rule->family, AF_INET, AF_INET6));
@@ -436,13 +410,15 @@ static void log_routing_policy_rule_debug(const RoutingPolicyRule *rule, const c
         if (!DEBUG_LOGGING)
                 return;
 
+        (void) network_config_state_to_string_alloc(rule->state, &state);
         (void) in_addr_prefix_to_string(rule->family, &rule->from, rule->from_prefixlen, &from);
         (void) in_addr_prefix_to_string(rule->family, &rule->to, rule->to_prefixlen, &to);
         (void) manager_get_route_table_to_string(m, rule->table, &table);
 
         log_link_debug(link,
-                       "%s routing policy rule: priority: %"PRIu32", %s -> %s, iif: %s, oif: %s, table: %s",
-                       str, rule->priority, strna(from), strna(to),
+                       "%s %s routing policy rule (%s): priority: %"PRIu32", %s -> %s, iif: %s, oif: %s, table: %s",
+                       str, strna(network_config_source_to_string(rule->source)), strna(state),
+                       rule->priority, strna(from), strna(to),
                        strna(rule->iif), strna(rule->oif), strna(table));
 }
 
@@ -474,11 +450,9 @@ static int routing_policy_rule_set_netlink_message(const RoutingPolicyRule *rule
                         return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
         }
 
-        if (rule->priority_set) {
-                r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not append FRA_PRIORITY attribute: %m");
-        }
+        r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not append FRA_PRIORITY attribute: %m");
 
         if (rule->tos > 0) {
                 r = sd_rtnl_message_routing_policy_rule_set_tos(m, rule->tos);
@@ -567,14 +541,10 @@ static int routing_policy_rule_set_netlink_message(const RoutingPolicyRule *rule
         return 0;
 }
 
-static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Manager *manager) {
+static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
         int r;
 
         assert(m);
-        assert(manager);
-        assert(manager->routing_policy_rule_remove_messages > 0);
-
-        manager->routing_policy_rule_remove_messages--;
 
         r = sd_netlink_message_get_errno(m);
         if (r < 0)
@@ -583,18 +553,18 @@ static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_messa
         return 1;
 }
 
-static int routing_policy_rule_remove(const RoutingPolicyRule *rule, Manager *manager) {
+static int routing_policy_rule_remove(RoutingPolicyRule *rule) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
         int r;
 
         assert(rule);
-        assert(manager);
-        assert(manager->rtnl);
+        assert(rule->manager);
+        assert(rule->manager->rtnl);
         assert(IN_SET(rule->family, AF_INET, AF_INET6));
 
-        log_routing_policy_rule_debug(rule, "Removing", NULL, manager);
+        log_routing_policy_rule_debug(rule, "Removing", NULL, rule->manager);
 
-        r = sd_rtnl_message_new_routing_policy_rule(manager->rtnl, &m, RTM_DELRULE, rule->family);
+        r = sd_rtnl_message_new_routing_policy_rule(rule->manager->rtnl, &m, RTM_DELRULE, rule->family);
         if (r < 0)
                 return log_error_errno(r, "Could not allocate RTM_DELRULE message: %m");
 
@@ -602,22 +572,20 @@ static int routing_policy_rule_remove(const RoutingPolicyRule *rule, Manager *ma
         if (r < 0)
                 return r;
 
-        r = netlink_call_async(manager->rtnl, NULL, m,
+        r = netlink_call_async(rule->manager->rtnl, NULL, m,
                                routing_policy_rule_remove_handler,
-                               NULL, manager);
+                               NULL, NULL);
         if (r < 0)
                 return log_error_errno(r, "Could not send rtnetlink message: %m");
 
-        manager->routing_policy_rule_remove_messages++;
-
+        routing_policy_rule_enter_removing(rule);
         return 0;
 }
 
 static int routing_policy_rule_configure(
-                const RoutingPolicyRule *rule,
+                RoutingPolicyRule *rule,
                 Link *link,
-                link_netlink_message_handler_t callback,
-                RoutingPolicyRule **ret) {
+                link_netlink_message_handler_t callback) {
 
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
         int r;
@@ -640,10 +608,6 @@ static int routing_policy_rule_configure(
         if (r < 0)
                 return r;
 
-        r = routing_policy_rule_add(link->manager, rule, ret);
-        if (r < 0)
-                return log_link_error_errno(link, r, "Could not add rule: %m");
-
         r = netlink_call_async(link->manager->rtnl, NULL, m, callback,
                                link_netlink_destroy_callback, link);
         if (r < 0)
@@ -651,94 +615,70 @@ static int routing_policy_rule_configure(
 
         link_ref(link);
 
+        routing_policy_rule_enter_configuring(rule);
         return r;
 }
 
-static int links_have_routing_policy_rule(const Manager *m, const RoutingPolicyRule *rule, const Link *except) {
+int manager_drop_routing_policy_rules_internal(Manager *m, bool foreign, const Link *except) {
+        RoutingPolicyRule *rule;
         Link *link;
-        int r;
+        int k, r;
 
         assert(m);
-        assert(rule);
-
-        HASHMAP_FOREACH(link, m->links_by_index) {
-                RoutingPolicyRule *link_rule;
 
-                if (link == except)
+        /* First, mark all existing rules. */
+        SET_FOREACH(rule, m->rules) {
+                /* Do not touch rules managed by kernel. */
+                if (rule->protocol == RTPROT_KERNEL)
                         continue;
 
-                if (!link->network)
+                /* When 'foreign' is true, do not remove rules we configured. */
+                if (foreign && rule->source != NETWORK_CONFIG_SOURCE_FOREIGN)
                         continue;
 
-                HASHMAP_FOREACH(link_rule, link->network->rules_by_section)
-                        if (IN_SET(link_rule->family, AF_INET, AF_INET6)) {
-                                if (routing_policy_rule_equal(link_rule, rule))
-                                        return true;
-                        } else {
-                                /* The case Family=both. */
-                                _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
-
-                                r = routing_policy_rule_dup(link_rule, &tmp);
-                                if (r < 0)
-                                        return r;
-
-                                tmp->family = AF_INET;
-                                if (routing_policy_rule_equal(tmp, rule))
-                                        return true;
+                /* Ignore rules not assigned yet or already removing. */
+                if (!routing_policy_rule_exists(rule))
+                        continue;
 
-                                tmp->family = AF_INET6;
-                                if (routing_policy_rule_equal(tmp, rule))
-                                        return true;
-                        }
+                routing_policy_rule_mark(rule);
         }
 
-        return false;
-}
-
-int manager_drop_routing_policy_rules_internal(Manager *m, bool foreign, const Link *except) {
-        RoutingPolicyRule *rule;
-        int k, r = 0;
-        Set *rules;
-
-        assert(m);
-
-        rules = foreign ? m->rules_foreign : m->rules;
-        SET_FOREACH(rule, rules) {
-                /* Do not touch rules managed by kernel. */
-                if (rule->protocol == RTPROT_KERNEL)
+        /* Then, unmark all rules requested by active links. */
+        HASHMAP_FOREACH(link, m->links_by_index) {
+                if (link == except)
                         continue;
 
-                /* The rule will be configured later, or already configured by a link. */
-                k = links_have_routing_policy_rule(m, rule, except);
-                if (k != 0) {
-                        if (k < 0 && r >= 0)
-                                r = k;
+                if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
                         continue;
-                }
-
-                if (!foreign) {
-                        _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
 
-                        /* The rule may be configured without priority. Try to find without priority. */
+                HASHMAP_FOREACH(rule, link->network->rules_by_section) {
+                        RoutingPolicyRule *existing;
 
-                        k = routing_policy_rule_dup(rule, &tmp);
-                        if (k < 0) {
-                                if (r >= 0)
-                                        r = k;
-                                continue;
-                        }
+                        if (IN_SET(rule->family, AF_INET, AF_INET6)) {
+                                if (routing_policy_rule_get(m, rule, &existing) >= 0)
+                                        routing_policy_rule_unmark(existing);
+                        } else {
+                                /* The case Family=both. */
+                                rule->family = AF_INET;
+                                if (routing_policy_rule_get(m, rule, &existing) >= 0)
+                                        routing_policy_rule_unmark(existing);
 
-                        tmp->priority_set = false;
+                                rule->family = AF_INET6;
+                                if (routing_policy_rule_get(m, rule, &existing) >= 0)
+                                        routing_policy_rule_unmark(existing);
 
-                        k = links_have_routing_policy_rule(m, tmp, except);
-                        if (k != 0) {
-                                if (k < 0 && r >= 0)
-                                        r = k;
-                                continue;
+                                rule->family = AF_UNSPEC;
                         }
                 }
+        }
+
+        /* Finally, remove all marked rules. */
+        r = 0;
+        SET_FOREACH(rule, m->rules) {
+                if (!routing_policy_rule_is_marked(rule))
+                        continue;
 
-                k = routing_policy_rule_remove(rule, m);
+                k = routing_policy_rule_remove(rule);
                 if (k < 0 && r >= 0)
                         r = k;
         }
@@ -779,64 +719,73 @@ static int static_routing_policy_rule_configure_handler(sd_netlink *rtnl, sd_net
 static int link_request_routing_policy_rule(
                 Link *link,
                 RoutingPolicyRule *rule,
-                bool consume_object,
                 unsigned *message_counter,
                 link_netlink_message_handler_t netlink_handler,
                 Request **ret) {
 
+        RoutingPolicyRule *existing;
+        int r;
+
         assert(link);
         assert(link->manager);
         assert(rule);
+        assert(rule->source != NETWORK_CONFIG_SOURCE_FOREIGN);
 
-        log_routing_policy_rule_debug(rule, "Requesting", link, link->manager);
-        return link_queue_request(link, REQUEST_TYPE_ROUTING_POLICY_RULE, rule, consume_object,
-                                  message_counter, netlink_handler, ret);
-}
-
-static int link_request_static_routing_policy_rule(Link *link, RoutingPolicyRule *rule) {
-        int r;
-
-        if (IN_SET(rule->family, AF_INET, AF_INET6))
-                return link_request_routing_policy_rule(link, rule, false,
-                                                        &link->static_routing_policy_rule_messages,
-                                                        static_routing_policy_rule_configure_handler,
-                                                        NULL);
-
-        if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4)) {
+        if (routing_policy_rule_get(link->manager, rule, &existing) < 0) {
                 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
 
                 r = routing_policy_rule_dup(rule, &tmp);
                 if (r < 0)
                         return r;
 
-                tmp->family = AF_INET;
-
-                r = link_request_routing_policy_rule(link, TAKE_PTR(tmp), true,
-                                                     &link->static_routing_policy_rule_messages,
-                                                     static_routing_policy_rule_configure_handler,
-                                                     NULL);
+                r = routing_policy_rule_acquire_priority(link->manager, tmp);
                 if (r < 0)
                         return r;
-        }
-
-        if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6)) {
-                _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
 
-                r = routing_policy_rule_dup(rule, &tmp);
+                r = routing_policy_rule_add(link->manager, tmp);
                 if (r < 0)
                         return r;
 
-                tmp->family = AF_INET6;
+                existing = TAKE_PTR(tmp);
+        } else
+                existing->source = rule->source;
 
-                r = link_request_routing_policy_rule(link, TAKE_PTR(tmp), true,
-                                                     &link->static_routing_policy_rule_messages,
-                                                     static_routing_policy_rule_configure_handler,
-                                                     NULL);
-                if (r < 0)
-                        return r;
+        log_routing_policy_rule_debug(existing, "Requesting", link, link->manager);
+        r = link_queue_request(link, REQUEST_TYPE_ROUTING_POLICY_RULE, existing, false,
+                               message_counter, netlink_handler, ret);
+        if (r <= 0)
+                return r;
+
+        routing_policy_rule_enter_requesting(existing);
+        return 1;
+}
+
+static int link_request_static_routing_policy_rule(Link *link, RoutingPolicyRule *rule) {
+        int r;
+
+        if (IN_SET(rule->family, AF_INET, AF_INET6))
+                return link_request_routing_policy_rule(link, rule,
+                                                        &link->static_routing_policy_rule_messages,
+                                                        static_routing_policy_rule_configure_handler,
+                                                        NULL);
+
+        rule->family = AF_INET;
+        r = link_request_routing_policy_rule(link, rule,
+                                             &link->static_routing_policy_rule_messages,
+                                             static_routing_policy_rule_configure_handler,
+                                             NULL);
+        if (r < 0) {
+                rule->family = AF_UNSPEC;
+                return r;
         }
 
-        return 0;
+        rule->family = AF_INET6;
+        r = link_request_routing_policy_rule(link, rule,
+                                             &link->static_routing_policy_rule_messages,
+                                             static_routing_policy_rule_configure_handler,
+                                             NULL);
+        rule->family = AF_UNSPEC;
+        return r;
 }
 
 int link_request_static_routing_policy_rules(Link *link) {
@@ -866,7 +815,6 @@ int link_request_static_routing_policy_rules(Link *link) {
 }
 
 int request_process_routing_policy_rule(Request *req) {
-        RoutingPolicyRule *ret = NULL;  /* avoid false maybe-uninitialized warning */
         int r;
 
         assert(req);
@@ -877,10 +825,7 @@ int request_process_routing_policy_rule(Request *req) {
         if (!link_is_ready_to_configure(req->link, false))
                 return 0;
 
-        if (req->link->manager->routing_policy_rule_remove_messages > 0)
-                return 0;
-
-        r = routing_policy_rule_configure(req->rule, req->link, req->netlink_handler, &ret);
+        r = routing_policy_rule_configure(req->rule, req->link, req->netlink_handler);
         if (r < 0)
                 return r;
 
@@ -1090,28 +1035,35 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man
                  * protocol of the received rule is RTPROT_KERNEL or RTPROT_STATIC. */
                 tmp->protocol = routing_policy_rule_is_created_by_kernel(tmp) ? RTPROT_KERNEL : RTPROT_STATIC;
 
-        (void) routing_policy_rule_get(m, tmp, false, &rule);
+        (void) routing_policy_rule_get(m, tmp, &rule);
 
         switch (type) {
         case RTM_NEWRULE:
                 if (rule) {
-                        log_routing_policy_rule_debug(tmp, "Received remembered", NULL, m);
-                        r = routing_policy_rule_update_priority(rule, tmp->priority);
-                        if (r < 0)
-                                log_warning_errno(r, "Failed to update priority of remembered routing policy rule, ignoring: %m");
-                } else if (!m->manage_foreign_rules)
-                        log_routing_policy_rule_debug(tmp, "Ignoring received foreign", NULL, m);
-                else {
-                        log_routing_policy_rule_debug(tmp, "Remembering foreign", NULL, m);
-                        r = routing_policy_rule_consume_foreign(m, TAKE_PTR(tmp));
-                        if (r < 0)
+                        routing_policy_rule_enter_configured(rule);
+                        log_routing_policy_rule_debug(rule, "Received remembered", NULL, m);
+                } else if (!m->manage_foreign_rules) {
+                        routing_policy_rule_enter_configured(tmp);
+                        log_routing_policy_rule_debug(tmp, "Ignoring received", NULL, m);
+                } else {
+                        routing_policy_rule_enter_configured(tmp);
+                        log_routing_policy_rule_debug(tmp, "Remembering", NULL, m);
+                        r = routing_policy_rule_add(m, tmp);
+                        if (r < 0) {
                                 log_warning_errno(r, "Could not remember foreign rule, ignoring: %m");
+                                return 0;
+                        }
+                        TAKE_PTR(tmp);
                 }
                 break;
         case RTM_DELRULE:
                 if (rule) {
-                        log_routing_policy_rule_debug(tmp, "Forgetting", NULL, m);
-                        routing_policy_rule_free(rule);
+                        routing_policy_rule_enter_removed(rule);
+                        if (rule->state == 0) {
+                                log_routing_policy_rule_debug(rule, "Forgetting", NULL, m);
+                                routing_policy_rule_free(rule);
+                        } else
+                                log_routing_policy_rule_debug(rule, "Removed", NULL, m);
                 } else
                         log_routing_policy_rule_debug(tmp, "Kernel removed unknown", NULL, m);
                 break;
index 557048c3f48e3c0570d3f960dfb74191fa4ac677..757b17bcb6d99f4aa17fc17a258993c8746836c4 100644 (file)
@@ -18,6 +18,8 @@ typedef struct RoutingPolicyRule {
         Manager *manager;
         Network *network;
         NetworkConfigSection *section;
+        NetworkConfigSource source;
+        NetworkConfigState state;
 
         bool invert_rule;
         bool priority_set;
@@ -70,6 +72,8 @@ static inline int manager_drop_routing_policy_rules(Manager *m, const Link *exce
         return manager_drop_routing_policy_rules_internal(m, false, except);
 }
 
+DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(RoutingPolicyRule, routing_policy_rule);
+
 CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_tos);
 CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_table);
 CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_fwmark_mask);