1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-31 14:50:15 +03:00

network: allow to configure routing policy rule even if requesting interface is not activated yet (#36257)

Fixes a regression caused by 4f8b153d903fd4a6e8d7d3e49113582d70d1525a
(v257).
Fixes #36244.
This commit is contained in:
Luca Boccassi 2025-02-07 22:56:36 +00:00 committed by GitHub
commit 382e8a03ca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 100 additions and 1 deletions

View File

@ -200,6 +200,17 @@ bool link_is_ready_to_configure(Link *link, bool allow_unmanaged) {
return check_ready_for_all_sr_iov_ports(link, allow_unmanaged, link_is_ready_to_configure_one);
}
bool link_is_ready_to_configure_by_name(Manager *manager, const char *name, bool allow_unmanaged) {
assert(manager);
assert(name);
Link *link;
if (link_get_by_name(manager, name, &link) < 0)
return false;
return link_is_ready_to_configure(link, allow_unmanaged);
}
void link_ntp_settings_clear(Link *link) {
link->ntp = strv_free(link->ntp);
}

View File

@ -225,6 +225,7 @@ typedef struct Link {
typedef int (*link_netlink_message_handler_t)(sd_netlink*, sd_netlink_message*, Link*);
bool link_is_ready_to_configure(Link *link, bool allow_unmanaged);
bool link_is_ready_to_configure_by_name(Manager *manager, const char *name, bool allow_unmanaged);
void link_ntp_settings_clear(Link *link);
void link_dns_settings_clear(Link *link);

View File

@ -872,6 +872,31 @@ int link_drop_routing_policy_rules(Link *link, bool only_static) {
return r;
}
static int routing_policy_rule_is_ready_to_configure(const RoutingPolicyRule *rule, Link *link) {
assert(rule);
assert(link);
assert(link->manager);
/* For routing policy rules, it is not necessary to check operstate and friends of the interface.
* Hence, here we refuse to configure rules only when the interface is already removed, or in the
* failed state. */
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
return false;
/* Strictly speaking checking existence of IIF and OIF below is not necessary. But, configuring
* routing policy rule with non-existent IIF or OIF is mostly meaningless, and 'ip rule' command
* shows [detached] for such rules, that may confuse users. Let's postpone to configure if one of
* IIF/OIF does not exist. */
if (rule->iif && !link_is_ready_to_configure_by_name(link->manager, rule->iif, /* allow_unmanaged = */ true))
return false;
if (rule->oif && !link_is_ready_to_configure_by_name(link->manager, rule->oif, /* allow_unmanaged = */ true))
return false;
return true;
}
static int routing_policy_rule_process_request(Request *req, Link *link, RoutingPolicyRule *rule) {
RoutingPolicyRule *existing;
int r;
@ -881,7 +906,7 @@ static int routing_policy_rule_process_request(Request *req, Link *link, Routing
assert(link->manager);
assert(rule);
if (!link_is_ready_to_configure(link, false))
if (!routing_policy_rule_is_ready_to_configure(rule, link))
return 0;
r = routing_policy_rule_configure(rule, link, req);

View File

@ -0,0 +1,23 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Name=test1
Name=test2
[Link]
ActivationPolicy=manual
[Network]
IPv6AcceptRA=no
[RoutingPolicyRule]
Family=both
Priority=10
SuppressPrefixLength=0
Table=51819
[RoutingPolicyRule]
Family=both
FirewallMark=911
InvertRule=true
Priority=11
Table=51820

View File

@ -3999,6 +3999,45 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
print(output)
self.assertIn('10113: from all iif test1 lookup 1011', output)
def test_routing_policy_rule_manual(self):
# For issue #36244.
copy_network_unit(
'11-dummy.netdev',
'25-routing-policy-rule-manual.network')
start_networkd()
self.wait_operstate('test1', operstate='off', setup_state='configuring', setup_timeout=20)
check_output('ip link add test2 type dummy')
self.wait_operstate('test2', operstate='off', setup_state='configuring', setup_timeout=20)
networkctl('up', 'test2')
self.wait_online('test2:degraded')
# The request for the routing policy rules are bound to test1. Hence, we need to wait for the rules
# being configured explicitly.
for _ in range(20):
time.sleep(0.5)
output = check_output('ip -4 rule list table 51819')
if output != '10: from all lookup 51819 suppress_prefixlength 0 proto static':
continue
output = check_output('ip -6 rule list table 51819')
if output != '10: from all lookup 51819 suppress_prefixlength 0 proto static':
continue
output = check_output('ip -4 rule list table 51820')
if output != '11: not from all fwmark 0x38f lookup 51820 proto static':
continue
output = check_output('ip -6 rule list table 51820')
if output != '11: not from all fwmark 0x38f lookup 51820 proto static':
continue
break
else:
self.assertFalse(True)
@expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
def test_routing_policy_rule_port_range(self):
copy_network_unit('25-fibrule-port-range.network', '11-dummy.netdev')