]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network/routing-policy-rule: remove rules that have conflicting flags
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 19 Aug 2024 21:19:46 +0000 (06:19 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 20 Aug 2024 12:02:30 +0000 (21:02 +0900)
The kernel does not distinguish rules with different flags in
rule_exists(), but the flags of an existing rule cannot be updated.
Let's remove rules that have conflicting flags, and configure new rules
later with requested flags.

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

index 5ce384f8721a42af327782946e2b56a1fcdbfa48..460e621b2b1b3148a1ef95d72d0754077cb80e48 100644 (file)
@@ -350,6 +350,20 @@ static bool routing_policy_rule_equal(const RoutingPolicyRule *a, const RoutingP
         return routing_policy_rule_compare_func_full(a, b, /* all = */ false) == 0;
 }
 
+static bool routing_policy_rule_can_update(const RoutingPolicyRule *existing, const RoutingPolicyRule *requesting, int family) {
+        assert(existing);
+        assert(requesting);
+
+        if (!routing_policy_rule_equal(existing, requesting, family, existing->priority))
+                return false;
+
+        /* These flags cannot be updated. */
+        if ((existing->flags ^ requesting->flags) & (FIB_RULE_PERMANENT|FIB_RULE_INVERT))
+                return false;
+
+        return true;
+}
+
 static int routing_policy_rule_get(Manager *m, const RoutingPolicyRule *in, int family, RoutingPolicyRule **ret) {
         RoutingPolicyRule *rule;
 
@@ -742,6 +756,23 @@ static int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, Re
         return request_call_netlink_async(link->manager->rtnl, m, req);
 }
 
+static void manager_unmark_routing_policy_rule(Manager *m, const RoutingPolicyRule *rule, int family) {
+        RoutingPolicyRule *existing;
+
+        assert(m);
+        assert(rule);
+        assert(rule->family == AF_UNSPEC || rule->family == family);
+        assert(IN_SET(family, AF_INET, AF_INET6));
+
+        if (routing_policy_rule_get(m, rule, family, &existing) < 0)
+                return;
+
+        if (!routing_policy_rule_can_update(existing, rule, rule->family))
+                return;
+
+        routing_policy_rule_unmark(existing);
+}
+
 static void manager_mark_routing_policy_rules(Manager *m, bool foreign, const Link *except) {
         RoutingPolicyRule *rule;
         Link *link;
@@ -774,17 +805,12 @@ static void manager_mark_routing_policy_rules(Manager *m, bool foreign, const Li
                         continue;
 
                 HASHMAP_FOREACH(rule, link->network->rules_by_section) {
-                        RoutingPolicyRule *existing;
-
-                        if (IN_SET(rule->family, AF_INET, AF_INET6)) {
-                                if (routing_policy_rule_get(m, rule, rule->family, &existing) >= 0)
-                                        routing_policy_rule_unmark(existing);
-                        } else {
-                                if (routing_policy_rule_get(m, rule, AF_INET, &existing) >= 0)
-                                        routing_policy_rule_unmark(existing);
-
-                                if (routing_policy_rule_get(m, rule, AF_INET6, &existing) >= 0)
-                                        routing_policy_rule_unmark(existing);
+                        if (IN_SET(rule->family, AF_INET, AF_INET6))
+                                manager_unmark_routing_policy_rule(m, rule, rule->family);
+                        else {
+                                assert(rule->address_family == ADDRESS_FAMILY_YES);
+                                manager_unmark_routing_policy_rule(m, rule, AF_INET);
+                                manager_unmark_routing_policy_rule(m, rule, AF_INET6);
                         }
                 }
         }