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 expectedFailureIfLinkFileFieldIsNotSet():
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_LINK_FILE=' in ret
.stdout
.rstrip():
102 call('ip link del dummy99')
107 return unittest
.expectedFailure(func
)
111 def expectedFailureIfEthtoolDoesNotSupportDriver():
114 rc
= call('ip link add name dummy99 type dummy')
116 ret
= run('udevadm info -w10s /sys/class/net/dummy99', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
117 if ret
.returncode
== 0 and 'E: ID_NET_DRIVER=dummy' in ret
.stdout
.rstrip():
119 call('ip link del dummy99')
124 return unittest
.expectedFailure(func
)
129 os
.makedirs(network_unit_file_path
, exist_ok
=True)
130 os
.makedirs(networkd_ci_path
, exist_ok
=True)
132 shutil
.rmtree(networkd_ci_path
)
133 copytree(os
.path
.join(os
.path
.dirname(os
.path
.abspath(__file__
)), 'conf'), networkd_ci_path
)
135 check_output('systemctl stop systemd-networkd.socket')
136 check_output('systemctl stop systemd-networkd.service')
145 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin
,
149 drop_in
+= ['ExecStart=!!' + networkd_bin
]
151 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
153 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
155 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
157 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
158 if asan_options
or lsan_options
or ubsan_options
:
159 drop_in
+= ['SystemCallFilter=']
160 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
161 drop_in
+= ['MemoryDenyWriteExecute=no']
163 os
.makedirs('/run/systemd/system/systemd-networkd.service.d', exist_ok
=True)
164 with
open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode
='w') as f
:
165 f
.write('\n'.join(drop_in
))
167 check_output('systemctl daemon-reload')
168 print(check_output('systemctl cat systemd-networkd.service'))
170 def tearDownModule():
171 shutil
.rmtree(networkd_ci_path
)
173 check_output('systemctl stop systemd-networkd.service')
175 shutil
.rmtree('/run/systemd/system/systemd-networkd.service.d')
176 check_output('systemctl daemon-reload')
178 check_output('systemctl start systemd-networkd.socket')
179 check_output('systemctl start systemd-networkd.service')
181 def read_link_attr(link
, dev
, attribute
):
182 with
open(os
.path
.join(os
.path
.join(os
.path
.join('/sys/class/net/', link
), dev
), attribute
)) as f
:
183 return f
.readline().strip()
185 def read_bridge_port_attr(bridge
, link
, attribute
):
186 path_bridge
= os
.path
.join('/sys/devices/virtual/net', bridge
)
187 path_port
= 'lower_' + link
+ '/brport'
188 path
= os
.path
.join(path_bridge
, path_port
)
190 with
open(os
.path
.join(path
, attribute
)) as f
:
191 return f
.readline().strip()
193 def link_exists(link
):
194 return os
.path
.exists(os
.path
.join('/sys/class/net', link
))
196 def remove_links(links
):
198 if link_exists(link
):
199 call('ip link del dev', link
)
202 def remove_fou_ports(ports
):
204 call('ip fou del port', port
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
206 def remove_routing_policy_rule_tables(tables
):
210 rc
= call('ip rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
212 def remove_routes(routes
):
213 for route_type
, addr
in routes
:
214 call('ip route del', route_type
, addr
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
216 def remove_l2tp_tunnels(tunnel_ids
):
217 output
= check_output('ip l2tp show tunnel')
218 for tid
in tunnel_ids
:
219 words
='Tunnel ' + tid
+ ', encap'
221 call('ip l2tp del tunnel tid', tid
)
224 def read_ipv6_sysctl_attr(link
, attribute
):
225 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, link
), attribute
)) as f
:
226 return f
.readline().strip()
228 def read_ipv4_sysctl_attr(link
, attribute
):
229 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv4_path
, link
), attribute
)) as f
:
230 return f
.readline().strip()
232 def copy_unit_to_networkd_unit_path(*units
):
235 shutil
.copy(os
.path
.join(networkd_ci_path
, unit
), network_unit_file_path
)
236 if (os
.path
.exists(os
.path
.join(networkd_ci_path
, unit
+ '.d'))):
237 copytree(os
.path
.join(networkd_ci_path
, unit
+ '.d'), os
.path
.join(network_unit_file_path
, unit
+ '.d'))
239 def remove_unit_from_networkd_path(units
):
241 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
))):
242 os
.remove(os
.path
.join(network_unit_file_path
, unit
))
243 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
+ '.d'))):
244 shutil
.rmtree(os
.path
.join(network_unit_file_path
, unit
+ '.d'))
246 def warn_about_firewalld():
247 rc
= call('systemctl -q is-active firewalld.service')
249 print('\nWARNING: firewalld.service is active. The test may fail.')
251 def start_dnsmasq(additional_options
='', ipv4_range
='192.168.5.10,192.168.5.200', ipv6_range
='2600::10,2600::20', lease_time
='1h'):
252 warn_about_firewalld()
253 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
254 check_output(dnsmasq_command
)
256 def stop_dnsmasq(pid_file
):
257 if os
.path
.exists(pid_file
):
258 with
open(pid_file
, 'r') as f
:
259 pid
= f
.read().rstrip(' \t\r\n\0')
260 os
.kill(int(pid
), signal
.SIGTERM
)
264 def search_words_in_dnsmasq_log(words
, show_all
=False):
265 if os
.path
.exists(dnsmasq_log_file
):
266 with
open (dnsmasq_log_file
) as in_file
:
267 contents
= in_file
.read()
270 for line
in contents
.splitlines():
273 print("%s, %s" % (words
, line
))
277 def remove_lease_file():
278 if os
.path
.exists(os
.path
.join(networkd_ci_path
, 'lease')):
279 os
.remove(os
.path
.join(networkd_ci_path
, 'lease'))
281 def remove_log_file():
282 if os
.path
.exists(dnsmasq_log_file
):
283 os
.remove(dnsmasq_log_file
)
285 def remove_networkd_state_files():
286 if os
.path
.exists(os
.path
.join(networkd_runtime_directory
, 'state')):
287 os
.remove(os
.path
.join(networkd_runtime_directory
, 'state'))
289 def stop_networkd(show_logs
=True, remove_state_files
=True):
291 invocation_id
= check_output('systemctl show systemd-networkd -p InvocationID --value')
292 check_output('systemctl stop systemd-networkd')
294 print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
))
295 if remove_state_files
:
296 remove_networkd_state_files()
298 def start_networkd(sleep_sec
=0):
299 check_output('systemctl start systemd-networkd')
301 time
.sleep(sleep_sec
)
303 def restart_networkd(sleep_sec
=0, show_logs
=True, remove_state_files
=True):
304 stop_networkd(show_logs
, remove_state_files
)
305 start_networkd(sleep_sec
)
307 def wait_online(links_with_operstate
, timeout
='20s', bool_any
=False):
308 args
= wait_online_cmd
+ [f
'--timeout={timeout}'] + [f
'--interface={link}' for link
in links_with_operstate
]
312 check_output(*args
, env
=env
)
313 except subprocess
.CalledProcessError
:
314 for link
in links_with_operstate
:
315 output
= check_output(*networkctl_cmd
, 'status', link
.split(':')[0], env
=env
)
319 def get_operstate(link
, show_status
=True, setup_state
='configured'):
320 output
= check_output(*networkctl_cmd
, 'status', link
, env
=env
)
323 for line
in output
.splitlines():
324 if 'State:' in line
and (not setup_state
or setup_state
in line
):
325 return line
.split()[1]
329 def check_link_exists(self
, link
):
330 self
.assertTrue(link_exists(link
))
332 def check_operstate(self
, link
, expected
, show_status
=True, setup_state
='configured'):
333 self
.assertRegex(get_operstate(link
, show_status
, setup_state
), expected
)
335 def wait_address(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
336 for i
in range(timeout_sec
):
339 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
340 if re
.search(address_regex
, output
):
343 self
.assertRegex(output
, address_regex
)
345 class NetworkctlTests(unittest
.TestCase
, Utilities
):
354 '11-dummy-mtu.netdev',
357 'netdev-link-local-addressing-yes.network',
361 remove_links(self
.links
)
362 stop_networkd(show_logs
=False)
365 remove_links(self
.links
)
366 remove_unit_from_networkd_path(self
.units
)
367 stop_networkd(show_logs
=True)
370 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
373 wait_online(['test1:degraded'])
375 output
= check_output(*networkctl_cmd
, 'list', env
=env
)
376 self
.assertRegex(output
, '1 lo ')
377 self
.assertRegex(output
, 'test1')
379 output
= check_output(*networkctl_cmd
, 'list', 'test1', env
=env
)
380 self
.assertNotRegex(output
, '1 lo ')
381 self
.assertRegex(output
, 'test1')
383 output
= check_output(*networkctl_cmd
, 'list', 'te*', env
=env
)
384 self
.assertNotRegex(output
, '1 lo ')
385 self
.assertRegex(output
, 'test1')
387 output
= check_output(*networkctl_cmd
, 'status', 'te*', env
=env
)
388 self
.assertNotRegex(output
, '1: lo ')
389 self
.assertRegex(output
, 'test1')
391 output
= check_output(*networkctl_cmd
, 'status', 'tes[a-z][0-9]', env
=env
)
392 self
.assertNotRegex(output
, '1: lo ')
393 self
.assertRegex(output
, 'test1')
396 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
399 wait_online(['test1:degraded'])
401 output
= check_output(*networkctl_cmd
, 'status', 'test1', env
=env
)
402 self
.assertRegex(output
, 'MTU: 1600')
405 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
407 wait_online(['test1:degraded'])
409 output
= check_output(*networkctl_cmd
, 'status', 'test1')
411 self
.assertRegex(output
, 'Type: ether')
413 output
= check_output(*networkctl_cmd
, 'status', 'lo')
415 self
.assertRegex(output
, 'Type: loopback')
417 @expectedFailureIfLinkFileFieldIsNotSet()
418 def test_udev_link_file(self
):
419 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
421 wait_online(['test1:degraded'])
423 output
= check_output(*networkctl_cmd
, 'status', 'test1')
425 self
.assertRegex(output
, r
'Link File: (?:/usr)/lib/systemd/network/99-default.link')
426 self
.assertRegex(output
, r
'Network File: /run/systemd/network/11-dummy.network')
428 output
= check_output(*networkctl_cmd
, 'status', 'lo')
430 self
.assertRegex(output
, r
'Link File: (?:/usr)/lib/systemd/network/99-default.link')
431 self
.assertRegex(output
, r
'Network File: n/a')
433 @expectedFailureIfEthtoolDoesNotSupportDriver()
434 def test_udev_driver(self
):
435 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
436 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
439 wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
441 output
= check_output(*networkctl_cmd
, 'status', 'test1', env
=env
)
442 self
.assertRegex(output
, 'Driver: dummy')
444 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
445 self
.assertRegex(output
, 'Driver: veth')
447 output
= check_output(*networkctl_cmd
, 'status', 'veth-peer', env
=env
)
448 self
.assertRegex(output
, 'Driver: veth')
450 def test_delete_links(self
):
451 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
452 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
455 wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
457 check_output(*networkctl_cmd
, 'delete', 'test1', 'veth99')
458 self
.assertFalse(link_exists('test1'))
459 self
.assertFalse(link_exists('veth99'))
460 self
.assertFalse(link_exists('veth-peer'))
462 class NetworkdNetDevTests(unittest
.TestCase
, Utilities
):
521 '10-dropin-test.netdev',
525 '13-not-match-udev-property.network',
526 '14-match-udev-property.network',
527 '15-name-conflict-test.netdev',
530 '21-vlan-test1.network',
533 '25-6rd-tunnel.netdev',
535 '25-bond-balanced-tlb.netdev',
537 '25-bridge-configure-without-carrier.network',
539 '25-erspan-tunnel-local-any.netdev',
540 '25-erspan-tunnel.netdev',
541 '25-fou-gretap.netdev',
543 '25-fou-ipip.netdev',
544 '25-fou-ipproto-gre.netdev',
545 '25-fou-ipproto-ipip.netdev',
548 '25-gretap-tunnel-local-any.netdev',
549 '25-gretap-tunnel.netdev',
550 '25-gre-tunnel-local-any.netdev',
551 '25-gre-tunnel-remote-any.netdev',
552 '25-gre-tunnel.netdev',
553 '25-ip6gretap-tunnel-local-any.netdev',
554 '25-ip6gretap-tunnel.netdev',
555 '25-ip6gre-tunnel-local-any.netdev',
556 '25-ip6gre-tunnel-remote-any.netdev',
557 '25-ip6gre-tunnel.netdev',
558 '25-ip6tnl-tunnel-remote-any.netdev',
559 '25-ip6tnl-tunnel-local-any.netdev',
560 '25-ip6tnl-tunnel.netdev',
561 '25-ipip-tunnel-independent.netdev',
562 '25-ipip-tunnel-local-any.netdev',
563 '25-ipip-tunnel-remote-any.netdev',
564 '25-ipip-tunnel.netdev',
567 '25-isatap-tunnel.netdev',
572 '25-sit-tunnel-local-any.netdev',
573 '25-sit-tunnel-remote-any.netdev',
574 '25-sit-tunnel.netdev',
577 '25-tunnel-local-any.network',
578 '25-tunnel-remote-any.network',
583 '25-vti6-tunnel-local-any.netdev',
584 '25-vti6-tunnel-remote-any.netdev',
585 '25-vti6-tunnel.netdev',
586 '25-vti-tunnel-local-any.netdev',
587 '25-vti-tunnel-remote-any.netdev',
588 '25-vti-tunnel.netdev',
591 '25-wireguard-23-peers.netdev',
592 '25-wireguard-23-peers.network',
593 '25-wireguard-preshared-key.txt',
594 '25-wireguard-private-key.txt',
595 '25-wireguard.netdev',
596 '25-wireguard.network',
612 'netdev-link-local-addressing-yes.network',
616 'vxlan-test1.network',
624 remove_fou_ports(self
.fou_ports
)
625 remove_links(self
.links
)
626 stop_networkd(show_logs
=False)
629 remove_fou_ports(self
.fou_ports
)
630 remove_links(self
.links
)
631 remove_unit_from_networkd_path(self
.units
)
632 stop_networkd(show_logs
=True)
634 def test_dropin_and_name_conflict(self
):
635 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
638 wait_online(['dropin-test:off'])
640 output
= check_output('ip link show dropin-test')
642 self
.assertRegex(output
, '00:50:56:c0:00:28')
644 def test_match_udev_property(self
):
645 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
647 wait_online(['dummy98:routable'])
649 output
= check_output('networkctl status dummy98')
651 self
.assertRegex(output
, 'Network File: /run/systemd/network/14-match-udev-property')
653 def test_wait_online_any(self
):
654 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
657 wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
659 self
.check_operstate('bridge99', '(?:off|no-carrier)', setup_state
='configuring')
660 self
.check_operstate('test1', 'degraded')
662 def test_bridge(self
):
663 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
666 wait_online(['bridge99:no-carrier'])
668 tick
= os
.sysconf('SC_CLK_TCK')
669 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
670 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
671 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge','forward_delay')) / tick
))
672 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge','ageing_time')) / tick
))
673 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge','priority')))
674 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','multicast_querier')))
675 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','multicast_snooping')))
676 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','stp_state')))
679 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
682 wait_online(['bond99:off', 'bond98:off'])
684 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
685 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
686 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
687 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
688 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
689 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
690 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
691 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
692 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
693 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
694 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
696 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
697 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
700 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
701 '21-vlan.network', '21-vlan-test1.network')
704 wait_online(['test1:degraded', 'vlan99:routable'])
706 output
= check_output('ip -d link show test1')
708 self
.assertRegex(output
, ' mtu 2000 ')
710 output
= check_output('ip -d link show vlan99')
712 self
.assertRegex(output
, ' mtu 2000 ')
713 self
.assertRegex(output
, 'REORDER_HDR')
714 self
.assertRegex(output
, 'LOOSE_BINDING')
715 self
.assertRegex(output
, 'GVRP')
716 self
.assertRegex(output
, 'MVRP')
717 self
.assertRegex(output
, ' id 99 ')
719 output
= check_output('ip -4 address show dev test1')
721 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
722 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
724 output
= check_output('ip -4 address show dev vlan99')
726 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
728 def test_macvtap(self
):
729 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
730 with self
.subTest(mode
=mode
):
731 if mode
!= 'private':
733 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
734 '11-dummy.netdev', 'macvtap.network')
735 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
736 f
.write('[MACVTAP]\nMode=' + mode
)
739 wait_online(['macvtap99:degraded', 'test1:degraded'])
741 output
= check_output('ip -d link show macvtap99')
743 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
745 def test_macvlan(self
):
746 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
747 with self
.subTest(mode
=mode
):
748 if mode
!= 'private':
750 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
751 '11-dummy.netdev', 'macvlan.network')
752 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
753 f
.write('[MACVLAN]\nMode=' + mode
)
756 wait_online(['macvlan99:degraded', 'test1:degraded'])
758 output
= check_output('ip -d link show test1')
760 self
.assertRegex(output
, ' mtu 2000 ')
762 output
= check_output('ip -d link show macvlan99')
764 self
.assertRegex(output
, ' mtu 2000 ')
765 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
767 @expectedFailureIfModuleIsNotAvailable('ipvlan')
768 def test_ipvlan(self
):
769 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
770 with self
.subTest(mode
=mode
, flag
=flag
):
773 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
774 '11-dummy.netdev', 'ipvlan.network')
775 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
776 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
779 wait_online(['ipvlan99:degraded', 'test1:degraded'])
781 output
= check_output('ip -d link show ipvlan99')
783 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
785 @expectedFailureIfModuleIsNotAvailable('ipvtap')
786 def test_ipvtap(self
):
787 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
788 with self
.subTest(mode
=mode
, flag
=flag
):
791 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
792 '11-dummy.netdev', 'ipvtap.network')
793 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
794 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
797 wait_online(['ipvtap99:degraded', 'test1:degraded'])
799 output
= check_output('ip -d link show ipvtap99')
801 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
804 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
807 wait_online(['veth99:degraded', 'veth-peer:degraded'])
809 output
= check_output('ip -d link show veth99')
811 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
812 output
= check_output('ip -d link show veth-peer')
814 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
817 copy_unit_to_networkd_unit_path('25-tun.netdev')
820 wait_online(['tun99:off'])
822 output
= check_output('ip -d link show tun99')
824 # Old ip command does not support IFF_ flags
825 self
.assertRegex(output
, 'tun (?:type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
828 copy_unit_to_networkd_unit_path('25-tap.netdev')
831 wait_online(['tap99:off'])
833 output
= check_output('ip -d link show tap99')
835 # Old ip command does not support IFF_ flags
836 self
.assertRegex(output
, 'tun (?:type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
838 @expectedFailureIfModuleIsNotAvailable('vrf')
840 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
843 wait_online(['vrf99:carrier'])
845 @expectedFailureIfModuleIsNotAvailable('vcan')
847 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
850 wait_online(['vcan99:carrier'])
852 @expectedFailureIfModuleIsNotAvailable('vxcan')
853 def test_vxcan(self
):
854 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
857 wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
859 @expectedFailureIfModuleIsNotAvailable('wireguard')
860 def test_wireguard(self
):
861 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
862 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
863 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt')
865 wait_online(['wg99:carrier', 'wg98:routable'])
867 if shutil
.which('wg'):
870 output
= check_output('wg show wg99 listen-port')
871 self
.assertRegex(output
, '51820')
872 output
= check_output('wg show wg99 fwmark')
873 self
.assertRegex(output
, '0x4d2')
874 output
= check_output('wg show wg99 allowed-ips')
875 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
876 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
877 output
= check_output('wg show wg99 persistent-keepalive')
878 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
879 output
= check_output('wg show wg99 endpoints')
880 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
881 output
= check_output('wg show wg99 private-key')
882 self
.assertRegex(output
, r
'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
883 output
= check_output('wg show wg99 preshared-keys')
884 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
885 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
887 output
= check_output('wg show wg98 private-key')
888 self
.assertRegex(output
, r
'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
890 def test_geneve(self
):
891 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
894 wait_online(['geneve99:degraded'])
896 output
= check_output('ip -d link show geneve99')
898 self
.assertRegex(output
, '192.168.22.1')
899 self
.assertRegex(output
, '6082')
900 self
.assertRegex(output
, 'udpcsum')
901 self
.assertRegex(output
, 'udp6zerocsumrx')
903 def test_ipip_tunnel(self
):
904 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
905 '25-ipip-tunnel.netdev', '25-tunnel.network',
906 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
907 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
909 wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'dummy98:degraded'])
911 output
= check_output('ip -d link show ipiptun99')
913 self
.assertRegex(output
, 'ipip (?:ipip |)remote 192.169.224.239 local 192.168.223.238 dev dummy98')
914 output
= check_output('ip -d link show ipiptun98')
916 self
.assertRegex(output
, 'ipip (?:ipip |)remote 192.169.224.239 local any dev dummy98')
917 output
= check_output('ip -d link show ipiptun97')
919 self
.assertRegex(output
, 'ipip (?:ipip |)remote any local 192.168.223.238 dev dummy98')
921 def test_gre_tunnel(self
):
922 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
923 '25-gre-tunnel.netdev', '25-tunnel.network',
924 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
925 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
927 wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'dummy98:degraded'])
929 output
= check_output('ip -d link show gretun99')
931 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
932 self
.assertRegex(output
, 'ikey 1.2.3.103')
933 self
.assertRegex(output
, 'okey 1.2.4.103')
934 self
.assertRegex(output
, 'iseq')
935 self
.assertRegex(output
, 'oseq')
936 output
= check_output('ip -d link show gretun98')
938 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
939 self
.assertRegex(output
, 'ikey 0.0.0.104')
940 self
.assertRegex(output
, 'okey 0.0.0.104')
941 self
.assertNotRegex(output
, 'iseq')
942 self
.assertNotRegex(output
, 'oseq')
943 output
= check_output('ip -d link show gretun97')
945 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
946 self
.assertRegex(output
, 'ikey 0.0.0.105')
947 self
.assertRegex(output
, 'okey 0.0.0.105')
948 self
.assertNotRegex(output
, 'iseq')
949 self
.assertNotRegex(output
, 'oseq')
951 def test_ip6gre_tunnel(self
):
952 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
953 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
954 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
955 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
958 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
960 self
.check_link_exists('dummy98')
961 self
.check_link_exists('ip6gretun99')
962 self
.check_link_exists('ip6gretun98')
963 self
.check_link_exists('ip6gretun97')
965 output
= check_output('ip -d link show ip6gretun99')
967 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
968 output
= check_output('ip -d link show ip6gretun98')
970 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
971 output
= check_output('ip -d link show ip6gretun97')
973 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
975 def test_gretap_tunnel(self
):
976 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
977 '25-gretap-tunnel.netdev', '25-tunnel.network',
978 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
980 wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
982 output
= check_output('ip -d link show gretap99')
984 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
985 self
.assertRegex(output
, 'ikey 0.0.0.106')
986 self
.assertRegex(output
, 'okey 0.0.0.106')
987 self
.assertRegex(output
, 'iseq')
988 self
.assertRegex(output
, 'oseq')
989 output
= check_output('ip -d link show gretap98')
991 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
992 self
.assertRegex(output
, 'ikey 0.0.0.107')
993 self
.assertRegex(output
, 'okey 0.0.0.107')
994 self
.assertRegex(output
, 'iseq')
995 self
.assertRegex(output
, 'oseq')
997 def test_ip6gretap_tunnel(self
):
998 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
999 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1000 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1002 wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
1004 output
= check_output('ip -d link show ip6gretap99')
1006 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1007 output
= check_output('ip -d link show ip6gretap98')
1009 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1011 def test_vti_tunnel(self
):
1012 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
1013 '25-vti-tunnel.netdev', '25-tunnel.network',
1014 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1015 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1017 wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'dummy98:degraded'])
1019 output
= check_output('ip -d link show vtitun99')
1021 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1022 output
= check_output('ip -d link show vtitun98')
1024 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
1025 output
= check_output('ip -d link show vtitun97')
1027 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
1029 def test_vti6_tunnel(self
):
1030 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
1031 '25-vti6-tunnel.netdev', '25-tunnel.network',
1032 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1033 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1035 wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
1037 output
= check_output('ip -d link show vti6tun99')
1039 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1040 output
= check_output('ip -d link show vti6tun98')
1042 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
1043 output
= check_output('ip -d link show vti6tun97')
1045 self
.assertRegex(output
, 'vti6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1047 def test_ip6tnl_tunnel(self
):
1048 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
1049 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1050 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1051 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1053 wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
1055 output
= check_output('ip -d link show ip6tnl99')
1057 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1058 output
= check_output('ip -d link show ip6tnl98')
1060 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
1061 output
= check_output('ip -d link show ip6tnl97')
1063 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1065 def test_sit_tunnel(self
):
1066 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1067 '25-sit-tunnel.netdev', '25-tunnel.network',
1068 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1069 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1071 wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'dummy98:degraded'])
1073 output
= check_output('ip -d link show sittun99')
1075 self
.assertRegex(output
, "sit (?:ip6ip |)remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1076 output
= check_output('ip -d link show sittun98')
1078 self
.assertRegex(output
, "sit (?:ip6ip |)remote 10.65.223.239 local any dev dummy98")
1079 output
= check_output('ip -d link show sittun97')
1081 self
.assertRegex(output
, "sit (?:ip6ip |)remote any local 10.65.223.238 dev dummy98")
1083 def test_isatap_tunnel(self
):
1084 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1085 '25-isatap-tunnel.netdev', '25-tunnel.network')
1087 wait_online(['isataptun99:routable', 'dummy98:degraded'])
1089 output
= check_output('ip -d link show isataptun99')
1091 self
.assertRegex(output
, "isatap ")
1093 def test_6rd_tunnel(self
):
1094 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1095 '25-6rd-tunnel.netdev', '25-tunnel.network')
1097 wait_online(['sittun99:routable', 'dummy98:degraded'])
1099 output
= check_output('ip -d link show sittun99')
1101 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1103 @expectedFailureIfERSPANModuleIsNotAvailable()
1104 def test_erspan_tunnel(self
):
1105 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1106 '25-erspan-tunnel.netdev', '25-tunnel.network',
1107 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1109 wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1111 output
= check_output('ip -d link show erspan99')
1113 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1114 self
.assertRegex(output
, 'ikey 0.0.0.101')
1115 self
.assertRegex(output
, 'okey 0.0.0.101')
1116 self
.assertRegex(output
, 'iseq')
1117 self
.assertRegex(output
, 'oseq')
1118 output
= check_output('ip -d link show erspan98')
1120 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1121 self
.assertRegex(output
, '102')
1122 self
.assertRegex(output
, 'ikey 0.0.0.102')
1123 self
.assertRegex(output
, 'okey 0.0.0.102')
1124 self
.assertRegex(output
, 'iseq')
1125 self
.assertRegex(output
, 'oseq')
1127 def test_tunnel_independent(self
):
1128 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1131 wait_online(['ipiptun99:carrier'])
1133 @expectedFailureIfModuleIsNotAvailable('fou')
1135 # The following redundant check is necessary for CentOS CI.
1136 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1137 self
.assertTrue(is_module_available('fou'))
1139 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1140 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1141 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1144 wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'])
1146 output
= check_output('ip fou show')
1148 self
.assertRegex(output
, 'port 55555 ipproto 4')
1149 self
.assertRegex(output
, 'port 55556 ipproto 47')
1151 output
= check_output('ip -d link show ipiptun96')
1153 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1154 output
= check_output('ip -d link show sittun96')
1156 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1157 output
= check_output('ip -d link show gretun96')
1159 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1160 output
= check_output('ip -d link show gretap96')
1162 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1164 def test_vxlan(self
):
1165 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1166 '11-dummy.netdev', 'vxlan-test1.network')
1169 wait_online(['test1:degraded', 'vxlan99:degraded'])
1171 output
= check_output('ip -d link show vxlan99')
1173 self
.assertRegex(output
, '999')
1174 self
.assertRegex(output
, '5555')
1175 self
.assertRegex(output
, 'l2miss')
1176 self
.assertRegex(output
, 'l3miss')
1177 self
.assertRegex(output
, 'udpcsum')
1178 self
.assertRegex(output
, 'udp6zerocsumtx')
1179 self
.assertRegex(output
, 'udp6zerocsumrx')
1180 self
.assertRegex(output
, 'remcsumtx')
1181 self
.assertRegex(output
, 'remcsumrx')
1182 self
.assertRegex(output
, 'gbp')
1184 output
= check_output('bridge fdb show dev vxlan99')
1186 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1187 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1188 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1190 def test_macsec(self
):
1191 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1192 'macsec.network', '12-dummy.netdev')
1195 wait_online(['dummy98:degraded', 'macsec99:routable'])
1197 output
= check_output('ip -d link show macsec99')
1199 self
.assertRegex(output
, 'macsec99@dummy98')
1200 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1201 self
.assertRegex(output
, 'encrypt on')
1203 output
= check_output('ip macsec show macsec99')
1205 self
.assertRegex(output
, 'encrypt on')
1206 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1207 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1208 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1209 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1210 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1211 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1212 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1213 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1214 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1215 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1216 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1218 def test_nlmon(self
):
1219 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1222 wait_online(['nlmon99:carrier'])
1224 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1235 '25-l2tp-dummy.network',
1236 '25-l2tp-ip.netdev',
1237 '25-l2tp-udp.netdev']
1239 l2tp_tunnel_ids
= [ '10' ]
1242 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1243 remove_links(self
.links
)
1244 stop_networkd(show_logs
=False)
1247 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1248 remove_links(self
.links
)
1249 remove_unit_from_networkd_path(self
.units
)
1250 stop_networkd(show_logs
=True)
1252 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1253 def test_l2tp_udp(self
):
1254 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-udp.netdev')
1257 wait_online(['test1:routable', 'l2tp-ses1:off', 'l2tp-ses2:off'])
1259 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1261 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1262 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1263 self
.assertRegex(output
, "Peer tunnel 11")
1264 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1265 self
.assertRegex(output
, "UDP checksum: enabled")
1267 output
= check_output('ip l2tp show session tid 10 session_id 15')
1269 self
.assertRegex(output
, "Session 15 in tunnel 10")
1270 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1271 self
.assertRegex(output
, "interface name: l2tp-ses1")
1273 output
= check_output('ip l2tp show session tid 10 session_id 17')
1275 self
.assertRegex(output
, "Session 17 in tunnel 10")
1276 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1277 self
.assertRegex(output
, "interface name: l2tp-ses2")
1279 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1280 def test_l2tp_ip(self
):
1281 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-ip.netdev')
1284 wait_online(['test1:routable', 'l2tp-ses3:off', 'l2tp-ses4:off'])
1286 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1288 self
.assertRegex(output
, "Tunnel 10, encap IP")
1289 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1290 self
.assertRegex(output
, "Peer tunnel 12")
1292 output
= check_output('ip l2tp show session tid 10 session_id 25')
1294 self
.assertRegex(output
, "Session 25 in tunnel 10")
1295 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1296 self
.assertRegex(output
, "interface name: l2tp-ses3")
1298 output
= check_output('ip l2tp show session tid 10 session_id 27')
1300 self
.assertRegex(output
, "Session 27 in tunnel 10")
1301 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1302 self
.assertRegex(output
, "interface name: l2tp-ses4")
1304 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1314 '23-active-slave.network',
1315 '24-keep-configuration-static.network',
1316 '24-search-domain.network',
1317 '25-address-link-section.network',
1318 '25-address-preferred-lifetime-zero-ipv6.network',
1319 '25-address-static.network',
1320 '25-bind-carrier.network',
1321 '25-bond-active-backup-slave.netdev',
1322 '25-fibrule-invert.network',
1323 '25-fibrule-port-range.network',
1324 '25-ipv6-address-label-section.network',
1325 '25-neighbor-section.network',
1326 '25-link-local-addressing-no.network',
1327 '25-link-local-addressing-yes.network',
1328 '25-link-section-unmanaged.network',
1329 '25-route-ipv6-src.network',
1330 '25-route-static.network',
1331 '25-sysctl-disable-ipv6.network',
1332 '25-sysctl.network',
1333 'configure-without-carrier.network',
1334 'routing-policy-rule-dummy98.network',
1335 'routing-policy-rule-test1.network']
1337 routing_policy_rule_tables
= ['7', '8']
1338 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1341 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1342 remove_routes(self
.routes
)
1343 remove_links(self
.links
)
1344 stop_networkd(show_logs
=False)
1347 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1348 remove_routes(self
.routes
)
1349 remove_links(self
.links
)
1350 remove_unit_from_networkd_path(self
.units
)
1351 stop_networkd(show_logs
=True)
1353 def test_address_static(self
):
1354 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1357 wait_online(['dummy98:routable'])
1359 output
= check_output('ip -4 address show dev dummy98')
1361 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1362 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1363 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1366 self
.assertNotRegex(output
, '10.10.0.1/16')
1367 self
.assertNotRegex(output
, '10.10.0.2/16')
1369 output
= check_output('ip -4 address show dev dummy98 label 32')
1370 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1372 output
= check_output('ip -4 address show dev dummy98 label 33')
1373 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1375 output
= check_output('ip -4 address show dev dummy98 label 34')
1376 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1378 output
= check_output('ip -4 address show dev dummy98 label 35')
1379 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1381 output
= check_output('ip -6 address show dev dummy98')
1383 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1384 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1385 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1386 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1387 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1388 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1390 def test_address_preferred_lifetime_zero_ipv6(self
):
1391 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero-ipv6.network', '12-dummy.netdev')
1394 self
.check_link_exists('dummy98')
1395 self
.check_operstate('dummy98', 'routable', setup_state
='configuring')
1397 output
= check_output('ip address show dummy98')
1399 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1400 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1402 def test_configure_without_carrier(self
):
1403 copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
1405 wait_online(['test1:routable'])
1407 output
= check_output(*networkctl_cmd
, 'status', 'test1')
1409 self
.assertRegex(output
, '192.168.0.15')
1410 self
.assertRegex(output
, '192.168.0.1')
1411 self
.assertRegex(output
, 'routable')
1413 def test_routing_policy_rule(self
):
1414 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1416 wait_online(['test1:degraded'])
1418 output
= check_output('ip rule')
1420 self
.assertRegex(output
, '111')
1421 self
.assertRegex(output
, 'from 192.168.100.18')
1422 self
.assertRegex(output
, r
'tos (?:0x08|throughput)\s')
1423 self
.assertRegex(output
, 'iif test1')
1424 self
.assertRegex(output
, 'oif test1')
1425 self
.assertRegex(output
, 'lookup 7')
1427 def test_routing_policy_rule_issue_11280(self
):
1428 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1429 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1431 for trial
in range(3):
1432 # Remove state files only first time
1434 wait_online(['test1:degraded', 'dummy98:degraded'])
1437 output
= check_output('ip rule list table 7')
1439 self
.assertRegex(output
, '111: from 192.168.100.18 tos (?:0x08|throughput) iif test1 oif test1 lookup 7')
1441 output
= check_output('ip rule list table 8')
1443 self
.assertRegex(output
, '112: from 192.168.101.18 tos (?:0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1445 stop_networkd(remove_state_files
=False)
1447 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1448 def test_routing_policy_rule_port_range(self
):
1449 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1451 wait_online(['test1:degraded'])
1453 output
= check_output('ip rule')
1455 self
.assertRegex(output
, '111')
1456 self
.assertRegex(output
, 'from 192.168.100.18')
1457 self
.assertRegex(output
, '1123-1150')
1458 self
.assertRegex(output
, '3224-3290')
1459 self
.assertRegex(output
, 'tcp')
1460 self
.assertRegex(output
, 'lookup 7')
1462 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1463 def test_routing_policy_rule_invert(self
):
1464 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1466 wait_online(['test1:degraded'])
1468 output
= check_output('ip rule')
1470 self
.assertRegex(output
, '111')
1471 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
1472 self
.assertRegex(output
, 'tcp')
1473 self
.assertRegex(output
, 'lookup 7')
1475 def test_route_static(self
):
1476 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1478 wait_online(['dummy98:routable'])
1480 output
= check_output('ip -6 route show dev dummy98')
1482 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1483 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
1485 output
= check_output('ip -6 route show dev dummy98 default')
1486 self
.assertRegex(output
, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1488 output
= check_output('ip -4 route show dev dummy98')
1490 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1491 self
.assertRegex(output
, '149.10.124.64 proto static scope link')
1492 self
.assertRegex(output
, '169.254.0.0/16 proto static scope link metric 2048')
1493 self
.assertRegex(output
, '192.168.1.1 proto static initcwnd 20')
1494 self
.assertRegex(output
, '192.168.1.2 proto static initrwnd 30')
1496 output
= check_output('ip -4 route show dev dummy98 default')
1497 self
.assertRegex(output
, 'default via 149.10.125.65 proto static onlink')
1498 self
.assertRegex(output
, 'default via 149.10.124.64 proto static')
1499 self
.assertRegex(output
, 'default proto static')
1501 output
= check_output('ip route show type blackhole')
1503 self
.assertRegex(output
, 'blackhole 202.54.1.2 proto static')
1505 output
= check_output('ip route show type unreachable')
1507 self
.assertRegex(output
, 'unreachable 202.54.1.3 proto static')
1509 output
= check_output('ip route show type prohibit')
1511 self
.assertRegex(output
, 'prohibit 202.54.1.4 proto static')
1513 def test_ip_route_ipv6_src_route(self
):
1514 # a dummy device does not make the addresses go through tentative state, so we
1515 # reuse a bond from an earlier test, which does make the addresses go through
1516 # tentative state, and do our test on that
1517 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1519 wait_online(['dummy98:enslaved', 'bond199:routable'])
1521 output
= check_output('ip -6 route list dev bond199')
1523 self
.assertRegex(output
, 'abcd::/16')
1524 self
.assertRegex(output
, 'src')
1525 self
.assertRegex(output
, '2001:1234:56:8f63::2')
1527 def test_ip_link_mac_address(self
):
1528 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
1530 wait_online(['dummy98:degraded'])
1532 output
= check_output('ip link show dummy98')
1534 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
1536 def test_ip_link_unmanaged(self
):
1537 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
1540 self
.check_link_exists('dummy98')
1542 self
.check_operstate('dummy98', 'off', setup_state
='unmanaged')
1544 def test_ipv6_address_label(self
):
1545 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
1547 wait_online(['dummy98:degraded'])
1549 output
= check_output('ip addrlabel list')
1551 self
.assertRegex(output
, '2004:da8:1::/64')
1553 def test_ipv6_neighbor(self
):
1554 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
1556 wait_online(['dummy98:degraded'], timeout
='40s')
1558 output
= check_output('ip neigh list dev dummy98')
1560 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
1561 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
1563 def test_link_local_addressing(self
):
1564 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
1565 '25-link-local-addressing-no.network', '12-dummy.netdev')
1567 wait_online(['test1:degraded', 'dummy98:carrier'])
1569 output
= check_output('ip address show dev test1')
1571 self
.assertRegex(output
, 'inet .* scope link')
1572 self
.assertRegex(output
, 'inet6 .* scope link')
1574 output
= check_output('ip address show dev dummy98')
1576 self
.assertNotRegex(output
, 'inet6* .* scope link')
1579 Documentation/networking/ip-sysctl.txt
1581 addr_gen_mode - INTEGER
1582 Defines how link-local and autoconf addresses are generated.
1584 0: generate address based on EUI64 (default)
1585 1: do no generate a link-local address, use EUI64 for addresses generated
1587 2: generate stable privacy addresses, using the secret from
1588 stable_secret (RFC7217)
1589 3: generate stable privacy addresses, using a random secret if unset
1592 test1_addr_gen_mode
= ''
1593 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
1594 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
1598 # if stable_secret is unset, then EIO is returned
1599 test1_addr_gen_mode
= '0'
1601 test1_addr_gen_mode
= '2'
1603 test1_addr_gen_mode
= '0'
1605 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
1606 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
1608 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
1609 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
1611 def test_sysctl(self
):
1612 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
1614 wait_online(['dummy98:degraded'])
1616 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
1617 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
1618 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
1619 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
1620 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
1621 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
1622 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
1624 def test_sysctl_disable_ipv6(self
):
1625 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
1627 print('## Disable ipv6')
1628 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
1629 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
1632 wait_online(['dummy98:routable'])
1634 output
= check_output('ip -4 address show dummy98')
1636 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1637 output
= check_output('ip -6 address show dummy98')
1639 self
.assertEqual(output
, '')
1640 output
= check_output('ip -4 route show dev dummy98')
1642 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
1643 output
= check_output('ip -6 route show dev dummy98')
1645 self
.assertEqual(output
, '')
1647 check_output('ip link del dummy98')
1649 print('## Enable ipv6')
1650 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
1651 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
1654 wait_online(['dummy98:routable'])
1656 output
= check_output('ip -4 address show dummy98')
1658 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1659 output
= check_output('ip -6 address show dummy98')
1661 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
1662 self
.assertRegex(output
, 'inet6 .* scope link')
1663 output
= check_output('ip -4 route show dev dummy98')
1665 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
1666 output
= check_output('ip -6 route show dev dummy98')
1668 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
1670 def test_bind_carrier(self
):
1671 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
1673 wait_online(['test1:routable'])
1675 check_output('ip link add dummy98 type dummy')
1676 check_output('ip link set dummy98 up')
1678 output
= check_output('ip address show test1')
1680 self
.assertRegex(output
, 'UP,LOWER_UP')
1681 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1682 self
.check_operstate('test1', 'routable')
1684 check_output('ip link add dummy99 type dummy')
1685 check_output('ip link set dummy99 up')
1687 output
= check_output('ip address show test1')
1689 self
.assertRegex(output
, 'UP,LOWER_UP')
1690 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1691 self
.check_operstate('test1', 'routable')
1693 check_output('ip link del dummy98')
1695 output
= check_output('ip address show test1')
1697 self
.assertRegex(output
, 'UP,LOWER_UP')
1698 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1699 self
.check_operstate('test1', 'routable')
1701 check_output('ip link del dummy99')
1703 output
= check_output('ip address show test1')
1705 self
.assertNotRegex(output
, 'UP,LOWER_UP')
1706 self
.assertRegex(output
, 'DOWN')
1707 self
.assertNotRegex(output
, '192.168.10')
1708 self
.check_operstate('test1', 'off')
1710 check_output('ip link add dummy98 type dummy')
1711 check_output('ip link set dummy98 up')
1713 output
= check_output('ip address show test1')
1715 self
.assertRegex(output
, 'UP,LOWER_UP')
1716 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1717 self
.check_operstate('test1', 'routable')
1719 def test_domain(self
):
1720 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
1722 wait_online(['dummy98:routable'])
1724 output
= check_output(*networkctl_cmd
, 'status', 'dummy98', env
=env
)
1726 self
.assertRegex(output
, 'Address: 192.168.42.100')
1727 self
.assertRegex(output
, 'DNS: 192.168.42.1')
1728 self
.assertRegex(output
, 'Search Domains: one')
1730 def test_keep_configuration_static(self
):
1731 check_output('systemctl stop systemd-networkd')
1733 check_output('ip link add name dummy98 type dummy')
1734 check_output('ip address add 10.1.2.3/16 dev dummy98')
1735 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
1736 output
= check_output('ip address show dummy98')
1738 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
1739 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
1740 output
= check_output('ip route show dev dummy98')
1743 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
1745 wait_online(['dummy98:routable'])
1747 output
= check_output('ip address show dummy98')
1749 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
1750 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
1752 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
1762 '23-active-slave.network',
1763 '23-bond199.network',
1764 '23-primary-slave.network',
1765 '25-bond-active-backup-slave.netdev',
1768 'bond-slave.network']
1771 remove_links(self
.links
)
1772 stop_networkd(show_logs
=False)
1775 remove_links(self
.links
)
1776 remove_unit_from_networkd_path(self
.units
)
1777 stop_networkd(show_logs
=True)
1779 def test_bond_active_slave(self
):
1780 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1782 wait_online(['dummy98:enslaved', 'bond199:degraded'])
1784 output
= check_output('ip -d link show bond199')
1786 self
.assertRegex(output
, 'active_slave dummy98')
1788 def test_bond_primary_slave(self
):
1789 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1791 wait_online(['dummy98:enslaved', 'bond199:degraded'])
1793 output
= check_output('ip -d link show bond199')
1795 self
.assertRegex(output
, 'primary dummy98')
1797 def test_bond_operstate(self
):
1798 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
1799 'bond99.network','bond-slave.network')
1801 wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
1803 output
= check_output('ip -d link show dummy98')
1805 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
1807 output
= check_output('ip -d link show test1')
1809 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
1811 output
= check_output('ip -d link show bond99')
1813 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
1815 self
.check_operstate('dummy98', 'enslaved')
1816 self
.check_operstate('test1', 'enslaved')
1817 self
.check_operstate('bond99', 'routable')
1819 check_output('ip link set dummy98 down')
1822 self
.check_operstate('dummy98', 'off')
1823 self
.check_operstate('test1', 'enslaved')
1824 self
.check_operstate('bond99', 'degraded-carrier')
1826 check_output('ip link set dummy98 up')
1829 self
.check_operstate('dummy98', 'enslaved')
1830 self
.check_operstate('test1', 'enslaved')
1831 self
.check_operstate('bond99', 'routable')
1833 check_output('ip link set dummy98 down')
1834 check_output('ip link set test1 down')
1837 self
.check_operstate('dummy98', 'off')
1838 self
.check_operstate('test1', 'off')
1840 for trial
in range(30):
1843 output
= check_output('ip address show bond99')
1845 if get_operstate('bond99') == 'no-carrier':
1848 # Huh? Kernel does not recognize that all slave interfaces are down?
1849 # Let's confirm that networkd's operstate is consistent with ip's result.
1850 self
.assertNotRegex(output
, 'NO-CARRIER')
1852 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
1862 '26-bridge-slave-interface-1.network',
1863 '26-bridge-slave-interface-2.network',
1864 '26-bridge-vlan-master.network',
1865 '26-bridge-vlan-slave.network',
1866 'bridge99-ignore-carrier-loss.network',
1869 routing_policy_rule_tables
= ['100']
1872 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1873 remove_links(self
.links
)
1874 stop_networkd(show_logs
=False)
1877 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1878 remove_links(self
.links
)
1879 remove_unit_from_networkd_path(self
.units
)
1880 stop_networkd(show_logs
=True)
1882 def test_bridge_vlan(self
):
1883 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
1884 '26-bridge.netdev', '26-bridge-vlan-master.network')
1886 wait_online(['test1:enslaved', 'bridge99:degraded'])
1888 output
= check_output('bridge vlan show dev test1')
1890 self
.assertNotRegex(output
, '4063')
1891 for i
in range(4064, 4095):
1892 self
.assertRegex(output
, f
'{i}')
1893 self
.assertNotRegex(output
, '4095')
1895 output
= check_output('bridge vlan show dev bridge99')
1897 self
.assertNotRegex(output
, '4059')
1898 for i
in range(4060, 4095):
1899 self
.assertRegex(output
, f
'{i}')
1900 self
.assertNotRegex(output
, '4095')
1902 def test_bridge_property(self
):
1903 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1904 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1907 wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
1909 output
= check_output('ip -d link show test1')
1911 self
.assertRegex(output
, 'master')
1912 self
.assertRegex(output
, 'bridge')
1914 output
= check_output('ip -d link show dummy98')
1916 self
.assertRegex(output
, 'master')
1917 self
.assertRegex(output
, 'bridge')
1919 output
= check_output('ip addr show bridge99')
1921 self
.assertRegex(output
, '192.168.0.15/24')
1923 output
= check_output('bridge -d link show dummy98')
1925 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
1926 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
1927 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
1928 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
1929 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
1930 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
1931 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
1932 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
1934 # CONFIG_BRIDGE_IGMP_SNOOPING=y
1935 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
1936 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
1938 check_output('ip address add 192.168.0.16/24 dev bridge99')
1941 output
= check_output('ip addr show bridge99')
1943 self
.assertRegex(output
, '192.168.0.16/24')
1945 self
.assertEqual(call('ip link del test1'), 0)
1948 self
.check_operstate('bridge99', 'degraded-carrier')
1950 check_output('ip link del dummy98')
1953 self
.check_operstate('bridge99', 'no-carrier')
1955 output
= check_output('ip address show bridge99')
1957 self
.assertRegex(output
, 'NO-CARRIER')
1958 self
.assertNotRegex(output
, '192.168.0.15/24')
1959 self
.assertNotRegex(output
, '192.168.0.16/24')
1961 def test_bridge_ignore_carrier_loss(self
):
1962 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1963 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1964 'bridge99-ignore-carrier-loss.network')
1966 wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
1968 check_output('ip address add 192.168.0.16/24 dev bridge99')
1971 check_output('ip link del test1')
1972 check_output('ip link del dummy98')
1975 output
= check_output('ip address show bridge99')
1977 self
.assertRegex(output
, 'NO-CARRIER')
1978 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1979 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
1981 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
1982 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
1983 'bridge99-ignore-carrier-loss.network')
1985 wait_online(['bridge99:no-carrier'])
1987 for trial
in range(4):
1988 check_output('ip link add dummy98 type dummy')
1989 check_output('ip link set dummy98 up')
1991 check_output('ip link del dummy98')
1993 wait_online(['bridge99:routable', 'dummy98:enslaved'])
1995 output
= check_output('ip address show bridge99')
1997 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1999 output
= check_output('ip rule list table 100')
2001 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
2003 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
2007 '23-emit-lldp.network',
2012 remove_links(self
.links
)
2013 stop_networkd(show_logs
=False)
2016 remove_links(self
.links
)
2017 remove_unit_from_networkd_path(self
.units
)
2018 stop_networkd(show_logs
=True)
2020 def test_lldp(self
):
2021 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
2023 wait_online(['veth99:degraded', 'veth-peer:degraded'])
2025 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
2027 self
.assertRegex(output
, 'veth-peer')
2028 self
.assertRegex(output
, 'veth99')
2030 class NetworkdRATests(unittest
.TestCase
, Utilities
):
2035 'ipv6-prefix.network',
2036 'ipv6-prefix-veth.network']
2039 remove_links(self
.links
)
2040 stop_networkd(show_logs
=False)
2043 remove_links(self
.links
)
2044 remove_unit_from_networkd_path(self
.units
)
2045 stop_networkd(show_logs
=True)
2047 def test_ipv6_prefix_delegation(self
):
2048 warn_about_firewalld()
2049 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
2051 wait_online(['veth99:routable', 'veth-peer:degraded'])
2053 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2055 self
.assertRegex(output
, '2002:da8:1:0')
2057 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
2062 'dhcp-client.network',
2063 'dhcp-client-timezone-router.network',
2064 'dhcp-server.network',
2065 'dhcp-server-timezone-router.network']
2068 remove_links(self
.links
)
2069 stop_networkd(show_logs
=False)
2072 remove_links(self
.links
)
2073 remove_unit_from_networkd_path(self
.units
)
2074 stop_networkd(show_logs
=True)
2076 def test_dhcp_server(self
):
2077 warn_about_firewalld()
2078 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
2080 wait_online(['veth99:routable', 'veth-peer:routable'])
2082 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2084 self
.assertRegex(output
, '192.168.5.*')
2085 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
2086 self
.assertRegex(output
, 'DNS: 192.168.5.1')
2087 self
.assertRegex(output
, 'NTP: 192.168.5.1')
2089 def test_emit_router_timezone(self
):
2090 warn_about_firewalld()
2091 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
2093 wait_online(['veth99:routable', 'veth-peer:routable'])
2095 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2097 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
2098 self
.assertRegex(output
, '192.168.5.*')
2099 self
.assertRegex(output
, 'Europe/Berlin')
2101 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
2110 'dhcp-client-anonymize.network',
2111 'dhcp-client-gateway-onlink-implicit.network',
2112 'dhcp-client-ipv4-dhcp-settings.network',
2113 'dhcp-client-ipv4-only-ipv6-disabled.network',
2114 'dhcp-client-ipv4-only.network',
2115 'dhcp-client-ipv6-only.network',
2116 'dhcp-client-ipv6-rapid-commit.network',
2117 'dhcp-client-keep-configuration-dhcp-on-stop.network',
2118 'dhcp-client-keep-configuration-dhcp.network',
2119 'dhcp-client-listen-port.network',
2120 'dhcp-client-route-metric.network',
2121 'dhcp-client-route-table.network',
2122 'dhcp-client-use-routes-no.network',
2123 'dhcp-client-vrf.network',
2124 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
2125 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
2126 'dhcp-client-with-static-address.network',
2127 'dhcp-client.network',
2128 'dhcp-server-veth-peer.network',
2129 'dhcp-v4-server-veth-peer.network',
2133 stop_dnsmasq(dnsmasq_pid_file
)
2134 remove_links(self
.links
)
2135 stop_networkd(show_logs
=False)
2138 stop_dnsmasq(dnsmasq_pid_file
)
2141 remove_links(self
.links
)
2142 remove_unit_from_networkd_path(self
.units
)
2143 stop_networkd(show_logs
=True)
2145 def test_dhcp_client_ipv6_only(self
):
2146 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2149 wait_online(['veth-peer:carrier'])
2151 wait_online(['veth99:routable', 'veth-peer:routable'])
2153 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2155 self
.assertRegex(output
, '2600::')
2156 self
.assertNotRegex(output
, '192.168.5')
2158 # Confirm that ipv6 token is not set in the kernel
2159 output
= check_output('ip token show dev veth99')
2161 self
.assertRegex(output
, 'token :: dev veth99')
2163 def test_dhcp_client_ipv4_only(self
):
2164 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
2167 wait_online(['veth-peer:carrier'])
2169 wait_online(['veth99:routable', 'veth-peer:routable'])
2171 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2173 self
.assertNotRegex(output
, '2600::')
2174 self
.assertRegex(output
, '192.168.5')
2176 def test_dhcp_client_ipv4_ipv6(self
):
2177 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
2178 'dhcp-client-ipv4-only.network')
2180 wait_online(['veth-peer:carrier'])
2182 wait_online(['veth99:routable', 'veth-peer:routable'])
2184 # link become 'routable' when at least one protocol provide an valid address.
2185 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2186 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2188 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2190 self
.assertRegex(output
, '2600::')
2191 self
.assertRegex(output
, '192.168.5')
2193 def test_dhcp_client_settings(self
):
2194 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
2197 wait_online(['veth-peer:carrier'])
2199 wait_online(['veth99:routable', 'veth-peer:routable'])
2201 print('## ip address show dev veth99')
2202 output
= check_output('ip address show dev veth99')
2204 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2205 self
.assertRegex(output
, '192.168.5')
2206 self
.assertRegex(output
, '1492')
2209 print('## ip route show table main dev veth99')
2210 output
= check_output('ip route show table main dev veth99')
2212 self
.assertNotRegex(output
, 'proto dhcp')
2214 print('## ip route show table 211 dev veth99')
2215 output
= check_output('ip route show table 211 dev veth99')
2217 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
2218 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
2219 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
2221 print('## dnsmasq log')
2222 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
2223 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
2224 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
2225 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
2227 def test_dhcp6_client_settings_rapidcommit_true(self
):
2228 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2230 wait_online(['veth-peer:carrier'])
2232 wait_online(['veth99:routable', 'veth-peer:routable'])
2234 output
= check_output('ip address show dev veth99')
2236 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2237 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
2239 def test_dhcp6_client_settings_rapidcommit_false(self
):
2240 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
2242 wait_online(['veth-peer:carrier'])
2244 wait_online(['veth99:routable', 'veth-peer:routable'])
2246 output
= check_output('ip address show dev veth99')
2248 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2249 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
2251 def test_dhcp_client_settings_anonymize(self
):
2252 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
2254 wait_online(['veth-peer:carrier'])
2256 wait_online(['veth99:routable', 'veth-peer:routable'])
2258 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
2259 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
2260 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
2262 def test_dhcp_client_listen_port(self
):
2263 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
2265 wait_online(['veth-peer:carrier'])
2266 start_dnsmasq('--dhcp-alternate-port=67,5555')
2267 wait_online(['veth99:routable', 'veth-peer:routable'])
2269 # link become 'routable' when at least one protocol provide an valid address.
2270 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2271 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2273 output
= check_output('ip -4 address show dev veth99')
2275 self
.assertRegex(output
, '192.168.5.* dynamic')
2277 def test_dhcp_client_with_static_address(self
):
2278 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
2279 'dhcp-client-with-static-address.network')
2281 wait_online(['veth-peer:carrier'])
2283 wait_online(['veth99:routable', 'veth-peer:routable'])
2285 output
= check_output('ip address show dev veth99 scope global')
2287 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
2288 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
2290 output
= check_output('ip route show dev veth99')
2292 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
2293 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
2294 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
2295 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
2297 def test_dhcp_route_table_id(self
):
2298 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
2300 wait_online(['veth-peer:carrier'])
2302 wait_online(['veth99:routable', 'veth-peer:routable'])
2304 output
= check_output('ip route show table 12')
2306 self
.assertRegex(output
, 'veth99 proto dhcp')
2307 self
.assertRegex(output
, '192.168.5.1')
2309 def test_dhcp_route_metric(self
):
2310 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
2312 wait_online(['veth-peer:carrier'])
2314 wait_online(['veth99:routable', 'veth-peer:routable'])
2316 output
= check_output('ip route show dev veth99')
2318 self
.assertRegex(output
, 'metric 24')
2320 def test_dhcp_client_use_routes_no(self
):
2321 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2322 'dhcp-client-use-routes-no.network')
2324 wait_online(['veth-peer:carrier'])
2325 start_dnsmasq(lease_time
='2m')
2326 wait_online(['veth99:routable', 'veth-peer:routable'])
2328 output
= check_output('ip address show dev veth99 scope global')
2330 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2332 output
= check_output('ip route show dev veth99')
2334 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
2335 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
2336 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
2337 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
2339 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2340 print('Wait for the dynamic address to be renewed')
2343 wait_online(['veth99:routable'])
2345 output
= check_output('ip route show dev veth99')
2347 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
2348 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
2349 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
2350 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
2352 def test_dhcp_keep_configuration_dhcp(self
):
2353 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
2355 wait_online(['veth-peer:carrier'])
2356 start_dnsmasq(lease_time
='2m')
2357 wait_online(['veth99:routable', 'veth-peer:routable'])
2359 output
= check_output('ip address show dev veth99 scope global')
2361 self
.assertRegex(output
, r
'192.168.5.*')
2363 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2365 self
.assertRegex(output
, r
'192.168.5.*')
2367 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
2368 stop_dnsmasq(dnsmasq_pid_file
)
2370 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2371 print('Wait for the dynamic address to be expired')
2374 print('The lease address should be kept after lease expired')
2375 output
= check_output('ip address show dev veth99 scope global')
2377 self
.assertRegex(output
, r
'192.168.5.*')
2379 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2381 self
.assertRegex(output
, r
'192.168.5.*')
2383 check_output('systemctl stop systemd-networkd')
2385 print('The lease address should be kept after networkd stopped')
2386 output
= check_output('ip address show dev veth99 scope global')
2388 self
.assertRegex(output
, r
'192.168.5.*')
2390 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2392 self
.assertRegex(output
, r
'192.168.5.*')
2394 check_output('systemctl start systemd-networkd')
2395 wait_online(['veth-peer:routable'])
2397 print('Still the lease address should be kept after networkd restarted')
2398 output
= check_output('ip address show dev veth99 scope global')
2400 self
.assertRegex(output
, r
'192.168.5.*')
2402 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2404 self
.assertRegex(output
, r
'192.168.5.*')
2406 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
2407 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
2409 wait_online(['veth-peer:carrier'])
2410 start_dnsmasq(lease_time
='2m')
2411 wait_online(['veth99:routable', 'veth-peer:routable'])
2413 output
= check_output('ip address show dev veth99 scope global')
2415 self
.assertRegex(output
, r
'192.168.5.*')
2417 stop_dnsmasq(dnsmasq_pid_file
)
2418 check_output('systemctl stop systemd-networkd')
2420 output
= check_output('ip address show dev veth99 scope global')
2422 self
.assertRegex(output
, r
'192.168.5.*')
2425 wait_online(['veth-peer:routable'])
2427 output
= check_output('ip address show dev veth99 scope global')
2429 self
.assertNotRegex(output
, r
'192.168.5.*')
2431 def test_dhcp_client_reuse_address_as_static(self
):
2432 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
2434 wait_online(['veth-peer:carrier'])
2436 wait_online(['veth99:routable', 'veth-peer:routable'])
2438 # link become 'routable' when at least one protocol provide an valid address.
2439 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2440 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2442 output
= check_output('ip address show dev veth99 scope global')
2444 self
.assertRegex(output
, '192.168.5')
2445 self
.assertRegex(output
, '2600::')
2447 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
2448 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
2449 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
2450 print(static_network
)
2452 remove_unit_from_networkd_path(['dhcp-client.network'])
2454 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
2455 f
.write(static_network
)
2457 # When networkd started, the links are already configured, so let's wait for 5 seconds
2458 # the links to be re-configured.
2460 wait_online(['veth99:routable', 'veth-peer:routable'])
2462 output
= check_output('ip -4 address show dev veth99 scope global')
2464 self
.assertRegex(output
, '192.168.5')
2465 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
2467 output
= check_output('ip -6 address show dev veth99 scope global')
2469 self
.assertRegex(output
, '2600::')
2470 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
2472 @expectedFailureIfModuleIsNotAvailable('vrf')
2473 def test_dhcp_client_vrf(self
):
2474 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
2475 '25-vrf.netdev', '25-vrf.network')
2477 wait_online(['veth-peer:carrier'])
2479 wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
2481 # link become 'routable' when at least one protocol provide an valid address.
2482 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2483 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2485 print('## ip -d link show dev vrf99')
2486 output
= check_output('ip -d link show dev vrf99')
2488 self
.assertRegex(output
, 'vrf table 42')
2490 print('## ip address show vrf vrf99')
2491 output
= check_output('ip address show vrf vrf99')
2493 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2494 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2495 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)')
2496 self
.assertRegex(output
, 'inet6 .* scope link')
2498 print('## ip address show dev veth99')
2499 output
= check_output('ip address show dev veth99')
2501 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2502 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2503 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)')
2504 self
.assertRegex(output
, 'inet6 .* scope link')
2506 print('## ip route show vrf vrf99')
2507 output
= check_output('ip route show vrf vrf99')
2509 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
2510 self
.assertRegex(output
, 'default dev veth99 proto static scope link')
2511 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
2512 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
2513 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
2514 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
2516 print('## ip route show table main dev veth99')
2517 output
= check_output('ip route show table main dev veth99')
2519 self
.assertEqual(output
, '')
2521 def test_dhcp_client_gateway_onlink_implicit(self
):
2522 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2523 'dhcp-client-gateway-onlink-implicit.network')
2525 wait_online(['veth-peer:carrier'])
2527 wait_online(['veth99:routable', 'veth-peer:routable'])
2529 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2531 self
.assertRegex(output
, '192.168.5')
2533 output
= check_output('ip route list dev veth99 10.0.0.0/8')
2535 self
.assertRegex(output
, 'onlink')
2536 output
= check_output('ip route list dev veth99 192.168.100.0/24')
2538 self
.assertRegex(output
, 'onlink')
2540 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
2541 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2542 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
2544 wait_online(['veth-peer:carrier'])
2545 start_dnsmasq(lease_time
='2m')
2546 wait_online(['veth99:routable', 'veth-peer:routable'])
2548 output
= check_output('ip address show dev veth99')
2551 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2552 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2553 output
= check_output('ip -6 address show dev veth99 scope link')
2554 self
.assertRegex(output
, 'inet6 .* scope link')
2555 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2556 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2557 output
= check_output('ip -4 address show dev veth99 scope link')
2558 self
.assertNotRegex(output
, 'inet .* scope link')
2560 print('Wait for the dynamic address to be expired')
2563 output
= check_output('ip address show dev veth99')
2566 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2567 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2568 output
= check_output('ip -6 address show dev veth99 scope link')
2569 self
.assertRegex(output
, 'inet6 .* scope link')
2570 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2571 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2572 output
= check_output('ip -4 address show dev veth99 scope link')
2573 self
.assertNotRegex(output
, 'inet .* scope link')
2575 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
2577 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
2578 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2579 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
2581 wait_online(['veth99:degraded', 'veth-peer:routable'])
2583 output
= check_output('ip address show dev veth99')
2586 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2587 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2588 output
= check_output('ip -6 address show dev veth99 scope link')
2589 self
.assertRegex(output
, 'inet6 .* scope link')
2590 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2591 self
.assertNotRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2592 output
= check_output('ip -4 address show dev veth99 scope link')
2593 self
.assertRegex(output
, 'inet .* scope link')
2595 def test_dhcp_client_route_remove_on_renew(self
):
2596 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2597 'dhcp-client-ipv4-only-ipv6-disabled.network')
2599 wait_online(['veth-peer:carrier'])
2600 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
2601 wait_online(['veth99:routable', 'veth-peer:routable'])
2603 # test for issue #12490
2605 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2607 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2609 for line
in output
.splitlines():
2610 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
2611 address1
= line
.split()[1].split('/')[0]
2614 output
= check_output('ip -4 route show dev veth99')
2616 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2617 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2619 stop_dnsmasq(dnsmasq_pid_file
)
2620 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
2622 print('Wait for the dynamic address to be expired')
2625 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2627 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2629 for line
in output
.splitlines():
2630 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
2631 address2
= line
.split()[1].split('/')[0]
2634 self
.assertNotEqual(address1
, address2
)
2636 output
= check_output('ip -4 route show dev veth99')
2638 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2639 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2640 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
2641 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
2643 if __name__
== '__main__':
2644 parser
= argparse
.ArgumentParser()
2645 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
2646 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
2647 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
2648 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
2649 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
2650 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
2651 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
2652 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
2653 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
2654 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
2657 if ns
.networkd_bin
or ns
.wait_online_bin
or ns
.networkctl_bin
:
2658 print('WARNING: --networkd, --wait-online, or --networkctl options are ignored when --build-dir is specified.')
2659 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
2660 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
2661 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
2664 networkd_bin
= ns
.networkd_bin
2665 if ns
.wait_online_bin
:
2666 wait_online_bin
= ns
.wait_online_bin
2667 if ns
.networkctl_bin
:
2668 networkctl_bin
= ns
.networkctl_bin
2670 use_valgrind
= ns
.use_valgrind
2671 enable_debug
= ns
.enable_debug
2672 asan_options
= ns
.asan_options
2673 lsan_options
= ns
.lsan_options
2674 ubsan_options
= ns
.ubsan_options
2677 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
2678 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
2680 networkctl_cmd
= [networkctl_bin
]
2681 wait_online_cmd
= [wait_online_bin
]
2684 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
2686 env
.update({ 'ASAN_OPTIONS' : asan_options
})
2688 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
2690 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
2693 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,