mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +03:00
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 0a0c2672db
, but for
routing policy rule.
This commit is contained in:
parent
4f8b153d90
commit
65f5f58156
@ -465,6 +465,21 @@ static int routing_policy_rule_acquire_priority(Manager *manager, RoutingPolicyR
|
|||||||
return r;
|
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)
|
ORDERED_HASHMAP_FOREACH(network, manager->networks)
|
||||||
HASHMAP_FOREACH(tmp, network->rules_by_section) {
|
HASHMAP_FOREACH(tmp, network->rules_by_section) {
|
||||||
if (tmp->family != AF_UNSPEC && tmp->family != rule->family)
|
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) {
|
static int routing_policy_rule_process_request(Request *req, Link *link, RoutingPolicyRule *rule) {
|
||||||
|
RoutingPolicyRule *existing;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(req);
|
assert(req);
|
||||||
assert(link);
|
assert(link);
|
||||||
|
assert(link->manager);
|
||||||
assert(rule);
|
assert(rule);
|
||||||
|
|
||||||
if (!link_is_ready_to_configure(link, false))
|
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");
|
return log_link_warning_errno(link, r, "Failed to configure routing policy rule: %m");
|
||||||
|
|
||||||
routing_policy_rule_enter_configuring(rule);
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -814,9 +834,17 @@ static int static_routing_policy_rule_configure_handler(
|
|||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
assert(link);
|
assert(link);
|
||||||
|
assert(rule);
|
||||||
|
|
||||||
r = sd_netlink_message_get_errno(m);
|
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");
|
log_link_message_warning_errno(link, m, r, "Could not add routing policy rule");
|
||||||
link_enter_failed(link);
|
link_enter_failed(link);
|
||||||
return 1;
|
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) {
|
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;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
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)
|
if (routing_policy_rule_get_request(link->manager, rule, family, NULL) >= 0)
|
||||||
return 0; /* already requested, skipping. */
|
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);
|
r = routing_policy_rule_dup(rule, family, &tmp);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
if (routing_policy_rule_get(link->manager, tmp, family, &existing) < 0) {
|
||||||
r = routing_policy_rule_acquire_priority(link->manager, tmp);
|
r = routing_policy_rule_acquire_priority(link->manager, tmp);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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);
|
/* Copy state for logging below. */
|
||||||
if (r < 0)
|
tmp->state = existing->state;
|
||||||
return r;
|
}
|
||||||
|
|
||||||
existing = tmp;
|
log_routing_policy_rule_debug(tmp, "Requesting", link, link->manager);
|
||||||
} else
|
|
||||||
existing->source = rule->source;
|
|
||||||
|
|
||||||
log_routing_policy_rule_debug(existing, "Requesting", link, link->manager);
|
|
||||||
r = link_queue_request_safe(link, REQUEST_TYPE_ROUTING_POLICY_RULE,
|
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_hash_func,
|
||||||
routing_policy_rule_compare_func,
|
routing_policy_rule_compare_func,
|
||||||
routing_policy_rule_process_request,
|
routing_policy_rule_process_request,
|
||||||
@ -876,7 +906,11 @@ static int link_request_routing_policy_rule(Link *link, const RoutingPolicyRule
|
|||||||
if (r <= 0)
|
if (r <= 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
routing_policy_rule_enter_requesting(tmp);
|
||||||
|
if (existing)
|
||||||
routing_policy_rule_enter_requesting(existing);
|
routing_policy_rule_enter_requesting(existing);
|
||||||
|
|
||||||
|
TAKE_PTR(tmp);
|
||||||
return 1;
|
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) {
|
int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
|
||||||
_cleanup_(routing_policy_rule_unrefp) RoutingPolicyRule *tmp = NULL;
|
_cleanup_(routing_policy_rule_unrefp) RoutingPolicyRule *tmp = NULL;
|
||||||
|
bool adjust_protocol = false, is_new = false;
|
||||||
RoutingPolicyRule *rule = NULL;
|
RoutingPolicyRule *rule = NULL;
|
||||||
bool adjust_protocol = false;
|
Request *req = NULL;
|
||||||
uint16_t type;
|
uint16_t type;
|
||||||
int r;
|
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);
|
r = sd_netlink_message_read_u32(message, FRA_FWMARK, &tmp->fwmark);
|
||||||
if (r < 0 && r != -ENODATA) {
|
if (r < 0 && r != -ENODATA) {
|
||||||
log_warning_errno(r, "rtnl: could not get FRA_FWMARK attribute, ignoring: %m");
|
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;
|
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(m, tmp, tmp->family, &rule);
|
||||||
|
(void) routing_policy_rule_get_request(m, tmp, tmp->family, &req);
|
||||||
|
|
||||||
switch (type) {
|
if (type == RTM_DELRULE) {
|
||||||
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 (rule) {
|
if (rule) {
|
||||||
routing_policy_rule_enter_removed(rule);
|
routing_policy_rule_enter_removed(rule);
|
||||||
if (rule->state == 0) {
|
log_routing_policy_rule_debug(rule, "Forgetting removed", NULL, m);
|
||||||
log_routing_policy_rule_debug(rule, "Forgetting", NULL, m);
|
|
||||||
routing_policy_rule_detach(rule);
|
routing_policy_rule_detach(rule);
|
||||||
} else
|
|
||||||
log_routing_policy_rule_debug(rule, "Removed", NULL, m);
|
|
||||||
} else
|
} else
|
||||||
log_routing_policy_rule_debug(tmp, "Kernel removed unknown", NULL, m);
|
log_routing_policy_rule_debug(tmp, "Kernel removed unknown", NULL, m);
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
if (req)
|
||||||
assert_not_reached();
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user