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 resolved_bin
='/usr/lib/systemd/systemd-resolved'
27 wait_online_bin
='/usr/lib/systemd/systemd-networkd-wait-online'
28 networkctl_bin
='/usr/bin/networkctl'
29 resolvectl_bin
='/usr/bin/resolvectl'
30 timedatectl_bin
='/usr/bin/timedatectl'
38 def check_output(*command
, **kwargs
):
39 # This replaces both check_output and check_call (output can be ignored)
40 command
= command
[0].split() + list(command
[1:])
41 return subprocess
.check_output(command
, universal_newlines
=True, **kwargs
).rstrip()
43 def call(*command
, **kwargs
):
44 command
= command
[0].split() + list(command
[1:])
45 return subprocess
.call(command
, universal_newlines
=True, **kwargs
)
47 def run(*command
, **kwargs
):
48 command
= command
[0].split() + list(command
[1:])
49 return subprocess
.run(command
, universal_newlines
=True, **kwargs
)
51 def is_module_available(module_name
):
52 lsmod_output
= check_output('lsmod')
53 module_re
= re
.compile(rf
'^{re.escape(module_name)}\b', re
.MULTILINE
)
54 return module_re
.search(lsmod_output
) or not call('modprobe', module_name
)
56 def expectedFailureIfModuleIsNotAvailable(module_name
):
58 if not is_module_available(module_name
):
59 return unittest
.expectedFailure(func
)
64 def expectedFailureIfERSPANModuleIsNotAvailable():
66 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')
68 call('ip link del erspan99')
71 return unittest
.expectedFailure(func
)
75 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable():
77 rc
= call('ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
79 call('ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
82 return unittest
.expectedFailure(func
)
86 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
88 rc
= call('ip rule add not from 192.168.100.19 ipproto tcp table 7')
90 call('ip rule del not from 192.168.100.19 ipproto tcp table 7')
93 return unittest
.expectedFailure(func
)
97 def expectedFailureIfLinkFileFieldIsNotSet():
100 rc
= call('ip link add name dummy99 type dummy')
102 ret
= run('udevadm info -w10s /sys/class/net/dummy99', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
103 if ret
.returncode
== 0 and 'E: ID_NET_LINK_FILE=' in ret
.stdout
.rstrip():
105 call('ip link del dummy99')
110 return unittest
.expectedFailure(func
)
115 os
.makedirs(network_unit_file_path
, exist_ok
=True)
116 os
.makedirs(networkd_ci_path
, exist_ok
=True)
118 shutil
.rmtree(networkd_ci_path
)
119 copytree(os
.path
.join(os
.path
.dirname(os
.path
.abspath(__file__
)), 'conf'), networkd_ci_path
)
121 check_output('systemctl stop systemd-networkd.socket')
122 check_output('systemctl stop systemd-networkd.service')
123 check_output('systemctl stop systemd-resolved.service')
132 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin
,
136 drop_in
+= ['ExecStart=!!' + networkd_bin
]
138 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
140 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
142 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
144 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
145 if asan_options
or lsan_options
or ubsan_options
:
146 drop_in
+= ['SystemCallFilter=']
147 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
148 drop_in
+= ['MemoryDenyWriteExecute=no']
150 os
.makedirs('/run/systemd/system/systemd-networkd.service.d', exist_ok
=True)
151 with
open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode
='w') as f
:
152 f
.write('\n'.join(drop_in
))
160 drop_in
+= ['ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + resolved_bin
]
162 drop_in
+= ['ExecStart=!!' + resolved_bin
]
164 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
166 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
168 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
170 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
171 if asan_options
or lsan_options
or ubsan_options
:
172 drop_in
+= ['SystemCallFilter=']
173 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
174 drop_in
+= ['MemoryDenyWriteExecute=no']
176 os
.makedirs('/run/systemd/system/systemd-resolved.service.d', exist_ok
=True)
177 with
open('/run/systemd/system/systemd-resolved.service.d/00-override.conf', mode
='w') as f
:
178 f
.write('\n'.join(drop_in
))
180 check_output('systemctl daemon-reload')
181 print(check_output('systemctl cat systemd-networkd.service'))
182 print(check_output('systemctl cat systemd-resolved.service'))
183 check_output('systemctl restart systemd-resolved')
185 def tearDownModule():
186 shutil
.rmtree(networkd_ci_path
)
188 check_output('systemctl stop systemd-networkd.service')
189 check_output('systemctl stop systemd-resolved.service')
191 shutil
.rmtree('/run/systemd/system/systemd-networkd.service.d')
192 shutil
.rmtree('/run/systemd/system/systemd-resolved.service.d')
193 check_output('systemctl daemon-reload')
195 check_output('systemctl start systemd-networkd.socket')
196 check_output('systemctl start systemd-resolved.service')
198 def read_link_attr(link
, dev
, attribute
):
199 with
open(os
.path
.join(os
.path
.join(os
.path
.join('/sys/class/net/', link
), dev
), attribute
)) as f
:
200 return f
.readline().strip()
202 def read_bridge_port_attr(bridge
, link
, attribute
):
203 path_bridge
= os
.path
.join('/sys/devices/virtual/net', bridge
)
204 path_port
= 'lower_' + link
+ '/brport'
205 path
= os
.path
.join(path_bridge
, path_port
)
207 with
open(os
.path
.join(path
, attribute
)) as f
:
208 return f
.readline().strip()
210 def link_exists(link
):
211 return os
.path
.exists(os
.path
.join('/sys/class/net', link
))
213 def remove_links(links
):
215 if link_exists(link
):
216 call('ip link del dev', link
)
219 def remove_fou_ports(ports
):
221 call('ip fou del port', port
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
223 def remove_routing_policy_rule_tables(tables
):
227 rc
= call('ip rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
229 def remove_routes(routes
):
230 for route_type
, addr
in routes
:
231 call('ip route del', route_type
, addr
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
233 def remove_l2tp_tunnels(tunnel_ids
):
234 output
= check_output('ip l2tp show tunnel')
235 for tid
in tunnel_ids
:
236 words
='Tunnel ' + tid
+ ', encap'
238 call('ip l2tp del tunnel tid', tid
)
241 def read_ipv6_sysctl_attr(link
, attribute
):
242 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, link
), attribute
)) as f
:
243 return f
.readline().strip()
245 def read_ipv4_sysctl_attr(link
, attribute
):
246 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv4_path
, link
), attribute
)) as f
:
247 return f
.readline().strip()
249 def copy_unit_to_networkd_unit_path(*units
):
252 shutil
.copy(os
.path
.join(networkd_ci_path
, unit
), network_unit_file_path
)
253 if (os
.path
.exists(os
.path
.join(networkd_ci_path
, unit
+ '.d'))):
254 copytree(os
.path
.join(networkd_ci_path
, unit
+ '.d'), os
.path
.join(network_unit_file_path
, unit
+ '.d'))
256 def remove_unit_from_networkd_path(units
):
258 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
))):
259 os
.remove(os
.path
.join(network_unit_file_path
, unit
))
260 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
+ '.d'))):
261 shutil
.rmtree(os
.path
.join(network_unit_file_path
, unit
+ '.d'))
263 def warn_about_firewalld():
264 rc
= call('systemctl -q is-active firewalld.service')
266 print('\nWARNING: firewalld.service is active. The test may fail.')
268 def start_dnsmasq(additional_options
='', ipv4_range
='192.168.5.10,192.168.5.200', ipv6_range
='2600::10,2600::20', lease_time
='1h'):
269 warn_about_firewalld()
270 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
271 check_output(dnsmasq_command
)
273 def stop_dnsmasq(pid_file
):
274 if os
.path
.exists(pid_file
):
275 with
open(pid_file
, 'r') as f
:
276 pid
= f
.read().rstrip(' \t\r\n\0')
277 os
.kill(int(pid
), signal
.SIGTERM
)
281 def search_words_in_dnsmasq_log(words
, show_all
=False):
282 if os
.path
.exists(dnsmasq_log_file
):
283 with
open (dnsmasq_log_file
) as in_file
:
284 contents
= in_file
.read()
287 for line
in contents
.splitlines():
290 print("%s, %s" % (words
, line
))
294 def remove_lease_file():
295 if os
.path
.exists(os
.path
.join(networkd_ci_path
, 'lease')):
296 os
.remove(os
.path
.join(networkd_ci_path
, 'lease'))
298 def remove_log_file():
299 if os
.path
.exists(dnsmasq_log_file
):
300 os
.remove(dnsmasq_log_file
)
302 def remove_networkd_state_files():
303 if os
.path
.exists(os
.path
.join(networkd_runtime_directory
, 'state')):
304 os
.remove(os
.path
.join(networkd_runtime_directory
, 'state'))
306 def stop_networkd(show_logs
=True, remove_state_files
=True):
308 invocation_id
= check_output('systemctl show systemd-networkd -p InvocationID --value')
309 check_output('systemctl stop systemd-networkd')
311 print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
))
312 if remove_state_files
:
313 remove_networkd_state_files()
315 def start_networkd(sleep_sec
=0):
316 check_output('systemctl start systemd-networkd')
318 time
.sleep(sleep_sec
)
320 def restart_networkd(sleep_sec
=0, show_logs
=True, remove_state_files
=True):
321 stop_networkd(show_logs
, remove_state_files
)
322 start_networkd(sleep_sec
)
324 def wait_online(links_with_operstate
, timeout
='20s', bool_any
=False):
325 args
= wait_online_cmd
+ [f
'--timeout={timeout}'] + [f
'--interface={link}' for link
in links_with_operstate
]
329 check_output(*args
, env
=env
)
330 except subprocess
.CalledProcessError
:
331 for link
in links_with_operstate
:
332 output
= check_output(*networkctl_cmd
, 'status', link
.split(':')[0], env
=env
)
336 def get_operstate(link
, show_status
=True, setup_state
='configured'):
337 output
= check_output(*networkctl_cmd
, 'status', link
, env
=env
)
340 for line
in output
.splitlines():
341 if 'State:' in line
and (not setup_state
or setup_state
in line
):
342 return line
.split()[1]
346 def check_link_exists(self
, link
):
347 self
.assertTrue(link_exists(link
))
349 def check_operstate(self
, link
, expected
, show_status
=True, setup_state
='configured'):
350 self
.assertRegex(get_operstate(link
, show_status
, setup_state
), expected
)
352 def wait_address(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
353 for i
in range(timeout_sec
):
356 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
357 if re
.search(address_regex
, output
):
360 self
.assertRegex(output
, address_regex
)
362 class NetworkctlTests(unittest
.TestCase
, Utilities
):
371 '11-dummy-mtu.netdev',
374 'netdev-link-local-addressing-yes.network',
378 remove_links(self
.links
)
379 stop_networkd(show_logs
=False)
382 remove_links(self
.links
)
383 remove_unit_from_networkd_path(self
.units
)
384 stop_networkd(show_logs
=True)
387 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
390 wait_online(['test1:degraded'])
392 output
= check_output(*networkctl_cmd
, 'list', env
=env
)
393 self
.assertRegex(output
, '1 lo ')
394 self
.assertRegex(output
, 'test1')
396 output
= check_output(*networkctl_cmd
, 'list', 'test1', env
=env
)
397 self
.assertNotRegex(output
, '1 lo ')
398 self
.assertRegex(output
, 'test1')
400 output
= check_output(*networkctl_cmd
, 'list', 'te*', env
=env
)
401 self
.assertNotRegex(output
, '1 lo ')
402 self
.assertRegex(output
, 'test1')
404 output
= check_output(*networkctl_cmd
, 'status', 'te*', env
=env
)
405 self
.assertNotRegex(output
, '1: lo ')
406 self
.assertRegex(output
, 'test1')
408 output
= check_output(*networkctl_cmd
, 'status', 'tes[a-z][0-9]', env
=env
)
409 self
.assertNotRegex(output
, '1: lo ')
410 self
.assertRegex(output
, 'test1')
413 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
416 wait_online(['test1:degraded'])
418 output
= check_output(*networkctl_cmd
, 'status', 'test1', env
=env
)
419 self
.assertRegex(output
, 'MTU: 1600')
422 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
424 wait_online(['test1:degraded'])
426 output
= check_output(*networkctl_cmd
, 'status', 'test1')
428 self
.assertRegex(output
, 'Type: ether')
430 output
= check_output(*networkctl_cmd
, 'status', 'lo')
432 self
.assertRegex(output
, 'Type: loopback')
434 @expectedFailureIfLinkFileFieldIsNotSet()
435 def test_udev_link_file(self
):
436 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
438 wait_online(['test1:degraded'])
440 output
= check_output(*networkctl_cmd
, 'status', 'test1')
442 self
.assertRegex(output
, r
'Link File: (?:/usr)/lib/systemd/network/99-default.link')
443 self
.assertRegex(output
, r
'Network File: /run/systemd/network/11-dummy.network')
445 output
= check_output(*networkctl_cmd
, 'status', 'lo')
447 self
.assertRegex(output
, r
'Link File: (?:/usr)/lib/systemd/network/99-default.link')
448 self
.assertRegex(output
, r
'Network File: n/a')
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
):
464 links_remove_earlier
= [
528 '10-dropin-test.netdev',
532 '13-not-match-udev-property.network',
533 '14-match-udev-property.network',
534 '15-name-conflict-test.netdev',
537 '21-vlan-test1.network',
540 '25-6rd-tunnel.netdev',
542 '25-bond-balanced-tlb.netdev',
544 '25-bridge-configure-without-carrier.network',
546 '25-erspan-tunnel-local-any.netdev',
547 '25-erspan-tunnel.netdev',
548 '25-fou-gretap.netdev',
550 '25-fou-ipip.netdev',
551 '25-fou-ipproto-gre.netdev',
552 '25-fou-ipproto-ipip.netdev',
555 '25-gretap-tunnel-local-any.netdev',
556 '25-gretap-tunnel.netdev',
557 '25-gre-tunnel-any-any.netdev',
558 '25-gre-tunnel-local-any.netdev',
559 '25-gre-tunnel-remote-any.netdev',
560 '25-gre-tunnel.netdev',
561 '25-ip6gretap-tunnel-local-any.netdev',
562 '25-ip6gretap-tunnel.netdev',
563 '25-ip6gre-tunnel-any-any.netdev',
564 '25-ip6gre-tunnel-local-any.netdev',
565 '25-ip6gre-tunnel-remote-any.netdev',
566 '25-ip6gre-tunnel.netdev',
567 '25-ip6tnl-tunnel-any-any.netdev',
568 '25-ip6tnl-tunnel-local-any.netdev',
569 '25-ip6tnl-tunnel-remote-any.netdev',
570 '25-ip6tnl-tunnel.netdev',
571 '25-ipip-tunnel-any-any.netdev',
572 '25-ipip-tunnel-independent.netdev',
573 '25-ipip-tunnel-independent-loopback.netdev',
574 '25-ipip-tunnel-local-any.netdev',
575 '25-ipip-tunnel-remote-any.netdev',
576 '25-ipip-tunnel.netdev',
579 '25-isatap-tunnel.netdev',
584 '25-sit-tunnel-any-any.netdev',
585 '25-sit-tunnel-local-any.netdev',
586 '25-sit-tunnel-remote-any.netdev',
587 '25-sit-tunnel.netdev',
590 '25-tunnel-local-any.network',
591 '25-tunnel-remote-any.network',
596 '25-vti6-tunnel-any-any.netdev',
597 '25-vti6-tunnel-local-any.netdev',
598 '25-vti6-tunnel-remote-any.netdev',
599 '25-vti6-tunnel.netdev',
600 '25-vti-tunnel-any-any.netdev',
601 '25-vti-tunnel-local-any.netdev',
602 '25-vti-tunnel-remote-any.netdev',
603 '25-vti-tunnel.netdev',
606 '25-wireguard-23-peers.netdev',
607 '25-wireguard-23-peers.network',
608 '25-wireguard-preshared-key.txt',
609 '25-wireguard-private-key.txt',
610 '25-wireguard.netdev',
611 '25-wireguard.network',
613 '25-xfrm-independent.netdev',
629 'netdev-link-local-addressing-yes.network',
633 'vxlan-test1.network',
643 remove_fou_ports(self
.fou_ports
)
644 remove_links(self
.links_remove_earlier
)
645 remove_links(self
.links
)
646 stop_networkd(show_logs
=False)
649 remove_fou_ports(self
.fou_ports
)
650 remove_links(self
.links_remove_earlier
)
651 remove_links(self
.links
)
652 remove_unit_from_networkd_path(self
.units
)
653 stop_networkd(show_logs
=True)
655 def test_dropin_and_name_conflict(self
):
656 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
659 wait_online(['dropin-test:off'])
661 output
= check_output('ip link show dropin-test')
663 self
.assertRegex(output
, '00:50:56:c0:00:28')
665 def test_match_udev_property(self
):
666 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
668 wait_online(['dummy98:routable'])
670 output
= check_output('networkctl status dummy98')
672 self
.assertRegex(output
, 'Network File: /run/systemd/network/14-match-udev-property')
674 def test_wait_online_any(self
):
675 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
678 wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
680 self
.check_operstate('bridge99', '(?:off|no-carrier)', setup_state
='configuring')
681 self
.check_operstate('test1', 'degraded')
683 def test_bridge(self
):
684 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
687 wait_online(['bridge99:no-carrier'])
689 tick
= os
.sysconf('SC_CLK_TCK')
690 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
691 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
692 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge','forward_delay')) / tick
))
693 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge','ageing_time')) / tick
))
694 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge','priority')))
695 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','multicast_querier')))
696 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','multicast_snooping')))
697 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','stp_state')))
700 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
703 wait_online(['bond99:off', 'bond98:off'])
705 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
706 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
707 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
708 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
709 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
710 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
711 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
712 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
713 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
714 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
715 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
717 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
718 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
721 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
722 '21-vlan.network', '21-vlan-test1.network')
725 wait_online(['test1:degraded', 'vlan99:routable'])
727 output
= check_output('ip -d link show test1')
729 self
.assertRegex(output
, ' mtu 2000 ')
731 output
= check_output('ip -d link show vlan99')
733 self
.assertRegex(output
, ' mtu 2000 ')
734 self
.assertRegex(output
, 'REORDER_HDR')
735 self
.assertRegex(output
, 'LOOSE_BINDING')
736 self
.assertRegex(output
, 'GVRP')
737 self
.assertRegex(output
, 'MVRP')
738 self
.assertRegex(output
, ' id 99 ')
740 output
= check_output('ip -4 address show dev test1')
742 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
743 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
745 output
= check_output('ip -4 address show dev vlan99')
747 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
749 def test_macvtap(self
):
750 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
751 with self
.subTest(mode
=mode
):
752 if mode
!= 'private':
754 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
755 '11-dummy.netdev', 'macvtap.network')
756 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
757 f
.write('[MACVTAP]\nMode=' + mode
)
760 wait_online(['macvtap99:degraded', 'test1:degraded'])
762 output
= check_output('ip -d link show macvtap99')
764 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
766 def test_macvlan(self
):
767 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
768 with self
.subTest(mode
=mode
):
769 if mode
!= 'private':
771 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
772 '11-dummy.netdev', 'macvlan.network')
773 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
774 f
.write('[MACVLAN]\nMode=' + mode
)
777 wait_online(['macvlan99:degraded', 'test1:degraded'])
779 output
= check_output('ip -d link show test1')
781 self
.assertRegex(output
, ' mtu 2000 ')
783 output
= check_output('ip -d link show macvlan99')
785 self
.assertRegex(output
, ' mtu 2000 ')
786 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
788 @expectedFailureIfModuleIsNotAvailable('ipvlan')
789 def test_ipvlan(self
):
790 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
791 with self
.subTest(mode
=mode
, flag
=flag
):
794 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
795 '11-dummy.netdev', 'ipvlan.network')
796 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
797 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
800 wait_online(['ipvlan99:degraded', 'test1:degraded'])
802 output
= check_output('ip -d link show ipvlan99')
804 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
806 @expectedFailureIfModuleIsNotAvailable('ipvtap')
807 def test_ipvtap(self
):
808 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
809 with self
.subTest(mode
=mode
, flag
=flag
):
812 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
813 '11-dummy.netdev', 'ipvtap.network')
814 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
815 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
818 wait_online(['ipvtap99:degraded', 'test1:degraded'])
820 output
= check_output('ip -d link show ipvtap99')
822 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
825 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
828 wait_online(['veth99:degraded', 'veth-peer:degraded'])
830 output
= check_output('ip -d link show veth99')
832 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
833 output
= check_output('ip -d link show veth-peer')
835 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
838 copy_unit_to_networkd_unit_path('25-tun.netdev')
841 wait_online(['tun99:off'])
843 output
= check_output('ip -d link show tun99')
845 # Old ip command does not support IFF_ flags
846 self
.assertRegex(output
, 'tun (?:type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
849 copy_unit_to_networkd_unit_path('25-tap.netdev')
852 wait_online(['tap99:off'])
854 output
= check_output('ip -d link show tap99')
856 # Old ip command does not support IFF_ flags
857 self
.assertRegex(output
, 'tun (?:type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
859 @expectedFailureIfModuleIsNotAvailable('vrf')
861 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
864 wait_online(['vrf99:carrier'])
866 @expectedFailureIfModuleIsNotAvailable('vcan')
868 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
871 wait_online(['vcan99:carrier'])
873 @expectedFailureIfModuleIsNotAvailable('vxcan')
874 def test_vxcan(self
):
875 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
878 wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
880 @expectedFailureIfModuleIsNotAvailable('wireguard')
881 def test_wireguard(self
):
882 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
883 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
884 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt')
886 wait_online(['wg99:carrier', 'wg98:routable'])
888 if shutil
.which('wg'):
891 output
= check_output('wg show wg99 listen-port')
892 self
.assertRegex(output
, '51820')
893 output
= check_output('wg show wg99 fwmark')
894 self
.assertRegex(output
, '0x4d2')
895 output
= check_output('wg show wg99 allowed-ips')
896 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
897 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
898 output
= check_output('wg show wg99 persistent-keepalive')
899 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
900 output
= check_output('wg show wg99 endpoints')
901 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
902 output
= check_output('wg show wg99 private-key')
903 self
.assertRegex(output
, r
'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
904 output
= check_output('wg show wg99 preshared-keys')
905 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
906 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
908 output
= check_output('wg show wg98 private-key')
909 self
.assertRegex(output
, r
'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
911 def test_geneve(self
):
912 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
915 wait_online(['geneve99:degraded'])
917 output
= check_output('ip -d link show geneve99')
919 self
.assertRegex(output
, '192.168.22.1')
920 self
.assertRegex(output
, '6082')
921 self
.assertRegex(output
, 'udpcsum')
922 self
.assertRegex(output
, 'udp6zerocsumrx')
924 def test_ipip_tunnel(self
):
925 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
926 '25-ipip-tunnel.netdev', '25-tunnel.network',
927 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
928 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
929 '25-ipip-tunnel-any-any.netdev', '25-tunnel-any-any.network')
931 wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'ipiptun96:routable', 'dummy98:degraded'])
933 output
= check_output('ip -d link show ipiptun99')
935 self
.assertRegex(output
, 'ipip (?:ipip |)remote 192.169.224.239 local 192.168.223.238 dev dummy98')
936 output
= check_output('ip -d link show ipiptun98')
938 self
.assertRegex(output
, 'ipip (?:ipip |)remote 192.169.224.239 local any dev dummy98')
939 output
= check_output('ip -d link show ipiptun97')
941 self
.assertRegex(output
, 'ipip (?:ipip |)remote any local 192.168.223.238 dev dummy98')
942 output
= check_output('ip -d link show ipiptun96')
944 self
.assertRegex(output
, 'ipip (?:ipip |)remote any local any dev dummy98')
946 def test_gre_tunnel(self
):
947 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
948 '25-gre-tunnel.netdev', '25-tunnel.network',
949 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
950 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
951 '25-gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
953 wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'gretun96:routable', 'dummy98:degraded'])
955 output
= check_output('ip -d link show gretun99')
957 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
958 self
.assertRegex(output
, 'ikey 1.2.3.103')
959 self
.assertRegex(output
, 'okey 1.2.4.103')
960 self
.assertRegex(output
, 'iseq')
961 self
.assertRegex(output
, 'oseq')
962 output
= check_output('ip -d link show gretun98')
964 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
965 self
.assertRegex(output
, 'ikey 0.0.0.104')
966 self
.assertRegex(output
, 'okey 0.0.0.104')
967 self
.assertNotRegex(output
, 'iseq')
968 self
.assertNotRegex(output
, 'oseq')
969 output
= check_output('ip -d link show gretun97')
971 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
972 self
.assertRegex(output
, 'ikey 0.0.0.105')
973 self
.assertRegex(output
, 'okey 0.0.0.105')
974 self
.assertNotRegex(output
, 'iseq')
975 self
.assertNotRegex(output
, 'oseq')
976 output
= check_output('ip -d link show gretun96')
978 self
.assertRegex(output
, 'gre remote any local any dev dummy98')
979 self
.assertRegex(output
, 'ikey 0.0.0.106')
980 self
.assertRegex(output
, 'okey 0.0.0.106')
981 self
.assertNotRegex(output
, 'iseq')
982 self
.assertNotRegex(output
, 'oseq')
984 def test_ip6gre_tunnel(self
):
985 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
986 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
987 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
988 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
989 '25-ip6gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
992 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
994 self
.check_link_exists('dummy98')
995 self
.check_link_exists('ip6gretun99')
996 self
.check_link_exists('ip6gretun98')
997 self
.check_link_exists('ip6gretun97')
998 self
.check_link_exists('ip6gretun96')
1000 output
= check_output('ip -d link show ip6gretun99')
1002 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1003 output
= check_output('ip -d link show ip6gretun98')
1005 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
1006 output
= check_output('ip -d link show ip6gretun97')
1008 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
1009 output
= check_output('ip -d link show ip6gretun96')
1011 self
.assertRegex(output
, 'ip6gre remote any local any dev dummy98')
1013 def test_gretap_tunnel(self
):
1014 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
1015 '25-gretap-tunnel.netdev', '25-tunnel.network',
1016 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1018 wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
1020 output
= check_output('ip -d link show gretap99')
1022 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1023 self
.assertRegex(output
, 'ikey 0.0.0.106')
1024 self
.assertRegex(output
, 'okey 0.0.0.106')
1025 self
.assertRegex(output
, 'iseq')
1026 self
.assertRegex(output
, 'oseq')
1027 output
= check_output('ip -d link show gretap98')
1029 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
1030 self
.assertRegex(output
, 'ikey 0.0.0.107')
1031 self
.assertRegex(output
, 'okey 0.0.0.107')
1032 self
.assertRegex(output
, 'iseq')
1033 self
.assertRegex(output
, 'oseq')
1035 def test_ip6gretap_tunnel(self
):
1036 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
1037 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1038 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1040 wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
1042 output
= check_output('ip -d link show ip6gretap99')
1044 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1045 output
= check_output('ip -d link show ip6gretap98')
1047 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1049 def test_vti_tunnel(self
):
1050 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
1051 '25-vti-tunnel.netdev', '25-tunnel.network',
1052 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1053 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1054 '25-vti-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1056 wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'vtitun96:routable', 'dummy98:degraded'])
1058 output
= check_output('ip -d link show vtitun99')
1060 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1061 output
= check_output('ip -d link show vtitun98')
1063 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
1064 output
= check_output('ip -d link show vtitun97')
1066 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
1067 output
= check_output('ip -d link show vtitun96')
1069 self
.assertRegex(output
, 'vti remote any local any dev dummy98')
1071 def test_vti6_tunnel(self
):
1072 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
1073 '25-vti6-tunnel.netdev', '25-tunnel.network',
1074 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1075 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1077 wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
1079 output
= check_output('ip -d link show vti6tun99')
1081 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1082 output
= check_output('ip -d link show vti6tun98')
1084 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
1085 output
= check_output('ip -d link show vti6tun97')
1087 self
.assertRegex(output
, 'vti6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1089 def test_ip6tnl_tunnel(self
):
1090 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
1091 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1092 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1093 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1095 wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
1097 output
= check_output('ip -d link show ip6tnl99')
1099 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1100 output
= check_output('ip -d link show ip6tnl98')
1102 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
1103 output
= check_output('ip -d link show ip6tnl97')
1105 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1107 def test_sit_tunnel(self
):
1108 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1109 '25-sit-tunnel.netdev', '25-tunnel.network',
1110 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1111 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1112 '25-sit-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1114 wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'sittun96:routable', 'dummy98:degraded'])
1116 output
= check_output('ip -d link show sittun99')
1118 self
.assertRegex(output
, "sit (?:ip6ip |)remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1119 output
= check_output('ip -d link show sittun98')
1121 self
.assertRegex(output
, "sit (?:ip6ip |)remote 10.65.223.239 local any dev dummy98")
1122 output
= check_output('ip -d link show sittun97')
1124 self
.assertRegex(output
, "sit (?:ip6ip |)remote any local 10.65.223.238 dev dummy98")
1125 output
= check_output('ip -d link show sittun96')
1127 self
.assertRegex(output
, "sit (?:ip6ip |)remote any local any dev dummy98")
1129 def test_isatap_tunnel(self
):
1130 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1131 '25-isatap-tunnel.netdev', '25-tunnel.network')
1133 wait_online(['isataptun99:routable', 'dummy98:degraded'])
1135 output
= check_output('ip -d link show isataptun99')
1137 self
.assertRegex(output
, "isatap ")
1139 def test_6rd_tunnel(self
):
1140 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1141 '25-6rd-tunnel.netdev', '25-tunnel.network')
1143 wait_online(['sittun99:routable', 'dummy98:degraded'])
1145 output
= check_output('ip -d link show sittun99')
1147 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1149 @expectedFailureIfERSPANModuleIsNotAvailable()
1150 def test_erspan_tunnel(self
):
1151 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1152 '25-erspan-tunnel.netdev', '25-tunnel.network',
1153 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1155 wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1157 output
= check_output('ip -d link show erspan99')
1159 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1160 self
.assertRegex(output
, 'ikey 0.0.0.101')
1161 self
.assertRegex(output
, 'okey 0.0.0.101')
1162 self
.assertRegex(output
, 'iseq')
1163 self
.assertRegex(output
, 'oseq')
1164 output
= check_output('ip -d link show erspan98')
1166 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1167 self
.assertRegex(output
, '102')
1168 self
.assertRegex(output
, 'ikey 0.0.0.102')
1169 self
.assertRegex(output
, 'okey 0.0.0.102')
1170 self
.assertRegex(output
, 'iseq')
1171 self
.assertRegex(output
, 'oseq')
1173 def test_tunnel_independent(self
):
1174 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1177 wait_online(['ipiptun99:carrier'])
1179 def test_tunnel_independent_loopback(self
):
1180 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent-loopback.netdev', 'netdev-link-local-addressing-yes.network')
1183 wait_online(['ipiptun99:carrier'])
1185 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1186 def test_xfrm(self
):
1187 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'xfrm.network',
1188 '25-xfrm.netdev', 'netdev-link-local-addressing-yes.network')
1191 wait_online(['xfrm99:degraded', 'dummy98:degraded'])
1193 output
= check_output('ip link show dev xfrm99')
1196 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1197 def test_xfrm_independent(self
):
1198 copy_unit_to_networkd_unit_path('25-xfrm-independent.netdev', 'netdev-link-local-addressing-yes.network')
1201 wait_online(['xfrm99:degraded'])
1203 @expectedFailureIfModuleIsNotAvailable('fou')
1205 # The following redundant check is necessary for CentOS CI.
1206 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1207 self
.assertTrue(is_module_available('fou'))
1209 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1210 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1211 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1214 wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'])
1216 output
= check_output('ip fou show')
1218 self
.assertRegex(output
, 'port 55555 ipproto 4')
1219 self
.assertRegex(output
, 'port 55556 ipproto 47')
1221 output
= check_output('ip -d link show ipiptun96')
1223 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1224 output
= check_output('ip -d link show sittun96')
1226 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1227 output
= check_output('ip -d link show gretun96')
1229 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1230 output
= check_output('ip -d link show gretap96')
1232 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1234 def test_vxlan(self
):
1235 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1236 '11-dummy.netdev', 'vxlan-test1.network')
1239 wait_online(['test1:degraded', 'vxlan99:degraded'])
1241 output
= check_output('ip -d link show vxlan99')
1243 self
.assertRegex(output
, '999')
1244 self
.assertRegex(output
, '5555')
1245 self
.assertRegex(output
, 'l2miss')
1246 self
.assertRegex(output
, 'l3miss')
1247 self
.assertRegex(output
, 'udpcsum')
1248 self
.assertRegex(output
, 'udp6zerocsumtx')
1249 self
.assertRegex(output
, 'udp6zerocsumrx')
1250 self
.assertRegex(output
, 'remcsumtx')
1251 self
.assertRegex(output
, 'remcsumrx')
1252 self
.assertRegex(output
, 'gbp')
1254 output
= check_output('bridge fdb show dev vxlan99')
1256 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1257 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1258 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1260 def test_macsec(self
):
1261 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1262 'macsec.network', '12-dummy.netdev')
1265 wait_online(['dummy98:degraded', 'macsec99:routable'])
1267 output
= check_output('ip -d link show macsec99')
1269 self
.assertRegex(output
, 'macsec99@dummy98')
1270 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1271 self
.assertRegex(output
, 'encrypt on')
1273 output
= check_output('ip macsec show macsec99')
1275 self
.assertRegex(output
, 'encrypt on')
1276 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1277 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1278 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1279 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1280 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1281 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1282 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1283 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1284 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1285 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1286 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1288 def test_nlmon(self
):
1289 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1292 wait_online(['nlmon99:carrier'])
1294 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1305 '25-l2tp-dummy.network',
1306 '25-l2tp-ip.netdev',
1307 '25-l2tp-udp.netdev']
1309 l2tp_tunnel_ids
= [ '10' ]
1312 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1313 remove_links(self
.links
)
1314 stop_networkd(show_logs
=False)
1317 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1318 remove_links(self
.links
)
1319 remove_unit_from_networkd_path(self
.units
)
1320 stop_networkd(show_logs
=True)
1322 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1323 def test_l2tp_udp(self
):
1324 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-udp.netdev')
1327 wait_online(['test1:routable', 'l2tp-ses1:off', 'l2tp-ses2:off'])
1329 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1331 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1332 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1333 self
.assertRegex(output
, "Peer tunnel 11")
1334 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1335 self
.assertRegex(output
, "UDP checksum: enabled")
1337 output
= check_output('ip l2tp show session tid 10 session_id 15')
1339 self
.assertRegex(output
, "Session 15 in tunnel 10")
1340 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1341 self
.assertRegex(output
, "interface name: l2tp-ses1")
1343 output
= check_output('ip l2tp show session tid 10 session_id 17')
1345 self
.assertRegex(output
, "Session 17 in tunnel 10")
1346 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1347 self
.assertRegex(output
, "interface name: l2tp-ses2")
1349 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1350 def test_l2tp_ip(self
):
1351 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-ip.netdev')
1354 wait_online(['test1:routable', 'l2tp-ses3:off', 'l2tp-ses4:off'])
1356 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1358 self
.assertRegex(output
, "Tunnel 10, encap IP")
1359 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1360 self
.assertRegex(output
, "Peer tunnel 12")
1362 output
= check_output('ip l2tp show session tid 10 session_id 25')
1364 self
.assertRegex(output
, "Session 25 in tunnel 10")
1365 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1366 self
.assertRegex(output
, "interface name: l2tp-ses3")
1368 output
= check_output('ip l2tp show session tid 10 session_id 27')
1370 self
.assertRegex(output
, "Session 27 in tunnel 10")
1371 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1372 self
.assertRegex(output
, "interface name: l2tp-ses4")
1374 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1384 '23-active-slave.network',
1385 '24-keep-configuration-static.network',
1386 '24-search-domain.network',
1387 '25-address-link-section.network',
1388 '25-address-preferred-lifetime-zero-ipv6.network',
1389 '25-address-static.network',
1390 '25-bind-carrier.network',
1391 '25-bond-active-backup-slave.netdev',
1392 '25-fibrule-invert.network',
1393 '25-fibrule-port-range.network',
1394 '25-ipv6-address-label-section.network',
1395 '25-neighbor-section.network',
1396 '25-link-local-addressing-no.network',
1397 '25-link-local-addressing-yes.network',
1398 '25-link-section-unmanaged.network',
1399 '25-route-ipv6-src.network',
1400 '25-route-static.network',
1401 '25-sysctl-disable-ipv6.network',
1402 '25-sysctl.network',
1403 'configure-without-carrier.network',
1404 'routing-policy-rule-dummy98.network',
1405 'routing-policy-rule-test1.network']
1407 routing_policy_rule_tables
= ['7', '8']
1408 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1411 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1412 remove_routes(self
.routes
)
1413 remove_links(self
.links
)
1414 stop_networkd(show_logs
=False)
1417 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1418 remove_routes(self
.routes
)
1419 remove_links(self
.links
)
1420 remove_unit_from_networkd_path(self
.units
)
1421 stop_networkd(show_logs
=True)
1423 def test_address_static(self
):
1424 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1427 wait_online(['dummy98:routable'])
1429 output
= check_output('ip -4 address show dev dummy98')
1431 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1432 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1433 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1436 self
.assertNotRegex(output
, '10.10.0.1/16')
1437 self
.assertNotRegex(output
, '10.10.0.2/16')
1439 output
= check_output('ip -4 address show dev dummy98 label 32')
1440 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1442 output
= check_output('ip -4 address show dev dummy98 label 33')
1443 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1445 output
= check_output('ip -4 address show dev dummy98 label 34')
1446 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1448 output
= check_output('ip -4 address show dev dummy98 label 35')
1449 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1451 output
= check_output('ip -6 address show dev dummy98')
1453 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1454 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1455 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1456 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1457 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1458 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1460 def test_address_preferred_lifetime_zero_ipv6(self
):
1461 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero-ipv6.network', '12-dummy.netdev')
1464 self
.check_link_exists('dummy98')
1465 self
.check_operstate('dummy98', 'routable', setup_state
='configuring')
1467 output
= check_output('ip address show dummy98')
1469 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1470 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1472 def test_configure_without_carrier(self
):
1473 copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
1475 wait_online(['test1:routable'])
1477 output
= check_output(*networkctl_cmd
, 'status', 'test1')
1479 self
.assertRegex(output
, '192.168.0.15')
1480 self
.assertRegex(output
, '192.168.0.1')
1481 self
.assertRegex(output
, 'routable')
1483 def test_routing_policy_rule(self
):
1484 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1486 wait_online(['test1:degraded'])
1488 output
= check_output('ip rule')
1490 self
.assertRegex(output
, '111')
1491 self
.assertRegex(output
, 'from 192.168.100.18')
1492 self
.assertRegex(output
, r
'tos (?:0x08|throughput)\s')
1493 self
.assertRegex(output
, 'iif test1')
1494 self
.assertRegex(output
, 'oif test1')
1495 self
.assertRegex(output
, 'lookup 7')
1497 def test_routing_policy_rule_issue_11280(self
):
1498 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1499 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1501 for trial
in range(3):
1502 # Remove state files only first time
1504 wait_online(['test1:degraded', 'dummy98:degraded'])
1507 output
= check_output('ip rule list table 7')
1509 self
.assertRegex(output
, '111: from 192.168.100.18 tos (?:0x08|throughput) iif test1 oif test1 lookup 7')
1511 output
= check_output('ip rule list table 8')
1513 self
.assertRegex(output
, '112: from 192.168.101.18 tos (?:0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1515 stop_networkd(remove_state_files
=False)
1517 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1518 def test_routing_policy_rule_port_range(self
):
1519 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1521 wait_online(['test1:degraded'])
1523 output
= check_output('ip rule')
1525 self
.assertRegex(output
, '111')
1526 self
.assertRegex(output
, 'from 192.168.100.18')
1527 self
.assertRegex(output
, '1123-1150')
1528 self
.assertRegex(output
, '3224-3290')
1529 self
.assertRegex(output
, 'tcp')
1530 self
.assertRegex(output
, 'lookup 7')
1532 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1533 def test_routing_policy_rule_invert(self
):
1534 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1536 wait_online(['test1:degraded'])
1538 output
= check_output('ip rule')
1540 self
.assertRegex(output
, '111')
1541 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
1542 self
.assertRegex(output
, 'tcp')
1543 self
.assertRegex(output
, 'lookup 7')
1545 def test_route_static(self
):
1546 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1548 wait_online(['dummy98:routable'])
1550 output
= check_output('ip -6 route show dev dummy98')
1552 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1553 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
1555 output
= check_output('ip -6 route show dev dummy98 default')
1556 self
.assertRegex(output
, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1558 output
= check_output('ip -4 route show dev dummy98')
1560 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1561 self
.assertRegex(output
, '149.10.124.64 proto static scope link')
1562 self
.assertRegex(output
, '169.254.0.0/16 proto static scope link metric 2048')
1563 self
.assertRegex(output
, '192.168.1.1 proto static initcwnd 20')
1564 self
.assertRegex(output
, '192.168.1.2 proto static initrwnd 30')
1566 output
= check_output('ip -4 route show dev dummy98 default')
1567 self
.assertRegex(output
, 'default via 149.10.125.65 proto static onlink')
1568 self
.assertRegex(output
, 'default via 149.10.124.64 proto static')
1569 self
.assertRegex(output
, 'default proto static')
1571 output
= check_output('ip route show type blackhole')
1573 self
.assertRegex(output
, 'blackhole 202.54.1.2 proto static')
1575 output
= check_output('ip route show type unreachable')
1577 self
.assertRegex(output
, 'unreachable 202.54.1.3 proto static')
1579 output
= check_output('ip route show type prohibit')
1581 self
.assertRegex(output
, 'prohibit 202.54.1.4 proto static')
1583 def test_ip_route_ipv6_src_route(self
):
1584 # a dummy device does not make the addresses go through tentative state, so we
1585 # reuse a bond from an earlier test, which does make the addresses go through
1586 # tentative state, and do our test on that
1587 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1589 wait_online(['dummy98:enslaved', 'bond199:routable'])
1591 output
= check_output('ip -6 route list dev bond199')
1593 self
.assertRegex(output
, 'abcd::/16')
1594 self
.assertRegex(output
, 'src')
1595 self
.assertRegex(output
, '2001:1234:56:8f63::2')
1597 def test_ip_link_mac_address(self
):
1598 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
1600 wait_online(['dummy98:degraded'])
1602 output
= check_output('ip link show dummy98')
1604 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
1606 def test_ip_link_unmanaged(self
):
1607 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
1610 self
.check_link_exists('dummy98')
1612 self
.check_operstate('dummy98', 'off', setup_state
='unmanaged')
1614 def test_ipv6_address_label(self
):
1615 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
1617 wait_online(['dummy98:degraded'])
1619 output
= check_output('ip addrlabel list')
1621 self
.assertRegex(output
, '2004:da8:1::/64')
1623 def test_ipv6_neighbor(self
):
1624 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
1626 wait_online(['dummy98:degraded'], timeout
='40s')
1628 output
= check_output('ip neigh list dev dummy98')
1630 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
1631 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
1633 def test_link_local_addressing(self
):
1634 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
1635 '25-link-local-addressing-no.network', '12-dummy.netdev')
1637 wait_online(['test1:degraded', 'dummy98:carrier'])
1639 output
= check_output('ip address show dev test1')
1641 self
.assertRegex(output
, 'inet .* scope link')
1642 self
.assertRegex(output
, 'inet6 .* scope link')
1644 output
= check_output('ip address show dev dummy98')
1646 self
.assertNotRegex(output
, 'inet6* .* scope link')
1649 Documentation/networking/ip-sysctl.txt
1651 addr_gen_mode - INTEGER
1652 Defines how link-local and autoconf addresses are generated.
1654 0: generate address based on EUI64 (default)
1655 1: do no generate a link-local address, use EUI64 for addresses generated
1657 2: generate stable privacy addresses, using the secret from
1658 stable_secret (RFC7217)
1659 3: generate stable privacy addresses, using a random secret if unset
1662 test1_addr_gen_mode
= ''
1663 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
1664 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
1668 # if stable_secret is unset, then EIO is returned
1669 test1_addr_gen_mode
= '0'
1671 test1_addr_gen_mode
= '2'
1673 test1_addr_gen_mode
= '0'
1675 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
1676 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
1678 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
1679 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
1681 def test_sysctl(self
):
1682 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
1684 wait_online(['dummy98:degraded'])
1686 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
1687 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
1688 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
1689 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
1690 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
1691 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
1692 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
1694 def test_sysctl_disable_ipv6(self
):
1695 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
1697 print('## Disable ipv6')
1698 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
1699 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
1702 wait_online(['dummy98:routable'])
1704 output
= check_output('ip -4 address show dummy98')
1706 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1707 output
= check_output('ip -6 address show dummy98')
1709 self
.assertEqual(output
, '')
1710 output
= check_output('ip -4 route show dev dummy98')
1712 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
1713 output
= check_output('ip -6 route show dev dummy98')
1715 self
.assertEqual(output
, '')
1717 check_output('ip link del dummy98')
1719 print('## Enable ipv6')
1720 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
1721 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
1724 wait_online(['dummy98:routable'])
1726 output
= check_output('ip -4 address show dummy98')
1728 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1729 output
= check_output('ip -6 address show dummy98')
1731 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
1732 self
.assertRegex(output
, 'inet6 .* scope link')
1733 output
= check_output('ip -4 route show dev dummy98')
1735 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
1736 output
= check_output('ip -6 route show dev dummy98')
1738 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
1740 def test_bind_carrier(self
):
1741 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
1743 wait_online(['test1:routable'])
1745 check_output('ip link add dummy98 type dummy')
1746 check_output('ip link set dummy98 up')
1748 output
= check_output('ip address show test1')
1750 self
.assertRegex(output
, 'UP,LOWER_UP')
1751 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1752 self
.check_operstate('test1', 'routable')
1754 check_output('ip link add dummy99 type dummy')
1755 check_output('ip link set dummy99 up')
1757 output
= check_output('ip address show test1')
1759 self
.assertRegex(output
, 'UP,LOWER_UP')
1760 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1761 self
.check_operstate('test1', 'routable')
1763 check_output('ip link del dummy98')
1765 output
= check_output('ip address show test1')
1767 self
.assertRegex(output
, 'UP,LOWER_UP')
1768 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1769 self
.check_operstate('test1', 'routable')
1771 check_output('ip link del dummy99')
1773 output
= check_output('ip address show test1')
1775 self
.assertNotRegex(output
, 'UP,LOWER_UP')
1776 self
.assertRegex(output
, 'DOWN')
1777 self
.assertNotRegex(output
, '192.168.10')
1778 self
.check_operstate('test1', 'off')
1780 check_output('ip link add dummy98 type dummy')
1781 check_output('ip link set dummy98 up')
1783 output
= check_output('ip address show test1')
1785 self
.assertRegex(output
, 'UP,LOWER_UP')
1786 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1787 self
.check_operstate('test1', 'routable')
1789 def test_domain(self
):
1790 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
1792 wait_online(['dummy98:routable'])
1794 output
= check_output(*networkctl_cmd
, 'status', 'dummy98', env
=env
)
1796 self
.assertRegex(output
, 'Address: 192.168.42.100')
1797 self
.assertRegex(output
, 'DNS: 192.168.42.1')
1798 self
.assertRegex(output
, 'Search Domains: one')
1800 def test_keep_configuration_static(self
):
1801 check_output('systemctl stop systemd-networkd')
1803 check_output('ip link add name dummy98 type dummy')
1804 check_output('ip address add 10.1.2.3/16 dev dummy98')
1805 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
1806 output
= check_output('ip address show dummy98')
1808 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
1809 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
1810 output
= check_output('ip route show dev dummy98')
1813 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
1815 wait_online(['dummy98:routable'])
1817 output
= check_output('ip address show dummy98')
1819 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
1820 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
1822 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
1832 '23-active-slave.network',
1833 '23-bond199.network',
1834 '23-primary-slave.network',
1835 '25-bond-active-backup-slave.netdev',
1838 'bond-slave.network']
1841 remove_links(self
.links
)
1842 stop_networkd(show_logs
=False)
1845 remove_links(self
.links
)
1846 remove_unit_from_networkd_path(self
.units
)
1847 stop_networkd(show_logs
=True)
1849 def test_bond_active_slave(self
):
1850 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1852 wait_online(['dummy98:enslaved', 'bond199:degraded'])
1854 output
= check_output('ip -d link show bond199')
1856 self
.assertRegex(output
, 'active_slave dummy98')
1858 def test_bond_primary_slave(self
):
1859 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1861 wait_online(['dummy98:enslaved', 'bond199:degraded'])
1863 output
= check_output('ip -d link show bond199')
1865 self
.assertRegex(output
, 'primary dummy98')
1867 def test_bond_operstate(self
):
1868 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
1869 'bond99.network','bond-slave.network')
1871 wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
1873 output
= check_output('ip -d link show dummy98')
1875 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
1877 output
= check_output('ip -d link show test1')
1879 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
1881 output
= check_output('ip -d link show bond99')
1883 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
1885 self
.check_operstate('dummy98', 'enslaved')
1886 self
.check_operstate('test1', 'enslaved')
1887 self
.check_operstate('bond99', 'routable')
1889 check_output('ip link set dummy98 down')
1892 self
.check_operstate('dummy98', 'off')
1893 self
.check_operstate('test1', 'enslaved')
1894 self
.check_operstate('bond99', 'degraded-carrier')
1896 check_output('ip link set dummy98 up')
1899 self
.check_operstate('dummy98', 'enslaved')
1900 self
.check_operstate('test1', 'enslaved')
1901 self
.check_operstate('bond99', 'routable')
1903 check_output('ip link set dummy98 down')
1904 check_output('ip link set test1 down')
1907 self
.check_operstate('dummy98', 'off')
1908 self
.check_operstate('test1', 'off')
1910 for trial
in range(30):
1913 output
= check_output('ip address show bond99')
1915 if get_operstate('bond99') == 'no-carrier':
1918 # Huh? Kernel does not recognize that all slave interfaces are down?
1919 # Let's confirm that networkd's operstate is consistent with ip's result.
1920 self
.assertNotRegex(output
, 'NO-CARRIER')
1922 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
1932 '26-bridge-slave-interface-1.network',
1933 '26-bridge-slave-interface-2.network',
1934 '26-bridge-vlan-master.network',
1935 '26-bridge-vlan-slave.network',
1936 'bridge99-ignore-carrier-loss.network',
1939 routing_policy_rule_tables
= ['100']
1942 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1943 remove_links(self
.links
)
1944 stop_networkd(show_logs
=False)
1947 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1948 remove_links(self
.links
)
1949 remove_unit_from_networkd_path(self
.units
)
1950 stop_networkd(show_logs
=True)
1952 def test_bridge_vlan(self
):
1953 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
1954 '26-bridge.netdev', '26-bridge-vlan-master.network')
1956 wait_online(['test1:enslaved', 'bridge99:degraded'])
1958 output
= check_output('bridge vlan show dev test1')
1960 self
.assertNotRegex(output
, '4063')
1961 for i
in range(4064, 4095):
1962 self
.assertRegex(output
, f
'{i}')
1963 self
.assertNotRegex(output
, '4095')
1965 output
= check_output('bridge vlan show dev bridge99')
1967 self
.assertNotRegex(output
, '4059')
1968 for i
in range(4060, 4095):
1969 self
.assertRegex(output
, f
'{i}')
1970 self
.assertNotRegex(output
, '4095')
1972 def test_bridge_property(self
):
1973 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1974 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1977 wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
1979 output
= check_output('ip -d link show test1')
1981 self
.assertRegex(output
, 'master')
1982 self
.assertRegex(output
, 'bridge')
1984 output
= check_output('ip -d link show dummy98')
1986 self
.assertRegex(output
, 'master')
1987 self
.assertRegex(output
, 'bridge')
1989 output
= check_output('ip addr show bridge99')
1991 self
.assertRegex(output
, '192.168.0.15/24')
1993 output
= check_output('bridge -d link show dummy98')
1995 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
1996 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
1997 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
1998 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
1999 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
2000 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
2001 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
2002 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
2004 # CONFIG_BRIDGE_IGMP_SNOOPING=y
2005 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
2006 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
2008 check_output('ip address add 192.168.0.16/24 dev bridge99')
2011 output
= check_output('ip addr show bridge99')
2013 self
.assertRegex(output
, '192.168.0.16/24')
2015 self
.assertEqual(call('ip link del test1'), 0)
2018 self
.check_operstate('bridge99', 'degraded-carrier')
2020 check_output('ip link del dummy98')
2023 self
.check_operstate('bridge99', 'no-carrier')
2025 output
= check_output('ip address show bridge99')
2027 self
.assertRegex(output
, 'NO-CARRIER')
2028 self
.assertNotRegex(output
, '192.168.0.15/24')
2029 self
.assertNotRegex(output
, '192.168.0.16/24')
2031 def test_bridge_ignore_carrier_loss(self
):
2032 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2033 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2034 'bridge99-ignore-carrier-loss.network')
2036 wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2038 check_output('ip address add 192.168.0.16/24 dev bridge99')
2041 check_output('ip link del test1')
2042 check_output('ip link del dummy98')
2045 output
= check_output('ip address show bridge99')
2047 self
.assertRegex(output
, 'NO-CARRIER')
2048 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2049 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
2051 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
2052 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
2053 'bridge99-ignore-carrier-loss.network')
2055 wait_online(['bridge99:no-carrier'])
2057 for trial
in range(4):
2058 check_output('ip link add dummy98 type dummy')
2059 check_output('ip link set dummy98 up')
2061 check_output('ip link del dummy98')
2063 wait_online(['bridge99:routable', 'dummy98:enslaved'])
2065 output
= check_output('ip address show bridge99')
2067 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2069 output
= check_output('ip rule list table 100')
2071 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
2073 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
2077 '23-emit-lldp.network',
2082 remove_links(self
.links
)
2083 stop_networkd(show_logs
=False)
2086 remove_links(self
.links
)
2087 remove_unit_from_networkd_path(self
.units
)
2088 stop_networkd(show_logs
=True)
2090 def test_lldp(self
):
2091 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
2093 wait_online(['veth99:degraded', 'veth-peer:degraded'])
2095 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
2097 self
.assertRegex(output
, 'veth-peer')
2098 self
.assertRegex(output
, 'veth99')
2100 class NetworkdRATests(unittest
.TestCase
, Utilities
):
2105 'ipv6-prefix.network',
2106 'ipv6-prefix-veth.network']
2109 remove_links(self
.links
)
2110 stop_networkd(show_logs
=False)
2113 remove_links(self
.links
)
2114 remove_unit_from_networkd_path(self
.units
)
2115 stop_networkd(show_logs
=True)
2117 def test_ipv6_prefix_delegation(self
):
2118 warn_about_firewalld()
2119 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
2121 wait_online(['veth99:routable', 'veth-peer:degraded'])
2123 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2125 self
.assertRegex(output
, '2002:da8:1:0')
2127 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
2132 'dhcp-client.network',
2133 'dhcp-client-timezone-router.network',
2134 'dhcp-server.network',
2135 'dhcp-server-timezone-router.network']
2138 remove_links(self
.links
)
2139 stop_networkd(show_logs
=False)
2142 remove_links(self
.links
)
2143 remove_unit_from_networkd_path(self
.units
)
2144 stop_networkd(show_logs
=True)
2146 def test_dhcp_server(self
):
2147 warn_about_firewalld()
2148 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
2150 wait_online(['veth99:routable', 'veth-peer:routable'])
2152 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2154 self
.assertRegex(output
, '192.168.5.*')
2155 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
2156 self
.assertRegex(output
, 'DNS: 192.168.5.1')
2157 self
.assertRegex(output
, 'NTP: 192.168.5.1')
2159 def test_emit_router_timezone(self
):
2160 warn_about_firewalld()
2161 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
2163 wait_online(['veth99:routable', 'veth-peer:routable'])
2165 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2167 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
2168 self
.assertRegex(output
, '192.168.5.*')
2169 self
.assertRegex(output
, 'Europe/Berlin')
2171 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
2180 'dhcp-client-anonymize.network',
2181 'dhcp-client-gateway-onlink-implicit.network',
2182 'dhcp-client-ipv4-dhcp-settings.network',
2183 'dhcp-client-ipv4-only-ipv6-disabled.network',
2184 'dhcp-client-ipv4-only.network',
2185 'dhcp-client-ipv6-only.network',
2186 'dhcp-client-ipv6-rapid-commit.network',
2187 'dhcp-client-keep-configuration-dhcp-on-stop.network',
2188 'dhcp-client-keep-configuration-dhcp.network',
2189 'dhcp-client-listen-port.network',
2190 'dhcp-client-reassign-static-routes-ipv4.network',
2191 'dhcp-client-reassign-static-routes-ipv6.network',
2192 'dhcp-client-route-metric.network',
2193 'dhcp-client-route-table.network',
2194 'dhcp-client-use-dns-ipv4-and-ra.network',
2195 'dhcp-client-use-dns-ipv4.network',
2196 'dhcp-client-use-dns-no.network',
2197 'dhcp-client-use-dns-yes.network',
2198 'dhcp-client-use-routes-no.network',
2199 'dhcp-client-vrf.network',
2200 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
2201 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
2202 'dhcp-client-with-static-address.network',
2203 'dhcp-client.network',
2204 'dhcp-server-veth-peer.network',
2205 'dhcp-v4-server-veth-peer.network',
2209 stop_dnsmasq(dnsmasq_pid_file
)
2210 remove_links(self
.links
)
2211 stop_networkd(show_logs
=False)
2214 stop_dnsmasq(dnsmasq_pid_file
)
2217 remove_links(self
.links
)
2218 remove_unit_from_networkd_path(self
.units
)
2219 stop_networkd(show_logs
=True)
2221 def test_dhcp_client_ipv6_only(self
):
2222 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2225 wait_online(['veth-peer:carrier'])
2227 wait_online(['veth99:routable', 'veth-peer:routable'])
2229 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2231 self
.assertRegex(output
, '2600::')
2232 self
.assertNotRegex(output
, '192.168.5')
2234 # Confirm that ipv6 token is not set in the kernel
2235 output
= check_output('ip token show dev veth99')
2237 self
.assertRegex(output
, 'token :: dev veth99')
2239 def test_dhcp_client_ipv4_only(self
):
2240 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
2243 wait_online(['veth-peer:carrier'])
2245 wait_online(['veth99:routable', 'veth-peer:routable'])
2247 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2249 self
.assertNotRegex(output
, '2600::')
2250 self
.assertRegex(output
, '192.168.5')
2252 def test_dhcp_client_ipv4_ipv6(self
):
2253 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
2254 'dhcp-client-ipv4-only.network')
2256 wait_online(['veth-peer:carrier'])
2258 wait_online(['veth99:routable', 'veth-peer:routable'])
2260 # link become 'routable' when at least one protocol provide an valid address.
2261 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2262 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2264 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2266 self
.assertRegex(output
, '2600::')
2267 self
.assertRegex(output
, '192.168.5')
2269 def test_dhcp_client_settings(self
):
2270 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
2273 wait_online(['veth-peer:carrier'])
2275 wait_online(['veth99:routable', 'veth-peer:routable'])
2277 print('## ip address show dev veth99')
2278 output
= check_output('ip address show dev veth99')
2280 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2281 self
.assertRegex(output
, '192.168.5')
2282 self
.assertRegex(output
, '1492')
2285 print('## ip route show table main dev veth99')
2286 output
= check_output('ip route show table main dev veth99')
2288 self
.assertNotRegex(output
, 'proto dhcp')
2290 print('## ip route show table 211 dev veth99')
2291 output
= check_output('ip route show table 211 dev veth99')
2293 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
2294 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
2295 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
2297 print('## dnsmasq log')
2298 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
2299 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
2300 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
2301 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
2303 def test_dhcp6_client_settings_rapidcommit_true(self
):
2304 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2306 wait_online(['veth-peer:carrier'])
2308 wait_online(['veth99:routable', 'veth-peer:routable'])
2310 output
= check_output('ip address show dev veth99')
2312 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2313 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
2315 def test_dhcp6_client_settings_rapidcommit_false(self
):
2316 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
2318 wait_online(['veth-peer:carrier'])
2320 wait_online(['veth99:routable', 'veth-peer:routable'])
2322 output
= check_output('ip address show dev veth99')
2324 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2325 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
2327 def test_dhcp_client_settings_anonymize(self
):
2328 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
2330 wait_online(['veth-peer:carrier'])
2332 wait_online(['veth99:routable', 'veth-peer:routable'])
2334 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
2335 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
2336 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
2338 def test_dhcp_client_listen_port(self
):
2339 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
2341 wait_online(['veth-peer:carrier'])
2342 start_dnsmasq('--dhcp-alternate-port=67,5555')
2343 wait_online(['veth99:routable', 'veth-peer:routable'])
2345 # link become 'routable' when at least one protocol provide an valid address.
2346 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2347 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2349 output
= check_output('ip -4 address show dev veth99')
2351 self
.assertRegex(output
, '192.168.5.* dynamic')
2353 def test_dhcp_client_with_static_address(self
):
2354 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
2355 'dhcp-client-with-static-address.network')
2357 wait_online(['veth-peer:carrier'])
2359 wait_online(['veth99:routable', 'veth-peer:routable'])
2361 output
= check_output('ip address show dev veth99 scope global')
2363 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
2364 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
2366 output
= check_output('ip route show dev veth99')
2368 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
2369 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
2370 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
2371 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
2373 def test_dhcp_route_table_id(self
):
2374 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
2376 wait_online(['veth-peer:carrier'])
2378 wait_online(['veth99:routable', 'veth-peer:routable'])
2380 output
= check_output('ip route show table 12')
2382 self
.assertRegex(output
, 'veth99 proto dhcp')
2383 self
.assertRegex(output
, '192.168.5.1')
2385 def test_dhcp_route_metric(self
):
2386 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
2388 wait_online(['veth-peer:carrier'])
2390 wait_online(['veth99:routable', 'veth-peer:routable'])
2392 output
= check_output('ip route show dev veth99')
2394 self
.assertRegex(output
, 'metric 24')
2396 def test_dhcp_client_reassign_static_routes_ipv4(self
):
2397 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2398 'dhcp-client-reassign-static-routes-ipv4.network')
2400 wait_online(['veth-peer:carrier'])
2401 start_dnsmasq(lease_time
='2m')
2402 wait_online(['veth99:routable', 'veth-peer:routable'])
2404 output
= check_output('ip address show dev veth99 scope global')
2406 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2408 output
= check_output('ip route show dev veth99')
2410 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
2411 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
2412 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
2413 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
2415 stop_dnsmasq(dnsmasq_pid_file
)
2416 start_dnsmasq(ipv4_range
='192.168.5.210,192.168.5.220', lease_time
='2m')
2418 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2419 print('Wait for the dynamic address to be renewed')
2422 wait_online(['veth99:routable'])
2424 output
= check_output('ip route show dev veth99')
2426 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
2427 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
2428 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
2429 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
2431 def test_dhcp_client_reassign_static_routes_ipv6(self
):
2432 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2433 'dhcp-client-reassign-static-routes-ipv6.network')
2435 wait_online(['veth-peer:carrier'])
2436 start_dnsmasq(lease_time
='2m')
2437 wait_online(['veth99:routable', 'veth-peer:routable'])
2439 output
= check_output('ip address show dev veth99 scope global')
2441 self
.assertRegex(output
, r
'inet6 2600::[0-9a-f]*/128 scope global (?:noprefixroute dynamic|dynamic noprefixroute)')
2443 output
= check_output('ip -6 route show dev veth99')
2445 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
2446 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
2448 stop_dnsmasq(dnsmasq_pid_file
)
2449 start_dnsmasq(ipv6_range
='2600::30,2600::40', lease_time
='2m')
2451 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2452 print('Wait for the dynamic address to be renewed')
2455 wait_online(['veth99:routable'])
2457 output
= check_output('ip -6 route show dev veth99')
2459 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
2460 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
2462 def test_dhcp_keep_configuration_dhcp(self
):
2463 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
2465 wait_online(['veth-peer:carrier'])
2466 start_dnsmasq(lease_time
='2m')
2467 wait_online(['veth99:routable', 'veth-peer:routable'])
2469 output
= check_output('ip address show dev veth99 scope global')
2471 self
.assertRegex(output
, r
'192.168.5.*')
2473 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2475 self
.assertRegex(output
, r
'192.168.5.*')
2477 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
2478 stop_dnsmasq(dnsmasq_pid_file
)
2480 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2481 print('Wait for the dynamic address to be expired')
2484 print('The lease address should be kept after lease expired')
2485 output
= check_output('ip address show dev veth99 scope global')
2487 self
.assertRegex(output
, r
'192.168.5.*')
2489 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2491 self
.assertRegex(output
, r
'192.168.5.*')
2493 check_output('systemctl stop systemd-networkd')
2495 print('The lease address should be kept after networkd stopped')
2496 output
= check_output('ip address show dev veth99 scope global')
2498 self
.assertRegex(output
, r
'192.168.5.*')
2500 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2502 self
.assertRegex(output
, r
'192.168.5.*')
2504 check_output('systemctl start systemd-networkd')
2505 wait_online(['veth-peer:routable'])
2507 print('Still the lease address should be kept after networkd restarted')
2508 output
= check_output('ip address show dev veth99 scope global')
2510 self
.assertRegex(output
, r
'192.168.5.*')
2512 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2514 self
.assertRegex(output
, r
'192.168.5.*')
2516 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
2517 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
2519 wait_online(['veth-peer:carrier'])
2520 start_dnsmasq(lease_time
='2m')
2521 wait_online(['veth99:routable', 'veth-peer:routable'])
2523 output
= check_output('ip address show dev veth99 scope global')
2525 self
.assertRegex(output
, r
'192.168.5.*')
2527 stop_dnsmasq(dnsmasq_pid_file
)
2528 check_output('systemctl stop systemd-networkd')
2530 output
= check_output('ip address show dev veth99 scope global')
2532 self
.assertRegex(output
, r
'192.168.5.*')
2535 wait_online(['veth-peer:routable'])
2537 output
= check_output('ip address show dev veth99 scope global')
2539 self
.assertNotRegex(output
, r
'192.168.5.*')
2541 def test_dhcp_client_reuse_address_as_static(self
):
2542 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
2544 wait_online(['veth-peer:carrier'])
2546 wait_online(['veth99:routable', 'veth-peer:routable'])
2548 # link become 'routable' when at least one protocol provide an valid address.
2549 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2550 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2552 output
= check_output('ip address show dev veth99 scope global')
2554 self
.assertRegex(output
, '192.168.5')
2555 self
.assertRegex(output
, '2600::')
2557 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
2558 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
2559 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
2560 print(static_network
)
2562 remove_unit_from_networkd_path(['dhcp-client.network'])
2564 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
2565 f
.write(static_network
)
2567 # When networkd started, the links are already configured, so let's wait for 5 seconds
2568 # the links to be re-configured.
2570 wait_online(['veth99:routable', 'veth-peer:routable'])
2572 output
= check_output('ip -4 address show dev veth99 scope global')
2574 self
.assertRegex(output
, '192.168.5')
2575 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
2577 output
= check_output('ip -6 address show dev veth99 scope global')
2579 self
.assertRegex(output
, '2600::')
2580 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
2582 @expectedFailureIfModuleIsNotAvailable('vrf')
2583 def test_dhcp_client_vrf(self
):
2584 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
2585 '25-vrf.netdev', '25-vrf.network')
2587 wait_online(['veth-peer:carrier'])
2589 wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
2591 # link become 'routable' when at least one protocol provide an valid address.
2592 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2593 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2595 print('## ip -d link show dev vrf99')
2596 output
= check_output('ip -d link show dev vrf99')
2598 self
.assertRegex(output
, 'vrf table 42')
2600 print('## ip address show vrf vrf99')
2601 output
= check_output('ip address show vrf vrf99')
2603 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2604 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2605 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)')
2606 self
.assertRegex(output
, 'inet6 .* scope link')
2608 print('## ip address show dev veth99')
2609 output
= check_output('ip address show dev veth99')
2611 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2612 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2613 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)')
2614 self
.assertRegex(output
, 'inet6 .* scope link')
2616 print('## ip route show vrf vrf99')
2617 output
= check_output('ip route show vrf vrf99')
2619 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
2620 self
.assertRegex(output
, 'default dev veth99 proto static scope link')
2621 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
2622 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
2623 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
2624 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
2626 print('## ip route show table main dev veth99')
2627 output
= check_output('ip route show table main dev veth99')
2629 self
.assertEqual(output
, '')
2631 def test_dhcp_client_gateway_onlink_implicit(self
):
2632 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2633 'dhcp-client-gateway-onlink-implicit.network')
2635 wait_online(['veth-peer:carrier'])
2637 wait_online(['veth99:routable', 'veth-peer:routable'])
2639 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2641 self
.assertRegex(output
, '192.168.5')
2643 output
= check_output('ip route list dev veth99 10.0.0.0/8')
2645 self
.assertRegex(output
, 'onlink')
2646 output
= check_output('ip route list dev veth99 192.168.100.0/24')
2648 self
.assertRegex(output
, 'onlink')
2650 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
2651 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2652 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
2654 wait_online(['veth-peer:carrier'])
2655 start_dnsmasq(lease_time
='2m')
2656 wait_online(['veth99:routable', 'veth-peer:routable'])
2658 output
= check_output('ip address show dev veth99')
2661 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2662 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2663 output
= check_output('ip -6 address show dev veth99 scope link')
2664 self
.assertRegex(output
, 'inet6 .* scope link')
2665 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2666 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2667 output
= check_output('ip -4 address show dev veth99 scope link')
2668 self
.assertNotRegex(output
, 'inet .* scope link')
2670 print('Wait for the dynamic address to be expired')
2673 output
= check_output('ip address show dev veth99')
2676 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2677 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2678 output
= check_output('ip -6 address show dev veth99 scope link')
2679 self
.assertRegex(output
, 'inet6 .* scope link')
2680 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2681 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2682 output
= check_output('ip -4 address show dev veth99 scope link')
2683 self
.assertNotRegex(output
, 'inet .* scope link')
2685 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
2687 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
2688 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2689 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
2691 wait_online(['veth99:degraded', 'veth-peer:routable'])
2693 output
= check_output('ip address show dev veth99')
2696 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2697 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2698 output
= check_output('ip -6 address show dev veth99 scope link')
2699 self
.assertRegex(output
, 'inet6 .* scope link')
2700 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2701 self
.assertNotRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2702 output
= check_output('ip -4 address show dev veth99 scope link')
2703 self
.assertRegex(output
, 'inet .* scope link')
2705 def test_dhcp_client_route_remove_on_renew(self
):
2706 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2707 'dhcp-client-ipv4-only-ipv6-disabled.network')
2709 wait_online(['veth-peer:carrier'])
2710 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
2711 wait_online(['veth99:routable', 'veth-peer:routable'])
2713 # test for issue #12490
2715 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2717 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2719 for line
in output
.splitlines():
2720 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
2721 address1
= line
.split()[1].split('/')[0]
2724 output
= check_output('ip -4 route show dev veth99')
2726 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2727 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2729 stop_dnsmasq(dnsmasq_pid_file
)
2730 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
2732 print('Wait for the dynamic address to be expired')
2735 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2737 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2739 for line
in output
.splitlines():
2740 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
2741 address2
= line
.split()[1].split('/')[0]
2744 self
.assertNotEqual(address1
, address2
)
2746 output
= check_output('ip -4 route show dev veth99')
2748 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2749 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2750 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
2751 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
2753 def test_dhcp_client_use_dns_yes(self
):
2754 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-yes.network')
2757 wait_online(['veth-peer:carrier'])
2758 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
2759 wait_online(['veth99:routable', 'veth-peer:routable'])
2761 # link become 'routable' when at least one protocol provide an valid address.
2762 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2763 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2766 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
2768 self
.assertRegex(output
, '192.168.5.1')
2769 self
.assertRegex(output
, '2600::1')
2771 def test_dhcp_client_use_dns_no(self
):
2772 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-no.network')
2775 wait_online(['veth-peer:carrier'])
2776 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
2777 wait_online(['veth99:routable', 'veth-peer:routable'])
2779 # link become 'routable' when at least one protocol provide an valid address.
2780 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2781 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2784 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
2786 self
.assertNotRegex(output
, '192.168.5.1')
2787 self
.assertNotRegex(output
, '2600::1')
2789 def test_dhcp_client_use_dns_ipv4(self
):
2790 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4.network')
2793 wait_online(['veth-peer:carrier'])
2794 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
2795 wait_online(['veth99:routable', 'veth-peer:routable'])
2797 # link become 'routable' when at least one protocol provide an valid address.
2798 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2799 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2802 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
2804 self
.assertRegex(output
, '192.168.5.1')
2805 self
.assertNotRegex(output
, '2600::1')
2807 def test_dhcp_client_use_dns_ipv4_and_ra(self
):
2808 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4-and-ra.network')
2811 wait_online(['veth-peer:carrier'])
2812 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
2813 wait_online(['veth99:routable', 'veth-peer:routable'])
2815 # link become 'routable' when at least one protocol provide an valid address.
2816 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2817 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2820 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
2822 self
.assertRegex(output
, '192.168.5.1')
2823 self
.assertRegex(output
, '2600::1')
2825 if __name__
== '__main__':
2826 parser
= argparse
.ArgumentParser()
2827 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
2828 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
2829 parser
.add_argument('--resolved', help='Path to systemd-resolved', dest
='resolved_bin')
2830 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
2831 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
2832 parser
.add_argument('--resolvectl', help='Path to resolvectl', dest
='resolvectl_bin')
2833 parser
.add_argument('--timedatectl', help='Path to timedatectl', dest
='timedatectl_bin')
2834 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
2835 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
2836 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
2837 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
2838 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
2839 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
2842 if ns
.networkd_bin
or ns
.resolved_bin
or ns
.wait_online_bin
or ns
.networkctl_bin
or ns
.resolvectl_bin
or ns
.timedatectl_bin
:
2843 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
2844 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
2845 resolved_bin
= os
.path
.join(ns
.build_dir
, 'systemd-resolved')
2846 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
2847 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
2848 resolvectl_bin
= os
.path
.join(ns
.build_dir
, 'resolvectl')
2849 timedatectl_bin
= os
.path
.join(ns
.build_dir
, 'timedatectl')
2852 networkd_bin
= ns
.networkd_bin
2854 resolved_bin
= ns
.resolved_bin
2855 if ns
.wait_online_bin
:
2856 wait_online_bin
= ns
.wait_online_bin
2857 if ns
.networkctl_bin
:
2858 networkctl_bin
= ns
.networkctl_bin
2859 if ns
.resolvectl_bin
:
2860 resolvectl_bin
= ns
.resolvectl_bin
2861 if ns
.timedatectl_bin
:
2862 timedatectl_bin
= ns
.timedatectl_bin
2864 use_valgrind
= ns
.use_valgrind
2865 enable_debug
= ns
.enable_debug
2866 asan_options
= ns
.asan_options
2867 lsan_options
= ns
.lsan_options
2868 ubsan_options
= ns
.ubsan_options
2871 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
2872 resolvectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin
]
2873 timedatectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin
]
2874 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
2876 networkctl_cmd
= [networkctl_bin
]
2877 resolvectl_cmd
= [resolvectl_bin
]
2878 timedatectl_cmd
= [timedatectl_bin
]
2879 wait_online_cmd
= [wait_online_bin
]
2882 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
2884 env
.update({ 'ASAN_OPTIONS' : asan_options
})
2886 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
2888 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
2891 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,