mirror of
https://github.com/Dasharo/systemd.git
synced 2026-03-06 15:02:31 -08:00
Merge pull request #30433 from yuwata/network-nexthop-cleanups
network: introduce ManageForeignNextHops=
This commit is contained in:
@@ -90,6 +90,17 @@
|
||||
<xi:include href="version-info.xml" xpointer="v246"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>ManageForeignNextHops=</varname></term>
|
||||
<listitem><para>A boolean. When true, <command>systemd-networkd</command> will remove nexthops
|
||||
that are not configured in .network files (except for routes with protocol
|
||||
<literal>kernel</literal>). When false, it will
|
||||
not remove any foreign nexthops, keeping them even if they are not configured in a .network file.
|
||||
Defaults to yes.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>RouteTable=</varname></term>
|
||||
<listitem><para>Defines the route table name. Takes a whitespace-separated list of the pairs of
|
||||
|
||||
@@ -1715,8 +1715,10 @@ NFTSet=prefix:netdev:filter:eth_ipv4_prefix</programlisting>
|
||||
<varlistentry>
|
||||
<term><varname>Id=</varname></term>
|
||||
<listitem>
|
||||
<para>The id of the next hop. Takes an integer in the range 1…4294967295. If unspecified,
|
||||
then automatically chosen by kernel.</para>
|
||||
<para>The id of the next hop. Takes an integer in the range 1…4294967295.
|
||||
This is mandatory if <varname>ManageForeignNextHops=no</varname> is specified in
|
||||
<citerefentry><refentrytitle>networkd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
|
||||
Otherwise, if unspecified, an unused ID will be automatically picked.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v244"/>
|
||||
</listitem>
|
||||
|
||||
@@ -25,6 +25,7 @@ Network.SpeedMeter, config_parse_bool,
|
||||
Network.SpeedMeterIntervalSec, config_parse_sec, 0, offsetof(Manager, speed_meter_interval_usec)
|
||||
Network.ManageForeignRoutingPolicyRules, config_parse_bool, 0, offsetof(Manager, manage_foreign_rules)
|
||||
Network.ManageForeignRoutes, config_parse_bool, 0, offsetof(Manager, manage_foreign_routes)
|
||||
Network.ManageForeignNextHops, config_parse_bool, 0, offsetof(Manager, manage_foreign_nexthops)
|
||||
Network.RouteTable, config_parse_route_table_names, 0, 0
|
||||
Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions, 0, offsetof(Manager, ipv6_privacy_extensions)
|
||||
DHCPv4.DUIDType, config_parse_duid_type, 0, offsetof(Manager, dhcp_duid)
|
||||
|
||||
@@ -591,6 +591,7 @@ int manager_new(Manager **ret, bool test_mode) {
|
||||
.online_state = _LINK_ONLINE_STATE_INVALID,
|
||||
.manage_foreign_routes = true,
|
||||
.manage_foreign_rules = true,
|
||||
.manage_foreign_nexthops = true,
|
||||
.ethtool_fd = -EBADF,
|
||||
.dhcp_duid.type = DUID_TYPE_EN,
|
||||
.dhcp6_duid.type = DUID_TYPE_EN,
|
||||
@@ -867,6 +868,9 @@ static int manager_enumerate_nexthop(Manager *m) {
|
||||
assert(m);
|
||||
assert(m->rtnl);
|
||||
|
||||
if (!m->manage_foreign_nexthops)
|
||||
return 0;
|
||||
|
||||
r = sd_rtnl_message_new_nexthop(m->rtnl, &req, RTM_GETNEXTHOP, 0, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -38,6 +38,7 @@ struct Manager {
|
||||
bool restarting;
|
||||
bool manage_foreign_routes;
|
||||
bool manage_foreign_rules;
|
||||
bool manage_foreign_nexthops;
|
||||
|
||||
Set *dirty_links;
|
||||
Set *new_wlan_ifindices;
|
||||
|
||||
@@ -318,6 +318,10 @@ static int nexthop_acquire_id(Manager *manager, NextHop *nexthop) {
|
||||
if (nexthop->id > 0)
|
||||
return 0;
|
||||
|
||||
/* If ManageForeignNextHops=no, nexthop with id == 0 should be already filtered by
|
||||
* nexthop_section_verify(). */
|
||||
assert(manager->manage_foreign_nexthops);
|
||||
|
||||
/* Find the lowest unused ID. */
|
||||
|
||||
ORDERED_HASHMAP_FOREACH(network, manager->networks) {
|
||||
@@ -988,6 +992,13 @@ static int nexthop_section_verify(NextHop *nh) {
|
||||
if (section_is_invalid(nh->section))
|
||||
return -EINVAL;
|
||||
|
||||
if (!nh->network->manager->manage_foreign_nexthops && nh->id == 0)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: [NextHop] section without specifying Id= is not supported "
|
||||
"if ManageForeignNextHops=no is set in networkd.conf. "
|
||||
"Ignoring [NextHop] section from line %u.",
|
||||
nh->section->filename, nh->section->line);
|
||||
|
||||
if (!hashmap_isempty(nh->group)) {
|
||||
if (in_addr_is_set(nh->family, &nh->gw))
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#SpeedMeterIntervalSec=10sec
|
||||
#ManageForeignRoutingPolicyRules=yes
|
||||
#ManageForeignRoutes=yes
|
||||
#ManageForeignNextHops=yes
|
||||
#RouteTable=
|
||||
#IPv6PrivacyExtensions=no
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
[Network]
|
||||
ManageForeignNextHops=no
|
||||
@@ -3284,8 +3284,6 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
|
||||
print(output)
|
||||
self.assertEqual(output, '')
|
||||
|
||||
self.tearDown()
|
||||
|
||||
def test_route_static(self):
|
||||
first = True
|
||||
for manage_foreign_routes in [True, False]:
|
||||
@@ -3844,74 +3842,86 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
|
||||
self.assertRegex(output, 'inet 10.1.2.3/16 scope global dummy98')
|
||||
self.assertNotRegex(output, 'inet 10.2.3.4/16 scope global dynamic dummy98')
|
||||
|
||||
@expectedFailureIfNexthopIsNotAvailable()
|
||||
def test_nexthop(self):
|
||||
def check_nexthop(self):
|
||||
self.wait_online(['veth99:routable', 'veth-peer:routable', 'dummy98:routable'])
|
||||
def check_nexthop(self, manage_foreign_nexthops):
|
||||
self.wait_online(['veth99:routable', 'veth-peer:routable', 'dummy98:routable'])
|
||||
|
||||
output = check_output('ip nexthop list dev veth99')
|
||||
print(output)
|
||||
self.assertIn('id 1 via 192.168.5.1 dev veth99', output)
|
||||
self.assertIn('id 2 via 2001:1234:5:8f63::2 dev veth99', output)
|
||||
self.assertIn('id 3 dev veth99', output)
|
||||
self.assertIn('id 4 dev veth99', output)
|
||||
self.assertRegex(output, 'id 5 via 192.168.10.1 dev veth99 .*onlink')
|
||||
self.assertIn('id 8 via fe80:0:222:4dff:ff:ff:ff:ff dev veth99', output)
|
||||
output = check_output('ip nexthop list dev veth99')
|
||||
print(output)
|
||||
self.assertIn('id 1 via 192.168.5.1 dev veth99', output)
|
||||
self.assertIn('id 2 via 2001:1234:5:8f63::2 dev veth99', output)
|
||||
self.assertIn('id 3 dev veth99', output)
|
||||
self.assertIn('id 4 dev veth99', output)
|
||||
self.assertRegex(output, 'id 5 via 192.168.10.1 dev veth99 .*onlink')
|
||||
self.assertIn('id 8 via fe80:0:222:4dff:ff:ff:ff:ff dev veth99', output)
|
||||
if manage_foreign_nexthops:
|
||||
self.assertRegex(output, r'id [0-9]* via 192.168.5.2 dev veth99')
|
||||
|
||||
output = check_output('ip nexthop list dev dummy98')
|
||||
print(output)
|
||||
self.assertIn('id 20 via 192.168.20.1 dev dummy98', output)
|
||||
output = check_output('ip nexthop list dev dummy98')
|
||||
print(output)
|
||||
self.assertIn('id 20 via 192.168.20.1 dev dummy98', output)
|
||||
if manage_foreign_nexthops:
|
||||
self.assertNotIn('id 42 via 192.168.20.2 dev dummy98', output)
|
||||
else:
|
||||
self.assertIn('id 42 via 192.168.20.2 dev dummy98', output)
|
||||
|
||||
# kernel manages blackhole nexthops on lo
|
||||
output = check_output('ip nexthop list dev lo')
|
||||
print(output)
|
||||
self.assertIn('id 6 blackhole', output)
|
||||
self.assertIn('id 7 blackhole', output)
|
||||
# kernel manages blackhole nexthops on lo
|
||||
output = check_output('ip nexthop list dev lo')
|
||||
print(output)
|
||||
self.assertIn('id 6 blackhole', output)
|
||||
self.assertIn('id 7 blackhole', output)
|
||||
|
||||
# group nexthops are shown with -0 option
|
||||
output = check_output('ip -0 nexthop list id 21')
|
||||
print(output)
|
||||
self.assertRegex(output, r'id 21 group (1,3/20|20/1,3)')
|
||||
# group nexthops are shown with -0 option
|
||||
output = check_output('ip -0 nexthop list id 21')
|
||||
print(output)
|
||||
self.assertRegex(output, r'id 21 group (1,3/20|20/1,3)')
|
||||
|
||||
output = check_output('ip route show dev veth99 10.10.10.10')
|
||||
print(output)
|
||||
self.assertEqual('10.10.10.10 nhid 1 via 192.168.5.1 proto static', output)
|
||||
output = check_output('ip route show dev veth99 10.10.10.10')
|
||||
print(output)
|
||||
self.assertEqual('10.10.10.10 nhid 1 via 192.168.5.1 proto static', output)
|
||||
|
||||
output = check_output('ip route show dev veth99 10.10.10.11')
|
||||
print(output)
|
||||
self.assertEqual('10.10.10.11 nhid 2 via inet6 2001:1234:5:8f63::2 proto static', output)
|
||||
output = check_output('ip route show dev veth99 10.10.10.11')
|
||||
print(output)
|
||||
self.assertEqual('10.10.10.11 nhid 2 via inet6 2001:1234:5:8f63::2 proto static', output)
|
||||
|
||||
output = check_output('ip route show dev veth99 10.10.10.12')
|
||||
print(output)
|
||||
self.assertEqual('10.10.10.12 nhid 5 via 192.168.10.1 proto static onlink', output)
|
||||
output = check_output('ip route show dev veth99 10.10.10.12')
|
||||
print(output)
|
||||
self.assertEqual('10.10.10.12 nhid 5 via 192.168.10.1 proto static onlink', output)
|
||||
|
||||
output = check_output('ip -6 route show dev veth99 2001:1234:5:8f62::1')
|
||||
print(output)
|
||||
self.assertEqual('2001:1234:5:8f62::1 nhid 2 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium', output)
|
||||
output = check_output('ip -6 route show dev veth99 2001:1234:5:8f62::1')
|
||||
print(output)
|
||||
self.assertEqual('2001:1234:5:8f62::1 nhid 2 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium', output)
|
||||
|
||||
output = check_output('ip route show 10.10.10.13')
|
||||
print(output)
|
||||
self.assertEqual('blackhole 10.10.10.13 nhid 6 dev lo proto static', output)
|
||||
output = check_output('ip route show 10.10.10.13')
|
||||
print(output)
|
||||
self.assertEqual('blackhole 10.10.10.13 nhid 6 dev lo proto static', output)
|
||||
|
||||
output = check_output('ip -6 route show 2001:1234:5:8f62::2')
|
||||
print(output)
|
||||
self.assertEqual('blackhole 2001:1234:5:8f62::2 nhid 7 dev lo proto static metric 1024 pref medium', output)
|
||||
output = check_output('ip -6 route show 2001:1234:5:8f62::2')
|
||||
print(output)
|
||||
self.assertEqual('blackhole 2001:1234:5:8f62::2 nhid 7 dev lo proto static metric 1024 pref medium', output)
|
||||
|
||||
output = check_output('ip route show 10.10.10.14')
|
||||
print(output)
|
||||
self.assertIn('10.10.10.14 nhid 21 proto static', output)
|
||||
self.assertIn('nexthop via 192.168.20.1 dev dummy98 weight 1', output)
|
||||
self.assertIn('nexthop via 192.168.5.1 dev veth99 weight 3', output)
|
||||
output = check_output('ip route show 10.10.10.14')
|
||||
print(output)
|
||||
self.assertIn('10.10.10.14 nhid 21 proto static', output)
|
||||
self.assertIn('nexthop via 192.168.20.1 dev dummy98 weight 1', output)
|
||||
self.assertIn('nexthop via 192.168.5.1 dev veth99 weight 3', output)
|
||||
|
||||
output = check_output(*networkctl_cmd, '--json=short', 'status', env=env)
|
||||
check_json(output)
|
||||
output = check_output(*networkctl_cmd, '--json=short', 'status', env=env)
|
||||
check_json(output)
|
||||
|
||||
def _test_nexthop(self, manage_foreign_nexthops):
|
||||
if not manage_foreign_nexthops:
|
||||
copy_networkd_conf_dropin('networkd-manage-foreign-nexthops-no.conf')
|
||||
|
||||
check_output('ip link add dummy98 type dummy')
|
||||
check_output('ip link set dummy98 up')
|
||||
check_output('ip address add 192.168.20.20/24 dev dummy98')
|
||||
check_output('ip nexthop add id 42 via 192.168.20.2 dev dummy98')
|
||||
|
||||
copy_network_unit('25-nexthop.network', '25-veth.netdev', '25-veth-peer.network',
|
||||
'12-dummy.netdev', '25-nexthop-dummy.network')
|
||||
start_networkd()
|
||||
|
||||
check_nexthop(self)
|
||||
self.check_nexthop(manage_foreign_nexthops)
|
||||
|
||||
remove_network_unit('25-nexthop.network')
|
||||
copy_network_unit('25-nexthop-nothing.network')
|
||||
@@ -3930,7 +3940,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
|
||||
networkctl_reconfigure('dummy98')
|
||||
networkctl_reload()
|
||||
|
||||
check_nexthop(self)
|
||||
self.check_nexthop(manage_foreign_nexthops)
|
||||
|
||||
remove_link('veth99')
|
||||
time.sleep(2)
|
||||
@@ -3939,6 +3949,19 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
|
||||
print(output)
|
||||
self.assertEqual(output, '')
|
||||
|
||||
@expectedFailureIfNexthopIsNotAvailable()
|
||||
def test_nexthop(self):
|
||||
first = True
|
||||
for manage_foreign_nexthops in [True, False]:
|
||||
if first:
|
||||
first = False
|
||||
else:
|
||||
self.tearDown()
|
||||
|
||||
print(f'### test_nexthop(manage_foreign_nexthops={manage_foreign_nexthops})')
|
||||
with self.subTest(manage_foreign_nexthops=manage_foreign_nexthops):
|
||||
self._test_nexthop(manage_foreign_nexthops)
|
||||
|
||||
class NetworkdTCTests(unittest.TestCase, Utilities):
|
||||
|
||||
def setUp(self):
|
||||
|
||||
Reference in New Issue
Block a user