]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/network/networkd-routing-policy-rule.c
networkd: Fix race condition in [RoutingPolicyRule] handling (#7615)
[thirdparty/systemd.git] / src / network / networkd-routing-policy-rule.c
index 221ab4cb858c1dae868ed5f20ffd717786b5f527..1314564c1107a61e6d49b5c12738bb00046e3fc6 100644 (file)
@@ -324,7 +324,7 @@ static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_messa
         assert(link);
         assert(link->ifname);
 
-        link->link_messages--;
+        link->routing_policy_rule_remove_messages--;
 
         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                 return 1;
@@ -438,9 +438,9 @@ int link_routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, vo
         assert(m);
         assert(link);
         assert(link->ifname);
-        assert(link->link_messages > 0);
+        assert(link->routing_policy_rule_messages > 0);
 
-        link->link_messages--;
+        link->routing_policy_rule_messages--;
 
         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                 return 1;
@@ -449,8 +449,11 @@ int link_routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, vo
         if (r < 0 && r != -EEXIST)
                 log_link_warning_errno(link, r, "Could not add routing policy rule: %m");
 
-        if (link->link_messages == 0)
+        if (link->routing_policy_rule_messages == 0) {
                 log_link_debug(link, "Routing policy rule configured");
+                link->routing_policy_rules_configured = true;
+                link_check_ready(link);
+        }
 
         return 1;
 }
@@ -836,7 +839,7 @@ int config_parse_routing_policy_rule_device(
         return 0;
 }
 
-static int routing_policy_rule_read_full_file(char *state_file, char **ret) {
+static int routing_policy_rule_read_full_file(const char *state_file, char **ret) {
         _cleanup_free_ char *s = NULL;
         size_t size;
         int r;
@@ -857,16 +860,87 @@ static int routing_policy_rule_read_full_file(char *state_file, char **ret) {
         return size;
 }
 
-int routing_policy_rule_load(Manager *m) {
+int routing_policy_serialize_rules(Set *rules, FILE *f) {
+        RoutingPolicyRule *rule = NULL;
+        Iterator i;
+        int r;
+
+        assert(f);
+
+        SET_FOREACH(rule, rules, i) {
+                _cleanup_free_ char *from_str = NULL, *to_str = NULL;
+                bool space = false;
+
+                fputs("RULE=", f);
+
+                if (!in_addr_is_null(rule->family, &rule->from)) {
+                        r = in_addr_to_string(rule->family, &rule->from, &from_str);
+                        if (r < 0)
+                                return r;
+
+                        fprintf(f, "from=%s/%hhu",
+                                from_str, rule->from_prefixlen);
+                        space = true;
+                }
+
+                if (!in_addr_is_null(rule->family, &rule->to)) {
+                        r = in_addr_to_string(rule->family, &rule->to, &to_str);
+                        if (r < 0)
+                                return r;
+
+                        fprintf(f, "%sto=%s/%hhu",
+                                space ? " " : "",
+                                to_str, rule->to_prefixlen);
+                        space = true;
+                }
+
+                if (rule->tos != 0) {
+                        fprintf(f, "%stos=%hhu",
+                                space ? " " : "",
+                                rule->tos);
+                        space = true;
+                }
+
+                if (rule->fwmark != 0) {
+                        fprintf(f, "%sfwmark=%"PRIu32"/%"PRIu32,
+                                space ? " " : "",
+                                rule->fwmark, rule->fwmask);
+                        space = true;
+                }
+
+                if (rule->iif) {
+                        fprintf(f, "%siif=%s",
+                                space ? " " : "",
+                                rule->iif);
+                        space = true;
+                }
+
+                if (rule->oif) {
+                        fprintf(f, "%soif=%s",
+                                space ? " " : "",
+                                rule->oif);
+                        space = true;
+                }
+
+                fprintf(f, "%stable=%"PRIu32 "\n",
+                        space ? " " : "",
+                        rule->table);
+        }
+
+        return 0;
+}
+
+int routing_policy_load_rules(const char *state_file, Set **rules) {
         _cleanup_strv_free_ char **l = NULL;
         _cleanup_free_ char *data = NULL;
         const char *p;
         char **i;
         int r;
 
-        assert(m);
+        assert(state_file);
+        assert(rules);
 
-        r = routing_policy_rule_read_full_file(m->state_file, &data);
+        r = routing_policy_rule_read_full_file(state_file, &data);
         if (r <= 0)
                 return r;
 
@@ -874,7 +948,7 @@ int routing_policy_rule_load(Manager *m) {
         if (!l)
                 return -ENOMEM;
 
-        r = set_ensure_allocated(&m->rules_saved, &routing_policy_rule_hash_ops);
+        r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops);
         if (r < 0)
                 return r;
 
@@ -885,9 +959,6 @@ int routing_policy_rule_load(Manager *m) {
                 if (!p)
                         continue;
 
-                p = strchr(*i, '=');
-                p++;
-
                 r = routing_policy_rule_new(&rule);
                 if (r < 0)
                         return r;
@@ -942,25 +1013,24 @@ int routing_policy_rule_load(Manager *m) {
                                 }
                         } else if (streq(a, "fwmark")) {
 
-                                r = parse_fwmark_fwmask(a, &rule->fwmark, &rule->fwmask);
+                                r = parse_fwmark_fwmask(b, &rule->fwmark, &rule->fwmask);
                                 if (r < 0) {
                                         log_error_errno(r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a);
                                         continue;
                                 }
-                        } else if (streq(a, "IncomingInterface")) {
+                        } else if (streq(a, "iif")) {
 
-                                rule->iif = strdup(a);
-                                if (!rule->iif)
+                                if (free_and_strdup(&rule->iif, b) < 0)
                                         return log_oom();
-                        } else if (streq(a, "OutgoingInterface")) {
 
-                                rule->oif = strdup(a);
-                                if (!rule->oif)
+                        } else if (streq(a, "oif")) {
+
+                                if (free_and_strdup(&rule->oif, b) < 0)
                                         return log_oom();
                         }
                 }
 
-                r = set_put(m->rules_saved, rule);
+                r = set_put(*rules, rule);
                 if (r < 0) {
                         log_warning_errno(r, "Failed to add RPDB rule to saved DB, ignoring: %s", p);
                         continue;
@@ -990,7 +1060,7 @@ void routing_policy_rule_purge(Manager *m, Link *link) {
                                 continue;
                         }
 
-                        link->link_messages++;
+                        link->routing_policy_rule_remove_messages++;
                 }
         }
 }