2 # SPDX-License-Identifier: LGPL-2.1+
3 # systemd-networkd tests
14 from shutil
import copytree
16 network_unit_file_path
='/run/systemd/network'
17 networkd_runtime_directory
='/run/systemd/netif'
18 networkd_ci_path
='/run/networkd-ci'
19 network_sysctl_ipv6_path
='/proc/sys/net/ipv6/conf'
20 network_sysctl_ipv4_path
='/proc/sys/net/ipv4/conf'
22 dnsmasq_pid_file
='/run/networkd-ci/test-test-dnsmasq.pid'
23 dnsmasq_log_file
='/run/networkd-ci/test-dnsmasq-log-file'
25 networkd_bin
='/usr/lib/systemd/systemd-networkd'
26 wait_online_bin
='/usr/lib/systemd/systemd-networkd-wait-online'
27 networkctl_bin
='/usr/bin/networkctl'
35 def check_output(*command
, **kwargs
):
36 # This replaces both check_output and check_call (output can be ignored)
37 command
= command
[0].split() + list(command
[1:])
38 return subprocess
.check_output(command
, universal_newlines
=True, **kwargs
).rstrip()
40 def call(*command
, **kwargs
):
41 command
= command
[0].split() + list(command
[1:])
42 return subprocess
.call(command
, universal_newlines
=True, **kwargs
)
44 def run(*command
, **kwargs
):
45 command
= command
[0].split() + list(command
[1:])
46 return subprocess
.run(command
, universal_newlines
=True, **kwargs
)
48 def is_module_available(module_name
):
49 lsmod_output
= check_output('lsmod')
50 module_re
= re
.compile(rf
'^{re.escape(module_name)}\b', re
.MULTILINE
)
51 return module_re
.search(lsmod_output
) or not call('modprobe', module_name
)
53 def expectedFailureIfModuleIsNotAvailable(module_name
):
55 if not is_module_available(module_name
):
56 return unittest
.expectedFailure(func
)
61 def expectedFailureIfERSPANModuleIsNotAvailable():
63 rc
= call('ip link add dev erspan99 type erspan seq key 30 local 192.168.1.4 remote 192.168.1.1 erspan_ver 1 erspan 123')
65 call('ip link del erspan99')
68 return unittest
.expectedFailure(func
)
72 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable():
74 rc
= call('ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
76 call('ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
79 return unittest
.expectedFailure(func
)
83 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
85 rc
= call('ip rule add not from 192.168.100.19 ipproto tcp table 7')
87 call('ip rule del not from 192.168.100.19 ipproto tcp table 7')
90 return unittest
.expectedFailure(func
)
94 def expectedFailureIfEthtoolDoesNotSupportDriver():
97 rc
= call('ip link add name dummy99 type dummy')
99 ret
= run('udevadm info -w10s /sys/class/net/dummy99', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
100 if ret
.returncode
== 0 and 'E: ID_NET_DRIVER=dummy' in ret
.stdout
.rstrip():
102 call('ip link del dummy99')
107 return unittest
.expectedFailure(func
)
112 os
.makedirs(network_unit_file_path
, exist_ok
=True)
113 os
.makedirs(networkd_ci_path
, exist_ok
=True)
115 shutil
.rmtree(networkd_ci_path
)
116 copytree(os
.path
.join(os
.path
.dirname(os
.path
.abspath(__file__
)), 'conf'), networkd_ci_path
)
118 check_output('systemctl stop systemd-networkd.socket')
119 check_output('systemctl stop systemd-networkd.service')
128 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin
,
132 drop_in
+= ['ExecStart=!!' + networkd_bin
]
134 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
136 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
138 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
140 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
141 if asan_options
or lsan_options
or ubsan_options
:
142 drop_in
+= ['SystemCallFilter=']
143 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
144 drop_in
+= ['MemoryDenyWriteExecute=no']
146 os
.makedirs('/run/systemd/system/systemd-networkd.service.d', exist_ok
=True)
147 with
open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode
='w') as f
:
148 f
.write('\n'.join(drop_in
))
150 check_output('systemctl daemon-reload')
151 print(check_output('systemctl cat systemd-networkd.service'))
153 def tearDownModule():
154 shutil
.rmtree(networkd_ci_path
)
156 check_output('systemctl stop systemd-networkd.service')
158 shutil
.rmtree('/run/systemd/system/systemd-networkd.service.d')
159 check_output('systemctl daemon-reload')
161 check_output('systemctl start systemd-networkd.socket')
162 check_output('systemctl start systemd-networkd.service')
164 def read_link_attr(link
, dev
, attribute
):
165 with
open(os
.path
.join(os
.path
.join(os
.path
.join('/sys/class/net/', link
), dev
), attribute
)) as f
:
166 return f
.readline().strip()
168 def read_bridge_port_attr(bridge
, link
, attribute
):
169 path_bridge
= os
.path
.join('/sys/devices/virtual/net', bridge
)
170 path_port
= 'lower_' + link
+ '/brport'
171 path
= os
.path
.join(path_bridge
, path_port
)
173 with
open(os
.path
.join(path
, attribute
)) as f
:
174 return f
.readline().strip()
176 def link_exists(link
):
177 return os
.path
.exists(os
.path
.join('/sys/class/net', link
))
179 def remove_links(links
):
181 if link_exists(link
):
182 call('ip link del dev', link
)
185 def remove_fou_ports(ports
):
187 call('ip fou del port', port
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
189 def remove_routing_policy_rule_tables(tables
):
193 rc
= call('ip rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
195 def remove_routes(routes
):
196 for route_type
, addr
in routes
:
197 call('ip route del', route_type
, addr
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
199 def remove_l2tp_tunnels(tunnel_ids
):
200 output
= check_output('ip l2tp show tunnel')
201 for tid
in tunnel_ids
:
202 words
='Tunnel ' + tid
+ ', encap'
204 call('ip l2tp del tunnel tid', tid
)
207 def read_ipv6_sysctl_attr(link
, attribute
):
208 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, link
), attribute
)) as f
:
209 return f
.readline().strip()
211 def read_ipv4_sysctl_attr(link
, attribute
):
212 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv4_path
, link
), attribute
)) as f
:
213 return f
.readline().strip()
215 def copy_unit_to_networkd_unit_path(*units
):
218 shutil
.copy(os
.path
.join(networkd_ci_path
, unit
), network_unit_file_path
)
219 if (os
.path
.exists(os
.path
.join(networkd_ci_path
, unit
+ '.d'))):
220 copytree(os
.path
.join(networkd_ci_path
, unit
+ '.d'), os
.path
.join(network_unit_file_path
, unit
+ '.d'))
222 def remove_unit_from_networkd_path(units
):
224 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
))):
225 os
.remove(os
.path
.join(network_unit_file_path
, unit
))
226 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
+ '.d'))):
227 shutil
.rmtree(os
.path
.join(network_unit_file_path
, unit
+ '.d'))
229 def warn_about_firewalld():
230 rc
= call('systemctl -q is-active firewalld.service')
232 print('\nWARNING: firewalld.service is active. The test may fail.')
234 def start_dnsmasq(additional_options
='', ipv4_range
='192.168.5.10,192.168.5.200', ipv6_range
='2600::10,2600::20', lease_time
='1h'):
235 warn_about_firewalld()
236 dnsmasq_command
= f
'dnsmasq -8 /var/run/networkd-ci/test-dnsmasq-log-file --log-queries=extra --log-dhcp --pid-file=/var/run/networkd-ci/test-test-dnsmasq.pid --conf-file=/dev/null --interface=veth-peer --enable-ra --dhcp-range={ipv6_range},{lease_time} --dhcp-range={ipv4_range},{lease_time} -R --dhcp-leasefile=/var/run/networkd-ci/lease --dhcp-option=26,1492 --dhcp-option=option:router,192.168.5.1 --dhcp-option=33,192.168.5.4,192.168.5.5 --port=0 ' + additional_options
237 check_output(dnsmasq_command
)
239 def stop_dnsmasq(pid_file
):
240 if os
.path
.exists(pid_file
):
241 with
open(pid_file
, 'r') as f
:
242 pid
= f
.read().rstrip(' \t\r\n\0')
243 os
.kill(int(pid
), signal
.SIGTERM
)
247 def search_words_in_dnsmasq_log(words
, show_all
=False):
248 if os
.path
.exists(dnsmasq_log_file
):
249 with
open (dnsmasq_log_file
) as in_file
:
250 contents
= in_file
.read()
253 for line
in contents
.splitlines():
256 print("%s, %s" % (words
, line
))
260 def remove_lease_file():
261 if os
.path
.exists(os
.path
.join(networkd_ci_path
, 'lease')):
262 os
.remove(os
.path
.join(networkd_ci_path
, 'lease'))
264 def remove_log_file():
265 if os
.path
.exists(dnsmasq_log_file
):
266 os
.remove(dnsmasq_log_file
)
268 def start_networkd(sleep_sec
=0, remove_state_files
=True):
269 if (remove_state_files
and
270 os
.path
.exists(os
.path
.join(networkd_runtime_directory
, 'state'))):
271 check_output('systemctl stop systemd-networkd')
272 os
.remove(os
.path
.join(networkd_runtime_directory
, 'state'))
273 check_output('systemctl start systemd-networkd')
275 check_output('systemctl restart systemd-networkd')
277 time
.sleep(sleep_sec
)
279 def wait_online(links_with_operstate
, timeout
='20s', bool_any
=False):
280 args
= wait_online_cmd
+ [f
'--timeout={timeout}'] + [f
'--interface={link}' for link
in links_with_operstate
]
284 check_output(*args
, env
=env
)
285 except subprocess
.CalledProcessError
:
286 for link
in links_with_operstate
:
287 output
= check_output(*networkctl_cmd
, 'status', link
.split(':')[0], env
=env
)
291 def get_operstate(link
, show_status
=True, setup_state
='configured'):
292 output
= check_output(*networkctl_cmd
, 'status', link
, env
=env
)
295 for line
in output
.splitlines():
296 if 'State:' in line
and (not setup_state
or setup_state
in line
):
297 return line
.split()[1]
301 def check_link_exists(self
, link
):
302 self
.assertTrue(link_exists(link
))
304 def check_operstate(self
, link
, expected
, show_status
=True, setup_state
='configured'):
305 self
.assertRegex(get_operstate(link
, show_status
, setup_state
), expected
)
307 def wait_address(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
308 for i
in range(timeout_sec
):
311 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
312 if re
.search(address_regex
, output
):
315 self
.assertRegex(output
, address_regex
)
317 class NetworkctlTests(unittest
.TestCase
, Utilities
):
326 '11-dummy-mtu.netdev',
329 'netdev-link-local-addressing-yes.network',
333 remove_links(self
.links
)
336 remove_links(self
.links
)
337 remove_unit_from_networkd_path(self
.units
)
340 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
343 wait_online(['test1:degraded'])
345 output
= check_output(*networkctl_cmd
, 'list', env
=env
)
346 self
.assertRegex(output
, '1 lo ')
347 self
.assertRegex(output
, 'test1')
349 output
= check_output(*networkctl_cmd
, 'list', 'test1', env
=env
)
350 self
.assertNotRegex(output
, '1 lo ')
351 self
.assertRegex(output
, 'test1')
353 output
= check_output(*networkctl_cmd
, 'list', 'te*', env
=env
)
354 self
.assertNotRegex(output
, '1 lo ')
355 self
.assertRegex(output
, 'test1')
357 output
= check_output(*networkctl_cmd
, 'status', 'te*', env
=env
)
358 self
.assertNotRegex(output
, '1: lo ')
359 self
.assertRegex(output
, 'test1')
361 output
= check_output(*networkctl_cmd
, 'status', 'tes[a-z][0-9]', env
=env
)
362 self
.assertNotRegex(output
, '1: lo ')
363 self
.assertRegex(output
, 'test1')
366 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
369 wait_online(['test1:degraded'])
371 output
= check_output(*networkctl_cmd
, 'status', 'test1', env
=env
)
372 self
.assertRegex(output
, 'MTU: 1600')
374 @expectedFailureIfEthtoolDoesNotSupportDriver()
375 def test_udev_driver(self
):
376 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
377 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
380 wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
382 output
= check_output(*networkctl_cmd
, 'status', 'test1', env
=env
)
383 self
.assertRegex(output
, 'Driver: dummy')
385 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
386 self
.assertRegex(output
, 'Driver: veth')
388 output
= check_output(*networkctl_cmd
, 'status', 'veth-peer', env
=env
)
389 self
.assertRegex(output
, 'Driver: veth')
391 def test_delete_links(self
):
392 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
393 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
396 wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
398 check_output(*networkctl_cmd
, 'delete', 'test1', 'veth99')
399 self
.assertFalse(link_exists('test1'))
400 self
.assertFalse(link_exists('veth99'))
401 self
.assertFalse(link_exists('veth-peer'))
403 class NetworkdNetDevTests(unittest
.TestCase
, Utilities
):
462 '10-dropin-test.netdev',
466 '13-not-match-udev-property.network',
467 '14-match-udev-property.network',
468 '15-name-conflict-test.netdev',
471 '21-vlan-test1.network',
474 '25-6rd-tunnel.netdev',
476 '25-bond-balanced-tlb.netdev',
478 '25-bridge-configure-without-carrier.network',
480 '25-erspan-tunnel-local-any.netdev',
481 '25-erspan-tunnel.netdev',
482 '25-fou-gretap.netdev',
484 '25-fou-ipip.netdev',
485 '25-fou-ipproto-gre.netdev',
486 '25-fou-ipproto-ipip.netdev',
489 '25-gretap-tunnel-local-any.netdev',
490 '25-gretap-tunnel.netdev',
491 '25-gre-tunnel-local-any.netdev',
492 '25-gre-tunnel-remote-any.netdev',
493 '25-gre-tunnel.netdev',
494 '25-ip6gretap-tunnel-local-any.netdev',
495 '25-ip6gretap-tunnel.netdev',
496 '25-ip6gre-tunnel-local-any.netdev',
497 '25-ip6gre-tunnel-remote-any.netdev',
498 '25-ip6gre-tunnel.netdev',
499 '25-ip6tnl-tunnel-remote-any.netdev',
500 '25-ip6tnl-tunnel-local-any.netdev',
501 '25-ip6tnl-tunnel.netdev',
502 '25-ipip-tunnel-independent.netdev',
503 '25-ipip-tunnel-local-any.netdev',
504 '25-ipip-tunnel-remote-any.netdev',
505 '25-ipip-tunnel.netdev',
508 '25-isatap-tunnel.netdev',
513 '25-sit-tunnel-local-any.netdev',
514 '25-sit-tunnel-remote-any.netdev',
515 '25-sit-tunnel.netdev',
518 '25-tunnel-local-any.network',
519 '25-tunnel-remote-any.network',
524 '25-vti6-tunnel-local-any.netdev',
525 '25-vti6-tunnel-remote-any.netdev',
526 '25-vti6-tunnel.netdev',
527 '25-vti-tunnel-local-any.netdev',
528 '25-vti-tunnel-remote-any.netdev',
529 '25-vti-tunnel.netdev',
532 '25-wireguard-23-peers.netdev',
533 '25-wireguard-23-peers.network',
534 '25-wireguard-preshared-key.txt',
535 '25-wireguard-private-key.txt',
536 '25-wireguard.netdev',
537 '25-wireguard.network',
553 'netdev-link-local-addressing-yes.network',
557 'vxlan-test1.network',
565 remove_fou_ports(self
.fou_ports
)
566 remove_links(self
.links
)
569 remove_fou_ports(self
.fou_ports
)
570 remove_links(self
.links
)
571 remove_unit_from_networkd_path(self
.units
)
573 def test_dropin_and_name_conflict(self
):
574 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
577 wait_online(['dropin-test:off'])
579 output
= check_output('ip link show dropin-test')
581 self
.assertRegex(output
, '00:50:56:c0:00:28')
583 def test_match_udev_property(self
):
584 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
586 wait_online(['dummy98:routable'])
588 output
= check_output('networkctl status dummy98')
590 self
.assertRegex(output
, 'Network File: /run/systemd/network/14-match-udev-property')
592 def test_wait_online_any(self
):
593 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
596 wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
598 self
.check_operstate('bridge99', '(?:off|no-carrier)', setup_state
='configuring')
599 self
.check_operstate('test1', 'degraded')
601 def test_bridge(self
):
602 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
605 wait_online(['bridge99:no-carrier'])
607 tick
= os
.sysconf('SC_CLK_TCK')
608 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
609 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
610 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge','forward_delay')) / tick
))
611 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge','ageing_time')) / tick
))
612 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge','priority')))
613 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','multicast_querier')))
614 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','multicast_snooping')))
615 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','stp_state')))
618 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
621 wait_online(['bond99:off', 'bond98:off'])
623 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
624 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
625 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
626 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
627 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
628 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
629 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
630 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
631 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
632 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
633 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
635 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
636 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
639 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
640 '21-vlan.network', '21-vlan-test1.network')
643 wait_online(['test1:degraded', 'vlan99:routable'])
645 output
= check_output('ip -d link show test1')
647 self
.assertRegex(output
, ' mtu 2000 ')
649 output
= check_output('ip -d link show vlan99')
651 self
.assertRegex(output
, ' mtu 2000 ')
652 self
.assertRegex(output
, 'REORDER_HDR')
653 self
.assertRegex(output
, 'LOOSE_BINDING')
654 self
.assertRegex(output
, 'GVRP')
655 self
.assertRegex(output
, 'MVRP')
656 self
.assertRegex(output
, ' id 99 ')
658 output
= check_output('ip -4 address show dev test1')
660 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
661 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
663 output
= check_output('ip -4 address show dev vlan99')
665 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
667 def test_macvtap(self
):
668 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
669 with self
.subTest(mode
=mode
):
670 if mode
!= 'private':
672 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
673 '11-dummy.netdev', 'macvtap.network')
674 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
675 f
.write('[MACVTAP]\nMode=' + mode
)
678 wait_online(['macvtap99:degraded', 'test1:degraded'])
680 output
= check_output('ip -d link show macvtap99')
682 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
684 def test_macvlan(self
):
685 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
686 with self
.subTest(mode
=mode
):
687 if mode
!= 'private':
689 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
690 '11-dummy.netdev', 'macvlan.network')
691 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
692 f
.write('[MACVLAN]\nMode=' + mode
)
695 wait_online(['macvlan99:degraded', 'test1:degraded'])
697 output
= check_output('ip -d link show test1')
699 self
.assertRegex(output
, ' mtu 2000 ')
701 output
= check_output('ip -d link show macvlan99')
703 self
.assertRegex(output
, ' mtu 2000 ')
704 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
706 @expectedFailureIfModuleIsNotAvailable('ipvlan')
707 def test_ipvlan(self
):
708 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
709 with self
.subTest(mode
=mode
, flag
=flag
):
712 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
713 '11-dummy.netdev', 'ipvlan.network')
714 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
715 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
718 wait_online(['ipvlan99:degraded', 'test1:degraded'])
720 output
= check_output('ip -d link show ipvlan99')
722 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
724 @expectedFailureIfModuleIsNotAvailable('ipvtap')
725 def test_ipvtap(self
):
726 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
727 with self
.subTest(mode
=mode
, flag
=flag
):
730 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
731 '11-dummy.netdev', 'ipvtap.network')
732 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
733 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
736 wait_online(['ipvtap99:degraded', 'test1:degraded'])
738 output
= check_output('ip -d link show ipvtap99')
740 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
743 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
746 wait_online(['veth99:degraded', 'veth-peer:degraded'])
748 output
= check_output('ip -d link show veth99')
750 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
751 output
= check_output('ip -d link show veth-peer')
753 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
756 copy_unit_to_networkd_unit_path('25-tun.netdev')
759 wait_online(['tun99:off'])
761 output
= check_output('ip -d link show tun99')
763 # Old ip command does not support IFF_ flags
764 self
.assertRegex(output
, 'tun (?:type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
767 copy_unit_to_networkd_unit_path('25-tap.netdev')
770 wait_online(['tap99:off'])
772 output
= check_output('ip -d link show tap99')
774 # Old ip command does not support IFF_ flags
775 self
.assertRegex(output
, 'tun (?:type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
777 @expectedFailureIfModuleIsNotAvailable('vrf')
779 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
782 wait_online(['vrf99:carrier'])
784 @expectedFailureIfModuleIsNotAvailable('vcan')
786 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
789 wait_online(['vcan99:carrier'])
791 @expectedFailureIfModuleIsNotAvailable('vxcan')
792 def test_vxcan(self
):
793 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
796 wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
798 @expectedFailureIfModuleIsNotAvailable('wireguard')
799 def test_wireguard(self
):
800 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
801 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
802 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt')
804 wait_online(['wg99:carrier', 'wg98:routable'])
806 if shutil
.which('wg'):
809 output
= check_output('wg show wg99 listen-port')
810 self
.assertRegex(output
, '51820')
811 output
= check_output('wg show wg99 fwmark')
812 self
.assertRegex(output
, '0x4d2')
813 output
= check_output('wg show wg99 allowed-ips')
814 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
815 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
816 output
= check_output('wg show wg99 persistent-keepalive')
817 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
818 output
= check_output('wg show wg99 endpoints')
819 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
820 output
= check_output('wg show wg99 private-key')
821 self
.assertRegex(output
, r
'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
822 output
= check_output('wg show wg99 preshared-keys')
823 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
824 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
826 output
= check_output('wg show wg98 private-key')
827 self
.assertRegex(output
, r
'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
829 def test_geneve(self
):
830 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
833 wait_online(['geneve99:degraded'])
835 output
= check_output('ip -d link show geneve99')
837 self
.assertRegex(output
, '192.168.22.1')
838 self
.assertRegex(output
, '6082')
839 self
.assertRegex(output
, 'udpcsum')
840 self
.assertRegex(output
, 'udp6zerocsumrx')
842 def test_ipip_tunnel(self
):
843 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
844 '25-ipip-tunnel.netdev', '25-tunnel.network',
845 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
846 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
848 wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'dummy98:degraded'])
850 output
= check_output('ip -d link show ipiptun99')
852 self
.assertRegex(output
, 'ipip (?:ipip |)remote 192.169.224.239 local 192.168.223.238 dev dummy98')
853 output
= check_output('ip -d link show ipiptun98')
855 self
.assertRegex(output
, 'ipip (?:ipip |)remote 192.169.224.239 local any dev dummy98')
856 output
= check_output('ip -d link show ipiptun97')
858 self
.assertRegex(output
, 'ipip (?:ipip |)remote any local 192.168.223.238 dev dummy98')
860 def test_gre_tunnel(self
):
861 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
862 '25-gre-tunnel.netdev', '25-tunnel.network',
863 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
864 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
866 wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'dummy98:degraded'])
868 output
= check_output('ip -d link show gretun99')
870 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
871 self
.assertRegex(output
, 'ikey 1.2.3.103')
872 self
.assertRegex(output
, 'okey 1.2.4.103')
873 self
.assertRegex(output
, 'iseq')
874 self
.assertRegex(output
, 'oseq')
875 output
= check_output('ip -d link show gretun98')
877 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
878 self
.assertRegex(output
, 'ikey 0.0.0.104')
879 self
.assertRegex(output
, 'okey 0.0.0.104')
880 self
.assertNotRegex(output
, 'iseq')
881 self
.assertNotRegex(output
, 'oseq')
882 output
= check_output('ip -d link show gretun97')
884 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
885 self
.assertRegex(output
, 'ikey 0.0.0.105')
886 self
.assertRegex(output
, 'okey 0.0.0.105')
887 self
.assertNotRegex(output
, 'iseq')
888 self
.assertNotRegex(output
, 'oseq')
890 def test_ip6gre_tunnel(self
):
891 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
892 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
893 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
894 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
897 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
899 self
.check_link_exists('dummy98')
900 self
.check_link_exists('ip6gretun99')
901 self
.check_link_exists('ip6gretun98')
902 self
.check_link_exists('ip6gretun97')
904 output
= check_output('ip -d link show ip6gretun99')
906 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
907 output
= check_output('ip -d link show ip6gretun98')
909 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
910 output
= check_output('ip -d link show ip6gretun97')
912 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
914 def test_gretap_tunnel(self
):
915 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
916 '25-gretap-tunnel.netdev', '25-tunnel.network',
917 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
919 wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
921 output
= check_output('ip -d link show gretap99')
923 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
924 self
.assertRegex(output
, 'ikey 0.0.0.106')
925 self
.assertRegex(output
, 'okey 0.0.0.106')
926 self
.assertRegex(output
, 'iseq')
927 self
.assertRegex(output
, 'oseq')
928 output
= check_output('ip -d link show gretap98')
930 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
931 self
.assertRegex(output
, 'ikey 0.0.0.107')
932 self
.assertRegex(output
, 'okey 0.0.0.107')
933 self
.assertRegex(output
, 'iseq')
934 self
.assertRegex(output
, 'oseq')
936 def test_ip6gretap_tunnel(self
):
937 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
938 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
939 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
941 wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
943 output
= check_output('ip -d link show ip6gretap99')
945 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
946 output
= check_output('ip -d link show ip6gretap98')
948 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
950 def test_vti_tunnel(self
):
951 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
952 '25-vti-tunnel.netdev', '25-tunnel.network',
953 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
954 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
956 wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'dummy98:degraded'])
958 output
= check_output('ip -d link show vtitun99')
960 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
961 output
= check_output('ip -d link show vtitun98')
963 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
964 output
= check_output('ip -d link show vtitun97')
966 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
968 def test_vti6_tunnel(self
):
969 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
970 '25-vti6-tunnel.netdev', '25-tunnel.network',
971 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
972 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
974 wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
976 output
= check_output('ip -d link show vti6tun99')
978 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
979 output
= check_output('ip -d link show vti6tun98')
981 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
982 output
= check_output('ip -d link show vti6tun97')
984 self
.assertRegex(output
, 'vti6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
986 def test_ip6tnl_tunnel(self
):
987 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
988 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
989 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
990 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
992 wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
994 output
= check_output('ip -d link show ip6tnl99')
996 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
997 output
= check_output('ip -d link show ip6tnl98')
999 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
1000 output
= check_output('ip -d link show ip6tnl97')
1002 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1004 def test_sit_tunnel(self
):
1005 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1006 '25-sit-tunnel.netdev', '25-tunnel.network',
1007 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1008 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1010 wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'dummy98:degraded'])
1012 output
= check_output('ip -d link show sittun99')
1014 self
.assertRegex(output
, "sit (?:ip6ip |)remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1015 output
= check_output('ip -d link show sittun98')
1017 self
.assertRegex(output
, "sit (?:ip6ip |)remote 10.65.223.239 local any dev dummy98")
1018 output
= check_output('ip -d link show sittun97')
1020 self
.assertRegex(output
, "sit (?:ip6ip |)remote any local 10.65.223.238 dev dummy98")
1022 def test_isatap_tunnel(self
):
1023 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1024 '25-isatap-tunnel.netdev', '25-tunnel.network')
1026 wait_online(['isataptun99:routable', 'dummy98:degraded'])
1028 output
= check_output('ip -d link show isataptun99')
1030 self
.assertRegex(output
, "isatap ")
1032 def test_6rd_tunnel(self
):
1033 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1034 '25-6rd-tunnel.netdev', '25-tunnel.network')
1036 wait_online(['sittun99:routable', 'dummy98:degraded'])
1038 output
= check_output('ip -d link show sittun99')
1040 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1042 @expectedFailureIfERSPANModuleIsNotAvailable()
1043 def test_erspan_tunnel(self
):
1044 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1045 '25-erspan-tunnel.netdev', '25-tunnel.network',
1046 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1048 wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1050 output
= check_output('ip -d link show erspan99')
1052 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1053 self
.assertRegex(output
, 'ikey 0.0.0.101')
1054 self
.assertRegex(output
, 'okey 0.0.0.101')
1055 self
.assertRegex(output
, 'iseq')
1056 self
.assertRegex(output
, 'oseq')
1057 output
= check_output('ip -d link show erspan98')
1059 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1060 self
.assertRegex(output
, '102')
1061 self
.assertRegex(output
, 'ikey 0.0.0.102')
1062 self
.assertRegex(output
, 'okey 0.0.0.102')
1063 self
.assertRegex(output
, 'iseq')
1064 self
.assertRegex(output
, 'oseq')
1066 def test_tunnel_independent(self
):
1067 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1070 wait_online(['ipiptun99:carrier'])
1072 @expectedFailureIfModuleIsNotAvailable('fou')
1074 # The following redundant check is necessary for CentOS CI.
1075 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1076 self
.assertTrue(is_module_available('fou'))
1078 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1079 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1080 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1083 wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'])
1085 output
= check_output('ip fou show')
1087 self
.assertRegex(output
, 'port 55555 ipproto 4')
1088 self
.assertRegex(output
, 'port 55556 ipproto 47')
1090 output
= check_output('ip -d link show ipiptun96')
1092 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1093 output
= check_output('ip -d link show sittun96')
1095 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1096 output
= check_output('ip -d link show gretun96')
1098 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1099 output
= check_output('ip -d link show gretap96')
1101 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1103 def test_vxlan(self
):
1104 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1105 '11-dummy.netdev', 'vxlan-test1.network')
1108 wait_online(['test1:degraded', 'vxlan99:degraded'])
1110 output
= check_output('ip -d link show vxlan99')
1112 self
.assertRegex(output
, '999')
1113 self
.assertRegex(output
, '5555')
1114 self
.assertRegex(output
, 'l2miss')
1115 self
.assertRegex(output
, 'l3miss')
1116 self
.assertRegex(output
, 'udpcsum')
1117 self
.assertRegex(output
, 'udp6zerocsumtx')
1118 self
.assertRegex(output
, 'udp6zerocsumrx')
1119 self
.assertRegex(output
, 'remcsumtx')
1120 self
.assertRegex(output
, 'remcsumrx')
1121 self
.assertRegex(output
, 'gbp')
1123 output
= check_output('bridge fdb show dev vxlan99')
1125 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1126 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1127 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1129 def test_macsec(self
):
1130 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1131 'macsec.network', '12-dummy.netdev')
1134 wait_online(['dummy98:degraded', 'macsec99:routable'])
1136 output
= check_output('ip -d link show macsec99')
1138 self
.assertRegex(output
, 'macsec99@dummy98')
1139 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1140 self
.assertRegex(output
, 'encrypt on')
1142 output
= check_output('ip macsec show macsec99')
1144 self
.assertRegex(output
, 'encrypt on')
1145 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1146 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1147 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1148 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1149 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1150 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1151 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1152 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1153 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1154 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1155 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1157 def test_nlmon(self
):
1158 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1161 wait_online(['nlmon99:carrier'])
1163 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1174 '25-l2tp-dummy.network',
1175 '25-l2tp-ip.netdev',
1176 '25-l2tp-udp.netdev']
1178 l2tp_tunnel_ids
= [ '10' ]
1181 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1182 remove_links(self
.links
)
1185 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1186 remove_links(self
.links
)
1187 remove_unit_from_networkd_path(self
.units
)
1189 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1190 def test_l2tp_udp(self
):
1191 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-udp.netdev')
1194 wait_online(['test1:routable', 'l2tp-ses1:off', 'l2tp-ses2:off'])
1196 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1198 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1199 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1200 self
.assertRegex(output
, "Peer tunnel 11")
1201 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1202 self
.assertRegex(output
, "UDP checksum: enabled")
1204 output
= check_output('ip l2tp show session tid 10 session_id 15')
1206 self
.assertRegex(output
, "Session 15 in tunnel 10")
1207 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1208 self
.assertRegex(output
, "interface name: l2tp-ses1")
1210 output
= check_output('ip l2tp show session tid 10 session_id 17')
1212 self
.assertRegex(output
, "Session 17 in tunnel 10")
1213 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1214 self
.assertRegex(output
, "interface name: l2tp-ses2")
1216 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1217 def test_l2tp_ip(self
):
1218 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-ip.netdev')
1221 wait_online(['test1:routable', 'l2tp-ses3:off', 'l2tp-ses4:off'])
1223 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1225 self
.assertRegex(output
, "Tunnel 10, encap IP")
1226 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1227 self
.assertRegex(output
, "Peer tunnel 12")
1229 output
= check_output('ip l2tp show session tid 10 session_id 25')
1231 self
.assertRegex(output
, "Session 25 in tunnel 10")
1232 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1233 self
.assertRegex(output
, "interface name: l2tp-ses3")
1235 output
= check_output('ip l2tp show session tid 10 session_id 27')
1237 self
.assertRegex(output
, "Session 27 in tunnel 10")
1238 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1239 self
.assertRegex(output
, "interface name: l2tp-ses4")
1241 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1251 '23-active-slave.network',
1252 '24-keep-configuration-static.network',
1253 '24-search-domain.network',
1254 '25-address-link-section.network',
1255 '25-address-preferred-lifetime-zero-ipv6.network',
1256 '25-address-static.network',
1257 '25-bind-carrier.network',
1258 '25-bond-active-backup-slave.netdev',
1259 '25-fibrule-invert.network',
1260 '25-fibrule-port-range.network',
1261 '25-ipv6-address-label-section.network',
1262 '25-neighbor-section.network',
1263 '25-link-local-addressing-no.network',
1264 '25-link-local-addressing-yes.network',
1265 '25-link-section-unmanaged.network',
1266 '25-route-ipv6-src.network',
1267 '25-route-static.network',
1268 '25-sysctl-disable-ipv6.network',
1269 '25-sysctl.network',
1270 'configure-without-carrier.network',
1271 'routing-policy-rule-dummy98.network',
1272 'routing-policy-rule-test1.network']
1274 routing_policy_rule_tables
= ['7', '8']
1275 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1278 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1279 remove_routes(self
.routes
)
1280 remove_links(self
.links
)
1283 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1284 remove_routes(self
.routes
)
1285 remove_links(self
.links
)
1286 remove_unit_from_networkd_path(self
.units
)
1288 def test_address_static(self
):
1289 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1292 wait_online(['dummy98:routable'])
1294 output
= check_output('ip -4 address show dev dummy98')
1296 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1297 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1298 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1301 self
.assertNotRegex(output
, '10.10.0.1/16')
1302 self
.assertNotRegex(output
, '10.10.0.2/16')
1304 output
= check_output('ip -4 address show dev dummy98 label 32')
1305 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1307 output
= check_output('ip -4 address show dev dummy98 label 33')
1308 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1310 output
= check_output('ip -4 address show dev dummy98 label 34')
1311 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1313 output
= check_output('ip -4 address show dev dummy98 label 35')
1314 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1316 output
= check_output('ip -6 address show dev dummy98')
1318 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1319 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1320 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1321 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1322 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1323 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1325 def test_address_preferred_lifetime_zero_ipv6(self
):
1326 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero-ipv6.network', '12-dummy.netdev')
1329 self
.check_link_exists('dummy98')
1330 self
.check_operstate('dummy98', 'routable', setup_state
='configuring')
1332 output
= check_output('ip address show dummy98')
1334 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1335 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1337 def test_configure_without_carrier(self
):
1338 copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
1340 wait_online(['test1:routable'])
1342 output
= check_output(*networkctl_cmd
, 'status', 'test1')
1344 self
.assertRegex(output
, '192.168.0.15')
1345 self
.assertRegex(output
, '192.168.0.1')
1346 self
.assertRegex(output
, 'routable')
1348 def test_routing_policy_rule(self
):
1349 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1351 wait_online(['test1:degraded'])
1353 output
= check_output('ip rule')
1355 self
.assertRegex(output
, '111')
1356 self
.assertRegex(output
, 'from 192.168.100.18')
1357 self
.assertRegex(output
, r
'tos (?:0x08|throughput)\s')
1358 self
.assertRegex(output
, 'iif test1')
1359 self
.assertRegex(output
, 'oif test1')
1360 self
.assertRegex(output
, 'lookup 7')
1362 def test_routing_policy_rule_issue_11280(self
):
1363 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1364 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1366 for trial
in range(3):
1367 # Remove state files only first time
1368 start_networkd(0, remove_state_files
=(trial
== 0))
1369 wait_online(['test1:degraded', 'dummy98:degraded'])
1372 output
= check_output('ip rule list table 7')
1374 self
.assertRegex(output
, '111: from 192.168.100.18 tos (?:0x08|throughput) iif test1 oif test1 lookup 7')
1376 output
= check_output('ip rule list table 8')
1378 self
.assertRegex(output
, '112: from 192.168.101.18 tos (?:0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1380 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1381 def test_routing_policy_rule_port_range(self
):
1382 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1384 wait_online(['test1:degraded'])
1386 output
= check_output('ip rule')
1388 self
.assertRegex(output
, '111')
1389 self
.assertRegex(output
, 'from 192.168.100.18')
1390 self
.assertRegex(output
, '1123-1150')
1391 self
.assertRegex(output
, '3224-3290')
1392 self
.assertRegex(output
, 'tcp')
1393 self
.assertRegex(output
, 'lookup 7')
1395 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1396 def test_routing_policy_rule_invert(self
):
1397 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1399 wait_online(['test1:degraded'])
1401 output
= check_output('ip rule')
1403 self
.assertRegex(output
, '111')
1404 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
1405 self
.assertRegex(output
, 'tcp')
1406 self
.assertRegex(output
, 'lookup 7')
1408 def test_route_static(self
):
1409 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1411 wait_online(['dummy98:routable'])
1413 output
= check_output('ip -6 route show dev dummy98')
1415 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1416 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
1418 output
= check_output('ip -6 route show dev dummy98 default')
1419 self
.assertRegex(output
, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1421 output
= check_output('ip -4 route show dev dummy98')
1423 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1424 self
.assertRegex(output
, '149.10.124.64 proto static scope link')
1425 self
.assertRegex(output
, '169.254.0.0/16 proto static scope link metric 2048')
1426 self
.assertRegex(output
, '192.168.1.1 proto static initcwnd 20')
1427 self
.assertRegex(output
, '192.168.1.2 proto static initrwnd 30')
1429 output
= check_output('ip -4 route show dev dummy98 default')
1430 self
.assertRegex(output
, 'default via 149.10.125.65 proto static onlink')
1431 self
.assertRegex(output
, 'default via 149.10.124.64 proto static')
1432 self
.assertRegex(output
, 'default proto static')
1434 output
= check_output('ip route show type blackhole')
1436 self
.assertRegex(output
, 'blackhole 202.54.1.2 proto static')
1438 output
= check_output('ip route show type unreachable')
1440 self
.assertRegex(output
, 'unreachable 202.54.1.3 proto static')
1442 output
= check_output('ip route show type prohibit')
1444 self
.assertRegex(output
, 'prohibit 202.54.1.4 proto static')
1446 def test_ip_route_ipv6_src_route(self
):
1447 # a dummy device does not make the addresses go through tentative state, so we
1448 # reuse a bond from an earlier test, which does make the addresses go through
1449 # tentative state, and do our test on that
1450 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1452 wait_online(['dummy98:enslaved', 'bond199:routable'])
1454 output
= check_output('ip -6 route list dev bond199')
1456 self
.assertRegex(output
, 'abcd::/16')
1457 self
.assertRegex(output
, 'src')
1458 self
.assertRegex(output
, '2001:1234:56:8f63::2')
1460 def test_ip_link_mac_address(self
):
1461 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
1463 wait_online(['dummy98:degraded'])
1465 output
= check_output('ip link show dummy98')
1467 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
1469 def test_ip_link_unmanaged(self
):
1470 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
1473 self
.check_link_exists('dummy98')
1475 self
.check_operstate('dummy98', 'off', setup_state
='unmanaged')
1477 def test_ipv6_address_label(self
):
1478 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
1480 wait_online(['dummy98:degraded'])
1482 output
= check_output('ip addrlabel list')
1484 self
.assertRegex(output
, '2004:da8:1::/64')
1486 def test_ipv6_neighbor(self
):
1487 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
1489 wait_online(['dummy98:degraded'], timeout
='40s')
1491 output
= check_output('ip neigh list dev dummy98')
1493 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
1494 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
1496 def test_link_local_addressing(self
):
1497 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
1498 '25-link-local-addressing-no.network', '12-dummy.netdev')
1500 wait_online(['test1:degraded', 'dummy98:carrier'])
1502 output
= check_output('ip address show dev test1')
1504 self
.assertRegex(output
, 'inet .* scope link')
1505 self
.assertRegex(output
, 'inet6 .* scope link')
1507 output
= check_output('ip address show dev dummy98')
1509 self
.assertNotRegex(output
, 'inet6* .* scope link')
1512 Documentation/networking/ip-sysctl.txt
1514 addr_gen_mode - INTEGER
1515 Defines how link-local and autoconf addresses are generated.
1517 0: generate address based on EUI64 (default)
1518 1: do no generate a link-local address, use EUI64 for addresses generated
1520 2: generate stable privacy addresses, using the secret from
1521 stable_secret (RFC7217)
1522 3: generate stable privacy addresses, using a random secret if unset
1525 test1_addr_gen_mode
= ''
1526 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
1527 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
1531 # if stable_secret is unset, then EIO is returned
1532 test1_addr_gen_mode
= '0'
1534 test1_addr_gen_mode
= '2'
1536 test1_addr_gen_mode
= '0'
1538 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
1539 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
1541 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
1542 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
1544 def test_sysctl(self
):
1545 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
1547 wait_online(['dummy98:degraded'])
1549 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
1550 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
1551 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
1552 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
1553 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
1554 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
1555 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
1557 def test_sysctl_disable_ipv6(self
):
1558 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
1560 print('## Disable ipv6')
1561 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
1562 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
1565 wait_online(['dummy98:routable'])
1567 output
= check_output('ip -4 address show dummy98')
1569 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1570 output
= check_output('ip -6 address show dummy98')
1572 self
.assertEqual(output
, '')
1573 output
= check_output('ip -4 route show dev dummy98')
1575 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
1576 output
= check_output('ip -6 route show dev dummy98')
1578 self
.assertEqual(output
, '')
1580 check_output('ip link del dummy98')
1582 print('## Enable ipv6')
1583 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
1584 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
1587 wait_online(['dummy98:routable'])
1589 output
= check_output('ip -4 address show dummy98')
1591 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1592 output
= check_output('ip -6 address show dummy98')
1594 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
1595 self
.assertRegex(output
, 'inet6 .* scope link')
1596 output
= check_output('ip -4 route show dev dummy98')
1598 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
1599 output
= check_output('ip -6 route show dev dummy98')
1601 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
1603 def test_bind_carrier(self
):
1604 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
1606 wait_online(['test1:routable'])
1608 check_output('ip link add dummy98 type dummy')
1609 check_output('ip link set dummy98 up')
1611 output
= check_output('ip address show test1')
1613 self
.assertRegex(output
, 'UP,LOWER_UP')
1614 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1615 self
.check_operstate('test1', 'routable')
1617 check_output('ip link add dummy99 type dummy')
1618 check_output('ip link set dummy99 up')
1620 output
= check_output('ip address show test1')
1622 self
.assertRegex(output
, 'UP,LOWER_UP')
1623 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1624 self
.check_operstate('test1', 'routable')
1626 check_output('ip link del dummy98')
1628 output
= check_output('ip address show test1')
1630 self
.assertRegex(output
, 'UP,LOWER_UP')
1631 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1632 self
.check_operstate('test1', 'routable')
1634 check_output('ip link del dummy99')
1636 output
= check_output('ip address show test1')
1638 self
.assertNotRegex(output
, 'UP,LOWER_UP')
1639 self
.assertRegex(output
, 'DOWN')
1640 self
.assertNotRegex(output
, '192.168.10')
1641 self
.check_operstate('test1', 'off')
1643 check_output('ip link add dummy98 type dummy')
1644 check_output('ip link set dummy98 up')
1646 output
= check_output('ip address show test1')
1648 self
.assertRegex(output
, 'UP,LOWER_UP')
1649 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1650 self
.check_operstate('test1', 'routable')
1652 def test_domain(self
):
1653 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
1655 wait_online(['dummy98:routable'])
1657 output
= check_output(*networkctl_cmd
, 'status', 'dummy98', env
=env
)
1659 self
.assertRegex(output
, 'Address: 192.168.42.100')
1660 self
.assertRegex(output
, 'DNS: 192.168.42.1')
1661 self
.assertRegex(output
, 'Search Domains: one')
1663 def test_keep_configuration_static(self
):
1664 check_output('systemctl stop systemd-networkd')
1666 check_output('ip link add name dummy98 type dummy')
1667 check_output('ip address add 10.1.2.3/16 dev dummy98')
1668 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
1669 output
= check_output('ip address show dummy98')
1671 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
1672 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
1673 output
= check_output('ip route show dev dummy98')
1676 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
1678 wait_online(['dummy98:routable'])
1680 output
= check_output('ip address show dummy98')
1682 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
1683 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
1685 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
1695 '23-active-slave.network',
1696 '23-bond199.network',
1697 '23-primary-slave.network',
1698 '25-bond-active-backup-slave.netdev',
1701 'bond-slave.network']
1704 remove_links(self
.links
)
1707 remove_links(self
.links
)
1708 remove_unit_from_networkd_path(self
.units
)
1710 def test_bond_active_slave(self
):
1711 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1713 wait_online(['dummy98:enslaved', 'bond199:degraded'])
1715 output
= check_output('ip -d link show bond199')
1717 self
.assertRegex(output
, 'active_slave dummy98')
1719 def test_bond_primary_slave(self
):
1720 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1722 wait_online(['dummy98:enslaved', 'bond199:degraded'])
1724 output
= check_output('ip -d link show bond199')
1726 self
.assertRegex(output
, 'primary dummy98')
1728 def test_bond_operstate(self
):
1729 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
1730 'bond99.network','bond-slave.network')
1732 wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
1734 output
= check_output('ip -d link show dummy98')
1736 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
1738 output
= check_output('ip -d link show test1')
1740 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
1742 output
= check_output('ip -d link show bond99')
1744 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
1746 self
.check_operstate('dummy98', 'enslaved')
1747 self
.check_operstate('test1', 'enslaved')
1748 self
.check_operstate('bond99', 'routable')
1750 check_output('ip link set dummy98 down')
1753 self
.check_operstate('dummy98', 'off')
1754 self
.check_operstate('test1', 'enslaved')
1755 self
.check_operstate('bond99', 'degraded-carrier')
1757 check_output('ip link set dummy98 up')
1760 self
.check_operstate('dummy98', 'enslaved')
1761 self
.check_operstate('test1', 'enslaved')
1762 self
.check_operstate('bond99', 'routable')
1764 check_output('ip link set dummy98 down')
1765 check_output('ip link set test1 down')
1768 self
.check_operstate('dummy98', 'off')
1769 self
.check_operstate('test1', 'off')
1771 for trial
in range(30):
1774 output
= check_output('ip address show bond99')
1776 if get_operstate('bond99') == 'no-carrier':
1779 # Huh? Kernel does not recognize that all slave interfaces are down?
1780 # Let's confirm that networkd's operstate is consistent with ip's result.
1781 self
.assertNotRegex(output
, 'NO-CARRIER')
1783 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
1793 '26-bridge-slave-interface-1.network',
1794 '26-bridge-slave-interface-2.network',
1795 'bridge99-ignore-carrier-loss.network',
1798 routing_policy_rule_tables
= ['100']
1801 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1802 remove_links(self
.links
)
1805 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1806 remove_links(self
.links
)
1807 remove_unit_from_networkd_path(self
.units
)
1809 def test_bridge_property(self
):
1810 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1811 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1814 wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
1816 output
= check_output('ip -d link show test1')
1818 self
.assertRegex(output
, 'master')
1819 self
.assertRegex(output
, 'bridge')
1821 output
= check_output('ip -d link show dummy98')
1823 self
.assertRegex(output
, 'master')
1824 self
.assertRegex(output
, 'bridge')
1826 output
= check_output('ip addr show bridge99')
1828 self
.assertRegex(output
, '192.168.0.15/24')
1830 output
= check_output('bridge -d link show dummy98')
1832 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
1833 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
1834 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
1835 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
1836 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
1837 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
1838 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
1839 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
1841 # CONFIG_BRIDGE_IGMP_SNOOPING=y
1842 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
1843 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
1845 check_output('ip address add 192.168.0.16/24 dev bridge99')
1848 output
= check_output('ip addr show bridge99')
1850 self
.assertRegex(output
, '192.168.0.16/24')
1852 self
.assertEqual(call('ip link del test1'), 0)
1855 self
.check_operstate('bridge99', 'degraded-carrier')
1857 check_output('ip link del dummy98')
1860 self
.check_operstate('bridge99', 'no-carrier')
1862 output
= check_output('ip address show bridge99')
1864 self
.assertRegex(output
, 'NO-CARRIER')
1865 self
.assertNotRegex(output
, '192.168.0.15/24')
1866 self
.assertNotRegex(output
, '192.168.0.16/24')
1868 def test_bridge_ignore_carrier_loss(self
):
1869 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1870 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1871 'bridge99-ignore-carrier-loss.network')
1873 wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
1875 check_output('ip address add 192.168.0.16/24 dev bridge99')
1878 check_output('ip link del test1')
1879 check_output('ip link del dummy98')
1882 output
= check_output('ip address show bridge99')
1884 self
.assertRegex(output
, 'NO-CARRIER')
1885 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1886 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
1888 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
1889 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
1890 'bridge99-ignore-carrier-loss.network')
1892 wait_online(['bridge99:no-carrier'])
1894 for trial
in range(4):
1895 check_output('ip link add dummy98 type dummy')
1896 check_output('ip link set dummy98 up')
1898 check_output('ip link del dummy98')
1900 wait_online(['bridge99:routable', 'dummy98:enslaved'])
1902 output
= check_output('ip address show bridge99')
1904 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1906 output
= check_output('ip rule list table 100')
1908 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
1910 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
1914 '23-emit-lldp.network',
1919 remove_links(self
.links
)
1922 remove_links(self
.links
)
1923 remove_unit_from_networkd_path(self
.units
)
1925 def test_lldp(self
):
1926 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
1928 wait_online(['veth99:degraded', 'veth-peer:degraded'])
1930 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
1932 self
.assertRegex(output
, 'veth-peer')
1933 self
.assertRegex(output
, 'veth99')
1935 class NetworkdRATests(unittest
.TestCase
, Utilities
):
1940 'ipv6-prefix.network',
1941 'ipv6-prefix-veth.network']
1944 remove_links(self
.links
)
1947 remove_links(self
.links
)
1948 remove_unit_from_networkd_path(self
.units
)
1950 def test_ipv6_prefix_delegation(self
):
1951 warn_about_firewalld()
1952 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
1954 wait_online(['veth99:routable', 'veth-peer:degraded'])
1956 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
1958 self
.assertRegex(output
, '2002:da8:1:0')
1960 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
1965 'dhcp-client.network',
1966 'dhcp-client-timezone-router.network',
1967 'dhcp-server.network',
1968 'dhcp-server-timezone-router.network']
1971 remove_links(self
.links
)
1974 remove_links(self
.links
)
1975 remove_unit_from_networkd_path(self
.units
)
1977 def test_dhcp_server(self
):
1978 warn_about_firewalld()
1979 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
1981 wait_online(['veth99:routable', 'veth-peer:routable'])
1983 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
1985 self
.assertRegex(output
, '192.168.5.*')
1986 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
1987 self
.assertRegex(output
, 'DNS: 192.168.5.1')
1988 self
.assertRegex(output
, 'NTP: 192.168.5.1')
1990 def test_emit_router_timezone(self
):
1991 warn_about_firewalld()
1992 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
1994 wait_online(['veth99:routable', 'veth-peer:routable'])
1996 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
1998 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
1999 self
.assertRegex(output
, '192.168.5.*')
2000 self
.assertRegex(output
, 'Europe/Berlin')
2002 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
2011 'dhcp-client-anonymize.network',
2012 'dhcp-client-gateway-onlink-implicit.network',
2013 'dhcp-client-ipv4-dhcp-settings.network',
2014 'dhcp-client-ipv4-only-ipv6-disabled.network',
2015 'dhcp-client-ipv4-only.network',
2016 'dhcp-client-ipv6-only.network',
2017 'dhcp-client-ipv6-rapid-commit.network',
2018 'dhcp-client-keep-configuration-dhcp-on-stop.network',
2019 'dhcp-client-keep-configuration-dhcp.network',
2020 'dhcp-client-listen-port.network',
2021 'dhcp-client-route-metric.network',
2022 'dhcp-client-route-table.network',
2023 'dhcp-client-vrf.network',
2024 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
2025 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
2026 'dhcp-client.network',
2027 'dhcp-server-veth-peer.network',
2028 'dhcp-v4-server-veth-peer.network',
2032 stop_dnsmasq(dnsmasq_pid_file
)
2033 remove_links(self
.links
)
2036 stop_dnsmasq(dnsmasq_pid_file
)
2039 remove_links(self
.links
)
2040 remove_unit_from_networkd_path(self
.units
)
2042 def test_dhcp_client_ipv6_only(self
):
2043 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2046 wait_online(['veth-peer:carrier'])
2048 wait_online(['veth99:routable', 'veth-peer:routable'])
2050 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2052 self
.assertRegex(output
, '2600::')
2053 self
.assertNotRegex(output
, '192.168.5')
2055 # Confirm that ipv6 token is not set in the kernel
2056 output
= check_output('ip token show dev veth99')
2058 self
.assertRegex(output
, 'token :: dev veth99')
2060 def test_dhcp_client_ipv4_only(self
):
2061 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
2064 wait_online(['veth-peer:carrier'])
2066 wait_online(['veth99:routable', 'veth-peer:routable'])
2068 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2070 self
.assertNotRegex(output
, '2600::')
2071 self
.assertRegex(output
, '192.168.5')
2073 def test_dhcp_client_ipv4_ipv6(self
):
2074 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
2075 'dhcp-client-ipv4-only.network')
2077 wait_online(['veth-peer:carrier'])
2079 wait_online(['veth99:routable', 'veth-peer:routable'])
2081 # link become 'routable' when at least one protocol provide an valid address.
2082 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2083 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2085 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2087 self
.assertRegex(output
, '2600::')
2088 self
.assertRegex(output
, '192.168.5')
2090 def test_dhcp_client_settings(self
):
2091 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
2094 wait_online(['veth-peer:carrier'])
2096 wait_online(['veth99:routable', 'veth-peer:routable'])
2098 print('## ip address show dev veth99')
2099 output
= check_output('ip address show dev veth99')
2101 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2102 self
.assertRegex(output
, '192.168.5')
2103 self
.assertRegex(output
, '1492')
2106 print('## ip route show table main dev veth99')
2107 output
= check_output('ip route show table main dev veth99')
2109 self
.assertNotRegex(output
, 'proto dhcp')
2111 print('## ip route show table 211 dev veth99')
2112 output
= check_output('ip route show table 211 dev veth99')
2114 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
2115 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
2116 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
2118 print('## dnsmasq log')
2119 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
2120 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
2121 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
2122 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
2124 def test_dhcp6_client_settings_rapidcommit_true(self
):
2125 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2127 wait_online(['veth-peer:carrier'])
2129 wait_online(['veth99:routable', 'veth-peer:routable'])
2131 output
= check_output('ip address show dev veth99')
2133 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2134 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
2136 def test_dhcp6_client_settings_rapidcommit_false(self
):
2137 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
2139 wait_online(['veth-peer:carrier'])
2141 wait_online(['veth99:routable', 'veth-peer:routable'])
2143 output
= check_output('ip address show dev veth99')
2145 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2146 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
2148 def test_dhcp_client_settings_anonymize(self
):
2149 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
2151 wait_online(['veth-peer:carrier'])
2153 wait_online(['veth99:routable', 'veth-peer:routable'])
2155 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
2156 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
2157 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
2159 def test_dhcp_client_listen_port(self
):
2160 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
2162 wait_online(['veth-peer:carrier'])
2163 start_dnsmasq('--dhcp-alternate-port=67,5555')
2164 wait_online(['veth99:routable', 'veth-peer:routable'])
2166 # link become 'routable' when at least one protocol provide an valid address.
2167 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2168 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2170 output
= check_output('ip -4 address show dev veth99')
2172 self
.assertRegex(output
, '192.168.5.* dynamic')
2174 def test_dhcp_route_table_id(self
):
2175 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
2177 wait_online(['veth-peer:carrier'])
2179 wait_online(['veth99:routable', 'veth-peer:routable'])
2181 output
= check_output('ip route show table 12')
2183 self
.assertRegex(output
, 'veth99 proto dhcp')
2184 self
.assertRegex(output
, '192.168.5.1')
2186 def test_dhcp_route_metric(self
):
2187 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
2189 wait_online(['veth-peer:carrier'])
2191 wait_online(['veth99:routable', 'veth-peer:routable'])
2193 output
= check_output('ip route show dev veth99')
2195 self
.assertRegex(output
, 'metric 24')
2197 def test_dhcp_keep_configuration_dhcp(self
):
2198 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
2200 wait_online(['veth-peer:carrier'])
2201 start_dnsmasq(lease_time
='2m')
2202 wait_online(['veth99:routable', 'veth-peer:routable'])
2204 output
= check_output('ip address show dev veth99 scope global')
2206 self
.assertRegex(output
, r
'192.168.5.*')
2208 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2210 self
.assertRegex(output
, r
'192.168.5.*')
2212 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
2213 stop_dnsmasq(dnsmasq_pid_file
)
2215 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2216 print('Wait for the dynamic address to be expired')
2219 print('The lease address should be kept after lease expired')
2220 output
= check_output('ip address show dev veth99 scope global')
2222 self
.assertRegex(output
, r
'192.168.5.*')
2224 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2226 self
.assertRegex(output
, r
'192.168.5.*')
2228 check_output('systemctl stop systemd-networkd')
2230 print('The lease address should be kept after networkd stopped')
2231 output
= check_output('ip address show dev veth99 scope global')
2233 self
.assertRegex(output
, r
'192.168.5.*')
2235 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2237 self
.assertRegex(output
, r
'192.168.5.*')
2239 check_output('systemctl start systemd-networkd')
2240 wait_online(['veth-peer:routable'])
2242 print('Still the lease address should be kept after networkd restarted')
2243 output
= check_output('ip address show dev veth99 scope global')
2245 self
.assertRegex(output
, r
'192.168.5.*')
2247 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2249 self
.assertRegex(output
, r
'192.168.5.*')
2251 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
2252 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
2254 wait_online(['veth-peer:carrier'])
2255 start_dnsmasq(lease_time
='2m')
2256 wait_online(['veth99:routable', 'veth-peer:routable'])
2258 output
= check_output('ip address show dev veth99 scope global')
2260 self
.assertRegex(output
, r
'192.168.5.*')
2262 stop_dnsmasq(dnsmasq_pid_file
)
2263 check_output('systemctl stop systemd-networkd')
2265 output
= check_output('ip address show dev veth99 scope global')
2267 self
.assertRegex(output
, r
'192.168.5.*')
2270 wait_online(['veth-peer:routable'])
2272 output
= check_output('ip address show dev veth99 scope global')
2274 self
.assertNotRegex(output
, r
'192.168.5.*')
2276 def test_dhcp_client_reuse_address_as_static(self
):
2277 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
2279 wait_online(['veth-peer:carrier'])
2281 wait_online(['veth99:routable', 'veth-peer:routable'])
2283 # link become 'routable' when at least one protocol provide an valid address.
2284 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2285 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2287 output
= check_output('ip address show dev veth99 scope global')
2289 self
.assertRegex(output
, '192.168.5')
2290 self
.assertRegex(output
, '2600::')
2292 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
2293 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
2294 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
2295 print(static_network
)
2297 remove_unit_from_networkd_path(['dhcp-client.network'])
2299 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
2300 f
.write(static_network
)
2302 # When networkd started, the links are already configured, so let's wait for 5 seconds
2303 # the links to be re-configured.
2305 wait_online(['veth99:routable', 'veth-peer:routable'])
2307 output
= check_output('ip -4 address show dev veth99 scope global')
2309 self
.assertRegex(output
, '192.168.5')
2310 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
2312 output
= check_output('ip -6 address show dev veth99 scope global')
2314 self
.assertRegex(output
, '2600::')
2315 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
2317 @expectedFailureIfModuleIsNotAvailable('vrf')
2318 def test_dhcp_client_vrf(self
):
2319 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
2320 '25-vrf.netdev', '25-vrf.network')
2322 wait_online(['veth-peer:carrier'])
2324 wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
2326 # link become 'routable' when at least one protocol provide an valid address.
2327 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2328 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2330 print('## ip -d link show dev vrf99')
2331 output
= check_output('ip -d link show dev vrf99')
2333 self
.assertRegex(output
, 'vrf table 42')
2335 print('## ip address show vrf vrf99')
2336 output
= check_output('ip address show vrf vrf99')
2338 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2339 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2340 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)')
2341 self
.assertRegex(output
, 'inet6 .* scope link')
2343 print('## ip address show dev veth99')
2344 output
= check_output('ip address show dev veth99')
2346 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2347 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2348 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)')
2349 self
.assertRegex(output
, 'inet6 .* scope link')
2351 print('## ip route show vrf vrf99')
2352 output
= check_output('ip route show vrf vrf99')
2354 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
2355 self
.assertRegex(output
, 'default dev veth99 proto static scope link')
2356 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
2357 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
2358 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
2359 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
2361 print('## ip route show table main dev veth99')
2362 output
= check_output('ip route show table main dev veth99')
2364 self
.assertEqual(output
, '')
2366 def test_dhcp_client_gateway_onlink_implicit(self
):
2367 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2368 'dhcp-client-gateway-onlink-implicit.network')
2370 wait_online(['veth-peer:carrier'])
2372 wait_online(['veth99:routable', 'veth-peer:routable'])
2374 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2376 self
.assertRegex(output
, '192.168.5')
2378 output
= check_output('ip route list dev veth99 10.0.0.0/8')
2380 self
.assertRegex(output
, 'onlink')
2381 output
= check_output('ip route list dev veth99 192.168.100.0/24')
2383 self
.assertRegex(output
, 'onlink')
2385 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
2386 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2387 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
2389 wait_online(['veth-peer:carrier'])
2390 start_dnsmasq(lease_time
='2m')
2391 wait_online(['veth99:routable', 'veth-peer:routable'])
2393 output
= check_output('ip address show dev veth99')
2396 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2397 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2398 output
= check_output('ip -6 address show dev veth99 scope link')
2399 self
.assertRegex(output
, 'inet6 .* scope link')
2400 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2401 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2402 output
= check_output('ip -4 address show dev veth99 scope link')
2403 self
.assertNotRegex(output
, 'inet .* scope link')
2405 print('Wait for the dynamic address to be expired')
2408 output
= check_output('ip address show dev veth99')
2411 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2412 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2413 output
= check_output('ip -6 address show dev veth99 scope link')
2414 self
.assertRegex(output
, 'inet6 .* scope link')
2415 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2416 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2417 output
= check_output('ip -4 address show dev veth99 scope link')
2418 self
.assertNotRegex(output
, 'inet .* scope link')
2420 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
2422 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
2423 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2424 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
2426 wait_online(['veth99:degraded', 'veth-peer:routable'])
2428 output
= check_output('ip address show dev veth99')
2431 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2432 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2433 output
= check_output('ip -6 address show dev veth99 scope link')
2434 self
.assertRegex(output
, 'inet6 .* scope link')
2435 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2436 self
.assertNotRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2437 output
= check_output('ip -4 address show dev veth99 scope link')
2438 self
.assertRegex(output
, 'inet .* scope link')
2440 def test_dhcp_client_route_remove_on_renew(self
):
2441 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2442 'dhcp-client-ipv4-only-ipv6-disabled.network')
2444 wait_online(['veth-peer:carrier'])
2445 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
2446 wait_online(['veth99:routable', 'veth-peer:routable'])
2448 # test for issue #12490
2450 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2452 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2454 for line
in output
.splitlines():
2455 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
2456 address1
= line
.split()[1].split('/')[0]
2459 output
= check_output('ip -4 route show dev veth99')
2461 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2462 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2464 stop_dnsmasq(dnsmasq_pid_file
)
2465 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
2467 print('Wait for the dynamic address to be expired')
2470 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2472 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2474 for line
in output
.splitlines():
2475 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
2476 address2
= line
.split()[1].split('/')[0]
2479 self
.assertNotEqual(address1
, address2
)
2481 output
= check_output('ip -4 route show dev veth99')
2483 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2484 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2485 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
2486 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
2488 if __name__
== '__main__':
2489 parser
= argparse
.ArgumentParser()
2490 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
2491 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
2492 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
2493 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
2494 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
2495 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
2496 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
2497 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
2498 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
2499 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
2502 if ns
.networkd_bin
or ns
.wait_online_bin
or ns
.networkctl_bin
:
2503 print('WARNING: --networkd, --wait-online, or --networkctl options are ignored when --build-dir is specified.')
2504 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
2505 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
2506 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
2509 networkd_bin
= ns
.networkd_bin
2510 if ns
.wait_online_bin
:
2511 wait_online_bin
= ns
.wait_online_bin
2512 if ns
.networkctl_bin
:
2513 networkctl_bin
= ns
.networkctl_bin
2515 use_valgrind
= ns
.use_valgrind
2516 enable_debug
= ns
.enable_debug
2517 asan_options
= ns
.asan_options
2518 lsan_options
= ns
.lsan_options
2519 ubsan_options
= ns
.ubsan_options
2522 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
2523 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
2525 networkctl_cmd
= [networkctl_bin
]
2526 wait_online_cmd
= [wait_online_bin
]
2529 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
2531 env
.update({ 'ASAN_OPTIONS' : asan_options
})
2533 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
2535 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
2538 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,