2 # SPDX-License-Identifier: LGPL-2.1-or-later
3 # systemd-networkd tests
16 from shutil
import copytree
17 from pathlib
import Path
19 network_unit_file_path
='/run/systemd/network'
20 networkd_runtime_directory
='/run/systemd/netif'
21 networkd_conf_dropin_path
='/run/systemd/networkd.conf.d'
22 networkd_ci_path
='/run/networkd-ci'
23 network_sysctl_ipv6_path
='/proc/sys/net/ipv6/conf'
24 network_sysctl_ipv4_path
='/proc/sys/net/ipv4/conf'
26 udev_rules_dir
='/run/udev/rules.d'
28 dnsmasq_pid_file
='/run/networkd-ci/test-dnsmasq.pid'
29 dnsmasq_log_file
='/run/networkd-ci/test-dnsmasq.log'
30 dnsmasq_lease_file
='/run/networkd-ci/test-dnsmasq.lease'
32 isc_dhcpd_pid_file
='/run/networkd-ci/test-isc-dhcpd.pid'
33 isc_dhcpd_lease_file
='/run/networkd-ci/test-isc-dhcpd.lease'
35 systemd_lib_paths
=['/usr/lib/systemd', '/lib/systemd']
36 which_paths
=':'.join(systemd_lib_paths
+ os
.getenv('PATH', os
.defpath
).lstrip(':').split(':'))
38 networkd_bin
=shutil
.which('systemd-networkd', path
=which_paths
)
39 resolved_bin
=shutil
.which('systemd-resolved', path
=which_paths
)
40 udevd_bin
=shutil
.which('systemd-udevd', path
=which_paths
)
41 wait_online_bin
=shutil
.which('systemd-networkd-wait-online', path
=which_paths
)
42 networkctl_bin
=shutil
.which('networkctl', path
=which_paths
)
43 resolvectl_bin
=shutil
.which('resolvectl', path
=which_paths
)
44 timedatectl_bin
=shutil
.which('timedatectl', path
=which_paths
)
56 def check_output(*command
, **kwargs
):
57 # This replaces both check_output and check_call (output can be ignored)
58 command
= command
[0].split() + list(command
[1:])
59 return subprocess
.check_output(command
, universal_newlines
=True, **kwargs
).rstrip()
61 def call(*command
, **kwargs
):
62 command
= command
[0].split() + list(command
[1:])
63 return subprocess
.call(command
, universal_newlines
=True, **kwargs
)
65 def run(*command
, **kwargs
):
66 command
= command
[0].split() + list(command
[1:])
67 return subprocess
.run(command
, universal_newlines
=True, check
=False, **kwargs
)
69 def is_module_available(module_name
):
70 lsmod_output
= check_output('lsmod')
71 module_re
= re
.compile(rf
'^{re.escape(module_name)}\b', re
.MULTILINE
)
72 return module_re
.search(lsmod_output
) or not call('modprobe', module_name
, stderr
=subprocess
.DEVNULL
)
74 def expectedFailureIfModuleIsNotAvailable(module_name
):
76 if not is_module_available(module_name
):
77 return unittest
.expectedFailure(func
)
82 def expectedFailureIfERSPANModuleIsNotAvailable():
84 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', stderr
=subprocess
.DEVNULL
)
86 call('ip link del erspan99')
89 return unittest
.expectedFailure(func
)
93 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable():
95 rc
= call('ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7', stderr
=subprocess
.DEVNULL
)
97 call('ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
100 return unittest
.expectedFailure(func
)
104 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
106 rc
= call('ip rule add not from 192.168.100.19 ipproto tcp table 7', stderr
=subprocess
.DEVNULL
)
108 call('ip rule del not from 192.168.100.19 ipproto tcp table 7')
111 return unittest
.expectedFailure(func
)
115 def expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable():
118 rc
= call('ip rule add from 192.168.100.19 table 7 uidrange 200-300', stderr
=subprocess
.DEVNULL
)
120 ret
= run('ip rule list from 192.168.100.19 table 7', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
121 if ret
.returncode
== 0 and 'uidrange 200-300' in ret
.stdout
.rstrip():
123 call('ip rule del from 192.168.100.19 table 7 uidrange 200-300')
128 return unittest
.expectedFailure(func
)
132 def expectedFailureIfLinkFileFieldIsNotSet():
135 rc
= call('ip link add name dummy99 type dummy', stderr
=subprocess
.DEVNULL
)
137 ret
= run('udevadm info -w10s /sys/class/net/dummy99', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
138 if ret
.returncode
== 0 and 'E: ID_NET_LINK_FILE=' in ret
.stdout
.rstrip():
140 call('ip link del dummy99')
145 return unittest
.expectedFailure(func
)
149 def expectedFailureIfNexthopIsNotAvailable():
151 rc
= call('ip nexthop list', stderr
=subprocess
.DEVNULL
)
155 return unittest
.expectedFailure(func
)
159 def expectedFailureIfRTA_VIAIsNotSupported():
161 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
162 call('ip link set up dev dummy98', stderr
=subprocess
.DEVNULL
)
163 call('ip route add 2001:1234:5:8fff:ff:ff:ff:fe/128 dev dummy98', stderr
=subprocess
.DEVNULL
)
164 rc
= call('ip route add 10.10.10.10 via inet6 2001:1234:5:8fff:ff:ff:ff:fe dev dummy98', stderr
=subprocess
.DEVNULL
)
165 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
169 return unittest
.expectedFailure(func
)
173 def expectedFailureIfAlternativeNameIsNotAvailable():
176 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
177 rc
= call('ip link prop add dev dummy98 altname hogehogehogehogehoge', stderr
=subprocess
.DEVNULL
)
179 rc
= call('ip link show dev hogehogehogehogehoge', stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
183 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
187 return unittest
.expectedFailure(func
)
191 def expectedFailureIfNetdevsimWithSRIOVIsNotAvailable():
193 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
194 rc
= call('modprobe netdevsim', stderr
=subprocess
.DEVNULL
)
196 return unittest
.expectedFailure(func
)
199 with
open('/sys/bus/netdevsim/new_device', mode
='w') as f
:
202 return unittest
.expectedFailure(func
)
204 call('udevadm settle')
205 call('udevadm info -w10s /sys/devices/netdevsim99/net/eni99np1', stderr
=subprocess
.DEVNULL
)
207 with
open('/sys/class/net/eni99np1/device/sriov_numvfs', mode
='w') as f
:
210 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
211 return unittest
.expectedFailure(func
)
213 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
218 def expectedFailureIfCAKEIsNotAvailable():
220 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
221 rc
= call('tc qdisc add dev dummy98 parent root cake', stderr
=subprocess
.DEVNULL
)
222 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
226 return unittest
.expectedFailure(func
)
230 def expectedFailureIfPIEIsNotAvailable():
232 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
233 rc
= call('tc qdisc add dev dummy98 parent root pie', stderr
=subprocess
.DEVNULL
)
234 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
238 return unittest
.expectedFailure(func
)
242 def expectedFailureIfHHFIsNotAvailable():
244 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
245 rc
= call('tc qdisc add dev dummy98 parent root hhf', stderr
=subprocess
.DEVNULL
)
246 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
250 return unittest
.expectedFailure(func
)
254 def expectedFailureIfETSIsNotAvailable():
256 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
257 rc
= call('tc qdisc add dev dummy98 parent root ets bands 10', stderr
=subprocess
.DEVNULL
)
258 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
262 return unittest
.expectedFailure(func
)
266 def expectedFailureIfFQPIEIsNotAvailable():
268 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
269 rc
= call('tc qdisc add dev dummy98 parent root fq_pie', stderr
=subprocess
.DEVNULL
)
270 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
274 return unittest
.expectedFailure(func
)
281 os
.makedirs(network_unit_file_path
, exist_ok
=True)
282 os
.makedirs(networkd_conf_dropin_path
, exist_ok
=True)
283 os
.makedirs(networkd_ci_path
, exist_ok
=True)
284 os
.makedirs(udev_rules_dir
, exist_ok
=True)
286 shutil
.rmtree(networkd_ci_path
)
287 copytree(os
.path
.join(os
.path
.dirname(os
.path
.abspath(__file__
)), 'conf'), networkd_ci_path
)
289 shutil
.copy(os
.path
.join(networkd_ci_path
, '00-debug-net.rules'), udev_rules_dir
)
291 for u
in ['systemd-networkd.socket', 'systemd-networkd.service', 'systemd-resolved.service',
292 'systemd-udevd-kernel.socket', 'systemd-udevd-control.socket', 'systemd-udevd.service',
293 'firewalld.service']:
294 if call(f
'systemctl is-active --quiet {u}') == 0:
295 check_output(f
'systemctl stop {u}')
296 running_units
.append(u
)
300 'StartLimitIntervalSec=0',
307 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin
,
311 drop_in
+= ['ExecStart=!!' + networkd_bin
]
313 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
315 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
317 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
319 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
320 if asan_options
or lsan_options
or ubsan_options
:
321 drop_in
+= ['SystemCallFilter=']
322 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
323 drop_in
+= ['MemoryDenyWriteExecute=no']
330 os
.makedirs('/run/systemd/system/systemd-networkd.service.d', exist_ok
=True)
331 with
open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode
='w') as f
:
332 f
.write('\n'.join(drop_in
))
340 drop_in
+= ['ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + resolved_bin
]
342 drop_in
+= ['ExecStart=!!' + resolved_bin
]
344 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
346 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
348 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
350 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
351 if asan_options
or lsan_options
or ubsan_options
:
352 drop_in
+= ['SystemCallFilter=']
353 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
354 drop_in
+= ['MemoryDenyWriteExecute=no']
361 os
.makedirs('/run/systemd/system/systemd-resolved.service.d', exist_ok
=True)
362 with
open('/run/systemd/system/systemd-resolved.service.d/00-override.conf', mode
='w') as f
:
363 f
.write('\n'.join(drop_in
))
368 'ExecStart=!!' + udevd_bin
,
371 os
.makedirs('/run/systemd/system/systemd-udevd.service.d', exist_ok
=True)
372 with
open('/run/systemd/system/systemd-udevd.service.d/00-override.conf', mode
='w') as f
:
373 f
.write('\n'.join(drop_in
))
375 check_output('systemctl daemon-reload')
376 print(check_output('systemctl cat systemd-networkd.service'))
377 print(check_output('systemctl cat systemd-resolved.service'))
378 print(check_output('systemctl cat systemd-udevd.service'))
379 check_output('systemctl restart systemd-resolved')
380 check_output('systemctl restart systemd-udevd')
382 def tearDownModule():
385 shutil
.rmtree(networkd_ci_path
)
386 os
.remove(os
.path
.join(udev_rules_dir
, '00-debug-net.rules'))
388 for u
in ['systemd-networkd.socket', 'systemd-networkd.service', 'systemd-resolved.service']:
389 check_output(f
'systemctl stop {u}')
391 shutil
.rmtree('/run/systemd/system/systemd-networkd.service.d')
392 shutil
.rmtree('/run/systemd/system/systemd-resolved.service.d')
393 shutil
.rmtree('/run/systemd/system/systemd-udevd.service.d')
394 check_output('systemctl daemon-reload')
395 check_output('systemctl restart systemd-udevd.service')
397 for u
in running_units
:
398 check_output(f
'systemctl start {u}')
400 def read_link_attr(*args
):
401 with
open(os
.path
.join('/sys/class/net/', *args
)) as f
:
402 return f
.readline().strip()
404 def read_bridge_port_attr(bridge
, link
, attribute
):
405 path_bridge
= os
.path
.join('/sys/devices/virtual/net', bridge
)
406 path_port
= 'lower_' + link
+ '/brport'
407 path
= os
.path
.join(path_bridge
, path_port
)
409 with
open(os
.path
.join(path
, attribute
)) as f
:
410 return f
.readline().strip()
412 def link_exists(link
):
413 return os
.path
.exists(os
.path
.join('/sys/class/net', link
))
415 def remove_links(links
):
417 if link_exists(link
):
418 call('ip link del dev', link
)
421 def remove_fou_ports(ports
):
423 call('ip fou del port', port
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
425 def remove_routing_policy_rule_tables(tables
):
429 rc
= call('ip rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
432 rc
= call('ip -6 rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
434 def remove_routes(routes
):
435 for route_type
, addr
in routes
:
436 call('ip route del', route_type
, addr
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
438 def remove_blackhole_nexthops():
439 ret
= run('ip nexthop show dev lo', stdout
=subprocess
.PIPE
, stderr
=subprocess
.DEVNULL
)
440 if ret
.returncode
== 0:
441 for line
in ret
.stdout
.rstrip().splitlines():
443 call(f
'ip nexthop del id {id}')
445 def remove_l2tp_tunnels(tunnel_ids
):
446 output
= check_output('ip l2tp show tunnel')
447 for tid
in tunnel_ids
:
448 words
='Tunnel ' + tid
+ ', encap'
450 call('ip l2tp del tunnel tid', tid
)
453 def read_ipv6_sysctl_attr(link
, attribute
):
454 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, link
), attribute
)) as f
:
455 return f
.readline().strip()
457 def read_ipv4_sysctl_attr(link
, attribute
):
458 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv4_path
, link
), attribute
)) as f
:
459 return f
.readline().strip()
461 def copy_unit_to_networkd_unit_path(*units
, dropins
=True):
462 """Copy networkd unit files into the testbed.
464 Any networkd unit file type can be specified, as well as drop-in files.
466 By default, all drop-ins for a specified unit file are copied in;
467 to avoid that specify dropins=False.
469 When a drop-in file is specified, its unit file is also copied in automatically.
473 if dropins
and os
.path
.exists(os
.path
.join(networkd_ci_path
, unit
+ '.d')):
474 copytree(os
.path
.join(networkd_ci_path
, unit
+ '.d'), os
.path
.join(network_unit_file_path
, unit
+ '.d'))
475 if unit
.endswith('.conf'):
477 dropindir
= os
.path
.join(network_unit_file_path
, os
.path
.dirname(dropin
))
478 os
.makedirs(dropindir
, exist_ok
=True)
479 shutil
.copy(os
.path
.join(networkd_ci_path
, dropin
), dropindir
)
480 unit
= os
.path
.dirname(dropin
).rstrip('.d')
481 shutil
.copy(os
.path
.join(networkd_ci_path
, unit
), network_unit_file_path
)
483 def remove_unit_from_networkd_path(units
):
484 """Remove previously copied unit files from the testbed.
486 Drop-ins will be removed automatically.
489 if os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
)):
490 os
.remove(os
.path
.join(network_unit_file_path
, unit
))
491 if os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
+ '.d')):
492 shutil
.rmtree(os
.path
.join(network_unit_file_path
, unit
+ '.d'))
494 def copy_networkd_conf_dropin(*dropins
):
495 """Copy networkd.conf dropin files into the testbed."""
496 for dropin
in dropins
:
497 shutil
.copy(os
.path
.join(networkd_ci_path
, dropin
), networkd_conf_dropin_path
)
499 def remove_networkd_conf_dropin(dropins
):
500 """Remove previously copied networkd.conf dropin files from the testbed."""
501 for dropin
in dropins
:
502 if os
.path
.exists(os
.path
.join(networkd_conf_dropin_path
, dropin
)):
503 os
.remove(os
.path
.join(networkd_conf_dropin_path
, dropin
))
505 def start_dnsmasq(additional_options
='', interface
='veth-peer', ipv4_range
='192.168.5.10,192.168.5.200', ipv4_router
='192.168.5.1', ipv6_range
='2600::10,2600::20', lease_time
='1h'):
506 dnsmasq_command
= f
'dnsmasq -8 {dnsmasq_log_file} --log-queries=extra --log-dhcp --pid-file={dnsmasq_pid_file} --conf-file=/dev/null --bind-interfaces --interface={interface} --enable-ra --dhcp-range={ipv6_range},{lease_time} --dhcp-range={ipv4_range},{lease_time} -R --dhcp-leasefile={dnsmasq_lease_file} --dhcp-option=26,1492 --dhcp-option=option:router,{ipv4_router} --port=0 ' + additional_options
507 check_output(dnsmasq_command
)
509 def stop_by_pid_file(pid_file
):
510 if os
.path
.exists(pid_file
):
511 with
open(pid_file
, 'r') as f
:
512 pid
= f
.read().rstrip(' \t\r\n\0')
513 os
.kill(int(pid
), signal
.SIGTERM
)
517 print(f
"PID {pid} is still alive, waiting...")
520 if e
.errno
== errno
.ESRCH
:
522 print(f
"Unexpected exception when waiting for {pid} to die: {e.errno}")
527 stop_by_pid_file(dnsmasq_pid_file
)
529 def dump_dnsmasq_log_file():
530 if os
.path
.exists(dnsmasq_log_file
):
531 with
open (dnsmasq_log_file
) as in_file
:
532 print(in_file
.read())
534 def search_words_in_dnsmasq_log(words
, show_all
=False):
535 if os
.path
.exists(dnsmasq_log_file
):
536 with
open (dnsmasq_log_file
) as in_file
:
537 contents
= in_file
.read()
540 for line
in contents
.splitlines():
543 print("%s, %s" % (words
, line
))
547 def remove_dnsmasq_lease_file():
548 if os
.path
.exists(dnsmasq_lease_file
):
549 os
.remove(dnsmasq_lease_file
)
551 def remove_dnsmasq_log_file():
552 if os
.path
.exists(dnsmasq_log_file
):
553 os
.remove(dnsmasq_log_file
)
555 def start_isc_dhcpd(interface
, conf_file
, ip
):
556 conf_file_path
= os
.path
.join(networkd_ci_path
, conf_file
)
557 isc_dhcpd_command
= f
'dhcpd {ip} -cf {conf_file_path} -lf {isc_dhcpd_lease_file} -pf {isc_dhcpd_pid_file} {interface}'
558 Path(isc_dhcpd_lease_file
).touch()
559 check_output(isc_dhcpd_command
)
561 def stop_isc_dhcpd():
562 stop_by_pid_file(isc_dhcpd_pid_file
)
563 if os
.path
.exists(isc_dhcpd_lease_file
):
564 os
.remove(isc_dhcpd_lease_file
)
566 def remove_networkd_state_files():
567 if os
.path
.exists(os
.path
.join(networkd_runtime_directory
, 'state')):
568 os
.remove(os
.path
.join(networkd_runtime_directory
, 'state'))
570 def stop_networkd(show_logs
=True, remove_state_files
=True):
572 invocation_id
= check_output('systemctl show systemd-networkd -p InvocationID --value')
573 check_output('systemctl stop systemd-networkd.socket')
574 check_output('systemctl stop systemd-networkd.service')
576 print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
))
577 if remove_state_files
:
578 remove_networkd_state_files()
580 def start_networkd(sleep_sec
=0):
581 check_output('systemctl start systemd-networkd')
583 time
.sleep(sleep_sec
)
585 def restart_networkd(sleep_sec
=0, show_logs
=True, remove_state_files
=True):
586 stop_networkd(show_logs
, remove_state_files
)
587 start_networkd(sleep_sec
)
590 # pylint: disable=no-member
592 def check_link_exists(self
, link
):
593 self
.assertTrue(link_exists(link
))
595 def check_link_attr(self
, *args
):
596 self
.assertEqual(read_link_attr(*args
[:-1]), args
[-1])
598 def wait_activated(self
, link
, state
='down', timeout
=20, fail_assert
=True):
599 # wait for the interface is activated.
600 invocation_id
= check_output('systemctl show systemd-networkd -p InvocationID --value')
601 needle
= f
'{link}: Bringing link {state}'
603 for iteration
in range(timeout
+1):
604 output
= check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
)
605 if needle
in output
and flag
in check_output(f
'ip link show {link}'):
607 if iteration
< timeout
:
610 self
.fail(f
'Timed out waiting for {link} activated.')
613 def wait_operstate(self
, link
, operstate
='degraded', setup_state
='configured', setup_timeout
=5, fail_assert
=True):
614 """Wait for the link to reach the specified operstate and/or setup state.
616 Specify None or '' for either operstate or setup_state to ignore that state.
617 This will recheck until the state conditions are met or the timeout expires.
619 If the link successfully matches the requested state, this returns True.
620 If this times out waiting for the link to match, the behavior depends on the
621 'fail_assert' parameter; if True, this causes a test assertion failure,
622 otherwise this returns False. The default is to cause assertion failure.
624 Note that this function matches on *exactly* the given operstate and setup_state.
625 To wait for a link to reach *or exceed* a given operstate, use wait_online().
632 for secs
in range(setup_timeout
+ 1):
633 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
, env
=env
)
635 if re
.search(rf
'(?m)^\s*State:\s+{operstate}\s+\({setup_state}\)\s*$', output
):
637 # don't bother sleeping if time is up
638 if secs
< setup_timeout
:
641 self
.fail(f
'Timed out waiting for {link} to reach state {operstate}/{setup_state}')
644 def wait_online(self
, links_with_operstate
, timeout
='20s', bool_any
=False, ipv4
=False, ipv6
=False, setup_state
='configured', setup_timeout
=5):
645 """Wait for the link(s) to reach the specified operstate and/or setup state.
647 This is similar to wait_operstate() but can be used for multiple links,
648 and it also calls systemd-networkd-wait-online to wait for the given operstate.
649 The operstate should be specified in the link name, like 'eth0:degraded'.
650 If just a link name is provided, wait-online's default operstate to wait for is degraded.
652 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
653 'setup_timeout' controls the per-link timeout waiting for the setup_state.
655 Set 'bool_any' to True to wait for any (instead of all) of the given links.
656 If this is set, no setup_state checks are done.
658 Set 'ipv4' or 'ipv6' to True to wait for IPv4 address or IPv6 address, respectively, of each of the given links.
659 This is applied only for the operational state 'degraded' or above.
661 Note that this function waits for the link(s) to reach *or exceed* the given operstate.
662 However, the setup_state, if specified, must be matched *exactly*.
664 This returns if the link(s) reached the requested operstate/setup_state; otherwise it
665 raises CalledProcessError or fails test assertion.
667 args
= wait_online_cmd
+ [f
'--timeout={timeout}'] + [f
'--interface={link}' for link
in links_with_operstate
]
675 check_output(*args
, env
=env
)
676 except subprocess
.CalledProcessError
:
677 for link
in links_with_operstate
:
678 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
.split(':')[0], env
=env
)
681 if not bool_any
and setup_state
:
682 for link
in links_with_operstate
:
683 self
.wait_operstate(link
.split(':')[0], None, setup_state
, setup_timeout
)
685 def wait_address(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
686 for i
in range(timeout_sec
):
689 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
690 if re
.search(address_regex
, output
) and 'tentative' not in output
:
693 self
.assertRegex(output
, address_regex
)
695 def wait_address_dropped(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
696 for i
in range(timeout_sec
):
699 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
700 if not re
.search(address_regex
, output
):
703 self
.assertNotRegex(output
, address_regex
)
705 class NetworkctlTests(unittest
.TestCase
, Utilities
):
715 '11-dummy-mtu.netdev',
719 '25-address-static.network',
721 'netdev-link-local-addressing-yes.network',
725 remove_links(self
.links
)
726 stop_networkd(show_logs
=False)
729 remove_links(self
.links
)
730 remove_unit_from_networkd_path(self
.units
)
731 stop_networkd(show_logs
=True)
733 @expectedFailureIfAlternativeNameIsNotAvailable()
734 def test_altname(self
):
735 copy_unit_to_networkd_unit_path('netdev-link-local-addressing-yes.network', '12-dummy.netdev', '12-dummy.link')
736 check_output('udevadm control --reload')
738 self
.wait_online(['dummy98:degraded'])
740 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
741 self
.assertRegex(output
, 'hogehogehogehogehogehoge')
743 def test_reconfigure(self
):
744 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
746 self
.wait_online(['dummy98:routable'])
748 output
= check_output('ip -4 address show dev dummy98')
750 self
.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output
)
751 self
.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output
)
752 self
.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output
)
754 check_output('ip address del 10.1.2.3/16 dev dummy98')
755 check_output('ip address del 10.1.2.4/16 dev dummy98')
756 check_output('ip address del 10.2.2.4/16 dev dummy98')
758 check_output(*networkctl_cmd
, 'reconfigure', 'dummy98', env
=env
)
759 self
.wait_online(['dummy98:routable'])
761 output
= check_output('ip -4 address show dev dummy98')
763 self
.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output
)
764 self
.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output
)
765 self
.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output
)
767 remove_unit_from_networkd_path(['25-address-static.network'])
769 check_output(*networkctl_cmd
, 'reload', env
=env
)
770 self
.wait_operstate('dummy98', 'degraded', setup_state
='unmanaged')
772 output
= check_output('ip -4 address show dev dummy98')
774 self
.assertNotIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output
)
775 self
.assertNotIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output
)
776 self
.assertNotIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output
)
778 copy_unit_to_networkd_unit_path('25-address-static.network')
779 check_output(*networkctl_cmd
, 'reload', env
=env
)
780 self
.wait_online(['dummy98:routable'])
782 output
= check_output('ip -4 address show dev dummy98')
784 self
.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output
)
785 self
.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output
)
786 self
.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output
)
788 def test_reload(self
):
791 copy_unit_to_networkd_unit_path('11-dummy.netdev')
792 check_output(*networkctl_cmd
, 'reload', env
=env
)
793 self
.wait_operstate('test1', 'off', setup_state
='unmanaged')
795 copy_unit_to_networkd_unit_path('11-dummy.network')
796 check_output(*networkctl_cmd
, 'reload', env
=env
)
797 self
.wait_online(['test1:degraded'])
799 remove_unit_from_networkd_path(['11-dummy.network'])
800 check_output(*networkctl_cmd
, 'reload', env
=env
)
801 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
803 remove_unit_from_networkd_path(['11-dummy.netdev'])
804 check_output(*networkctl_cmd
, 'reload', env
=env
)
805 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
807 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
808 check_output(*networkctl_cmd
, 'reload', env
=env
)
809 self
.wait_operstate('test1', 'degraded')
812 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
815 self
.wait_online(['test1:degraded'])
817 output
= check_output(*networkctl_cmd
, 'list', env
=env
)
818 self
.assertRegex(output
, '1 lo ')
819 self
.assertRegex(output
, 'test1')
821 output
= check_output(*networkctl_cmd
, 'list', 'test1', env
=env
)
822 self
.assertNotRegex(output
, '1 lo ')
823 self
.assertRegex(output
, 'test1')
825 output
= check_output(*networkctl_cmd
, 'list', 'te*', env
=env
)
826 self
.assertNotRegex(output
, '1 lo ')
827 self
.assertRegex(output
, 'test1')
829 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'te*', env
=env
)
830 self
.assertNotRegex(output
, '1: lo ')
831 self
.assertRegex(output
, 'test1')
833 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'tes[a-z][0-9]', env
=env
)
834 self
.assertNotRegex(output
, '1: lo ')
835 self
.assertRegex(output
, 'test1')
838 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
841 self
.wait_online(['test1:degraded'])
843 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
844 self
.assertRegex(output
, 'MTU: 1600')
847 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
849 self
.wait_online(['test1:degraded'])
851 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
853 self
.assertRegex(output
, 'Type: ether')
855 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
857 self
.assertRegex(output
, 'Type: loopback')
859 @expectedFailureIfLinkFileFieldIsNotSet()
860 def test_udev_link_file(self
):
861 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
863 self
.wait_online(['test1:degraded'])
865 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
867 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
868 self
.assertRegex(output
, r
'Network File: /run/systemd/network/11-dummy.network')
870 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
872 self
.assertRegex(output
, r
'Link File: n/a')
873 self
.assertRegex(output
, r
'Network File: n/a')
875 def test_delete_links(self
):
876 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
877 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
880 self
.wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
882 check_output(*networkctl_cmd
, 'delete', 'test1', 'veth99', env
=env
)
883 self
.assertFalse(link_exists('test1'))
884 self
.assertFalse(link_exists('veth99'))
885 self
.assertFalse(link_exists('veth-peer'))
887 class NetworkdNetDevTests(unittest
.TestCase
, Utilities
):
889 links_remove_earlier
= [
964 '10-dropin-test.netdev',
968 '13-not-match-udev-property.network',
969 '14-match-udev-property.network',
970 '15-name-conflict-test.netdev',
973 '21-vlan-test1.network',
976 '25-6rd-tunnel.netdev',
980 '25-bond-balanced-tlb.netdev',
982 '25-bridge-configure-without-carrier.network',
984 '25-erspan-tunnel-local-any.netdev',
985 '25-erspan-tunnel.netdev',
986 '25-fou-gretap.netdev',
988 '25-fou-ipip.netdev',
989 '25-fou-ipproto-gre.netdev',
990 '25-fou-ipproto-ipip.netdev',
993 '25-gretap-tunnel-local-any.netdev',
994 '25-gretap-tunnel.netdev',
995 '25-gre-tunnel-any-any.netdev',
996 '25-gre-tunnel-local-any.netdev',
997 '25-gre-tunnel-remote-any.netdev',
998 '25-gre-tunnel.netdev',
1000 '25-ip6gretap-tunnel-local-any.netdev',
1001 '25-ip6gretap-tunnel.netdev',
1002 '25-ip6gre-tunnel-any-any.netdev',
1003 '25-ip6gre-tunnel-local-any.netdev',
1004 '25-ip6gre-tunnel-remote-any.netdev',
1005 '25-ip6gre-tunnel.netdev',
1006 '25-ip6tnl-tunnel-any-any.netdev',
1007 '25-ip6tnl-tunnel-local-any.netdev',
1008 '25-ip6tnl-tunnel-local-slaac.netdev',
1009 '25-ip6tnl-tunnel-local-slaac.network',
1010 '25-ip6tnl-tunnel-remote-any.netdev',
1011 '25-ip6tnl-tunnel.netdev',
1012 '25-ipip-tunnel-any-any.netdev',
1013 '25-ipip-tunnel-independent.netdev',
1014 '25-ipip-tunnel-independent-loopback.netdev',
1015 '25-ipip-tunnel-local-any.netdev',
1016 '25-ipip-tunnel-remote-any.netdev',
1017 '25-ipip-tunnel.netdev',
1020 '25-isatap-tunnel.netdev',
1023 '25-macsec.network',
1025 '25-sit-tunnel-any-any.netdev',
1026 '25-sit-tunnel-local-any.netdev',
1027 '25-sit-tunnel-remote-any.netdev',
1028 '25-sit-tunnel.netdev',
1031 '25-tunnel-any-any.network',
1032 '25-tunnel-local-any.network',
1033 '25-tunnel-remote-any.network',
1034 '25-tunnel.network',
1036 '25-veth-mtu.netdev',
1039 '25-vti6-tunnel-any-any.netdev',
1040 '25-vti6-tunnel-local-any.netdev',
1041 '25-vti6-tunnel-remote-any.netdev',
1042 '25-vti6-tunnel.netdev',
1043 '25-vti-tunnel-any-any.netdev',
1044 '25-vti-tunnel-local-any.netdev',
1045 '25-vti-tunnel-remote-any.netdev',
1046 '25-vti-tunnel.netdev',
1048 '25-vxlan-independent.netdev',
1049 '25-vxlan-ipv6.netdev',
1050 '25-vxlan-local-slaac.netdev',
1051 '25-vxlan-local-slaac.network',
1052 '25-vxlan-veth99.network',
1054 '25-wireguard-23-peers.netdev',
1055 '25-wireguard-23-peers.network',
1056 '25-wireguard-no-peer.netdev',
1057 '25-wireguard-no-peer.network',
1058 '25-wireguard-preshared-key.txt',
1059 '25-wireguard-private-key.txt',
1060 '25-wireguard.netdev',
1061 '25-wireguard.network',
1063 '25-xfrm-independent.netdev',
1069 'ip6gretap.network',
1070 'ip6gretun.network',
1071 'ip6tnl-slaac.network',
1074 'ipv6-prefix.network',
1081 'netdev-link-local-addressing-yes.network',
1085 'vxlan-ipv6.network',
1086 'vxlan-test1.network',
1096 remove_fou_ports(self
.fou_ports
)
1097 remove_links(self
.links_remove_earlier
)
1098 remove_links(self
.links
)
1099 stop_networkd(show_logs
=False)
1102 remove_fou_ports(self
.fou_ports
)
1103 remove_links(self
.links_remove_earlier
)
1104 remove_links(self
.links
)
1105 remove_unit_from_networkd_path(self
.units
)
1106 stop_networkd(show_logs
=True)
1108 def test_dropin_and_name_conflict(self
):
1109 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
1112 self
.wait_online(['dropin-test:off'], setup_state
='unmanaged')
1114 output
= check_output('ip link show dropin-test')
1116 self
.assertRegex(output
, '00:50:56:c0:00:28')
1118 def test_match_udev_property(self
):
1119 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
1121 self
.wait_online(['dummy98:routable'])
1123 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
1125 self
.assertRegex(output
, 'Network File: /run/systemd/network/14-match-udev-property')
1127 def test_wait_online_any(self
):
1128 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
1131 self
.wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
1133 self
.wait_operstate('bridge99', '(off|no-carrier)', setup_state
='configuring')
1134 self
.wait_operstate('test1', 'degraded')
1136 @expectedFailureIfModuleIsNotAvailable('bareudp')
1137 def test_bareudp(self
):
1138 copy_unit_to_networkd_unit_path('25-bareudp.netdev', 'netdev-link-local-addressing-yes.network')
1141 self
.wait_online(['bareudp99:degraded'])
1143 output
= check_output('ip -d link show bareudp99')
1145 self
.assertRegex(output
, 'dstport 1000 ')
1146 self
.assertRegex(output
, 'ethertype ip ')
1148 @expectedFailureIfModuleIsNotAvailable('batman-adv')
1149 def test_batadv(self
):
1150 copy_unit_to_networkd_unit_path('25-batadv.netdev', 'netdev-link-local-addressing-yes.network')
1153 self
.wait_online(['batadv99:degraded'])
1155 output
= check_output('ip -d link show batadv99')
1157 self
.assertRegex(output
, 'batadv')
1159 def test_bridge(self
):
1160 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
1163 self
.wait_online(['bridge99:no-carrier'])
1165 tick
= os
.sysconf('SC_CLK_TCK')
1166 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
1167 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
1168 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'forward_delay')) / tick
))
1169 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'ageing_time')) / tick
))
1170 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge', 'priority')))
1171 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_querier')))
1172 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_snooping')))
1173 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'stp_state')))
1174 self
.assertEqual(3, int(read_link_attr('bridge99', 'bridge', 'multicast_igmp_version')))
1176 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
1178 self
.assertRegex(output
, 'Priority: 9')
1179 self
.assertRegex(output
, 'STP: yes')
1180 self
.assertRegex(output
, 'Multicast IGMP Version: 3')
1182 def test_bond(self
):
1183 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
1186 self
.wait_online(['bond99:off', 'bond98:off'], setup_state
='unmanaged')
1188 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
1189 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
1190 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
1191 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
1192 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
1193 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
1194 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
1195 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
1196 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
1197 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
1198 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
1200 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
1201 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
1203 def test_vlan(self
):
1204 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
1205 '21-vlan.network', '21-vlan-test1.network')
1208 self
.wait_online(['test1:degraded', 'vlan99:routable'])
1210 output
= check_output('ip -d link show test1')
1212 self
.assertRegex(output
, ' mtu 2000 ')
1214 output
= check_output('ip -d link show vlan99')
1216 self
.assertRegex(output
, ' mtu 2000 ')
1217 self
.assertRegex(output
, 'REORDER_HDR')
1218 self
.assertRegex(output
, 'LOOSE_BINDING')
1219 self
.assertRegex(output
, 'GVRP')
1220 self
.assertRegex(output
, 'MVRP')
1221 self
.assertRegex(output
, ' id 99 ')
1223 output
= check_output('ip -4 address show dev test1')
1225 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
1226 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
1228 output
= check_output('ip -4 address show dev vlan99')
1230 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
1232 def test_macvtap(self
):
1233 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
1234 with self
.subTest(mode
=mode
):
1235 if mode
!= 'private':
1237 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
1238 '11-dummy.netdev', 'macvtap.network')
1239 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
1240 f
.write('[MACVTAP]\nMode=' + mode
)
1243 self
.wait_online(['macvtap99:degraded',
1244 'test1:carrier' if mode
== 'passthru' else 'test1:degraded'])
1246 output
= check_output('ip -d link show macvtap99')
1248 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
1250 def test_macvlan(self
):
1251 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
1252 with self
.subTest(mode
=mode
):
1253 if mode
!= 'private':
1255 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
1256 '11-dummy.netdev', 'macvlan.network')
1257 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
1258 f
.write('[MACVLAN]\nMode=' + mode
)
1261 self
.wait_online(['macvlan99:degraded',
1262 'test1:carrier' if mode
== 'passthru' else 'test1:degraded'])
1264 output
= check_output('ip -d link show test1')
1266 self
.assertRegex(output
, ' mtu 2000 ')
1268 output
= check_output('ip -d link show macvlan99')
1270 self
.assertRegex(output
, ' mtu 2000 ')
1271 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
1273 rc
= call("ip link del test1")
1274 self
.assertEqual(rc
, 0)
1277 rc
= call("ip link add test1 type dummy")
1278 self
.assertEqual(rc
, 0)
1281 self
.wait_online(['macvlan99:degraded',
1282 'test1:carrier' if mode
== 'passthru' else 'test1:degraded'])
1284 output
= check_output('ip -d link show test1')
1286 self
.assertRegex(output
, ' mtu 2000 ')
1288 output
= check_output('ip -d link show macvlan99')
1290 self
.assertRegex(output
, ' mtu 2000 ')
1291 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
1293 @expectedFailureIfModuleIsNotAvailable('ipvlan')
1294 def test_ipvlan(self
):
1295 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1296 with self
.subTest(mode
=mode
, flag
=flag
):
1299 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
1300 '11-dummy.netdev', 'ipvlan.network')
1301 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
1302 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
1305 self
.wait_online(['ipvlan99:degraded', 'test1:degraded'])
1307 output
= check_output('ip -d link show ipvlan99')
1309 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
1311 @expectedFailureIfModuleIsNotAvailable('ipvtap')
1312 def test_ipvtap(self
):
1313 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1314 with self
.subTest(mode
=mode
, flag
=flag
):
1317 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
1318 '11-dummy.netdev', 'ipvtap.network')
1319 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
1320 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
1323 self
.wait_online(['ipvtap99:degraded', 'test1:degraded'])
1325 output
= check_output('ip -d link show ipvtap99')
1327 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
1329 def test_veth(self
):
1330 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network',
1331 '25-veth-mtu.netdev')
1334 self
.wait_online(['veth99:degraded', 'veth-peer:degraded', 'veth-mtu:degraded', 'veth-mtu-peer:degraded'])
1336 output
= check_output('ip -d link show veth99')
1338 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
1339 output
= check_output('ip -d link show veth-peer')
1341 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
1343 output
= check_output('ip -d link show veth-mtu')
1345 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:be')
1346 self
.assertRegex(output
, 'mtu 1800')
1347 output
= check_output('ip -d link show veth-mtu-peer')
1349 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bf')
1350 self
.assertRegex(output
, 'mtu 1800')
1353 copy_unit_to_networkd_unit_path('25-tun.netdev')
1356 self
.wait_online(['tun99:off'], setup_state
='unmanaged')
1358 output
= check_output('ip -d link show tun99')
1360 # Old ip command does not support IFF_ flags
1361 self
.assertRegex(output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
1364 copy_unit_to_networkd_unit_path('25-tap.netdev')
1367 self
.wait_online(['tap99:off'], setup_state
='unmanaged')
1369 output
= check_output('ip -d link show tap99')
1371 # Old ip command does not support IFF_ flags
1372 self
.assertRegex(output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
1374 @expectedFailureIfModuleIsNotAvailable('vrf')
1376 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
1379 self
.wait_online(['vrf99:carrier'])
1381 @expectedFailureIfModuleIsNotAvailable('vcan')
1382 def test_vcan(self
):
1383 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
1386 self
.wait_online(['vcan99:carrier'])
1388 @expectedFailureIfModuleIsNotAvailable('vxcan')
1389 def test_vxcan(self
):
1390 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
1393 self
.wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
1395 @expectedFailureIfModuleIsNotAvailable('wireguard')
1396 def test_wireguard(self
):
1397 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
1398 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
1399 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt',
1400 '25-wireguard-no-peer.netdev', '25-wireguard-no-peer.network')
1402 self
.wait_online(['wg99:routable', 'wg98:routable', 'wg97:carrier'])
1404 output
= check_output('ip -4 address show dev wg99')
1406 self
.assertIn('inet 192.168.124.1/24 scope global wg99', output
)
1408 output
= check_output('ip -4 address show dev wg98')
1410 self
.assertIn('inet 192.168.123.123/24 scope global wg98', output
)
1412 output
= check_output('ip -6 address show dev wg98')
1414 self
.assertIn('inet6 fd8d:4d6d:3ccb:500::1/64 scope global', output
)
1416 output
= check_output('ip -4 route show dev wg99 table 1234')
1418 self
.assertIn('192.168.26.0/24 proto static metric 123', output
)
1420 output
= check_output('ip -6 route show dev wg99 table 1234')
1422 self
.assertIn('fd31:bf08:57cb::/48 proto static metric 123 pref medium', output
)
1424 output
= check_output('ip -6 route show dev wg98 table 1234')
1426 self
.assertIn('fd8d:4d6d:3ccb:500:c79:2339:edce:ece1 proto static metric 123 pref medium', output
)
1427 self
.assertIn('fd8d:4d6d:3ccb:500:1dbf:ca8a:32d3:dd81 proto static metric 123 pref medium', output
)
1428 self
.assertIn('fd8d:4d6d:3ccb:500:1e54:1415:35d0:a47c proto static metric 123 pref medium', output
)
1429 self
.assertIn('fd8d:4d6d:3ccb:500:270d:b5dd:4a3f:8909 proto static metric 123 pref medium', output
)
1430 self
.assertIn('fd8d:4d6d:3ccb:500:5660:679d:3532:94d8 proto static metric 123 pref medium', output
)
1431 self
.assertIn('fd8d:4d6d:3ccb:500:6825:573f:30f3:9472 proto static metric 123 pref medium', output
)
1432 self
.assertIn('fd8d:4d6d:3ccb:500:6f2e:6888:c6fd:dfb9 proto static metric 123 pref medium', output
)
1433 self
.assertIn('fd8d:4d6d:3ccb:500:8d4d:bab:7280:a09a proto static metric 123 pref medium', output
)
1434 self
.assertIn('fd8d:4d6d:3ccb:500:900c:d437:ec27:8822 proto static metric 123 pref medium', output
)
1435 self
.assertIn('fd8d:4d6d:3ccb:500:9742:9931:5217:18d5 proto static metric 123 pref medium', output
)
1436 self
.assertIn('fd8d:4d6d:3ccb:500:9c11:d820:2e96:9be0 proto static metric 123 pref medium', output
)
1437 self
.assertIn('fd8d:4d6d:3ccb:500:a072:80da:de4f:add1 proto static metric 123 pref medium', output
)
1438 self
.assertIn('fd8d:4d6d:3ccb:500:a3f3:df38:19b0:721 proto static metric 123 pref medium', output
)
1439 self
.assertIn('fd8d:4d6d:3ccb:500:a94b:cd6a:a32d:90e6 proto static metric 123 pref medium', output
)
1440 self
.assertIn('fd8d:4d6d:3ccb:500:b39c:9cdc:755a:ead3 proto static metric 123 pref medium', output
)
1441 self
.assertIn('fd8d:4d6d:3ccb:500:b684:4f81:2e3e:132e proto static metric 123 pref medium', output
)
1442 self
.assertIn('fd8d:4d6d:3ccb:500:bad5:495d:8e9c:3427 proto static metric 123 pref medium', output
)
1443 self
.assertIn('fd8d:4d6d:3ccb:500:bfe5:c3c3:5d77:fcb proto static metric 123 pref medium', output
)
1444 self
.assertIn('fd8d:4d6d:3ccb:500:c624:6bf7:4c09:3b59 proto static metric 123 pref medium', output
)
1445 self
.assertIn('fd8d:4d6d:3ccb:500:d4f9:5dc:9296:a1a proto static metric 123 pref medium', output
)
1446 self
.assertIn('fd8d:4d6d:3ccb:500:dcdd:d33b:90c9:6088 proto static metric 123 pref medium', output
)
1447 self
.assertIn('fd8d:4d6d:3ccb:500:e2e1:ae15:103f:f376 proto static metric 123 pref medium', output
)
1448 self
.assertIn('fd8d:4d6d:3ccb:500:f349:c4f0:10c1:6b4 proto static metric 123 pref medium', output
)
1449 self
.assertIn('fd8d:4d6d:3ccb:c79:2339:edce::/96 proto static metric 123 pref medium', output
)
1450 self
.assertIn('fd8d:4d6d:3ccb:1dbf:ca8a:32d3::/96 proto static metric 123 pref medium', output
)
1451 self
.assertIn('fd8d:4d6d:3ccb:1e54:1415:35d0::/96 proto static metric 123 pref medium', output
)
1452 self
.assertIn('fd8d:4d6d:3ccb:270d:b5dd:4a3f::/96 proto static metric 123 pref medium', output
)
1453 self
.assertIn('fd8d:4d6d:3ccb:5660:679d:3532::/96 proto static metric 123 pref medium', output
)
1454 self
.assertIn('fd8d:4d6d:3ccb:6825:573f:30f3::/96 proto static metric 123 pref medium', output
)
1455 self
.assertIn('fd8d:4d6d:3ccb:6f2e:6888:c6fd::/96 proto static metric 123 pref medium', output
)
1456 self
.assertIn('fd8d:4d6d:3ccb:8d4d:bab:7280::/96 proto static metric 123 pref medium', output
)
1457 self
.assertIn('fd8d:4d6d:3ccb:900c:d437:ec27::/96 proto static metric 123 pref medium', output
)
1458 self
.assertIn('fd8d:4d6d:3ccb:9742:9931:5217::/96 proto static metric 123 pref medium', output
)
1459 self
.assertIn('fd8d:4d6d:3ccb:9c11:d820:2e96::/96 proto static metric 123 pref medium', output
)
1460 self
.assertIn('fd8d:4d6d:3ccb:a072:80da:de4f::/96 proto static metric 123 pref medium', output
)
1461 self
.assertIn('fd8d:4d6d:3ccb:a3f3:df38:19b0::/96 proto static metric 123 pref medium', output
)
1462 self
.assertIn('fd8d:4d6d:3ccb:a94b:cd6a:a32d::/96 proto static metric 123 pref medium', output
)
1463 self
.assertIn('fd8d:4d6d:3ccb:b39c:9cdc:755a::/96 proto static metric 123 pref medium', output
)
1464 self
.assertIn('fd8d:4d6d:3ccb:b684:4f81:2e3e::/96 proto static metric 123 pref medium', output
)
1465 self
.assertIn('fd8d:4d6d:3ccb:bad5:495d:8e9c::/96 proto static metric 123 pref medium', output
)
1466 self
.assertIn('fd8d:4d6d:3ccb:bfe5:c3c3:5d77::/96 proto static metric 123 pref medium', output
)
1467 self
.assertIn('fd8d:4d6d:3ccb:c624:6bf7:4c09::/96 proto static metric 123 pref medium', output
)
1468 self
.assertIn('fd8d:4d6d:3ccb:d4f9:5dc:9296::/96 proto static metric 123 pref medium', output
)
1469 self
.assertIn('fd8d:4d6d:3ccb:dcdd:d33b:90c9::/96 proto static metric 123 pref medium', output
)
1470 self
.assertIn('fd8d:4d6d:3ccb:e2e1:ae15:103f::/96 proto static metric 123 pref medium', output
)
1471 self
.assertIn('fd8d:4d6d:3ccb:f349:c4f0:10c1::/96 proto static metric 123 pref medium', output
)
1473 if shutil
.which('wg'):
1476 output
= check_output('wg show wg99 listen-port')
1477 self
.assertEqual(output
, '51820')
1478 output
= check_output('wg show wg99 fwmark')
1479 self
.assertEqual(output
, '0x4d2')
1480 output
= check_output('wg show wg99 private-key')
1481 self
.assertEqual(output
, 'EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=')
1482 output
= check_output('wg show wg99 allowed-ips')
1483 self
.assertIn('9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c=\t192.168.124.3/32', output
)
1484 self
.assertIn('TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10=\t192.168.124.2/32', output
)
1485 self
.assertIn('lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128', output
)
1486 self
.assertIn('RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48', output
)
1487 output
= check_output('wg show wg99 persistent-keepalive')
1488 self
.assertIn('9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c=\toff', output
)
1489 self
.assertIn('TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10=\toff', output
)
1490 self
.assertIn('lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\toff', output
)
1491 self
.assertIn('RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t20', output
)
1492 output
= check_output('wg show wg99 endpoints')
1493 self
.assertIn('9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c=\t(none)', output
)
1494 self
.assertIn('TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10=\t(none)', output
)
1495 self
.assertIn('lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\t(none)', output
)
1496 self
.assertIn('RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t192.168.27.3:51820', output
)
1497 output
= check_output('wg show wg99 preshared-keys')
1498 self
.assertIn('9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c=\t6Fsg8XN0DE6aPQgAX4r2oazEYJOGqyHUz3QRH/jCB+I=', output
)
1499 self
.assertIn('TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10=\tit7nd33chCT/tKT2ZZWfYyp43Zs+6oif72hexnSNMqA=', output
)
1500 self
.assertIn('lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tcPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=', output
)
1501 self
.assertIn('RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\tIIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=', output
)
1503 output
= check_output('wg show wg98 private-key')
1504 self
.assertEqual(output
, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr+WHtZLZ90FU=')
1506 output
= check_output('wg show wg97 listen-port')
1507 self
.assertEqual(output
, '51821')
1508 output
= check_output('wg show wg97 fwmark')
1509 self
.assertEqual(output
, '0x4d3')
1511 def test_geneve(self
):
1512 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
1515 self
.wait_online(['geneve99:degraded'])
1517 output
= check_output('ip -d link show geneve99')
1519 self
.assertRegex(output
, '192.168.22.1')
1520 self
.assertRegex(output
, '6082')
1521 self
.assertRegex(output
, 'udpcsum')
1522 self
.assertRegex(output
, 'udp6zerocsumrx')
1524 def test_ipip_tunnel(self
):
1525 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
1526 '25-ipip-tunnel.netdev', '25-tunnel.network',
1527 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1528 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1529 '25-ipip-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1531 self
.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'ipiptun96:routable', 'dummy98:degraded'])
1533 output
= check_output('ip -d link show ipiptun99')
1535 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98')
1536 output
= check_output('ip -d link show ipiptun98')
1538 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98')
1539 output
= check_output('ip -d link show ipiptun97')
1541 self
.assertRegex(output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98')
1542 output
= check_output('ip -d link show ipiptun96')
1544 self
.assertRegex(output
, 'ipip (ipip )?remote any local any dev dummy98')
1546 def test_gre_tunnel(self
):
1547 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
1548 '25-gre-tunnel.netdev', '25-tunnel.network',
1549 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1550 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1551 '25-gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1553 self
.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'gretun96:routable', 'dummy98:degraded'])
1555 output
= check_output('ip -d link show gretun99')
1557 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1558 self
.assertRegex(output
, 'ikey 1.2.3.103')
1559 self
.assertRegex(output
, 'okey 1.2.4.103')
1560 self
.assertRegex(output
, 'iseq')
1561 self
.assertRegex(output
, 'oseq')
1562 output
= check_output('ip -d link show gretun98')
1564 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
1565 self
.assertRegex(output
, 'ikey 0.0.0.104')
1566 self
.assertRegex(output
, 'okey 0.0.0.104')
1567 self
.assertNotRegex(output
, 'iseq')
1568 self
.assertNotRegex(output
, 'oseq')
1569 output
= check_output('ip -d link show gretun97')
1571 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
1572 self
.assertRegex(output
, 'ikey 0.0.0.105')
1573 self
.assertRegex(output
, 'okey 0.0.0.105')
1574 self
.assertNotRegex(output
, 'iseq')
1575 self
.assertNotRegex(output
, 'oseq')
1576 output
= check_output('ip -d link show gretun96')
1578 self
.assertRegex(output
, 'gre remote any local any dev dummy98')
1579 self
.assertRegex(output
, 'ikey 0.0.0.106')
1580 self
.assertRegex(output
, 'okey 0.0.0.106')
1581 self
.assertNotRegex(output
, 'iseq')
1582 self
.assertNotRegex(output
, 'oseq')
1584 def test_ip6gre_tunnel(self
):
1585 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
1586 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
1587 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1588 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1589 '25-ip6gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1592 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1594 self
.check_link_exists('dummy98')
1595 self
.check_link_exists('ip6gretun99')
1596 self
.check_link_exists('ip6gretun98')
1597 self
.check_link_exists('ip6gretun97')
1598 self
.check_link_exists('ip6gretun96')
1600 output
= check_output('ip -d link show ip6gretun99')
1602 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1603 output
= check_output('ip -d link show ip6gretun98')
1605 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
1606 output
= check_output('ip -d link show ip6gretun97')
1608 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
1609 output
= check_output('ip -d link show ip6gretun96')
1611 self
.assertRegex(output
, 'ip6gre remote any local any dev dummy98')
1613 def test_gretap_tunnel(self
):
1614 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
1615 '25-gretap-tunnel.netdev', '25-tunnel.network',
1616 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1618 self
.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
1620 output
= check_output('ip -d link show gretap99')
1622 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1623 self
.assertRegex(output
, 'ikey 0.0.0.106')
1624 self
.assertRegex(output
, 'okey 0.0.0.106')
1625 self
.assertRegex(output
, 'iseq')
1626 self
.assertRegex(output
, 'oseq')
1627 output
= check_output('ip -d link show gretap98')
1629 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
1630 self
.assertRegex(output
, 'ikey 0.0.0.107')
1631 self
.assertRegex(output
, 'okey 0.0.0.107')
1632 self
.assertRegex(output
, 'iseq')
1633 self
.assertRegex(output
, 'oseq')
1635 def test_ip6gretap_tunnel(self
):
1636 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
1637 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1638 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1640 self
.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
1642 output
= check_output('ip -d link show ip6gretap99')
1644 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1645 output
= check_output('ip -d link show ip6gretap98')
1647 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1649 def test_vti_tunnel(self
):
1650 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
1651 '25-vti-tunnel.netdev', '25-tunnel.network',
1652 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1653 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1654 '25-vti-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1656 self
.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'vtitun96:routable', 'dummy98:degraded'])
1658 output
= check_output('ip -d link show vtitun99')
1660 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1661 output
= check_output('ip -d link show vtitun98')
1663 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
1664 output
= check_output('ip -d link show vtitun97')
1666 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
1667 output
= check_output('ip -d link show vtitun96')
1669 self
.assertRegex(output
, 'vti remote any local any dev dummy98')
1671 def test_vti6_tunnel(self
):
1672 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
1673 '25-vti6-tunnel.netdev', '25-tunnel.network',
1674 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1675 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1677 self
.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
1679 output
= check_output('ip -d link show vti6tun99')
1681 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1682 output
= check_output('ip -d link show vti6tun98')
1684 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1685 output
= check_output('ip -d link show vti6tun97')
1687 self
.assertRegex(output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1689 def test_ip6tnl_tunnel(self
):
1690 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
1691 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1692 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1693 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1694 '25-veth.netdev', 'ip6tnl-slaac.network', 'ipv6-prefix.network',
1695 '25-ip6tnl-tunnel-local-slaac.netdev', '25-ip6tnl-tunnel-local-slaac.network')
1697 self
.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'ip6tnl-slaac:degraded',
1698 'dummy98:degraded', 'veth99:routable', 'veth-peer:degraded'])
1700 output
= check_output('ip -d link show ip6tnl99')
1702 self
.assertIn('ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98', output
)
1703 output
= check_output('ip -d link show ip6tnl98')
1705 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1706 output
= check_output('ip -d link show ip6tnl97')
1708 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1709 output
= check_output('ip -d link show ip6tnl-slaac')
1711 self
.assertIn('ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99', output
)
1713 output
= check_output('ip -6 address show veth99')
1715 self
.assertIn('inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic', output
)
1717 output
= check_output('ip -4 route show default')
1719 self
.assertIn('default dev ip6tnl-slaac proto static', output
)
1721 def test_sit_tunnel(self
):
1722 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1723 '25-sit-tunnel.netdev', '25-tunnel.network',
1724 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1725 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1726 '25-sit-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1728 self
.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'sittun96:routable', 'dummy98:degraded'])
1730 output
= check_output('ip -d link show sittun99')
1732 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1733 output
= check_output('ip -d link show sittun98')
1735 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98")
1736 output
= check_output('ip -d link show sittun97')
1738 self
.assertRegex(output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98")
1739 output
= check_output('ip -d link show sittun96')
1741 self
.assertRegex(output
, "sit (ip6ip )?remote any local any dev dummy98")
1743 def test_isatap_tunnel(self
):
1744 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1745 '25-isatap-tunnel.netdev', '25-tunnel.network')
1747 self
.wait_online(['isataptun99:routable', 'dummy98:degraded'])
1749 output
= check_output('ip -d link show isataptun99')
1751 self
.assertRegex(output
, "isatap ")
1753 def test_6rd_tunnel(self
):
1754 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1755 '25-6rd-tunnel.netdev', '25-tunnel.network')
1757 self
.wait_online(['sittun99:routable', 'dummy98:degraded'])
1759 output
= check_output('ip -d link show sittun99')
1761 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1763 @expectedFailureIfERSPANModuleIsNotAvailable()
1764 def test_erspan_tunnel(self
):
1765 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1766 '25-erspan-tunnel.netdev', '25-tunnel.network',
1767 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1769 self
.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1771 output
= check_output('ip -d link show erspan99')
1773 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1774 self
.assertRegex(output
, 'ikey 0.0.0.101')
1775 self
.assertRegex(output
, 'okey 0.0.0.101')
1776 self
.assertRegex(output
, 'iseq')
1777 self
.assertRegex(output
, 'oseq')
1778 output
= check_output('ip -d link show erspan98')
1780 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1781 self
.assertRegex(output
, '102')
1782 self
.assertRegex(output
, 'ikey 0.0.0.102')
1783 self
.assertRegex(output
, 'okey 0.0.0.102')
1784 self
.assertRegex(output
, 'iseq')
1785 self
.assertRegex(output
, 'oseq')
1787 def test_tunnel_independent(self
):
1788 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1791 self
.wait_online(['ipiptun99:carrier'])
1793 def test_tunnel_independent_loopback(self
):
1794 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent-loopback.netdev', 'netdev-link-local-addressing-yes.network')
1797 self
.wait_online(['ipiptun99:carrier'])
1799 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1800 def test_xfrm(self
):
1801 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'xfrm.network',
1802 '25-xfrm.netdev', '25-xfrm-independent.netdev',
1803 'netdev-link-local-addressing-yes.network')
1806 self
.wait_online(['dummy98:degraded', 'xfrm98:degraded', 'xfrm99:degraded'])
1808 output
= check_output('ip -d link show dev xfrm98')
1810 self
.assertIn('xfrm98@dummy98:', output
)
1811 self
.assertIn('xfrm if_id 0x98 ', output
)
1813 output
= check_output('ip -d link show dev xfrm99')
1815 self
.assertIn('xfrm99@lo:', output
)
1816 self
.assertIn('xfrm if_id 0x99 ', output
)
1818 @expectedFailureIfModuleIsNotAvailable('fou')
1820 # The following redundant check is necessary for CentOS CI.
1821 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1822 self
.assertTrue(is_module_available('fou'))
1824 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1825 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1826 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1829 self
.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'], setup_state
='unmanaged')
1831 output
= check_output('ip fou show')
1833 self
.assertRegex(output
, 'port 55555 ipproto 4')
1834 self
.assertRegex(output
, 'port 55556 ipproto 47')
1836 output
= check_output('ip -d link show ipiptun96')
1838 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1839 output
= check_output('ip -d link show sittun96')
1841 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1842 output
= check_output('ip -d link show gretun96')
1844 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1845 output
= check_output('ip -d link show gretap96')
1847 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1849 def test_vxlan(self
):
1850 copy_unit_to_networkd_unit_path('11-dummy.netdev', 'vxlan-test1.network',
1851 '25-vxlan.netdev', 'vxlan.network',
1852 '25-vxlan-ipv6.netdev', 'vxlan-ipv6.network',
1853 '25-vxlan-independent.netdev', 'netdev-link-local-addressing-yes.network',
1854 '25-veth.netdev', '25-vxlan-veth99.network', 'ipv6-prefix.network',
1855 '25-vxlan-local-slaac.netdev', '25-vxlan-local-slaac.network')
1858 self
.wait_online(['test1:degraded', 'veth99:routable', 'veth-peer:degraded',
1859 'vxlan99:degraded', 'vxlan98:degraded', 'vxlan97:degraded', 'vxlan-slaac:degraded'])
1861 output
= check_output('ip -d link show vxlan99')
1863 self
.assertIn('999', output
)
1864 self
.assertIn('5555', output
)
1865 self
.assertIn('l2miss', output
)
1866 self
.assertIn('l3miss', output
)
1867 self
.assertIn('udpcsum', output
)
1868 self
.assertIn('udp6zerocsumtx', output
)
1869 self
.assertIn('udp6zerocsumrx', output
)
1870 self
.assertIn('remcsumtx', output
)
1871 self
.assertIn('remcsumrx', output
)
1872 self
.assertIn('gbp', output
)
1874 output
= check_output('bridge fdb show dev vxlan99')
1876 self
.assertIn('00:11:22:33:44:55 dst 10.0.0.5 self permanent', output
)
1877 self
.assertIn('00:11:22:33:44:66 dst 10.0.0.6 self permanent', output
)
1878 self
.assertIn('00:11:22:33:44:77 dst 10.0.0.7 via test1 self permanent', output
)
1880 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'vxlan99', env
=env
)
1882 self
.assertIn('VNI: 999', output
)
1883 self
.assertIn('Destination Port: 5555', output
)
1884 self
.assertIn('Underlying Device: test1', output
)
1886 output
= check_output('bridge fdb show dev vxlan97')
1888 self
.assertIn('00:00:00:00:00:00 dst fe80::23b:d2ff:fe95:967f via test1 self permanent', output
)
1889 self
.assertIn('00:00:00:00:00:00 dst fe80::27c:16ff:fec0:6c74 via test1 self permanent', output
)
1890 self
.assertIn('00:00:00:00:00:00 dst fe80::2a2:e4ff:fef9:2269 via test1 self permanent', output
)
1892 output
= check_output('ip -d link show vxlan-slaac')
1894 self
.assertIn('vxlan id 4831584 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99', output
)
1896 output
= check_output('ip -6 address show veth99')
1898 self
.assertIn('inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic', output
)
1900 def test_macsec(self
):
1901 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1902 'macsec.network', '12-dummy.netdev')
1905 self
.wait_online(['dummy98:degraded', 'macsec99:routable'])
1907 output
= check_output('ip -d link show macsec99')
1909 self
.assertRegex(output
, 'macsec99@dummy98')
1910 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1911 self
.assertRegex(output
, 'encrypt on')
1913 output
= check_output('ip macsec show macsec99')
1915 self
.assertRegex(output
, 'encrypt on')
1916 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1917 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1918 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1919 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1920 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1921 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1922 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1923 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1924 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1925 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1926 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1928 def test_nlmon(self
):
1929 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1932 self
.wait_online(['nlmon99:carrier'])
1934 @expectedFailureIfModuleIsNotAvailable('ifb')
1936 copy_unit_to_networkd_unit_path('25-ifb.netdev', 'netdev-link-local-addressing-yes.network')
1939 self
.wait_online(['ifb99:degraded'])
1941 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1952 '25-l2tp-dummy.network',
1954 '25-l2tp-ip.netdev',
1955 '25-l2tp-udp.netdev']
1957 l2tp_tunnel_ids
= [ '10' ]
1960 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1961 remove_links(self
.links
)
1962 stop_networkd(show_logs
=False)
1965 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1966 remove_links(self
.links
)
1967 remove_unit_from_networkd_path(self
.units
)
1968 stop_networkd(show_logs
=True)
1970 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1971 def test_l2tp_udp(self
):
1972 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1973 '25-l2tp-udp.netdev', '25-l2tp.network')
1976 self
.wait_online(['test1:routable', 'l2tp-ses1:degraded', 'l2tp-ses2:degraded'])
1978 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1980 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1981 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1982 self
.assertRegex(output
, "Peer tunnel 11")
1983 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1984 self
.assertRegex(output
, "UDP checksum: enabled")
1986 output
= check_output('ip l2tp show session tid 10 session_id 15')
1988 self
.assertRegex(output
, "Session 15 in tunnel 10")
1989 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1990 self
.assertRegex(output
, "interface name: l2tp-ses1")
1992 output
= check_output('ip l2tp show session tid 10 session_id 17')
1994 self
.assertRegex(output
, "Session 17 in tunnel 10")
1995 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1996 self
.assertRegex(output
, "interface name: l2tp-ses2")
1998 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1999 def test_l2tp_ip(self
):
2000 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
2001 '25-l2tp-ip.netdev', '25-l2tp.network')
2004 self
.wait_online(['test1:routable', 'l2tp-ses3:degraded', 'l2tp-ses4:degraded'])
2006 output
= check_output('ip l2tp show tunnel tunnel_id 10')
2008 self
.assertRegex(output
, "Tunnel 10, encap IP")
2009 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
2010 self
.assertRegex(output
, "Peer tunnel 12")
2012 output
= check_output('ip l2tp show session tid 10 session_id 25')
2014 self
.assertRegex(output
, "Session 25 in tunnel 10")
2015 self
.assertRegex(output
, "Peer session 26, tunnel 12")
2016 self
.assertRegex(output
, "interface name: l2tp-ses3")
2018 output
= check_output('ip l2tp show session tid 10 session_id 27')
2020 self
.assertRegex(output
, "Session 27 in tunnel 10")
2021 self
.assertRegex(output
, "Peer session 28, tunnel 12")
2022 self
.assertRegex(output
, "interface name: l2tp-ses4")
2024 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
2041 '23-active-slave.network',
2042 '24-keep-configuration-static.network',
2043 '24-search-domain.network',
2044 '25-address-ipv4acd-veth99.network',
2045 '25-address-link-section.network',
2046 '25-address-peer-ipv4.network',
2047 '25-address-static.network',
2048 '25-activation-policy.network',
2049 '25-bind-carrier.network',
2050 '25-bond-active-backup-slave.netdev',
2051 '25-fibrule-invert.network',
2052 '25-fibrule-port-range.network',
2053 '25-fibrule-uidrange.network',
2054 '25-gre-tunnel-remote-any.netdev',
2055 '25-ip6gre-tunnel-remote-any.netdev',
2056 '25-ipv6-address-label-section.network',
2057 '25-ipv6-proxy-ndp.network',
2058 '25-link-local-addressing-no.network',
2059 '25-link-local-addressing-yes.network',
2060 '25-link-section-unmanaged.network',
2061 '25-neighbor-section.network',
2062 '25-neighbor-next.network',
2063 '25-neighbor-ipv6.network',
2064 '25-neighbor-ip-dummy.network',
2065 '25-neighbor-ip.network',
2066 '25-nexthop-dummy.network',
2067 '25-nexthop-nothing.network',
2068 '25-nexthop.network',
2069 '25-qdisc-cake.network',
2070 '25-qdisc-clsact-and-htb.network',
2071 '25-qdisc-drr.network',
2072 '25-qdisc-ets.network',
2073 '25-qdisc-fq_pie.network',
2074 '25-qdisc-hhf.network',
2075 '25-qdisc-ingress-netem-compat.network',
2076 '25-qdisc-pie.network',
2077 '25-qdisc-qfq.network',
2078 '25-prefix-route-with-vrf.network',
2079 '25-prefix-route-without-vrf.network',
2080 '25-route-ipv6-src.network',
2081 '25-route-static.network',
2082 '25-route-via-ipv6.network',
2083 '25-route-vrf.network',
2084 '25-gateway-static.network',
2085 '25-gateway-next-static.network',
2086 '25-sysctl-disable-ipv6.network',
2087 '25-sysctl.network',
2089 '25-veth-peer.network',
2093 '26-link-local-addressing-ipv6.network',
2094 'dhcp-client-ipv4-ipv6ra-prefix-client-with-delay.network',
2095 'dhcp-server-with-ipv6-prefix.network',
2096 'ipv6ra-prefix-client-with-static-ipv4-address.network',
2097 'ipv6-prefix-with-delay.network',
2098 'routing-policy-rule-dummy98.network',
2099 'routing-policy-rule-test1.network',
2100 'routing-policy-rule-reconfigure1.network',
2101 'routing-policy-rule-reconfigure2.network',
2104 networkd_conf_dropins
= [
2105 'networkd-manage-foreign-routes-no.conf',
2108 routing_policy_rule_tables
= ['7', '8', '9', '10', '1011']
2109 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
2112 remove_blackhole_nexthops()
2113 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2114 remove_routes(self
.routes
)
2115 remove_links(self
.links
)
2116 stop_networkd(show_logs
=False)
2117 call('ip netns del ns99', stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
2120 remove_blackhole_nexthops()
2121 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2122 remove_routes(self
.routes
)
2123 remove_links(self
.links
)
2124 remove_unit_from_networkd_path(self
.units
)
2125 remove_networkd_conf_dropin(self
.networkd_conf_dropins
)
2126 stop_networkd(show_logs
=True)
2127 call('ip netns del ns99', stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
2129 def test_address_static(self
):
2130 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
2133 self
.wait_online(['dummy98:routable'])
2135 output
= check_output('ip -4 address show dev dummy98')
2137 self
.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output
)
2138 self
.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output
)
2139 self
.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output
)
2140 self
.assertIn('inet 10.7.8.9/16 brd 10.7.255.255 scope link deprecated dummy98', output
)
2141 self
.assertIn('inet 10.8.8.1/16 scope global dummy98', output
)
2142 self
.assertIn('inet 10.8.8.2/16 brd 10.8.8.128 scope global secondary dummy98', output
)
2143 self
.assertRegex(output
, 'inet 10.9.0.1/16 (metric 128 |)brd 10.9.255.255 scope global dummy98')
2145 # test for ENOBUFS issue #17012
2146 for i
in range(1,254):
2147 self
.assertIn(f
'inet 10.3.3.{i}/16 brd 10.3.255.255', output
)
2150 self
.assertNotIn('10.10.0.1/16', output
)
2151 self
.assertNotIn('10.10.0.2/16', output
)
2153 output
= check_output('ip -4 address show dev dummy98 label 32')
2154 self
.assertIn('inet 10.3.2.3/16 brd 10.3.255.255 scope global 32', output
)
2156 output
= check_output('ip -4 address show dev dummy98 label 33')
2157 self
.assertIn('inet 10.4.2.3 peer 10.4.2.4/16 scope global 33', output
)
2159 output
= check_output('ip -4 address show dev dummy98 label 34')
2160 self
.assertRegex(output
, r
'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
2162 output
= check_output('ip -4 address show dev dummy98 label 35')
2163 self
.assertRegex(output
, r
'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
2165 output
= check_output('ip -4 route show dev dummy98')
2167 self
.assertIn('10.9.0.0/16 proto kernel scope link src 10.9.0.1 metric 128', output
)
2169 output
= check_output('ip -6 address show dev dummy98')
2171 self
.assertIn('inet6 2001:db8:0:f101::15/64 scope global', output
)
2172 self
.assertIn('inet6 2001:db8:0:f101::16/64 scope global', output
)
2173 self
.assertIn('inet6 2001:db8:0:f102::15/64 scope global', output
)
2174 self
.assertIn('inet6 2001:db8:0:f102::16/64 scope global', output
)
2175 self
.assertIn('inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global', output
)
2176 self
.assertIn('inet6 2001:db8:1:f101::1/64 scope global deprecated', output
)
2177 self
.assertRegex(output
, r
'inet6 fd[0-9a-f:]*1/64 scope global')
2180 # 1. set preferred lifetime forever to drop the deprecated flag for testing #20891.
2181 self
.assertEqual(call('ip address change 10.7.8.9/16 dev dummy98 preferred_lft forever'), 0)
2182 self
.assertEqual(call('ip address change 2001:db8:1:f101::1/64 dev dummy98 preferred_lft forever'), 0)
2183 output
= check_output('ip -4 address show dev dummy98')
2185 self
.assertNotIn('deprecated', output
)
2186 output
= check_output('ip -6 address show dev dummy98')
2188 self
.assertNotIn('deprecated', output
)
2190 # 2. reconfigure the interface.
2191 check_output(*networkctl_cmd
, 'reconfigure', 'dummy98', env
=env
)
2192 self
.wait_online(['dummy98:routable'])
2194 # 3. check the deprecated flag is set for the address configured with PreferredLifetime=0
2195 output
= check_output('ip -4 address show dev dummy98')
2197 self
.assertIn('inet 10.7.8.9/16 brd 10.7.255.255 scope link deprecated dummy98', output
)
2198 output
= check_output('ip -6 address show dev dummy98')
2200 self
.assertIn('inet6 2001:db8:1:f101::1/64 scope global deprecated', output
)
2202 # test for ENOBUFS issue #17012
2203 output
= check_output('ip -4 address show dev dummy98')
2204 for i
in range(1,254):
2205 self
.assertIn(f
'inet 10.3.3.{i}/16 brd 10.3.255.255', output
)
2207 # TODO: check json string
2208 check_output(*networkctl_cmd
, '--json=short', 'status', env
=env
)
2210 def test_address_ipv4acd(self
):
2211 check_output('ip netns add ns99')
2212 check_output('ip link add veth99 type veth peer veth-peer')
2213 check_output('ip link set veth-peer netns ns99')
2214 check_output('ip link set veth99 up')
2215 check_output('ip netns exec ns99 ip link set veth-peer up')
2216 check_output('ip netns exec ns99 ip address add 192.168.100.10/24 dev veth-peer')
2218 copy_unit_to_networkd_unit_path('25-address-ipv4acd-veth99.network', dropins
=False)
2220 self
.wait_online(['veth99:routable'])
2222 output
= check_output('ip -4 address show dev veth99')
2224 self
.assertNotIn('192.168.100.10/24', output
)
2225 self
.assertIn('192.168.100.11/24', output
)
2227 copy_unit_to_networkd_unit_path('25-address-ipv4acd-veth99.network.d/conflict-address.conf')
2228 run(*networkctl_cmd
, 'reload', env
=env
)
2230 rc
= call(*wait_online_cmd
, '--timeout=10s', '--interface=veth99:routable', env
=env
)
2231 self
.assertTrue(rc
== 1)
2233 output
= check_output('ip -4 address show dev veth99')
2235 self
.assertNotIn('192.168.100.10/24', output
)
2236 self
.assertIn('192.168.100.11/24', output
)
2238 def test_address_peer_ipv4(self
):
2239 # test for issue #17304
2240 copy_unit_to_networkd_unit_path('25-address-peer-ipv4.network', '12-dummy.netdev')
2242 for trial
in range(2):
2248 self
.wait_online(['dummy98:routable'])
2250 output
= check_output('ip -4 address show dev dummy98')
2251 self
.assertIn('inet 100.64.0.1 peer 100.64.0.2/32 scope global', output
)
2253 @expectedFailureIfModuleIsNotAvailable('vrf')
2254 def test_prefix_route(self
):
2255 copy_unit_to_networkd_unit_path('25-prefix-route-with-vrf.network', '12-dummy.netdev',
2256 '25-prefix-route-without-vrf.network', '11-dummy.netdev',
2257 '25-vrf.netdev', '25-vrf.network')
2258 for trial
in range(2):
2264 self
.wait_online(['dummy98:routable', 'test1:routable', 'vrf99:carrier'])
2266 output
= check_output('ip route show table 42 dev dummy98')
2267 print('### ip route show table 42 dev dummy98')
2269 self
.assertRegex(output
, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1')
2270 self
.assertRegex(output
, '10.20.33.0/24 proto kernel scope link src 10.20.33.1')
2271 self
.assertRegex(output
, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1')
2272 self
.assertRegex(output
, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1')
2273 self
.assertRegex(output
, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1')
2274 self
.assertRegex(output
, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1')
2275 self
.assertRegex(output
, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1')
2276 output
= check_output('ip -6 route show table 42 dev dummy98')
2277 print('### ip -6 route show table 42 dev dummy98')
2281 self
.assertRegex(output
, 'local fdde:11:22::1 proto kernel metric 0 pref medium')
2282 #self.assertRegex(output, 'fdde:11:22::1 proto kernel metric 256 pref medium')
2283 self
.assertRegex(output
, 'local fdde:11:33::1 proto kernel metric 0 pref medium')
2284 self
.assertRegex(output
, 'fdde:11:33::/64 proto kernel metric 256 pref medium')
2285 self
.assertRegex(output
, 'local fdde:11:44::1 proto kernel metric 0 pref medium')
2286 self
.assertRegex(output
, 'local fdde:11:55::1 proto kernel metric 0 pref medium')
2287 self
.assertRegex(output
, 'fe80::/64 proto kernel metric 256 pref medium')
2288 self
.assertRegex(output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium')
2292 output
= check_output('ip route show dev test1')
2293 print('### ip route show dev test1')
2295 self
.assertRegex(output
, '10.21.33.0/24 proto kernel scope link src 10.21.33.1')
2296 output
= check_output('ip route show table local dev test1')
2297 print('### ip route show table local dev test1')
2299 self
.assertRegex(output
, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1')
2300 self
.assertRegex(output
, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1')
2301 self
.assertRegex(output
, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1')
2302 self
.assertRegex(output
, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1')
2303 self
.assertRegex(output
, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1')
2304 self
.assertRegex(output
, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1')
2305 output
= check_output('ip -6 route show dev test1')
2306 print('### ip -6 route show dev test1')
2308 self
.assertRegex(output
, 'fdde:12:22::1 proto kernel metric 256 pref medium')
2309 self
.assertRegex(output
, 'fdde:12:33::/64 proto kernel metric 256 pref medium')
2310 self
.assertRegex(output
, 'fe80::/64 proto kernel metric 256 pref medium')
2311 output
= check_output('ip -6 route show table local dev test1')
2312 print('### ip -6 route show table local dev test1')
2314 self
.assertRegex(output
, 'local fdde:12:22::1 proto kernel metric 0 pref medium')
2315 self
.assertRegex(output
, 'local fdde:12:33::1 proto kernel metric 0 pref medium')
2316 self
.assertRegex(output
, 'local fdde:12:44::1 proto kernel metric 0 pref medium')
2317 self
.assertRegex(output
, 'local fdde:12:55::1 proto kernel metric 0 pref medium')
2318 self
.assertRegex(output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium')
2320 def test_configure_without_carrier(self
):
2321 copy_unit_to_networkd_unit_path('11-dummy.netdev')
2323 self
.wait_operstate('test1', 'off', '')
2324 check_output('ip link set dev test1 up carrier off')
2326 copy_unit_to_networkd_unit_path('25-test1.network.d/configure-without-carrier.conf', dropins
=False)
2328 self
.wait_online(['test1:no-carrier'])
2330 carrier_map
= {'on': '1', 'off': '0'}
2331 routable_map
= {'on': 'routable', 'off': 'no-carrier'}
2332 for carrier
in ['off', 'on', 'off']:
2333 with self
.subTest(carrier
=carrier
):
2334 if carrier_map
[carrier
] != read_link_attr('test1', 'carrier'):
2335 check_output(f
'ip link set dev test1 carrier {carrier}')
2336 self
.wait_online([f
'test1:{routable_map[carrier]}:{routable_map[carrier]}'])
2338 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
2340 self
.assertRegex(output
, '192.168.0.15')
2341 self
.assertRegex(output
, '192.168.0.1')
2342 self
.assertRegex(output
, routable_map
[carrier
])
2344 def test_configure_without_carrier_yes_ignore_carrier_loss_no(self
):
2345 copy_unit_to_networkd_unit_path('11-dummy.netdev')
2347 self
.wait_operstate('test1', 'off', '')
2348 check_output('ip link set dev test1 up carrier off')
2350 copy_unit_to_networkd_unit_path('25-test1.network')
2352 self
.wait_online(['test1:no-carrier'])
2354 carrier_map
= {'on': '1', 'off': '0'}
2355 routable_map
= {'on': 'routable', 'off': 'no-carrier'}
2356 for (carrier
, have_config
) in [('off', True), ('on', True), ('off', False)]:
2357 with self
.subTest(carrier
=carrier
, have_config
=have_config
):
2358 if carrier_map
[carrier
] != read_link_attr('test1', 'carrier'):
2359 check_output(f
'ip link set dev test1 carrier {carrier}')
2360 self
.wait_online([f
'test1:{routable_map[carrier]}:{routable_map[carrier]}'])
2362 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
2365 self
.assertRegex(output
, '192.168.0.15')
2366 self
.assertRegex(output
, '192.168.0.1')
2368 self
.assertNotRegex(output
, '192.168.0.15')
2369 self
.assertNotRegex(output
, '192.168.0.1')
2370 self
.assertRegex(output
, routable_map
[carrier
])
2372 def test_routing_policy_rule(self
):
2373 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
2375 self
.wait_online(['test1:degraded'])
2377 output
= check_output('ip rule list iif test1 priority 111')
2379 self
.assertRegex(output
, '111:')
2380 self
.assertRegex(output
, 'from 192.168.100.18')
2381 self
.assertRegex(output
, r
'tos (0x08|throughput)\s')
2382 self
.assertRegex(output
, 'iif test1')
2383 self
.assertRegex(output
, 'oif test1')
2384 self
.assertRegex(output
, 'lookup 7')
2386 output
= check_output('ip rule list iif test1 priority 101')
2388 self
.assertRegex(output
, '101:')
2389 self
.assertRegex(output
, 'from all')
2390 self
.assertRegex(output
, 'iif test1')
2391 self
.assertRegex(output
, 'lookup 9')
2393 output
= check_output('ip -6 rule list iif test1 priority 100')
2395 self
.assertRegex(output
, '100:')
2396 self
.assertRegex(output
, 'from all')
2397 self
.assertRegex(output
, 'iif test1')
2398 self
.assertRegex(output
, 'lookup 8')
2400 output
= check_output('ip rule list iif test1 priority 102')
2402 self
.assertRegex(output
, '102:')
2403 self
.assertRegex(output
, 'from 0.0.0.0/8')
2404 self
.assertRegex(output
, 'iif test1')
2405 self
.assertRegex(output
, 'lookup 10')
2407 # TODO: check json string
2408 check_output(*networkctl_cmd
, '--json=short', 'status', env
=env
)
2410 def test_routing_policy_rule_issue_11280(self
):
2411 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
2412 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
2415 # Remove state files only first time
2417 self
.wait_online(['test1:degraded', 'dummy98:degraded'])
2420 output
= check_output('ip rule list table 7')
2422 self
.assertRegex(output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
2424 output
= check_output('ip rule list table 8')
2426 self
.assertRegex(output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
2428 stop_networkd(remove_state_files
=False)
2430 def test_routing_policy_rule_reconfigure(self
):
2431 copy_unit_to_networkd_unit_path('routing-policy-rule-reconfigure2.network', '11-dummy.netdev')
2433 self
.wait_online(['test1:degraded'])
2435 output
= check_output('ip rule list table 1011')
2437 self
.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output
)
2438 self
.assertIn('10112: from all oif test1 lookup 1011', output
)
2439 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2440 self
.assertIn('10114: from 192.168.8.254 lookup 1011', output
)
2442 output
= check_output('ip -6 rule list table 1011')
2444 self
.assertIn('10112: from all oif test1 lookup 1011', output
)
2446 copy_unit_to_networkd_unit_path('routing-policy-rule-reconfigure1.network', '11-dummy.netdev')
2447 run(*networkctl_cmd
, 'reload', env
=env
)
2449 self
.wait_online(['test1:degraded'])
2451 output
= check_output('ip rule list table 1011')
2453 self
.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output
)
2454 self
.assertIn('10112: from all oif test1 lookup 1011', output
)
2455 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2456 self
.assertIn('10114: from 192.168.8.254 lookup 1011', output
)
2458 output
= check_output('ip -6 rule list table 1011')
2460 self
.assertNotIn('10112: from all oif test1 lookup 1011', output
)
2461 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2463 run('ip rule delete priority 10111')
2464 run('ip rule delete priority 10112')
2465 run('ip rule delete priority 10113')
2466 run('ip rule delete priority 10114')
2467 run('ip -6 rule delete priority 10113')
2469 output
= check_output('ip rule list table 1011')
2471 self
.assertEqual(output
, '')
2473 output
= check_output('ip -6 rule list table 1011')
2475 self
.assertEqual(output
, '')
2477 run(*networkctl_cmd
, 'reconfigure', 'test1', env
=env
)
2478 self
.wait_online(['test1:degraded'])
2480 output
= check_output('ip rule list table 1011')
2482 self
.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output
)
2483 self
.assertIn('10112: from all oif test1 lookup 1011', output
)
2484 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2485 self
.assertIn('10114: from 192.168.8.254 lookup 1011', output
)
2487 output
= check_output('ip -6 rule list table 1011')
2489 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2491 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
2492 def test_routing_policy_rule_port_range(self
):
2493 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
2495 self
.wait_online(['test1:degraded'])
2497 output
= check_output('ip rule')
2499 self
.assertRegex(output
, '111')
2500 self
.assertRegex(output
, 'from 192.168.100.18')
2501 self
.assertRegex(output
, '1123-1150')
2502 self
.assertRegex(output
, '3224-3290')
2503 self
.assertRegex(output
, 'tcp')
2504 self
.assertRegex(output
, 'lookup 7')
2506 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
2507 def test_routing_policy_rule_invert(self
):
2508 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
2510 self
.wait_online(['test1:degraded'])
2512 output
= check_output('ip rule')
2514 self
.assertRegex(output
, '111')
2515 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
2516 self
.assertRegex(output
, 'tcp')
2517 self
.assertRegex(output
, 'lookup 7')
2519 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable()
2520 def test_routing_policy_rule_uidrange(self
):
2521 copy_unit_to_networkd_unit_path('25-fibrule-uidrange.network', '11-dummy.netdev')
2523 self
.wait_online(['test1:degraded'])
2525 output
= check_output('ip rule')
2527 self
.assertRegex(output
, '111')
2528 self
.assertRegex(output
, 'from 192.168.100.18')
2529 self
.assertRegex(output
, 'lookup 7')
2530 self
.assertRegex(output
, 'uidrange 100-200')
2532 def _test_route_static(self
, manage_foreign_routes
):
2533 if not manage_foreign_routes
:
2534 copy_networkd_conf_dropin('networkd-manage-foreign-routes-no.conf')
2536 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
2538 self
.wait_online(['dummy98:routable'])
2540 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2543 print('### ip -6 route show dev dummy98')
2544 output
= check_output('ip -6 route show dev dummy98')
2546 self
.assertIn('2001:1234:5:8fff:ff:ff:ff:ff proto static', output
)
2547 self
.assertIn('2001:1234:5:8f63::1 proto kernel', output
)
2548 self
.assertIn('2001:1234:5:afff:ff:ff:ff:ff via fe80:0:222:4dff:ff:ff:ff:ff proto static', output
)
2550 print('### ip -6 route show default')
2551 output
= check_output('ip -6 route show default')
2553 self
.assertIn('default', output
)
2554 self
.assertIn('via 2001:1234:5:8fff:ff:ff:ff:ff', output
)
2556 print('### ip -4 route show dev dummy98')
2557 output
= check_output('ip -4 route show dev dummy98')
2559 self
.assertIn('149.10.124.48/28 proto kernel scope link src 149.10.124.58', output
)
2560 self
.assertIn('149.10.124.64 proto static scope link', output
)
2561 self
.assertIn('169.254.0.0/16 proto static scope link metric 2048', output
)
2562 self
.assertIn('192.168.1.1 proto static scope link initcwnd 20', output
)
2563 self
.assertIn('192.168.1.2 proto static scope link initrwnd 30', output
)
2564 self
.assertIn('192.168.1.3 proto static scope link advmss 30', output
)
2565 self
.assertIn('multicast 149.10.123.4 proto static', output
)
2567 print('### ip -4 route show dev dummy98 default')
2568 output
= check_output('ip -4 route show dev dummy98 default')
2570 self
.assertIn('default via 149.10.125.65 proto static onlink', output
)
2571 self
.assertIn('default via 149.10.124.64 proto static', output
)
2572 self
.assertIn('default proto static', output
)
2574 print('### ip -4 route show table local dev dummy98')
2575 output
= check_output('ip -4 route show table local dev dummy98')
2577 self
.assertIn('local 149.10.123.1 proto static scope host', output
)
2578 self
.assertIn('anycast 149.10.123.2 proto static scope link', output
)
2579 self
.assertIn('broadcast 149.10.123.3 proto static scope link', output
)
2581 print('### ip route show type blackhole')
2582 output
= check_output('ip route show type blackhole')
2584 self
.assertIn('blackhole 202.54.1.2 proto static', output
)
2586 print('### ip route show type unreachable')
2587 output
= check_output('ip route show type unreachable')
2589 self
.assertIn('unreachable 202.54.1.3 proto static', output
)
2591 print('### ip route show type prohibit')
2592 output
= check_output('ip route show type prohibit')
2594 self
.assertIn('prohibit 202.54.1.4 proto static', output
)
2596 print('### ip -6 route show type blackhole')
2597 output
= check_output('ip -6 route show type blackhole')
2599 self
.assertIn('blackhole 2001:1234:5678::2 dev lo proto static', output
)
2601 print('### ip -6 route show type unreachable')
2602 output
= check_output('ip -6 route show type unreachable')
2604 self
.assertIn('unreachable 2001:1234:5678::3 dev lo proto static', output
)
2606 print('### ip -6 route show type prohibit')
2607 output
= check_output('ip -6 route show type prohibit')
2609 self
.assertIn('prohibit 2001:1234:5678::4 dev lo proto static', output
)
2611 print('### ip route show 192.168.10.1')
2612 output
= check_output('ip route show 192.168.10.1')
2614 self
.assertIn('192.168.10.1 proto static', output
)
2615 self
.assertIn('nexthop via 149.10.124.59 dev dummy98 weight 10', output
)
2616 self
.assertIn('nexthop via 149.10.124.60 dev dummy98 weight 5', output
)
2618 print('### ip route show 192.168.10.2')
2619 output
= check_output('ip route show 192.168.10.2')
2621 # old ip command does not show IPv6 gateways...
2622 self
.assertIn('192.168.10.2 proto static', output
)
2623 self
.assertIn('nexthop', output
)
2624 self
.assertIn('dev dummy98 weight 10', output
)
2625 self
.assertIn('dev dummy98 weight 5', output
)
2627 print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2628 output
= check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2630 # old ip command does not show 'nexthop' keyword and weight...
2631 self
.assertIn('2001:1234:5:7fff:ff:ff:ff:ff', output
)
2632 self
.assertIn('via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98', output
)
2633 self
.assertIn('via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98', output
)
2635 # TODO: check json string
2636 check_output(*networkctl_cmd
, '--json=short', 'status', env
=env
)
2638 copy_unit_to_networkd_unit_path('25-address-static.network')
2639 check_output(*networkctl_cmd
, 'reload', env
=env
)
2641 self
.wait_online(['dummy98:routable'])
2643 # check all routes managed by Manager are removed
2644 print('### ip route show type blackhole')
2645 output
= check_output('ip route show type blackhole')
2647 self
.assertEqual(output
, '')
2649 print('### ip route show type unreachable')
2650 output
= check_output('ip route show type unreachable')
2652 self
.assertEqual(output
, '')
2654 print('### ip route show type prohibit')
2655 output
= check_output('ip route show type prohibit')
2657 self
.assertEqual(output
, '')
2659 print('### ip -6 route show type blackhole')
2660 output
= check_output('ip -6 route show type blackhole')
2662 self
.assertEqual(output
, '')
2664 print('### ip -6 route show type unreachable')
2665 output
= check_output('ip -6 route show type unreachable')
2667 self
.assertEqual(output
, '')
2669 print('### ip -6 route show type prohibit')
2670 output
= check_output('ip -6 route show type prohibit')
2672 self
.assertEqual(output
, '')
2674 remove_unit_from_networkd_path(['25-address-static.network'])
2675 check_output(*networkctl_cmd
, 'reload', env
=env
)
2677 self
.wait_online(['dummy98:routable'])
2679 # check all routes managed by Manager are reconfigured
2680 print('### ip route show type blackhole')
2681 output
= check_output('ip route show type blackhole')
2683 self
.assertIn('blackhole 202.54.1.2 proto static', output
)
2685 print('### ip route show type unreachable')
2686 output
= check_output('ip route show type unreachable')
2688 self
.assertIn('unreachable 202.54.1.3 proto static', output
)
2690 print('### ip route show type prohibit')
2691 output
= check_output('ip route show type prohibit')
2693 self
.assertIn('prohibit 202.54.1.4 proto static', output
)
2695 print('### ip -6 route show type blackhole')
2696 output
= check_output('ip -6 route show type blackhole')
2698 self
.assertIn('blackhole 2001:1234:5678::2 dev lo proto static', output
)
2700 print('### ip -6 route show type unreachable')
2701 output
= check_output('ip -6 route show type unreachable')
2703 self
.assertIn('unreachable 2001:1234:5678::3 dev lo proto static', output
)
2705 print('### ip -6 route show type prohibit')
2706 output
= check_output('ip -6 route show type prohibit')
2708 self
.assertIn('prohibit 2001:1234:5678::4 dev lo proto static', output
)
2710 rc
= call("ip link del dummy98")
2711 self
.assertEqual(rc
, 0)
2714 # check all routes managed by Manager are removed
2715 print('### ip route show type blackhole')
2716 output
= check_output('ip route show type blackhole')
2718 self
.assertEqual(output
, '')
2720 print('### ip route show type unreachable')
2721 output
= check_output('ip route show type unreachable')
2723 self
.assertEqual(output
, '')
2725 print('### ip route show type prohibit')
2726 output
= check_output('ip route show type prohibit')
2728 self
.assertEqual(output
, '')
2730 print('### ip -6 route show type blackhole')
2731 output
= check_output('ip -6 route show type blackhole')
2733 self
.assertEqual(output
, '')
2735 print('### ip -6 route show type unreachable')
2736 output
= check_output('ip -6 route show type unreachable')
2738 self
.assertEqual(output
, '')
2740 print('### ip -6 route show type prohibit')
2741 output
= check_output('ip -6 route show type prohibit')
2743 self
.assertEqual(output
, '')
2747 def test_route_static(self
):
2748 for manage_foreign_routes
in [True, False]:
2749 with self
.subTest(manage_foreign_routes
=manage_foreign_routes
):
2750 self
._test
_route
_static
(manage_foreign_routes
)
2752 @expectedFailureIfRTA_VIAIsNotSupported()
2753 def test_route_via_ipv6(self
):
2754 copy_unit_to_networkd_unit_path('25-route-via-ipv6.network', '12-dummy.netdev')
2756 self
.wait_online(['dummy98:routable'])
2758 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2761 print('### ip -6 route show dev dummy98')
2762 output
= check_output('ip -6 route show dev dummy98')
2764 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
2765 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
2767 print('### ip -4 route show dev dummy98')
2768 output
= check_output('ip -4 route show dev dummy98')
2770 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
2771 self
.assertRegex(output
, '149.10.124.66 via inet6 2001:1234:5:8fff:ff:ff:ff:ff proto static')
2773 @expectedFailureIfModuleIsNotAvailable('vrf')
2774 def test_route_vrf(self
):
2775 copy_unit_to_networkd_unit_path('25-route-vrf.network', '12-dummy.netdev',
2776 '25-vrf.netdev', '25-vrf.network')
2778 self
.wait_online(['dummy98:routable', 'vrf99:carrier'])
2780 output
= check_output('ip route show vrf vrf99')
2782 self
.assertRegex(output
, 'default via 192.168.100.1')
2784 output
= check_output('ip route show')
2786 self
.assertNotRegex(output
, 'default via 192.168.100.1')
2788 def test_gateway_reconfigure(self
):
2789 copy_unit_to_networkd_unit_path('25-gateway-static.network', '12-dummy.netdev')
2791 self
.wait_online(['dummy98:routable'])
2792 print('### ip -4 route show dev dummy98 default')
2793 output
= check_output('ip -4 route show dev dummy98 default')
2795 self
.assertRegex(output
, 'default via 149.10.124.59 proto static')
2796 self
.assertNotRegex(output
, '149.10.124.60')
2798 remove_unit_from_networkd_path(['25-gateway-static.network'])
2799 copy_unit_to_networkd_unit_path('25-gateway-next-static.network')
2801 self
.wait_online(['dummy98:routable'])
2802 print('### ip -4 route show dev dummy98 default')
2803 output
= check_output('ip -4 route show dev dummy98 default')
2805 self
.assertNotRegex(output
, '149.10.124.59')
2806 self
.assertRegex(output
, 'default via 149.10.124.60 proto static')
2808 def test_ip_route_ipv6_src_route(self
):
2809 # a dummy device does not make the addresses go through tentative state, so we
2810 # reuse a bond from an earlier test, which does make the addresses go through
2811 # tentative state, and do our test on that
2812 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2814 self
.wait_online(['dummy98:enslaved', 'bond199:routable'])
2816 output
= check_output('ip -6 route list dev bond199')
2818 self
.assertRegex(output
, 'abcd::/16')
2819 self
.assertRegex(output
, 'src')
2820 self
.assertRegex(output
, '2001:1234:56:8f63::2')
2822 def test_ip_link_mac_address(self
):
2823 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
2825 self
.wait_online(['dummy98:degraded'])
2827 output
= check_output('ip link show dummy98')
2829 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
2831 def test_ip_link_unmanaged(self
):
2832 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
2835 self
.check_link_exists('dummy98')
2837 self
.wait_operstate('dummy98', 'off', setup_state
='unmanaged')
2839 def test_ipv6_address_label(self
):
2840 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
2842 self
.wait_online(['dummy98:degraded'])
2844 output
= check_output('ip addrlabel list')
2846 self
.assertRegex(output
, '2004:da8:1::/64')
2848 def test_ipv6_proxy_ndp(self
):
2849 copy_unit_to_networkd_unit_path('25-ipv6-proxy-ndp.network', '12-dummy.netdev')
2852 self
.wait_online(['dummy98:routable'])
2854 output
= check_output('ip neighbor show proxy dev dummy98')
2856 for i
in range(1,5):
2857 self
.assertRegex(output
, f
'2607:5300:203:5215:{i}::1 *proxy')
2859 def test_neighbor_section(self
):
2860 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2862 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2864 print('### ip neigh list dev dummy98')
2865 output
= check_output('ip neigh list dev dummy98')
2867 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2868 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2870 # TODO: check json string
2871 check_output(*networkctl_cmd
, '--json=short', 'status', env
=env
)
2873 def test_neighbor_reconfigure(self
):
2874 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2876 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2878 print('### ip neigh list dev dummy98')
2879 output
= check_output('ip neigh list dev dummy98')
2881 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2882 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2884 remove_unit_from_networkd_path(['25-neighbor-section.network'])
2885 copy_unit_to_networkd_unit_path('25-neighbor-next.network')
2887 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2888 print('### ip neigh list dev dummy98')
2889 output
= check_output('ip neigh list dev dummy98')
2891 self
.assertNotRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2892 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT')
2893 self
.assertNotRegex(output
, '2004:da8:1::1.*PERMANENT')
2895 def test_neighbor_gre(self
):
2896 copy_unit_to_networkd_unit_path('25-neighbor-ip.network', '25-neighbor-ipv6.network', '25-neighbor-ip-dummy.network',
2897 '12-dummy.netdev', '25-gre-tunnel-remote-any.netdev', '25-ip6gre-tunnel-remote-any.netdev')
2899 self
.wait_online(['dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable'], timeout
='40s')
2901 output
= check_output('ip neigh list dev gretun97')
2903 self
.assertRegex(output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT')
2905 output
= check_output('ip neigh list dev ip6gretun97')
2907 self
.assertRegex(output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
2909 # TODO: check json string
2910 check_output(*networkctl_cmd
, '--json=short', 'status', env
=env
)
2912 def test_link_local_addressing(self
):
2913 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
2914 '25-link-local-addressing-no.network', '12-dummy.netdev')
2916 self
.wait_online(['test1:degraded', 'dummy98:carrier'])
2918 output
= check_output('ip address show dev test1')
2920 self
.assertRegex(output
, 'inet .* scope link')
2921 self
.assertRegex(output
, 'inet6 .* scope link')
2923 output
= check_output('ip address show dev dummy98')
2925 self
.assertNotRegex(output
, 'inet6* .* scope link')
2927 # Documentation/networking/ip-sysctl.txt
2929 # addr_gen_mode - INTEGER
2930 # Defines how link-local and autoconf addresses are generated.
2932 # 0: generate address based on EUI64 (default)
2933 # 1: do no generate a link-local address, use EUI64 for addresses generated
2935 # 2: generate stable privacy addresses, using the secret from
2936 # stable_secret (RFC7217)
2937 # 3: generate stable privacy addresses, using a random secret if unset
2939 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'stable_secret'), '0123:4567:89ab:cdef:0123:4567:89ab:cdef')
2940 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), '2')
2941 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
2943 def test_link_local_addressing_remove_ipv6ll(self
):
2944 copy_unit_to_networkd_unit_path('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
2946 self
.wait_online(['dummy98:degraded'])
2948 output
= check_output('ip address show dev dummy98')
2950 self
.assertRegex(output
, 'inet6 .* scope link')
2952 copy_unit_to_networkd_unit_path('25-link-local-addressing-no.network')
2954 self
.wait_online(['dummy98:carrier'])
2956 output
= check_output('ip address show dev dummy98')
2958 self
.assertNotRegex(output
, 'inet6* .* scope link')
2960 def test_sysctl(self
):
2961 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
2963 self
.wait_online(['dummy98:degraded'])
2965 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
2966 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
2967 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
2968 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
2969 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
2970 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
2971 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
2972 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'accept_local'), '1')
2974 def test_sysctl_disable_ipv6(self
):
2975 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
2977 print('## Disable ipv6')
2978 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
2979 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
2982 self
.wait_online(['dummy98:routable'])
2984 output
= check_output('ip -4 address show dummy98')
2986 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2987 output
= check_output('ip -6 address show dummy98')
2989 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2990 self
.assertRegex(output
, 'inet6 .* scope link')
2991 output
= check_output('ip -4 route show dev dummy98')
2993 self
.assertRegex(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2994 output
= check_output('ip -6 route show default')
2996 self
.assertRegex(output
, 'default')
2997 self
.assertRegex(output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff')
2999 check_output('ip link del dummy98')
3001 print('## Enable ipv6')
3002 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
3003 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
3006 self
.wait_online(['dummy98:routable'])
3008 output
= check_output('ip -4 address show dummy98')
3010 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
3011 output
= check_output('ip -6 address show dummy98')
3013 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
3014 self
.assertRegex(output
, 'inet6 .* scope link')
3015 output
= check_output('ip -4 route show dev dummy98')
3017 self
.assertRegex(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
3018 output
= check_output('ip -6 route show default')
3020 self
.assertRegex(output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff')
3022 def test_bind_carrier(self
):
3023 check_output('ip link add dummy98 type dummy')
3024 check_output('ip link set dummy98 up')
3027 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
3029 self
.wait_online(['test1:routable'])
3031 output
= check_output('ip address show test1')
3033 self
.assertRegex(output
, 'UP,LOWER_UP')
3034 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
3035 self
.wait_operstate('test1', 'routable')
3037 check_output('ip link add dummy99 type dummy')
3038 check_output('ip link set dummy99 up')
3040 output
= check_output('ip address show test1')
3042 self
.assertRegex(output
, 'UP,LOWER_UP')
3043 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
3044 self
.wait_operstate('test1', 'routable')
3046 check_output('ip link del dummy98')
3048 output
= check_output('ip address show test1')
3050 self
.assertRegex(output
, 'UP,LOWER_UP')
3051 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
3052 self
.wait_operstate('test1', 'routable')
3054 check_output('ip link set dummy99 down')
3056 output
= check_output('ip address show test1')
3058 self
.assertNotRegex(output
, 'UP,LOWER_UP')
3059 self
.assertRegex(output
, 'DOWN')
3060 self
.assertNotRegex(output
, '192.168.10')
3061 self
.wait_operstate('test1', 'off')
3063 check_output('ip link set dummy99 up')
3065 output
= check_output('ip address show test1')
3067 self
.assertRegex(output
, 'UP,LOWER_UP')
3068 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
3069 self
.wait_operstate('test1', 'routable')
3071 def _test_activation_policy(self
, test
):
3072 conffile
= '25-activation-policy.network'
3074 conffile
= f
'{conffile}.d/{test}.conf'
3075 copy_unit_to_networkd_unit_path('11-dummy.netdev', conffile
, dropins
=False)
3078 always
= test
.startswith('always')
3079 initial_up
= test
!= 'manual' and not test
.endswith('down') # note: default is up
3080 expect_up
= initial_up
3081 next_up
= not expect_up
3083 if test
.endswith('down'):
3084 self
.wait_activated('test1')
3086 for iteration
in range(4):
3087 with self
.subTest(iteration
=iteration
, expect_up
=expect_up
):
3088 operstate
= 'routable' if expect_up
else 'off'
3089 setup_state
= 'configured' if expect_up
else ('configuring' if iteration
== 0 else None)
3090 self
.wait_operstate('test1', operstate
, setup_state
=setup_state
, setup_timeout
=20)
3093 self
.assertIn('UP', check_output('ip link show test1'))
3094 self
.assertIn('192.168.10.30/24', check_output('ip address show test1'))
3095 self
.assertIn('default via 192.168.10.1', check_output('ip route show dev test1'))
3097 self
.assertIn('DOWN', check_output('ip link show test1'))
3100 check_output('ip link set dev test1 up')
3102 check_output('ip link set dev test1 down')
3103 expect_up
= initial_up
if always
else next_up
3104 next_up
= not next_up
3108 def test_activation_policy(self
):
3109 for test
in ['up', 'always-up', 'manual', 'always-down', 'down', '']:
3110 with self
.subTest(test
=test
):
3112 self
._test
_activation
_policy
(test
)
3115 def _test_activation_policy_required_for_online(self
, policy
, required
):
3116 conffile
= '25-activation-policy.network'
3117 units
= ['11-dummy.netdev', '12-dummy.netdev', '12-dummy.network', conffile
]
3119 units
+= [f
'{conffile}.d/{policy}.conf']
3121 units
+= [f
'{conffile}.d/required-{required}.conf']
3122 copy_unit_to_networkd_unit_path(*units
, dropins
=False)
3125 if policy
.endswith('down'):
3126 self
.wait_activated('test1')
3128 if policy
.endswith('down') or policy
== 'manual':
3129 self
.wait_operstate('test1', 'off', setup_state
='configuring')
3131 self
.wait_online(['test1'])
3133 if policy
== 'always-down':
3134 # if always-down, required for online is forced to no
3137 # otherwise if required for online is specified, it should match that
3138 expected
= required
== 'yes'
3140 # otherwise if only policy specified, required for online defaults to
3141 # true if policy is up, always-up, or bound
3142 expected
= policy
.endswith('up') or policy
== 'bound'
3144 # default is true, if neither are specified
3147 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
3150 yesno
= 'yes' if expected
else 'no'
3151 self
.assertRegex(output
, f
'Required For Online: {yesno}')
3153 def test_activation_policy_required_for_online(self
):
3154 for policy
in ['up', 'always-up', 'manual', 'always-down', 'down', 'bound', '']:
3155 for required
in ['yes', 'no', '']:
3156 with self
.subTest(policy
=policy
, required
=required
):
3158 self
._test
_activation
_policy
_required
_for
_online
(policy
, required
)
3161 def test_domain(self
):
3162 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
3164 self
.wait_online(['dummy98:routable'])
3166 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
3168 self
.assertRegex(output
, 'Address: 192.168.42.100')
3169 self
.assertRegex(output
, 'DNS: 192.168.42.1')
3170 self
.assertRegex(output
, 'Search Domains: one')
3172 def test_keep_configuration_static(self
):
3173 check_output('systemctl stop systemd-networkd.socket')
3174 check_output('systemctl stop systemd-networkd.service')
3176 check_output('ip link add name dummy98 type dummy')
3177 check_output('ip address add 10.1.2.3/16 dev dummy98')
3178 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
3179 output
= check_output('ip address show dummy98')
3181 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
3182 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
3183 output
= check_output('ip route show dev dummy98')
3186 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
3188 self
.wait_online(['dummy98:routable'])
3190 output
= check_output('ip address show dummy98')
3192 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
3193 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
3195 @expectedFailureIfNexthopIsNotAvailable()
3196 def test_nexthop(self
):
3197 def check_nexthop(self
):
3198 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'dummy98:routable'])
3200 output
= check_output('ip nexthop list dev veth99')
3202 self
.assertIn('id 1 via 192.168.5.1 dev veth99', output
)
3203 self
.assertIn('id 2 via 2001:1234:5:8f63::2 dev veth99', output
)
3204 self
.assertIn('id 3 dev veth99', output
)
3205 self
.assertIn('id 4 dev veth99', output
)
3206 self
.assertRegex(output
, 'id 5 via 192.168.10.1 dev veth99 .*onlink')
3207 self
.assertIn('id 8 via fe80:0:222:4dff:ff:ff:ff:ff dev veth99', output
)
3208 self
.assertRegex(output
, r
'id [0-9]* via 192.168.5.2 dev veth99')
3210 output
= check_output('ip nexthop list dev dummy98')
3212 self
.assertIn('id 20 via 192.168.20.1 dev dummy98', output
)
3214 # kernel manages blackhole nexthops on lo
3215 output
= check_output('ip nexthop list dev lo')
3217 self
.assertIn('id 6 blackhole', output
)
3218 self
.assertIn('id 7 blackhole', output
)
3220 # group nexthops are shown with -0 option
3221 output
= check_output('ip -0 nexthop list id 21')
3223 self
.assertRegex(output
, r
'id 21 group (1,3/20|20/1,3)')
3225 output
= check_output('ip route show dev veth99 10.10.10.10')
3227 self
.assertEqual('10.10.10.10 nhid 1 via 192.168.5.1 proto static', output
)
3229 output
= check_output('ip route show dev veth99 10.10.10.11')
3231 self
.assertEqual('10.10.10.11 nhid 2 via inet6 2001:1234:5:8f63::2 proto static', output
)
3233 output
= check_output('ip route show dev veth99 10.10.10.12')
3235 self
.assertEqual('10.10.10.12 nhid 5 via 192.168.10.1 proto static onlink', output
)
3237 output
= check_output('ip -6 route show dev veth99 2001:1234:5:8f62::1')
3239 self
.assertEqual('2001:1234:5:8f62::1 nhid 2 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium', output
)
3241 output
= check_output('ip route show 10.10.10.13')
3243 self
.assertEqual('blackhole 10.10.10.13 nhid 6 dev lo proto static', output
)
3245 output
= check_output('ip -6 route show 2001:1234:5:8f62::2')
3247 self
.assertEqual('blackhole 2001:1234:5:8f62::2 nhid 7 dev lo proto static metric 1024 pref medium', output
)
3249 output
= check_output('ip route show 10.10.10.14')
3251 self
.assertIn('10.10.10.14 nhid 21 proto static', output
)
3252 self
.assertIn('nexthop via 192.168.20.1 dev dummy98 weight 1', output
)
3253 self
.assertIn('nexthop via 192.168.5.1 dev veth99 weight 3', output
)
3255 # TODO: check json string
3256 check_output(*networkctl_cmd
, '--json=short', 'status', env
=env
)
3258 copy_unit_to_networkd_unit_path('25-nexthop.network', '25-veth.netdev', '25-veth-peer.network',
3259 '12-dummy.netdev', '25-nexthop-dummy.network')
3264 remove_unit_from_networkd_path(['25-nexthop.network'])
3265 copy_unit_to_networkd_unit_path('25-nexthop-nothing.network')
3266 rc
= call(*networkctl_cmd
, 'reload', env
=env
)
3267 self
.assertEqual(rc
, 0)
3270 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3272 output
= check_output('ip nexthop list dev veth99')
3274 self
.assertEqual(output
, '')
3275 output
= check_output('ip nexthop list dev lo')
3277 self
.assertEqual(output
, '')
3279 remove_unit_from_networkd_path(['25-nexthop-nothing.network'])
3280 copy_unit_to_networkd_unit_path('25-nexthop.network')
3281 rc
= call(*networkctl_cmd
, 'reconfigure', 'dummy98', env
=env
)
3282 self
.assertEqual(rc
, 0)
3283 rc
= call(*networkctl_cmd
, 'reload', env
=env
)
3284 self
.assertEqual(rc
, 0)
3289 rc
= call('ip link del veth99')
3290 self
.assertEqual(rc
, 0)
3293 output
= check_output('ip nexthop list dev lo')
3295 self
.assertEqual(output
, '')
3297 def test_qdisc(self
):
3298 copy_unit_to_networkd_unit_path('25-qdisc-clsact-and-htb.network', '12-dummy.netdev',
3299 '25-qdisc-ingress-netem-compat.network', '11-dummy.netdev')
3300 check_output('modprobe sch_teql max_equalizers=2')
3303 self
.wait_online(['dummy98:routable', 'test1:routable'])
3305 output
= check_output('tc qdisc show dev test1')
3307 self
.assertRegex(output
, 'qdisc netem')
3308 self
.assertRegex(output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
3309 self
.assertRegex(output
, 'qdisc ingress')
3311 output
= check_output('tc qdisc show dev dummy98')
3313 self
.assertRegex(output
, 'qdisc clsact')
3315 self
.assertRegex(output
, 'qdisc htb 2: root')
3316 self
.assertRegex(output
, r
'default (0x30|30)')
3318 self
.assertRegex(output
, 'qdisc netem 30: parent 2:30')
3319 self
.assertRegex(output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
3320 self
.assertRegex(output
, 'qdisc fq_codel')
3321 self
.assertRegex(output
, 'limit 20480p flows 2048 quantum 1400 target 10(.0)?ms ce_threshold 100(.0)?ms interval 200(.0)?ms memory_limit 64Mb ecn')
3323 self
.assertRegex(output
, 'qdisc teql1 31: parent 2:31')
3325 self
.assertRegex(output
, 'qdisc fq 32: parent 2:32')
3326 self
.assertRegex(output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
3327 self
.assertRegex(output
, 'quantum 1500')
3328 self
.assertRegex(output
, 'initial_quantum 13000')
3329 self
.assertRegex(output
, 'maxrate 1Mbit')
3331 self
.assertRegex(output
, 'qdisc codel 33: parent 2:33')
3332 self
.assertRegex(output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn')
3334 self
.assertRegex(output
, 'qdisc fq_codel 34: parent 2:34')
3335 self
.assertRegex(output
, 'limit 20480p flows 2048 quantum 1400 target 10(.0)?ms ce_threshold 100(.0)?ms interval 200(.0)?ms memory_limit 64Mb ecn')
3337 self
.assertRegex(output
, 'qdisc tbf 35: parent 2:35')
3338 self
.assertRegex(output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms')
3340 self
.assertRegex(output
, 'qdisc sfq 36: parent 2:36')
3341 self
.assertRegex(output
, 'perturb 5sec')
3343 self
.assertRegex(output
, 'qdisc pfifo 37: parent 2:37')
3344 self
.assertRegex(output
, 'limit 100000p')
3346 self
.assertRegex(output
, 'qdisc gred 38: parent 2:38')
3347 self
.assertRegex(output
, 'vqs 12 default 10 grio')
3349 self
.assertRegex(output
, 'qdisc sfb 39: parent 2:39')
3350 self
.assertRegex(output
, 'limit 200000')
3352 self
.assertRegex(output
, 'qdisc bfifo 3a: parent 2:3a')
3353 self
.assertRegex(output
, 'limit 1000000')
3355 self
.assertRegex(output
, 'qdisc pfifo_head_drop 3b: parent 2:3b')
3356 self
.assertRegex(output
, 'limit 1023p')
3358 self
.assertRegex(output
, 'qdisc pfifo_fast 3c: parent 2:3c')
3360 output
= check_output('tc -d class show dev dummy98')
3362 self
.assertRegex(output
, 'class htb 2:30 root leaf 30:')
3363 self
.assertRegex(output
, 'class htb 2:31 root leaf 31:')
3364 self
.assertRegex(output
, 'class htb 2:32 root leaf 32:')
3365 self
.assertRegex(output
, 'class htb 2:33 root leaf 33:')
3366 self
.assertRegex(output
, 'class htb 2:34 root leaf 34:')
3367 self
.assertRegex(output
, 'class htb 2:35 root leaf 35:')
3368 self
.assertRegex(output
, 'class htb 2:36 root leaf 36:')
3369 self
.assertRegex(output
, 'class htb 2:37 root leaf 37:')
3370 self
.assertRegex(output
, 'class htb 2:38 root leaf 38:')
3371 self
.assertRegex(output
, 'class htb 2:39 root leaf 39:')
3372 self
.assertRegex(output
, 'class htb 2:3a root leaf 3a:')
3373 self
.assertRegex(output
, 'class htb 2:3b root leaf 3b:')
3374 self
.assertRegex(output
, 'class htb 2:3c root leaf 3c:')
3375 self
.assertRegex(output
, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit')
3376 self
.assertRegex(output
, 'burst 123456')
3377 self
.assertRegex(output
, 'cburst 123457')
3379 def test_qdisc2(self
):
3380 copy_unit_to_networkd_unit_path('25-qdisc-drr.network', '12-dummy.netdev',
3381 '25-qdisc-qfq.network', '11-dummy.netdev')
3384 self
.wait_online(['dummy98:routable', 'test1:routable'])
3386 output
= check_output('tc qdisc show dev dummy98')
3388 self
.assertRegex(output
, 'qdisc drr 2: root')
3389 output
= check_output('tc class show dev dummy98')
3391 self
.assertRegex(output
, 'class drr 2:30 root quantum 2000b')
3393 output
= check_output('tc qdisc show dev test1')
3395 self
.assertRegex(output
, 'qdisc qfq 2: root')
3396 output
= check_output('tc class show dev test1')
3398 self
.assertRegex(output
, 'class qfq 2:30 root weight 2 maxpkt 16000')
3399 self
.assertRegex(output
, 'class qfq 2:31 root weight 10 maxpkt 8000')
3401 @expectedFailureIfCAKEIsNotAvailable()
3402 def test_qdisc_cake(self
):
3403 copy_unit_to_networkd_unit_path('25-qdisc-cake.network', '12-dummy.netdev')
3405 self
.wait_online(['dummy98:routable'])
3407 output
= check_output('tc qdisc show dev dummy98')
3409 self
.assertIn('qdisc cake 3a: root', output
)
3410 self
.assertIn('bandwidth 500Mbit', output
)
3411 self
.assertIn('autorate-ingress', output
)
3412 self
.assertIn('diffserv8', output
)
3413 self
.assertIn('dual-dsthost', output
)
3414 self
.assertIn(' nat', output
)
3415 self
.assertIn(' wash', output
)
3416 self
.assertIn(' split-gso', output
)
3417 self
.assertIn(' raw', output
)
3418 self
.assertIn(' atm', output
)
3419 self
.assertIn('overhead 128', output
)
3420 self
.assertIn('mpu 20', output
)
3421 self
.assertIn('fwmark 0xff00', output
)
3423 @expectedFailureIfPIEIsNotAvailable()
3424 def test_qdisc_pie(self
):
3425 copy_unit_to_networkd_unit_path('25-qdisc-pie.network', '12-dummy.netdev')
3427 self
.wait_online(['dummy98:routable'])
3429 output
= check_output('tc qdisc show dev dummy98')
3431 self
.assertRegex(output
, 'qdisc pie 3a: root')
3432 self
.assertRegex(output
, 'limit 200000')
3434 @expectedFailureIfHHFIsNotAvailable()
3435 def test_qdisc_hhf(self
):
3436 copy_unit_to_networkd_unit_path('25-qdisc-hhf.network', '12-dummy.netdev')
3438 self
.wait_online(['dummy98:routable'])
3440 output
= check_output('tc qdisc show dev dummy98')
3442 self
.assertRegex(output
, 'qdisc hhf 3a: root')
3443 self
.assertRegex(output
, 'limit 1022p')
3445 @expectedFailureIfETSIsNotAvailable()
3446 def test_qdisc_ets(self
):
3447 copy_unit_to_networkd_unit_path('25-qdisc-ets.network', '12-dummy.netdev')
3449 self
.wait_online(['dummy98:routable'])
3451 output
= check_output('tc qdisc show dev dummy98')
3454 self
.assertRegex(output
, 'qdisc ets 3a: root')
3455 self
.assertRegex(output
, 'bands 10 strict 3')
3456 self
.assertRegex(output
, 'quanta 1 2 3 4 5')
3457 self
.assertRegex(output
, 'priomap 3 4 5 6 7')
3459 @expectedFailureIfFQPIEIsNotAvailable()
3460 def test_qdisc_fq_pie(self
):
3461 copy_unit_to_networkd_unit_path('25-qdisc-fq_pie.network', '12-dummy.netdev')
3463 self
.wait_online(['dummy98:routable'])
3465 output
= check_output('tc qdisc show dev dummy98')
3468 self
.assertRegex(output
, 'qdisc fq_pie 3a: root')
3469 self
.assertRegex(output
, 'limit 200000p')
3471 def test_wait_online_ipv4(self
):
3472 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-with-ipv6-prefix.network', 'dhcp-client-ipv4-ipv6ra-prefix-client-with-delay.network')
3475 self
.wait_online(['veth99:routable'], ipv4
=True)
3477 self
.wait_address('veth99', r
'192.168.5.[0-9]+', ipv
='-4', timeout_sec
=1)
3479 def test_wait_online_ipv6(self
):
3480 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix-with-delay.network', 'ipv6ra-prefix-client-with-static-ipv4-address.network')
3483 self
.wait_online(['veth99:routable'], ipv6
=True)
3485 self
.wait_address('veth99', r
'2002:da8:1:0:1034:56ff:fe78:9abc', ipv
='-6', timeout_sec
=1)
3487 class NetworkdStateFileTests(unittest
.TestCase
, Utilities
):
3494 'state-file-tests.network',
3498 remove_links(self
.links
)
3499 stop_networkd(show_logs
=False)
3502 remove_links(self
.links
)
3503 remove_unit_from_networkd_path(self
.units
)
3504 stop_networkd(show_logs
=True)
3506 def test_state_file(self
):
3507 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'state-file-tests.network')
3509 self
.wait_online(['dummy98:routable'])
3511 output
= check_output(*networkctl_cmd
, '--no-legend', 'list', 'dummy98', env
=env
)
3513 ifindex
= output
.split()[0]
3515 path
= os
.path
.join('/run/systemd/netif/links/', ifindex
)
3516 self
.assertTrue(os
.path
.exists(path
))
3518 # make link state file updated
3519 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
3521 # TODO: check json string
3522 check_output(*networkctl_cmd
, '--json=short', 'status', env
=env
)
3524 with
open(path
) as f
:
3526 self
.assertRegex(data
, r
'IPV4_ADDRESS_STATE=routable')
3527 self
.assertRegex(data
, r
'IPV6_ADDRESS_STATE=routable')
3528 self
.assertRegex(data
, r
'ADMIN_STATE=configured')
3529 self
.assertRegex(data
, r
'OPER_STATE=routable')
3530 self
.assertRegex(data
, r
'REQUIRED_FOR_ONLINE=yes')
3531 self
.assertRegex(data
, r
'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
3532 self
.assertRegex(data
, r
'REQUIRED_FAMILY_FOR_ONLINE=both')
3533 self
.assertRegex(data
, r
'ACTIVATION_POLICY=up')
3534 self
.assertRegex(data
, r
'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
3535 self
.assertRegex(data
, r
'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
3536 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
3537 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
3538 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
3539 self
.assertRegex(data
, r
'LLMNR=no')
3540 self
.assertRegex(data
, r
'MDNS=yes')
3541 self
.assertRegex(data
, r
'DNSSEC=no')
3543 check_output(*resolvectl_cmd
, 'dns', 'dummy98', '10.10.10.12#ccc.com', '10.10.10.13', '1111:2222::3333', env
=env
)
3544 check_output(*resolvectl_cmd
, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env
=env
)
3545 check_output(*resolvectl_cmd
, 'llmnr', 'dummy98', 'yes', env
=env
)
3546 check_output(*resolvectl_cmd
, 'mdns', 'dummy98', 'no', env
=env
)
3547 check_output(*resolvectl_cmd
, 'dnssec', 'dummy98', 'yes', env
=env
)
3548 check_output(*timedatectl_cmd
, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env
=env
)
3550 # TODO: check json string
3551 check_output(*networkctl_cmd
, '--json=short', 'status', env
=env
)
3553 with
open(path
) as f
:
3555 self
.assertRegex(data
, r
'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333')
3556 self
.assertRegex(data
, r
'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org')
3557 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
3558 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
3559 self
.assertRegex(data
, r
'LLMNR=yes')
3560 self
.assertRegex(data
, r
'MDNS=no')
3561 self
.assertRegex(data
, r
'DNSSEC=yes')
3563 check_output(*timedatectl_cmd
, 'revert', 'dummy98', env
=env
)
3565 # TODO: check json string
3566 check_output(*networkctl_cmd
, '--json=short', 'status', env
=env
)
3568 with
open(path
) as f
:
3570 self
.assertRegex(data
, r
'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333')
3571 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
3572 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
3573 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
3574 self
.assertRegex(data
, r
'LLMNR=yes')
3575 self
.assertRegex(data
, r
'MDNS=no')
3576 self
.assertRegex(data
, r
'DNSSEC=yes')
3578 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
3580 # TODO: check json string
3581 check_output(*networkctl_cmd
, '--json=short', 'status', env
=env
)
3583 with
open(path
) as f
:
3585 self
.assertRegex(data
, r
'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
3586 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
3587 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
3588 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
3589 self
.assertRegex(data
, r
'LLMNR=no')
3590 self
.assertRegex(data
, r
'MDNS=yes')
3591 self
.assertRegex(data
, r
'DNSSEC=no')
3593 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
3603 '23-active-slave.network',
3604 '23-bond199.network',
3605 '23-keep-master.network',
3606 '23-primary-slave.network',
3607 '25-bond-active-backup-slave.netdev',
3610 'bond-slave.network']
3613 remove_links(self
.links
)
3614 stop_networkd(show_logs
=False)
3617 remove_links(self
.links
)
3618 remove_unit_from_networkd_path(self
.units
)
3619 stop_networkd(show_logs
=True)
3621 def test_bond_keep_master(self
):
3622 check_output('ip link add bond199 type bond mode active-backup')
3623 check_output('ip link add dummy98 type dummy')
3624 check_output('ip link set dummy98 master bond199')
3626 copy_unit_to_networkd_unit_path('23-keep-master.network')
3628 self
.wait_online(['dummy98:enslaved'])
3630 output
= check_output('ip -d link show bond199')
3632 self
.assertRegex(output
, 'active_slave dummy98')
3634 output
= check_output('ip -d link show dummy98')
3636 self
.assertRegex(output
, 'master bond199')
3638 def test_bond_active_slave(self
):
3639 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
3641 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
3643 output
= check_output('ip -d link show bond199')
3645 self
.assertRegex(output
, 'active_slave dummy98')
3647 def test_bond_primary_slave(self
):
3648 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
3650 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
3652 output
= check_output('ip -d link show bond199')
3654 self
.assertRegex(output
, 'primary dummy98')
3656 def test_bond_operstate(self
):
3657 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
3658 'bond99.network','bond-slave.network')
3660 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
3662 output
= check_output('ip -d link show dummy98')
3664 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
3666 output
= check_output('ip -d link show test1')
3668 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
3670 output
= check_output('ip -d link show bond99')
3672 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
3674 self
.wait_operstate('dummy98', 'enslaved')
3675 self
.wait_operstate('test1', 'enslaved')
3676 self
.wait_operstate('bond99', 'routable')
3678 check_output('ip link set dummy98 down')
3680 self
.wait_operstate('dummy98', 'off')
3681 self
.wait_operstate('test1', 'enslaved')
3682 self
.wait_operstate('bond99', 'degraded-carrier')
3684 check_output('ip link set dummy98 up')
3686 self
.wait_operstate('dummy98', 'enslaved')
3687 self
.wait_operstate('test1', 'enslaved')
3688 self
.wait_operstate('bond99', 'routable')
3690 check_output('ip link set dummy98 down')
3691 check_output('ip link set test1 down')
3693 self
.wait_operstate('dummy98', 'off')
3694 self
.wait_operstate('test1', 'off')
3696 if not self
.wait_operstate('bond99', 'no-carrier', setup_timeout
=30, fail_assert
=False):
3697 # Huh? Kernel does not recognize that all slave interfaces are down?
3698 # Let's confirm that networkd's operstate is consistent with ip's result.
3699 self
.assertNotRegex(output
, 'NO-CARRIER')
3701 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
3714 '23-keep-master.network',
3716 '26-bridge-configure-without-carrier.network',
3717 '26-bridge-issue-20373.netdev',
3718 '26-bridge-mdb-master.network',
3719 '26-bridge-mdb-slave.network',
3720 '26-bridge-slave-interface-1.network',
3721 '26-bridge-slave-interface-2.network',
3722 '26-bridge-vlan-master-issue-20373.network',
3723 '26-bridge-vlan-master.network',
3724 '26-bridge-vlan-slave-issue-20373.network',
3725 '26-bridge-vlan-slave.network',
3726 'bridge99-ignore-carrier-loss.network',
3730 routing_policy_rule_tables
= ['100']
3733 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
3734 remove_links(self
.links
)
3735 stop_networkd(show_logs
=False)
3738 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
3739 remove_links(self
.links
)
3740 remove_unit_from_networkd_path(self
.units
)
3741 stop_networkd(show_logs
=True)
3743 def test_bridge_vlan(self
):
3744 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
3745 '26-bridge.netdev', '26-bridge-vlan-master.network')
3747 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
3749 output
= check_output('bridge vlan show dev test1')
3751 self
.assertNotRegex(output
, '4063')
3752 for i
in range(4064, 4095):
3753 self
.assertRegex(output
, f
'{i}')
3754 self
.assertNotRegex(output
, '4095')
3756 output
= check_output('bridge vlan show dev bridge99')
3758 self
.assertNotRegex(output
, '4059')
3759 for i
in range(4060, 4095):
3760 self
.assertRegex(output
, f
'{i}')
3761 self
.assertNotRegex(output
, '4095')
3763 def test_bridge_vlan_issue_20373(self
):
3764 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave-issue-20373.network',
3765 '26-bridge-issue-20373.netdev', '26-bridge-vlan-master-issue-20373.network',
3766 '21-vlan.netdev', '21-vlan.network')
3768 self
.wait_online(['test1:enslaved', 'bridge99:degraded', 'vlan99:routable'])
3770 output
= check_output('bridge vlan show dev test1')
3772 self
.assertIn('100 PVID Egress Untagged', output
)
3773 self
.assertIn('560', output
)
3774 self
.assertIn('600', output
)
3776 output
= check_output('bridge vlan show dev bridge99')
3778 self
.assertIn('1 PVID Egress Untagged', output
)
3779 self
.assertIn('100', output
)
3780 self
.assertIn('600', output
)
3782 def test_bridge_mdb(self
):
3783 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-mdb-slave.network',
3784 '26-bridge.netdev', '26-bridge-mdb-master.network')
3786 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
3788 output
= check_output('bridge mdb show dev bridge99')
3790 self
.assertRegex(output
, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064')
3791 self
.assertRegex(output
, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065')
3793 # Old kernel may not support bridge MDB entries on bridge master
3794 if call('bridge mdb add dev bridge99 port bridge99 grp 224.0.1.3 temp vid 4068', stderr
=subprocess
.DEVNULL
) == 0:
3795 self
.assertRegex(output
, 'dev bridge99 port bridge99 grp ff02:aaaa:fee5::1:4 temp *vid 4066')
3796 self
.assertRegex(output
, 'dev bridge99 port bridge99 grp 224.0.1.2 temp *vid 4067')
3798 def test_bridge_keep_master(self
):
3799 check_output('ip link add bridge99 type bridge')
3800 check_output('ip link set bridge99 up')
3801 check_output('ip link add dummy98 type dummy')
3802 check_output('ip link set dummy98 master bridge99')
3804 copy_unit_to_networkd_unit_path('23-keep-master.network')
3806 self
.wait_online(['dummy98:enslaved'])
3808 output
= check_output('ip -d link show dummy98')
3810 self
.assertRegex(output
, 'master bridge99')
3811 self
.assertRegex(output
, 'bridge')
3813 output
= check_output('bridge -d link show dummy98')
3815 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
3816 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
3817 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
3818 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
3819 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
3820 # CONFIG_BRIDGE_IGMP_SNOOPING=y
3821 if os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast'):
3822 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
3823 if os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress'):
3824 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
3825 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
3826 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'priority'), '23')
3827 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard'), '1')
3828 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'root_block'), '1')
3830 def test_bridge_property(self
):
3831 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
3832 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
3835 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
3837 output
= check_output('ip -d link show test1')
3839 self
.assertRegex(output
, 'master')
3840 self
.assertRegex(output
, 'bridge')
3842 output
= check_output('ip -d link show dummy98')
3844 self
.assertRegex(output
, 'master')
3845 self
.assertRegex(output
, 'bridge')
3847 output
= check_output('ip addr show bridge99')
3849 self
.assertRegex(output
, '192.168.0.15/24')
3851 output
= check_output('bridge -d link show dummy98')
3853 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
3854 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
3855 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
3856 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
3857 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
3858 # CONFIG_BRIDGE_IGMP_SNOOPING=y
3859 if os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast'):
3860 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
3861 if os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress'):
3862 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
3863 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
3864 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'priority'), '23')
3865 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard'), '1')
3866 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'root_block'), '1')
3868 output
= check_output('bridge -d link show test1')
3870 self
.assertEqual(read_bridge_port_attr('bridge99', 'test1', 'priority'), '0')
3872 check_output('ip address add 192.168.0.16/24 dev bridge99')
3875 output
= check_output('ip addr show bridge99')
3877 self
.assertRegex(output
, '192.168.0.16/24')
3880 print('### ip -6 route list table all dev bridge99')
3881 output
= check_output('ip -6 route list table all dev bridge99')
3883 self
.assertRegex(output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
3885 self
.assertEqual(call('ip link del test1'), 0)
3887 self
.wait_operstate('bridge99', 'degraded-carrier')
3889 check_output('ip link del dummy98')
3891 self
.wait_operstate('bridge99', 'no-carrier')
3893 output
= check_output('ip address show bridge99')
3895 self
.assertRegex(output
, 'NO-CARRIER')
3896 self
.assertNotRegex(output
, '192.168.0.15/24')
3897 self
.assertRegex(output
, '192.168.0.16/24') # foreign address is kept
3899 print('### ip -6 route list table all dev bridge99')
3900 output
= check_output('ip -6 route list table all dev bridge99')
3902 self
.assertRegex(output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
3904 def test_bridge_configure_without_carrier(self
):
3905 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-configure-without-carrier.network',
3909 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
3910 for test
in ['no-slave', 'add-slave', 'slave-up', 'slave-no-carrier', 'slave-carrier', 'slave-down']:
3911 with self
.subTest(test
=test
):
3912 if test
== 'no-slave':
3913 # bridge has no slaves; it's up but *might* not have carrier
3914 self
.wait_operstate('bridge99', operstate
=r
'(no-carrier|routable)', setup_state
=None, setup_timeout
=30)
3915 # due to a bug in the kernel, newly-created bridges are brought up
3916 # *with* carrier, unless they have had any setting changed; e.g.
3917 # their mac set, priority set, etc. Then, they will lose carrier
3918 # as soon as a (down) slave interface is added, and regain carrier
3919 # again once the slave interface is brought up.
3920 #self.check_link_attr('bridge99', 'carrier', '0')
3921 elif test
== 'add-slave':
3922 # add slave to bridge, but leave it down; bridge is definitely no-carrier
3923 self
.check_link_attr('test1', 'operstate', 'down')
3924 check_output('ip link set dev test1 master bridge99')
3925 self
.wait_operstate('bridge99', operstate
='no-carrier', setup_state
=None)
3926 self
.check_link_attr('bridge99', 'carrier', '0')
3927 elif test
== 'slave-up':
3928 # bring up slave, which will have carrier; bridge gains carrier
3929 check_output('ip link set dev test1 up')
3930 self
.wait_online(['bridge99:routable'])
3931 self
.check_link_attr('bridge99', 'carrier', '1')
3932 elif test
== 'slave-no-carrier':
3933 # drop slave carrier; bridge loses carrier
3934 check_output('ip link set dev test1 carrier off')
3935 self
.wait_online(['bridge99:no-carrier:no-carrier'])
3936 self
.check_link_attr('bridge99', 'carrier', '0')
3937 elif test
== 'slave-carrier':
3938 # restore slave carrier; bridge gains carrier
3939 check_output('ip link set dev test1 carrier on')
3940 self
.wait_online(['bridge99:routable'])
3941 self
.check_link_attr('bridge99', 'carrier', '1')
3942 elif test
== 'slave-down':
3943 # bring down slave; bridge loses carrier
3944 check_output('ip link set dev test1 down')
3945 self
.wait_online(['bridge99:no-carrier:no-carrier'])
3946 self
.check_link_attr('bridge99', 'carrier', '0')
3948 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
3949 self
.assertRegex(output
, '10.1.2.3')
3950 self
.assertRegex(output
, '10.1.2.1')
3952 def test_bridge_ignore_carrier_loss(self
):
3953 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
3954 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
3955 'bridge99-ignore-carrier-loss.network')
3957 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
3959 check_output('ip address add 192.168.0.16/24 dev bridge99')
3962 check_output('ip link del test1')
3963 check_output('ip link del dummy98')
3966 output
= check_output('ip address show bridge99')
3968 self
.assertRegex(output
, 'NO-CARRIER')
3969 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
3970 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
3972 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
3973 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
3974 'bridge99-ignore-carrier-loss.network')
3976 self
.wait_online(['bridge99:no-carrier'])
3978 for trial
in range(4):
3979 check_output('ip link add dummy98 type dummy')
3980 check_output('ip link set dummy98 up')
3982 check_output('ip link del dummy98')
3984 self
.wait_online(['bridge99:routable', 'dummy98:enslaved'])
3986 output
= check_output('ip address show bridge99')
3988 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
3990 output
= check_output('ip rule list table 100')
3992 self
.assertIn('from all to 8.8.8.8 lookup 100', output
)
3994 class NetworkdSRIOVTests(unittest
.TestCase
, Utilities
):
3996 '25-sriov-udev.network',
4002 stop_networkd(show_logs
=False)
4003 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
4006 remove_unit_from_networkd_path(self
.units
)
4007 stop_networkd(show_logs
=True)
4008 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
4010 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable()
4011 def test_sriov(self
):
4012 call('modprobe netdevsim', stderr
=subprocess
.DEVNULL
)
4014 with
open('/sys/bus/netdevsim/new_device', mode
='w') as f
:
4017 call('udevadm settle')
4018 call('udevadm info -w10s /sys/devices/netdevsim99/net/eni99np1', stderr
=subprocess
.DEVNULL
)
4019 with
open('/sys/class/net/eni99np1/device/sriov_numvfs', mode
='w') as f
:
4022 copy_unit_to_networkd_unit_path('25-sriov.network')
4024 self
.wait_online(['eni99np1:routable'])
4026 output
= check_output('ip link show dev eni99np1')
4028 self
.assertRegex(output
,
4029 'vf 0 .*00:11:22:33:44:55.*vlan 5, qos 1, vlan protocol 802.1ad, spoof checking on, link-state enable, trust on, query_rss on\n *'
4030 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
4031 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4034 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable()
4035 def test_sriov_udev(self
):
4036 call('modprobe netdevsim', stderr
=subprocess
.DEVNULL
)
4038 copy_unit_to_networkd_unit_path('25-sriov.link', '25-sriov-udev.network')
4039 call('udevadm control --reload')
4041 with
open('/sys/bus/netdevsim/new_device', mode
='w') as f
:
4045 self
.wait_online(['eni99np1:routable'])
4047 output
= check_output('ip link show dev eni99np1')
4049 self
.assertRegex(output
,
4050 'vf 0 .*00:11:22:33:44:55.*vlan 5, qos 1, vlan protocol 802.1ad, spoof checking on, link-state enable, trust on, query_rss on\n *'
4051 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
4052 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4054 self
.assertNotIn('vf 3', output
)
4055 self
.assertNotIn('vf 4', output
)
4057 with
open(os
.path
.join(network_unit_file_path
, '25-sriov.link'), mode
='a') as f
:
4058 f
.write('[Link]\nSR-IOVVirtualFunctions=4\n')
4060 call('udevadm control --reload')
4061 call('udevadm trigger --action add --settle /sys/devices/netdevsim99/net/eni99np1')
4063 output
= check_output('ip link show dev eni99np1')
4065 self
.assertRegex(output
,
4066 'vf 0 .*00:11:22:33:44:55.*vlan 5, qos 1, vlan protocol 802.1ad, spoof checking on, link-state enable, trust on, query_rss on\n *'
4067 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
4068 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off\n *'
4071 self
.assertNotIn('vf 4', output
)
4073 with
open(os
.path
.join(network_unit_file_path
, '25-sriov.link'), mode
='a') as f
:
4074 f
.write('[Link]\nSR-IOVVirtualFunctions=\n')
4076 call('udevadm control --reload')
4077 call('udevadm trigger --action add --settle /sys/devices/netdevsim99/net/eni99np1')
4079 output
= check_output('ip link show dev eni99np1')
4081 self
.assertRegex(output
,
4082 'vf 0 .*00:11:22:33:44:55.*vlan 5, qos 1, vlan protocol 802.1ad, spoof checking on, link-state enable, trust on, query_rss on\n *'
4083 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
4084 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off\n *'
4087 self
.assertNotIn('vf 4', output
)
4089 with
open(os
.path
.join(network_unit_file_path
, '25-sriov.link'), mode
='a') as f
:
4090 f
.write('[Link]\nSR-IOVVirtualFunctions=2\n')
4092 call('udevadm control --reload')
4093 call('udevadm trigger --action add --settle /sys/devices/netdevsim99/net/eni99np1')
4095 output
= check_output('ip link show dev eni99np1')
4097 self
.assertRegex(output
,
4098 'vf 0 .*00:11:22:33:44:55.*vlan 5, qos 1, vlan protocol 802.1ad, spoof checking on, link-state enable, trust on, query_rss on\n *'
4099 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off'
4101 self
.assertNotIn('vf 2', output
)
4102 self
.assertNotIn('vf 3', output
)
4103 self
.assertNotIn('vf 4', output
)
4105 with
open(os
.path
.join(network_unit_file_path
, '25-sriov.link'), mode
='a') as f
:
4106 f
.write('[Link]\nSR-IOVVirtualFunctions=\n')
4108 call('udevadm control --reload')
4109 call('udevadm trigger --action add --settle /sys/devices/netdevsim99/net/eni99np1')
4111 output
= check_output('ip link show dev eni99np1')
4113 self
.assertRegex(output
,
4114 'vf 0 .*00:11:22:33:44:55.*vlan 5, qos 1, vlan protocol 802.1ad, spoof checking on, link-state enable, trust on, query_rss on\n *'
4115 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
4116 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4118 self
.assertNotIn('vf 3', output
)
4119 self
.assertNotIn('vf 4', output
)
4121 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
4125 '23-emit-lldp.network',
4130 remove_links(self
.links
)
4131 stop_networkd(show_logs
=False)
4134 remove_links(self
.links
)
4135 remove_unit_from_networkd_path(self
.units
)
4136 stop_networkd(show_logs
=True)
4138 def test_lldp(self
):
4139 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
4141 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
4143 for trial
in range(10):
4147 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
4149 if re
.search(r
'veth99 .* veth-peer', output
):
4154 class NetworkdRATests(unittest
.TestCase
, Utilities
):
4159 'ipv6-prefix.network',
4160 'ipv6-prefix-veth.network',
4161 'ipv6-prefix-veth-token-static.network',
4162 'ipv6-prefix-veth-token-prefixstable.network',
4163 'ipv6-prefix-veth-token-prefixstable-without-address.network']
4166 remove_links(self
.links
)
4167 stop_networkd(show_logs
=False)
4170 remove_links(self
.links
)
4171 remove_unit_from_networkd_path(self
.units
)
4172 stop_networkd(show_logs
=True)
4174 def test_ipv6_prefix_delegation(self
):
4175 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
4177 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
4179 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
4181 self
.assertRegex(output
, 'fe80::')
4182 self
.assertRegex(output
, '2002:da8:1::1')
4184 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
4186 self
.assertIn('hogehoge.test', output
)
4188 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4190 self
.assertRegex(output
, '2002:da8:1:0')
4192 def test_ipv6_token_static(self
):
4193 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static.network')
4195 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
4197 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4199 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
4200 self
.assertRegex(output
, '2002:da8:1:0:fa:de:ca:fe')
4201 self
.assertRegex(output
, '2002:da8:2:0:1a:2b:3c:4d')
4202 self
.assertRegex(output
, '2002:da8:2:0:fa:de:ca:fe')
4204 def test_ipv6_token_prefixstable(self
):
4205 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable.network')
4207 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
4209 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4211 self
.assertIn('2002:da8:1:0:b47e:7975:fc7a:7d6e', output
)
4212 self
.assertIn('2002:da8:2:0:1034:56ff:fe78:9abc', output
) # EUI64
4214 def test_ipv6_token_prefixstable_without_address(self
):
4215 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable-without-address.network')
4217 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
4219 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4221 self
.assertIn('2002:da8:1:0:b47e:7975:fc7a:7d6e', output
)
4222 self
.assertIn('2002:da8:2:0:f689:561a:8eda:7443', output
)
4224 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
4233 'dhcp-client.network',
4234 'dhcp-client-static-lease.network',
4235 'dhcp-client-timezone-router.network',
4236 'dhcp-server.network',
4237 'dhcp-server-downstream.network',
4238 'dhcp-server-static-lease.network',
4239 'dhcp-server-timezone-router.network',
4240 'dhcp-server-uplink.network',
4244 remove_links(self
.links
)
4245 stop_networkd(show_logs
=False)
4248 remove_links(self
.links
)
4249 remove_unit_from_networkd_path(self
.units
)
4250 stop_networkd(show_logs
=True)
4252 def test_dhcp_server(self
):
4253 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
4255 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4257 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4259 self
.assertRegex(output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)')
4260 self
.assertIn('Gateway: 192.168.5.3', output
)
4261 self
.assertRegex(output
, 'DNS: 192.168.5.1\n *192.168.5.10')
4262 self
.assertRegex(output
, 'NTP: 192.168.5.1\n *192.168.5.11')
4264 def test_dhcp_server_with_uplink(self
):
4265 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server-downstream.network',
4266 '12-dummy.netdev', 'dhcp-server-uplink.network')
4268 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4270 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4272 self
.assertRegex(output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)')
4273 self
.assertIn('Gateway: 192.168.5.3', output
)
4274 self
.assertIn('DNS: 192.168.5.1', output
)
4275 self
.assertIn('NTP: 192.168.5.1', output
)
4277 def test_emit_router_timezone(self
):
4278 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
4280 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4282 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4284 self
.assertRegex(output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)')
4285 self
.assertIn('Gateway: 192.168.5.1', output
)
4286 self
.assertIn('Time Zone: Europe/Berlin', output
)
4288 def test_dhcp_server_static_lease(self
):
4289 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-static-lease.network', 'dhcp-server-static-lease.network')
4291 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4293 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4295 self
.assertIn('Address: 10.1.1.200 (DHCP4 via 10.1.1.1)', output
)
4297 class NetworkdDHCPServerRelayAgentTests(unittest
.TestCase
, Utilities
):
4306 'agent-veth-client.netdev',
4307 'agent-veth-server.netdev',
4308 'agent-client.network',
4309 'agent-server.network',
4310 'agent-client-peer.network',
4311 'agent-server-peer.network',
4315 remove_links(self
.links
)
4316 stop_networkd(show_logs
=False)
4319 remove_links(self
.links
)
4320 remove_unit_from_networkd_path(self
.units
)
4321 stop_networkd(show_logs
=True)
4323 def test_relay_agent(self
):
4324 copy_unit_to_networkd_unit_path(*self
.units
)
4327 self
.wait_online(['client:routable'])
4329 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'client', env
=env
)
4331 self
.assertRegex(output
, r
'Address: 192.168.5.150 \(DHCP4 via 192.168.5.1\)')
4333 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
4342 'dhcp-client-allow-list.network',
4343 'dhcp-client-anonymize.network',
4344 'dhcp-client-decline.network',
4345 'dhcp-client-gateway-ipv4.network',
4346 'dhcp-client-gateway-ipv6.network',
4347 'dhcp-client-gateway-onlink-implicit.network',
4348 'dhcp-client-ipv4-dhcp-settings.network',
4349 'dhcp-client-ipv4-only-ipv6-disabled.network',
4350 'dhcp-client-ipv4-only.network',
4351 'dhcp-client-ipv4-use-routes-use-gateway.network',
4352 'dhcp-client-ipv6-only.network',
4353 'dhcp-client-keep-configuration-dhcp-on-stop.network',
4354 'dhcp-client-keep-configuration-dhcp.network',
4355 'dhcp-client-listen-port.network',
4356 'dhcp-client-reassign-static-routes-ipv4.network',
4357 'dhcp-client-reassign-static-routes-ipv6.network',
4358 'dhcp-client-route-metric.network',
4359 'dhcp-client-route-table.network',
4360 'dhcp-client-use-dns-ipv4-and-ra.network',
4361 'dhcp-client-use-dns-ipv4.network',
4362 'dhcp-client-use-dns-no.network',
4363 'dhcp-client-use-dns-yes.network',
4364 'dhcp-client-use-domains.network',
4365 'dhcp-client-vrf.network',
4366 'dhcp-client-with-ipv4ll.network',
4367 'dhcp-client-with-static-address.network',
4368 'dhcp-client.network',
4369 'dhcp-server-decline.network',
4370 'dhcp-server-veth-peer.network',
4371 'dhcp-v4-server-veth-peer.network',
4376 remove_dnsmasq_lease_file()
4377 remove_dnsmasq_log_file()
4378 remove_links(self
.links
)
4379 stop_networkd(show_logs
=False)
4383 remove_dnsmasq_lease_file()
4384 remove_dnsmasq_log_file()
4385 remove_links(self
.links
)
4386 remove_unit_from_networkd_path(self
.units
)
4387 stop_networkd(show_logs
=True)
4389 def test_dhcp_client_ipv6_only(self
):
4390 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
4393 self
.wait_online(['veth-peer:carrier'])
4395 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4397 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4399 self
.assertRegex(output
, '2600::')
4400 self
.assertNotRegex(output
, '192.168.5')
4402 output
= check_output('ip addr show dev veth99')
4404 self
.assertRegex(output
, '2600::')
4405 self
.assertNotRegex(output
, '192.168.5')
4406 self
.assertNotRegex(output
, 'tentative')
4408 # Confirm that ipv6 token is not set in the kernel
4409 output
= check_output('ip token show dev veth99')
4411 self
.assertRegex(output
, 'token :: dev veth99')
4413 def test_dhcp_client_ipv4_only(self
):
4414 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
4417 self
.wait_online(['veth-peer:carrier'])
4418 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
4419 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4421 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4423 self
.assertNotRegex(output
, '2600::')
4424 self
.assertRegex(output
, '192.168.5')
4425 self
.assertRegex(output
, '192.168.5.6')
4426 self
.assertRegex(output
, '192.168.5.7')
4428 # checking routes to DNS servers
4429 output
= check_output('ip route show dev veth99')
4431 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
4432 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
4433 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
4436 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8', lease_time
='2m')
4438 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4439 print('Wait for the dynamic address to be renewed')
4442 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4444 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4446 self
.assertNotRegex(output
, '2600::')
4447 self
.assertRegex(output
, '192.168.5')
4448 self
.assertNotRegex(output
, '192.168.5.6')
4449 self
.assertRegex(output
, '192.168.5.7')
4450 self
.assertRegex(output
, '192.168.5.8')
4452 # checking routes to DNS servers
4453 output
= check_output('ip route show dev veth99')
4455 self
.assertNotRegex(output
, r
'192.168.5.6')
4456 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
4457 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
4458 self
.assertRegex(output
, r
'192.168.5.8 proto dhcp scope link src 192.168.5.181 metric 1024')
4460 def test_dhcp_client_ipv4_use_routes_gateway(self
):
4461 for (routes
, gateway
, dns_and_ntp_routes
, classless
) in itertools
.product([True, False], repeat
=4):
4463 with self
.subTest(routes
=routes
, gateway
=gateway
, dns_and_ntp_routes
=dns_and_ntp_routes
, classless
=classless
):
4464 self
._test
_dhcp
_client
_ipv
4_use
_routes
_gateway
(routes
, gateway
, dns_and_ntp_routes
, classless
)
4467 def _test_dhcp_client_ipv4_use_routes_gateway(self
, use_routes
, use_gateway
, dns_and_ntp_routes
, classless
):
4468 testunit
= 'dhcp-client-ipv4-use-routes-use-gateway.network'
4469 testunits
= ['25-veth.netdev', 'dhcp-server-veth-peer.network', testunit
]
4470 testunits
.append(f
'{testunit}.d/use-routes-{use_routes}.conf')
4471 testunits
.append(f
'{testunit}.d/use-gateway-{use_gateway}.conf')
4472 testunits
.append(f
'{testunit}.d/use-dns-and-ntp-routes-{dns_and_ntp_routes}.conf')
4473 copy_unit_to_networkd_unit_path(*testunits
, dropins
=False)
4476 self
.wait_online(['veth-peer:carrier'])
4477 additional_options
= '--dhcp-option=option:dns-server,192.168.5.10,8.8.8.8 --dhcp-option=option:ntp-server,192.168.5.11,9.9.9.9 --dhcp-option=option:static-route,192.168.5.100,192.168.5.2,8.8.8.8,192.168.5.3'
4479 additional_options
+= ' --dhcp-option=option:classless-static-route,0.0.0.0/0,192.168.5.4,8.0.0.0/8,192.168.5.5'
4480 start_dnsmasq(additional_options
=additional_options
, lease_time
='2m')
4481 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4483 output
= check_output('ip -4 route show dev veth99')
4489 self
.assertRegex(output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
4490 self
.assertRegex(output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
4491 self
.assertRegex(output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4492 self
.assertRegex(output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4494 self
.assertRegex(output
, r
'192.168.5.0/24 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4495 self
.assertRegex(output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024')
4496 self
.assertRegex(output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4498 self
.assertNotRegex(output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
4499 self
.assertNotRegex(output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
4500 self
.assertNotRegex(output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4501 self
.assertNotRegex(output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4502 self
.assertNotRegex(output
, r
'192.168.5.0/24 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4503 self
.assertNotRegex(output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024')
4504 self
.assertNotRegex(output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4507 if use_gateway
and (not classless
or not use_routes
):
4508 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
4510 self
.assertNotRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
4512 # Check route to gateway
4513 if (use_gateway
or dns_and_ntp_routes
) and (not classless
or not use_routes
):
4514 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4516 self
.assertNotRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4518 # Check RoutesToDNS= and RoutesToNTP=
4519 if dns_and_ntp_routes
:
4520 self
.assertRegex(output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4521 self
.assertRegex(output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4522 if classless
and use_routes
:
4523 self
.assertRegex(output
, r
'8.8.8.8 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
4524 self
.assertRegex(output
, r
'9.9.9.9 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
4526 self
.assertRegex(output
, r
'8.8.8.8 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
4527 self
.assertRegex(output
, r
'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
4529 self
.assertNotRegex(output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4530 self
.assertNotRegex(output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4531 self
.assertNotRegex(output
, r
'8.8.8.8 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024')
4532 self
.assertNotRegex(output
, r
'9.9.9.9 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024')
4534 # TODO: check json string
4535 check_output(*networkctl_cmd
, '--json=short', 'status', env
=env
)
4537 def test_dhcp_client_ipv4_ipv6(self
):
4538 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only.network')
4540 self
.wait_online(['veth-peer:carrier'])
4542 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4544 # link become 'routable' when at least one protocol provide an valid address.
4545 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4546 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4548 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4550 self
.assertRegex(output
, '2600::')
4551 self
.assertRegex(output
, '192.168.5')
4553 def test_dhcp_client_settings(self
):
4554 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
4557 self
.wait_online(['veth-peer:carrier'])
4559 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4561 print('## ip address show dev veth99')
4562 output
= check_output('ip address show dev veth99')
4564 self
.assertRegex(output
, '12:34:56:78:9a:bc')
4565 self
.assertRegex(output
, '192.168.5')
4566 self
.assertRegex(output
, '1492')
4567 self
.assertRegex(output
, 'test-label')
4569 print('## ip route show table main dev veth99')
4570 output
= check_output('ip route show table main dev veth99')
4573 main_table_is_empty
= output
== ''
4574 if not main_table_is_empty
:
4575 self
.assertNotRegex(output
, 'proto dhcp')
4577 print('## ip route show table 211 dev veth99')
4578 output
= check_output('ip route show table 211 dev veth99')
4580 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
4581 if main_table_is_empty
:
4582 self
.assertRegex(output
, '192.168.5.0/24 proto dhcp')
4583 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
4585 print('## dnsmasq log')
4586 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
4587 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
4588 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
4589 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
4591 def test_dhcp_client_settings_anonymize(self
):
4592 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
4594 self
.wait_online(['veth-peer:carrier'])
4596 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4598 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
4599 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
4600 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
4602 def test_dhcp_client_listen_port(self
):
4603 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
4605 self
.wait_online(['veth-peer:carrier'])
4606 start_dnsmasq('--dhcp-alternate-port=67,5555')
4607 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4609 output
= check_output('ip -4 address show dev veth99')
4611 self
.assertRegex(output
, '192.168.5.* dynamic')
4613 def test_dhcp_client_with_static_address(self
):
4614 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
4615 'dhcp-client-with-static-address.network')
4617 self
.wait_online(['veth-peer:carrier'])
4619 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4621 output
= check_output('ip address show dev veth99 scope global')
4623 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
4624 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global secondary dynamic veth99')
4626 output
= check_output('ip route show dev veth99')
4628 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
4629 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
4630 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4632 def test_dhcp_route_table_id(self
):
4633 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
4635 self
.wait_online(['veth-peer:carrier'])
4637 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4639 output
= check_output('ip route show table 12')
4641 self
.assertRegex(output
, 'veth99 proto dhcp')
4642 self
.assertRegex(output
, '192.168.5.1')
4644 def test_dhcp_route_metric(self
):
4645 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
4647 self
.wait_online(['veth-peer:carrier'])
4649 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4651 output
= check_output('ip route show dev veth99')
4653 self
.assertIn('default via 192.168.5.1 proto dhcp src 192.168.5.181 metric 24', output
)
4654 self
.assertIn('192.168.5.0/24 proto kernel scope link src 192.168.5.181 metric 24', output
)
4655 self
.assertIn('192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 24', output
)
4657 def test_dhcp_client_reassign_static_routes_ipv4(self
):
4658 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4659 'dhcp-client-reassign-static-routes-ipv4.network')
4661 self
.wait_online(['veth-peer:carrier'])
4662 start_dnsmasq(lease_time
='2m')
4663 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4665 output
= check_output('ip address show dev veth99 scope global')
4667 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
4669 output
= check_output('ip route show dev veth99')
4671 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
4672 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
4673 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
4674 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
4677 start_dnsmasq(ipv4_range
='192.168.5.210,192.168.5.220', lease_time
='2m')
4679 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4680 print('Wait for the dynamic address to be renewed')
4683 self
.wait_online(['veth99:routable'])
4685 output
= check_output('ip route show dev veth99')
4687 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
4688 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
4689 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
4690 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
4692 def test_dhcp_client_reassign_static_routes_ipv6(self
):
4693 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4694 'dhcp-client-reassign-static-routes-ipv6.network')
4696 self
.wait_online(['veth-peer:carrier'])
4697 start_dnsmasq(lease_time
='2m')
4698 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4700 output
= check_output('ip address show dev veth99 scope global')
4702 self
.assertRegex(output
, r
'inet6 2600::[0-9a-f]*/128 scope global (noprefixroute dynamic|dynamic noprefixroute)')
4704 output
= check_output('ip -6 route show dev veth99')
4706 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
4707 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
4710 start_dnsmasq(ipv6_range
='2600::30,2600::40', lease_time
='2m')
4712 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4713 print('Wait for the dynamic address to be renewed')
4716 self
.wait_online(['veth99:routable'])
4718 output
= check_output('ip -6 route show dev veth99')
4720 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
4721 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
4723 def test_dhcp_keep_configuration_dhcp(self
):
4724 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
4726 self
.wait_online(['veth-peer:carrier'])
4727 start_dnsmasq(lease_time
='2m')
4728 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4730 output
= check_output('ip address show dev veth99 scope global')
4732 self
.assertRegex(output
, r
'192.168.5.*')
4734 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4736 self
.assertRegex(output
, r
'192.168.5.*')
4738 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
4741 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4742 print('Wait for the dynamic address to be expired')
4745 print('The lease address should be kept after lease expired')
4746 output
= check_output('ip address show dev veth99 scope global')
4748 self
.assertRegex(output
, r
'192.168.5.*')
4750 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4752 self
.assertRegex(output
, r
'192.168.5.*')
4754 check_output('systemctl stop systemd-networkd.socket')
4755 check_output('systemctl stop systemd-networkd.service')
4757 print('The lease address should be kept after networkd stopped')
4758 output
= check_output('ip address show dev veth99 scope global')
4760 self
.assertRegex(output
, r
'192.168.5.*')
4762 with
open(os
.path
.join(network_unit_file_path
, 'dhcp-client-keep-configuration-dhcp.network'), mode
='a') as f
:
4763 f
.write('[Network]\nDHCP=no\n')
4766 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4768 print('Still the lease address should be kept after networkd restarted')
4769 output
= check_output('ip address show dev veth99 scope global')
4771 self
.assertRegex(output
, r
'192.168.5.*')
4773 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4775 self
.assertRegex(output
, r
'192.168.5.*')
4777 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
4778 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
4780 self
.wait_online(['veth-peer:carrier'])
4781 start_dnsmasq(lease_time
='2m')
4782 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4784 output
= check_output('ip address show dev veth99 scope global')
4786 self
.assertRegex(output
, r
'192.168.5.*')
4789 check_output('systemctl stop systemd-networkd.socket')
4790 check_output('systemctl stop systemd-networkd.service')
4792 output
= check_output('ip address show dev veth99 scope global')
4794 self
.assertRegex(output
, r
'192.168.5.*')
4797 self
.wait_online(['veth-peer:routable'])
4799 output
= check_output('ip address show dev veth99 scope global')
4801 self
.assertNotRegex(output
, r
'192.168.5.*')
4803 def test_dhcp_client_reuse_address_as_static(self
):
4804 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
4806 self
.wait_online(['veth-peer:carrier'])
4808 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4810 # link become 'routable' when at least one protocol provide an valid address.
4811 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4812 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4814 output
= check_output('ip address show dev veth99 scope global')
4816 self
.assertRegex(output
, '192.168.5')
4817 self
.assertRegex(output
, '2600::')
4819 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
4820 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
4821 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
4822 print(static_network
)
4824 remove_unit_from_networkd_path(['dhcp-client.network'])
4826 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
4827 f
.write(static_network
)
4829 # When networkd started, the links are already configured, so let's wait for 5 seconds
4830 # the links to be re-configured.
4832 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4834 output
= check_output('ip -4 address show dev veth99 scope global')
4836 self
.assertRegex(output
, '192.168.5')
4837 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
4839 output
= check_output('ip -6 address show dev veth99 scope global')
4841 self
.assertRegex(output
, '2600::')
4842 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
4844 @expectedFailureIfModuleIsNotAvailable('vrf')
4845 def test_dhcp_client_vrf(self
):
4846 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
4847 '25-vrf.netdev', '25-vrf.network')
4849 self
.wait_online(['veth-peer:carrier'])
4851 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
4853 # link become 'routable' when at least one protocol provide an valid address.
4854 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4855 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4857 print('## ip -d link show dev vrf99')
4858 output
= check_output('ip -d link show dev vrf99')
4860 self
.assertRegex(output
, 'vrf table 42')
4862 print('## ip address show vrf vrf99')
4863 output
= check_output('ip address show vrf vrf99')
4865 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
4866 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
4867 self
.assertRegex(output
, 'inet6 .* scope link')
4869 print('## ip address show dev veth99')
4870 output
= check_output('ip address show dev veth99')
4872 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
4873 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
4874 self
.assertRegex(output
, 'inet6 .* scope link')
4876 print('## ip route show vrf vrf99')
4877 output
= check_output('ip route show vrf vrf99')
4879 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
4880 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
4881 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
4883 print('## ip route show table main dev veth99')
4884 output
= check_output('ip route show table main dev veth99')
4886 self
.assertEqual(output
, '')
4888 def test_dhcp_client_gateway_ipv4(self
):
4889 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4890 'dhcp-client-gateway-ipv4.network')
4892 self
.wait_online(['veth-peer:carrier'])
4894 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4896 output
= check_output('ip route list dev veth99')
4898 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]*')
4899 self
.assertIn('10.0.0.0/8 via 192.168.5.1 proto dhcp', output
)
4901 with
open(os
.path
.join(network_unit_file_path
, 'dhcp-client-gateway-ipv4.network'), mode
='a') as f
:
4902 f
.write('[DHCPv4]\nUseGateway=no\n')
4904 rc
= call(*networkctl_cmd
, 'reload', env
=env
)
4905 self
.assertEqual(rc
, 0)
4908 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4910 output
= check_output('ip route list dev veth99')
4912 self
.assertNotRegex(output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]*')
4913 self
.assertIn('10.0.0.0/8 via 192.168.5.1 proto dhcp', output
)
4915 def test_dhcp_client_gateway_ipv6(self
):
4916 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4917 'dhcp-client-gateway-ipv6.network')
4919 self
.wait_online(['veth-peer:carrier'])
4921 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4923 output
= check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
4925 self
.assertRegex(output
, 'via fe80::1034:56ff:fe78:9abd')
4927 def test_dhcp_client_gateway_onlink_implicit(self
):
4928 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4929 'dhcp-client-gateway-onlink-implicit.network')
4931 self
.wait_online(['veth-peer:carrier'])
4933 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4935 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4937 self
.assertRegex(output
, '192.168.5')
4939 output
= check_output('ip route list dev veth99 10.0.0.0/8')
4941 self
.assertRegex(output
, 'onlink')
4942 output
= check_output('ip route list dev veth99 192.168.100.0/24')
4944 self
.assertRegex(output
, 'onlink')
4946 def test_dhcp_client_with_ipv4ll_with_dhcp_server(self
):
4947 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4948 'dhcp-client-with-ipv4ll.network')
4950 self
.wait_online(['veth-peer:carrier'])
4951 start_dnsmasq(lease_time
='2m')
4952 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4954 output
= check_output('ip address show dev veth99')
4957 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
4958 self
.assertNotRegex(output
, r
'inet6 2600::[0-9a-f]+/128 scope global dynamic')
4959 output
= check_output('ip -6 address show dev veth99 scope link')
4960 self
.assertRegex(output
, r
'inet6 .* scope link')
4961 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
4962 self
.assertRegex(output
, r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99')
4963 output
= check_output('ip -4 address show dev veth99 scope link')
4964 self
.assertNotRegex(output
, r
'inet 169\.254\.\d+\.\d+/16 metric 2048 brd 169\.254\.255\.255 scope link')
4966 print('Wait for the dynamic address to be expired')
4969 output
= check_output('ip address show dev veth99')
4972 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
4973 self
.assertNotRegex(output
, r
'inet6 2600::[0-9a-f]+/128 scope global dynamic')
4974 output
= check_output('ip -6 address show dev veth99 scope link')
4975 self
.assertRegex(output
, r
'inet6 .* scope link')
4976 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
4977 self
.assertRegex(output
, r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99')
4978 output
= check_output('ip -4 address show dev veth99 scope link')
4979 self
.assertNotRegex(output
, r
'inet 169\.254\.\d+\.\d+/16 metric 2048 brd 169\.254\.255\.255 scope link')
4981 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
4983 def test_dhcp_client_with_ipv4ll_without_dhcp_server(self
):
4984 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4985 'dhcp-client-with-ipv4ll.network')
4987 # we need to increase timeout above default, as this will need to wait for
4988 # systemd-networkd to get the dhcpv4 transient failure event
4989 self
.wait_online(['veth99:degraded', 'veth-peer:routable'], timeout
='60s')
4991 output
= check_output('ip address show dev veth99')
4994 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
4995 self
.assertNotRegex(output
, r
'inet6 2600::[0-9a-f]+/128 scope global dynamic')
4996 output
= check_output('ip -6 address show dev veth99 scope link')
4997 self
.assertRegex(output
, r
'inet6 .* scope link')
4998 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
4999 self
.assertNotRegex(output
, r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99')
5000 output
= check_output('ip -4 address show dev veth99 scope link')
5001 self
.assertRegex(output
, r
'inet 169\.254\.\d+\.\d+/16 metric 2048 brd 169\.254\.255\.255 scope link')
5003 start_dnsmasq(lease_time
='2m')
5004 self
.wait_address('veth99', r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic', ipv
='-4')
5005 self
.wait_address_dropped('veth99', r
'inet 169\.254\.\d+\.\d+/16 metric 2048 brd 169\.255\.255\.255 scope link', scope
='link', ipv
='-4')
5007 def test_dhcp_client_route_remove_on_renew(self
):
5008 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
5009 'dhcp-client-ipv4-only-ipv6-disabled.network')
5011 self
.wait_online(['veth-peer:carrier'])
5012 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
5013 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
5015 # test for issue #12490
5017 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
5019 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
5021 for line
in output
.splitlines():
5022 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
5023 address1
= line
.split()[1].split('/')[0]
5026 output
= check_output('ip -4 route show dev veth99')
5028 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
5029 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
5032 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
5034 print('Wait for the dynamic address to be expired')
5037 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
5039 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
5041 for line
in output
.splitlines():
5042 if 'metric 1024 brd 192.168.5.255 scope global dynamic veth99' in line
:
5043 address2
= line
.split()[1].split('/')[0]
5046 self
.assertNotEqual(address1
, address2
)
5048 output
= check_output('ip -4 route show dev veth99')
5050 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
5051 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
5052 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
5053 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
5055 def test_dhcp_client_use_dns_yes(self
):
5056 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-yes.network')
5059 self
.wait_online(['veth-peer:carrier'])
5060 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
5061 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
5063 # link become 'routable' when at least one protocol provide an valid address.
5064 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv
='-4')
5065 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
5068 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
5070 self
.assertRegex(output
, '192.168.5.1')
5071 self
.assertRegex(output
, '2600::1')
5073 # TODO: check json string
5074 check_output(*networkctl_cmd
, '--json=short', 'status', env
=env
)
5076 def test_dhcp_client_use_dns_no(self
):
5077 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-no.network')
5080 self
.wait_online(['veth-peer:carrier'])
5081 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
5082 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
5084 # link become 'routable' when at least one protocol provide an valid address.
5085 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv
='-4')
5086 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
5089 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
5091 self
.assertNotRegex(output
, '192.168.5.1')
5092 self
.assertNotRegex(output
, '2600::1')
5094 def test_dhcp_client_use_dns_ipv4(self
):
5095 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4.network')
5098 self
.wait_online(['veth-peer:carrier'])
5099 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
5100 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
5102 # link become 'routable' when at least one protocol provide an valid address.
5103 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv
='-4')
5104 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
5107 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
5109 self
.assertRegex(output
, '192.168.5.1')
5110 self
.assertNotRegex(output
, '2600::1')
5112 def test_dhcp_client_use_dns_ipv4_and_ra(self
):
5113 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4-and-ra.network')
5116 self
.wait_online(['veth-peer:carrier'])
5117 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
5118 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
5120 # link become 'routable' when at least one protocol provide an valid address.
5121 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv
='-4')
5122 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
5125 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
5127 self
.assertRegex(output
, '192.168.5.1')
5128 self
.assertRegex(output
, '2600::1')
5130 def test_dhcp_client_use_domains(self
):
5131 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-domains.network')
5134 self
.wait_online(['veth-peer:carrier'])
5135 start_dnsmasq('--dhcp-option=option:domain-search,example.com')
5136 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
5138 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
5140 self
.assertRegex(output
, 'Search Domains: example.com')
5143 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
5145 self
.assertRegex(output
, 'example.com')
5147 def test_dhcp_client_decline(self
):
5148 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-decline.network', 'dhcp-client-decline.network')
5151 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
5153 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
5155 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
5157 def test_dhcp_client_allow_list(self
):
5158 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-decline.network', 'dhcp-client-allow-list.network')
5161 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
5163 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
5165 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
5167 class NetworkdDHCPPDTests(unittest
.TestCase
, Utilities
):
5183 '25-veth-downstream-veth97.netdev',
5184 '25-veth-downstream-veth98.netdev',
5185 '80-6rd-tunnel.network',
5186 'dhcp-pd-downstream-dummy97.network',
5187 'dhcp-pd-downstream-dummy98.network',
5188 'dhcp-pd-downstream-dummy99.network',
5189 'dhcp-pd-downstream-test1.network',
5190 'dhcp-pd-downstream-veth97.network',
5191 'dhcp-pd-downstream-veth97-peer.network',
5192 'dhcp-pd-downstream-veth98.network',
5193 'dhcp-pd-downstream-veth98-peer.network',
5194 'dhcp4-6rd-server.network',
5195 'dhcp4-6rd-upstream.network',
5196 'dhcp6pd-server.network',
5197 'dhcp6pd-upstream.network',
5203 remove_links(self
.links
)
5204 stop_networkd(show_logs
=False)
5209 remove_links(self
.links
)
5210 remove_unit_from_networkd_path(self
.units
)
5211 stop_networkd(show_logs
=True)
5213 def test_dhcp6pd(self
):
5214 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp6pd-server.network', 'dhcp6pd-upstream.network',
5215 '25-veth-downstream-veth97.netdev', 'dhcp-pd-downstream-veth97.network', 'dhcp-pd-downstream-veth97-peer.network',
5216 '25-veth-downstream-veth98.netdev', 'dhcp-pd-downstream-veth98.network', 'dhcp-pd-downstream-veth98-peer.network',
5217 '11-dummy.netdev', 'dhcp-pd-downstream-test1.network',
5218 'dhcp-pd-downstream-dummy97.network',
5219 '12-dummy.netdev', 'dhcp-pd-downstream-dummy98.network',
5220 '13-dummy.netdev', 'dhcp-pd-downstream-dummy99.network')
5223 self
.wait_online(['veth-peer:routable'])
5224 start_isc_dhcpd('veth-peer', 'isc-dhcpd-dhcp6pd.conf', ip
='-6')
5225 self
.wait_online(['veth99:routable', 'test1:routable', 'dummy98:routable', 'dummy99:degraded',
5226 'veth97:routable', 'veth97-peer:routable', 'veth98:routable', 'veth98-peer:routable'])
5228 print('### ip -6 address show dev veth-peer scope global')
5229 output
= check_output('ip -6 address show dev veth-peer scope global')
5231 self
.assertIn('inet6 3ffe:501:ffff:100::1/64 scope global', output
)
5235 # dummy97: 0x01 (The link will appear later)
5237 # dummy99: auto -> 0x03 (No address assignment)
5240 # veth99: 0x10 (ignored, as it is upstream)
5242 print('### ip -6 address show dev veth99 scope global')
5243 output
= check_output('ip -6 address show dev veth99 scope global')
5246 self
.assertRegex(output
, 'inet6 3ffe:501:ffff:100::[0-9]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
5247 # address in IA_PD (Token=static)
5248 self
.assertRegex(output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/56 (metric 256 |)scope global dynamic')
5249 # address in IA_PD (Token=eui64)
5250 self
.assertRegex(output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1034:56ff:fe78:9abc/56 (metric 256 |)scope global dynamic')
5252 print('### ip -6 address show dev test1 scope global')
5253 output
= check_output('ip -6 address show dev test1 scope global')
5255 # address in IA_PD (Token=static)
5256 self
.assertRegex(output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5257 # address in IA_PD (temporary)
5258 # Note that the temporary addresses may appear after the link enters configured state
5259 self
.wait_address('test1', 'inet6 3ffe:501:ffff:[2-9a-f]00:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv
='-6')
5261 print('### ip -6 address show dev dummy98 scope global')
5262 output
= check_output('ip -6 address show dev dummy98 scope global')
5264 # address in IA_PD (Token=static)
5265 self
.assertRegex(output
, 'inet6 3ffe:501:ffff:[2-9a-f]02:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5266 # address in IA_PD (temporary)
5267 self
.wait_address('dummy98', 'inet6 3ffe:501:ffff:[2-9a-f]02:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv
='-6')
5269 print('### ip -6 address show dev dummy99 scope global')
5270 output
= check_output('ip -6 address show dev dummy99 scope global')
5273 self
.assertNotRegex(output
, 'inet6 3ffe:501:ffff:[2-9a-f]03')
5275 print('### ip -6 address show dev veth97 scope global')
5276 output
= check_output('ip -6 address show dev veth97 scope global')
5278 # address in IA_PD (Token=static)
5279 self
.assertRegex(output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5280 # address in IA_PD (Token=eui64)
5281 self
.assertRegex(output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr')
5282 # address in IA_PD (temporary)
5283 self
.wait_address('veth97', 'inet6 3ffe:501:ffff:[2-9a-f]08:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv
='-6')
5285 print('### ip -6 address show dev veth97-peer scope global')
5286 output
= check_output('ip -6 address show dev veth97-peer scope global')
5288 # NDisc address (Token=static)
5289 self
.assertRegex(output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
5290 # NDisc address (Token=eui64)
5291 self
.assertRegex(output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr')
5292 # NDisc address (temporary)
5293 self
.wait_address('veth97-peer', 'inet6 3ffe:501:ffff:[2-9a-f]08:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv
='-6')
5295 print('### ip -6 address show dev veth98 scope global')
5296 output
= check_output('ip -6 address show dev veth98 scope global')
5298 # address in IA_PD (Token=static)
5299 self
.assertRegex(output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5300 # address in IA_PD (Token=eui64)
5301 self
.assertRegex(output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr')
5302 # address in IA_PD (temporary)
5303 self
.wait_address('veth98', 'inet6 3ffe:501:ffff:[2-9a-f]09:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv
='-6')
5305 print('### ip -6 address show dev veth98-peer scope global')
5306 output
= check_output('ip -6 address show dev veth98-peer scope global')
5308 # NDisc address (Token=static)
5309 self
.assertRegex(output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
5310 # NDisc address (Token=eui64)
5311 self
.assertRegex(output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr')
5312 # NDisc address (temporary)
5313 self
.wait_address('veth98-peer', 'inet6 3ffe:501:ffff:[2-9a-f]09:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv
='-6')
5315 print('### ip -6 route show type unreachable')
5316 output
= check_output('ip -6 route show type unreachable')
5318 self
.assertRegex(output
, 'unreachable 3ffe:501:ffff:[2-9a-f]00::/56 dev lo proto dhcp')
5320 print('### ip -6 route show dev veth99')
5321 output
= check_output('ip -6 route show dev veth99')
5323 self
.assertRegex(output
, '3ffe:501:ffff:[2-9a-f]00::/56 proto kernel metric [0-9]* expires')
5325 print('### ip -6 route show dev test1')
5326 output
= check_output('ip -6 route show dev test1')
5328 self
.assertRegex(output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires')
5330 print('### ip -6 route show dev dummy98')
5331 output
= check_output('ip -6 route show dev dummy98')
5333 self
.assertRegex(output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto kernel metric [0-9]* expires')
5335 print('### ip -6 route show dev dummy99')
5336 output
= check_output('ip -6 route show dev dummy99')
5338 self
.assertRegex(output
, '3ffe:501:ffff:[2-9a-f]03::/64 proto dhcp metric [0-9]* expires')
5340 print('### ip -6 route show dev veth97')
5341 output
= check_output('ip -6 route show dev veth97')
5343 self
.assertRegex(output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto kernel metric [0-9]* expires')
5345 print('### ip -6 route show dev veth97-peer')
5346 output
= check_output('ip -6 route show dev veth97-peer')
5348 self
.assertRegex(output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto ra metric [0-9]* expires')
5350 print('### ip -6 route show dev veth98')
5351 output
= check_output('ip -6 route show dev veth98')
5353 self
.assertRegex(output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto kernel metric [0-9]* expires')
5355 print('### ip -6 route show dev veth98-peer')
5356 output
= check_output('ip -6 route show dev veth98-peer')
5358 self
.assertRegex(output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto ra metric [0-9]* expires')
5360 # Test case for a downstream which appears later
5361 check_output('ip link add dummy97 type dummy')
5362 self
.wait_online(['dummy97:routable'])
5364 print('### ip -6 address show dev dummy97 scope global')
5365 output
= check_output('ip -6 address show dev dummy97 scope global')
5367 # address in IA_PD (Token=static)
5368 self
.assertRegex(output
, 'inet6 3ffe:501:ffff:[2-9a-f]01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5369 # address in IA_PD (temporary)
5370 self
.wait_address('dummy97', 'inet6 3ffe:501:ffff:[2-9a-f]01:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv
='-6')
5372 print('### ip -6 route show dev dummy97')
5373 output
= check_output('ip -6 route show dev dummy97')
5375 self
.assertRegex(output
, '3ffe:501:ffff:[2-9a-f]01::/64 proto kernel metric [0-9]* expires')
5377 # Test case for reconfigure
5378 check_output(*networkctl_cmd
, 'reconfigure', 'dummy98', 'dummy99', env
=env
)
5379 self
.wait_online(['dummy98:routable'])
5381 print('### ip -6 address show dev dummy98 scope global')
5382 output
= check_output('ip -6 address show dev dummy98 scope global')
5384 # address in IA_PD (Token=static)
5385 self
.assertRegex(output
, 'inet6 3ffe:501:ffff:[2-9a-f]02:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5386 # address in IA_PD (temporary)
5387 self
.wait_address('dummy98', 'inet6 3ffe:501:ffff:[2-9a-f]02:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv
='-6')
5389 print('### ip -6 address show dev dummy99 scope global')
5390 output
= check_output('ip -6 address show dev dummy99 scope global')
5393 self
.assertNotRegex(output
, 'inet6 3ffe:501:ffff:[2-9a-f]03')
5395 print('### ip -6 route show dev dummy98')
5396 output
= check_output('ip -6 route show dev dummy98')
5398 self
.assertRegex(output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto kernel metric [0-9]* expires')
5400 print('### ip -6 route show dev dummy99')
5401 output
= check_output('ip -6 route show dev dummy99')
5403 self
.assertRegex(output
, '3ffe:501:ffff:[2-9a-f]03::/64 proto dhcp metric [0-9]* expires')
5405 def verify_dhcp4_6rd(self
, tunnel_name
):
5406 print('### ip -4 address show dev veth-peer scope global')
5407 output
= check_output('ip -4 address show dev veth-peer scope global')
5409 self
.assertIn('inet 10.0.0.1/8 brd 10.255.255.255 scope global veth-peer', output
)
5413 # dummy97: 0x01 (The link will appear later)
5415 # dummy99: auto -> 0x03 (No address assignment)
5420 print('### ip -4 address show dev veth99 scope global')
5421 output
= check_output('ip -4 address show dev veth99 scope global')
5423 self
.assertRegex(output
, 'inet 10.100.100.[0-9]*/8 (metric 1024 |)brd 10.255.255.255 scope global dynamic veth99')
5425 print('### ip -6 address show dev veth99 scope global')
5426 output
= check_output('ip -6 address show dev veth99 scope global')
5428 # address in IA_PD (Token=static)
5429 self
.assertRegex(output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5430 # address in IA_PD (Token=eui64)
5431 self
.assertRegex(output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic mngtmpaddr')
5432 # address in IA_PD (temporary)
5433 # Note that the temporary addresses may appear after the link enters configured state
5434 self
.wait_address('veth99', 'inet6 2001:db8:6464:[0-9a-f]+10:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv
='-6')
5436 print('### ip -6 address show dev test1 scope global')
5437 output
= check_output('ip -6 address show dev test1 scope global')
5439 # address in IA_PD (Token=static)
5440 self
.assertRegex(output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5441 # address in IA_PD (temporary)
5442 self
.wait_address('test1', 'inet6 2001:db8:6464:[0-9a-f]+00:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv
='-6')
5444 print('### ip -6 address show dev dummy98 scope global')
5445 output
= check_output('ip -6 address show dev dummy98 scope global')
5447 # address in IA_PD (Token=static)
5448 self
.assertRegex(output
, 'inet6 2001:db8:6464:[0-9a-f]+02:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5449 # address in IA_PD (temporary)
5450 self
.wait_address('dummy98', 'inet6 2001:db8:6464:[0-9a-f]+02:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv
='-6')
5452 print('### ip -6 address show dev dummy99 scope global')
5453 output
= check_output('ip -6 address show dev dummy99 scope global')
5456 self
.assertNotRegex(output
, 'inet6 2001:db8:6464:[0-9a-f]+03')
5458 print('### ip -6 address show dev veth97 scope global')
5459 output
= check_output('ip -6 address show dev veth97 scope global')
5461 # address in IA_PD (Token=static)
5462 self
.assertRegex(output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5463 # address in IA_PD (Token=eui64)
5464 self
.assertRegex(output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr')
5465 # address in IA_PD (temporary)
5466 self
.wait_address('veth97', 'inet6 2001:db8:6464:[0-9a-f]+08:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv
='-6')
5468 print('### ip -6 address show dev veth97-peer scope global')
5469 output
= check_output('ip -6 address show dev veth97-peer scope global')
5471 # NDisc address (Token=static)
5472 self
.assertRegex(output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
5473 # NDisc address (Token=eui64)
5474 self
.assertRegex(output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr')
5475 # NDisc address (temporary)
5476 self
.wait_address('veth97-peer', 'inet6 2001:db8:6464:[0-9a-f]+08:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv
='-6')
5478 print('### ip -6 address show dev veth98 scope global')
5479 output
= check_output('ip -6 address show dev veth98 scope global')
5481 # address in IA_PD (Token=static)
5482 self
.assertRegex(output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5483 # address in IA_PD (Token=eui64)
5484 self
.assertRegex(output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr')
5485 # address in IA_PD (temporary)
5486 self
.wait_address('veth98', 'inet6 2001:db8:6464:[0-9a-f]+09:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv
='-6')
5488 print('### ip -6 address show dev veth98-peer scope global')
5489 output
= check_output('ip -6 address show dev veth98-peer scope global')
5491 # NDisc address (Token=static)
5492 self
.assertRegex(output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
5493 # NDisc address (Token=eui64)
5494 self
.assertRegex(output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr')
5495 # NDisc address (temporary)
5496 self
.wait_address('veth98-peer', 'inet6 2001:db8:6464:[0-9a-f]+09:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv
='-6')
5498 print('### ip -6 route show type unreachable')
5499 output
= check_output('ip -6 route show type unreachable')
5501 self
.assertRegex(output
, 'unreachable 2001:db8:6464:[0-9a-f]+00::/56 dev lo proto dhcp')
5503 print('### ip -6 route show dev veth99')
5504 output
= check_output('ip -6 route show dev veth99')
5506 self
.assertRegex(output
, '2001:db8:6464:[0-9a-f]+10::/64 proto kernel metric [0-9]* expires')
5508 print('### ip -6 route show dev test1')
5509 output
= check_output('ip -6 route show dev test1')
5511 self
.assertRegex(output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires')
5513 print('### ip -6 route show dev dummy98')
5514 output
= check_output('ip -6 route show dev dummy98')
5516 self
.assertRegex(output
, '2001:db8:6464:[0-9a-f]+02::/64 proto kernel metric [0-9]* expires')
5518 print('### ip -6 route show dev dummy99')
5519 output
= check_output('ip -6 route show dev dummy99')
5521 self
.assertRegex(output
, '2001:db8:6464:[0-9a-f]+03::/64 proto dhcp metric [0-9]* expires')
5523 print('### ip -6 route show dev veth97')
5524 output
= check_output('ip -6 route show dev veth97')
5526 self
.assertRegex(output
, '2001:db8:6464:[0-9a-f]+08::/64 proto kernel metric [0-9]* expires')
5528 print('### ip -6 route show dev veth97-peer')
5529 output
= check_output('ip -6 route show dev veth97-peer')
5531 self
.assertRegex(output
, '2001:db8:6464:[0-9a-f]+08::/64 proto ra metric [0-9]* expires')
5533 print('### ip -6 route show dev veth98')
5534 output
= check_output('ip -6 route show dev veth98')
5536 self
.assertRegex(output
, '2001:db8:6464:[0-9a-f]+09::/64 proto kernel metric [0-9]* expires')
5538 print('### ip -6 route show dev veth98-peer')
5539 output
= check_output('ip -6 route show dev veth98-peer')
5541 self
.assertRegex(output
, '2001:db8:6464:[0-9a-f]+09::/64 proto ra metric [0-9]* expires')
5543 print('### ip -6 address show dev dummy97 scope global')
5544 output
= check_output('ip -6 address show dev dummy97 scope global')
5546 # address in IA_PD (Token=static)
5547 self
.assertRegex(output
, 'inet6 2001:db8:6464:[0-9a-f]+01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5548 # address in IA_PD (temporary)
5549 self
.wait_address('dummy97', 'inet6 2001:db8:6464:[0-9a-f]+01:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv
='-6')
5551 print('### ip -6 route show dev dummy97')
5552 output
= check_output('ip -6 route show dev dummy97')
5554 self
.assertRegex(output
, '2001:db8:6464:[0-9a-f]+01::/64 proto kernel metric [0-9]* expires')
5556 print('### ip -d link show dev {}'.format(tunnel_name
))
5557 output
= check_output('ip -d link show dev {}'.format(tunnel_name
))
5559 self
.assertIn('link/sit 10.100.100.', output
)
5560 self
.assertIn('local 10.100.100.', output
)
5561 self
.assertIn('ttl 64', output
)
5562 self
.assertIn('6rd-prefix 2001:db8::/32', output
)
5563 self
.assertIn('6rd-relay_prefix 10.0.0.0/8', output
)
5565 print('### ip -6 address show dev {}'.format(tunnel_name
))
5566 output
= check_output('ip -6 address show dev {}'.format(tunnel_name
))
5568 self
.assertRegex(output
, 'inet6 2001:db8:6464:[0-9a-f]+00:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/56 (metric 256 |)scope global dynamic')
5569 self
.assertRegex(output
, 'inet6 ::10.100.100.[0-9]+/96 scope global')
5571 print('### ip -6 route show dev {}'.format(tunnel_name
))
5572 output
= check_output('ip -6 route show dev {}'.format(tunnel_name
))
5574 self
.assertRegex(output
, '2001:db8:6464:[0-9a-f]+00::/56 proto kernel metric [0-9]* expires')
5575 self
.assertRegex(output
, '::/96 proto kernel metric [0-9]*')
5577 print('### ip -6 route show default')
5578 output
= check_output('ip -6 route show default')
5580 self
.assertIn('default', output
)
5581 self
.assertIn('via ::10.0.0.1 dev {}'.format(tunnel_name
), output
)
5583 def test_dhcp4_6rd(self
):
5584 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp4-6rd-server.network', 'dhcp4-6rd-upstream.network',
5585 '25-veth-downstream-veth97.netdev', 'dhcp-pd-downstream-veth97.network', 'dhcp-pd-downstream-veth97-peer.network',
5586 '25-veth-downstream-veth98.netdev', 'dhcp-pd-downstream-veth98.network', 'dhcp-pd-downstream-veth98-peer.network',
5587 '11-dummy.netdev', 'dhcp-pd-downstream-test1.network',
5588 'dhcp-pd-downstream-dummy97.network',
5589 '12-dummy.netdev', 'dhcp-pd-downstream-dummy98.network',
5590 '13-dummy.netdev', 'dhcp-pd-downstream-dummy99.network',
5591 '80-6rd-tunnel.network')
5594 self
.wait_online(['veth-peer:routable'])
5597 # 6rd-prefix: 2001:db8::/32
5598 # br-addresss: 10.0.0.1
5600 start_dnsmasq(additional_options
='--dhcp-option=212,08:20:20:01:0d:b8:00:00:00:00:00:00:00:00:00:00:00:00:0a:00:00:01', ipv4_range
='10.100.100.100,10.100.100.200', ipv4_router
='10.0.0.1', lease_time
='2m')
5601 self
.wait_online(['veth99:routable', 'test1:routable', 'dummy98:routable', 'dummy99:degraded',
5602 'veth97:routable', 'veth97-peer:routable', 'veth98:routable', 'veth98-peer:routable'])
5604 # Test case for a downstream which appears later
5605 check_output('ip link add dummy97 type dummy')
5606 self
.wait_online(['dummy97:routable'])
5610 for name
in os
.listdir('/sys/class/net/'):
5611 if name
.startswith('6rd-'):
5615 self
.wait_online(['{}:routable'.format(tunnel_name
)])
5617 self
.verify_dhcp4_6rd(tunnel_name
)
5619 # Test case for reconfigure
5620 check_output(*networkctl_cmd
, 'reconfigure', 'dummy98', 'dummy99', env
=env
)
5621 self
.wait_online(['dummy98:routable', 'dummy99:degraded'])
5623 self
.verify_dhcp4_6rd(tunnel_name
)
5625 # Test for renewing/rebinding lease
5626 print('wait for 120 sec')
5628 print('wait for 90 sec')
5630 print('wait for 60 sec')
5632 print('wait for 30 sec')
5635 dump_dnsmasq_log_file()
5637 self
.wait_online(['veth99:routable', 'test1:routable', 'dummy97:routable', 'dummy98:routable', 'dummy99:degraded',
5638 'veth97:routable', 'veth97-peer:routable', 'veth98:routable', 'veth98-peer:routable'])
5640 self
.verify_dhcp4_6rd(tunnel_name
)
5642 class NetworkdIPv6PrefixTests(unittest
.TestCase
, Utilities
):
5651 'ipv6ra-prefix-client-deny-list.network',
5652 'ipv6ra-prefix-client.network',
5653 'ipv6ra-prefix.network',
5654 'ipv6ra-uplink.network',
5658 remove_links(self
.links
)
5659 stop_networkd(show_logs
=False)
5662 remove_links(self
.links
)
5663 remove_unit_from_networkd_path(self
.units
)
5664 stop_networkd(show_logs
=True)
5666 def test_ipv6_route_prefix(self
):
5667 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client.network', 'ipv6ra-prefix.network',
5668 '12-dummy.netdev', 'ipv6ra-uplink.network')
5671 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'dummy98:routable'])
5673 output
= check_output('ip address show dev veth-peer')
5675 self
.assertIn('inet6 2001:db8:0:1:', output
)
5676 self
.assertNotIn('inet6 2001:db8:0:2:', output
)
5677 self
.assertNotIn('inet6 2001:db8:0:3:', output
)
5679 output
= check_output('ip -6 route show dev veth-peer')
5681 self
.assertIn('2001:db8:0:1::/64 proto ra', output
)
5682 self
.assertNotIn('2001:db8:0:2::/64 proto ra', output
)
5683 self
.assertNotIn('2001:db8:0:3::/64 proto ra', output
)
5684 self
.assertIn('2001:db0:fff::/64 via ', output
)
5685 self
.assertNotIn('2001:db1:fff::/64 via ', output
)
5686 self
.assertNotIn('2001:db2:fff::/64 via ', output
)
5688 output
= check_output('ip address show dev veth99')
5690 self
.assertNotIn('inet6 2001:db8:0:1:', output
)
5691 self
.assertIn('inet6 2001:db8:0:2:1a:2b:3c:4d', output
)
5692 self
.assertIn('inet6 2001:db8:0:2:fa:de:ca:fe', output
)
5693 self
.assertNotIn('inet6 2001:db8:0:3:', output
)
5695 output
= check_output(*resolvectl_cmd
, 'dns', 'veth-peer', env
=env
)
5697 self
.assertRegex(output
, '2001:db8:1:1::2')
5699 output
= check_output(*resolvectl_cmd
, 'domain', 'veth-peer', env
=env
)
5701 self
.assertIn('example.com', output
)
5703 # TODO: check json string
5704 check_output(*networkctl_cmd
, '--json=short', 'status', env
=env
)
5706 def test_ipv6_route_prefix_deny_list(self
):
5707 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client-deny-list.network', 'ipv6ra-prefix.network',
5708 '12-dummy.netdev', 'ipv6ra-uplink.network')
5711 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'dummy98:routable'])
5713 output
= check_output('ip address show dev veth-peer')
5715 self
.assertIn('inet6 2001:db8:0:1:', output
)
5716 self
.assertNotIn('inet6 2001:db8:0:2:', output
)
5718 output
= check_output('ip -6 route show dev veth-peer')
5720 self
.assertIn('2001:db8:0:1::/64 proto ra', output
)
5721 self
.assertNotIn('2001:db8:0:2::/64 proto ra', output
)
5722 self
.assertIn('2001:db0:fff::/64 via ', output
)
5723 self
.assertNotIn('2001:db1:fff::/64 via ', output
)
5725 output
= check_output('ip address show dev veth99')
5727 self
.assertNotIn('inet6 2001:db8:0:1:', output
)
5728 self
.assertIn('inet6 2001:db8:0:2:', output
)
5730 output
= check_output(*resolvectl_cmd
, 'dns', 'veth-peer', env
=env
)
5732 self
.assertRegex(output
, '2001:db8:1:1::2')
5734 output
= check_output(*resolvectl_cmd
, 'domain', 'veth-peer', env
=env
)
5736 self
.assertIn('example.com', output
)
5738 class NetworkdMTUTests(unittest
.TestCase
, Utilities
):
5743 '12-dummy-mtu.netdev',
5744 '12-dummy-mtu.link',
5749 remove_links(self
.links
)
5750 stop_networkd(show_logs
=False)
5753 remove_links(self
.links
)
5754 remove_unit_from_networkd_path(self
.units
)
5755 stop_networkd(show_logs
=True)
5757 def check_mtu(self
, mtu
, ipv6_mtu
=None, reset
=True):
5763 self
.wait_online(['dummy98:routable'])
5764 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
5765 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
5767 # test normal restart
5769 self
.wait_online(['dummy98:routable'])
5770 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
5771 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
5774 self
.reset_check_mtu(mtu
, ipv6_mtu
)
5776 def reset_check_mtu(self
, mtu
, ipv6_mtu
=None):
5777 ''' test setting mtu/ipv6_mtu with interface already up '''
5780 # note - changing the device mtu resets the ipv6 mtu
5781 run('ip link set up mtu 1501 dev dummy98')
5782 run('ip link set up mtu 1500 dev dummy98')
5783 self
.assertEqual(read_link_attr('dummy98', 'mtu'), '1500')
5784 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), '1500')
5786 self
.check_mtu(mtu
, ipv6_mtu
, reset
=False)
5788 def test_mtu_network(self
):
5789 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
5790 self
.check_mtu('1600')
5792 def test_mtu_netdev(self
):
5793 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network', dropins
=False)
5794 # note - MTU set by .netdev happens ONLY at device creation!
5795 self
.check_mtu('1600', reset
=False)
5797 def test_mtu_link(self
):
5798 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', dropins
=False)
5799 # must reload udev because it only picks up new files after 3 second delay
5800 call('udevadm control --reload')
5801 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
5802 self
.check_mtu('1600', reset
=False)
5804 def test_ipv6_mtu(self
):
5805 ''' set ipv6 mtu without setting device mtu '''
5806 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
5807 self
.check_mtu('1500', '1400')
5809 def test_ipv6_mtu_toolarge(self
):
5810 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
5811 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
5812 self
.check_mtu('1500', '1500')
5814 def test_mtu_network_ipv6_mtu(self
):
5815 ''' set ipv6 mtu and set device mtu via network file '''
5816 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
5817 self
.check_mtu('1600', '1550')
5819 def test_mtu_netdev_ipv6_mtu(self
):
5820 ''' set ipv6 mtu and set device mtu via netdev file '''
5821 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
5822 self
.check_mtu('1600', '1550', reset
=False)
5824 def test_mtu_link_ipv6_mtu(self
):
5825 ''' set ipv6 mtu and set device mtu via link file '''
5826 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
5827 # must reload udev because it only picks up new files after 3 second delay
5828 call('udevadm control --reload')
5829 self
.check_mtu('1600', '1550', reset
=False)
5832 if __name__
== '__main__':
5833 parser
= argparse
.ArgumentParser()
5834 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
5835 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
5836 parser
.add_argument('--resolved', help='Path to systemd-resolved', dest
='resolved_bin')
5837 parser
.add_argument('--udevd', help='Path to systemd-udevd', dest
='udevd_bin')
5838 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
5839 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
5840 parser
.add_argument('--resolvectl', help='Path to resolvectl', dest
='resolvectl_bin')
5841 parser
.add_argument('--timedatectl', help='Path to timedatectl', dest
='timedatectl_bin')
5842 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
5843 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
5844 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
5845 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
5846 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
5847 parser
.add_argument('--with-coverage', help='Loosen certain sandbox restrictions to make gcov happy', dest
='with_coverage', type=bool, nargs
='?', const
=True, default
=with_coverage
)
5848 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
5851 if ns
.networkd_bin
or ns
.resolved_bin
or ns
.udevd_bin
or ns
.wait_online_bin
or ns
.networkctl_bin
or ns
.resolvectl_bin
or ns
.timedatectl_bin
:
5852 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
5853 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
5854 resolved_bin
= os
.path
.join(ns
.build_dir
, 'systemd-resolved')
5855 udevd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-udevd')
5856 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
5857 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
5858 resolvectl_bin
= os
.path
.join(ns
.build_dir
, 'resolvectl')
5859 timedatectl_bin
= os
.path
.join(ns
.build_dir
, 'timedatectl')
5862 networkd_bin
= ns
.networkd_bin
5864 resolved_bin
= ns
.resolved_bin
5866 udevd_bin
= ns
.udevd_bin
5867 if ns
.wait_online_bin
:
5868 wait_online_bin
= ns
.wait_online_bin
5869 if ns
.networkctl_bin
:
5870 networkctl_bin
= ns
.networkctl_bin
5871 if ns
.resolvectl_bin
:
5872 resolvectl_bin
= ns
.resolvectl_bin
5873 if ns
.timedatectl_bin
:
5874 timedatectl_bin
= ns
.timedatectl_bin
5876 use_valgrind
= ns
.use_valgrind
5877 enable_debug
= ns
.enable_debug
5878 asan_options
= ns
.asan_options
5879 lsan_options
= ns
.lsan_options
5880 ubsan_options
= ns
.ubsan_options
5881 with_coverage
= ns
.with_coverage
5884 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
5885 resolvectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin
]
5886 timedatectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin
]
5887 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
5889 networkctl_cmd
= [networkctl_bin
]
5890 resolvectl_cmd
= [resolvectl_bin
]
5891 timedatectl_cmd
= [timedatectl_bin
]
5892 wait_online_cmd
= [wait_online_bin
]
5895 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
5897 env
.update({ 'ASAN_OPTIONS' : asan_options
})
5899 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
5901 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
5904 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,