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'
40 def check_output(*command
, **kwargs
):
41 # This replaces both check_output and check_call (output can be ignored)
42 command
= command
[0].split() + list(command
[1:])
43 return subprocess
.check_output(command
, universal_newlines
=True, **kwargs
).rstrip()
45 def call(*command
, **kwargs
):
46 command
= command
[0].split() + list(command
[1:])
47 return subprocess
.call(command
, universal_newlines
=True, **kwargs
)
49 def run(*command
, **kwargs
):
50 command
= command
[0].split() + list(command
[1:])
51 return subprocess
.run(command
, universal_newlines
=True, **kwargs
)
53 def is_module_available(module_name
):
54 lsmod_output
= check_output('lsmod')
55 module_re
= re
.compile(rf
'^{re.escape(module_name)}\b', re
.MULTILINE
)
56 return module_re
.search(lsmod_output
) or not call('modprobe', module_name
)
58 def expectedFailureIfModuleIsNotAvailable(module_name
):
60 if not is_module_available(module_name
):
61 return unittest
.expectedFailure(func
)
66 def expectedFailureIfERSPANModuleIsNotAvailable():
68 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')
70 call('ip link del erspan99')
73 return unittest
.expectedFailure(func
)
77 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable():
79 rc
= call('ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
81 call('ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
84 return unittest
.expectedFailure(func
)
88 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
90 rc
= call('ip rule add not from 192.168.100.19 ipproto tcp table 7')
92 call('ip rule del not from 192.168.100.19 ipproto tcp table 7')
95 return unittest
.expectedFailure(func
)
99 def expectedFailureIfLinkFileFieldIsNotSet():
102 rc
= call('ip link add name dummy99 type dummy')
104 ret
= run('udevadm info -w10s /sys/class/net/dummy99', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
105 if ret
.returncode
== 0 and 'E: ID_NET_LINK_FILE=' in ret
.stdout
.rstrip():
107 call('ip link del dummy99')
112 return unittest
.expectedFailure(func
)
119 os
.makedirs(network_unit_file_path
, exist_ok
=True)
120 os
.makedirs(networkd_ci_path
, exist_ok
=True)
122 shutil
.rmtree(networkd_ci_path
)
123 copytree(os
.path
.join(os
.path
.dirname(os
.path
.abspath(__file__
)), 'conf'), networkd_ci_path
)
125 for u
in ['systemd-networkd.socket', 'systemd-networkd.service', 'systemd-resolved.service', 'firewalld.service']:
126 if call(f
'systemctl is-active --quiet {u}') == 0:
127 check_output(f
'systemctl stop {u}')
128 running_units
.append(u
)
137 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin
,
141 drop_in
+= ['ExecStart=!!' + networkd_bin
]
143 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
145 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
147 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
149 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
150 if asan_options
or lsan_options
or ubsan_options
:
151 drop_in
+= ['SystemCallFilter=']
152 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
153 drop_in
+= ['MemoryDenyWriteExecute=no']
155 os
.makedirs('/run/systemd/system/systemd-networkd.service.d', exist_ok
=True)
156 with
open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode
='w') as f
:
157 f
.write('\n'.join(drop_in
))
165 drop_in
+= ['ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + resolved_bin
]
167 drop_in
+= ['ExecStart=!!' + resolved_bin
]
169 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
171 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
173 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
175 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
176 if asan_options
or lsan_options
or ubsan_options
:
177 drop_in
+= ['SystemCallFilter=']
178 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
179 drop_in
+= ['MemoryDenyWriteExecute=no']
181 os
.makedirs('/run/systemd/system/systemd-resolved.service.d', exist_ok
=True)
182 with
open('/run/systemd/system/systemd-resolved.service.d/00-override.conf', mode
='w') as f
:
183 f
.write('\n'.join(drop_in
))
185 check_output('systemctl daemon-reload')
186 print(check_output('systemctl cat systemd-networkd.service'))
187 print(check_output('systemctl cat systemd-resolved.service'))
188 check_output('systemctl restart systemd-resolved')
190 def tearDownModule():
193 shutil
.rmtree(networkd_ci_path
)
195 for u
in ['systemd-networkd.service', 'systemd-resolved.service']:
196 check_output(f
'systemctl stop {u}')
198 shutil
.rmtree('/run/systemd/system/systemd-networkd.service.d')
199 shutil
.rmtree('/run/systemd/system/systemd-resolved.service.d')
200 check_output('systemctl daemon-reload')
202 for u
in running_units
:
203 check_output(f
'systemctl start {u}')
205 def read_link_attr(link
, dev
, attribute
):
206 with
open(os
.path
.join(os
.path
.join(os
.path
.join('/sys/class/net/', link
), dev
), attribute
)) as f
:
207 return f
.readline().strip()
209 def read_bridge_port_attr(bridge
, link
, attribute
):
210 path_bridge
= os
.path
.join('/sys/devices/virtual/net', bridge
)
211 path_port
= 'lower_' + link
+ '/brport'
212 path
= os
.path
.join(path_bridge
, path_port
)
214 with
open(os
.path
.join(path
, attribute
)) as f
:
215 return f
.readline().strip()
217 def link_exists(link
):
218 return os
.path
.exists(os
.path
.join('/sys/class/net', link
))
220 def remove_links(links
):
222 if link_exists(link
):
223 call('ip link del dev', link
)
226 def remove_fou_ports(ports
):
228 call('ip fou del port', port
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
230 def remove_routing_policy_rule_tables(tables
):
234 rc
= call('ip rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
236 def remove_routes(routes
):
237 for route_type
, addr
in routes
:
238 call('ip route del', route_type
, addr
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
240 def remove_l2tp_tunnels(tunnel_ids
):
241 output
= check_output('ip l2tp show tunnel')
242 for tid
in tunnel_ids
:
243 words
='Tunnel ' + tid
+ ', encap'
245 call('ip l2tp del tunnel tid', tid
)
248 def read_ipv6_sysctl_attr(link
, attribute
):
249 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, link
), attribute
)) as f
:
250 return f
.readline().strip()
252 def read_ipv4_sysctl_attr(link
, attribute
):
253 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv4_path
, link
), attribute
)) as f
:
254 return f
.readline().strip()
256 def copy_unit_to_networkd_unit_path(*units
):
259 shutil
.copy(os
.path
.join(networkd_ci_path
, unit
), network_unit_file_path
)
260 if (os
.path
.exists(os
.path
.join(networkd_ci_path
, unit
+ '.d'))):
261 copytree(os
.path
.join(networkd_ci_path
, unit
+ '.d'), os
.path
.join(network_unit_file_path
, unit
+ '.d'))
263 def remove_unit_from_networkd_path(units
):
265 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
))):
266 os
.remove(os
.path
.join(network_unit_file_path
, unit
))
267 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
+ '.d'))):
268 shutil
.rmtree(os
.path
.join(network_unit_file_path
, unit
+ '.d'))
270 def start_dnsmasq(additional_options
='', ipv4_range
='192.168.5.10,192.168.5.200', ipv6_range
='2600::10,2600::20', lease_time
='1h'):
271 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
272 check_output(dnsmasq_command
)
274 def stop_dnsmasq(pid_file
):
275 if os
.path
.exists(pid_file
):
276 with
open(pid_file
, 'r') as f
:
277 pid
= f
.read().rstrip(' \t\r\n\0')
278 os
.kill(int(pid
), signal
.SIGTERM
)
282 def search_words_in_dnsmasq_log(words
, show_all
=False):
283 if os
.path
.exists(dnsmasq_log_file
):
284 with
open (dnsmasq_log_file
) as in_file
:
285 contents
= in_file
.read()
288 for line
in contents
.splitlines():
291 print("%s, %s" % (words
, line
))
295 def remove_lease_file():
296 if os
.path
.exists(os
.path
.join(networkd_ci_path
, 'lease')):
297 os
.remove(os
.path
.join(networkd_ci_path
, 'lease'))
299 def remove_log_file():
300 if os
.path
.exists(dnsmasq_log_file
):
301 os
.remove(dnsmasq_log_file
)
303 def remove_networkd_state_files():
304 if os
.path
.exists(os
.path
.join(networkd_runtime_directory
, 'state')):
305 os
.remove(os
.path
.join(networkd_runtime_directory
, 'state'))
307 def stop_networkd(show_logs
=True, remove_state_files
=True):
309 invocation_id
= check_output('systemctl show systemd-networkd -p InvocationID --value')
310 check_output('systemctl stop systemd-networkd')
312 print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
))
313 if remove_state_files
:
314 remove_networkd_state_files()
316 def start_networkd(sleep_sec
=0):
317 check_output('systemctl start systemd-networkd')
319 time
.sleep(sleep_sec
)
321 def restart_networkd(sleep_sec
=0, show_logs
=True, remove_state_files
=True):
322 stop_networkd(show_logs
, remove_state_files
)
323 start_networkd(sleep_sec
)
325 def get_operstate(link
, show_status
=True, setup_state
='configured'):
326 output
= check_output(*networkctl_cmd
, 'status', link
, env
=env
)
329 for line
in output
.splitlines():
330 if 'State:' in line
and (not setup_state
or setup_state
in line
):
331 return line
.split()[1]
335 def check_link_exists(self
, link
):
336 self
.assertTrue(link_exists(link
))
338 def check_operstate(self
, link
, expected
, show_status
=True, setup_state
='configured'):
339 self
.assertRegex(get_operstate(link
, show_status
, setup_state
), expected
)
341 def wait_online(self
, links_with_operstate
, timeout
='20s', bool_any
=False, setup_state
='configured'):
342 args
= wait_online_cmd
+ [f
'--timeout={timeout}'] + [f
'--interface={link}' for link
in links_with_operstate
]
346 check_output(*args
, env
=env
)
347 except subprocess
.CalledProcessError
:
348 for link
in links_with_operstate
:
349 output
= check_output(*networkctl_cmd
, 'status', link
.split(':')[0], env
=env
)
353 for link
in links_with_operstate
:
354 output
= check_output(*networkctl_cmd
, 'status', link
.split(':')[0])
356 for line
in output
.splitlines():
358 self
.assertRegex(line
, setup_state
)
360 def wait_address(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
361 for i
in range(timeout_sec
):
364 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
365 if re
.search(address_regex
, output
):
368 self
.assertRegex(output
, address_regex
)
370 class NetworkctlTests(unittest
.TestCase
, Utilities
):
379 '11-dummy-mtu.netdev',
382 'netdev-link-local-addressing-yes.network',
386 remove_links(self
.links
)
387 stop_networkd(show_logs
=False)
390 remove_links(self
.links
)
391 remove_unit_from_networkd_path(self
.units
)
392 stop_networkd(show_logs
=True)
395 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
398 self
.wait_online(['test1:degraded'])
400 output
= check_output(*networkctl_cmd
, 'list', env
=env
)
401 self
.assertRegex(output
, '1 lo ')
402 self
.assertRegex(output
, 'test1')
404 output
= check_output(*networkctl_cmd
, 'list', 'test1', env
=env
)
405 self
.assertNotRegex(output
, '1 lo ')
406 self
.assertRegex(output
, 'test1')
408 output
= check_output(*networkctl_cmd
, 'list', 'te*', env
=env
)
409 self
.assertNotRegex(output
, '1 lo ')
410 self
.assertRegex(output
, 'test1')
412 output
= check_output(*networkctl_cmd
, 'status', 'te*', env
=env
)
413 self
.assertNotRegex(output
, '1: lo ')
414 self
.assertRegex(output
, 'test1')
416 output
= check_output(*networkctl_cmd
, 'status', 'tes[a-z][0-9]', env
=env
)
417 self
.assertNotRegex(output
, '1: lo ')
418 self
.assertRegex(output
, 'test1')
421 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
424 self
.wait_online(['test1:degraded'])
426 output
= check_output(*networkctl_cmd
, 'status', 'test1', env
=env
)
427 self
.assertRegex(output
, 'MTU: 1600')
430 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
432 self
.wait_online(['test1:degraded'])
434 output
= check_output(*networkctl_cmd
, 'status', 'test1')
436 self
.assertRegex(output
, 'Type: ether')
438 output
= check_output(*networkctl_cmd
, 'status', 'lo')
440 self
.assertRegex(output
, 'Type: loopback')
442 @expectedFailureIfLinkFileFieldIsNotSet()
443 def test_udev_link_file(self
):
444 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
446 self
.wait_online(['test1:degraded'])
448 output
= check_output(*networkctl_cmd
, 'status', 'test1')
450 self
.assertRegex(output
, r
'Link File: (?:/usr)/lib/systemd/network/99-default.link')
451 self
.assertRegex(output
, r
'Network File: /run/systemd/network/11-dummy.network')
453 output
= check_output(*networkctl_cmd
, 'status', 'lo')
455 self
.assertRegex(output
, r
'Link File: (?:/usr)/lib/systemd/network/99-default.link')
456 self
.assertRegex(output
, r
'Network File: n/a')
458 def test_delete_links(self
):
459 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
460 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
463 self
.wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
465 check_output(*networkctl_cmd
, 'delete', 'test1', 'veth99')
466 self
.assertFalse(link_exists('test1'))
467 self
.assertFalse(link_exists('veth99'))
468 self
.assertFalse(link_exists('veth-peer'))
470 class NetworkdNetDevTests(unittest
.TestCase
, Utilities
):
472 links_remove_earlier
= [
536 '10-dropin-test.netdev',
540 '13-not-match-udev-property.network',
541 '14-match-udev-property.network',
542 '15-name-conflict-test.netdev',
545 '21-vlan-test1.network',
548 '25-6rd-tunnel.netdev',
550 '25-bond-balanced-tlb.netdev',
552 '25-bridge-configure-without-carrier.network',
554 '25-erspan-tunnel-local-any.netdev',
555 '25-erspan-tunnel.netdev',
556 '25-fou-gretap.netdev',
558 '25-fou-ipip.netdev',
559 '25-fou-ipproto-gre.netdev',
560 '25-fou-ipproto-ipip.netdev',
563 '25-gretap-tunnel-local-any.netdev',
564 '25-gretap-tunnel.netdev',
565 '25-gre-tunnel-any-any.netdev',
566 '25-gre-tunnel-local-any.netdev',
567 '25-gre-tunnel-remote-any.netdev',
568 '25-gre-tunnel.netdev',
569 '25-ip6gretap-tunnel-local-any.netdev',
570 '25-ip6gretap-tunnel.netdev',
571 '25-ip6gre-tunnel-any-any.netdev',
572 '25-ip6gre-tunnel-local-any.netdev',
573 '25-ip6gre-tunnel-remote-any.netdev',
574 '25-ip6gre-tunnel.netdev',
575 '25-ip6tnl-tunnel-any-any.netdev',
576 '25-ip6tnl-tunnel-local-any.netdev',
577 '25-ip6tnl-tunnel-remote-any.netdev',
578 '25-ip6tnl-tunnel.netdev',
579 '25-ipip-tunnel-any-any.netdev',
580 '25-ipip-tunnel-independent.netdev',
581 '25-ipip-tunnel-independent-loopback.netdev',
582 '25-ipip-tunnel-local-any.netdev',
583 '25-ipip-tunnel-remote-any.netdev',
584 '25-ipip-tunnel.netdev',
587 '25-isatap-tunnel.netdev',
592 '25-sit-tunnel-any-any.netdev',
593 '25-sit-tunnel-local-any.netdev',
594 '25-sit-tunnel-remote-any.netdev',
595 '25-sit-tunnel.netdev',
598 '25-tunnel-local-any.network',
599 '25-tunnel-remote-any.network',
604 '25-vti6-tunnel-any-any.netdev',
605 '25-vti6-tunnel-local-any.netdev',
606 '25-vti6-tunnel-remote-any.netdev',
607 '25-vti6-tunnel.netdev',
608 '25-vti-tunnel-any-any.netdev',
609 '25-vti-tunnel-local-any.netdev',
610 '25-vti-tunnel-remote-any.netdev',
611 '25-vti-tunnel.netdev',
614 '25-wireguard-23-peers.netdev',
615 '25-wireguard-23-peers.network',
616 '25-wireguard-preshared-key.txt',
617 '25-wireguard-private-key.txt',
618 '25-wireguard.netdev',
619 '25-wireguard.network',
621 '25-xfrm-independent.netdev',
637 'netdev-link-local-addressing-yes.network',
641 'vxlan-test1.network',
651 remove_fou_ports(self
.fou_ports
)
652 remove_links(self
.links_remove_earlier
)
653 remove_links(self
.links
)
654 stop_networkd(show_logs
=False)
657 remove_fou_ports(self
.fou_ports
)
658 remove_links(self
.links_remove_earlier
)
659 remove_links(self
.links
)
660 remove_unit_from_networkd_path(self
.units
)
661 stop_networkd(show_logs
=True)
663 def test_dropin_and_name_conflict(self
):
664 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
667 self
.wait_online(['dropin-test:off'], setup_state
='unmanaged')
669 output
= check_output('ip link show dropin-test')
671 self
.assertRegex(output
, '00:50:56:c0:00:28')
673 def test_match_udev_property(self
):
674 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
676 self
.wait_online(['dummy98:routable'])
678 output
= check_output('networkctl status dummy98')
680 self
.assertRegex(output
, 'Network File: /run/systemd/network/14-match-udev-property')
682 def test_wait_online_any(self
):
683 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
686 self
.wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
688 self
.check_operstate('bridge99', '(?:off|no-carrier)', setup_state
='configuring')
689 self
.check_operstate('test1', 'degraded')
691 def test_bridge(self
):
692 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
695 self
.wait_online(['bridge99:no-carrier'])
697 tick
= os
.sysconf('SC_CLK_TCK')
698 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
699 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
700 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge','forward_delay')) / tick
))
701 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge','ageing_time')) / tick
))
702 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge','priority')))
703 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','multicast_querier')))
704 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','multicast_snooping')))
705 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','stp_state')))
708 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
711 self
.wait_online(['bond99:off', 'bond98:off'], setup_state
='unmanaged')
713 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
714 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
715 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
716 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
717 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
718 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
719 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
720 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
721 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
722 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
723 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
725 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
726 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
729 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
730 '21-vlan.network', '21-vlan-test1.network')
733 self
.wait_online(['test1:degraded', 'vlan99:routable'])
735 output
= check_output('ip -d link show test1')
737 self
.assertRegex(output
, ' mtu 2000 ')
739 output
= check_output('ip -d link show vlan99')
741 self
.assertRegex(output
, ' mtu 2000 ')
742 self
.assertRegex(output
, 'REORDER_HDR')
743 self
.assertRegex(output
, 'LOOSE_BINDING')
744 self
.assertRegex(output
, 'GVRP')
745 self
.assertRegex(output
, 'MVRP')
746 self
.assertRegex(output
, ' id 99 ')
748 output
= check_output('ip -4 address show dev test1')
750 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
751 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
753 output
= check_output('ip -4 address show dev vlan99')
755 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
757 def test_macvtap(self
):
758 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
759 with self
.subTest(mode
=mode
):
760 if mode
!= 'private':
762 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
763 '11-dummy.netdev', 'macvtap.network')
764 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
765 f
.write('[MACVTAP]\nMode=' + mode
)
768 self
.wait_online(['macvtap99:degraded', 'test1:degraded'])
770 output
= check_output('ip -d link show macvtap99')
772 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
774 def test_macvlan(self
):
775 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
776 with self
.subTest(mode
=mode
):
777 if mode
!= 'private':
779 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
780 '11-dummy.netdev', 'macvlan.network')
781 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
782 f
.write('[MACVLAN]\nMode=' + mode
)
785 self
.wait_online(['macvlan99:degraded', 'test1:degraded'])
787 output
= check_output('ip -d link show test1')
789 self
.assertRegex(output
, ' mtu 2000 ')
791 output
= check_output('ip -d link show macvlan99')
793 self
.assertRegex(output
, ' mtu 2000 ')
794 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
796 @expectedFailureIfModuleIsNotAvailable('ipvlan')
797 def test_ipvlan(self
):
798 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
799 with self
.subTest(mode
=mode
, flag
=flag
):
802 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
803 '11-dummy.netdev', 'ipvlan.network')
804 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
805 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
808 self
.wait_online(['ipvlan99:degraded', 'test1:degraded'])
810 output
= check_output('ip -d link show ipvlan99')
812 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
814 @expectedFailureIfModuleIsNotAvailable('ipvtap')
815 def test_ipvtap(self
):
816 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
817 with self
.subTest(mode
=mode
, flag
=flag
):
820 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
821 '11-dummy.netdev', 'ipvtap.network')
822 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
823 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
826 self
.wait_online(['ipvtap99:degraded', 'test1:degraded'])
828 output
= check_output('ip -d link show ipvtap99')
830 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
833 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
836 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
838 output
= check_output('ip -d link show veth99')
840 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
841 output
= check_output('ip -d link show veth-peer')
843 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
846 copy_unit_to_networkd_unit_path('25-tun.netdev')
849 self
.wait_online(['tun99:off'], setup_state
='unmanaged')
851 output
= check_output('ip -d link show tun99')
853 # Old ip command does not support IFF_ flags
854 self
.assertRegex(output
, 'tun (?:type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
857 copy_unit_to_networkd_unit_path('25-tap.netdev')
860 self
.wait_online(['tap99:off'], setup_state
='unmanaged')
862 output
= check_output('ip -d link show tap99')
864 # Old ip command does not support IFF_ flags
865 self
.assertRegex(output
, 'tun (?:type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
867 @expectedFailureIfModuleIsNotAvailable('vrf')
869 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
872 self
.wait_online(['vrf99:carrier'])
874 @expectedFailureIfModuleIsNotAvailable('vcan')
876 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
879 self
.wait_online(['vcan99:carrier'])
881 @expectedFailureIfModuleIsNotAvailable('vxcan')
882 def test_vxcan(self
):
883 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
886 self
.wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
888 @expectedFailureIfModuleIsNotAvailable('wireguard')
889 def test_wireguard(self
):
890 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
891 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
892 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt')
894 self
.wait_online(['wg99:carrier', 'wg98:routable'])
896 if shutil
.which('wg'):
899 output
= check_output('wg show wg99 listen-port')
900 self
.assertRegex(output
, '51820')
901 output
= check_output('wg show wg99 fwmark')
902 self
.assertRegex(output
, '0x4d2')
903 output
= check_output('wg show wg99 allowed-ips')
904 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
905 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
906 output
= check_output('wg show wg99 persistent-keepalive')
907 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
908 output
= check_output('wg show wg99 endpoints')
909 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
910 output
= check_output('wg show wg99 private-key')
911 self
.assertRegex(output
, r
'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
912 output
= check_output('wg show wg99 preshared-keys')
913 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
914 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
916 output
= check_output('wg show wg98 private-key')
917 self
.assertRegex(output
, r
'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
919 def test_geneve(self
):
920 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
923 self
.wait_online(['geneve99:degraded'])
925 output
= check_output('ip -d link show geneve99')
927 self
.assertRegex(output
, '192.168.22.1')
928 self
.assertRegex(output
, '6082')
929 self
.assertRegex(output
, 'udpcsum')
930 self
.assertRegex(output
, 'udp6zerocsumrx')
932 def test_ipip_tunnel(self
):
933 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
934 '25-ipip-tunnel.netdev', '25-tunnel.network',
935 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
936 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
937 '25-ipip-tunnel-any-any.netdev', '25-tunnel-any-any.network')
939 self
.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'ipiptun96:routable', 'dummy98:degraded'])
941 output
= check_output('ip -d link show ipiptun99')
943 self
.assertRegex(output
, 'ipip (?:ipip |)remote 192.169.224.239 local 192.168.223.238 dev dummy98')
944 output
= check_output('ip -d link show ipiptun98')
946 self
.assertRegex(output
, 'ipip (?:ipip |)remote 192.169.224.239 local any dev dummy98')
947 output
= check_output('ip -d link show ipiptun97')
949 self
.assertRegex(output
, 'ipip (?:ipip |)remote any local 192.168.223.238 dev dummy98')
950 output
= check_output('ip -d link show ipiptun96')
952 self
.assertRegex(output
, 'ipip (?:ipip |)remote any local any dev dummy98')
954 def test_gre_tunnel(self
):
955 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
956 '25-gre-tunnel.netdev', '25-tunnel.network',
957 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
958 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
959 '25-gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
961 self
.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'gretun96:routable', 'dummy98:degraded'])
963 output
= check_output('ip -d link show gretun99')
965 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
966 self
.assertRegex(output
, 'ikey 1.2.3.103')
967 self
.assertRegex(output
, 'okey 1.2.4.103')
968 self
.assertRegex(output
, 'iseq')
969 self
.assertRegex(output
, 'oseq')
970 output
= check_output('ip -d link show gretun98')
972 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
973 self
.assertRegex(output
, 'ikey 0.0.0.104')
974 self
.assertRegex(output
, 'okey 0.0.0.104')
975 self
.assertNotRegex(output
, 'iseq')
976 self
.assertNotRegex(output
, 'oseq')
977 output
= check_output('ip -d link show gretun97')
979 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
980 self
.assertRegex(output
, 'ikey 0.0.0.105')
981 self
.assertRegex(output
, 'okey 0.0.0.105')
982 self
.assertNotRegex(output
, 'iseq')
983 self
.assertNotRegex(output
, 'oseq')
984 output
= check_output('ip -d link show gretun96')
986 self
.assertRegex(output
, 'gre remote any local any dev dummy98')
987 self
.assertRegex(output
, 'ikey 0.0.0.106')
988 self
.assertRegex(output
, 'okey 0.0.0.106')
989 self
.assertNotRegex(output
, 'iseq')
990 self
.assertNotRegex(output
, 'oseq')
992 def test_ip6gre_tunnel(self
):
993 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
994 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
995 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
996 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
997 '25-ip6gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1000 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1002 self
.check_link_exists('dummy98')
1003 self
.check_link_exists('ip6gretun99')
1004 self
.check_link_exists('ip6gretun98')
1005 self
.check_link_exists('ip6gretun97')
1006 self
.check_link_exists('ip6gretun96')
1008 output
= check_output('ip -d link show ip6gretun99')
1010 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1011 output
= check_output('ip -d link show ip6gretun98')
1013 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
1014 output
= check_output('ip -d link show ip6gretun97')
1016 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
1017 output
= check_output('ip -d link show ip6gretun96')
1019 self
.assertRegex(output
, 'ip6gre remote any local any dev dummy98')
1021 def test_gretap_tunnel(self
):
1022 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
1023 '25-gretap-tunnel.netdev', '25-tunnel.network',
1024 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1026 self
.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
1028 output
= check_output('ip -d link show gretap99')
1030 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1031 self
.assertRegex(output
, 'ikey 0.0.0.106')
1032 self
.assertRegex(output
, 'okey 0.0.0.106')
1033 self
.assertRegex(output
, 'iseq')
1034 self
.assertRegex(output
, 'oseq')
1035 output
= check_output('ip -d link show gretap98')
1037 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
1038 self
.assertRegex(output
, 'ikey 0.0.0.107')
1039 self
.assertRegex(output
, 'okey 0.0.0.107')
1040 self
.assertRegex(output
, 'iseq')
1041 self
.assertRegex(output
, 'oseq')
1043 def test_ip6gretap_tunnel(self
):
1044 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
1045 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1046 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1048 self
.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
1050 output
= check_output('ip -d link show ip6gretap99')
1052 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1053 output
= check_output('ip -d link show ip6gretap98')
1055 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1057 def test_vti_tunnel(self
):
1058 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
1059 '25-vti-tunnel.netdev', '25-tunnel.network',
1060 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1061 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1062 '25-vti-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1064 self
.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'vtitun96:routable', 'dummy98:degraded'])
1066 output
= check_output('ip -d link show vtitun99')
1068 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1069 output
= check_output('ip -d link show vtitun98')
1071 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
1072 output
= check_output('ip -d link show vtitun97')
1074 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
1075 output
= check_output('ip -d link show vtitun96')
1077 self
.assertRegex(output
, 'vti remote any local any dev dummy98')
1079 def test_vti6_tunnel(self
):
1080 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
1081 '25-vti6-tunnel.netdev', '25-tunnel.network',
1082 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1083 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1085 self
.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
1087 output
= check_output('ip -d link show vti6tun99')
1089 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1090 output
= check_output('ip -d link show vti6tun98')
1092 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
1093 output
= check_output('ip -d link show vti6tun97')
1095 self
.assertRegex(output
, 'vti6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1097 def test_ip6tnl_tunnel(self
):
1098 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
1099 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1100 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1101 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1103 self
.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
1105 output
= check_output('ip -d link show ip6tnl99')
1107 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1108 output
= check_output('ip -d link show ip6tnl98')
1110 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
1111 output
= check_output('ip -d link show ip6tnl97')
1113 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1115 def test_sit_tunnel(self
):
1116 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1117 '25-sit-tunnel.netdev', '25-tunnel.network',
1118 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1119 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1120 '25-sit-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1122 self
.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'sittun96:routable', 'dummy98:degraded'])
1124 output
= check_output('ip -d link show sittun99')
1126 self
.assertRegex(output
, "sit (?:ip6ip |)remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1127 output
= check_output('ip -d link show sittun98')
1129 self
.assertRegex(output
, "sit (?:ip6ip |)remote 10.65.223.239 local any dev dummy98")
1130 output
= check_output('ip -d link show sittun97')
1132 self
.assertRegex(output
, "sit (?:ip6ip |)remote any local 10.65.223.238 dev dummy98")
1133 output
= check_output('ip -d link show sittun96')
1135 self
.assertRegex(output
, "sit (?:ip6ip |)remote any local any dev dummy98")
1137 def test_isatap_tunnel(self
):
1138 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1139 '25-isatap-tunnel.netdev', '25-tunnel.network')
1141 self
.wait_online(['isataptun99:routable', 'dummy98:degraded'])
1143 output
= check_output('ip -d link show isataptun99')
1145 self
.assertRegex(output
, "isatap ")
1147 def test_6rd_tunnel(self
):
1148 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1149 '25-6rd-tunnel.netdev', '25-tunnel.network')
1151 self
.wait_online(['sittun99:routable', 'dummy98:degraded'])
1153 output
= check_output('ip -d link show sittun99')
1155 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1157 @expectedFailureIfERSPANModuleIsNotAvailable()
1158 def test_erspan_tunnel(self
):
1159 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1160 '25-erspan-tunnel.netdev', '25-tunnel.network',
1161 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1163 self
.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1165 output
= check_output('ip -d link show erspan99')
1167 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1168 self
.assertRegex(output
, 'ikey 0.0.0.101')
1169 self
.assertRegex(output
, 'okey 0.0.0.101')
1170 self
.assertRegex(output
, 'iseq')
1171 self
.assertRegex(output
, 'oseq')
1172 output
= check_output('ip -d link show erspan98')
1174 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1175 self
.assertRegex(output
, '102')
1176 self
.assertRegex(output
, 'ikey 0.0.0.102')
1177 self
.assertRegex(output
, 'okey 0.0.0.102')
1178 self
.assertRegex(output
, 'iseq')
1179 self
.assertRegex(output
, 'oseq')
1181 def test_tunnel_independent(self
):
1182 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1185 self
.wait_online(['ipiptun99:carrier'])
1187 def test_tunnel_independent_loopback(self
):
1188 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent-loopback.netdev', 'netdev-link-local-addressing-yes.network')
1191 self
.wait_online(['ipiptun99:carrier'])
1193 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1194 def test_xfrm(self
):
1195 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'xfrm.network',
1196 '25-xfrm.netdev', 'netdev-link-local-addressing-yes.network')
1199 self
.wait_online(['xfrm99:degraded', 'dummy98:degraded'])
1201 output
= check_output('ip link show dev xfrm99')
1204 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1205 def test_xfrm_independent(self
):
1206 copy_unit_to_networkd_unit_path('25-xfrm-independent.netdev', 'netdev-link-local-addressing-yes.network')
1209 self
.wait_online(['xfrm99:degraded'])
1211 @expectedFailureIfModuleIsNotAvailable('fou')
1213 # The following redundant check is necessary for CentOS CI.
1214 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1215 self
.assertTrue(is_module_available('fou'))
1217 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1218 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1219 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1222 self
.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'], setup_state
='unmanaged')
1224 output
= check_output('ip fou show')
1226 self
.assertRegex(output
, 'port 55555 ipproto 4')
1227 self
.assertRegex(output
, 'port 55556 ipproto 47')
1229 output
= check_output('ip -d link show ipiptun96')
1231 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1232 output
= check_output('ip -d link show sittun96')
1234 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1235 output
= check_output('ip -d link show gretun96')
1237 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1238 output
= check_output('ip -d link show gretap96')
1240 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1242 def test_vxlan(self
):
1243 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1244 '11-dummy.netdev', 'vxlan-test1.network')
1247 self
.wait_online(['test1:degraded', 'vxlan99:degraded'])
1249 output
= check_output('ip -d link show vxlan99')
1251 self
.assertRegex(output
, '999')
1252 self
.assertRegex(output
, '5555')
1253 self
.assertRegex(output
, 'l2miss')
1254 self
.assertRegex(output
, 'l3miss')
1255 self
.assertRegex(output
, 'udpcsum')
1256 self
.assertRegex(output
, 'udp6zerocsumtx')
1257 self
.assertRegex(output
, 'udp6zerocsumrx')
1258 self
.assertRegex(output
, 'remcsumtx')
1259 self
.assertRegex(output
, 'remcsumrx')
1260 self
.assertRegex(output
, 'gbp')
1262 output
= check_output('bridge fdb show dev vxlan99')
1264 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1265 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1266 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1268 def test_macsec(self
):
1269 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1270 'macsec.network', '12-dummy.netdev')
1273 self
.wait_online(['dummy98:degraded', 'macsec99:routable'])
1275 output
= check_output('ip -d link show macsec99')
1277 self
.assertRegex(output
, 'macsec99@dummy98')
1278 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1279 self
.assertRegex(output
, 'encrypt on')
1281 output
= check_output('ip macsec show macsec99')
1283 self
.assertRegex(output
, 'encrypt on')
1284 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1285 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1286 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1287 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1288 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1289 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1290 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1291 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1292 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1293 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1294 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1296 def test_nlmon(self
):
1297 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1300 self
.wait_online(['nlmon99:carrier'])
1302 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1313 '25-l2tp-dummy.network',
1315 '25-l2tp-ip.netdev',
1316 '25-l2tp-udp.netdev']
1318 l2tp_tunnel_ids
= [ '10' ]
1321 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1322 remove_links(self
.links
)
1323 stop_networkd(show_logs
=False)
1326 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1327 remove_links(self
.links
)
1328 remove_unit_from_networkd_path(self
.units
)
1329 stop_networkd(show_logs
=True)
1331 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1332 def test_l2tp_udp(self
):
1333 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1334 '25-l2tp-udp.netdev', '25-l2tp.network')
1337 self
.wait_online(['test1:routable', 'l2tp-ses1:degraded', 'l2tp-ses2:degraded'])
1339 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1341 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1342 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1343 self
.assertRegex(output
, "Peer tunnel 11")
1344 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1345 self
.assertRegex(output
, "UDP checksum: enabled")
1347 output
= check_output('ip l2tp show session tid 10 session_id 15')
1349 self
.assertRegex(output
, "Session 15 in tunnel 10")
1350 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1351 self
.assertRegex(output
, "interface name: l2tp-ses1")
1353 output
= check_output('ip l2tp show session tid 10 session_id 17')
1355 self
.assertRegex(output
, "Session 17 in tunnel 10")
1356 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1357 self
.assertRegex(output
, "interface name: l2tp-ses2")
1359 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1360 def test_l2tp_ip(self
):
1361 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1362 '25-l2tp-ip.netdev', '25-l2tp.network')
1365 self
.wait_online(['test1:routable', 'l2tp-ses3:degraded', 'l2tp-ses4:degraded'])
1367 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1369 self
.assertRegex(output
, "Tunnel 10, encap IP")
1370 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1371 self
.assertRegex(output
, "Peer tunnel 12")
1373 output
= check_output('ip l2tp show session tid 10 session_id 25')
1375 self
.assertRegex(output
, "Session 25 in tunnel 10")
1376 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1377 self
.assertRegex(output
, "interface name: l2tp-ses3")
1379 output
= check_output('ip l2tp show session tid 10 session_id 27')
1381 self
.assertRegex(output
, "Session 27 in tunnel 10")
1382 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1383 self
.assertRegex(output
, "interface name: l2tp-ses4")
1385 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1398 '23-active-slave.network',
1399 '24-keep-configuration-static.network',
1400 '24-search-domain.network',
1401 '25-address-link-section.network',
1402 '25-address-preferred-lifetime-zero-ipv6.network',
1403 '25-address-static.network',
1404 '25-bind-carrier.network',
1405 '25-bond-active-backup-slave.netdev',
1406 '25-fibrule-invert.network',
1407 '25-fibrule-port-range.network',
1408 '25-gre-tunnel-remote-any.netdev',
1409 '25-ip6gre-tunnel-remote-any.netdev',
1410 '25-ipv6-address-label-section.network',
1411 '25-neighbor-section.network',
1412 '25-neighbor-ipv6.network',
1413 '25-neighbor-ip-dummy.network',
1414 '25-neighbor-ip.network',
1415 '25-link-local-addressing-no.network',
1416 '25-link-local-addressing-yes.network',
1417 '25-link-section-unmanaged.network',
1418 '25-route-ipv6-src.network',
1419 '25-route-static.network',
1420 '25-sysctl-disable-ipv6.network',
1421 '25-sysctl.network',
1422 'configure-without-carrier.network',
1423 'routing-policy-rule-dummy98.network',
1424 'routing-policy-rule-test1.network']
1426 routing_policy_rule_tables
= ['7', '8']
1427 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1430 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1431 remove_routes(self
.routes
)
1432 remove_links(self
.links
)
1433 stop_networkd(show_logs
=False)
1436 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1437 remove_routes(self
.routes
)
1438 remove_links(self
.links
)
1439 remove_unit_from_networkd_path(self
.units
)
1440 stop_networkd(show_logs
=True)
1442 def test_address_static(self
):
1443 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1446 self
.wait_online(['dummy98:routable'])
1448 output
= check_output('ip -4 address show dev dummy98')
1450 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1451 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1452 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1455 self
.assertNotRegex(output
, '10.10.0.1/16')
1456 self
.assertNotRegex(output
, '10.10.0.2/16')
1458 output
= check_output('ip -4 address show dev dummy98 label 32')
1459 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1461 output
= check_output('ip -4 address show dev dummy98 label 33')
1462 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1464 output
= check_output('ip -4 address show dev dummy98 label 34')
1465 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1467 output
= check_output('ip -4 address show dev dummy98 label 35')
1468 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1470 output
= check_output('ip -6 address show dev dummy98')
1472 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1473 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1474 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1475 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1476 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1477 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1479 def test_address_preferred_lifetime_zero_ipv6(self
):
1480 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero-ipv6.network', '12-dummy.netdev')
1483 self
.check_link_exists('dummy98')
1484 self
.check_operstate('dummy98', 'routable', setup_state
='configuring')
1486 output
= check_output('ip address show dummy98')
1488 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1489 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1491 def test_configure_without_carrier(self
):
1492 copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
1494 self
.wait_online(['test1:routable'])
1496 output
= check_output(*networkctl_cmd
, 'status', 'test1')
1498 self
.assertRegex(output
, '192.168.0.15')
1499 self
.assertRegex(output
, '192.168.0.1')
1500 self
.assertRegex(output
, 'routable')
1502 def test_routing_policy_rule(self
):
1503 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1505 self
.wait_online(['test1:degraded'])
1507 output
= check_output('ip rule')
1509 self
.assertRegex(output
, '111')
1510 self
.assertRegex(output
, 'from 192.168.100.18')
1511 self
.assertRegex(output
, r
'tos (?:0x08|throughput)\s')
1512 self
.assertRegex(output
, 'iif test1')
1513 self
.assertRegex(output
, 'oif test1')
1514 self
.assertRegex(output
, 'lookup 7')
1516 def test_routing_policy_rule_issue_11280(self
):
1517 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1518 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1520 for trial
in range(3):
1521 # Remove state files only first time
1523 self
.wait_online(['test1:degraded', 'dummy98:degraded'])
1526 output
= check_output('ip rule list table 7')
1528 self
.assertRegex(output
, '111: from 192.168.100.18 tos (?:0x08|throughput) iif test1 oif test1 lookup 7')
1530 output
= check_output('ip rule list table 8')
1532 self
.assertRegex(output
, '112: from 192.168.101.18 tos (?:0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1534 stop_networkd(remove_state_files
=False)
1536 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1537 def test_routing_policy_rule_port_range(self
):
1538 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1540 self
.wait_online(['test1:degraded'])
1542 output
= check_output('ip rule')
1544 self
.assertRegex(output
, '111')
1545 self
.assertRegex(output
, 'from 192.168.100.18')
1546 self
.assertRegex(output
, '1123-1150')
1547 self
.assertRegex(output
, '3224-3290')
1548 self
.assertRegex(output
, 'tcp')
1549 self
.assertRegex(output
, 'lookup 7')
1551 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1552 def test_routing_policy_rule_invert(self
):
1553 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1555 self
.wait_online(['test1:degraded'])
1557 output
= check_output('ip rule')
1559 self
.assertRegex(output
, '111')
1560 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
1561 self
.assertRegex(output
, 'tcp')
1562 self
.assertRegex(output
, 'lookup 7')
1564 def test_route_static(self
):
1565 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1567 self
.wait_online(['dummy98:routable'])
1569 output
= check_output(*networkctl_cmd
, 'status', 'dummy98', env
=env
)
1572 print('### ip -6 route show dev dummy98')
1573 output
= check_output('ip -6 route show dev dummy98')
1575 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1576 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
1578 print('### ip -6 route show dev dummy98 default')
1579 output
= check_output('ip -6 route show dev dummy98 default')
1581 self
.assertRegex(output
, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1583 print('### ip -4 route show dev dummy98')
1584 output
= check_output('ip -4 route show dev dummy98')
1586 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1587 self
.assertRegex(output
, '149.10.124.64 proto static scope link')
1588 self
.assertRegex(output
, '169.254.0.0/16 proto static scope link metric 2048')
1589 self
.assertRegex(output
, '192.168.1.1 proto static initcwnd 20')
1590 self
.assertRegex(output
, '192.168.1.2 proto static initrwnd 30')
1591 self
.assertRegex(output
, 'multicast 149.10.123.4 proto static')
1593 print('### ip -4 route show dev dummy98 default')
1594 output
= check_output('ip -4 route show dev dummy98 default')
1596 self
.assertRegex(output
, 'default via 149.10.125.65 proto static onlink')
1597 self
.assertRegex(output
, 'default via 149.10.124.64 proto static')
1598 self
.assertRegex(output
, 'default proto static')
1600 print('### ip -4 route show table local dev dummy98')
1601 output
= check_output('ip -4 route show table local dev dummy98')
1603 self
.assertRegex(output
, 'local 149.10.123.1 proto static scope host')
1604 self
.assertRegex(output
, 'anycast 149.10.123.2 proto static scope link')
1605 self
.assertRegex(output
, 'broadcast 149.10.123.3 proto static scope link')
1607 print('### ip route show type blackhole')
1608 output
= check_output('ip route show type blackhole')
1610 self
.assertRegex(output
, 'blackhole 202.54.1.2 proto static')
1612 print('### ip route show type unreachable')
1613 output
= check_output('ip route show type unreachable')
1615 self
.assertRegex(output
, 'unreachable 202.54.1.3 proto static')
1617 print('### ip route show type prohibit')
1618 output
= check_output('ip route show type prohibit')
1620 self
.assertRegex(output
, 'prohibit 202.54.1.4 proto static')
1622 def test_ip_route_ipv6_src_route(self
):
1623 # a dummy device does not make the addresses go through tentative state, so we
1624 # reuse a bond from an earlier test, which does make the addresses go through
1625 # tentative state, and do our test on that
1626 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1628 self
.wait_online(['dummy98:enslaved', 'bond199:routable'])
1630 output
= check_output('ip -6 route list dev bond199')
1632 self
.assertRegex(output
, 'abcd::/16')
1633 self
.assertRegex(output
, 'src')
1634 self
.assertRegex(output
, '2001:1234:56:8f63::2')
1636 def test_ip_link_mac_address(self
):
1637 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
1639 self
.wait_online(['dummy98:degraded'])
1641 output
= check_output('ip link show dummy98')
1643 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
1645 def test_ip_link_unmanaged(self
):
1646 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
1649 self
.check_link_exists('dummy98')
1651 self
.check_operstate('dummy98', 'off', setup_state
='unmanaged')
1653 def test_ipv6_address_label(self
):
1654 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
1656 self
.wait_online(['dummy98:degraded'])
1658 output
= check_output('ip addrlabel list')
1660 self
.assertRegex(output
, '2004:da8:1::/64')
1662 def test_neighbor_section(self
):
1663 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
1665 self
.wait_online(['dummy98:degraded'], timeout
='40s')
1667 output
= check_output('ip neigh list dev dummy98')
1669 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
1670 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
1672 def test_neighbor_gre(self
):
1673 copy_unit_to_networkd_unit_path('25-neighbor-ip.network', '25-neighbor-ipv6.network', '25-neighbor-ip-dummy.network',
1674 '12-dummy.netdev', '25-gre-tunnel-remote-any.netdev', '25-ip6gre-tunnel-remote-any.netdev')
1676 self
.wait_online(['dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable'], timeout
='40s')
1678 output
= check_output('ip neigh list dev gretun97')
1680 self
.assertRegex(output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT')
1682 output
= check_output('ip neigh list dev ip6gretun97')
1684 self
.assertRegex(output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
1686 def test_link_local_addressing(self
):
1687 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
1688 '25-link-local-addressing-no.network', '12-dummy.netdev')
1690 self
.wait_online(['test1:degraded', 'dummy98:carrier'])
1692 output
= check_output('ip address show dev test1')
1694 self
.assertRegex(output
, 'inet .* scope link')
1695 self
.assertRegex(output
, 'inet6 .* scope link')
1697 output
= check_output('ip address show dev dummy98')
1699 self
.assertNotRegex(output
, 'inet6* .* scope link')
1702 Documentation/networking/ip-sysctl.txt
1704 addr_gen_mode - INTEGER
1705 Defines how link-local and autoconf addresses are generated.
1707 0: generate address based on EUI64 (default)
1708 1: do no generate a link-local address, use EUI64 for addresses generated
1710 2: generate stable privacy addresses, using the secret from
1711 stable_secret (RFC7217)
1712 3: generate stable privacy addresses, using a random secret if unset
1715 test1_addr_gen_mode
= ''
1716 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
1717 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
1721 # if stable_secret is unset, then EIO is returned
1722 test1_addr_gen_mode
= '0'
1724 test1_addr_gen_mode
= '2'
1726 test1_addr_gen_mode
= '0'
1728 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
1729 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
1731 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
1732 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
1734 def test_sysctl(self
):
1735 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
1737 self
.wait_online(['dummy98:degraded'])
1739 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
1740 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
1741 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
1742 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
1743 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
1744 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
1745 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
1747 def test_sysctl_disable_ipv6(self
):
1748 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
1750 print('## Disable ipv6')
1751 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
1752 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
1755 self
.wait_online(['dummy98:routable'])
1757 output
= check_output('ip -4 address show dummy98')
1759 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1760 output
= check_output('ip -6 address show dummy98')
1762 self
.assertEqual(output
, '')
1763 output
= check_output('ip -4 route show dev dummy98')
1765 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
1766 output
= check_output('ip -6 route show dev dummy98')
1768 self
.assertEqual(output
, '')
1770 check_output('ip link del dummy98')
1772 print('## Enable ipv6')
1773 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
1774 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
1777 self
.wait_online(['dummy98:routable'])
1779 output
= check_output('ip -4 address show dummy98')
1781 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1782 output
= check_output('ip -6 address show dummy98')
1784 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
1785 self
.assertRegex(output
, 'inet6 .* scope link')
1786 output
= check_output('ip -4 route show dev dummy98')
1788 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
1789 output
= check_output('ip -6 route show dev dummy98')
1791 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
1793 def test_bind_carrier(self
):
1794 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
1796 self
.wait_online(['test1:routable'])
1798 check_output('ip link add dummy98 type dummy')
1799 check_output('ip link set dummy98 up')
1801 output
= check_output('ip address show test1')
1803 self
.assertRegex(output
, 'UP,LOWER_UP')
1804 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1805 self
.check_operstate('test1', 'routable')
1807 check_output('ip link add dummy99 type dummy')
1808 check_output('ip link set dummy99 up')
1810 output
= check_output('ip address show test1')
1812 self
.assertRegex(output
, 'UP,LOWER_UP')
1813 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1814 self
.check_operstate('test1', 'routable')
1816 check_output('ip link del dummy98')
1818 output
= check_output('ip address show test1')
1820 self
.assertRegex(output
, 'UP,LOWER_UP')
1821 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1822 self
.check_operstate('test1', 'routable')
1824 check_output('ip link del dummy99')
1826 output
= check_output('ip address show test1')
1828 self
.assertNotRegex(output
, 'UP,LOWER_UP')
1829 self
.assertRegex(output
, 'DOWN')
1830 self
.assertNotRegex(output
, '192.168.10')
1831 self
.check_operstate('test1', 'off')
1833 check_output('ip link add dummy98 type dummy')
1834 check_output('ip link set dummy98 up')
1836 output
= check_output('ip address show test1')
1838 self
.assertRegex(output
, 'UP,LOWER_UP')
1839 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1840 self
.check_operstate('test1', 'routable')
1842 def test_domain(self
):
1843 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
1845 self
.wait_online(['dummy98:routable'])
1847 output
= check_output(*networkctl_cmd
, 'status', 'dummy98', env
=env
)
1849 self
.assertRegex(output
, 'Address: 192.168.42.100')
1850 self
.assertRegex(output
, 'DNS: 192.168.42.1')
1851 self
.assertRegex(output
, 'Search Domains: one')
1853 def test_keep_configuration_static(self
):
1854 check_output('systemctl stop systemd-networkd')
1856 check_output('ip link add name dummy98 type dummy')
1857 check_output('ip address add 10.1.2.3/16 dev dummy98')
1858 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
1859 output
= check_output('ip address show dummy98')
1861 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
1862 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
1863 output
= check_output('ip route show dev dummy98')
1866 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
1868 self
.wait_online(['dummy98:routable'])
1870 output
= check_output('ip address show dummy98')
1872 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
1873 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
1875 class NetworkdStateFileTests(unittest
.TestCase
, Utilities
):
1882 'state-file-tests.network',
1886 remove_links(self
.links
)
1887 stop_networkd(show_logs
=False)
1890 remove_links(self
.links
)
1891 remove_unit_from_networkd_path(self
.units
)
1892 stop_networkd(show_logs
=True)
1894 def test_state_file(self
):
1895 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'state-file-tests.network')
1897 self
.wait_online(['dummy98:routable'])
1899 output
= check_output(*networkctl_cmd
, '--no-legend', 'list', 'dummy98', env
=env
)
1901 ifindex
= output
.split()[0]
1903 path
= os
.path
.join('/run/systemd/netif/links/', ifindex
)
1904 self
.assertTrue(os
.path
.exists(path
))
1907 with
open(path
) as f
:
1909 self
.assertRegex(data
, r
'ADMIN_STATE=configured')
1910 self
.assertRegex(data
, r
'OPER_STATE=routable')
1911 self
.assertRegex(data
, r
'REQUIRED_FOR_ONLINE=yes')
1912 self
.assertRegex(data
, r
'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
1913 self
.assertRegex(data
, r
'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
1914 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
1915 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
1916 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
1917 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
1918 self
.assertRegex(data
, r
'LLMNR=no')
1919 self
.assertRegex(data
, r
'MDNS=yes')
1920 self
.assertRegex(data
, r
'DNSSEC=no')
1921 self
.assertRegex(data
, r
'ADDRESSES=192.168.(?:10.10|12.12)/24 192.168.(?:12.12|10.10)/24')
1923 check_output(*resolvectl_cmd
, 'dns', 'dummy98', '10.10.10.12', '10.10.10.13', env
=env
)
1924 check_output(*resolvectl_cmd
, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env
=env
)
1925 check_output(*resolvectl_cmd
, 'llmnr', 'dummy98', 'yes', env
=env
)
1926 check_output(*resolvectl_cmd
, 'mdns', 'dummy98', 'no', env
=env
)
1927 check_output(*resolvectl_cmd
, 'dnssec', 'dummy98', 'yes', env
=env
)
1928 check_output(*timedatectl_cmd
, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env
=env
)
1931 with
open(path
) as f
:
1933 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
1934 self
.assertRegex(data
, r
'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org')
1935 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
1936 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
1937 self
.assertRegex(data
, r
'LLMNR=yes')
1938 self
.assertRegex(data
, r
'MDNS=no')
1939 self
.assertRegex(data
, r
'DNSSEC=yes')
1941 check_output(*timedatectl_cmd
, 'revert', 'dummy98', env
=env
)
1944 with
open(path
) as f
:
1946 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
1947 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
1948 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
1949 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
1950 self
.assertRegex(data
, r
'LLMNR=yes')
1951 self
.assertRegex(data
, r
'MDNS=no')
1952 self
.assertRegex(data
, r
'DNSSEC=yes')
1954 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
1957 with
open(path
) as f
:
1959 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
1960 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
1961 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
1962 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
1963 self
.assertRegex(data
, r
'LLMNR=no')
1964 self
.assertRegex(data
, r
'MDNS=yes')
1965 self
.assertRegex(data
, r
'DNSSEC=no')
1967 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
1977 '23-active-slave.network',
1978 '23-bond199.network',
1979 '23-primary-slave.network',
1980 '25-bond-active-backup-slave.netdev',
1983 'bond-slave.network']
1986 remove_links(self
.links
)
1987 stop_networkd(show_logs
=False)
1990 remove_links(self
.links
)
1991 remove_unit_from_networkd_path(self
.units
)
1992 stop_networkd(show_logs
=True)
1994 def test_bond_active_slave(self
):
1995 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1997 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
1999 output
= check_output('ip -d link show bond199')
2001 self
.assertRegex(output
, 'active_slave dummy98')
2003 def test_bond_primary_slave(self
):
2004 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2006 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2008 output
= check_output('ip -d link show bond199')
2010 self
.assertRegex(output
, 'primary dummy98')
2012 def test_bond_operstate(self
):
2013 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
2014 'bond99.network','bond-slave.network')
2016 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
2018 output
= check_output('ip -d link show dummy98')
2020 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2022 output
= check_output('ip -d link show test1')
2024 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2026 output
= check_output('ip -d link show bond99')
2028 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
2030 self
.check_operstate('dummy98', 'enslaved')
2031 self
.check_operstate('test1', 'enslaved')
2032 self
.check_operstate('bond99', 'routable')
2034 check_output('ip link set dummy98 down')
2037 self
.check_operstate('dummy98', 'off')
2038 self
.check_operstate('test1', 'enslaved')
2039 self
.check_operstate('bond99', 'degraded-carrier')
2041 check_output('ip link set dummy98 up')
2044 self
.check_operstate('dummy98', 'enslaved')
2045 self
.check_operstate('test1', 'enslaved')
2046 self
.check_operstate('bond99', 'routable')
2048 check_output('ip link set dummy98 down')
2049 check_output('ip link set test1 down')
2052 self
.check_operstate('dummy98', 'off')
2053 self
.check_operstate('test1', 'off')
2055 for trial
in range(30):
2058 output
= check_output('ip address show bond99')
2060 if get_operstate('bond99') == 'no-carrier':
2063 # Huh? Kernel does not recognize that all slave interfaces are down?
2064 # Let's confirm that networkd's operstate is consistent with ip's result.
2065 self
.assertNotRegex(output
, 'NO-CARRIER')
2067 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
2077 '26-bridge-slave-interface-1.network',
2078 '26-bridge-slave-interface-2.network',
2079 '26-bridge-vlan-master.network',
2080 '26-bridge-vlan-slave.network',
2081 'bridge99-ignore-carrier-loss.network',
2084 routing_policy_rule_tables
= ['100']
2087 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2088 remove_links(self
.links
)
2089 stop_networkd(show_logs
=False)
2092 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2093 remove_links(self
.links
)
2094 remove_unit_from_networkd_path(self
.units
)
2095 stop_networkd(show_logs
=True)
2097 def test_bridge_vlan(self
):
2098 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
2099 '26-bridge.netdev', '26-bridge-vlan-master.network')
2101 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
2103 output
= check_output('bridge vlan show dev test1')
2105 self
.assertNotRegex(output
, '4063')
2106 for i
in range(4064, 4095):
2107 self
.assertRegex(output
, f
'{i}')
2108 self
.assertNotRegex(output
, '4095')
2110 output
= check_output('bridge vlan show dev bridge99')
2112 self
.assertNotRegex(output
, '4059')
2113 for i
in range(4060, 4095):
2114 self
.assertRegex(output
, f
'{i}')
2115 self
.assertNotRegex(output
, '4095')
2117 def test_bridge_property(self
):
2118 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2119 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2122 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2124 output
= check_output('ip -d link show test1')
2126 self
.assertRegex(output
, 'master')
2127 self
.assertRegex(output
, 'bridge')
2129 output
= check_output('ip -d link show dummy98')
2131 self
.assertRegex(output
, 'master')
2132 self
.assertRegex(output
, 'bridge')
2134 output
= check_output('ip addr show bridge99')
2136 self
.assertRegex(output
, '192.168.0.15/24')
2138 output
= check_output('bridge -d link show dummy98')
2140 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
2141 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
2142 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
2143 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
2144 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
2145 # CONFIG_BRIDGE_IGMP_SNOOPING=y
2146 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
2147 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
2148 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
2149 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
2150 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
2151 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'priority'), '23')
2152 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard'), '1')
2153 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'root_block'), '1')
2155 output
= check_output('bridge -d link show test1')
2157 self
.assertEqual(read_bridge_port_attr('bridge99', 'test1', 'priority'), '0')
2159 check_output('ip address add 192.168.0.16/24 dev bridge99')
2162 output
= check_output('ip addr show bridge99')
2164 self
.assertRegex(output
, '192.168.0.16/24')
2166 self
.assertEqual(call('ip link del test1'), 0)
2169 self
.check_operstate('bridge99', 'degraded-carrier')
2171 check_output('ip link del dummy98')
2174 self
.check_operstate('bridge99', 'no-carrier')
2176 output
= check_output('ip address show bridge99')
2178 self
.assertRegex(output
, 'NO-CARRIER')
2179 self
.assertNotRegex(output
, '192.168.0.15/24')
2180 self
.assertNotRegex(output
, '192.168.0.16/24')
2182 def test_bridge_ignore_carrier_loss(self
):
2183 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2184 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2185 'bridge99-ignore-carrier-loss.network')
2187 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2189 check_output('ip address add 192.168.0.16/24 dev bridge99')
2192 check_output('ip link del test1')
2193 check_output('ip link del dummy98')
2196 output
= check_output('ip address show bridge99')
2198 self
.assertRegex(output
, 'NO-CARRIER')
2199 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2200 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
2202 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
2203 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
2204 'bridge99-ignore-carrier-loss.network')
2206 self
.wait_online(['bridge99:no-carrier'])
2208 for trial
in range(4):
2209 check_output('ip link add dummy98 type dummy')
2210 check_output('ip link set dummy98 up')
2212 check_output('ip link del dummy98')
2214 self
.wait_online(['bridge99:routable', 'dummy98:enslaved'])
2216 output
= check_output('ip address show bridge99')
2218 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2220 output
= check_output('ip rule list table 100')
2222 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
2224 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
2228 '23-emit-lldp.network',
2233 remove_links(self
.links
)
2234 stop_networkd(show_logs
=False)
2237 remove_links(self
.links
)
2238 remove_unit_from_networkd_path(self
.units
)
2239 stop_networkd(show_logs
=True)
2241 def test_lldp(self
):
2242 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
2244 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
2246 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
2248 self
.assertRegex(output
, 'veth-peer')
2249 self
.assertRegex(output
, 'veth99')
2251 class NetworkdRATests(unittest
.TestCase
, Utilities
):
2256 'ipv6-prefix.network',
2257 'ipv6-prefix-veth.network']
2260 remove_links(self
.links
)
2261 stop_networkd(show_logs
=False)
2264 remove_links(self
.links
)
2265 remove_unit_from_networkd_path(self
.units
)
2266 stop_networkd(show_logs
=True)
2268 def test_ipv6_prefix_delegation(self
):
2269 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
2271 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2273 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2275 self
.assertRegex(output
, '2002:da8:1:0')
2277 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
2282 'dhcp-client.network',
2283 'dhcp-client-timezone-router.network',
2284 'dhcp-server.network',
2285 'dhcp-server-timezone-router.network']
2288 remove_links(self
.links
)
2289 stop_networkd(show_logs
=False)
2292 remove_links(self
.links
)
2293 remove_unit_from_networkd_path(self
.units
)
2294 stop_networkd(show_logs
=True)
2296 def test_dhcp_server(self
):
2297 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
2299 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2301 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2303 self
.assertRegex(output
, '192.168.5.*')
2304 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
2305 self
.assertRegex(output
, 'DNS: 192.168.5.1')
2306 self
.assertRegex(output
, 'NTP: 192.168.5.1')
2308 def test_emit_router_timezone(self
):
2309 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
2311 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2313 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2315 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
2316 self
.assertRegex(output
, '192.168.5.*')
2317 self
.assertRegex(output
, 'Europe/Berlin')
2319 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
2328 'dhcp-client-anonymize.network',
2329 'dhcp-client-gateway-onlink-implicit.network',
2330 'dhcp-client-ipv4-dhcp-settings.network',
2331 'dhcp-client-ipv4-only-ipv6-disabled.network',
2332 'dhcp-client-ipv4-only.network',
2333 'dhcp-client-ipv6-only.network',
2334 'dhcp-client-ipv6-rapid-commit.network',
2335 'dhcp-client-keep-configuration-dhcp-on-stop.network',
2336 'dhcp-client-keep-configuration-dhcp.network',
2337 'dhcp-client-listen-port.network',
2338 'dhcp-client-reassign-static-routes-ipv4.network',
2339 'dhcp-client-reassign-static-routes-ipv6.network',
2340 'dhcp-client-route-metric.network',
2341 'dhcp-client-route-table.network',
2342 'dhcp-client-use-dns-ipv4-and-ra.network',
2343 'dhcp-client-use-dns-ipv4.network',
2344 'dhcp-client-use-dns-no.network',
2345 'dhcp-client-use-dns-yes.network',
2346 'dhcp-client-use-domains.network',
2347 'dhcp-client-use-routes-no.network',
2348 'dhcp-client-vrf.network',
2349 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
2350 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
2351 'dhcp-client-with-static-address.network',
2352 'dhcp-client.network',
2353 'dhcp-server-veth-peer.network',
2354 'dhcp-v4-server-veth-peer.network',
2355 'dhcp-client-use-domains.network',
2359 stop_dnsmasq(dnsmasq_pid_file
)
2360 remove_links(self
.links
)
2361 stop_networkd(show_logs
=False)
2364 stop_dnsmasq(dnsmasq_pid_file
)
2367 remove_links(self
.links
)
2368 remove_unit_from_networkd_path(self
.units
)
2369 stop_networkd(show_logs
=True)
2371 def test_dhcp_client_ipv6_only(self
):
2372 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2375 self
.wait_online(['veth-peer:carrier'])
2377 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2379 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2381 self
.assertRegex(output
, '2600::')
2382 self
.assertNotRegex(output
, '192.168.5')
2384 # Confirm that ipv6 token is not set in the kernel
2385 output
= check_output('ip token show dev veth99')
2387 self
.assertRegex(output
, 'token :: dev veth99')
2389 def test_dhcp_client_ipv4_only(self
):
2390 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
2393 self
.wait_online(['veth-peer:carrier'])
2394 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
2395 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2397 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2399 self
.assertNotRegex(output
, '2600::')
2400 self
.assertRegex(output
, '192.168.5')
2401 self
.assertRegex(output
, '192.168.5.6')
2402 self
.assertRegex(output
, '192.168.5.7')
2404 # checking routes to DNS servers
2405 output
= check_output('ip route show dev veth99')
2407 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
2408 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
2409 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
2411 stop_dnsmasq(dnsmasq_pid_file
)
2412 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8', lease_time
='2m')
2414 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2415 print('Wait for the dynamic address to be renewed')
2418 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2420 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2422 self
.assertNotRegex(output
, '2600::')
2423 self
.assertRegex(output
, '192.168.5')
2424 self
.assertNotRegex(output
, '192.168.5.6')
2425 self
.assertRegex(output
, '192.168.5.7')
2426 self
.assertRegex(output
, '192.168.5.8')
2428 # checking routes to DNS servers
2429 output
= check_output('ip route show dev veth99')
2431 self
.assertNotRegex(output
, r
'192.168.5.6')
2432 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
2433 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
2434 self
.assertRegex(output
, r
'192.168.5.8 proto dhcp scope link src 192.168.5.181 metric 1024')
2436 def test_dhcp_client_ipv4_ipv6(self
):
2437 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
2438 'dhcp-client-ipv4-only.network')
2440 self
.wait_online(['veth-peer:carrier'])
2442 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2444 # link become 'routable' when at least one protocol provide an valid address.
2445 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2446 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2448 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2450 self
.assertRegex(output
, '2600::')
2451 self
.assertRegex(output
, '192.168.5')
2453 def test_dhcp_client_settings(self
):
2454 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
2457 self
.wait_online(['veth-peer:carrier'])
2459 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2461 print('## ip address show dev veth99')
2462 output
= check_output('ip address show dev veth99')
2464 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2465 self
.assertRegex(output
, '192.168.5')
2466 self
.assertRegex(output
, '1492')
2468 print('## ip route show table main dev veth99')
2469 output
= check_output('ip route show table main dev veth99')
2472 main_table_is_empty
= output
== ''
2473 if not main_table_is_empty
:
2474 self
.assertNotRegex(output
, 'proto dhcp')
2476 print('## ip route show table 211 dev veth99')
2477 output
= check_output('ip route show table 211 dev veth99')
2479 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
2480 if main_table_is_empty
:
2481 self
.assertRegex(output
, '192.168.5.0/24 proto dhcp')
2482 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
2483 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
2485 print('## dnsmasq log')
2486 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
2487 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
2488 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
2489 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
2491 def test_dhcp6_client_settings_rapidcommit_true(self
):
2492 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2494 self
.wait_online(['veth-peer:carrier'])
2496 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2498 output
= check_output('ip address show dev veth99')
2500 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2501 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
2503 def test_dhcp6_client_settings_rapidcommit_false(self
):
2504 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
2506 self
.wait_online(['veth-peer:carrier'])
2508 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2510 output
= check_output('ip address show dev veth99')
2512 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2513 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
2515 def test_dhcp_client_settings_anonymize(self
):
2516 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
2518 self
.wait_online(['veth-peer:carrier'])
2520 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2522 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
2523 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
2524 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
2526 def test_dhcp_client_listen_port(self
):
2527 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
2529 self
.wait_online(['veth-peer:carrier'])
2530 start_dnsmasq('--dhcp-alternate-port=67,5555')
2531 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2533 # link become 'routable' when at least one protocol provide an valid address.
2534 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2535 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2537 output
= check_output('ip -4 address show dev veth99')
2539 self
.assertRegex(output
, '192.168.5.* dynamic')
2541 def test_dhcp_client_with_static_address(self
):
2542 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
2543 'dhcp-client-with-static-address.network')
2545 self
.wait_online(['veth-peer:carrier'])
2547 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2549 output
= check_output('ip address show dev veth99 scope global')
2551 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
2552 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
2554 output
= check_output('ip route show dev veth99')
2556 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
2557 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
2558 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
2559 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
2561 def test_dhcp_route_table_id(self
):
2562 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
2564 self
.wait_online(['veth-peer:carrier'])
2566 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2568 output
= check_output('ip route show table 12')
2570 self
.assertRegex(output
, 'veth99 proto dhcp')
2571 self
.assertRegex(output
, '192.168.5.1')
2573 def test_dhcp_route_metric(self
):
2574 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
2576 self
.wait_online(['veth-peer:carrier'])
2578 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2580 output
= check_output('ip route show dev veth99')
2582 self
.assertRegex(output
, 'metric 24')
2584 def test_dhcp_client_reassign_static_routes_ipv4(self
):
2585 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2586 'dhcp-client-reassign-static-routes-ipv4.network')
2588 self
.wait_online(['veth-peer:carrier'])
2589 start_dnsmasq(lease_time
='2m')
2590 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2592 output
= check_output('ip address show dev veth99 scope global')
2594 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2596 output
= check_output('ip route show dev veth99')
2598 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
2599 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
2600 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
2601 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
2603 stop_dnsmasq(dnsmasq_pid_file
)
2604 start_dnsmasq(ipv4_range
='192.168.5.210,192.168.5.220', lease_time
='2m')
2606 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2607 print('Wait for the dynamic address to be renewed')
2610 self
.wait_online(['veth99:routable'])
2612 output
= check_output('ip route show dev veth99')
2614 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
2615 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
2616 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
2617 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
2619 def test_dhcp_client_reassign_static_routes_ipv6(self
):
2620 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2621 'dhcp-client-reassign-static-routes-ipv6.network')
2623 self
.wait_online(['veth-peer:carrier'])
2624 start_dnsmasq(lease_time
='2m')
2625 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2627 output
= check_output('ip address show dev veth99 scope global')
2629 self
.assertRegex(output
, r
'inet6 2600::[0-9a-f]*/128 scope global (?:noprefixroute dynamic|dynamic noprefixroute)')
2631 output
= check_output('ip -6 route show dev veth99')
2633 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
2634 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
2636 stop_dnsmasq(dnsmasq_pid_file
)
2637 start_dnsmasq(ipv6_range
='2600::30,2600::40', lease_time
='2m')
2639 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2640 print('Wait for the dynamic address to be renewed')
2643 self
.wait_online(['veth99:routable'])
2645 output
= check_output('ip -6 route show dev veth99')
2647 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
2648 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
2650 def test_dhcp_keep_configuration_dhcp(self
):
2651 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
2653 self
.wait_online(['veth-peer:carrier'])
2654 start_dnsmasq(lease_time
='2m')
2655 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2657 output
= check_output('ip address show dev veth99 scope global')
2659 self
.assertRegex(output
, r
'192.168.5.*')
2661 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2663 self
.assertRegex(output
, r
'192.168.5.*')
2665 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
2666 stop_dnsmasq(dnsmasq_pid_file
)
2668 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2669 print('Wait for the dynamic address to be expired')
2672 print('The lease address should be kept after lease expired')
2673 output
= check_output('ip address show dev veth99 scope global')
2675 self
.assertRegex(output
, r
'192.168.5.*')
2677 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2679 self
.assertRegex(output
, r
'192.168.5.*')
2681 check_output('systemctl stop systemd-networkd')
2683 print('The lease address should be kept after networkd stopped')
2684 output
= check_output('ip address show dev veth99 scope global')
2686 self
.assertRegex(output
, r
'192.168.5.*')
2688 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2690 self
.assertRegex(output
, r
'192.168.5.*')
2693 self
.wait_online(['veth-peer:routable'])
2695 print('Still the lease address should be kept after networkd restarted')
2696 output
= check_output('ip address show dev veth99 scope global')
2698 self
.assertRegex(output
, r
'192.168.5.*')
2700 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2702 self
.assertRegex(output
, r
'192.168.5.*')
2704 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
2705 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
2707 self
.wait_online(['veth-peer:carrier'])
2708 start_dnsmasq(lease_time
='2m')
2709 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2711 output
= check_output('ip address show dev veth99 scope global')
2713 self
.assertRegex(output
, r
'192.168.5.*')
2715 stop_dnsmasq(dnsmasq_pid_file
)
2716 check_output('systemctl stop systemd-networkd')
2718 output
= check_output('ip address show dev veth99 scope global')
2720 self
.assertRegex(output
, r
'192.168.5.*')
2723 self
.wait_online(['veth-peer:routable'])
2725 output
= check_output('ip address show dev veth99 scope global')
2727 self
.assertNotRegex(output
, r
'192.168.5.*')
2729 def test_dhcp_client_reuse_address_as_static(self
):
2730 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
2732 self
.wait_online(['veth-peer:carrier'])
2734 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2736 # link become 'routable' when at least one protocol provide an valid address.
2737 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2738 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2740 output
= check_output('ip address show dev veth99 scope global')
2742 self
.assertRegex(output
, '192.168.5')
2743 self
.assertRegex(output
, '2600::')
2745 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
2746 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
2747 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
2748 print(static_network
)
2750 remove_unit_from_networkd_path(['dhcp-client.network'])
2752 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
2753 f
.write(static_network
)
2755 # When networkd started, the links are already configured, so let's wait for 5 seconds
2756 # the links to be re-configured.
2758 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2760 output
= check_output('ip -4 address show dev veth99 scope global')
2762 self
.assertRegex(output
, '192.168.5')
2763 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
2765 output
= check_output('ip -6 address show dev veth99 scope global')
2767 self
.assertRegex(output
, '2600::')
2768 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
2770 @expectedFailureIfModuleIsNotAvailable('vrf')
2771 def test_dhcp_client_vrf(self
):
2772 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
2773 '25-vrf.netdev', '25-vrf.network')
2775 self
.wait_online(['veth-peer:carrier'])
2777 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
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')
2783 print('## ip -d link show dev vrf99')
2784 output
= check_output('ip -d link show dev vrf99')
2786 self
.assertRegex(output
, 'vrf table 42')
2788 print('## ip address show vrf vrf99')
2789 output
= check_output('ip address show vrf vrf99')
2791 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2792 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2793 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)')
2794 self
.assertRegex(output
, 'inet6 .* scope link')
2796 print('## ip address show dev veth99')
2797 output
= check_output('ip address show dev veth99')
2799 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2800 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2801 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)')
2802 self
.assertRegex(output
, 'inet6 .* scope link')
2804 print('## ip route show vrf vrf99')
2805 output
= check_output('ip route show vrf vrf99')
2807 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
2808 self
.assertRegex(output
, 'default dev veth99 proto static scope link')
2809 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
2810 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
2811 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
2812 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
2814 print('## ip route show table main dev veth99')
2815 output
= check_output('ip route show table main dev veth99')
2817 self
.assertEqual(output
, '')
2819 def test_dhcp_client_gateway_onlink_implicit(self
):
2820 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2821 'dhcp-client-gateway-onlink-implicit.network')
2823 self
.wait_online(['veth-peer:carrier'])
2825 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2827 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2829 self
.assertRegex(output
, '192.168.5')
2831 output
= check_output('ip route list dev veth99 10.0.0.0/8')
2833 self
.assertRegex(output
, 'onlink')
2834 output
= check_output('ip route list dev veth99 192.168.100.0/24')
2836 self
.assertRegex(output
, 'onlink')
2838 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
2839 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2840 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
2842 self
.wait_online(['veth-peer:carrier'])
2843 start_dnsmasq(lease_time
='2m')
2844 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2846 output
= check_output('ip address show dev veth99')
2849 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2850 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2851 output
= check_output('ip -6 address show dev veth99 scope link')
2852 self
.assertRegex(output
, 'inet6 .* scope link')
2853 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2854 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2855 output
= check_output('ip -4 address show dev veth99 scope link')
2856 self
.assertNotRegex(output
, 'inet .* scope link')
2858 print('Wait for the dynamic address to be expired')
2861 output
= check_output('ip address show dev veth99')
2864 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2865 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2866 output
= check_output('ip -6 address show dev veth99 scope link')
2867 self
.assertRegex(output
, 'inet6 .* scope link')
2868 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2869 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2870 output
= check_output('ip -4 address show dev veth99 scope link')
2871 self
.assertNotRegex(output
, 'inet .* scope link')
2873 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
2875 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
2876 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2877 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
2879 self
.wait_online(['veth99:degraded', 'veth-peer:routable'])
2881 output
= check_output('ip address show dev veth99')
2884 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2885 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2886 output
= check_output('ip -6 address show dev veth99 scope link')
2887 self
.assertRegex(output
, 'inet6 .* scope link')
2888 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2889 self
.assertNotRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2890 output
= check_output('ip -4 address show dev veth99 scope link')
2891 self
.assertRegex(output
, 'inet .* scope link')
2893 def test_dhcp_client_route_remove_on_renew(self
):
2894 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2895 'dhcp-client-ipv4-only-ipv6-disabled.network')
2897 self
.wait_online(['veth-peer:carrier'])
2898 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
2899 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2901 # test for issue #12490
2903 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2905 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2907 for line
in output
.splitlines():
2908 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
2909 address1
= line
.split()[1].split('/')[0]
2912 output
= check_output('ip -4 route show dev veth99')
2914 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2915 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2917 stop_dnsmasq(dnsmasq_pid_file
)
2918 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
2920 print('Wait for the dynamic address to be expired')
2923 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2925 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2927 for line
in output
.splitlines():
2928 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
2929 address2
= line
.split()[1].split('/')[0]
2932 self
.assertNotEqual(address1
, address2
)
2934 output
= check_output('ip -4 route show dev veth99')
2936 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2937 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2938 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
2939 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
2941 def test_dhcp_client_use_dns_yes(self
):
2942 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-yes.network')
2945 self
.wait_online(['veth-peer:carrier'])
2946 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
2947 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2949 # link become 'routable' when at least one protocol provide an valid address.
2950 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2951 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2954 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
2956 self
.assertRegex(output
, '192.168.5.1')
2957 self
.assertRegex(output
, '2600::1')
2959 def test_dhcp_client_use_dns_no(self
):
2960 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-no.network')
2963 self
.wait_online(['veth-peer:carrier'])
2964 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
2965 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2967 # link become 'routable' when at least one protocol provide an valid address.
2968 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2969 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2972 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
2974 self
.assertNotRegex(output
, '192.168.5.1')
2975 self
.assertNotRegex(output
, '2600::1')
2977 def test_dhcp_client_use_dns_ipv4(self
):
2978 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4.network')
2981 self
.wait_online(['veth-peer:carrier'])
2982 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
2983 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2985 # link become 'routable' when at least one protocol provide an valid address.
2986 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2987 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2990 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
2992 self
.assertRegex(output
, '192.168.5.1')
2993 self
.assertNotRegex(output
, '2600::1')
2995 def test_dhcp_client_use_dns_ipv4_and_ra(self
):
2996 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4-and-ra.network')
2999 self
.wait_online(['veth-peer:carrier'])
3000 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3001 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3003 # link become 'routable' when at least one protocol provide an valid address.
3004 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3005 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3008 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3010 self
.assertRegex(output
, '192.168.5.1')
3011 self
.assertRegex(output
, '2600::1')
3013 def test_dhcp_client_use_domains(self
):
3014 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-domains.network')
3017 self
.wait_online(['veth-peer:carrier'])
3018 start_dnsmasq('--dhcp-option=option:domain-search,example.com')
3019 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3021 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
3023 self
.assertRegex(output
, 'Search Domains: example.com')
3026 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
3028 self
.assertRegex(output
, 'example.com')
3030 if __name__
== '__main__':
3031 parser
= argparse
.ArgumentParser()
3032 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
3033 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
3034 parser
.add_argument('--resolved', help='Path to systemd-resolved', dest
='resolved_bin')
3035 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
3036 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
3037 parser
.add_argument('--resolvectl', help='Path to resolvectl', dest
='resolvectl_bin')
3038 parser
.add_argument('--timedatectl', help='Path to timedatectl', dest
='timedatectl_bin')
3039 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
3040 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
3041 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
3042 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
3043 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
3044 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
3047 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
:
3048 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
3049 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
3050 resolved_bin
= os
.path
.join(ns
.build_dir
, 'systemd-resolved')
3051 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
3052 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
3053 resolvectl_bin
= os
.path
.join(ns
.build_dir
, 'resolvectl')
3054 timedatectl_bin
= os
.path
.join(ns
.build_dir
, 'timedatectl')
3057 networkd_bin
= ns
.networkd_bin
3059 resolved_bin
= ns
.resolved_bin
3060 if ns
.wait_online_bin
:
3061 wait_online_bin
= ns
.wait_online_bin
3062 if ns
.networkctl_bin
:
3063 networkctl_bin
= ns
.networkctl_bin
3064 if ns
.resolvectl_bin
:
3065 resolvectl_bin
= ns
.resolvectl_bin
3066 if ns
.timedatectl_bin
:
3067 timedatectl_bin
= ns
.timedatectl_bin
3069 use_valgrind
= ns
.use_valgrind
3070 enable_debug
= ns
.enable_debug
3071 asan_options
= ns
.asan_options
3072 lsan_options
= ns
.lsan_options
3073 ubsan_options
= ns
.ubsan_options
3076 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
3077 resolvectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin
]
3078 timedatectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin
]
3079 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
3081 networkctl_cmd
= [networkctl_bin
]
3082 resolvectl_cmd
= [resolvectl_bin
]
3083 timedatectl_cmd
= [timedatectl_bin
]
3084 wait_online_cmd
= [wait_online_bin
]
3087 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
3089 env
.update({ 'ASAN_OPTIONS' : asan_options
})
3091 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
3093 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
3096 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,