summaryrefslogtreecommitdiffstats
path: root/src/network/networkd-routing-policy-rule.c
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2024-08-19 21:02:46 +0200
committerYu Watanabe <watanabe.yu+github@gmail.com>2024-08-20 14:02:30 +0200
commit65f5f581568448d6098358b704cae10a656d09f0 (patch)
tree7672bdfa2ac9021b899a250d36547237ffee3330 /src/network/networkd-routing-policy-rule.c
parentnetwork/routing-policy-rule: skip requesting when rule is already requested (diff)
downloadsystemd-65f5f581568448d6098358b704cae10a656d09f0.tar.xz
systemd-65f5f581568448d6098358b704cae10a656d09f0.zip
network/routing-policy-rule: do not save rule to Manager before it is configured
Otherwise, if we fail to configure the rule, then the manager will keep nonexistent rule forever. So, let's first copy the rule and put it on Request, then on success generate a new copy based on the netlink notification and store it to Manager. This is the same as 0a0c2672dbd22dc85d660e5baa7e1bef701beb88, but for routing policy rule.
Diffstat (limited to '')
-rw-r--r--src/network/networkd-routing-policy-rule.c149
1 files changed, 97 insertions, 52 deletions
diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c
index 95261fc258..6ec81eec8c 100644
--- a/src/network/networkd-routing-policy-rule.c
+++ b/src/network/networkd-routing-policy-rule.c
@@ -465,6 +465,21 @@ static int routing_policy_rule_acquire_priority(Manager *manager, RoutingPolicyR
return r;
}
+ Request *req;
+ ORDERED_SET_FOREACH(req, manager->request_queue) {
+ if (req->type != REQUEST_TYPE_ROUTING_POLICY_RULE)
+ continue;
+
+ tmp = ASSERT_PTR(req->userdata);
+ 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;
+ }
+
ORDERED_HASHMAP_FOREACH(network, manager->networks)
HASHMAP_FOREACH(tmp, network->rules_by_section) {
if (tmp->family != AF_UNSPEC && tmp->family != rule->family)
@@ -786,10 +801,12 @@ void link_foreignize_routing_policy_rules(Link *link) {
}
static int routing_policy_rule_process_request(Request *req, Link *link, RoutingPolicyRule *rule) {
+ RoutingPolicyRule *existing;
int r;
assert(req);
assert(link);
+ assert(link->manager);
assert(rule);
if (!link_is_ready_to_configure(link, false))
@@ -800,6 +817,9 @@ static int routing_policy_rule_process_request(Request *req, Link *link, Routing
return log_link_warning_errno(link, r, "Failed to configure routing policy rule: %m");
routing_policy_rule_enter_configuring(rule);
+ if (routing_policy_rule_get(link->manager, rule, rule->family, &existing) >= 0)
+ routing_policy_rule_enter_configuring(existing);
+
return 1;
}
@@ -814,9 +834,17 @@ static int static_routing_policy_rule_configure_handler(
assert(m);
assert(link);
+ assert(rule);
r = sd_netlink_message_get_errno(m);
- if (r < 0 && r != -EEXIST) {
+ if (r == -EEXIST) {
+ RoutingPolicyRule *existing;
+
+ if (routing_policy_rule_get(link->manager, rule, rule->family, &existing) >= 0) {
+ existing->source = rule->source;
+ routing_policy_rule_enter_configured(existing);
+ }
+ } else if (r < 0) {
log_link_message_warning_errno(link, m, r, "Could not add routing policy rule");
link_enter_failed(link);
return 1;
@@ -832,7 +860,8 @@ static int static_routing_policy_rule_configure_handler(
}
static int link_request_routing_policy_rule(Link *link, const RoutingPolicyRule *rule, int family) {
- RoutingPolicyRule *existing;
+ _cleanup_(routing_policy_rule_unrefp) RoutingPolicyRule *tmp = NULL;
+ RoutingPolicyRule *existing = NULL;
int r;
assert(link);
@@ -845,28 +874,29 @@ static int link_request_routing_policy_rule(Link *link, const RoutingPolicyRule
if (routing_policy_rule_get_request(link->manager, rule, family, NULL) >= 0)
return 0; /* already requested, skipping. */
- if (routing_policy_rule_get(link->manager, rule, family, &existing) < 0) {
- _cleanup_(routing_policy_rule_unrefp) RoutingPolicyRule *tmp = NULL;
-
- r = routing_policy_rule_dup(rule, family, &tmp);
- if (r < 0)
- return r;
+ r = routing_policy_rule_dup(rule, family, &tmp);
+ if (r < 0)
+ return r;
+ if (routing_policy_rule_get(link->manager, tmp, family, &existing) < 0) {
r = routing_policy_rule_acquire_priority(link->manager, tmp);
if (r < 0)
return r;
+ } else {
+ /* Copy priority from existing rule. */
+ if (!tmp->priority_set) {
+ tmp->priority_set = true;
+ tmp->priority = existing->priority;
+ }
- r = routing_policy_rule_attach(link->manager, tmp);
- if (r < 0)
- return r;
-
- existing = tmp;
- } else
- existing->source = rule->source;
+ /* Copy state for logging below. */
+ tmp->state = existing->state;
+ }
- log_routing_policy_rule_debug(existing, "Requesting", link, link->manager);
+ log_routing_policy_rule_debug(tmp, "Requesting", link, link->manager);
r = link_queue_request_safe(link, REQUEST_TYPE_ROUTING_POLICY_RULE,
- existing, NULL,
+ tmp,
+ routing_policy_rule_unref,
routing_policy_rule_hash_func,
routing_policy_rule_compare_func,
routing_policy_rule_process_request,
@@ -876,7 +906,11 @@ static int link_request_routing_policy_rule(Link *link, const RoutingPolicyRule
if (r <= 0)
return r;
- routing_policy_rule_enter_requesting(existing);
+ routing_policy_rule_enter_requesting(tmp);
+ if (existing)
+ routing_policy_rule_enter_requesting(existing);
+
+ TAKE_PTR(tmp);
return 1;
}
@@ -947,8 +981,9 @@ static bool routing_policy_rule_is_created_by_kernel(const RoutingPolicyRule *ru
int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
_cleanup_(routing_policy_rule_unrefp) RoutingPolicyRule *tmp = NULL;
+ bool adjust_protocol = false, is_new = false;
RoutingPolicyRule *rule = NULL;
- bool adjust_protocol = false;
+ Request *req = NULL;
uint16_t type;
int r;
@@ -1011,12 +1046,6 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man
}
}
- r = sd_rtnl_message_routing_policy_rule_get_flags(message, &tmp->flags);
- if (r < 0) {
- log_warning_errno(r, "rtnl: received rule message without valid flag, ignoring: %m");
- return 0;
- }
-
r = sd_netlink_message_read_u32(message, FRA_FWMARK, &tmp->fwmark);
if (r < 0 && r != -ENODATA) {
log_warning_errno(r, "rtnl: could not get FRA_FWMARK attribute, ignoring: %m");
@@ -1135,41 +1164,57 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man
tmp->protocol = routing_policy_rule_is_created_by_kernel(tmp) ? RTPROT_KERNEL : RTPROT_STATIC;
(void) routing_policy_rule_get(m, tmp, tmp->family, &rule);
+ (void) routing_policy_rule_get_request(m, tmp, tmp->family, &req);
- switch (type) {
- case RTM_NEWRULE:
- if (rule) {
- 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_attach(m, tmp);
- if (r < 0) {
- log_warning_errno(r, "Could not remember foreign rule, ignoring: %m");
- return 0;
- }
- }
- break;
- case RTM_DELRULE:
+ if (type == RTM_DELRULE) {
if (rule) {
routing_policy_rule_enter_removed(rule);
- if (rule->state == 0) {
- log_routing_policy_rule_debug(rule, "Forgetting", NULL, m);
- routing_policy_rule_detach(rule);
- } else
- log_routing_policy_rule_debug(rule, "Removed", NULL, m);
+ log_routing_policy_rule_debug(rule, "Forgetting removed", NULL, m);
+ routing_policy_rule_detach(rule);
} else
log_routing_policy_rule_debug(tmp, "Kernel removed unknown", NULL, m);
- break;
- default:
- assert_not_reached();
+ if (req)
+ routing_policy_rule_enter_removed(req->userdata);
+
+ return 0;
}
+ if (!rule) {
+ if (!req && !m->manage_foreign_rules) {
+ routing_policy_rule_enter_configured(tmp);
+ log_routing_policy_rule_debug(tmp, "Ignoring received", NULL, m);
+ return 0;
+ }
+
+ /* If we did not know the rule, then save it. */
+ r = routing_policy_rule_attach(m, tmp);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to save received routing policy rule, ignoring: %m");
+ return 0;
+ }
+
+ rule = tmp;
+ is_new = true;
+ }
+
+ /* Also update information that cannot be obtained through netlink notification. */
+ if (req && req->waiting_reply) {
+ RoutingPolicyRule *req_rule = ASSERT_PTR(req->userdata);
+
+ rule->source = req_rule->source;
+ }
+
+ /* Then, update miscellaneous info from netlink notification. */
+ r = sd_rtnl_message_routing_policy_rule_get_flags(message, &rule->flags);
+ if (r < 0)
+ log_debug_errno(r, "rtnl: received rule message without valid flag, ignoring: %m");
+
+ routing_policy_rule_enter_configured(rule);
+ if (req)
+ routing_policy_rule_enter_configured(req->userdata);
+
+ log_routing_policy_rule_debug(rule, is_new ? "Remembering" : "Received remembered", NULL, m);
return 1;
}