]>
git.ipfire.org Git - thirdparty/systemd.git/blob - test/test-network/systemd-networkd-tests.py
2 # SPDX-License-Identifier: LGPL-2.1-or-later
3 # pylint: disable=line-too-long,too-many-lines,too-many-branches,too-many-statements,too-many-arguments
4 # pylint: disable=too-many-public-methods,too-many-boolean-expressions,invalid-name
5 # pylint: disable=missing-function-docstring,missing-class-docstring,missing-module-docstring
6 # systemd-networkd tests
8 # These tests can be executed in the systemd mkosi image when booted in QEMU. After booting the QEMU VM,
9 # simply run this file which can be found in the VM at /usr/lib/systemd/tests/testdata/test-network/systemd-networkd-tests.py.
27 network_unit_dir
= '/run/systemd/network'
28 networkd_conf_dropin_dir
= '/run/systemd/networkd.conf.d'
29 networkd_ci_temp_dir
= '/run/networkd-ci'
30 udev_rules_dir
= '/run/udev/rules.d'
32 dnsmasq_pid_file
= '/run/networkd-ci/test-dnsmasq.pid'
33 dnsmasq_log_file
= '/run/networkd-ci/test-dnsmasq.log'
34 dnsmasq_lease_file
= '/run/networkd-ci/test-dnsmasq.lease'
36 isc_dhcpd_pid_file
= '/run/networkd-ci/test-isc-dhcpd.pid'
37 isc_dhcpd_lease_file
= '/run/networkd-ci/test-isc-dhcpd.lease'
39 radvd_pid_file
= '/run/networkd-ci/test-radvd.pid'
41 systemd_lib_paths
= [ '/usr/lib/systemd' , '/lib/systemd' ]
42 which_paths
= ':' . join ( systemd_lib_paths
+ os
. getenv ( 'PATH' , os
. defpath
). lstrip ( ':' ). split ( ':' ))
44 networkd_bin
= shutil
. which ( 'systemd-networkd' , path
= which_paths
)
45 resolved_bin
= shutil
. which ( 'systemd-resolved' , path
= which_paths
)
46 timesyncd_bin
= shutil
. which ( 'systemd-timesyncd' , path
= which_paths
)
47 udevd_bin
= shutil
. which ( 'systemd-udevd' , path
= which_paths
)
48 wait_online_bin
= shutil
. which ( 'systemd-networkd-wait-online' , path
= which_paths
)
49 networkctl_bin
= shutil
. which ( 'networkctl' , path
= which_paths
)
50 resolvectl_bin
= shutil
. which ( 'resolvectl' , path
= which_paths
)
51 timedatectl_bin
= shutil
. which ( 'timedatectl' , path
= which_paths
)
52 udevadm_bin
= shutil
. which ( 'udevadm' , path
= which_paths
)
80 saved_ipv4_rules
= None
81 saved_ipv6_rules
= None
85 if os
. path
. exists ( path
):
89 shutil
. rmtree ( path
, ignore_errors
= True )
95 shutil
. copytree ( src
, dst
, copy_function
= shutil
. copy
)
98 os
. makedirs ( path
, exist_ok
= True )
101 pathlib
. Path ( path
). touch ()
103 # pylint: disable=R1710
104 def check_output (* command
, ** kwargs
):
105 # This checks the result and returns stdout (and stderr) on success.
106 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
107 ret
= subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. PIPE
, stderr
= subprocess
. STDOUT
, ** kwargs
)
108 if ret
. returncode
== 0 :
109 return ret
. stdout
. rstrip ()
110 # When returncode != 0, print stdout and stderr, then trigger CalledProcessError.
112 ret
. check_returncode ()
114 def call (* command
, ** kwargs
):
115 # This returns returncode. stdout and stderr are merged and shown in console
116 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
117 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stderr
= subprocess
. STDOUT
, ** kwargs
). returncode
119 def call_check (* command
, ** kwargs
):
120 # Same as call() above, but it triggers CalledProcessError if rc != 0
121 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
122 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stderr
= subprocess
. STDOUT
, ** kwargs
). check_returncode ()
124 def call_quiet (* command
, ** kwargs
):
125 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
126 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. DEVNULL
, stderr
= subprocess
. DEVNULL
, ** kwargs
). returncode
128 def run (* command
, ** kwargs
):
129 # This returns CompletedProcess instance.
130 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
131 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. PIPE
, stderr
= subprocess
. PIPE
, ** kwargs
)
133 def check_json ( string
):
136 except json
. JSONDecodeError
:
137 print ( f
"String is not a valid JSON: ' {string} '" )
140 def is_module_available (* module_names
):
141 for module_name
in module_names
:
142 lsmod_output
= check_output ( 'lsmod' )
143 module_re
= re
. compile ( rf
'^{re.escape(module_name)} \b ' , re
. MULTILINE
)
144 if not module_re
. search ( lsmod_output
) and call_quiet ( 'modprobe' , module_name
) != 0 :
148 def expectedFailureIfModuleIsNotAvailable (* module_names
):
150 return func
if is_module_available (* module_names
) else unittest
. expectedFailure ( func
)
154 def expectedFailureIfERSPANv0IsNotSupported ():
155 # erspan version 0 is supported since f989d546a2d5a9f001f6f8be49d98c10ab9b1897 (v5.8)
157 rc
= call_quiet ( 'ip link add dev erspan99 type erspan seq key 30 local 192.168.1.4 remote 192.168.1.1 erspan_ver 0' )
158 remove_link ( 'erspan99' )
159 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
163 def expectedFailureIfERSPANv2IsNotSupported ():
164 # erspan version 2 is supported since f551c91de262ba36b20c3ac19538afb4f4507441 (v4.16)
166 rc
= call_quiet ( 'ip link add dev erspan99 type erspan seq key 30 local 192.168.1.4 remote 192.168.1.1 erspan_ver 2' )
167 remove_link ( 'erspan99' )
168 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
172 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable ():
174 rc
= call_quiet ( 'ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7' )
175 call_quiet ( 'ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7' )
176 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
180 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable ():
182 rc
= call_quiet ( 'ip rule add not from 192.168.100.19 ipproto tcp table 7' )
183 call_quiet ( 'ip rule del not from 192.168.100.19 ipproto tcp table 7' )
184 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
188 def expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable ():
191 if call_quiet ( 'ip rule add from 192.168.100.19 table 7 uidrange 200-300' ) == 0 :
192 ret
= run ( 'ip rule list from 192.168.100.19 table 7' )
193 supported
= ret
. returncode
== 0 and 'uidrange 200-300' in ret
. stdout
194 call_quiet ( 'ip rule del from 192.168.100.19 table 7 uidrange 200-300' )
195 return func
if supported
else unittest
. expectedFailure ( func
)
199 def expectedFailureIfNexthopIsNotAvailable ():
201 rc
= call_quiet ( 'ip nexthop list' )
202 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
206 def expectedFailureIfRTA_VIAIsNotSupported ():
208 call_quiet ( 'ip link add dummy98 type dummy' )
209 call_quiet ( 'ip link set up dev dummy98' )
210 call_quiet ( 'ip route add 2001:1234:5:8fff:ff:ff:ff:fe/128 dev dummy98' )
211 rc
= call_quiet ( 'ip route add 10.10.10.10 via inet6 2001:1234:5:8fff:ff:ff:ff:fe dev dummy98' )
212 remove_link ( 'dummy98' )
213 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
217 def expectedFailureIfAlternativeNameIsNotAvailable ():
219 call_quiet ( 'ip link add dummy98 type dummy' )
221 call_quiet ( 'ip link prop add dev dummy98 altname hogehogehogehogehoge' ) == 0 and \
222 call_quiet ( 'ip link show dev hogehogehogehogehoge' ) == 0
223 remove_link ( 'dummy98' )
224 return func
if supported
else unittest
. expectedFailure ( func
)
228 def expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ():
230 def finalize ( func
, supported
):
231 call_quiet ( 'rmmod netdevsim' )
232 return func
if supported
else unittest
. expectedFailure ( func
)
234 call_quiet ( 'rmmod netdevsim' )
235 if call_quiet ( 'modprobe netdevsim' ) != 0 :
236 return finalize ( func
, False )
239 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
242 return finalize ( func
, False )
244 return finalize ( func
, os
. path
. exists ( '/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs' ))
248 # pylint: disable=C0415
249 def compare_kernel_version ( min_kernel_version
):
252 from packaging
import version
254 print ( 'Failed to import either platform or packaging module, assuming the comparison failed' )
257 # Get only the actual kernel version without any build/distro/arch stuff
258 # e.g. '5.18.5-200.fc36.x86_64' -> '5.18.5'
259 kver
= platform
. release (). split ( '-' )[ 0 ]
261 return version
. parse ( kver
) >= version
. parse ( min_kernel_version
)
264 check_output (* udevadm_cmd
, 'control' , '--reload' )
266 def copy_network_unit (* units
, copy_dropins
= True ):
268 Copy networkd unit files into the testbed.
270 Any networkd unit file type can be specified, as well as drop-in files.
272 By default, all drop-ins for a specified unit file are copied in;
273 to avoid that specify dropins=False.
275 When a drop-in file is specified, its unit file is also copied in automatically.
278 mkdir_p ( network_unit_dir
)
280 if copy_dropins
and os
. path
. exists ( os
. path
. join ( networkd_ci_temp_dir
, unit
+ '.d' )):
281 cp_r ( os
. path
. join ( networkd_ci_temp_dir
, unit
+ '.d' ), os
. path
. join ( network_unit_dir
, unit
+ '.d' ))
283 if unit
. endswith ( '.conf' ):
285 unit
= os
. path
. dirname ( dropin
). rstrip ( '.d' )
286 dropindir
= os
. path
. join ( network_unit_dir
, unit
+ '.d' )
288 cp ( os
. path
. join ( networkd_ci_temp_dir
, dropin
), dropindir
)
290 cp ( os
. path
. join ( networkd_ci_temp_dir
, unit
), network_unit_dir
)
292 if unit
. endswith ( '.link' ):
298 def remove_network_unit (* units
):
300 Remove previously copied unit files from the testbed.
302 Drop-ins will be removed automatically.
306 rm_f ( os
. path
. join ( network_unit_dir
, unit
))
307 rm_rf ( os
. path
. join ( network_unit_dir
, unit
+ '.d' ))
309 if unit
. endswith ( '.link' ) or unit
. endswith ( '.link.d' ):
315 def clear_network_units ():
317 if os
. path
. exists ( network_unit_dir
):
318 units
= os
. listdir ( network_unit_dir
)
320 if unit
. endswith ( '.link' ) or unit
. endswith ( '.link.d' ):
323 rm_rf ( network_unit_dir
)
328 def copy_networkd_conf_dropin (* dropins
):
329 """Copy networkd.conf dropin files into the testbed."""
330 mkdir_p ( networkd_conf_dropin_dir
)
331 for dropin
in dropins
:
332 cp ( os
. path
. join ( networkd_ci_temp_dir
, dropin
), networkd_conf_dropin_dir
)
334 def remove_networkd_conf_dropin (* dropins
):
335 """Remove previously copied networkd.conf dropin files from the testbed."""
336 for dropin
in dropins
:
337 rm_f ( os
. path
. join ( networkd_conf_dropin_dir
, dropin
))
339 def clear_networkd_conf_dropins ():
340 rm_rf ( networkd_conf_dropin_dir
)
342 def copy_udev_rule (* rules
):
343 """Copy udev rules"""
344 mkdir_p ( udev_rules_dir
)
346 cp ( os
. path
. join ( networkd_ci_temp_dir
, rule
), udev_rules_dir
)
348 def remove_udev_rule (* rules
):
349 """Remove previously copied udev rules"""
351 rm_f ( os
. path
. join ( udev_rules_dir
, rule
))
353 def clear_udev_rules ():
354 rm_rf ( udev_rules_dir
)
356 def save_active_units ():
357 for u
in [ 'systemd-networkd.socket' , 'systemd-networkd.service' ,
358 'systemd-resolved.service' , 'systemd-timesyncd.service' ,
359 'firewalld.service' ]:
360 if call ( f
'systemctl is-active --quiet {u} ' ) == 0 :
361 call ( f
'systemctl stop {u} ' )
362 active_units
. append ( u
)
364 def restore_active_units ():
365 if 'systemd-networkd.socket' in active_units
:
366 call ( 'systemctl stop systemd-networkd.socket systemd-networkd.service' )
367 for u
in active_units
:
368 call ( f
'systemctl restart {u} ' )
370 def create_unit_dropin ( unit
, contents
):
371 mkdir_p ( f
'/run/systemd/system/ {unit} .d' )
372 with
open ( f
'/run/systemd/system/ {unit} .d/00-override.conf' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
373 f
. write ( ' \n ' . join ( contents
))
375 def create_service_dropin ( service
, command
, additional_settings
= None ):
379 f
'ExecStart=!! {valgrind_cmd}{command} ' ,
382 drop_in
+= [ 'Environment=SYSTEMD_LOG_LEVEL=debug' ]
384 drop_in
+= [ f
'Environment=ASAN_OPTIONS=" {asan_options} "' ]
386 drop_in
+= [ f
'Environment=LSAN_OPTIONS=" {lsan_options} "' ]
388 drop_in
+= [ f
'Environment=UBSAN_OPTIONS=" {ubsan_options} "' ]
389 if asan_options
or lsan_options
or ubsan_options
:
390 drop_in
+= [ 'SystemCallFilter=' ]
391 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
392 drop_in
+= [ 'MemoryDenyWriteExecute=no' ]
395 'Environment=SYSTEMD_MEMPOOL=0' ,
403 if additional_settings
:
404 drop_in
+= additional_settings
406 create_unit_dropin ( f
' {service} .service' , drop_in
)
408 def link_exists ( link
):
409 return call_quiet ( f
'ip link show {link} ' ) == 0
411 def link_resolve ( link
):
412 return check_output ( f
'ip link show {link} ' ). split ( ':' )[ 1 ]. strip ()
414 def remove_link (* links
, protect
= False ):
416 if protect
and link
in protected_links
:
418 if link_exists ( link
):
419 call ( f
'ip link del dev {link} ' )
421 def save_existing_links ():
422 links
= os
. listdir ( '/sys/class/net' )
424 if link_exists ( link
):
425 protected_links
. add ( link
)
427 print ( '### The following links will be protected:' )
428 print ( ', ' . join ( sorted ( list ( protected_links
))))
431 links
= os
. listdir ( '/sys/class/net' )
432 remove_link (* links
, protect
= True )
434 def flush_nexthops ():
435 # Currently, the 'ip nexthop' command does not have 'save' and 'restore'.
436 # Hence, we cannot restore nexthops in a simple way.
437 # Let's assume there is no nexthop used in the system
438 call_quiet ( 'ip nexthop flush' )
441 # pylint: disable=global-statement
443 saved_routes
= check_output ( 'ip route show table all' )
444 print ( '### The following routes will be protected:' )
449 output
= check_output ( 'ip route show table all' )
450 for line
in output
. splitlines ():
451 if line
in saved_routes
:
453 if 'proto kernel' in line
:
455 if ' dev ' in line
and not ' dev lo ' in line
:
459 print ( '### Removing routes that did not exist when the test started.' )
461 call ( f
'ip route del {line} ' )
463 def save_routing_policy_rules ():
464 # pylint: disable=global-statement
465 global saved_ipv4_rules
, saved_ipv6_rules
467 output
= check_output ( f
'ip - {ipv} rule show' )
468 print ( f
'### The following IPv {ipv} routing policy rules will be protected:' )
472 saved_ipv4_rules
= save ( 4 )
473 saved_ipv6_rules
= save ( 6 )
475 def flush_routing_policy_rules ():
476 def flush ( ipv
, saved_rules
):
478 output
= check_output ( f
'ip - {ipv} rule show' )
479 for line
in output
. splitlines ():
480 if line
in saved_rules
:
484 print ( f
'### Removing IPv {ipv} routing policy rules that did not exist when the test started.' )
486 words
= line
. replace ( 'lookup [l3mdev-table]' , 'l3mdev' ). split ()
487 priority
= words
[ 0 ]. rstrip ( ':' )
488 call ( f
'ip - {ipv} rule del priority {priority} ' + ' ' . join ( words
[ 1 :]))
490 flush ( 4 , saved_ipv4_rules
)
491 flush ( 6 , saved_ipv6_rules
)
493 def flush_fou_ports ():
494 ret
= run ( 'ip fou show' )
495 if ret
. returncode
!= 0 :
496 return # fou may not be supported
497 for line
in ret
. stdout
. splitlines ():
498 port
= line
. split ()[ 1 ]
499 call ( f
'ip fou del port {port} ' )
501 def flush_l2tp_tunnels ():
503 ret
= run ( 'ip l2tp show tunnel' )
504 if ret
. returncode
!= 0 :
505 return # l2tp may not be supported
506 for line
in ret
. stdout
. splitlines ():
508 if words
[ 0 ] == 'Tunnel' :
509 tid
= words
[ 1 ]. rstrip ( ',' )
510 call ( f
'ip l2tp del tunnel tunnel_id {tid} ' )
513 # Removing L2TP tunnel is asynchronous and slightly takes a time.
516 r
= run ( f
'ip l2tp show tunnel tunnel_id {tid} ' )
517 if r
. returncode
!= 0 or len ( r
. stdout
. rstrip ()) == 0 :
521 print ( f
'Cannot remove L2TP tunnel {tid} , ignoring.' )
524 # pylint: disable=global-statement
525 global saved_timezone
526 r
= run (* timedatectl_cmd
, 'show' , '--value' , '--property' , 'Timezone' , env
= env
)
527 if r
. returncode
== 0 :
528 saved_timezone
= r
. stdout
. rstrip ()
529 print ( f
'### Saved timezone: {saved_timezone} ' )
531 def restore_timezone ():
533 call (* timedatectl_cmd
, 'set-timezone' , f
' {saved_timezone} ' , env
= env
)
535 def read_link_attr (* args
):
536 with
open ( os
. path
. join ( '/sys/class/net' , * args
), encoding
= 'utf-8' ) as f
:
537 return f
. readline (). strip ()
539 def read_link_state_file ( link
):
540 ifindex
= read_link_attr ( link
, 'ifindex' )
541 path
= os
. path
. join ( '/run/systemd/netif/links' , ifindex
)
542 with
open ( path
, encoding
= 'utf-8' ) as f
:
545 def read_ip_sysctl_attr ( link
, attribute
, ipv
):
546 with
open ( os
. path
. join ( '/proc/sys/net' , ipv
, 'conf' , link
, attribute
), encoding
= 'utf-8' ) as f
:
547 return f
. readline (). strip ()
549 def read_ipv6_sysctl_attr ( link
, attribute
):
550 return read_ip_sysctl_attr ( link
, attribute
, 'ipv6' )
552 def read_ipv4_sysctl_attr ( link
, attribute
):
553 return read_ip_sysctl_attr ( link
, attribute
, 'ipv4' )
555 def stop_by_pid_file ( pid_file
):
556 if not os
. path
. exists ( pid_file
):
558 with
open ( pid_file
, 'r' , encoding
= 'utf-8' ) as f
:
559 pid
= f
. read (). rstrip ( ' \t\r\n \0' )
560 os
. kill ( int ( pid
), signal
. SIGTERM
)
564 print ( f
"PID {pid} is still alive, waiting..." )
567 if e
. errno
== errno
. ESRCH
:
569 print ( f
"Unexpected exception when waiting for {pid} to die: {e.errno}" )
572 def start_dnsmasq (* additional_options
, interface
= 'veth-peer' , lease_time
= '2m' , ipv4_range
= '192.168.5.10,192.168.5.200' , ipv4_router
= '192.168.5.1' , ipv6_range
= '2600::10,2600::20' ):
575 f
'--log-facility= {dnsmasq_log_file} ' ,
576 '--log-queries=extra' ,
578 f
'--pid-file= {dnsmasq_pid_file} ' ,
579 '--conf-file=/dev/null' ,
581 f
'--interface= {interface} ' ,
582 f
'--dhcp-leasefile= {dnsmasq_lease_file} ' ,
584 f
'--dhcp-range= {ipv6_range} , {lease_time} ' ,
585 f
'--dhcp-range= {ipv4_range} , {lease_time} ' ,
586 '--dhcp-option=option:mtu,1492' ,
587 f
'--dhcp-option=option:router, {ipv4_router} ' ,
590 ) + additional_options
591 check_output (* command
)
594 stop_by_pid_file ( dnsmasq_pid_file
)
595 rm_f ( dnsmasq_lease_file
)
596 rm_f ( dnsmasq_log_file
)
598 def read_dnsmasq_log_file ():
599 with
open ( dnsmasq_log_file
, encoding
= 'utf-8' ) as f
:
602 def start_isc_dhcpd ( conf_file
, ipv
, interface
= 'veth-peer' ):
603 conf_file_path
= os
. path
. join ( networkd_ci_temp_dir
, conf_file
)
604 isc_dhcpd_command
= f
'dhcpd {ipv} -cf {conf_file_path} -lf {isc_dhcpd_lease_file} -pf {isc_dhcpd_pid_file} {interface} '
605 touch ( isc_dhcpd_lease_file
)
606 check_output ( isc_dhcpd_command
)
608 def stop_isc_dhcpd ():
609 stop_by_pid_file ( isc_dhcpd_pid_file
)
610 rm_f ( isc_dhcpd_lease_file
)
612 def start_radvd (* additional_options
, config_file
):
613 config_file_path
= os
. path
. join ( networkd_ci_temp_dir
, 'radvd' , config_file
)
616 f
'--pidfile= {radvd_pid_file} ' ,
617 f
'--config= {config_file_path} ' ,
618 '--logmethod=stderr' ,
619 ) + additional_options
620 check_output (* command
)
623 stop_by_pid_file ( radvd_pid_file
)
625 def radvd_check_config ( config_file
):
626 if not shutil
. which ( 'radvd' ):
627 print ( 'radvd is not installed, assuming the config check failed' )
630 # Note: can't use networkd_ci_temp_dir here, as this command may run before that dir is
631 # set up (one instance is @unittest.skipX())
632 config_file_path
= os
. path
. join ( os
. path
. dirname ( os
. path
. abspath ( __file__
)), 'conf/radvd' , config_file
)
633 return call ( f
'radvd --config= {config_file_path} --configtest' ) == 0
635 def networkd_invocation_id ():
636 return check_output ( 'systemctl show --value -p InvocationID systemd-networkd.service' )
638 def read_networkd_log ( invocation_id
= None ):
639 if not invocation_id
:
640 invocation_id
= networkd_invocation_id ()
641 return check_output ( 'journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
)
643 def stop_networkd ( show_logs
= True ):
645 invocation_id
= networkd_invocation_id ()
646 check_output ( 'systemctl stop systemd-networkd.socket' )
647 check_output ( 'systemctl stop systemd-networkd.service' )
649 print ( read_networkd_log ( invocation_id
))
651 def start_networkd ():
652 check_output ( 'systemctl start systemd-networkd' )
654 def restart_networkd ( show_logs
= True ):
656 invocation_id
= networkd_invocation_id ()
657 check_output ( 'systemctl restart systemd-networkd.service' )
659 print ( read_networkd_log ( invocation_id
))
662 return int ( check_output ( 'systemctl show --value -p MainPID systemd-networkd.service' ))
664 def networkctl_reconfigure (* links
):
665 check_output (* networkctl_cmd
, 'reconfigure' , * links
, env
= env
)
667 def networkctl_reload ( sleep_time
= 1 ):
668 check_output (* networkctl_cmd
, 'reload' , env
= env
)
669 # 'networkctl reload' asynchronously reconfigure links.
670 # Hence, we need to wait for a short time for link to be in configuring state.
672 time
. sleep ( sleep_time
)
677 def tear_down_common ():
678 # 1. stop DHCP/RA servers
684 call_quiet ( 'rmmod netdevsim' )
685 call_quiet ( 'rmmod sch_teql' )
687 # 3. remove network namespace
688 call_quiet ( 'ip netns del ns99' )
698 clear_network_units ()
699 clear_networkd_conf_dropins ()
704 flush_routing_policy_rules ()
708 rm_rf ( networkd_ci_temp_dir
)
709 cp_r ( os
. path
. join ( os
. path
. dirname ( os
. path
. abspath ( __file__
)), 'conf' ), networkd_ci_temp_dir
)
711 clear_network_units ()
712 clear_networkd_conf_dropins ()
715 copy_udev_rule ( '00-debug-net.rules' )
719 save_existing_links ()
721 save_routing_policy_rules ()
724 create_service_dropin ( 'systemd-networkd' , networkd_bin
,
725 [ '[Service]' , 'Restart=no' , '[Unit]' , 'StartLimitIntervalSec=0' ])
726 create_service_dropin ( 'systemd-resolved' , resolved_bin
)
727 create_service_dropin ( 'systemd-timesyncd' , timesyncd_bin
)
729 # TODO: also run udevd with sanitizers, valgrind, or coverage
730 #create_service_dropin('systemd-udevd', udevd_bin,
731 # f'{udevadm_bin} control --reload --timeout 0')
733 'systemd-udevd.service' ,
737 f
'ExecStart=!!@ {udevd_bin} systemd-udevd' ,
741 'systemd-networkd.socket' ,
744 'StartLimitIntervalSec=0' ,
748 check_output ( 'systemctl daemon-reload' )
749 print ( check_output ( 'systemctl cat systemd-networkd.service' ))
750 print ( check_output ( 'systemctl cat systemd-resolved.service' ))
751 print ( check_output ( 'systemctl cat systemd-timesyncd.service' ))
752 print ( check_output ( 'systemctl cat systemd-udevd.service' ))
753 check_output ( 'systemctl restart systemd-resolved.service' )
754 check_output ( 'systemctl restart systemd-timesyncd.service' )
755 check_output ( 'systemctl restart systemd-udevd.service' )
757 def tearDownModule ():
758 rm_rf ( networkd_ci_temp_dir
)
760 clear_network_units ()
761 clear_networkd_conf_dropins ()
765 rm_rf ( '/run/systemd/system/systemd-networkd.service.d' )
766 rm_rf ( '/run/systemd/system/systemd-networkd.socket.d' )
767 rm_rf ( '/run/systemd/system/systemd-resolved.service.d' )
768 rm_rf ( '/run/systemd/system/systemd-timesyncd.service.d' )
769 rm_rf ( '/run/systemd/system/systemd-udevd.service.d' )
770 check_output ( 'systemctl daemon-reload' )
771 check_output ( 'systemctl restart systemd-udevd.service' )
772 restore_active_units ()
775 # pylint: disable=no-member
777 def check_link_exists ( self
, link
, expected
= True ):
779 self
. assertTrue ( link_exists ( link
))
781 self
. assertFalse ( link_exists ( link
))
783 def check_link_attr ( self
, * args
):
784 self
. assertEqual ( read_link_attr (* args
[:- 1 ]), args
[- 1 ])
786 def check_bridge_port_attr ( self
, master
, port
, attribute
, expected
, allow_enoent
= False ):
787 path
= os
. path
. join ( '/sys/devices/virtual/net' , master
, 'lower_' + port
, 'brport' , attribute
)
788 if allow_enoent
and not os
. path
. exists ( path
):
790 with
open ( path
, encoding
= 'utf-8' ) as f
:
791 self
. assertEqual ( f
. readline (). strip (), expected
)
793 def check_ipv4_sysctl_attr ( self
, link
, attribute
, expected
):
794 self
. assertEqual ( read_ipv4_sysctl_attr ( link
, attribute
), expected
)
796 def check_ipv6_sysctl_attr ( self
, link
, attribute
, expected
):
797 self
. assertEqual ( read_ipv6_sysctl_attr ( link
, attribute
), expected
)
799 def wait_links ( self
, * links
, timeout
= 20 , fail_assert
= True ):
800 def links_exist (* links
):
802 if not link_exists ( link
):
806 for iteration
in range ( timeout
+ 1 ):
810 if links_exist (* links
):
813 self
. fail ( 'Timed out waiting for all links to be created: ' + ', ' . join ( list ( links
)))
816 def wait_activated ( self
, link
, state
= 'down' , timeout
= 20 , fail_assert
= True ):
817 # wait for the interface is activated.
818 invocation_id
= check_output ( 'systemctl show systemd-networkd -p InvocationID --value' )
819 needle
= f
' {link} : Bringing link {state} '
821 for iteration
in range ( timeout
+ 1 ):
824 if not link_exists ( link
):
826 output
= check_output ( 'journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
)
827 if needle
in output
and flag
in check_output ( f
'ip link show {link} ' ):
830 self
. fail ( f
'Timed out waiting for {link} activated.' )
833 def wait_operstate ( self
, link
, operstate
= 'degraded' , setup_state
= 'configured' , setup_timeout
= 5 , fail_assert
= True ):
834 """Wait for the link to reach the specified operstate and/or setup state.
836 Specify None or '' for either operstate or setup_state to ignore that state.
837 This will recheck until the state conditions are met or the timeout expires.
839 If the link successfully matches the requested state, this returns True.
840 If this times out waiting for the link to match, the behavior depends on the
841 'fail_assert' parameter; if True, this causes a test assertion failure,
842 otherwise this returns False. The default is to cause assertion failure.
844 Note that this function matches on *exactly* the given operstate and setup_state.
845 To wait for a link to reach *or exceed* a given operstate, use wait_online().
852 for secs
in range ( setup_timeout
+ 1 ):
855 if not link_exists ( link
):
857 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , link
, env
= env
)
858 if re
. search ( rf
'(?m)^\s*State:\s+ {operstate} \s+\( {setup_state} \)\s*$' , output
):
862 self
. fail ( f
'Timed out waiting for {link} to reach state {operstate} / {setup_state} ' )
865 def wait_online ( self
, links_with_operstate
, timeout
= '20s' , bool_any
= False , ipv4
= False , ipv6
= False , setup_state
= 'configured' , setup_timeout
= 5 ):
866 """Wait for the links to reach the specified operstate and/or setup state.
868 This is similar to wait_operstate() but can be used for multiple links,
869 and it also calls systemd-networkd-wait-online to wait for the given operstate.
870 The operstate should be specified in the link name, like 'eth0:degraded'.
871 If just a link name is provided, wait-online's default operstate to wait for is degraded.
873 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
874 'setup_timeout' controls the per-link timeout waiting for the setup_state.
876 Set 'bool_any' to True to wait for any (instead of all) of the given links.
877 If this is set, no setup_state checks are done.
879 Set 'ipv4' or 'ipv6' to True to wait for IPv4 address or IPv6 address, respectively, of each of the given links.
880 This is applied only for the operational state 'degraded' or above.
882 Note that this function waits for the links to reach *or exceed* the given operstate.
883 However, the setup_state, if specified, must be matched *exactly*.
885 This returns if the links reached the requested operstate/setup_state; otherwise it
886 raises CalledProcessError or fails test assertion.
888 args
= wait_online_cmd
+ [ f
'--timeout= {timeout} ' ] + [ f
'--interface= {link} ' for link
in links_with_operstate
] + [ f
'--ignore= {link} ' for link
in protected_links
]
896 check_output (* args
, env
= wait_online_env
)
897 except subprocess
. CalledProcessError
:
898 # show detailed status on failure
899 for link
in links_with_operstate
:
900 name
= link
. split ( ':' )[ 0 ]
901 if link_exists ( name
):
902 call (* networkctl_cmd
, '-n' , '0' , 'status' , name
, env
= env
)
904 if not bool_any
and setup_state
:
905 for link
in links_with_operstate
:
906 self
. wait_operstate ( link
. split ( ':' )[ 0 ], None , setup_state
, setup_timeout
)
908 def wait_address ( self
, link
, address_regex
, scope
= 'global' , ipv
= '' , timeout_sec
= 100 ):
909 for i
in range ( timeout_sec
):
912 output
= check_output ( f
'ip {ipv} address show dev {link} scope {scope} ' )
913 if re
. search ( address_regex
, output
) and 'tentative' not in output
:
916 self
. assertRegex ( output
, address_regex
)
918 def wait_address_dropped ( self
, link
, address_regex
, scope
= 'global' , ipv
= '' , timeout_sec
= 100 ):
919 for i
in range ( timeout_sec
):
922 output
= check_output ( f
'ip {ipv} address show dev {link} scope {scope} ' )
923 if not re
. search ( address_regex
, output
):
926 self
. assertNotRegex ( output
, address_regex
)
928 def wait_route ( self
, link
, route_regex
, table
= 'main' , ipv
= '' , timeout_sec
= 100 ):
929 for i
in range ( timeout_sec
):
932 output
= check_output ( f
'ip {ipv} route show dev {link} table {table} ' )
933 if re
. search ( route_regex
, output
):
936 self
. assertRegex ( output
, route_regex
)
938 def check_netlabel ( self
, interface
, address
, label
= 'system_u:object_r:root_t:s0' ):
939 if not shutil
. which ( 'selinuxenabled' ):
940 print ( '## Checking NetLabel skipped: selinuxenabled command not found.' )
941 elif call_quiet ( 'selinuxenabled' ) != 0 :
942 print ( '## Checking NetLabel skipped: SELinux disabled.' )
943 elif not shutil
. which ( 'netlabelctl' ): # not packaged by all distros
944 print ( '## Checking NetLabel skipped: netlabelctl command not found.' )
946 output
= check_output ( 'netlabelctl unlbl list' )
948 self
. assertRegex ( output
, f
'interface: {interface} ,address: {address} ,label:" {label} "' )
950 class NetworkctlTests ( unittest
. TestCase
, Utilities
):
958 @expectedFailureIfAlternativeNameIsNotAvailable ()
959 def test_altname ( self
):
960 copy_network_unit ( '26-netdev-link-local-addressing-yes.network' , '12-dummy.netdev' , '12-dummy.link' )
962 self
. wait_online ([ 'dummy98:degraded' ])
964 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
965 self
. assertRegex ( output
, 'hogehogehogehogehogehoge' )
967 @expectedFailureIfAlternativeNameIsNotAvailable ()
968 def test_rename_to_altname ( self
):
969 copy_network_unit ( '26-netdev-link-local-addressing-yes.network' ,
970 '12-dummy.netdev' , '12-dummy-rename-to-altname.link' )
972 self
. wait_online ([ 'dummyalt:degraded' ])
974 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummyalt' , env
= env
)
975 self
. assertIn ( 'hogehogehogehogehogehoge' , output
)
976 self
. assertNotIn ( 'dummy98' , output
)
978 def test_reconfigure ( self
):
979 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' )
981 self
. wait_online ([ 'dummy98:routable' ])
983 output
= check_output ( 'ip -4 address show dev dummy98' )
985 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
986 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
987 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
989 check_output ( 'ip address del 10.1.2.3/16 dev dummy98' )
990 check_output ( 'ip address del 10.1.2.4/16 dev dummy98' )
991 check_output ( 'ip address del 10.2.2.4/16 dev dummy98' )
993 networkctl_reconfigure ( 'dummy98' )
994 self
. wait_online ([ 'dummy98:routable' ])
996 output
= check_output ( 'ip -4 address show dev dummy98' )
998 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
999 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
1000 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
1002 remove_network_unit ( '25-address-static.network' )
1005 self
. wait_operstate ( 'dummy98' , 'degraded' , setup_state
= 'unmanaged' )
1007 output
= check_output ( 'ip -4 address show dev dummy98' )
1009 self
. assertNotIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
1010 self
. assertNotIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
1011 self
. assertNotIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
1013 copy_network_unit ( '25-address-static.network' )
1015 self
. wait_online ([ 'dummy98:routable' ])
1017 output
= check_output ( 'ip -4 address show dev dummy98' )
1019 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
1020 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
1021 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
1023 def test_renew ( self
):
1025 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
1026 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
1028 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
1029 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
1030 self
. assertRegex ( output
, 'DNS: 192.168.5.1 \n *192.168.5.10' )
1031 self
. assertRegex ( output
, 'NTP: 192.168.5.1 \n *192.168.5.11' )
1033 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server.network' )
1036 output
= check_output (* networkctl_cmd
, '--lines=0' , '--stats' , '--all' , '--full' , '--json=short' , 'status' )
1039 for verb
in [ 'renew' , 'forcerenew' ]:
1040 call_check (* networkctl_cmd
, verb
, 'veth99' )
1042 call_check (* networkctl_cmd
, verb
, 'veth99' , 'veth99' , 'veth99' )
1045 def test_up_down ( self
):
1046 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' )
1048 self
. wait_online ([ 'dummy98:routable' ])
1050 call_check (* networkctl_cmd
, 'down' , 'dummy98' )
1051 self
. wait_online ([ 'dummy98:off' ])
1052 call_check (* networkctl_cmd
, 'up' , 'dummy98' )
1053 self
. wait_online ([ 'dummy98:routable' ])
1054 call_check (* networkctl_cmd
, 'down' , 'dummy98' , 'dummy98' , 'dummy98' )
1055 self
. wait_online ([ 'dummy98:off' ])
1056 call_check (* networkctl_cmd
, 'up' , 'dummy98' , 'dummy98' , 'dummy98' )
1057 self
. wait_online ([ 'dummy98:routable' ])
1059 def test_reload ( self
):
1062 copy_network_unit ( '11-dummy.netdev' )
1064 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'unmanaged' )
1066 copy_network_unit ( '11-dummy.network' )
1068 self
. wait_online ([ 'test1:degraded' ])
1070 remove_network_unit ( '11-dummy.network' )
1072 self
. wait_operstate ( 'test1' , 'degraded' , setup_state
= 'unmanaged' )
1074 remove_network_unit ( '11-dummy.netdev' )
1076 self
. wait_operstate ( 'test1' , 'degraded' , setup_state
= 'unmanaged' )
1078 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1080 self
. wait_operstate ( 'test1' , 'degraded' )
1082 def test_glob ( self
):
1083 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1086 self
. wait_online ([ 'test1:degraded' ])
1088 output
= check_output (* networkctl_cmd
, 'list' , env
= env
)
1089 self
. assertRegex ( output
, '1 lo ' )
1090 self
. assertRegex ( output
, 'test1' )
1092 output
= check_output (* networkctl_cmd
, 'list' , 'test1' , env
= env
)
1093 self
. assertNotRegex ( output
, '1 lo ' )
1094 self
. assertRegex ( output
, 'test1' )
1096 output
= check_output (* networkctl_cmd
, 'list' , 'te*' , env
= env
)
1097 self
. assertNotRegex ( output
, '1 lo ' )
1098 self
. assertRegex ( output
, 'test1' )
1100 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'te*' , env
= env
)
1101 self
. assertNotRegex ( output
, '1: lo ' )
1102 self
. assertRegex ( output
, 'test1' )
1104 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'tes[a-z][0-9]' , env
= env
)
1105 self
. assertNotRegex ( output
, '1: lo ' )
1106 self
. assertRegex ( output
, 'test1' )
1109 copy_network_unit ( '11-dummy-mtu.netdev' , '11-dummy.network' )
1112 self
. wait_online ([ 'test1:degraded' ])
1114 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
1115 self
. assertRegex ( output
, 'MTU: 1600' )
1117 def test_type ( self
):
1118 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1120 self
. wait_online ([ 'test1:degraded' ])
1122 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
1124 self
. assertRegex ( output
, 'Type: ether' )
1126 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'lo' , env
= env
)
1128 self
. assertRegex ( output
, 'Type: loopback' )
1130 def test_udev_link_file ( self
):
1131 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' , '25-default.link' )
1133 self
. wait_online ([ 'test1:degraded' ])
1135 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
1137 self
. assertRegex ( output
, r
'Link File: /run/systemd/network/25-default.link' )
1138 self
. assertRegex ( output
, r
'Network File: /run/systemd/network/11-dummy.network' )
1140 # This test may be run on the system that has older udevd than 70f32a260b5ebb68c19ecadf5d69b3844896ba55 (v249).
1141 # In that case, the udev DB for the loopback network interface may already have ID_NET_LINK_FILE property.
1142 # Let's reprocess the interface and drop the property.
1143 check_output (* udevadm_cmd
, 'trigger' , '--settle' , '--action=add' , '/sys/class/net/lo' )
1144 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'lo' , env
= env
)
1146 self
. assertRegex ( output
, r
'Link File: n/a' )
1147 self
. assertRegex ( output
, r
'Network File: n/a' )
1149 def test_delete_links ( self
):
1150 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' ,
1151 '25-veth.netdev' , '26-netdev-link-local-addressing-yes.network' )
1154 self
. wait_online ([ 'test1:degraded' , 'veth99:degraded' , 'veth-peer:degraded' ])
1156 check_output (* networkctl_cmd
, 'delete' , 'test1' , 'veth99' , env
= env
)
1157 self
. check_link_exists ( 'test1' , expected
= False )
1158 self
. check_link_exists ( 'veth99' , expected
= False )
1159 self
. check_link_exists ( 'veth-peer' , expected
= False )
1161 def test_label ( self
):
1162 call_check (* networkctl_cmd
, 'label' )
1164 class NetworkdMatchTests ( unittest
. TestCase
, Utilities
):
1172 @expectedFailureIfAlternativeNameIsNotAvailable ()
1173 def test_match ( self
):
1174 copy_network_unit ( '12-dummy-mac.netdev' ,
1175 '12-dummy-match-mac-01.network' ,
1176 '12-dummy-match-mac-02.network' ,
1177 '12-dummy-match-renamed.network' ,
1178 '12-dummy-match-altname.network' ,
1179 '12-dummy-altname.link' )
1182 self
. wait_online ([ 'dummy98:routable' ])
1183 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
1184 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-mac-01.network' , output
)
1185 output
= check_output ( 'ip -4 address show dev dummy98' )
1186 self
. assertIn ( '10.0.0.1/16' , output
)
1188 check_output ( 'ip link set dev dummy98 down' )
1189 check_output ( 'ip link set dev dummy98 address 12:34:56:78:9a:02' )
1191 self
. wait_address ( 'dummy98' , '10.0.0.2/16' , ipv
= '-4' , timeout_sec
= 10 )
1192 self
. wait_online ([ 'dummy98:routable' ])
1193 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
1194 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-mac-02.network' , output
)
1196 check_output ( 'ip link set dev dummy98 down' )
1197 check_output ( 'ip link set dev dummy98 name dummy98-1' )
1199 self
. wait_address ( 'dummy98-1' , '10.0.1.2/16' , ipv
= '-4' , timeout_sec
= 10 )
1200 self
. wait_online ([ 'dummy98-1:routable' ])
1201 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98-1' , env
= env
)
1202 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-renamed.network' , output
)
1204 check_output ( 'ip link set dev dummy98-1 down' )
1205 check_output ( 'ip link set dev dummy98-1 name dummy98-2' )
1206 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '/sys/class/net/dummy98-2' )
1208 self
. wait_address ( 'dummy98-2' , '10.0.2.2/16' , ipv
= '-4' , timeout_sec
= 10 )
1209 self
. wait_online ([ 'dummy98-2:routable' ])
1210 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98-2' , env
= env
)
1211 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-altname.network' , output
)
1213 def test_match_udev_property ( self
):
1214 copy_network_unit ( '12-dummy.netdev' , '13-not-match-udev-property.network' , '14-match-udev-property.network' )
1216 self
. wait_online ([ 'dummy98:routable' ])
1218 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
1220 self
. assertRegex ( output
, 'Network File: /run/systemd/network/14-match-udev-property' )
1222 class WaitOnlineTests ( unittest
. TestCase
, Utilities
):
1230 def test_wait_online_any ( self
):
1231 copy_network_unit ( '25-bridge.netdev' , '25-bridge.network' , '11-dummy.netdev' , '11-dummy.network' )
1234 self
. wait_online ([ 'bridge99' , 'test1:degraded' ], bool_any
= True )
1236 self
. wait_operstate ( 'bridge99' , '(off|no-carrier)' , setup_state
= 'configuring' )
1237 self
. wait_operstate ( 'test1' , 'degraded' )
1239 class NetworkdNetDevTests ( unittest
. TestCase
, Utilities
):
1247 def test_dropin_and_name_conflict ( self
):
1248 copy_network_unit ( '10-dropin-test.netdev' , '15-name-conflict-test.netdev' )
1251 self
. wait_online ([ 'dropin-test:off' ], setup_state
= 'unmanaged' )
1253 output
= check_output ( 'ip link show dropin-test' )
1255 self
. assertRegex ( output
, '00:50:56:c0:00:28' )
1257 @expectedFailureIfModuleIsNotAvailable ( 'bareudp' )
1258 def test_bareudp ( self
):
1259 copy_network_unit ( '25-bareudp.netdev' , '26-netdev-link-local-addressing-yes.network' )
1262 self
. wait_online ([ 'bareudp99:degraded' ])
1264 output
= check_output ( 'ip -d link show bareudp99' )
1266 self
. assertRegex ( output
, 'dstport 1000 ' )
1267 self
. assertRegex ( output
, 'ethertype ip ' )
1269 @expectedFailureIfModuleIsNotAvailable ( 'batman-adv' )
1270 def test_batadv ( self
):
1271 copy_network_unit ( '25-batadv.netdev' , '26-netdev-link-local-addressing-yes.network' )
1274 self
. wait_online ([ 'batadv99:degraded' ])
1276 output
= check_output ( 'ip -d link show batadv99' )
1278 self
. assertRegex ( output
, 'batadv' )
1280 def test_bridge ( self
):
1281 copy_network_unit ( '25-bridge.netdev' , '25-bridge-configure-without-carrier.network' )
1284 self
. wait_online ([ 'bridge99:no-carrier' ])
1286 tick
= os
. sysconf ( 'SC_CLK_TCK' )
1287 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'hello_time' )) / tick
))
1288 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'max_age' )) / tick
))
1289 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'forward_delay' )) / tick
))
1290 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'ageing_time' )) / tick
))
1291 self
. assertEqual ( 9 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'priority' )))
1292 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_querier' )))
1293 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_snooping' )))
1294 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'stp_state' )))
1295 self
. assertEqual ( 3 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_igmp_version' )))
1297 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bridge99' , env
= env
)
1299 self
. assertRegex ( output
, 'Priority: 9' )
1300 self
. assertRegex ( output
, 'STP: yes' )
1301 self
. assertRegex ( output
, 'Multicast IGMP Version: 3' )
1303 output
= check_output ( 'ip -d link show bridge99' )
1305 self
. assertIn ( 'vlan_filtering 1 ' , output
)
1306 self
. assertIn ( 'vlan_protocol 802.1ad ' , output
)
1307 self
. assertIn ( 'vlan_default_pvid 9 ' , output
)
1309 def test_bond ( self
):
1310 copy_network_unit ( '25-bond.netdev' , '25-bond-balanced-tlb.netdev' )
1313 self
. wait_online ([ 'bond99:off' , 'bond98:off' ], setup_state
= 'unmanaged' )
1315 self
. check_link_attr ( 'bond99' , 'bonding' , 'mode' , '802.3ad 4' )
1316 self
. check_link_attr ( 'bond99' , 'bonding' , 'xmit_hash_policy' , 'layer3+4 1' )
1317 self
. check_link_attr ( 'bond99' , 'bonding' , 'miimon' , '1000' )
1318 self
. check_link_attr ( 'bond99' , 'bonding' , 'lacp_rate' , 'fast 1' )
1319 self
. check_link_attr ( 'bond99' , 'bonding' , 'updelay' , '2000' )
1320 self
. check_link_attr ( 'bond99' , 'bonding' , 'downdelay' , '2000' )
1321 self
. check_link_attr ( 'bond99' , 'bonding' , 'resend_igmp' , '4' )
1322 self
. check_link_attr ( 'bond99' , 'bonding' , 'min_links' , '1' )
1323 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_actor_sys_prio' , '1218' )
1324 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_user_port_key' , '811' )
1325 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_actor_system' , '00:11:22:33:44:55' )
1327 self
. check_link_attr ( 'bond98' , 'bonding' , 'mode' , 'balance-tlb 5' )
1328 self
. check_link_attr ( 'bond98' , 'bonding' , 'tlb_dynamic_lb' , '1' )
1330 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bond99' , env
= env
)
1332 self
. assertIn ( 'Mode: 802.3ad' , output
)
1333 self
. assertIn ( 'Miimon: 1s' , output
)
1334 self
. assertIn ( 'Updelay: 2s' , output
)
1335 self
. assertIn ( 'Downdelay: 2s' , output
)
1337 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bond98' , env
= env
)
1339 self
. assertIn ( 'Mode: balance-tlb' , output
)
1341 def test_vlan ( self
):
1342 copy_network_unit ( '21-vlan.netdev' , '11-dummy.netdev' ,
1343 '21-vlan.network' , '21-vlan-test1.network' )
1346 self
. wait_online ([ 'test1:degraded' , 'vlan99:routable' ])
1348 output
= check_output ( 'ip -d link show test1' )
1350 self
. assertRegex ( output
, ' mtu 2000 ' )
1352 output
= check_output ( 'ip -d link show vlan99' )
1354 self
. assertIn ( ' mtu 2000 ' , output
)
1355 self
. assertIn ( 'REORDER_HDR' , output
)
1356 self
. assertIn ( 'LOOSE_BINDING' , output
)
1357 self
. assertIn ( 'GVRP' , output
)
1358 self
. assertIn ( 'MVRP' , output
)
1359 self
. assertIn ( ' id 99 ' , output
)
1360 self
. assertIn ( 'ingress-qos-map { 4:100 7:13 }' , output
)
1361 self
. assertIn ( 'egress-qos-map { 0:1 1:3 6:6 7:7 10:3 }' , output
)
1363 output
= check_output ( 'ip -4 address show dev test1' )
1365 self
. assertRegex ( output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1' )
1366 self
. assertRegex ( output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1' )
1368 output
= check_output ( 'ip -4 address show dev vlan99' )
1370 self
. assertRegex ( output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99' )
1372 def test_vlan_on_bond ( self
):
1373 # For issue #24377 (https://github.com/systemd/systemd/issues/24377),
1374 # which is fixed by b05e52000b4eee764b383cc3031da0a3739e996e (PR#24020).
1376 copy_network_unit ( '21-bond-802.3ad.netdev' , '21-bond-802.3ad.network' ,
1377 '21-vlan-on-bond.netdev' , '21-vlan-on-bond.network' )
1379 self
. wait_online ([ 'bond99:off' ])
1380 self
. wait_operstate ( 'vlan99' , operstate
= 'off' , setup_state
= 'configuring' , setup_timeout
= 10 )
1382 # The commit b05e52000b4eee764b383cc3031da0a3739e996e adds ", ignoring". To make it easily confirmed
1383 # that the issue is fixed by the commit, let's allow to match both string.
1384 log_re
= re
. compile ( 'vlan99: Could not bring up interface(, ignoring|): Network is down$' , re
. MULTILINE
)
1388 if log_re
. search ( read_networkd_log ()):
1393 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '21-dummy-bond-slave.network' )
1395 self
. wait_online ([ 'test1:enslaved' , 'dummy98:enslaved' , 'bond99:carrier' , 'vlan99:routable' ])
1397 def test_macvtap ( self
):
1399 for mode
in [ 'private' , 'vepa' , 'bridge' , 'passthru' ]:
1405 print ( f
'### test_macvtap(mode= {mode} )' )
1406 with self
. subTest ( mode
= mode
):
1407 copy_network_unit ( '21-macvtap.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1408 '11-dummy.netdev' , '25-macvtap.network' )
1409 with
open ( os
. path
. join ( network_unit_dir
, '21-macvtap.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1410 f
. write ( '[MACVTAP] \n Mode=' + mode
)
1413 self
. wait_online ([ 'macvtap99:degraded' ,
1414 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1416 output
= check_output ( 'ip -d link show macvtap99' )
1418 self
. assertRegex ( output
, 'macvtap mode ' + mode
+ ' ' )
1420 def test_macvlan ( self
):
1422 for mode
in [ 'private' , 'vepa' , 'bridge' , 'passthru' ]:
1428 print ( f
'### test_macvlan(mode= {mode} )' )
1429 with self
. subTest ( mode
= mode
):
1430 copy_network_unit ( '21-macvlan.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1431 '11-dummy.netdev' , '25-macvlan.network' )
1432 with
open ( os
. path
. join ( network_unit_dir
, '21-macvlan.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1433 f
. write ( '[MACVLAN] \n Mode=' + mode
)
1436 self
. wait_online ([ 'macvlan99:degraded' ,
1437 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1439 output
= check_output ( 'ip -d link show test1' )
1441 self
. assertRegex ( output
, ' mtu 2000 ' )
1443 output
= check_output ( 'ip -d link show macvlan99' )
1445 self
. assertRegex ( output
, ' mtu 2000 ' )
1446 self
. assertRegex ( output
, 'macvlan mode ' + mode
+ ' ' )
1448 remove_link ( 'test1' )
1451 check_output ( "ip link add test1 type dummy" )
1452 self
. wait_online ([ 'macvlan99:degraded' ,
1453 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1455 output
= check_output ( 'ip -d link show test1' )
1457 self
. assertRegex ( output
, ' mtu 2000 ' )
1459 output
= check_output ( 'ip -d link show macvlan99' )
1461 self
. assertRegex ( output
, ' mtu 2000 ' )
1462 self
. assertRegex ( output
, 'macvlan mode ' + mode
+ ' ' )
1464 @expectedFailureIfModuleIsNotAvailable ( 'ipvlan' )
1465 def test_ipvlan ( self
):
1467 for mode
, flag
in [[ 'L2' , 'private' ], [ 'L3' , 'vepa' ], [ 'L3S' , 'bridge' ]]:
1473 print ( f
'### test_ipvlan(mode= {mode} , flag= {flag} )' )
1474 with self
. subTest ( mode
= mode
, flag
= flag
):
1475 copy_network_unit ( '25-ipvlan.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1476 '11-dummy.netdev' , '25-ipvlan.network' )
1477 with
open ( os
. path
. join ( network_unit_dir
, '25-ipvlan.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1478 f
. write ( '[IPVLAN] \n Mode=' + mode
+ ' \n Flags=' + flag
)
1481 self
. wait_online ([ 'ipvlan99:degraded' , 'test1:degraded' ])
1483 output
= check_output ( 'ip -d link show ipvlan99' )
1485 self
. assertRegex ( output
, 'ipvlan *mode ' + mode
. lower () + ' ' + flag
)
1487 @expectedFailureIfModuleIsNotAvailable ( 'ipvtap' )
1488 def test_ipvtap ( self
):
1490 for mode
, flag
in [[ 'L2' , 'private' ], [ 'L3' , 'vepa' ], [ 'L3S' , 'bridge' ]]:
1496 print ( f
'### test_ipvtap(mode= {mode} , flag= {flag} )' )
1497 with self
. subTest ( mode
= mode
, flag
= flag
):
1498 copy_network_unit ( '25-ipvtap.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1499 '11-dummy.netdev' , '25-ipvtap.network' )
1500 with
open ( os
. path
. join ( network_unit_dir
, '25-ipvtap.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1501 f
. write ( '[IPVTAP] \n Mode=' + mode
+ ' \n Flags=' + flag
)
1504 self
. wait_online ([ 'ipvtap99:degraded' , 'test1:degraded' ])
1506 output
= check_output ( 'ip -d link show ipvtap99' )
1508 self
. assertRegex ( output
, 'ipvtap *mode ' + mode
. lower () + ' ' + flag
)
1510 def test_veth ( self
):
1511 copy_network_unit ( '25-veth.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1512 '25-veth-mtu.netdev' )
1515 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:degraded' , 'veth-mtu:degraded' , 'veth-mtu-peer:degraded' ])
1517 output
= check_output ( 'ip -d link show veth99' )
1519 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bc' )
1520 output
= check_output ( 'ip -d link show veth-peer' )
1522 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bd' )
1524 output
= check_output ( 'ip -d link show veth-mtu' )
1526 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:be' )
1527 self
. assertRegex ( output
, 'mtu 1800' )
1528 output
= check_output ( 'ip -d link show veth-mtu-peer' )
1530 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bf' )
1531 self
. assertRegex ( output
, 'mtu 1800' )
1533 def test_tuntap ( self
):
1534 copy_network_unit ( '25-tun.netdev' , '25-tap.netdev' , '26-netdev-link-local-addressing-yes.network' )
1537 self
. wait_online ([ 'testtun99:degraded' , 'testtap99:degraded' ])
1539 pid
= networkd_pid ()
1540 name
= psutil
. Process ( pid
). name ()[: 15 ]
1542 output
= check_output ( 'ip -d tuntap show' )
1544 self
. assertRegex ( output
, fr
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1545 self
. assertRegex ( output
, fr
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1547 output
= check_output ( 'ip -d link show testtun99' )
1549 # Old ip command does not support IFF_ flags
1550 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1551 self
. assertIn ( 'UP,LOWER_UP' , output
)
1553 output
= check_output ( 'ip -d link show testtap99' )
1555 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1556 self
. assertIn ( 'UP,LOWER_UP' , output
)
1558 remove_network_unit ( '26-netdev-link-local-addressing-yes.network' )
1561 self
. wait_online ([ 'testtun99:degraded' , 'testtap99:degraded' ], setup_state
= 'unmanaged' )
1563 pid
= networkd_pid ()
1564 name
= psutil
. Process ( pid
). name ()[: 15 ]
1566 output
= check_output ( 'ip -d tuntap show' )
1568 self
. assertRegex ( output
, fr
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1569 self
. assertRegex ( output
, fr
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1571 output
= check_output ( 'ip -d link show testtun99' )
1573 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1574 self
. assertIn ( 'UP,LOWER_UP' , output
)
1576 output
= check_output ( 'ip -d link show testtap99' )
1578 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1579 self
. assertIn ( 'UP,LOWER_UP' , output
)
1581 clear_network_units ()
1583 self
. wait_online ([ 'testtun99:off' , 'testtap99:off' ], setup_state
= 'unmanaged' )
1585 output
= check_output ( 'ip -d tuntap show' )
1587 self
. assertRegex ( output
, r
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$' )
1588 self
. assertRegex ( output
, r
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$' )
1593 output
= check_output ( 'ip -d link show testtun99' )
1595 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1596 if 'NO-CARRIER' in output
:
1604 output
= check_output ( 'ip -d link show testtap99' )
1606 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1607 if 'NO-CARRIER' in output
:
1612 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
1614 copy_network_unit ( '25-vrf.netdev' , '26-netdev-link-local-addressing-yes.network' )
1617 self
. wait_online ([ 'vrf99:carrier' ])
1619 @expectedFailureIfModuleIsNotAvailable ( 'vcan' )
1620 def test_vcan ( self
):
1621 copy_network_unit ( '25-vcan.netdev' , '26-netdev-link-local-addressing-yes.network' )
1624 self
. wait_online ([ 'vcan99:carrier' ])
1626 @expectedFailureIfModuleIsNotAvailable ( 'vxcan' )
1627 def test_vxcan ( self
):
1628 copy_network_unit ( '25-vxcan.netdev' , '26-netdev-link-local-addressing-yes.network' )
1631 self
. wait_online ([ 'vxcan99:carrier' , 'vxcan-peer:carrier' ])
1633 @expectedFailureIfModuleIsNotAvailable ( 'wireguard' )
1634 def test_wireguard ( self
):
1635 copy_network_unit ( '25-wireguard.netdev' , '25-wireguard.network' ,
1636 '25-wireguard-23-peers.netdev' , '25-wireguard-23-peers.network' ,
1637 '25-wireguard-preshared-key.txt' , '25-wireguard-private-key.txt' ,
1638 '25-wireguard-no-peer.netdev' , '25-wireguard-no-peer.network' )
1640 self
. wait_online ([ 'wg99:routable' , 'wg98:routable' , 'wg97:carrier' ])
1642 output
= check_output ( 'ip -4 address show dev wg99' )
1644 self
. assertIn ( 'inet 192.168.124.1/24 scope global wg99' , output
)
1646 output
= check_output ( 'ip -4 address show dev wg99' )
1648 self
. assertIn ( 'inet 169.254.11.1/24 scope link wg99' , output
)
1650 output
= check_output ( 'ip -6 address show dev wg99' )
1652 self
. assertIn ( 'inet6 fe80::1/64 scope link' , output
)
1654 output
= check_output ( 'ip -4 address show dev wg98' )
1656 self
. assertIn ( 'inet 192.168.123.123/24 scope global wg98' , output
)
1658 output
= check_output ( 'ip -6 address show dev wg98' )
1660 self
. assertIn ( 'inet6 fd8d:4d6d:3ccb:500::1/64 scope global' , output
)
1662 output
= check_output ( 'ip -4 route show dev wg99 table 1234' )
1664 self
. assertIn ( '192.168.26.0/24 proto static metric 123' , output
)
1666 output
= check_output ( 'ip -6 route show dev wg99 table 1234' )
1668 self
. assertIn ( 'fd31:bf08:57cb::/48 proto static metric 123 pref medium' , output
)
1670 output
= check_output ( 'ip -6 route show dev wg98 table 1234' )
1672 self
. assertIn ( 'fd8d:4d6d:3ccb:500:c79:2339:edce:ece1 proto static metric 123 pref medium' , output
)
1673 self
. assertIn ( 'fd8d:4d6d:3ccb:500:1dbf:ca8a:32d3:dd81 proto static metric 123 pref medium' , output
)
1674 self
. assertIn ( 'fd8d:4d6d:3ccb:500:1e54:1415:35d0:a47c proto static metric 123 pref medium' , output
)
1675 self
. assertIn ( 'fd8d:4d6d:3ccb:500:270d:b5dd:4a3f:8909 proto static metric 123 pref medium' , output
)
1676 self
. assertIn ( 'fd8d:4d6d:3ccb:500:5660:679d:3532:94d8 proto static metric 123 pref medium' , output
)
1677 self
. assertIn ( 'fd8d:4d6d:3ccb:500:6825:573f:30f3:9472 proto static metric 123 pref medium' , output
)
1678 self
. assertIn ( 'fd8d:4d6d:3ccb:500:6f2e:6888:c6fd:dfb9 proto static metric 123 pref medium' , output
)
1679 self
. assertIn ( 'fd8d:4d6d:3ccb:500:8d4d:bab:7280:a09a proto static metric 123 pref medium' , output
)
1680 self
. assertIn ( 'fd8d:4d6d:3ccb:500:900c:d437:ec27:8822 proto static metric 123 pref medium' , output
)
1681 self
. assertIn ( 'fd8d:4d6d:3ccb:500:9742:9931:5217:18d5 proto static metric 123 pref medium' , output
)
1682 self
. assertIn ( 'fd8d:4d6d:3ccb:500:9c11:d820:2e96:9be0 proto static metric 123 pref medium' , output
)
1683 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a072:80da:de4f:add1 proto static metric 123 pref medium' , output
)
1684 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a3f3:df38:19b0:721 proto static metric 123 pref medium' , output
)
1685 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a94b:cd6a:a32d:90e6 proto static metric 123 pref medium' , output
)
1686 self
. assertIn ( 'fd8d:4d6d:3ccb:500:b39c:9cdc:755a:ead3 proto static metric 123 pref medium' , output
)
1687 self
. assertIn ( 'fd8d:4d6d:3ccb:500:b684:4f81:2e3e:132e proto static metric 123 pref medium' , output
)
1688 self
. assertIn ( 'fd8d:4d6d:3ccb:500:bad5:495d:8e9c:3427 proto static metric 123 pref medium' , output
)
1689 self
. assertIn ( 'fd8d:4d6d:3ccb:500:bfe5:c3c3:5d77:fcb proto static metric 123 pref medium' , output
)
1690 self
. assertIn ( 'fd8d:4d6d:3ccb:500:c624:6bf7:4c09:3b59 proto static metric 123 pref medium' , output
)
1691 self
. assertIn ( 'fd8d:4d6d:3ccb:500:d4f9:5dc:9296:a1a proto static metric 123 pref medium' , output
)
1692 self
. assertIn ( 'fd8d:4d6d:3ccb:500:dcdd:d33b:90c9:6088 proto static metric 123 pref medium' , output
)
1693 self
. assertIn ( 'fd8d:4d6d:3ccb:500:e2e1:ae15:103f:f376 proto static metric 123 pref medium' , output
)
1694 self
. assertIn ( 'fd8d:4d6d:3ccb:500:f349:c4f0:10c1:6b4 proto static metric 123 pref medium' , output
)
1695 self
. assertIn ( 'fd8d:4d6d:3ccb:c79:2339:edce::/96 proto static metric 123 pref medium' , output
)
1696 self
. assertIn ( 'fd8d:4d6d:3ccb:1dbf:ca8a:32d3::/96 proto static metric 123 pref medium' , output
)
1697 self
. assertIn ( 'fd8d:4d6d:3ccb:1e54:1415:35d0::/96 proto static metric 123 pref medium' , output
)
1698 self
. assertIn ( 'fd8d:4d6d:3ccb:270d:b5dd:4a3f::/96 proto static metric 123 pref medium' , output
)
1699 self
. assertIn ( 'fd8d:4d6d:3ccb:5660:679d:3532::/96 proto static metric 123 pref medium' , output
)
1700 self
. assertIn ( 'fd8d:4d6d:3ccb:6825:573f:30f3::/96 proto static metric 123 pref medium' , output
)
1701 self
. assertIn ( 'fd8d:4d6d:3ccb:6f2e:6888:c6fd::/96 proto static metric 123 pref medium' , output
)
1702 self
. assertIn ( 'fd8d:4d6d:3ccb:8d4d:bab:7280::/96 proto static metric 123 pref medium' , output
)
1703 self
. assertIn ( 'fd8d:4d6d:3ccb:900c:d437:ec27::/96 proto static metric 123 pref medium' , output
)
1704 self
. assertIn ( 'fd8d:4d6d:3ccb:9742:9931:5217::/96 proto static metric 123 pref medium' , output
)
1705 self
. assertIn ( 'fd8d:4d6d:3ccb:9c11:d820:2e96::/96 proto static metric 123 pref medium' , output
)
1706 self
. assertIn ( 'fd8d:4d6d:3ccb:a072:80da:de4f::/96 proto static metric 123 pref medium' , output
)
1707 self
. assertIn ( 'fd8d:4d6d:3ccb:a3f3:df38:19b0::/96 proto static metric 123 pref medium' , output
)
1708 self
. assertIn ( 'fd8d:4d6d:3ccb:a94b:cd6a:a32d::/96 proto static metric 123 pref medium' , output
)
1709 self
. assertIn ( 'fd8d:4d6d:3ccb:b39c:9cdc:755a::/96 proto static metric 123 pref medium' , output
)
1710 self
. assertIn ( 'fd8d:4d6d:3ccb:b684:4f81:2e3e::/96 proto static metric 123 pref medium' , output
)
1711 self
. assertIn ( 'fd8d:4d6d:3ccb:bad5:495d:8e9c::/96 proto static metric 123 pref medium' , output
)
1712 self
. assertIn ( 'fd8d:4d6d:3ccb:bfe5:c3c3:5d77::/96 proto static metric 123 pref medium' , output
)
1713 self
. assertIn ( 'fd8d:4d6d:3ccb:c624:6bf7:4c09::/96 proto static metric 123 pref medium' , output
)
1714 self
. assertIn ( 'fd8d:4d6d:3ccb:d4f9:5dc:9296::/96 proto static metric 123 pref medium' , output
)
1715 self
. assertIn ( 'fd8d:4d6d:3ccb:dcdd:d33b:90c9::/96 proto static metric 123 pref medium' , output
)
1716 self
. assertIn ( 'fd8d:4d6d:3ccb:e2e1:ae15:103f::/96 proto static metric 123 pref medium' , output
)
1717 self
. assertIn ( 'fd8d:4d6d:3ccb:f349:c4f0:10c1::/96 proto static metric 123 pref medium' , output
)
1719 if shutil
. which ( 'wg' ):
1722 output
= check_output ( 'wg show wg99 listen-port' )
1723 self
. assertEqual ( output
, '51820' )
1724 output
= check_output ( 'wg show wg99 fwmark' )
1725 self
. assertEqual ( output
, '0x4d2' )
1726 output
= check_output ( 'wg show wg99 private-key' )
1727 self
. assertEqual ( output
, 'EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=' )
1728 output
= check_output ( 'wg show wg99 allowed-ips' )
1729 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t 192.168.124.3/32' , output
)
1730 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t 192.168.124.2/32' , output
)
1731 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t fdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128' , output
)
1732 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 192.168.26.0/24 fd31:bf08:57cb::/48' , output
)
1733 output
= check_output ( 'wg show wg99 persistent-keepalive' )
1734 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t off' , output
)
1735 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t off' , output
)
1736 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t off' , output
)
1737 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 20' , output
)
1738 output
= check_output ( 'wg show wg99 endpoints' )
1739 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t (none)' , output
)
1740 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t (none)' , output
)
1741 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t (none)' , output
)
1742 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 192.168.27.3:51820' , output
)
1743 output
= check_output ( 'wg show wg99 preshared-keys' )
1744 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t 6Fsg8XN0DE6aPQgAX4r2oazEYJOGqyHUz3QRH/jCB+I=' , output
)
1745 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t it7nd33chCT/tKT2ZZWfYyp43Zs+6oif72hexnSNMqA=' , output
)
1746 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=' , output
)
1747 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=' , output
)
1749 output
= check_output ( 'wg show wg98 private-key' )
1750 self
. assertEqual ( output
, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr+WHtZLZ90FU=' )
1752 output
= check_output ( 'wg show wg97 listen-port' )
1753 self
. assertEqual ( output
, '51821' )
1754 output
= check_output ( 'wg show wg97 fwmark' )
1755 self
. assertEqual ( output
, '0x4d3' )
1757 def test_geneve ( self
):
1758 copy_network_unit ( '25-geneve.netdev' , '26-netdev-link-local-addressing-yes.network' )
1761 self
. wait_online ([ 'geneve99:degraded' ])
1763 output
= check_output ( 'ip -d link show geneve99' )
1765 self
. assertRegex ( output
, '192.168.22.1' )
1766 self
. assertRegex ( output
, '6082' )
1767 self
. assertRegex ( output
, 'udpcsum' )
1768 self
. assertRegex ( output
, 'udp6zerocsumrx' )
1770 def test_ipip_tunnel ( self
):
1771 copy_network_unit ( '12-dummy.netdev' , '25-ipip.network' ,
1772 '25-ipip-tunnel.netdev' , '25-tunnel.network' ,
1773 '25-ipip-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1774 '25-ipip-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1775 '25-ipip-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1777 self
. wait_online ([ 'ipiptun99:routable' , 'ipiptun98:routable' , 'ipiptun97:routable' , 'ipiptun96:routable' , 'dummy98:degraded' ])
1779 output
= check_output ( 'ip -d link show ipiptun99' )
1781 self
. assertRegex ( output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98' )
1782 output
= check_output ( 'ip -d link show ipiptun98' )
1784 self
. assertRegex ( output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98' )
1785 output
= check_output ( 'ip -d link show ipiptun97' )
1787 self
. assertRegex ( output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98' )
1788 output
= check_output ( 'ip -d link show ipiptun96' )
1790 self
. assertRegex ( output
, 'ipip (ipip )?remote any local any dev dummy98' )
1792 def test_gre_tunnel ( self
):
1793 copy_network_unit ( '12-dummy.netdev' , '25-gretun.network' ,
1794 '25-gre-tunnel.netdev' , '25-tunnel.network' ,
1795 '25-gre-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1796 '25-gre-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1797 '25-gre-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1799 self
. wait_online ([ 'gretun99:routable' , 'gretun98:routable' , 'gretun97:routable' , 'gretun96:routable' , 'dummy98:degraded' ])
1801 output
= check_output ( 'ip -d link show gretun99' )
1803 self
. assertRegex ( output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1804 self
. assertRegex ( output
, 'ikey 1.2.3.103' )
1805 self
. assertRegex ( output
, 'okey 1.2.4.103' )
1806 self
. assertRegex ( output
, 'iseq' )
1807 self
. assertRegex ( output
, 'oseq' )
1808 output
= check_output ( 'ip -d link show gretun98' )
1810 self
. assertRegex ( output
, 'gre remote 10.65.223.239 local any dev dummy98' )
1811 self
. assertRegex ( output
, 'ikey 0.0.0.104' )
1812 self
. assertRegex ( output
, 'okey 0.0.0.104' )
1813 self
. assertNotRegex ( output
, 'iseq' )
1814 self
. assertNotRegex ( output
, 'oseq' )
1815 output
= check_output ( 'ip -d link show gretun97' )
1817 self
. assertRegex ( output
, 'gre remote any local 10.65.223.238 dev dummy98' )
1818 self
. assertRegex ( output
, 'ikey 0.0.0.105' )
1819 self
. assertRegex ( output
, 'okey 0.0.0.105' )
1820 self
. assertNotRegex ( output
, 'iseq' )
1821 self
. assertNotRegex ( output
, 'oseq' )
1822 output
= check_output ( 'ip -d link show gretun96' )
1824 self
. assertRegex ( output
, 'gre remote any local any dev dummy98' )
1825 self
. assertRegex ( output
, 'ikey 0.0.0.106' )
1826 self
. assertRegex ( output
, 'okey 0.0.0.106' )
1827 self
. assertNotRegex ( output
, 'iseq' )
1828 self
. assertNotRegex ( output
, 'oseq' )
1830 def test_ip6gre_tunnel ( self
):
1831 copy_network_unit ( '12-dummy.netdev' , '25-ip6gretun.network' ,
1832 '25-ip6gre-tunnel.netdev' , '25-tunnel.network' ,
1833 '25-ip6gre-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1834 '25-ip6gre-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1835 '25-ip6gre-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1838 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1840 self
. wait_links ( 'dummy98' , 'ip6gretun99' , 'ip6gretun98' , 'ip6gretun97' , 'ip6gretun96' )
1842 output
= check_output ( 'ip -d link show ip6gretun99' )
1844 self
. assertRegex ( output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1845 output
= check_output ( 'ip -d link show ip6gretun98' )
1847 self
. assertRegex ( output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98' )
1848 output
= check_output ( 'ip -d link show ip6gretun97' )
1850 self
. assertRegex ( output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98' )
1851 output
= check_output ( 'ip -d link show ip6gretun96' )
1853 self
. assertRegex ( output
, 'ip6gre remote any local any dev dummy98' )
1855 def test_gretap_tunnel ( self
):
1856 copy_network_unit ( '12-dummy.netdev' , '25-gretap.network' ,
1857 '25-gretap-tunnel.netdev' , '25-tunnel.network' ,
1858 '25-gretap-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1860 self
. wait_online ([ 'gretap99:routable' , 'gretap98:routable' , 'dummy98:degraded' ])
1862 output
= check_output ( 'ip -d link show gretap99' )
1864 self
. assertRegex ( output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1865 self
. assertRegex ( output
, 'ikey 0.0.0.106' )
1866 self
. assertRegex ( output
, 'okey 0.0.0.106' )
1867 self
. assertRegex ( output
, 'iseq' )
1868 self
. assertRegex ( output
, 'oseq' )
1869 self
. assertIn ( 'nopmtudisc' , output
)
1870 self
. assertIn ( 'ignore-df' , output
)
1871 output
= check_output ( 'ip -d link show gretap98' )
1873 self
. assertRegex ( output
, 'gretap remote 10.65.223.239 local any dev dummy98' )
1874 self
. assertRegex ( output
, 'ikey 0.0.0.107' )
1875 self
. assertRegex ( output
, 'okey 0.0.0.107' )
1876 self
. assertRegex ( output
, 'iseq' )
1877 self
. assertRegex ( output
, 'oseq' )
1879 def test_ip6gretap_tunnel ( self
):
1880 copy_network_unit ( '12-dummy.netdev' , '25-ip6gretap.network' ,
1881 '25-ip6gretap-tunnel.netdev' , '25-tunnel.network' ,
1882 '25-ip6gretap-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1884 self
. wait_online ([ 'ip6gretap99:routable' , 'ip6gretap98:routable' , 'dummy98:degraded' ])
1886 output
= check_output ( 'ip -d link show ip6gretap99' )
1888 self
. assertRegex ( output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1889 output
= check_output ( 'ip -d link show ip6gretap98' )
1891 self
. assertRegex ( output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98' )
1893 def test_vti_tunnel ( self
):
1894 copy_network_unit ( '12-dummy.netdev' , '25-vti.network' ,
1895 '25-vti-tunnel.netdev' , '25-tunnel.network' ,
1896 '25-vti-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1897 '25-vti-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1898 '25-vti-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1900 self
. wait_online ([ 'vtitun99:routable' , 'vtitun98:routable' , 'vtitun97:routable' , 'vtitun96:routable' , 'dummy98:degraded' ])
1902 output
= check_output ( 'ip -d link show vtitun99' )
1904 self
. assertRegex ( output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1905 output
= check_output ( 'ip -d link show vtitun98' )
1907 self
. assertRegex ( output
, 'vti remote 10.65.223.239 local any dev dummy98' )
1908 output
= check_output ( 'ip -d link show vtitun97' )
1910 self
. assertRegex ( output
, 'vti remote any local 10.65.223.238 dev dummy98' )
1911 output
= check_output ( 'ip -d link show vtitun96' )
1913 self
. assertRegex ( output
, 'vti remote any local any dev dummy98' )
1915 def test_vti6_tunnel ( self
):
1916 copy_network_unit ( '12-dummy.netdev' , '25-vti6.network' ,
1917 '25-vti6-tunnel.netdev' , '25-tunnel.network' ,
1918 '25-vti6-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1919 '25-vti6-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' )
1921 self
. wait_online ([ 'vti6tun99:routable' , 'vti6tun98:routable' , 'vti6tun97:routable' , 'dummy98:degraded' ])
1923 output
= check_output ( 'ip -d link show vti6tun99' )
1925 self
. assertRegex ( output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1926 output
= check_output ( 'ip -d link show vti6tun98' )
1928 self
. assertRegex ( output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98' )
1929 output
= check_output ( 'ip -d link show vti6tun97' )
1931 self
. assertRegex ( output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98' )
1933 def test_ip6tnl_tunnel ( self
):
1934 copy_network_unit ( '12-dummy.netdev' , '25-ip6tnl.network' ,
1935 '25-ip6tnl-tunnel.netdev' , '25-tunnel.network' ,
1936 '25-ip6tnl-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1937 '25-ip6tnl-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1938 '25-veth.netdev' , '25-ip6tnl-slaac.network' , '25-ipv6-prefix.network' ,
1939 '25-ip6tnl-tunnel-local-slaac.netdev' , '25-ip6tnl-tunnel-local-slaac.network' ,
1940 '25-ip6tnl-tunnel-external.netdev' , '26-netdev-link-local-addressing-yes.network' )
1942 self
. wait_online ([ 'ip6tnl99:routable' , 'ip6tnl98:routable' , 'ip6tnl97:routable' ,
1943 'ip6tnl-slaac:degraded' , 'ip6tnl-external:degraded' ,
1944 'dummy98:degraded' , 'veth99:routable' , 'veth-peer:degraded' ])
1946 output
= check_output ( 'ip -d link show ip6tnl99' )
1948 self
. assertIn ( 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' , output
)
1949 output
= check_output ( 'ip -d link show ip6tnl98' )
1951 self
. assertRegex ( output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98' )
1952 output
= check_output ( 'ip -d link show ip6tnl97' )
1954 self
. assertRegex ( output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98' )
1955 output
= check_output ( 'ip -d link show ip6tnl-external' )
1957 self
. assertIn ( 'ip6tnl-external@NONE:' , output
)
1958 self
. assertIn ( 'ip6tnl external ' , output
)
1959 output
= check_output ( 'ip -d link show ip6tnl-slaac' )
1961 self
. assertIn ( 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99' , output
)
1963 output
= check_output ( 'ip -6 address show veth99' )
1965 self
. assertIn ( 'inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic' , output
)
1967 output
= check_output ( 'ip -4 route show default' )
1969 self
. assertIn ( 'default dev ip6tnl-slaac proto static' , output
)
1971 def test_sit_tunnel ( self
):
1972 copy_network_unit ( '12-dummy.netdev' , '25-sit.network' ,
1973 '25-sit-tunnel.netdev' , '25-tunnel.network' ,
1974 '25-sit-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1975 '25-sit-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1976 '25-sit-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1978 self
. wait_online ([ 'sittun99:routable' , 'sittun98:routable' , 'sittun97:routable' , 'sittun96:routable' , 'dummy98:degraded' ])
1980 output
= check_output ( 'ip -d link show sittun99' )
1982 self
. assertRegex ( output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98" )
1983 output
= check_output ( 'ip -d link show sittun98' )
1985 self
. assertRegex ( output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98" )
1986 output
= check_output ( 'ip -d link show sittun97' )
1988 self
. assertRegex ( output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98" )
1989 output
= check_output ( 'ip -d link show sittun96' )
1991 self
. assertRegex ( output
, "sit (ip6ip )?remote any local any dev dummy98" )
1993 def test_isatap_tunnel ( self
):
1994 copy_network_unit ( '12-dummy.netdev' , '25-isatap.network' ,
1995 '25-isatap-tunnel.netdev' , '25-tunnel.network' )
1997 self
. wait_online ([ 'isataptun99:routable' , 'dummy98:degraded' ])
1999 output
= check_output ( 'ip -d link show isataptun99' )
2001 self
. assertRegex ( output
, "isatap " )
2003 def test_6rd_tunnel ( self
):
2004 copy_network_unit ( '12-dummy.netdev' , '25-6rd.network' ,
2005 '25-6rd-tunnel.netdev' , '25-tunnel.network' )
2007 self
. wait_online ([ 'sittun99:routable' , 'dummy98:degraded' ])
2009 output
= check_output ( 'ip -d link show sittun99' )
2011 self
. assertRegex ( output
, '6rd-prefix 2602::/24' )
2013 @expectedFailureIfERSPANv0IsNotSupported ()
2014 def test_erspan_tunnel_v0 ( self
):
2015 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
2016 '25-erspan0-tunnel.netdev' , '25-tunnel.network' ,
2017 '25-erspan0-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
2019 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
2021 output
= check_output ( 'ip -d link show erspan99' )
2023 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
2024 self
. assertIn ( 'erspan_ver 0' , output
)
2025 self
. assertNotIn ( 'erspan_index 123' , output
)
2026 self
. assertNotIn ( 'erspan_dir ingress' , output
)
2027 self
. assertNotIn ( 'erspan_hwid 1f' , output
)
2028 self
. assertIn ( 'ikey 0.0.0.101' , output
)
2029 self
. assertIn ( 'iseq' , output
)
2030 self
. assertIn ( 'nopmtudisc' , output
)
2031 self
. assertIn ( 'ignore-df' , output
)
2032 output
= check_output ( 'ip -d link show erspan98' )
2034 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
2035 self
. assertIn ( 'erspan_ver 0' , output
)
2036 self
. assertNotIn ( 'erspan_index 124' , output
)
2037 self
. assertNotIn ( 'erspan_dir egress' , output
)
2038 self
. assertNotIn ( 'erspan_hwid 2f' , output
)
2039 self
. assertIn ( 'ikey 0.0.0.102' , output
)
2040 self
. assertIn ( 'iseq' , output
)
2042 def test_erspan_tunnel_v1 ( self
):
2043 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
2044 '25-erspan1-tunnel.netdev' , '25-tunnel.network' ,
2045 '25-erspan1-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
2047 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
2049 output
= check_output ( 'ip -d link show erspan99' )
2051 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
2052 self
. assertIn ( 'erspan_ver 1' , output
)
2053 self
. assertIn ( 'erspan_index 123' , output
)
2054 self
. assertNotIn ( 'erspan_dir ingress' , output
)
2055 self
. assertNotIn ( 'erspan_hwid 1f' , output
)
2056 self
. assertIn ( 'ikey 0.0.0.101' , output
)
2057 self
. assertIn ( 'okey 0.0.0.101' , output
)
2058 self
. assertIn ( 'iseq' , output
)
2059 self
. assertIn ( 'oseq' , output
)
2060 output
= check_output ( 'ip -d link show erspan98' )
2062 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
2063 self
. assertIn ( 'erspan_ver 1' , output
)
2064 self
. assertIn ( 'erspan_index 124' , output
)
2065 self
. assertNotIn ( 'erspan_dir egress' , output
)
2066 self
. assertNotIn ( 'erspan_hwid 2f' , output
)
2067 self
. assertIn ( 'ikey 0.0.0.102' , output
)
2068 self
. assertIn ( 'okey 0.0.0.102' , output
)
2069 self
. assertIn ( 'iseq' , output
)
2070 self
. assertIn ( 'oseq' , output
)
2072 @expectedFailureIfERSPANv2IsNotSupported ()
2073 def test_erspan_tunnel_v2 ( self
):
2074 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
2075 '25-erspan2-tunnel.netdev' , '25-tunnel.network' ,
2076 '25-erspan2-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
2078 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
2080 output
= check_output ( 'ip -d link show erspan99' )
2082 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
2083 self
. assertIn ( 'erspan_ver 2' , output
)
2084 self
. assertNotIn ( 'erspan_index 123' , output
)
2085 self
. assertIn ( 'erspan_dir ingress' , output
)
2086 self
. assertIn ( 'erspan_hwid 0x1f' , output
)
2087 self
. assertIn ( 'ikey 0.0.0.101' , output
)
2088 self
. assertIn ( 'okey 0.0.0.101' , output
)
2089 self
. assertIn ( 'iseq' , output
)
2090 self
. assertIn ( 'oseq' , output
)
2091 output
= check_output ( 'ip -d link show erspan98' )
2093 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
2094 self
. assertIn ( 'erspan_ver 2' , output
)
2095 self
. assertNotIn ( 'erspan_index 124' , output
)
2096 self
. assertIn ( 'erspan_dir egress' , output
)
2097 self
. assertIn ( 'erspan_hwid 0x2f' , output
)
2098 self
. assertIn ( 'ikey 0.0.0.102' , output
)
2099 self
. assertIn ( 'okey 0.0.0.102' , output
)
2100 self
. assertIn ( 'iseq' , output
)
2101 self
. assertIn ( 'oseq' , output
)
2103 def test_tunnel_independent ( self
):
2104 copy_network_unit ( '25-ipip-tunnel-independent.netdev' , '26-netdev-link-local-addressing-yes.network' )
2107 self
. wait_online ([ 'ipiptun99:carrier' ])
2109 def test_tunnel_independent_loopback ( self
):
2110 copy_network_unit ( '25-ipip-tunnel-independent-loopback.netdev' , '26-netdev-link-local-addressing-yes.network' )
2113 self
. wait_online ([ 'ipiptun99:carrier' ])
2115 @expectedFailureIfModuleIsNotAvailable ( 'xfrm_interface' )
2116 def test_xfrm ( self
):
2117 copy_network_unit ( '12-dummy.netdev' , '25-xfrm.network' ,
2118 '25-xfrm.netdev' , '25-xfrm-independent.netdev' ,
2119 '26-netdev-link-local-addressing-yes.network' )
2122 self
. wait_online ([ 'dummy98:degraded' , 'xfrm98:degraded' , 'xfrm99:degraded' ])
2124 output
= check_output ( 'ip -d link show dev xfrm98' )
2126 self
. assertIn ( 'xfrm98@dummy98:' , output
)
2127 self
. assertIn ( 'xfrm if_id 0x98 ' , output
)
2129 output
= check_output ( 'ip -d link show dev xfrm99' )
2131 self
. assertIn ( 'xfrm99@lo:' , output
)
2132 self
. assertIn ( 'xfrm if_id 0x99 ' , output
)
2134 @expectedFailureIfModuleIsNotAvailable ( 'fou' )
2136 # The following redundant check is necessary for CentOS CI.
2137 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
2138 self
. assertTrue ( is_module_available ( 'fou' ))
2140 copy_network_unit ( '25-fou-ipproto-ipip.netdev' , '25-fou-ipproto-gre.netdev' ,
2141 '25-fou-ipip.netdev' , '25-fou-sit.netdev' ,
2142 '25-fou-gre.netdev' , '25-fou-gretap.netdev' )
2145 self
. wait_online ([ 'ipiptun96:off' , 'sittun96:off' , 'gretun96:off' , 'gretap96:off' ], setup_state
= 'unmanaged' )
2147 output
= check_output ( 'ip fou show' )
2149 self
. assertRegex ( output
, 'port 55555 ipproto 4' )
2150 self
. assertRegex ( output
, 'port 55556 ipproto 47' )
2152 output
= check_output ( 'ip -d link show ipiptun96' )
2154 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55555' )
2155 output
= check_output ( 'ip -d link show sittun96' )
2157 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55555' )
2158 output
= check_output ( 'ip -d link show gretun96' )
2160 self
. assertRegex ( output
, 'encap fou encap-sport 1001 encap-dport 55556' )
2161 output
= check_output ( 'ip -d link show gretap96' )
2163 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55556' )
2165 def test_vxlan ( self
):
2166 copy_network_unit ( '11-dummy.netdev' , '25-vxlan-test1.network' ,
2167 '25-vxlan.netdev' , '25-vxlan.network' ,
2168 '25-vxlan-ipv6.netdev' , '25-vxlan-ipv6.network' ,
2169 '25-vxlan-independent.netdev' , '26-netdev-link-local-addressing-yes.network' ,
2170 '25-veth.netdev' , '25-vxlan-veth99.network' , '25-ipv6-prefix.network' ,
2171 '25-vxlan-local-slaac.netdev' , '25-vxlan-local-slaac.network' )
2174 self
. wait_online ([ 'test1:degraded' , 'veth99:routable' , 'veth-peer:degraded' ,
2175 'vxlan99:degraded' , 'vxlan98:degraded' , 'vxlan97:degraded' , 'vxlan-slaac:degraded' ])
2177 output
= check_output ( 'ip -d -d link show vxlan99' )
2179 self
. assertIn ( '999' , output
)
2180 self
. assertIn ( '5555' , output
)
2181 self
. assertIn ( 'l2miss' , output
)
2182 self
. assertIn ( 'l3miss' , output
)
2183 self
. assertIn ( 'gbp' , output
)
2184 # Since [0] some of the options use slightly different names and some
2185 # options with default values are shown only if the -d(etails) setting
2187 # [0] https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit/?id=1215e9d3862387353d8672296cb4c6c16e8cbb72
2188 self
. assertRegex ( output
, '(udpcsum|udp_csum)' )
2189 self
. assertRegex ( output
, '(udp6zerocsumtx|udp_zero_csum6_tx)' )
2190 self
. assertRegex ( output
, '(udp6zerocsumrx|udp_zero_csum6_rx)' )
2191 self
. assertRegex ( output
, '(remcsumtx|remcsum_tx)' )
2192 self
. assertRegex ( output
, '(remcsumrx|remcsum_rx)' )
2194 output
= check_output ( 'bridge fdb show dev vxlan99' )
2196 self
. assertIn ( '00:11:22:33:44:55 dst 10.0.0.5 self permanent' , output
)
2197 self
. assertIn ( '00:11:22:33:44:66 dst 10.0.0.6 self permanent' , output
)
2198 self
. assertIn ( '00:11:22:33:44:77 dst 10.0.0.7 via test1 self permanent' , output
)
2200 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'vxlan99' , env
= env
)
2202 self
. assertIn ( 'VNI: 999' , output
)
2203 self
. assertIn ( 'Destination Port: 5555' , output
)
2204 self
. assertIn ( 'Underlying Device: test1' , output
)
2206 output
= check_output ( 'bridge fdb show dev vxlan97' )
2208 self
. assertIn ( '00:00:00:00:00:00 dst fe80::23b:d2ff:fe95:967f via test1 self permanent' , output
)
2209 self
. assertIn ( '00:00:00:00:00:00 dst fe80::27c:16ff:fec0:6c74 via test1 self permanent' , output
)
2210 self
. assertIn ( '00:00:00:00:00:00 dst fe80::2a2:e4ff:fef9:2269 via test1 self permanent' , output
)
2212 output
= check_output ( 'ip -d link show vxlan-slaac' )
2214 self
. assertIn ( 'vxlan id 4831584 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99' , output
)
2216 output
= check_output ( 'ip -6 address show veth99' )
2218 self
. assertIn ( 'inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic' , output
)
2220 @unittest . skipUnless ( compare_kernel_version ( "6" ), reason
= "Causes kernel panic on unpatched kernels: https://bugzilla.kernel.org/show_bug.cgi?id=208315" )
2221 def test_macsec ( self
):
2222 copy_network_unit ( '25-macsec.netdev' , '25-macsec.network' , '25-macsec.key' ,
2223 '26-macsec.network' , '12-dummy.netdev' )
2226 self
. wait_online ([ 'dummy98:degraded' , 'macsec99:routable' ])
2228 output
= check_output ( 'ip -d link show macsec99' )
2230 self
. assertRegex ( output
, 'macsec99@dummy98' )
2231 self
. assertRegex ( output
, 'macsec sci [0-9a-f]*000b' )
2232 self
. assertRegex ( output
, 'encrypt on' )
2234 output
= check_output ( 'ip macsec show macsec99' )
2236 self
. assertRegex ( output
, 'encrypt on' )
2237 self
. assertRegex ( output
, 'TXSC: [0-9a-f]*000b on SA 1' )
2238 self
. assertRegex ( output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000' )
2239 self
. assertRegex ( output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000' )
2240 self
. assertRegex ( output
, 'RXSC: c619528fe6a00100, state on' )
2241 self
. assertRegex ( output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000' )
2242 self
. assertRegex ( output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000' )
2243 self
. assertRegex ( output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000' )
2244 self
. assertRegex ( output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000' )
2245 self
. assertNotRegex ( output
, 'key 02030405067080900000000000000000' )
2246 self
. assertRegex ( output
, 'RXSC: 8c16456c83a90002, state on' )
2247 self
. assertRegex ( output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000' )
2249 def test_nlmon ( self
):
2250 copy_network_unit ( '25-nlmon.netdev' , '26-netdev-link-local-addressing-yes.network' )
2253 self
. wait_online ([ 'nlmon99:carrier' ])
2255 @expectedFailureIfModuleIsNotAvailable ( 'ifb' )
2257 copy_network_unit ( '25-ifb.netdev' , '26-netdev-link-local-addressing-yes.network' )
2260 self
. wait_online ([ 'ifb99:degraded' ])
2262 class NetworkdL2TPTests ( unittest
. TestCase
, Utilities
):
2270 @expectedFailureIfModuleIsNotAvailable ( 'l2tp_eth' , 'l2tp_netlink' )
2271 def test_l2tp_udp ( self
):
2272 copy_network_unit ( '11-dummy.netdev' , '25-l2tp-dummy.network' ,
2273 '25-l2tp-udp.netdev' , '25-l2tp.network' )
2276 self
. wait_online ([ 'test1:routable' , 'l2tp-ses1:degraded' , 'l2tp-ses2:degraded' ])
2278 output
= check_output ( 'ip l2tp show tunnel tunnel_id 10' )
2280 self
. assertRegex ( output
, "Tunnel 10, encap UDP" )
2281 self
. assertRegex ( output
, "From 192.168.30.100 to 192.168.30.101" )
2282 self
. assertRegex ( output
, "Peer tunnel 11" )
2283 self
. assertRegex ( output
, "UDP source / dest ports: 3000/4000" )
2284 self
. assertRegex ( output
, "UDP checksum: enabled" )
2286 output
= check_output ( 'ip l2tp show session tid 10 session_id 15' )
2288 self
. assertRegex ( output
, "Session 15 in tunnel 10" )
2289 self
. assertRegex ( output
, "Peer session 16, tunnel 11" )
2290 self
. assertRegex ( output
, "interface name: l2tp-ses1" )
2292 output
= check_output ( 'ip l2tp show session tid 10 session_id 17' )
2294 self
. assertRegex ( output
, "Session 17 in tunnel 10" )
2295 self
. assertRegex ( output
, "Peer session 18, tunnel 11" )
2296 self
. assertRegex ( output
, "interface name: l2tp-ses2" )
2298 @expectedFailureIfModuleIsNotAvailable ( 'l2tp_eth' , 'l2tp_ip' , 'l2tp_netlink' )
2299 def test_l2tp_ip ( self
):
2300 copy_network_unit ( '11-dummy.netdev' , '25-l2tp-dummy.network' ,
2301 '25-l2tp-ip.netdev' , '25-l2tp.network' )
2304 self
. wait_online ([ 'test1:routable' , 'l2tp-ses3:degraded' , 'l2tp-ses4:degraded' ])
2306 output
= check_output ( 'ip l2tp show tunnel tunnel_id 10' )
2308 self
. assertRegex ( output
, "Tunnel 10, encap IP" )
2309 self
. assertRegex ( output
, "From 192.168.30.100 to 192.168.30.101" )
2310 self
. assertRegex ( output
, "Peer tunnel 12" )
2312 output
= check_output ( 'ip l2tp show session tid 10 session_id 25' )
2314 self
. assertRegex ( output
, "Session 25 in tunnel 10" )
2315 self
. assertRegex ( output
, "Peer session 26, tunnel 12" )
2316 self
. assertRegex ( output
, "interface name: l2tp-ses3" )
2318 output
= check_output ( 'ip l2tp show session tid 10 session_id 27' )
2320 self
. assertRegex ( output
, "Session 27 in tunnel 10" )
2321 self
. assertRegex ( output
, "Peer session 28, tunnel 12" )
2322 self
. assertRegex ( output
, "interface name: l2tp-ses4" )
2324 class NetworkdNetworkTests ( unittest
. TestCase
, Utilities
):
2332 def test_address_static ( self
):
2333 # test for #22515. The address will be removed and replaced with /64 prefix.
2334 check_output ( 'ip link add dummy98 type dummy' )
2335 check_output ( 'ip link set dev dummy98 up' )
2336 check_output ( 'ip -6 address add 2001:db8:0:f101::15/128 dev dummy98' )
2337 self
. wait_address ( 'dummy98' , '2001:db8:0:f101::15/128' , ipv
= '-6' )
2338 check_output ( 'ip -4 address add 10.3.2.3/16 brd 10.3.255.250 scope global label dummy98:hoge dev dummy98' )
2339 self
. wait_address ( 'dummy98' , '10.3.2.3/16 brd 10.3.255.250' , ipv
= '-4' )
2341 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' )
2344 self
. wait_online ([ 'dummy98:routable' ])
2346 output
= check_output ( 'ip -4 address show dev dummy98' )
2348 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
2349 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
2350 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
2351 self
. assertIn ( 'inet 10.7.8.9/16 brd 10.7.255.255 scope link deprecated dummy98' , output
)
2352 self
. assertIn ( 'inet 10.8.8.1/16 scope global dummy98' , output
)
2353 self
. assertIn ( 'inet 10.8.8.2/16 brd 10.8.8.128 scope global secondary dummy98' , output
)
2354 self
. assertRegex ( output
, 'inet 10.9.0.1/16 (metric 128 |)brd 10.9.255.255 scope global dummy98' )
2356 # test for ENOBUFS issue #17012
2357 for i
in range ( 1 , 254 ):
2358 self
. assertIn ( f
'inet 10.3.3. {i} /16 brd 10.3.255.255' , output
)
2361 self
. assertNotIn ( '10.10.0.1/16' , output
)
2362 self
. assertNotIn ( '10.10.0.2/16' , output
)
2364 output
= check_output ( 'ip -4 address show dev dummy98 label 32' )
2365 self
. assertIn ( 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32' , output
)
2367 output
= check_output ( 'ip -4 address show dev dummy98 label 33' )
2368 self
. assertIn ( 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33' , output
)
2370 output
= check_output ( 'ip -4 address show dev dummy98 label 34' )
2371 self
. assertRegex ( output
, r
'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34' )
2373 output
= check_output ( 'ip -4 address show dev dummy98 label 35' )
2374 self
. assertRegex ( output
, r
'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35' )
2376 output
= check_output ( 'ip -4 route show dev dummy98' )
2378 self
. assertIn ( '10.9.0.0/16 proto kernel scope link src 10.9.0.1 metric 128' , output
)
2380 output
= check_output ( 'ip -6 address show dev dummy98' )
2382 self
. assertIn ( 'inet6 2001:db8:0:f101::15/64 scope global' , output
)
2383 self
. assertIn ( 'inet6 2001:db8:0:f101::16/64 scope global' , output
)
2384 self
. assertIn ( 'inet6 2001:db8:0:f102::15/64 scope global' , output
)
2385 self
. assertIn ( 'inet6 2001:db8:0:f102::16/64 scope global' , output
)
2386 self
. assertIn ( 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global' , output
)
2387 self
. assertIn ( 'inet6 2001:db8:1:f101::1/64 scope global deprecated' , output
)
2388 self
. assertRegex ( output
, r
'inet6 fd[0-9a-f:]*1/64 scope global' )
2390 self
. check_netlabel ( 'dummy98' , r
'10\.4\.3\.0/24' )
2393 # 1. set preferred lifetime forever to drop the deprecated flag for testing #20891.
2394 check_output ( 'ip address change 10.7.8.9/16 dev dummy98 preferred_lft forever' )
2395 check_output ( 'ip address change 2001:db8:1:f101::1/64 dev dummy98 preferred_lft forever' )
2396 output
= check_output ( 'ip -4 address show dev dummy98' )
2398 self
. assertNotIn ( 'deprecated' , output
)
2399 output
= check_output ( 'ip -6 address show dev dummy98' )
2401 self
. assertNotIn ( 'deprecated' , output
)
2403 # 2. reconfigure the interface.
2404 networkctl_reconfigure ( 'dummy98' )
2405 self
. wait_online ([ 'dummy98:routable' ])
2407 # 3. check the deprecated flag is set for the address configured with PreferredLifetime=0
2408 output
= check_output ( 'ip -4 address show dev dummy98' )
2410 self
. assertIn ( 'inet 10.7.8.9/16 brd 10.7.255.255 scope link deprecated dummy98' , output
)
2411 output
= check_output ( 'ip -6 address show dev dummy98' )
2413 self
. assertIn ( 'inet6 2001:db8:1:f101::1/64 scope global deprecated' , output
)
2415 # test for ENOBUFS issue #17012
2416 output
= check_output ( 'ip -4 address show dev dummy98' )
2417 for i
in range ( 1 , 254 ):
2418 self
. assertIn ( f
'inet 10.3.3. {i} /16 brd 10.3.255.255' , output
)
2420 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2424 def test_address_null ( self
):
2425 copy_network_unit ( '25-address-null.network' , '12-dummy.netdev' )
2428 self
. wait_online ([ 'dummy98:routable' ])
2430 output
= check_output ( 'ip address show dev dummy98 scope global' )
2433 ipv4_address_16
= re
. findall ( r
'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255' , output
)
2434 self
. assertEqual ( len ( ipv4_address_16
), 1 )
2435 ipv4_address_24
= re
. findall ( r
'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255' , output
)
2436 self
. assertEqual ( len ( ipv4_address_24
), 1 )
2437 ipv4_address_30
= re
. findall ( r
'inet 192.168.[0-9]*.[0-9]*/30 brd 192.168.[0-9]*.[0-9]*' , output
)
2438 self
. assertEqual ( len ( ipv4_address_30
), 1 )
2439 ipv6_address
= re
. findall ( r
'inet6 fd[0-9a-f:]*/64' , output
)
2440 self
. assertEqual ( len ( ipv6_address
), 1 )
2442 networkctl_reconfigure ( 'dummy98' )
2443 self
. wait_online ([ 'dummy98:routable' ])
2445 output
= check_output ( 'ip address show dev dummy98 scope global' )
2447 self
. assertIn ( ipv4_address_16
[ 0 ], output
)
2448 self
. assertIn ( ipv4_address_24
[ 0 ], output
)
2449 self
. assertIn ( ipv4_address_30
[ 0 ], output
)
2450 self
. assertIn ( ipv6_address
[ 0 ], output
)
2452 def test_address_ipv4acd ( self
):
2453 check_output ( 'ip netns add ns99' )
2454 check_output ( 'ip link add veth99 type veth peer veth-peer' )
2455 check_output ( 'ip link set veth-peer netns ns99' )
2456 check_output ( 'ip link set veth99 up' )
2457 check_output ( 'ip netns exec ns99 ip link set veth-peer up' )
2458 check_output ( 'ip netns exec ns99 ip address add 192.168.100.10/24 dev veth-peer' )
2460 copy_network_unit ( '25-address-ipv4acd-veth99.network' , copy_dropins
= False )
2462 self
. wait_online ([ 'veth99:routable' ])
2464 output
= check_output ( 'ip -4 address show dev veth99' )
2466 self
. assertNotIn ( '192.168.100.10/24' , output
)
2467 self
. assertIn ( '192.168.100.11/24' , output
)
2469 copy_network_unit ( '25-address-ipv4acd-veth99.network.d/conflict-address.conf' )
2471 self
. wait_operstate ( 'veth99' , operstate
= 'routable' , setup_state
= 'configuring' , setup_timeout
= 10 )
2473 output
= check_output ( 'ip -4 address show dev veth99' )
2475 self
. assertNotIn ( '192.168.100.10/24' , output
)
2476 self
. assertIn ( '192.168.100.11/24' , output
)
2478 def test_address_peer_ipv4 ( self
):
2479 # test for issue #17304
2480 copy_network_unit ( '25-address-peer-ipv4.network' , '12-dummy.netdev' )
2482 for trial
in range ( 2 ):
2488 self
. wait_online ([ 'dummy98:routable' ])
2490 output
= check_output ( 'ip -4 address show dev dummy98' )
2491 self
. assertIn ( 'inet 100.64.0.1 peer 100.64.0.2/32 scope global' , output
)
2493 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
2494 def test_prefix_route ( self
):
2495 copy_network_unit ( '25-prefix-route-with-vrf.network' , '12-dummy.netdev' ,
2496 '25-prefix-route-without-vrf.network' , '11-dummy.netdev' ,
2497 '25-vrf.netdev' , '25-vrf.network' )
2498 for trial
in range ( 2 ):
2504 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' , 'vrf99:carrier' ])
2506 output
= check_output ( 'ip route show table 42 dev dummy98' )
2507 print ( '### ip route show table 42 dev dummy98' )
2509 self
. assertRegex ( output
, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1' )
2510 self
. assertRegex ( output
, '10.20.33.0/24 proto kernel scope link src 10.20.33.1' )
2511 self
. assertRegex ( output
, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1' )
2512 self
. assertRegex ( output
, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1' )
2513 self
. assertRegex ( output
, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1' )
2514 self
. assertRegex ( output
, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1' )
2515 self
. assertRegex ( output
, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1' )
2516 output
= check_output ( 'ip -6 route show table 42 dev dummy98' )
2517 print ( '### ip -6 route show table 42 dev dummy98' )
2521 self
. assertRegex ( output
, 'local fdde:11:22::1 proto kernel metric 0 pref medium' )
2522 #self.assertRegex(output, 'fdde:11:22::1 proto kernel metric 256 pref medium')
2523 self
. assertRegex ( output
, 'local fdde:11:33::1 proto kernel metric 0 pref medium' )
2524 self
. assertRegex ( output
, 'fdde:11:33::/64 proto kernel metric 256 pref medium' )
2525 self
. assertRegex ( output
, 'local fdde:11:44::1 proto kernel metric 0 pref medium' )
2526 self
. assertRegex ( output
, 'local fdde:11:55::1 proto kernel metric 0 pref medium' )
2527 self
. assertRegex ( output
, 'fe80::/64 proto kernel metric 256 pref medium' )
2528 self
. assertRegex ( output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium' )
2532 output
= check_output ( 'ip route show dev test1' )
2533 print ( '### ip route show dev test1' )
2535 self
. assertRegex ( output
, '10.21.33.0/24 proto kernel scope link src 10.21.33.1' )
2536 output
= check_output ( 'ip route show table local dev test1' )
2537 print ( '### ip route show table local dev test1' )
2539 self
. assertRegex ( output
, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1' )
2540 self
. assertRegex ( output
, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1' )
2541 self
. assertRegex ( output
, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1' )
2542 self
. assertRegex ( output
, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1' )
2543 self
. assertRegex ( output
, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1' )
2544 self
. assertRegex ( output
, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1' )
2545 output
= check_output ( 'ip -6 route show dev test1' )
2546 print ( '### ip -6 route show dev test1' )
2548 self
. assertRegex ( output
, 'fdde:12:22::1 proto kernel metric 256 pref medium' )
2549 self
. assertRegex ( output
, 'fdde:12:33::/64 proto kernel metric 256 pref medium' )
2550 self
. assertRegex ( output
, 'fe80::/64 proto kernel metric 256 pref medium' )
2551 output
= check_output ( 'ip -6 route show table local dev test1' )
2552 print ( '### ip -6 route show table local dev test1' )
2554 self
. assertRegex ( output
, 'local fdde:12:22::1 proto kernel metric 0 pref medium' )
2555 self
. assertRegex ( output
, 'local fdde:12:33::1 proto kernel metric 0 pref medium' )
2556 self
. assertRegex ( output
, 'local fdde:12:44::1 proto kernel metric 0 pref medium' )
2557 self
. assertRegex ( output
, 'local fdde:12:55::1 proto kernel metric 0 pref medium' )
2558 self
. assertRegex ( output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium' )
2560 def test_configure_without_carrier ( self
):
2561 copy_network_unit ( '11-dummy.netdev' )
2563 self
. wait_operstate ( 'test1' , 'off' , '' )
2564 check_output ( 'ip link set dev test1 up carrier off' )
2566 copy_network_unit ( '25-test1.network.d/configure-without-carrier.conf' , copy_dropins
= False )
2568 self
. wait_online ([ 'test1:no-carrier' ])
2570 carrier_map
= { 'on' : '1' , 'off' : '0' }
2571 routable_map
= { 'on' : 'routable' , 'off' : 'no-carrier' }
2572 for carrier
in [ 'off' , 'on' , 'off' ]:
2573 with self
. subTest ( carrier
= carrier
):
2574 if carrier_map
[ carrier
] != read_link_attr ( 'test1' , 'carrier' ):
2575 check_output ( f
'ip link set dev test1 carrier {carrier} ' )
2576 self
. wait_online ([ f
'test1:{routable_map[carrier]}:{routable_map[carrier]}' ])
2578 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
2580 self
. assertRegex ( output
, '192.168.0.15' )
2581 self
. assertRegex ( output
, '192.168.0.1' )
2582 self
. assertRegex ( output
, routable_map
[ carrier
])
2584 def test_configure_without_carrier_yes_ignore_carrier_loss_no ( self
):
2585 copy_network_unit ( '11-dummy.netdev' )
2587 self
. wait_operstate ( 'test1' , 'off' , '' )
2588 check_output ( 'ip link set dev test1 up carrier off' )
2590 copy_network_unit ( '25-test1.network' )
2592 self
. wait_online ([ 'test1:no-carrier' ])
2594 carrier_map
= { 'on' : '1' , 'off' : '0' }
2595 routable_map
= { 'on' : 'routable' , 'off' : 'no-carrier' }
2596 for ( carrier
, have_config
) in [( 'off' , True ), ( 'on' , True ), ( 'off' , False )]:
2597 with self
. subTest ( carrier
= carrier
, have_config
= have_config
):
2598 if carrier_map
[ carrier
] != read_link_attr ( 'test1' , 'carrier' ):
2599 check_output ( f
'ip link set dev test1 carrier {carrier} ' )
2600 self
. wait_online ([ f
'test1:{routable_map[carrier]}:{routable_map[carrier]}' ])
2602 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
2605 self
. assertRegex ( output
, '192.168.0.15' )
2606 self
. assertRegex ( output
, '192.168.0.1' )
2608 self
. assertNotRegex ( output
, '192.168.0.15' )
2609 self
. assertNotRegex ( output
, '192.168.0.1' )
2610 self
. assertRegex ( output
, routable_map
[ carrier
])
2612 def test_routing_policy_rule ( self
):
2613 copy_network_unit ( '25-routing-policy-rule-test1.network' , '11-dummy.netdev' )
2615 self
. wait_online ([ 'test1:degraded' ])
2617 output
= check_output ( 'ip rule list iif test1 priority 111' )
2619 self
. assertRegex ( output
, '111:' )
2620 self
. assertRegex ( output
, 'from 192.168.100.18' )
2621 self
. assertRegex ( output
, r
'tos (0x08|throughput)\s' )
2622 self
. assertRegex ( output
, 'iif test1' )
2623 self
. assertRegex ( output
, 'oif test1' )
2624 self
. assertRegex ( output
, 'lookup 7' )
2626 output
= check_output ( 'ip rule list iif test1 priority 101' )
2628 self
. assertRegex ( output
, '101:' )
2629 self
. assertRegex ( output
, 'from all' )
2630 self
. assertRegex ( output
, 'iif test1' )
2631 self
. assertRegex ( output
, 'lookup 9' )
2633 output
= check_output ( 'ip -6 rule list iif test1 priority 100' )
2635 self
. assertRegex ( output
, '100:' )
2636 self
. assertRegex ( output
, 'from all' )
2637 self
. assertRegex ( output
, 'iif test1' )
2638 self
. assertRegex ( output
, 'lookup 8' )
2640 output
= check_output ( 'ip rule list iif test1 priority 102' )
2642 self
. assertRegex ( output
, '102:' )
2643 self
. assertRegex ( output
, 'from 0.0.0.0/8' )
2644 self
. assertRegex ( output
, 'iif test1' )
2645 self
. assertRegex ( output
, 'lookup 10' )
2647 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2650 def test_routing_policy_rule_issue_11280 ( self
):
2651 copy_network_unit ( '25-routing-policy-rule-test1.network' , '11-dummy.netdev' ,
2652 '25-routing-policy-rule-dummy98.network' , '12-dummy.netdev' )
2654 for trial
in range ( 3 ):
2655 restart_networkd ( show_logs
=( trial
> 0 ))
2656 self
. wait_online ([ 'test1:degraded' , 'dummy98:degraded' ])
2658 output
= check_output ( 'ip rule list table 7' )
2660 self
. assertRegex ( output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7' )
2662 output
= check_output ( 'ip rule list table 8' )
2664 self
. assertRegex ( output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8' )
2666 def test_routing_policy_rule_reconfigure ( self
):
2667 copy_network_unit ( '25-routing-policy-rule-reconfigure2.network' , '11-dummy.netdev' )
2669 self
. wait_online ([ 'test1:degraded' ])
2671 output
= check_output ( 'ip rule list table 1011' )
2673 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2674 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2675 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2676 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2678 output
= check_output ( 'ip -6 rule list table 1011' )
2680 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2682 copy_network_unit ( '25-routing-policy-rule-reconfigure1.network' , '11-dummy.netdev' )
2684 self
. wait_online ([ 'test1:degraded' ])
2686 output
= check_output ( 'ip rule list table 1011' )
2688 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2689 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2690 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2691 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2693 output
= check_output ( 'ip -6 rule list table 1011' )
2695 self
. assertNotIn ( '10112: from all oif test1 lookup 1011' , output
)
2696 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2698 call ( 'ip rule delete priority 10111' )
2699 call ( 'ip rule delete priority 10112' )
2700 call ( 'ip rule delete priority 10113' )
2701 call ( 'ip rule delete priority 10114' )
2702 call ( 'ip -6 rule delete priority 10113' )
2704 output
= check_output ( 'ip rule list table 1011' )
2706 self
. assertEqual ( output
, '' )
2708 output
= check_output ( 'ip -6 rule list table 1011' )
2710 self
. assertEqual ( output
, '' )
2712 networkctl_reconfigure ( 'test1' )
2713 self
. wait_online ([ 'test1:degraded' ])
2715 output
= check_output ( 'ip rule list table 1011' )
2717 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2718 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2719 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2720 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2722 output
= check_output ( 'ip -6 rule list table 1011' )
2724 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2726 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable ()
2727 def test_routing_policy_rule_port_range ( self
):
2728 copy_network_unit ( '25-fibrule-port-range.network' , '11-dummy.netdev' )
2730 self
. wait_online ([ 'test1:degraded' ])
2732 output
= check_output ( 'ip rule' )
2734 self
. assertRegex ( output
, '111' )
2735 self
. assertRegex ( output
, 'from 192.168.100.18' )
2736 self
. assertRegex ( output
, '1123-1150' )
2737 self
. assertRegex ( output
, '3224-3290' )
2738 self
. assertRegex ( output
, 'tcp' )
2739 self
. assertRegex ( output
, 'lookup 7' )
2741 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable ()
2742 def test_routing_policy_rule_invert ( self
):
2743 copy_network_unit ( '25-fibrule-invert.network' , '11-dummy.netdev' )
2745 self
. wait_online ([ 'test1:degraded' ])
2747 output
= check_output ( 'ip rule' )
2749 self
. assertRegex ( output
, '111' )
2750 self
. assertRegex ( output
, 'not.*?from.*?192.168.100.18' )
2751 self
. assertRegex ( output
, 'tcp' )
2752 self
. assertRegex ( output
, 'lookup 7' )
2754 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable ()
2755 def test_routing_policy_rule_uidrange ( self
):
2756 copy_network_unit ( '25-fibrule-uidrange.network' , '11-dummy.netdev' )
2758 self
. wait_online ([ 'test1:degraded' ])
2760 output
= check_output ( 'ip rule' )
2762 self
. assertRegex ( output
, '111' )
2763 self
. assertRegex ( output
, 'from 192.168.100.18' )
2764 self
. assertRegex ( output
, 'lookup 7' )
2765 self
. assertRegex ( output
, 'uidrange 100-200' )
2767 def _test_route_static ( self
, manage_foreign_routes
):
2768 if not manage_foreign_routes
:
2769 copy_networkd_conf_dropin ( 'networkd-manage-foreign-routes-no.conf' )
2771 copy_network_unit ( '25-route-static.network' , '12-dummy.netdev' )
2773 self
. wait_online ([ 'dummy98:routable' ])
2775 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
2778 print ( '### ip -6 route show dev dummy98' )
2779 output
= check_output ( 'ip -6 route show dev dummy98' )
2781 self
. assertIn ( '2001:1234:5:8fff:ff:ff:ff:ff proto static' , output
)
2782 self
. assertIn ( '2001:1234:5:8f63::1 proto kernel' , output
)
2783 self
. assertIn ( '2001:1234:5:afff:ff:ff:ff:ff via fe80:0:222:4dff:ff:ff:ff:ff proto static' , output
)
2785 print ( '### ip -6 route show default' )
2786 output
= check_output ( 'ip -6 route show default' )
2788 self
. assertIn ( 'default' , output
)
2789 self
. assertIn ( 'via 2001:1234:5:8fff:ff:ff:ff:ff' , output
)
2791 print ( '### ip -4 route show dev dummy98' )
2792 output
= check_output ( 'ip -4 route show dev dummy98' )
2794 self
. assertIn ( '149.10.124.48/28 proto kernel scope link src 149.10.124.58' , output
)
2795 self
. assertIn ( '149.10.124.64 proto static scope link' , output
)
2796 self
. assertIn ( '169.254.0.0/16 proto static scope link metric 2048' , output
)
2797 self
. assertIn ( '192.168.1.1 proto static scope link initcwnd 20' , output
)
2798 self
. assertIn ( '192.168.1.2 proto static scope link initrwnd 30' , output
)
2799 self
. assertIn ( '192.168.1.3 proto static scope link advmss 30' , output
)
2800 self
. assertIn ( 'multicast 149.10.123.4 proto static' , output
)
2802 print ( '### ip -4 route show dev dummy98 default' )
2803 output
= check_output ( 'ip -4 route show dev dummy98 default' )
2805 self
. assertIn ( 'default via 149.10.125.65 proto static onlink' , output
)
2806 self
. assertIn ( 'default via 149.10.124.64 proto static' , output
)
2807 self
. assertIn ( 'default proto static' , output
)
2809 print ( '### ip -4 route show table local dev dummy98' )
2810 output
= check_output ( 'ip -4 route show table local dev dummy98' )
2812 self
. assertIn ( 'local 149.10.123.1 proto static scope host' , output
)
2813 self
. assertIn ( 'anycast 149.10.123.2 proto static scope link' , output
)
2814 self
. assertIn ( 'broadcast 149.10.123.3 proto static scope link' , output
)
2816 print ( '### ip -4 route show type blackhole' )
2817 output
= check_output ( 'ip -4 route show type blackhole' )
2819 self
. assertIn ( 'blackhole 202.54.1.2 proto static' , output
)
2821 print ( '### ip -4 route show type unreachable' )
2822 output
= check_output ( 'ip -4 route show type unreachable' )
2824 self
. assertIn ( 'unreachable 202.54.1.3 proto static' , output
)
2826 print ( '### ip -4 route show type prohibit' )
2827 output
= check_output ( 'ip -4 route show type prohibit' )
2829 self
. assertIn ( 'prohibit 202.54.1.4 proto static' , output
)
2831 print ( '### ip -6 route show type blackhole' )
2832 output
= check_output ( 'ip -6 route show type blackhole' )
2834 self
. assertIn ( 'blackhole 2001:1234:5678::2 dev lo proto static' , output
)
2836 print ( '### ip -6 route show type unreachable' )
2837 output
= check_output ( 'ip -6 route show type unreachable' )
2839 self
. assertIn ( 'unreachable 2001:1234:5678::3 dev lo proto static' , output
)
2841 print ( '### ip -6 route show type prohibit' )
2842 output
= check_output ( 'ip -6 route show type prohibit' )
2844 self
. assertIn ( 'prohibit 2001:1234:5678::4 dev lo proto static' , output
)
2846 print ( '### ip route show 192.168.10.1' )
2847 output
= check_output ( 'ip route show 192.168.10.1' )
2849 self
. assertIn ( '192.168.10.1 proto static' , output
)
2850 self
. assertIn ( 'nexthop via 149.10.124.59 dev dummy98 weight 10' , output
)
2851 self
. assertIn ( 'nexthop via 149.10.124.60 dev dummy98 weight 5' , output
)
2853 print ( '### ip route show 192.168.10.2' )
2854 output
= check_output ( 'ip route show 192.168.10.2' )
2856 # old ip command does not show IPv6 gateways...
2857 self
. assertIn ( '192.168.10.2 proto static' , output
)
2858 self
. assertIn ( 'nexthop' , output
)
2859 self
. assertIn ( 'dev dummy98 weight 10' , output
)
2860 self
. assertIn ( 'dev dummy98 weight 5' , output
)
2862 print ( '### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff' )
2863 output
= check_output ( 'ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff' )
2865 # old ip command does not show 'nexthop' keyword and weight...
2866 self
. assertIn ( '2001:1234:5:7fff:ff:ff:ff:ff' , output
)
2867 self
. assertIn ( 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98' , output
)
2868 self
. assertIn ( 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98' , output
)
2870 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2873 copy_network_unit ( '25-address-static.network' )
2875 self
. wait_online ([ 'dummy98:routable' ])
2877 # check all routes managed by Manager are removed
2878 print ( '### ip -4 route show type blackhole' )
2879 output
= check_output ( 'ip -4 route show type blackhole' )
2881 self
. assertEqual ( output
, '' )
2883 print ( '### ip -4 route show type unreachable' )
2884 output
= check_output ( 'ip -4 route show type unreachable' )
2886 self
. assertEqual ( output
, '' )
2888 print ( '### ip -4 route show type prohibit' )
2889 output
= check_output ( 'ip -4 route show type prohibit' )
2891 self
. assertEqual ( output
, '' )
2893 print ( '### ip -6 route show type blackhole' )
2894 output
= check_output ( 'ip -6 route show type blackhole' )
2896 self
. assertEqual ( output
, '' )
2898 print ( '### ip -6 route show type unreachable' )
2899 output
= check_output ( 'ip -6 route show type unreachable' )
2901 self
. assertEqual ( output
, '' )
2903 print ( '### ip -6 route show type prohibit' )
2904 output
= check_output ( 'ip -6 route show type prohibit' )
2906 self
. assertEqual ( output
, '' )
2908 remove_network_unit ( '25-address-static.network' )
2910 self
. wait_online ([ 'dummy98:routable' ])
2912 # check all routes managed by Manager are reconfigured
2913 print ( '### ip -4 route show type blackhole' )
2914 output
= check_output ( 'ip -4 route show type blackhole' )
2916 self
. assertIn ( 'blackhole 202.54.1.2 proto static' , output
)
2918 print ( '### ip -4 route show type unreachable' )
2919 output
= check_output ( 'ip -4 route show type unreachable' )
2921 self
. assertIn ( 'unreachable 202.54.1.3 proto static' , output
)
2923 print ( '### ip -4 route show type prohibit' )
2924 output
= check_output ( 'ip -4 route show type prohibit' )
2926 self
. assertIn ( 'prohibit 202.54.1.4 proto static' , output
)
2928 print ( '### ip -6 route show type blackhole' )
2929 output
= check_output ( 'ip -6 route show type blackhole' )
2931 self
. assertIn ( 'blackhole 2001:1234:5678::2 dev lo proto static' , output
)
2933 print ( '### ip -6 route show type unreachable' )
2934 output
= check_output ( 'ip -6 route show type unreachable' )
2936 self
. assertIn ( 'unreachable 2001:1234:5678::3 dev lo proto static' , output
)
2938 print ( '### ip -6 route show type prohibit' )
2939 output
= check_output ( 'ip -6 route show type prohibit' )
2941 self
. assertIn ( 'prohibit 2001:1234:5678::4 dev lo proto static' , output
)
2943 remove_link ( 'dummy98' )
2946 # check all routes managed by Manager are removed
2947 print ( '### ip -4 route show type blackhole' )
2948 output
= check_output ( 'ip -4 route show type blackhole' )
2950 self
. assertEqual ( output
, '' )
2952 print ( '### ip -4 route show type unreachable' )
2953 output
= check_output ( 'ip -4 route show type unreachable' )
2955 self
. assertEqual ( output
, '' )
2957 print ( '### ip -4 route show type prohibit' )
2958 output
= check_output ( 'ip -4 route show type prohibit' )
2960 self
. assertEqual ( output
, '' )
2962 print ( '### ip -6 route show type blackhole' )
2963 output
= check_output ( 'ip -6 route show type blackhole' )
2965 self
. assertEqual ( output
, '' )
2967 print ( '### ip -6 route show type unreachable' )
2968 output
= check_output ( 'ip -6 route show type unreachable' )
2970 self
. assertEqual ( output
, '' )
2972 print ( '### ip -6 route show type prohibit' )
2973 output
= check_output ( 'ip -6 route show type prohibit' )
2975 self
. assertEqual ( output
, '' )
2979 def test_route_static ( self
):
2981 for manage_foreign_routes
in [ True , False ]:
2987 print ( f
'### test_route_static(manage_foreign_routes= {manage_foreign_routes} )' )
2988 with self
. subTest ( manage_foreign_routes
= manage_foreign_routes
):
2989 self
._ test
_ route
_ static
( manage_foreign_routes
)
2991 @expectedFailureIfRTA_VIAIsNotSupported ()
2992 def test_route_via_ipv6 ( self
):
2993 copy_network_unit ( '25-route-via-ipv6.network' , '12-dummy.netdev' )
2995 self
. wait_online ([ 'dummy98:routable' ])
2997 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
3000 print ( '### ip -6 route show dev dummy98' )
3001 output
= check_output ( 'ip -6 route show dev dummy98' )
3003 self
. assertRegex ( output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static' )
3004 self
. assertRegex ( output
, '2001:1234:5:8f63::1 proto kernel' )
3006 print ( '### ip -4 route show dev dummy98' )
3007 output
= check_output ( 'ip -4 route show dev dummy98' )
3009 self
. assertRegex ( output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58' )
3010 self
. assertRegex ( output
, '149.10.124.66 via inet6 2001:1234:5:8fff:ff:ff:ff:ff proto static' )
3012 @expectedFailureIfModuleIsNotAvailable ( 'tcp_dctcp' )
3013 def test_route_congctl ( self
):
3014 copy_network_unit ( '25-route-congctl.network' , '12-dummy.netdev' )
3016 self
. wait_online ([ 'dummy98:routable' ])
3018 print ( '### ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff' )
3019 output
= check_output ( 'ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff' )
3021 self
. assertIn ( '2001:1234:5:8fff:ff:ff:ff:ff proto static' , output
)
3022 self
. assertIn ( 'congctl dctcp' , output
)
3024 print ( '### ip -4 route show dev dummy98 149.10.124.66' )
3025 output
= check_output ( 'ip -4 route show dev dummy98 149.10.124.66' )
3027 self
. assertIn ( '149.10.124.66 proto static' , output
)
3028 self
. assertIn ( 'congctl dctcp' , output
)
3030 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
3031 def test_route_vrf ( self
):
3032 copy_network_unit ( '25-route-vrf.network' , '12-dummy.netdev' ,
3033 '25-vrf.netdev' , '25-vrf.network' )
3035 self
. wait_online ([ 'dummy98:routable' , 'vrf99:carrier' ])
3037 output
= check_output ( 'ip route show vrf vrf99' )
3039 self
. assertRegex ( output
, 'default via 192.168.100.1' )
3041 output
= check_output ( 'ip route show' )
3043 self
. assertNotRegex ( output
, 'default via 192.168.100.1' )
3045 def test_gateway_reconfigure ( self
):
3046 copy_network_unit ( '25-gateway-static.network' , '12-dummy.netdev' )
3048 self
. wait_online ([ 'dummy98:routable' ])
3049 print ( '### ip -4 route show dev dummy98 default' )
3050 output
= check_output ( 'ip -4 route show dev dummy98 default' )
3052 self
. assertIn ( 'default via 149.10.124.59 proto static' , output
)
3053 self
. assertNotIn ( '149.10.124.60' , output
)
3055 remove_network_unit ( '25-gateway-static.network' )
3056 copy_network_unit ( '25-gateway-next-static.network' )
3058 self
. wait_online ([ 'dummy98:routable' ])
3059 print ( '### ip -4 route show dev dummy98 default' )
3060 output
= check_output ( 'ip -4 route show dev dummy98 default' )
3062 self
. assertNotIn ( '149.10.124.59' , output
)
3063 self
. assertIn ( 'default via 149.10.124.60 proto static' , output
)
3065 def test_ip_route_ipv6_src_route ( self
):
3066 # a dummy device does not make the addresses go through tentative state, so we
3067 # reuse a bond from an earlier test, which does make the addresses go through
3068 # tentative state, and do our test on that
3069 copy_network_unit ( '23-active-slave.network' , '25-route-ipv6-src.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
3071 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:routable' ])
3073 output
= check_output ( 'ip -6 route list dev bond199' )
3075 self
. assertIn ( 'abcd::/16 via 2001:1234:56:8f63::1:1 proto static src 2001:1234:56:8f63::2' , output
)
3077 def test_route_preferred_source_with_existing_address ( self
):
3079 copy_network_unit ( '25-route-preferred-source.network' , '12-dummy.netdev' )
3084 networkctl_reconfigure ( 'dummy98' )
3086 self
. wait_online ([ 'dummy98:routable' ])
3088 output
= check_output ( 'ip -6 route list dev dummy98' )
3090 self
. assertIn ( 'abcd::/16 via 2001:1234:56:8f63::1:1 proto static src 2001:1234:56:8f63::1' , output
)
3092 def test_ip_link_mac_address ( self
):
3093 copy_network_unit ( '25-address-link-section.network' , '12-dummy.netdev' )
3095 self
. wait_online ([ 'dummy98:degraded' ])
3097 output
= check_output ( 'ip link show dummy98' )
3099 self
. assertRegex ( output
, '00:01:02:aa:bb:cc' )
3101 def test_ip_link_unmanaged ( self
):
3102 copy_network_unit ( '25-link-section-unmanaged.network' , '12-dummy.netdev' )
3105 self
. wait_operstate ( 'dummy98' , 'off' , setup_state
= 'unmanaged' )
3107 def test_ipv6_address_label ( self
):
3108 copy_network_unit ( '25-ipv6-address-label-section.network' , '12-dummy.netdev' )
3110 self
. wait_online ([ 'dummy98:degraded' ])
3112 output
= check_output ( 'ip addrlabel list' )
3114 self
. assertRegex ( output
, '2004:da8:1::/64' )
3116 def test_ipv6_proxy_ndp ( self
):
3117 copy_network_unit ( '25-ipv6-proxy-ndp.network' , '12-dummy.netdev' )
3120 self
. wait_online ([ 'dummy98:routable' ])
3122 output
= check_output ( 'ip neighbor show proxy dev dummy98' )
3124 for i
in range ( 1 , 5 ):
3125 self
. assertRegex ( output
, f
'2607:5300:203:5215: {i} ::1 *proxy' )
3127 def test_neighbor_section ( self
):
3128 copy_network_unit ( '25-neighbor-section.network' , '12-dummy.netdev' )
3130 self
. wait_online ([ 'dummy98:degraded' ], timeout
= '40s' )
3132 print ( '### ip neigh list dev dummy98' )
3133 output
= check_output ( 'ip neigh list dev dummy98' )
3135 self
. assertRegex ( output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT' )
3136 self
. assertRegex ( output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT' )
3138 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3141 def test_neighbor_reconfigure ( self
):
3142 copy_network_unit ( '25-neighbor-section.network' , '12-dummy.netdev' )
3144 self
. wait_online ([ 'dummy98:degraded' ], timeout
= '40s' )
3146 print ( '### ip neigh list dev dummy98' )
3147 output
= check_output ( 'ip neigh list dev dummy98' )
3149 self
. assertRegex ( output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT' )
3150 self
. assertRegex ( output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT' )
3152 remove_network_unit ( '25-neighbor-section.network' )
3153 copy_network_unit ( '25-neighbor-next.network' )
3155 self
. wait_online ([ 'dummy98:degraded' ], timeout
= '40s' )
3156 print ( '### ip neigh list dev dummy98' )
3157 output
= check_output ( 'ip neigh list dev dummy98' )
3159 self
. assertNotRegex ( output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT' )
3160 self
. assertRegex ( output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT' )
3161 self
. assertNotRegex ( output
, '2004:da8:1::1.*PERMANENT' )
3163 def test_neighbor_gre ( self
):
3164 copy_network_unit ( '25-neighbor-ip.network' , '25-neighbor-ipv6.network' , '25-neighbor-ip-dummy.network' ,
3165 '12-dummy.netdev' , '25-gre-tunnel-remote-any.netdev' , '25-ip6gre-tunnel-remote-any.netdev' )
3167 self
. wait_online ([ 'dummy98:degraded' , 'gretun97:routable' , 'ip6gretun97:routable' ], timeout
= '40s' )
3169 output
= check_output ( 'ip neigh list dev gretun97' )
3171 self
. assertRegex ( output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT' )
3173 output
= check_output ( 'ip neigh list dev ip6gretun97' )
3175 self
. assertRegex ( output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT' )
3177 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3180 def test_link_local_addressing ( self
):
3181 copy_network_unit ( '25-link-local-addressing-yes.network' , '11-dummy.netdev' ,
3182 '25-link-local-addressing-no.network' , '12-dummy.netdev' )
3184 self
. wait_online ([ 'test1:degraded' , 'dummy98:carrier' ])
3186 output
= check_output ( 'ip address show dev test1' )
3188 self
. assertRegex ( output
, 'inet .* scope link' )
3189 self
. assertRegex ( output
, 'inet6 .* scope link' )
3191 output
= check_output ( 'ip address show dev dummy98' )
3193 self
. assertNotRegex ( output
, 'inet6* .* scope link' )
3195 # Documentation/networking/ip-sysctl.txt
3197 # addr_gen_mode - INTEGER
3198 # Defines how link-local and autoconf addresses are generated.
3200 # 0: generate address based on EUI64 (default)
3201 # 1: do no generate a link-local address, use EUI64 for addresses generated
3203 # 2: generate stable privacy addresses, using the secret from
3204 # stable_secret (RFC7217)
3205 # 3: generate stable privacy addresses, using a random secret if unset
3207 self
. check_ipv6_sysctl_attr ( 'test1' , 'stable_secret' , '0123:4567:89ab:cdef:0123:4567:89ab:cdef' )
3208 self
. check_ipv6_sysctl_attr ( 'test1' , 'addr_gen_mode' , '2' )
3209 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'addr_gen_mode' , '1' )
3211 def test_link_local_addressing_ipv6ll ( self
):
3212 copy_network_unit ( '26-link-local-addressing-ipv6.network' , '12-dummy.netdev' )
3214 self
. wait_online ([ 'dummy98:degraded' ])
3216 # An IPv6LL address exists by default.
3217 output
= check_output ( 'ip address show dev dummy98' )
3219 self
. assertRegex ( output
, 'inet6 .* scope link' )
3221 copy_network_unit ( '25-link-local-addressing-no.network' )
3223 self
. wait_online ([ 'dummy98:carrier' ])
3225 # Check if the IPv6LL address is removed.
3226 output
= check_output ( 'ip address show dev dummy98' )
3228 self
. assertNotRegex ( output
, 'inet6 .* scope link' )
3230 remove_network_unit ( '25-link-local-addressing-no.network' )
3232 self
. wait_online ([ 'dummy98:degraded' ])
3234 # Check if a new IPv6LL address is assigned.
3235 output
= check_output ( 'ip address show dev dummy98' )
3237 self
. assertRegex ( output
, 'inet6 .* scope link' )
3239 def test_sysctl ( self
):
3240 copy_networkd_conf_dropin ( '25-global-ipv6-privacy-extensions.conf' )
3241 copy_network_unit ( '25-sysctl.network' , '12-dummy.netdev' , copy_dropins
= False )
3243 self
. wait_online ([ 'dummy98:degraded' ])
3245 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
3246 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'use_tempaddr' , '1' )
3247 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'dad_transmits' , '3' )
3248 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'hop_limit' , '5' )
3249 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'proxy_ndp' , '1' )
3250 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
3251 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'proxy_arp' , '1' )
3252 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'accept_local' , '1' )
3253 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'rp_filter' , '0' )
3255 copy_network_unit ( '25-sysctl.network.d/25-ipv6-privacy-extensions.conf' )
3257 self
. wait_online ([ 'dummy98:degraded' ])
3259 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'use_tempaddr' , '2' )
3261 def test_sysctl_disable_ipv6 ( self
):
3262 copy_network_unit ( '25-sysctl-disable-ipv6.network' , '12-dummy.netdev' )
3264 print ( '## Disable ipv6' )
3265 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=1' )
3266 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=1' )
3269 self
. wait_online ([ 'dummy98:routable' ])
3271 output
= check_output ( 'ip -4 address show dummy98' )
3273 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3274 output
= check_output ( 'ip -6 address show dummy98' )
3276 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3277 self
. assertRegex ( output
, 'inet6 .* scope link' )
3278 output
= check_output ( 'ip -4 route show dev dummy98' )
3280 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3281 output
= check_output ( 'ip -6 route show default' )
3283 self
. assertRegex ( output
, 'default' )
3284 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3286 remove_link ( 'dummy98' )
3288 print ( '## Enable ipv6' )
3289 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=0' )
3290 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=0' )
3293 self
. wait_online ([ 'dummy98:routable' ])
3295 output
= check_output ( 'ip -4 address show dummy98' )
3297 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3298 output
= check_output ( 'ip -6 address show dummy98' )
3300 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3301 self
. assertRegex ( output
, 'inet6 .* scope link' )
3302 output
= check_output ( 'ip -4 route show dev dummy98' )
3304 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3305 output
= check_output ( 'ip -6 route show default' )
3307 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3309 def test_bind_carrier ( self
):
3310 copy_network_unit ( '25-bind-carrier.network' , '11-dummy.netdev' )
3313 # no bound interface.
3314 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
3315 output
= check_output ( 'ip address show test1' )
3317 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3318 self
. assertIn ( 'DOWN' , output
)
3319 self
. assertNotIn ( '192.168.10' , output
)
3321 # add one bound interface. The interface will be up.
3322 check_output ( 'ip link add dummy98 type dummy' )
3323 check_output ( 'ip link set dummy98 up' )
3324 self
. wait_online ([ 'test1:routable' ])
3325 output
= check_output ( 'ip address show test1' )
3327 self
. assertIn ( 'UP,LOWER_UP' , output
)
3328 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3330 # add another bound interface. The interface is still up.
3331 check_output ( 'ip link add dummy99 type dummy' )
3332 check_output ( 'ip link set dummy99 up' )
3333 self
. wait_operstate ( 'dummy99' , 'degraded' , setup_state
= 'unmanaged' )
3334 output
= check_output ( 'ip address show test1' )
3336 self
. assertIn ( 'UP,LOWER_UP' , output
)
3337 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3339 # remove one of the bound interfaces. The interface is still up
3340 remove_link ( 'dummy98' )
3341 output
= check_output ( 'ip address show test1' )
3343 self
. assertIn ( 'UP,LOWER_UP' , output
)
3344 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3346 # bring down the remaining bound interface. The interface will be down.
3347 check_output ( 'ip link set dummy99 down' )
3348 self
. wait_operstate ( 'test1' , 'off' )
3349 self
. wait_address_dropped ( 'test1' , r
'192.168.10' , ipv
= '-4' , timeout_sec
= 10 )
3350 output
= check_output ( 'ip address show test1' )
3352 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3353 self
. assertIn ( 'DOWN' , output
)
3354 self
. assertNotIn ( '192.168.10' , output
)
3356 # bring up the bound interface. The interface will be up.
3357 check_output ( 'ip link set dummy99 up' )
3358 self
. wait_online ([ 'test1:routable' ])
3359 output
= check_output ( 'ip address show test1' )
3361 self
. assertIn ( 'UP,LOWER_UP' , output
)
3362 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3364 # remove the remaining bound interface. The interface will be down.
3365 remove_link ( 'dummy99' )
3366 self
. wait_operstate ( 'test1' , 'off' )
3367 self
. wait_address_dropped ( 'test1' , r
'192.168.10' , ipv
= '-4' , timeout_sec
= 10 )
3368 output
= check_output ( 'ip address show test1' )
3370 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3371 self
. assertIn ( 'DOWN' , output
)
3372 self
. assertNotIn ( '192.168.10' , output
)
3374 # re-add one bound interface. The interface will be up.
3375 check_output ( 'ip link add dummy98 type dummy' )
3376 check_output ( 'ip link set dummy98 up' )
3377 self
. wait_online ([ 'test1:routable' ])
3378 output
= check_output ( 'ip address show test1' )
3380 self
. assertIn ( 'UP,LOWER_UP' , output
)
3381 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3383 def _test_activation_policy ( self
, interface
, test
):
3384 conffile
= '25-activation-policy.network'
3386 conffile
= f
' {conffile} .d/ {test} .conf'
3387 if interface
== 'vlan99' :
3388 copy_network_unit ( '21-vlan.netdev' , '21-vlan-test1.network' )
3389 copy_network_unit ( '11-dummy.netdev' , conffile
, copy_dropins
= False )
3392 always
= test
. startswith ( 'always' )
3393 initial_up
= test
!= 'manual' and not test
. endswith ( 'down' ) # note: default is up
3394 expect_up
= initial_up
3395 next_up
= not expect_up
3397 if test
. endswith ( 'down' ):
3398 self
. wait_activated ( interface
)
3400 for iteration
in range ( 4 ):
3401 with self
. subTest ( iteration
= iteration
, expect_up
= expect_up
):
3402 operstate
= 'routable' if expect_up
else 'off'
3403 setup_state
= 'configured' if expect_up
else ( 'configuring' if iteration
== 0 else None )
3404 self
. wait_operstate ( interface
, operstate
, setup_state
= setup_state
, setup_timeout
= 20 )
3407 self
. assertIn ( 'UP' , check_output ( f
'ip link show {interface} ' ))
3408 self
. assertIn ( '192.168.10.30/24' , check_output ( f
'ip address show {interface} ' ))
3409 self
. assertIn ( 'default via 192.168.10.1' , check_output ( f
'ip route show dev {interface} ' ))
3411 self
. assertIn ( 'DOWN' , check_output ( f
'ip link show {interface} ' ))
3414 check_output ( f
'ip link set dev {interface} up' )
3416 check_output ( f
'ip link set dev {interface} down' )
3417 expect_up
= initial_up
if always
else next_up
3418 next_up
= not next_up
3422 def test_activation_policy ( self
):
3424 for interface
in [ 'test1' , 'vlan99' ]:
3425 for test
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , '' ]:
3431 print ( f
'### test_activation_policy(interface= {interface} , test= {test} )' )
3432 with self
. subTest ( interface
= interface
, test
= test
):
3433 self
._ test
_ activation
_ policy
( interface
, test
)
3435 def _test_activation_policy_required_for_online ( self
, policy
, required
):
3436 conffile
= '25-activation-policy.network'
3437 units
= [ '11-dummy.netdev' , '12-dummy.netdev' , '12-dummy.network' , conffile
]
3439 units
+= [ f
' {conffile} .d/ {policy} .conf' ]
3441 units
+= [ f
' {conffile} .d/required- {required} .conf' ]
3442 copy_network_unit (* units
, copy_dropins
= False )
3445 if policy
. endswith ( 'down' ):
3446 self
. wait_activated ( 'test1' )
3448 if policy
. endswith ( 'down' ) or policy
== 'manual' :
3449 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
3451 self
. wait_online ([ 'test1' ])
3453 if policy
== 'always-down' :
3454 # if always-down, required for online is forced to no
3457 # otherwise if required for online is specified, it should match that
3458 expected
= required
== 'yes'
3460 # otherwise if only policy specified, required for online defaults to
3461 # true if policy is up, always-up, or bound
3462 expected
= policy
. endswith ( 'up' ) or policy
== 'bound'
3464 # default is true, if neither are specified
3467 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
3470 yesno
= 'yes' if expected
else 'no'
3471 self
. assertRegex ( output
, f
'Required For Online: {yesno} ' )
3473 def test_activation_policy_required_for_online ( self
):
3475 for policy
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , 'bound' , '' ]:
3476 for required
in [ 'yes' , 'no' , '' ]:
3482 print ( f
'### test_activation_policy_required_for_online(policy= {policy} , required= {required} )' )
3483 with self
. subTest ( policy
= policy
, required
= required
):
3484 self
._ test
_ activation
_ policy
_ required
_ for
_ online
( policy
, required
)
3486 def test_domain ( self
):
3487 copy_network_unit ( '12-dummy.netdev' , '24-search-domain.network' )
3489 self
. wait_online ([ 'dummy98:routable' ])
3491 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
3493 self
. assertRegex ( output
, 'Address: 192.168.42.100' )
3494 self
. assertRegex ( output
, 'DNS: 192.168.42.1' )
3495 self
. assertRegex ( output
, 'Search Domains: one' )
3497 def test_keep_configuration_static ( self
):
3498 check_output ( 'ip link add name dummy98 type dummy' )
3499 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
3500 check_output ( 'ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500' )
3501 output
= check_output ( 'ip address show dummy98' )
3503 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
3504 self
. assertRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
3505 output
= check_output ( 'ip route show dev dummy98' )
3508 copy_network_unit ( '24-keep-configuration-static.network' )
3510 self
. wait_online ([ 'dummy98:routable' ])
3512 output
= check_output ( 'ip address show dummy98' )
3514 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
3515 self
. assertNotRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
3517 @expectedFailureIfNexthopIsNotAvailable ()
3518 def test_nexthop ( self
):
3519 def check_nexthop ( self
):
3520 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
3522 output
= check_output ( 'ip nexthop list dev veth99' )
3524 self
. assertIn ( 'id 1 via 192.168.5.1 dev veth99' , output
)
3525 self
. assertIn ( 'id 2 via 2001:1234:5:8f63::2 dev veth99' , output
)
3526 self
. assertIn ( 'id 3 dev veth99' , output
)
3527 self
. assertIn ( 'id 4 dev veth99' , output
)
3528 self
. assertRegex ( output
, 'id 5 via 192.168.10.1 dev veth99 .*onlink' )
3529 self
. assertIn ( 'id 8 via fe80:0:222:4dff:ff:ff:ff:ff dev veth99' , output
)
3530 self
. assertRegex ( output
, r
'id [0-9]* via 192.168.5.2 dev veth99' )
3532 output
= check_output ( 'ip nexthop list dev dummy98' )
3534 self
. assertIn ( 'id 20 via 192.168.20.1 dev dummy98' , output
)
3536 # kernel manages blackhole nexthops on lo
3537 output
= check_output ( 'ip nexthop list dev lo' )
3539 self
. assertIn ( 'id 6 blackhole' , output
)
3540 self
. assertIn ( 'id 7 blackhole' , output
)
3542 # group nexthops are shown with -0 option
3543 output
= check_output ( 'ip -0 nexthop list id 21' )
3545 self
. assertRegex ( output
, r
'id 21 group (1,3/20|20/1,3)' )
3547 output
= check_output ( 'ip route show dev veth99 10.10.10.10' )
3549 self
. assertEqual ( '10.10.10.10 nhid 1 via 192.168.5.1 proto static' , output
)
3551 output
= check_output ( 'ip route show dev veth99 10.10.10.11' )
3553 self
. assertEqual ( '10.10.10.11 nhid 2 via inet6 2001:1234:5:8f63::2 proto static' , output
)
3555 output
= check_output ( 'ip route show dev veth99 10.10.10.12' )
3557 self
. assertEqual ( '10.10.10.12 nhid 5 via 192.168.10.1 proto static onlink' , output
)
3559 output
= check_output ( 'ip -6 route show dev veth99 2001:1234:5:8f62::1' )
3561 self
. assertEqual ( '2001:1234:5:8f62::1 nhid 2 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium' , output
)
3563 output
= check_output ( 'ip route show 10.10.10.13' )
3565 self
. assertEqual ( 'blackhole 10.10.10.13 nhid 6 dev lo proto static' , output
)
3567 output
= check_output ( 'ip -6 route show 2001:1234:5:8f62::2' )
3569 self
. assertEqual ( 'blackhole 2001:1234:5:8f62::2 nhid 7 dev lo proto static metric 1024 pref medium' , output
)
3571 output
= check_output ( 'ip route show 10.10.10.14' )
3573 self
. assertIn ( '10.10.10.14 nhid 21 proto static' , output
)
3574 self
. assertIn ( 'nexthop via 192.168.20.1 dev dummy98 weight 1' , output
)
3575 self
. assertIn ( 'nexthop via 192.168.5.1 dev veth99 weight 3' , output
)
3577 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3580 copy_network_unit ( '25-nexthop.network' , '25-veth.netdev' , '25-veth-peer.network' ,
3581 '12-dummy.netdev' , '25-nexthop-dummy.network' )
3586 remove_network_unit ( '25-nexthop.network' )
3587 copy_network_unit ( '25-nexthop-nothing.network' )
3589 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
3591 output
= check_output ( 'ip nexthop list dev veth99' )
3593 self
. assertEqual ( output
, '' )
3594 output
= check_output ( 'ip nexthop list dev lo' )
3596 self
. assertEqual ( output
, '' )
3598 remove_network_unit ( '25-nexthop-nothing.network' )
3599 copy_network_unit ( '25-nexthop.network' )
3600 networkctl_reconfigure ( 'dummy98' )
3605 remove_link ( 'veth99' )
3608 output
= check_output ( 'ip nexthop list dev lo' )
3610 self
. assertEqual ( output
, '' )
3612 class NetworkdTCTests ( unittest
. TestCase
, Utilities
):
3620 @expectedFailureIfModuleIsNotAvailable ( 'sch_cake' )
3621 def test_qdisc_cake ( self
):
3622 copy_network_unit ( '25-qdisc-cake.network' , '12-dummy.netdev' )
3624 self
. wait_online ([ 'dummy98:routable' ])
3626 output
= check_output ( 'tc qdisc show dev dummy98' )
3628 self
. assertIn ( 'qdisc cake 3a: root' , output
)
3629 self
. assertIn ( 'bandwidth 500Mbit' , output
)
3630 self
. assertIn ( 'autorate-ingress' , output
)
3631 self
. assertIn ( 'diffserv8' , output
)
3632 self
. assertIn ( 'dual-dsthost' , output
)
3633 self
. assertIn ( ' nat' , output
)
3634 self
. assertIn ( ' wash' , output
)
3635 self
. assertIn ( ' split-gso' , output
)
3636 self
. assertIn ( ' raw' , output
)
3637 self
. assertIn ( ' atm' , output
)
3638 self
. assertIn ( 'overhead 128' , output
)
3639 self
. assertIn ( 'mpu 20' , output
)
3640 self
. assertIn ( 'fwmark 0xff00' , output
)
3641 self
. assertIn ( 'rtt 1s' , output
)
3642 self
. assertIn ( 'ack-filter-aggressive' , output
)
3644 @expectedFailureIfModuleIsNotAvailable ( 'sch_codel' )
3645 def test_qdisc_codel ( self
):
3646 copy_network_unit ( '25-qdisc-codel.network' , '12-dummy.netdev' )
3648 self
. wait_online ([ 'dummy98:routable' ])
3650 output
= check_output ( 'tc qdisc show dev dummy98' )
3652 self
. assertRegex ( output
, 'qdisc codel 33: root' )
3653 self
. assertRegex ( output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn' )
3655 @expectedFailureIfModuleIsNotAvailable ( 'sch_drr' )
3656 def test_qdisc_drr ( self
):
3657 copy_network_unit ( '25-qdisc-drr.network' , '12-dummy.netdev' )
3659 self
. wait_online ([ 'dummy98:routable' ])
3661 output
= check_output ( 'tc qdisc show dev dummy98' )
3663 self
. assertRegex ( output
, 'qdisc drr 2: root' )
3664 output
= check_output ( 'tc class show dev dummy98' )
3666 self
. assertRegex ( output
, 'class drr 2:30 root quantum 2000b' )
3668 @expectedFailureIfModuleIsNotAvailable ( 'sch_ets' )
3669 def test_qdisc_ets ( self
):
3670 copy_network_unit ( '25-qdisc-ets.network' , '12-dummy.netdev' )
3672 self
. wait_online ([ 'dummy98:routable' ])
3674 output
= check_output ( 'tc qdisc show dev dummy98' )
3677 self
. assertRegex ( output
, 'qdisc ets 3a: root' )
3678 self
. assertRegex ( output
, 'bands 10 strict 3' )
3679 self
. assertRegex ( output
, 'quanta 1 2 3 4 5' )
3680 self
. assertRegex ( output
, 'priomap 3 4 5 6 7' )
3682 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq' )
3683 def test_qdisc_fq ( self
):
3684 copy_network_unit ( '25-qdisc-fq.network' , '12-dummy.netdev' )
3686 self
. wait_online ([ 'dummy98:routable' ])
3688 output
= check_output ( 'tc qdisc show dev dummy98' )
3690 self
. assertRegex ( output
, 'qdisc fq 32: root' )
3691 self
. assertRegex ( output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511' )
3692 self
. assertRegex ( output
, 'quantum 1500' )
3693 self
. assertRegex ( output
, 'initial_quantum 13000' )
3694 self
. assertRegex ( output
, 'maxrate 1Mbit' )
3696 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_codel' )
3697 def test_qdisc_fq_codel ( self
):
3698 copy_network_unit ( '25-qdisc-fq_codel.network' , '12-dummy.netdev' )
3700 self
. wait_online ([ 'dummy98:routable' ])
3702 output
= check_output ( 'tc qdisc show dev dummy98' )
3704 self
. assertRegex ( output
, 'qdisc fq_codel 34: root' )
3705 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' )
3707 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_pie' )
3708 def test_qdisc_fq_pie ( self
):
3709 copy_network_unit ( '25-qdisc-fq_pie.network' , '12-dummy.netdev' )
3711 self
. wait_online ([ 'dummy98:routable' ])
3713 output
= check_output ( 'tc qdisc show dev dummy98' )
3716 self
. assertRegex ( output
, 'qdisc fq_pie 3a: root' )
3717 self
. assertRegex ( output
, 'limit 200000p' )
3719 @expectedFailureIfModuleIsNotAvailable ( 'sch_gred' )
3720 def test_qdisc_gred ( self
):
3721 copy_network_unit ( '25-qdisc-gred.network' , '12-dummy.netdev' )
3723 self
. wait_online ([ 'dummy98:routable' ])
3725 output
= check_output ( 'tc qdisc show dev dummy98' )
3727 self
. assertRegex ( output
, 'qdisc gred 38: root' )
3728 self
. assertRegex ( output
, 'vqs 12 default 10 grio' )
3730 @expectedFailureIfModuleIsNotAvailable ( 'sch_hhf' )
3731 def test_qdisc_hhf ( self
):
3732 copy_network_unit ( '25-qdisc-hhf.network' , '12-dummy.netdev' )
3734 self
. wait_online ([ 'dummy98:routable' ])
3736 output
= check_output ( 'tc qdisc show dev dummy98' )
3738 self
. assertRegex ( output
, 'qdisc hhf 3a: root' )
3739 self
. assertRegex ( output
, 'limit 1022p' )
3741 @expectedFailureIfModuleIsNotAvailable ( 'sch_htb' )
3742 def test_qdisc_htb_fifo ( self
):
3743 copy_network_unit ( '25-qdisc-htb-fifo.network' , '12-dummy.netdev' )
3745 self
. wait_online ([ 'dummy98:routable' ])
3747 output
= check_output ( 'tc qdisc show dev dummy98' )
3749 self
. assertRegex ( output
, 'qdisc htb 2: root' )
3750 self
. assertRegex ( output
, r
'default (0x30|30)' )
3752 self
. assertRegex ( output
, 'qdisc pfifo 37: parent 2:37' )
3753 self
. assertRegex ( output
, 'limit 100000p' )
3755 self
. assertRegex ( output
, 'qdisc bfifo 3a: parent 2:3a' )
3756 self
. assertRegex ( output
, 'limit 1000000' )
3758 self
. assertRegex ( output
, 'qdisc pfifo_head_drop 3b: parent 2:3b' )
3759 self
. assertRegex ( output
, 'limit 1023p' )
3761 self
. assertRegex ( output
, 'qdisc pfifo_fast 3c: parent 2:3c' )
3763 output
= check_output ( 'tc -d class show dev dummy98' )
3765 # Here (:|prio) is a workaround for a bug in iproute2 v6.2.0 caused by
3766 # https://github.com/shemminger/iproute2/commit/010a8388aea11e767ba3a2506728b9ad9760df0e
3767 # which is fixed in v6.3.0 by
3768 # https://github.com/shemminger/iproute2/commit/4e0e56e0ef05387f7f5d8ab41fe6ec6a1897b26d
3769 self
. assertRegex ( output
, 'class htb 2:37 root leaf 37(:|prio) ' )
3770 self
. assertRegex ( output
, 'class htb 2:3a root leaf 3a(:|prio) ' )
3771 self
. assertRegex ( output
, 'class htb 2:3b root leaf 3b(:|prio) ' )
3772 self
. assertRegex ( output
, 'class htb 2:3c root leaf 3c(:|prio) ' )
3773 self
. assertRegex ( output
, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit' )
3774 self
. assertRegex ( output
, 'burst 123456' )
3775 self
. assertRegex ( output
, 'cburst 123457' )
3777 @expectedFailureIfModuleIsNotAvailable ( 'sch_ingress' )
3778 def test_qdisc_ingress ( self
):
3779 copy_network_unit ( '25-qdisc-clsact.network' , '12-dummy.netdev' ,
3780 '25-qdisc-ingress.network' , '11-dummy.netdev' )
3782 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' ])
3784 output
= check_output ( 'tc qdisc show dev dummy98' )
3786 self
. assertRegex ( output
, 'qdisc clsact' )
3788 output
= check_output ( 'tc qdisc show dev test1' )
3790 self
. assertRegex ( output
, 'qdisc ingress' )
3792 @expectedFailureIfModuleIsNotAvailable ( 'sch_netem' )
3793 def test_qdisc_netem ( self
):
3794 copy_network_unit ( '25-qdisc-netem.network' , '12-dummy.netdev' ,
3795 '25-qdisc-netem-compat.network' , '11-dummy.netdev' )
3797 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' ])
3799 output
= check_output ( 'tc qdisc show dev dummy98' )
3801 self
. assertRegex ( output
, 'qdisc netem 30: root' )
3802 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
3804 output
= check_output ( 'tc qdisc show dev test1' )
3806 self
. assertRegex ( output
, 'qdisc netem [0-9a-f]*: root' )
3807 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
3809 @expectedFailureIfModuleIsNotAvailable ( 'sch_pie' )
3810 def test_qdisc_pie ( self
):
3811 copy_network_unit ( '25-qdisc-pie.network' , '12-dummy.netdev' )
3813 self
. wait_online ([ 'dummy98:routable' ])
3815 output
= check_output ( 'tc qdisc show dev dummy98' )
3817 self
. assertRegex ( output
, 'qdisc pie 3a: root' )
3818 self
. assertRegex ( output
, 'limit 200000' )
3820 @expectedFailureIfModuleIsNotAvailable ( 'sch_qfq' )
3821 def test_qdisc_qfq ( self
):
3822 copy_network_unit ( '25-qdisc-qfq.network' , '12-dummy.netdev' )
3824 self
. wait_online ([ 'dummy98:routable' ])
3826 output
= check_output ( 'tc qdisc show dev dummy98' )
3828 self
. assertRegex ( output
, 'qdisc qfq 2: root' )
3829 output
= check_output ( 'tc class show dev dummy98' )
3831 self
. assertRegex ( output
, 'class qfq 2:30 root weight 2 maxpkt 16000' )
3832 self
. assertRegex ( output
, 'class qfq 2:31 root weight 10 maxpkt 8000' )
3834 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfb' )
3835 def test_qdisc_sfb ( self
):
3836 copy_network_unit ( '25-qdisc-sfb.network' , '12-dummy.netdev' )
3838 self
. wait_online ([ 'dummy98:routable' ])
3840 output
= check_output ( 'tc qdisc show dev dummy98' )
3842 self
. assertRegex ( output
, 'qdisc sfb 39: root' )
3843 self
. assertRegex ( output
, 'limit 200000' )
3845 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfq' )
3846 def test_qdisc_sfq ( self
):
3847 copy_network_unit ( '25-qdisc-sfq.network' , '12-dummy.netdev' )
3849 self
. wait_online ([ 'dummy98:routable' ])
3851 output
= check_output ( 'tc qdisc show dev dummy98' )
3853 self
. assertRegex ( output
, 'qdisc sfq 36: root' )
3854 self
. assertRegex ( output
, 'perturb 5sec' )
3856 @expectedFailureIfModuleIsNotAvailable ( 'sch_tbf' )
3857 def test_qdisc_tbf ( self
):
3858 copy_network_unit ( '25-qdisc-tbf.network' , '12-dummy.netdev' )
3860 self
. wait_online ([ 'dummy98:routable' ])
3862 output
= check_output ( 'tc qdisc show dev dummy98' )
3864 self
. assertRegex ( output
, 'qdisc tbf 35: root' )
3865 self
. assertRegex ( output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms' )
3867 @expectedFailureIfModuleIsNotAvailable ( 'sch_teql' )
3868 def test_qdisc_teql ( self
):
3869 call_quiet ( 'rmmod sch_teql' )
3871 copy_network_unit ( '25-qdisc-teql.network' , '12-dummy.netdev' )
3873 self
. wait_links ( 'dummy98' )
3874 check_output ( 'modprobe sch_teql max_equalizers=2' )
3875 self
. wait_online ([ 'dummy98:routable' ])
3877 output
= check_output ( 'tc qdisc show dev dummy98' )
3879 self
. assertRegex ( output
, 'qdisc teql1 31: root' )
3881 class NetworkdStateFileTests ( unittest
. TestCase
, Utilities
):
3889 def test_state_file ( self
):
3890 copy_network_unit ( '12-dummy.netdev' , '25-state-file-tests.network' )
3892 self
. wait_online ([ 'dummy98:routable' ])
3894 # make link state file updated
3895 check_output (* resolvectl_cmd
, 'revert' , 'dummy98' , env
= env
)
3897 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3900 output
= read_link_state_file ( 'dummy98' )
3902 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
3903 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
3904 self
. assertIn ( 'ADMIN_STATE=configured' , output
)
3905 self
. assertIn ( 'OPER_STATE=routable' , output
)
3906 self
. assertIn ( 'REQUIRED_FOR_ONLINE=yes' , output
)
3907 self
. assertIn ( 'REQUIRED_OPER_STATE_FOR_ONLINE=routable' , output
)
3908 self
. assertIn ( 'REQUIRED_FAMILY_FOR_ONLINE=both' , output
)
3909 self
. assertIn ( 'ACTIVATION_POLICY=up' , output
)
3910 self
. assertIn ( 'NETWORK_FILE=/run/systemd/network/25-state-file-tests.network' , output
)
3911 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
3912 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
3913 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
3914 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
3915 self
. assertIn ( 'LLMNR=no' , output
)
3916 self
. assertIn ( 'MDNS=yes' , output
)
3917 self
. assertIn ( 'DNSSEC=no' , output
)
3919 check_output (* resolvectl_cmd
, 'dns' , 'dummy98' , '10.10.10.12#ccc.com' , '10.10.10.13' , '1111:2222::3333' , env
= env
)
3920 check_output (* resolvectl_cmd
, 'domain' , 'dummy98' , 'hogehogehoge' , '~foofoofoo' , env
= env
)
3921 check_output (* resolvectl_cmd
, 'llmnr' , 'dummy98' , 'yes' , env
= env
)
3922 check_output (* resolvectl_cmd
, 'mdns' , 'dummy98' , 'no' , env
= env
)
3923 check_output (* resolvectl_cmd
, 'dnssec' , 'dummy98' , 'yes' , env
= env
)
3924 check_output (* timedatectl_cmd
, 'ntp-servers' , 'dummy98' , '2.fedora.pool.ntp.org' , '3.fedora.pool.ntp.org' , env
= env
)
3926 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3929 output
= read_link_state_file ( 'dummy98' )
3931 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
3932 self
. assertIn ( 'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org' , output
)
3933 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
3934 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
3935 self
. assertIn ( 'LLMNR=yes' , output
)
3936 self
. assertIn ( 'MDNS=no' , output
)
3937 self
. assertIn ( 'DNSSEC=yes' , output
)
3939 check_output (* timedatectl_cmd
, 'revert' , 'dummy98' , env
= env
)
3941 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3944 output
= read_link_state_file ( 'dummy98' )
3946 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
3947 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
3948 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
3949 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
3950 self
. assertIn ( 'LLMNR=yes' , output
)
3951 self
. assertIn ( 'MDNS=no' , output
)
3952 self
. assertIn ( 'DNSSEC=yes' , output
)
3954 check_output (* resolvectl_cmd
, 'revert' , 'dummy98' , env
= env
)
3956 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3959 output
= read_link_state_file ( 'dummy98' )
3961 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
3962 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
3963 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
3964 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
3965 self
. assertIn ( 'LLMNR=no' , output
)
3966 self
. assertIn ( 'MDNS=yes' , output
)
3967 self
. assertIn ( 'DNSSEC=no' , output
)
3969 def test_address_state ( self
):
3970 copy_network_unit ( '12-dummy.netdev' , '12-dummy-no-address.network' )
3973 self
. wait_online ([ 'dummy98:degraded' ])
3975 output
= read_link_state_file ( 'dummy98' )
3976 self
. assertIn ( 'IPV4_ADDRESS_STATE=off' , output
)
3977 self
. assertIn ( 'IPV6_ADDRESS_STATE=degraded' , output
)
3979 # with a routable IPv4 address
3980 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
3981 self
. wait_online ([ 'dummy98:routable' ], ipv4
= True )
3982 self
. wait_online ([ 'dummy98:routable' ])
3984 output
= read_link_state_file ( 'dummy98' )
3985 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
3986 self
. assertIn ( 'IPV6_ADDRESS_STATE=degraded' , output
)
3988 check_output ( 'ip address del 10.1.2.3/16 dev dummy98' )
3990 # with a routable IPv6 address
3991 check_output ( 'ip address add 2002:da8:1:0:1034:56ff:fe78:9abc/64 dev dummy98' )
3992 self
. wait_online ([ 'dummy98:routable' ], ipv6
= True )
3993 self
. wait_online ([ 'dummy98:routable' ])
3995 output
= read_link_state_file ( 'dummy98' )
3996 self
. assertIn ( 'IPV4_ADDRESS_STATE=off' , output
)
3997 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
3999 class NetworkdBondTests ( unittest
. TestCase
, Utilities
):
4007 def test_bond_keep_master ( self
):
4008 check_output ( 'ip link add bond199 type bond mode active-backup' )
4009 check_output ( 'ip link add dummy98 type dummy' )
4010 check_output ( 'ip link set dummy98 master bond199' )
4012 copy_network_unit ( '23-keep-master.network' )
4014 self
. wait_online ([ 'dummy98:enslaved' ])
4016 output
= check_output ( 'ip -d link show bond199' )
4018 self
. assertRegex ( output
, 'active_slave dummy98' )
4020 output
= check_output ( 'ip -d link show dummy98' )
4022 self
. assertRegex ( output
, 'master bond199' )
4024 def test_bond_active_slave ( self
):
4025 copy_network_unit ( '23-active-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
4027 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
4029 output
= check_output ( 'ip -d link show bond199' )
4031 self
. assertIn ( 'active_slave dummy98' , output
)
4033 def test_bond_primary_slave ( self
):
4034 copy_network_unit ( '23-primary-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
4036 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
4038 output
= check_output ( 'ip -d link show bond199' )
4040 self
. assertIn ( 'primary dummy98' , output
)
4043 mkdir_p ( os
. path
. join ( network_unit_dir
, '23-bond199.network.d' ))
4044 for mac
in [ '00:11:22:33:44:55' , '00:11:22:33:44:56' ]:
4045 with
open ( os
. path
. join ( network_unit_dir
, '23-bond199.network.d/mac.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
4046 f
. write ( f
'[Link] \n MACAddress= {mac} \n ' )
4049 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
4051 output
= check_output ( 'ip -d link show bond199' )
4053 self
. assertIn ( f
'link/ether {mac} ' , output
)
4055 def test_bond_operstate ( self
):
4056 copy_network_unit ( '25-bond.netdev' , '11-dummy.netdev' , '12-dummy.netdev' ,
4057 '25-bond99.network' , '25-bond-slave.network' )
4059 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bond99:routable' ])
4061 output
= check_output ( 'ip -d link show dummy98' )
4063 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
4065 output
= check_output ( 'ip -d link show test1' )
4067 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
4069 output
= check_output ( 'ip -d link show bond99' )
4071 self
. assertRegex ( output
, 'MASTER,UP,LOWER_UP' )
4073 self
. wait_operstate ( 'dummy98' , 'enslaved' )
4074 self
. wait_operstate ( 'test1' , 'enslaved' )
4075 self
. wait_operstate ( 'bond99' , 'routable' )
4077 check_output ( 'ip link set dummy98 down' )
4079 self
. wait_operstate ( 'dummy98' , 'off' )
4080 self
. wait_operstate ( 'test1' , 'enslaved' )
4081 self
. wait_operstate ( 'bond99' , 'routable' )
4083 check_output ( 'ip link set dummy98 up' )
4085 self
. wait_operstate ( 'dummy98' , 'enslaved' )
4086 self
. wait_operstate ( 'test1' , 'enslaved' )
4087 self
. wait_operstate ( 'bond99' , 'routable' )
4089 check_output ( 'ip link set dummy98 down' )
4090 check_output ( 'ip link set test1 down' )
4092 self
. wait_operstate ( 'dummy98' , 'off' )
4093 self
. wait_operstate ( 'test1' , 'off' )
4095 if not self
. wait_operstate ( 'bond99' , 'no-carrier' , setup_timeout
= 30 , fail_assert
= False ):
4096 # Huh? Kernel does not recognize that all slave interfaces are down?
4097 # Let's confirm that networkd's operstate is consistent with ip's result.
4098 self
. assertNotRegex ( output
, 'NO-CARRIER' )
4100 class NetworkdBridgeTests ( unittest
. TestCase
, Utilities
):
4108 def test_bridge_vlan ( self
):
4109 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave.network' ,
4110 '26-bridge.netdev' , '26-bridge-vlan-master.network' )
4112 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' ])
4114 output
= check_output ( 'bridge vlan show dev test1' )
4116 self
. assertNotRegex ( output
, '4063' )
4117 for i
in range ( 4064 , 4095 ):
4118 self
. assertRegex ( output
, f
' {i} ' )
4119 self
. assertNotRegex ( output
, '4095' )
4121 output
= check_output ( 'bridge vlan show dev bridge99' )
4123 self
. assertNotRegex ( output
, '4059' )
4124 for i
in range ( 4060 , 4095 ):
4125 self
. assertRegex ( output
, f
' {i} ' )
4126 self
. assertNotRegex ( output
, '4095' )
4128 def test_bridge_vlan_issue_20373 ( self
):
4129 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave-issue-20373.network' ,
4130 '26-bridge-issue-20373.netdev' , '26-bridge-vlan-master-issue-20373.network' ,
4131 '21-vlan.netdev' , '21-vlan.network' )
4133 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' , 'vlan99:routable' ])
4135 output
= check_output ( 'bridge vlan show dev test1' )
4137 self
. assertIn ( '100 PVID Egress Untagged' , output
)
4138 self
. assertIn ( '560' , output
)
4139 self
. assertIn ( '600' , output
)
4141 output
= check_output ( 'bridge vlan show dev bridge99' )
4143 self
. assertIn ( '1 PVID Egress Untagged' , output
)
4144 self
. assertIn ( '100' , output
)
4145 self
. assertIn ( '600' , output
)
4147 def test_bridge_mdb ( self
):
4148 copy_network_unit ( '11-dummy.netdev' , '26-bridge-mdb-slave.network' ,
4149 '26-bridge.netdev' , '26-bridge-mdb-master.network' )
4151 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' ])
4153 output
= check_output ( 'bridge mdb show dev bridge99' )
4155 self
. assertRegex ( output
, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064' )
4156 self
. assertRegex ( output
, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065' )
4158 # Old kernel may not support bridge MDB entries on bridge master
4159 if call_quiet ( 'bridge mdb add dev bridge99 port bridge99 grp 224.0.1.3 temp vid 4068' ) == 0 :
4160 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp ff02:aaaa:fee5::1:4 temp *vid 4066' )
4161 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp 224.0.1.2 temp *vid 4067' )
4163 def test_bridge_keep_master ( self
):
4164 check_output ( 'ip link add bridge99 type bridge' )
4165 check_output ( 'ip link set bridge99 up' )
4166 check_output ( 'ip link add dummy98 type dummy' )
4167 check_output ( 'ip link set dummy98 master bridge99' )
4169 copy_network_unit ( '23-keep-master.network' )
4171 self
. wait_online ([ 'dummy98:enslaved' ])
4173 output
= check_output ( 'ip -d link show dummy98' )
4175 self
. assertRegex ( output
, 'master bridge99' )
4176 self
. assertRegex ( output
, 'bridge' )
4178 output
= check_output ( 'bridge -d link show dummy98' )
4180 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
4181 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
4182 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
4183 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
4184 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
4185 # CONFIG_BRIDGE_IGMP_SNOOPING=y
4186 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
4187 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
4188 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
4189 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
4190 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
4191 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
4193 def test_bridge_property ( self
):
4194 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
4195 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
4196 '25-bridge99.network' )
4198 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' ])
4200 output
= check_output ( 'ip -d link show bridge99' )
4202 self
. assertIn ( 'mtu 9000 ' , output
)
4204 output
= check_output ( 'ip -d link show test1' )
4206 self
. assertIn ( 'master bridge99 ' , output
)
4207 self
. assertIn ( 'bridge_slave' , output
)
4208 self
. assertIn ( 'mtu 9000 ' , output
)
4210 output
= check_output ( 'ip -d link show dummy98' )
4212 self
. assertIn ( 'master bridge99 ' , output
)
4213 self
. assertIn ( 'bridge_slave' , output
)
4214 self
. assertIn ( 'mtu 9000 ' , output
)
4216 output
= check_output ( 'ip addr show bridge99' )
4218 self
. assertIn ( '192.168.0.15/24' , output
)
4220 output
= check_output ( 'bridge -d link show dummy98' )
4222 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
4223 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
4224 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'isolated' , '1' )
4225 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
4226 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
4227 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
4228 # CONFIG_BRIDGE_IGMP_SNOOPING=y
4229 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
4230 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
4231 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
4232 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
4233 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
4234 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
4236 output
= check_output ( 'bridge -d link show test1' )
4238 self
. check_bridge_port_attr ( 'bridge99' , 'test1' , 'priority' , '0' )
4240 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
4241 output
= check_output ( 'ip addr show bridge99' )
4243 self
. assertIn ( '192.168.0.16/24' , output
)
4246 print ( '### ip -6 route list table all dev bridge99' )
4247 output
= check_output ( 'ip -6 route list table all dev bridge99' )
4249 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
4251 remove_link ( 'test1' )
4252 self
. wait_operstate ( 'bridge99' , 'routable' )
4254 output
= check_output ( 'ip -d link show bridge99' )
4256 self
. assertIn ( 'mtu 9000 ' , output
)
4258 output
= check_output ( 'ip -d link show dummy98' )
4260 self
. assertIn ( 'master bridge99 ' , output
)
4261 self
. assertIn ( 'bridge_slave' , output
)
4262 self
. assertIn ( 'mtu 9000 ' , output
)
4264 remove_link ( 'dummy98' )
4265 self
. wait_operstate ( 'bridge99' , 'no-carrier' )
4267 output
= check_output ( 'ip -d link show bridge99' )
4269 # When no carrier, the kernel may reset the MTU
4270 self
. assertIn ( 'NO-CARRIER' , output
)
4272 output
= check_output ( 'ip address show bridge99' )
4274 self
. assertNotIn ( '192.168.0.15/24' , output
)
4275 self
. assertIn ( '192.168.0.16/24' , output
) # foreign address is kept
4277 print ( '### ip -6 route list table all dev bridge99' )
4278 output
= check_output ( 'ip -6 route list table all dev bridge99' )
4280 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
4282 check_output ( 'ip link add dummy98 type dummy' )
4283 self
. wait_online ([ 'dummy98:enslaved' , 'bridge99:routable' ])
4285 output
= check_output ( 'ip -d link show bridge99' )
4287 self
. assertIn ( 'mtu 9000 ' , output
)
4289 output
= check_output ( 'ip -d link show dummy98' )
4291 self
. assertIn ( 'master bridge99 ' , output
)
4292 self
. assertIn ( 'bridge_slave' , output
)
4293 self
. assertIn ( 'mtu 9000 ' , output
)
4295 def test_bridge_configure_without_carrier ( self
):
4296 copy_network_unit ( '26-bridge.netdev' , '26-bridge-configure-without-carrier.network' ,
4300 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
4301 for test
in [ 'no-slave' , 'add-slave' , 'slave-up' , 'slave-no-carrier' , 'slave-carrier' , 'slave-down' ]:
4302 with self
. subTest ( test
= test
):
4303 if test
== 'no-slave' :
4304 # bridge has no slaves; it's up but *might* not have carrier
4305 self
. wait_operstate ( 'bridge99' , operstate
= r
'(no-carrier|routable)' , setup_state
= None , setup_timeout
= 30 )
4306 # due to a bug in the kernel, newly-created bridges are brought up
4307 # *with* carrier, unless they have had any setting changed; e.g.
4308 # their mac set, priority set, etc. Then, they will lose carrier
4309 # as soon as a (down) slave interface is added, and regain carrier
4310 # again once the slave interface is brought up.
4311 #self.check_link_attr('bridge99', 'carrier', '0')
4312 elif test
== 'add-slave' :
4313 # add slave to bridge, but leave it down; bridge is definitely no-carrier
4314 self
. check_link_attr ( 'test1' , 'operstate' , 'down' )
4315 check_output ( 'ip link set dev test1 master bridge99' )
4316 self
. wait_operstate ( 'bridge99' , operstate
= 'no-carrier' , setup_state
= None )
4317 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4318 elif test
== 'slave-up' :
4319 # bring up slave, which will have carrier; bridge gains carrier
4320 check_output ( 'ip link set dev test1 up' )
4321 self
. wait_online ([ 'bridge99:routable' ])
4322 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
4323 elif test
== 'slave-no-carrier' :
4324 # drop slave carrier; bridge loses carrier
4325 check_output ( 'ip link set dev test1 carrier off' )
4326 self
. wait_online ([ 'bridge99:no-carrier:no-carrier' ])
4327 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4328 elif test
== 'slave-carrier' :
4329 # restore slave carrier; bridge gains carrier
4330 check_output ( 'ip link set dev test1 carrier on' )
4331 self
. wait_online ([ 'bridge99:routable' ])
4332 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
4333 elif test
== 'slave-down' :
4334 # bring down slave; bridge loses carrier
4335 check_output ( 'ip link set dev test1 down' )
4336 self
. wait_online ([ 'bridge99:no-carrier:no-carrier' ])
4337 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4339 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bridge99' , env
= env
)
4340 self
. assertRegex ( output
, '10.1.2.3' )
4341 self
. assertRegex ( output
, '10.1.2.1' )
4343 def test_bridge_ignore_carrier_loss ( self
):
4344 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
4345 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
4346 '25-bridge99-ignore-carrier-loss.network' )
4348 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' ])
4350 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
4351 remove_link ( 'test1' , 'dummy98' )
4354 output
= check_output ( 'ip address show bridge99' )
4356 self
. assertRegex ( output
, 'NO-CARRIER' )
4357 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
4358 self
. assertRegex ( output
, 'inet 192.168.0.16/24 scope global secondary bridge99' )
4360 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain ( self
):
4361 copy_network_unit ( '26-bridge.netdev' , '26-bridge-slave-interface-1.network' ,
4362 '25-bridge99-ignore-carrier-loss.network' )
4364 self
. wait_online ([ 'bridge99:no-carrier' ])
4366 for trial
in range ( 4 ):
4367 check_output ( 'ip link add dummy98 type dummy' )
4368 check_output ( 'ip link set dummy98 up' )
4370 remove_link ( 'dummy98' )
4372 self
. wait_online ([ 'bridge99:routable' , 'dummy98:enslaved' ])
4374 output
= check_output ( 'ip address show bridge99' )
4376 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
4378 output
= check_output ( 'ip rule list table 100' )
4380 self
. assertIn ( 'from all to 8.8.8.8 lookup 100' , output
)
4382 class NetworkdSRIOVTests ( unittest
. TestCase
, Utilities
):
4390 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
4391 def test_sriov ( self
):
4392 copy_network_unit ( '25-default.link' , '25-sriov.network' )
4394 call ( 'modprobe netdevsim' )
4396 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4399 with
open ( '/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4403 self
. wait_online ([ 'eni99np1:routable' ])
4405 output
= check_output ( 'ip link show dev eni99np1' )
4407 self
. assertRegex ( output
,
4408 '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 *'
4409 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4410 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4413 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
4414 def test_sriov_udev ( self
):
4415 copy_network_unit ( '25-sriov.link' , '25-sriov-udev.network' )
4417 call ( 'modprobe netdevsim' )
4419 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4423 self
. wait_online ([ 'eni99np1:routable' ])
4425 # the name eni99np1 may be an alternative name.
4426 ifname
= link_resolve ( 'eni99np1' )
4428 output
= check_output ( 'ip link show dev eni99np1' )
4430 self
. assertRegex ( output
,
4431 '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 *'
4432 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4433 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4435 self
. assertNotIn ( 'vf 3' , output
)
4436 self
. assertNotIn ( 'vf 4' , output
)
4438 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4439 f
. write ( '[Link] \n SR-IOVVirtualFunctions=4 \n ' )
4442 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4444 output
= check_output ( 'ip link show dev eni99np1' )
4446 self
. assertRegex ( output
,
4447 '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 *'
4448 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4449 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
4452 self
. assertNotIn ( 'vf 4' , output
)
4454 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4455 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
4458 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4460 output
= check_output ( 'ip link show dev eni99np1' )
4462 self
. assertRegex ( output
,
4463 '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 *'
4464 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4465 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
4468 self
. assertNotIn ( 'vf 4' , output
)
4470 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4471 f
. write ( '[Link] \n SR-IOVVirtualFunctions=2 \n ' )
4474 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4476 output
= check_output ( 'ip link show dev eni99np1' )
4478 self
. assertRegex ( output
,
4479 '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 *'
4480 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off'
4482 self
. assertNotIn ( 'vf 2' , output
)
4483 self
. assertNotIn ( 'vf 3' , output
)
4484 self
. assertNotIn ( 'vf 4' , output
)
4486 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4487 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
4490 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4492 output
= check_output ( 'ip link show dev eni99np1' )
4494 self
. assertRegex ( output
,
4495 '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 *'
4496 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4497 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4499 self
. assertNotIn ( 'vf 3' , output
)
4500 self
. assertNotIn ( 'vf 4' , output
)
4502 class NetworkdLLDPTests ( unittest
. TestCase
, Utilities
):
4510 def test_lldp ( self
):
4511 copy_network_unit ( '23-emit-lldp.network' , '24-lldp.network' , '25-veth.netdev' )
4513 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:degraded' ])
4515 for trial
in range ( 10 ):
4519 output
= check_output (* networkctl_cmd
, 'lldp' , env
= env
)
4521 if re
. search ( r
'veth99 .* veth-peer' , output
):
4526 class NetworkdRATests ( unittest
. TestCase
, Utilities
):
4534 def test_ipv6_prefix_delegation ( self
):
4535 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth.network' )
4537 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4539 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth99' , env
= env
)
4541 self
. assertRegex ( output
, 'fe80::' )
4542 self
. assertRegex ( output
, '2002:da8:1::1' )
4544 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth99' , env
= env
)
4546 self
. assertIn ( 'hogehoge.test' , output
)
4548 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4550 self
. assertRegex ( output
, '2002:da8:1:0' )
4552 self
. check_netlabel ( 'veth99' , '2002:da8:1::/64' )
4553 self
. check_netlabel ( 'veth99' , '2002:da8:2::/64' )
4555 def test_ipv6_token_static ( self
):
4556 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-static.network' )
4558 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4560 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4562 self
. assertRegex ( output
, '2002:da8:1:0:1a:2b:3c:4d' )
4563 self
. assertRegex ( output
, '2002:da8:1:0:fa:de:ca:fe' )
4564 self
. assertRegex ( output
, '2002:da8:2:0:1a:2b:3c:4d' )
4565 self
. assertRegex ( output
, '2002:da8:2:0:fa:de:ca:fe' )
4567 def test_ipv6_token_prefixstable ( self
):
4568 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable.network' )
4570 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4572 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4574 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
4575 self
. assertIn ( '2002:da8:2:0:1034:56ff:fe78:9abc' , output
) # EUI64
4577 def test_ipv6_token_prefixstable_without_address ( self
):
4578 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable-without-address.network' )
4580 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4582 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4584 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
4585 self
. assertIn ( '2002:da8:2:0:f689:561a:8eda:7443' , output
)
4587 def test_router_preference ( self
):
4588 copy_network_unit ( '25-veth-client.netdev' ,
4589 '25-veth-router-high.netdev' ,
4590 '25-veth-router-low.netdev' ,
4592 '25-veth-bridge.network' ,
4593 '25-veth-client.network' ,
4594 '25-veth-router-high.network' ,
4595 '25-veth-router-low.network' ,
4596 '25-bridge99.network' )
4598 self
. wait_online ([ 'client-p:enslaved' ,
4599 'router-high:degraded' , 'router-high-p:enslaved' ,
4600 'router-low:degraded' , 'router-low-p:enslaved' ,
4601 'bridge99:routable' ])
4603 networkctl_reconfigure ( 'client' )
4604 self
. wait_online ([ 'client:routable' ])
4606 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4607 self
. wait_address ( 'client' , '2002:da8:1:98:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4608 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 512' , ipv
= '-6' , timeout_sec
= 10 )
4609 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 2048' , ipv
= '-6' , timeout_sec
= 10 )
4611 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
4613 self
. assertIn ( 'pref high' , output
)
4614 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
4616 self
. assertIn ( 'pref low' , output
)
4618 with
open ( os
. path
. join ( network_unit_dir
, '25-veth-client.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4619 f
. write ( ' \n [Link] \n MACAddress=12:34:56:78:9a:01 \n [IPv6AcceptRA] \n RouteMetric=100:200:300 \n ' )
4622 self
. wait_online ([ 'client:routable' ])
4624 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a01/64' , ipv
= '-6' , timeout_sec
= 10 )
4625 self
. wait_address ( 'client' , '2002:da8:1:98:1034:56ff:fe78:9a01/64' , ipv
= '-6' , timeout_sec
= 10 )
4626 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 100' , ipv
= '-6' , timeout_sec
= 10 )
4627 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 300' , ipv
= '-6' , timeout_sec
= 10 )
4629 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
4631 self
. assertIn ( 'pref high' , output
)
4632 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
4634 self
. assertIn ( 'pref low' , output
)
4636 @unittest . skipUnless ( radvd_check_config ( 'captive-portal.conf' ), "Installed radvd doesn't support captive portals" )
4637 def test_captive_portal ( self
):
4638 copy_network_unit ( '25-veth-client.netdev' ,
4639 '25-veth-router-captive.netdev' ,
4641 '25-veth-client-captive.network' ,
4642 '25-veth-router-captive.network' ,
4643 '25-veth-bridge-captive.network' ,
4644 '25-bridge99.network' )
4646 self
. wait_online ([ 'bridge99:routable' , 'client-p:enslaved' ,
4647 'router-captive:degraded' , 'router-captivep:enslaved' ])
4649 start_radvd ( config_file
= 'captive-portal.conf' )
4650 networkctl_reconfigure ( 'client' )
4651 self
. wait_online ([ 'client:routable' ])
4653 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4654 output
= check_output (* networkctl_cmd
, 'status' , 'client' , env
= env
)
4656 self
. assertIn ( 'Captive Portal: http://systemd.io' , output
)
4658 @unittest . skipUnless ( radvd_check_config ( 'captive-portal.conf' ), "Installed radvd doesn't support captive portals" )
4659 def test_invalid_captive_portal ( self
):
4660 def radvd_write_config ( captive_portal_uri
):
4661 with
open ( os
. path
. join ( networkd_ci_temp_dir
, 'radvd/bogus-captive-portal.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
4662 f
. write ( f
'interface router-captive {{ AdvSendAdvert on; AdvCaptivePortalAPI " {captive_portal_uri} "; prefix 2002:da8:1:99::/64 {{ AdvOnLink on; AdvAutonomous on; }}; }};' )
4664 captive_portal_uris
= [
4665 "42ěščěškd ěšč ě s" ,
4670 copy_network_unit ( '25-veth-client.netdev' ,
4671 '25-veth-router-captive.netdev' ,
4673 '25-veth-client-captive.network' ,
4674 '25-veth-router-captive.network' ,
4675 '25-veth-bridge-captive.network' ,
4676 '25-bridge99.network' )
4678 self
. wait_online ([ 'bridge99:routable' , 'client-p:enslaved' ,
4679 'router-captive:degraded' , 'router-captivep:enslaved' ])
4681 for uri
in captive_portal_uris
:
4682 print ( f
"Captive portal: {uri} " )
4683 radvd_write_config ( uri
)
4685 start_radvd ( config_file
= 'bogus-captive-portal.conf' )
4686 networkctl_reconfigure ( 'client' )
4687 self
. wait_online ([ 'client:routable' ])
4689 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4690 output
= check_output (* networkctl_cmd
, 'status' , 'client' , env
= env
)
4692 self
. assertNotIn ( 'Captive Portal:' , output
)
4694 class NetworkdDHCPServerTests ( unittest
. TestCase
, Utilities
):
4702 def test_dhcp_server ( self
):
4703 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server.network' )
4705 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4707 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4709 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4710 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
4711 self
. assertRegex ( output
, 'DNS: 192.168.5.1 \n *192.168.5.10' )
4712 self
. assertRegex ( output
, 'NTP: 192.168.5.1 \n *192.168.5.11' )
4714 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth-peer' , env
= env
)
4715 self
. assertRegex ( output
, "Offered DHCP leases: 192.168.5.[0-9]*" )
4717 def test_dhcp_server_with_uplink ( self
):
4718 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-downstream.network' ,
4719 '12-dummy.netdev' , '25-dhcp-server-uplink.network' )
4721 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4723 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4725 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4726 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
4727 self
. assertIn ( 'DNS: 192.168.5.1' , output
)
4728 self
. assertIn ( 'NTP: 192.168.5.1' , output
)
4730 def test_emit_router_timezone ( self
):
4731 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-timezone-router.network' , '25-dhcp-server-timezone-router.network' )
4733 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4735 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4737 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4738 self
. assertIn ( 'Gateway: 192.168.5.1' , output
)
4739 self
. assertIn ( 'Time Zone: Europe/Berlin' , output
)
4741 def test_dhcp_server_static_lease ( self
):
4742 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-static-lease.network' , '25-dhcp-server-static-lease.network' )
4744 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4746 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4748 self
. assertIn ( 'Address: 10.1.1.200 (DHCP4 via 10.1.1.1)' , output
)
4749 self
. assertIn ( 'DHCP4 Client ID: 12:34:56:78:9a:bc' , output
)
4751 def test_dhcp_server_static_lease_default_client_id ( self
):
4752 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-static-lease.network' )
4754 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4756 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4758 self
. assertIn ( 'Address: 10.1.1.200 (DHCP4 via 10.1.1.1)' , output
)
4759 self
. assertRegex ( output
, 'DHCP4 Client ID: IAID:[0-9a-z]*/DUID' )
4761 class NetworkdDHCPServerRelayAgentTests ( unittest
. TestCase
, Utilities
):
4769 def test_relay_agent ( self
):
4770 copy_network_unit ( '25-agent-veth-client.netdev' ,
4771 '25-agent-veth-server.netdev' ,
4772 '25-agent-client.network' ,
4773 '25-agent-server.network' ,
4774 '25-agent-client-peer.network' ,
4775 '25-agent-server-peer.network' )
4778 self
. wait_online ([ 'client:routable' ])
4780 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'client' , env
= env
)
4782 self
. assertRegex ( output
, r
'Address: 192.168.5.150 \(DHCP4 via 192.168.5.1\)' )
4784 class NetworkdDHCPClientTests ( unittest
. TestCase
, Utilities
):
4792 def test_dhcp_client_ipv6_only ( self
):
4793 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv6-only.network' )
4796 self
. wait_online ([ 'veth-peer:carrier' ])
4798 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4801 output
= check_output ( 'ip address show dev veth99 scope global' )
4803 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
4804 self
. assertNotIn ( '192.168.5' , output
)
4806 # checking semi-static route
4807 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
4809 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
4811 # Confirm that ipv6 token is not set in the kernel
4812 output
= check_output ( 'ip token show dev veth99' )
4814 self
. assertRegex ( output
, 'token :: dev veth99' )
4816 print ( '## dnsmasq log' )
4817 output
= read_dnsmasq_log_file ()
4819 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
4820 self
. assertNotIn ( 'DHCPADVERTISE(veth-peer)' , output
)
4821 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
4822 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
4823 self
. assertIn ( 'sent size: 0 option: 14 rapid-commit' , output
)
4825 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-ipv6-only.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4826 f
. write ( ' \n [DHCPv6] \n RapidCommit=no \n ' )
4832 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4835 output
= check_output ( 'ip address show dev veth99 scope global' )
4837 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
4838 self
. assertNotIn ( '192.168.5' , output
)
4840 # checking semi-static route
4841 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
4843 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
4845 print ( '## dnsmasq log' )
4846 output
= read_dnsmasq_log_file ()
4848 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
4849 self
. assertIn ( 'DHCPADVERTISE(veth-peer)' , output
)
4850 self
. assertIn ( 'DHCPREQUEST(veth-peer)' , output
)
4851 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
4852 self
. assertNotIn ( 'rapid-commit' , output
)
4854 def test_dhcp_client_ipv4_only ( self
):
4855 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv4-only.network' )
4858 self
. wait_online ([ 'veth-peer:carrier' ])
4859 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7' ,
4860 '--dhcp-option=option:domain-search,example.com' ,
4861 '--dhcp-alternate-port=67,5555' ,
4862 ipv4_range
= '192.168.5.110,192.168.5.119' )
4863 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4864 self
. wait_address ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' )
4866 print ( '## ip address show dev veth99 scope global' )
4867 output
= check_output ( 'ip address show dev veth99 scope global' )
4869 self
. assertIn ( 'mtu 1492' , output
)
4870 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
4871 self
. assertRegex ( output
, r
'inet 192.168.5.11[0-9]/24 metric 24 brd 192.168.5.255 scope global secondary dynamic noprefixroute test-label' )
4872 self
. assertNotIn ( '2600::' , output
)
4874 print ( '## ip route show table main dev veth99' )
4875 output
= check_output ( 'ip route show table main dev veth99' )
4877 # no DHCP routes assigned to the main table
4878 self
. assertNotIn ( 'proto dhcp' , output
)
4880 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
4881 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
4882 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
4883 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
4885 print ( '## ip route show table 211 dev veth99' )
4886 output
= check_output ( 'ip route show table 211 dev veth99' )
4888 self
. assertRegex ( output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.11[0-9] metric 24' )
4889 self
. assertRegex ( output
, '192.168.5.0/24 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4890 self
. assertRegex ( output
, '192.168.5.1 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4891 self
. assertRegex ( output
, '192.168.5.6 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4892 self
. assertRegex ( output
, '192.168.5.7 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4893 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
4895 print ( '## link state file' )
4896 output
= read_link_state_file ( 'veth99' )
4898 # checking DNS server and Domains
4899 self
. assertIn ( 'DNS=192.168.5.6 192.168.5.7' , output
)
4900 self
. assertIn ( 'DOMAINS=example.com' , output
)
4902 print ( '## dnsmasq log' )
4903 output
= read_dnsmasq_log_file ()
4905 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
4906 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc' , output
)
4907 self
. assertIn ( 'client provides name: test-hostname' , output
)
4908 self
. assertIn ( '26:mtu' , output
)
4910 # change address range, DNS servers, and Domains
4912 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8' ,
4913 '--dhcp-option=option:domain-search,foo.example.com' ,
4914 '--dhcp-alternate-port=67,5555' ,
4915 ipv4_range
= '192.168.5.120,192.168.5.129' ,)
4917 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4918 print ( 'Wait for the DHCP lease to be expired' )
4919 self
. wait_address_dropped ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' , timeout_sec
= 120 )
4920 self
. wait_address ( 'veth99' , r
'inet 192.168.5.12[0-9]*/24' , ipv
= '-4' )
4922 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4924 print ( '## ip address show dev veth99 scope global' )
4925 output
= check_output ( 'ip address show dev veth99 scope global' )
4927 self
. assertIn ( 'mtu 1492' , output
)
4928 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
4929 self
. assertNotIn ( '192.168.5.11' , output
)
4930 self
. assertRegex ( output
, r
'inet 192.168.5.12[0-9]/24 metric 24 brd 192.168.5.255 scope global secondary dynamic noprefixroute test-label' )
4931 self
. assertNotIn ( '2600::' , output
)
4933 print ( '## ip route show table main dev veth99' )
4934 output
= check_output ( 'ip route show table main dev veth99' )
4936 # no DHCP routes assigned to the main table
4937 self
. assertNotIn ( 'proto dhcp' , output
)
4939 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
4940 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
4941 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
4942 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
4944 print ( '## ip route show table 211 dev veth99' )
4945 output
= check_output ( 'ip route show table 211 dev veth99' )
4947 self
. assertRegex ( output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.12[0-9] metric 24' )
4948 self
. assertRegex ( output
, '192.168.5.0/24 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4949 self
. assertRegex ( output
, '192.168.5.1 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4950 self
. assertNotIn ( '192.168.5.6' , output
)
4951 self
. assertRegex ( output
, '192.168.5.7 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4952 self
. assertRegex ( output
, '192.168.5.8 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4953 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
4955 print ( '## link state file' )
4956 output
= read_link_state_file ( 'veth99' )
4958 # checking DNS server and Domains
4959 self
. assertIn ( 'DNS=192.168.5.1 192.168.5.7 192.168.5.8' , output
)
4960 self
. assertIn ( 'DOMAINS=foo.example.com' , output
)
4962 print ( '## dnsmasq log' )
4963 output
= read_dnsmasq_log_file ()
4965 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
4966 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 192.168.5.11' , output
)
4967 self
. assertIn ( 'client provides name: test-hostname' , output
)
4968 self
. assertIn ( '26:mtu' , output
)
4970 self
. check_netlabel ( 'veth99' , r
'192\.168\.5\.0/24' )
4972 def test_dhcp_client_ipv4_use_routes_gateway ( self
):
4974 for ( routes
, gateway
, dns_and_ntp_routes
, classless
) in itertools
. product ([ True , False ], repeat
= 4 ):
4980 print ( f
'### test_dhcp_client_ipv4_use_routes_gateway(routes= {routes} , gateway= {gateway} , dns_and_ntp_routes= {dns_and_ntp_routes} , classless= {classless} )' )
4981 with self
. subTest ( routes
= routes
, gateway
= gateway
, dns_and_ntp_routes
= dns_and_ntp_routes
, classless
= classless
):
4982 self
._ test
_ dhcp
_ client
_ ipv
4_u se
_ routes
_ gateway
( routes
, gateway
, dns_and_ntp_routes
, classless
)
4984 def _test_dhcp_client_ipv4_use_routes_gateway ( self
, use_routes
, use_gateway
, dns_and_ntp_routes
, classless
):
4985 testunit
= '25-dhcp-client-ipv4-use-routes-use-gateway.network'
4986 testunits
= [ '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , testunit
]
4987 testunits
. append ( f
' {testunit} .d/use-routes- {use_routes} .conf' )
4988 testunits
. append ( f
' {testunit} .d/use-gateway- {use_gateway} .conf' )
4989 testunits
. append ( f
' {testunit} .d/use-dns-and-ntp-routes- {dns_and_ntp_routes} .conf' )
4990 copy_network_unit (* testunits
, copy_dropins
= False )
4993 self
. wait_online ([ 'veth-peer:carrier' ])
4994 additional_options
= [
4995 '--dhcp-option=option:dns-server,192.168.5.10,8.8.8.8' ,
4996 '--dhcp-option=option:ntp-server,192.168.5.11,9.9.9.9' ,
4997 '--dhcp-option=option:static-route,192.168.5.100,192.168.5.2,8.8.8.8,192.168.5.3'
5000 additional_options
+= [
5001 '--dhcp-option=option:classless-static-route,0.0.0.0/0,192.168.5.4,8.0.0.0/8,192.168.5.5,192.168.5.64/26,192.168.5.5'
5003 start_dnsmasq (* additional_options
)
5004 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5006 output
= check_output ( 'ip -4 route show dev veth99' )
5012 self
. assertRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5013 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5014 self
. assertRegex ( output
, r
'192.168.5.64/26 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5015 self
. assertRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5016 self
. assertRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5018 self
. assertRegex ( output
, r
'192.168.5.0/24 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5019 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5020 self
. assertRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5022 self
. assertNotRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5023 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5024 self
. assertNotRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5025 self
. assertNotRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5026 self
. assertNotRegex ( output
, r
'192.168.5.0/24 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5027 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5028 self
. assertNotRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5031 if use_gateway
and ( not classless
or not use_routes
):
5032 self
. assertRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5034 self
. assertNotRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5036 # Check route to gateway
5037 if ( use_gateway
or dns_and_ntp_routes
) and ( not classless
or not use_routes
):
5038 self
. assertRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5040 self
. assertNotRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5042 # Check RoutesToDNS= and RoutesToNTP=
5043 if dns_and_ntp_routes
:
5044 self
. assertRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5045 self
. assertRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5046 if classless
and use_routes
:
5047 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5048 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5050 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5051 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5053 self
. assertNotRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5054 self
. assertNotRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5055 self
. assertNotRegex ( output
, r
'8.8.8.8 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
5056 self
. assertNotRegex ( output
, r
'9.9.9.9 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
5058 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5061 def test_dhcp_client_settings_anonymize ( self
):
5062 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-anonymize.network' )
5064 self
. wait_online ([ 'veth-peer:carrier' ])
5066 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5068 print ( '## dnsmasq log' )
5069 output
= read_dnsmasq_log_file ()
5071 self
. assertNotIn ( 'VendorClassIdentifier=SusantVendorTest' , output
)
5072 self
. assertNotIn ( 'test-hostname' , output
)
5073 self
. assertNotIn ( '26:mtu' , output
)
5075 def test_dhcp_keep_configuration_dhcp ( self
):
5076 copy_network_unit ( '25-veth.netdev' ,
5077 '25-dhcp-server-veth-peer.network' ,
5078 '25-dhcp-client-keep-configuration-dhcp.network' )
5080 self
. wait_online ([ 'veth-peer:carrier' ])
5082 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5084 output
= check_output ( 'ip address show dev veth99 scope global' )
5086 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5087 'valid_lft forever preferred_lft forever' )
5089 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
5092 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
5093 print ( 'Wait for the DHCP lease to be expired' )
5096 # The lease address should be kept after the lease expired
5097 output
= check_output ( 'ip address show dev veth99 scope global' )
5099 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5100 'valid_lft forever preferred_lft forever' )
5104 # The lease address should be kept after networkd stopped
5105 output
= check_output ( 'ip address show dev veth99 scope global' )
5107 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5108 'valid_lft forever preferred_lft forever' )
5110 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-keep-configuration-dhcp.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5111 f
. write ( '[Network] \n DHCP=no \n ' )
5114 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5116 # Still the lease address should be kept after networkd restarted
5117 output
= check_output ( 'ip address show dev veth99 scope global' )
5119 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5120 'valid_lft forever preferred_lft forever' )
5122 def test_dhcp_keep_configuration_dhcp_on_stop ( self
):
5123 copy_network_unit ( '25-veth.netdev' ,
5124 '25-dhcp-server-veth-peer.network' ,
5125 '25-dhcp-client-keep-configuration-dhcp-on-stop.network' )
5127 self
. wait_online ([ 'veth-peer:carrier' ])
5129 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5131 output
= check_output ( 'ip address show dev veth99 scope global' )
5133 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5138 output
= check_output ( 'ip address show dev veth99 scope global' )
5140 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5143 self
. wait_online ([ 'veth-peer:routable' ])
5145 output
= check_output ( 'ip address show dev veth99 scope global' )
5147 self
. assertNotIn ( '192.168.5.' , output
)
5149 def test_dhcp_client_reuse_address_as_static ( self
):
5150 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' )
5152 self
. wait_online ([ 'veth-peer:carrier' ])
5154 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5156 # link become 'routable' when at least one protocol provide an valid address.
5157 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5158 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5160 output
= check_output ( 'ip address show dev veth99 scope global' )
5161 ipv4_address
= re
. search ( r
'192.168.5.[0-9]*/24' , output
). group ()
5162 ipv6_address
= re
. search ( r
'2600::[0-9a-f:]*/128' , output
). group ()
5163 static_network
= ' \n ' . join ([ '[Match]' , 'Name=veth99' , '[Network]' , 'IPv6AcceptRA=no' , 'Address=' + ipv4_address
, 'Address=' + ipv6_address
])
5164 print ( static_network
)
5166 remove_network_unit ( '25-dhcp-client.network' )
5168 with
open ( os
. path
. join ( network_unit_dir
, '25-static.network' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5169 f
. write ( static_network
)
5172 self
. wait_online ([ 'veth99:routable' ])
5174 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
5176 self
. assertRegex ( output
, f
'inet {ipv4_address} brd 192.168.5.255 scope global veth99 \n *'
5177 'valid_lft forever preferred_lft forever' )
5179 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5181 self
. assertRegex ( output
, f
'inet6 {ipv6_address} scope global * \n *'
5182 'valid_lft forever preferred_lft forever' )
5184 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
5185 def test_dhcp_client_vrf ( self
):
5186 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-vrf.network' ,
5187 '25-vrf.netdev' , '25-vrf.network' )
5189 self
. wait_online ([ 'veth-peer:carrier' ])
5191 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'vrf99:carrier' ])
5193 # link become 'routable' when at least one protocol provide an valid address.
5194 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5195 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5197 print ( '## ip -d link show dev vrf99' )
5198 output
= check_output ( 'ip -d link show dev vrf99' )
5200 self
. assertRegex ( output
, 'vrf table 42' )
5202 print ( '## ip address show vrf vrf99' )
5203 output
= check_output ( 'ip address show vrf vrf99' )
5205 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5206 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5207 self
. assertRegex ( output
, 'inet6 .* scope link' )
5209 print ( '## ip address show dev veth99' )
5210 output
= check_output ( 'ip address show dev veth99' )
5212 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5213 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5214 self
. assertRegex ( output
, 'inet6 .* scope link' )
5216 print ( '## ip route show vrf vrf99' )
5217 output
= check_output ( 'ip route show vrf vrf99' )
5219 self
. assertRegex ( output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.' )
5220 self
. assertRegex ( output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5' )
5221 self
. assertRegex ( output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5' )
5223 print ( '## ip route show table main dev veth99' )
5224 output
= check_output ( 'ip route show table main dev veth99' )
5226 self
. assertEqual ( output
, '' )
5228 def test_dhcp_client_gateway_onlink_implicit ( self
):
5229 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
5230 '25-dhcp-client-gateway-onlink-implicit.network' )
5232 self
. wait_online ([ 'veth-peer:carrier' ])
5234 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5236 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
5238 self
. assertRegex ( output
, '192.168.5' )
5240 output
= check_output ( 'ip route list dev veth99 10.0.0.0/8' )
5242 self
. assertRegex ( output
, 'onlink' )
5243 output
= check_output ( 'ip route list dev veth99 192.168.100.0/24' )
5245 self
. assertRegex ( output
, 'onlink' )
5247 def test_dhcp_client_with_ipv4ll ( self
):
5248 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
5249 '25-dhcp-client-with-ipv4ll.network' )
5251 # we need to increase timeout above default, as this will need to wait for
5252 # systemd-networkd to get the dhcpv4 transient failure event
5253 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:routable' ], timeout
= '60s' )
5255 output
= check_output ( 'ip -4 address show dev veth99' )
5257 self
. assertNotIn ( '192.168.5.' , output
)
5258 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
5261 print ( 'Wait for a DHCP lease to be acquired and the IPv4LL address to be dropped' )
5262 self
. wait_address ( 'veth99' , r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic' , ipv
= '-4' )
5263 self
. wait_address_dropped ( 'veth99' , r
'inet 169\.254\.\d+\.\d+/16 metric 2048 brd 169\.254\.255\.255 scope link' , scope
= 'link' , ipv
= '-4' )
5264 self
. wait_online ([ 'veth99:routable' ])
5266 output
= check_output ( 'ip -4 address show dev veth99' )
5268 self
. assertRegex ( output
, r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99' )
5269 self
. assertNotIn ( '169.254.' , output
)
5270 self
. assertNotIn ( 'scope link' , output
)
5273 print ( 'Wait for the DHCP lease to be expired and an IPv4LL address to be acquired' )
5274 self
. wait_address_dropped ( 'veth99' , r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic' , ipv
= '-4' , timeout_sec
= 130 )
5275 self
. wait_address ( 'veth99' , r
'inet 169\.254\.133\.11/16 metric 2048 brd 169\.254\.255\.255 scope link' , scope
= 'link' , ipv
= '-4' )
5277 output
= check_output ( 'ip -4 address show dev veth99' )
5279 self
. assertNotIn ( '192.168.5.' , output
)
5280 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
5282 def test_dhcp_client_use_dns ( self
):
5283 def check ( self
, ipv4
, ipv6
):
5284 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5285 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5286 f
. write ( '[DHCPv4] \n UseDNS=' )
5287 f
. write ( 'yes' if ipv4
else 'no' )
5288 f
. write ( ' \n [DHCPv6] \n UseDNS=' )
5289 f
. write ( 'yes' if ipv6
else 'no' )
5290 f
. write ( ' \n [IPv6AcceptRA] \n UseDNS=no' )
5293 self
. wait_online ([ 'veth99:routable' ])
5295 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5296 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5297 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5299 # make resolved re-read the link state file
5300 check_output (* resolvectl_cmd
, 'revert' , 'veth99' , env
= env
)
5302 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth99' , env
= env
)
5305 self
. assertIn ( '192.168.5.1' , output
)
5307 self
. assertNotIn ( '192.168.5.1' , output
)
5309 self
. assertIn ( '2600::1' , output
)
5311 self
. assertNotIn ( '2600::1' , output
)
5313 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5316 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5319 self
. wait_online ([ 'veth-peer:carrier' ])
5320 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1' ,
5321 '--dhcp-option=option6:dns-server,[2600::1]' )
5323 check ( self
, True , True )
5324 check ( self
, True , False )
5325 check ( self
, False , True )
5326 check ( self
, False , False )
5328 def test_dhcp_client_use_captive_portal ( self
):
5329 def check ( self
, ipv4
, ipv6
):
5330 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5331 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5332 f
. write ( '[DHCPv4] \n UseCaptivePortal=' )
5333 f
. write ( 'yes' if ipv4
else 'no' )
5334 f
. write ( ' \n [DHCPv6] \n UseCaptivePortal=' )
5335 f
. write ( 'yes' if ipv6
else 'no' )
5336 f
. write ( ' \n [IPv6AcceptRA] \n UseCaptivePortal=no' )
5339 self
. wait_online ([ 'veth99:routable' ])
5341 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5342 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5343 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5345 output
= check_output (* networkctl_cmd
, 'status' , 'veth99' , env
= env
)
5348 self
. assertIn ( 'Captive Portal: http://systemd.io' , output
)
5350 self
. assertNotIn ( 'Captive Portal: http://systemd.io' , output
)
5352 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5355 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5358 self
. wait_online ([ 'veth-peer:carrier' ])
5359 start_dnsmasq ( '--dhcp-option=114,http://systemd.io' ,
5360 '--dhcp-option=option6:103,http://systemd.io' )
5362 check ( self
, True , True )
5363 check ( self
, True , False )
5364 check ( self
, False , True )
5365 check ( self
, False , False )
5367 def test_dhcp_client_reject_captive_portal ( self
):
5368 def check ( self
, ipv4
, ipv6
):
5369 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5370 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5371 f
. write ( '[DHCPv4] \n UseCaptivePortal=' )
5372 f
. write ( 'yes' if ipv4
else 'no' )
5373 f
. write ( ' \n [DHCPv6] \n UseCaptivePortal=' )
5374 f
. write ( 'yes' if ipv6
else 'no' )
5375 f
. write ( ' \n [IPv6AcceptRA] \n UseCaptivePortal=no' )
5378 self
. wait_online ([ 'veth99:routable' ])
5380 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5381 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5382 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5384 output
= check_output (* networkctl_cmd
, 'status' , 'veth99' , env
= env
)
5386 self
. assertNotIn ( 'Captive Portal: ' , output
)
5387 self
. assertNotIn ( 'invalid/url' , output
)
5389 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5392 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5395 self
. wait_online ([ 'veth-peer:carrier' ])
5396 masq
= lambda bs
: ':' . join ( f
'{b:02x}' for b
in bs
)
5397 start_dnsmasq ( '--dhcp-option=114,' + masq ( b
'http:// \x00 invalid/url' ),
5398 '--dhcp-option=option6:103,' + masq ( b
'http:// \x00 /invalid/url' ))
5400 check ( self
, True , True )
5401 check ( self
, True , False )
5402 check ( self
, False , True )
5403 check ( self
, False , False )
5405 class NetworkdDHCPPDTests ( unittest
. TestCase
, Utilities
):
5413 def test_dhcp6pd ( self
):
5414 copy_network_unit ( '25-veth.netdev' , '25-dhcp6pd-server.network' , '25-dhcp6pd-upstream.network' ,
5415 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
5416 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
5417 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
5418 '25-dhcp-pd-downstream-dummy97.network' ,
5419 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
5420 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' )
5423 self
. wait_online ([ 'veth-peer:routable' ])
5424 start_isc_dhcpd ( conf_file
= 'isc-dhcpd-dhcp6pd.conf' , ipv
= '-6' )
5425 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5426 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5428 print ( '### ip -6 address show dev veth-peer scope global' )
5429 output
= check_output ( 'ip -6 address show dev veth-peer scope global' )
5431 self
. assertIn ( 'inet6 3ffe:501:ffff:100::1/64 scope global' , output
)
5435 # dummy97: 0x01 (The link will appear later)
5437 # dummy99: auto -> 0x02 (No address assignment)
5442 print ( '### ip -6 address show dev veth99 scope global' )
5443 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5446 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:100::[0-9]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5447 # address in IA_PD (Token=static)
5448 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic' )
5449 # address in IA_PD (Token=eui64)
5450 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic' )
5451 # address in IA_PD (temporary)
5452 # Note that the temporary addresses may appear after the link enters configured state
5453 self
. wait_address ( 'veth99' , 'inet6 3ffe:501:ffff:[2-9a-f]10:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic' , ipv
= '-6' )
5455 print ( '### ip -6 address show dev test1 scope global' )
5456 output
= check_output ( 'ip -6 address show dev test1 scope global' )
5458 # address in IA_PD (Token=static)
5459 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5460 # address in IA_PD (temporary)
5461 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' )
5463 print ( '### ip -6 address show dev dummy98 scope global' )
5464 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5466 # address in IA_PD (Token=static)
5467 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5468 # address in IA_PD (temporary)
5469 self
. wait_address ( 'dummy98' , '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' )
5471 print ( '### ip -6 address show dev dummy99 scope global' )
5472 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5475 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
5477 print ( '### ip -6 address show dev veth97 scope global' )
5478 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
5480 # address in IA_PD (Token=static)
5481 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5482 # address in IA_PD (Token=eui64)
5483 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5484 # address in IA_PD (temporary)
5485 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' )
5487 print ( '### ip -6 address show dev veth97-peer scope global' )
5488 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
5490 # NDisc address (Token=static)
5491 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5492 # NDisc address (Token=eui64)
5493 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5494 # NDisc address (temporary)
5495 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' )
5497 print ( '### ip -6 address show dev veth98 scope global' )
5498 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
5500 # address in IA_PD (Token=static)
5501 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5502 # address in IA_PD (Token=eui64)
5503 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5504 # address in IA_PD (temporary)
5505 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' )
5507 print ( '### ip -6 address show dev veth98-peer scope global' )
5508 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
5510 # NDisc address (Token=static)
5511 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5512 # NDisc address (Token=eui64)
5513 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5514 # NDisc address (temporary)
5515 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' )
5517 print ( '### ip -6 route show type unreachable' )
5518 output
= check_output ( 'ip -6 route show type unreachable' )
5520 self
. assertRegex ( output
, 'unreachable 3ffe:501:ffff:[2-9a-f]00::/56 dev lo proto dhcp' )
5522 print ( '### ip -6 route show dev veth99' )
5523 output
= check_output ( 'ip -6 route show dev veth99' )
5525 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]10::/64 proto kernel metric [0-9]* expires' )
5527 print ( '### ip -6 route show dev test1' )
5528 output
= check_output ( 'ip -6 route show dev test1' )
5530 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5532 print ( '### ip -6 route show dev dummy98' )
5533 output
= check_output ( 'ip -6 route show dev dummy98' )
5535 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5537 print ( '### ip -6 route show dev dummy99' )
5538 output
= check_output ( 'ip -6 route show dev dummy99' )
5540 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
5542 print ( '### ip -6 route show dev veth97' )
5543 output
= check_output ( 'ip -6 route show dev veth97' )
5545 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto kernel metric [0-9]* expires' )
5547 print ( '### ip -6 route show dev veth97-peer' )
5548 output
= check_output ( 'ip -6 route show dev veth97-peer' )
5550 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto ra metric [0-9]* expires' )
5552 print ( '### ip -6 route show dev veth98' )
5553 output
= check_output ( 'ip -6 route show dev veth98' )
5555 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto kernel metric [0-9]* expires' )
5557 print ( '### ip -6 route show dev veth98-peer' )
5558 output
= check_output ( 'ip -6 route show dev veth98-peer' )
5560 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto ra metric [0-9]* expires' )
5562 # Test case for a downstream which appears later
5563 check_output ( 'ip link add dummy97 type dummy' )
5564 self
. wait_online ([ 'dummy97:routable' ])
5566 print ( '### ip -6 address show dev dummy97 scope global' )
5567 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
5569 # address in IA_PD (Token=static)
5570 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5571 # address in IA_PD (temporary)
5572 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' )
5574 print ( '### ip -6 route show dev dummy97' )
5575 output
= check_output ( 'ip -6 route show dev dummy97' )
5577 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]01::/64 proto kernel metric [0-9]* expires' )
5579 # Test case for reconfigure
5580 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
5581 self
. wait_online ([ 'dummy98:routable' , 'dummy99:degraded' ])
5583 print ( '### ip -6 address show dev dummy98 scope global' )
5584 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5586 # address in IA_PD (Token=static)
5587 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5588 # address in IA_PD (temporary)
5589 self
. wait_address ( 'dummy98' , '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' )
5591 print ( '### ip -6 address show dev dummy99 scope global' )
5592 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5595 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
5597 print ( '### ip -6 route show dev dummy98' )
5598 output
= check_output ( 'ip -6 route show dev dummy98' )
5600 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5602 print ( '### ip -6 route show dev dummy99' )
5603 output
= check_output ( 'ip -6 route show dev dummy99' )
5605 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
5607 self
. check_netlabel ( 'dummy98' , '3ffe:501:ffff:[2-9a-f]00::/64' )
5609 def verify_dhcp4_6rd ( self
, tunnel_name
):
5610 print ( '### ip -4 address show dev veth-peer scope global' )
5611 output
= check_output ( 'ip -4 address show dev veth-peer scope global' )
5613 self
. assertIn ( 'inet 10.0.0.1/8 brd 10.255.255.255 scope global veth-peer' , output
)
5617 # dummy97: 0x01 (The link will appear later)
5619 # dummy99: auto -> 0x0[23] (No address assignment)
5620 # 6rd-XXX: auto -> 0x0[23]
5625 print ( '### ip -4 address show dev veth99 scope global' )
5626 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
5628 self
. assertRegex ( output
, 'inet 10.100.100.[0-9]*/8 (metric 1024 |)brd 10.255.255.255 scope global dynamic veth99' )
5630 print ( '### ip -6 address show dev veth99 scope global' )
5631 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5633 # address in IA_PD (Token=static)
5634 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5635 # address in IA_PD (Token=eui64)
5636 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5637 # address in IA_PD (temporary)
5638 # Note that the temporary addresses may appear after the link enters configured state
5639 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' )
5641 print ( '### ip -6 address show dev test1 scope global' )
5642 output
= check_output ( 'ip -6 address show dev test1 scope global' )
5644 # address in IA_PD (Token=static)
5645 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5646 # address in IA_PD (temporary)
5647 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' )
5649 print ( '### ip -6 address show dev dummy98 scope global' )
5650 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5652 # address in IA_PD (Token=static)
5653 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5654 # address in IA_PD (temporary)
5655 self
. wait_address ( 'dummy98' , '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' )
5657 print ( '### ip -6 address show dev dummy99 scope global' )
5658 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5661 self
. assertNotRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+0[23]' )
5663 print ( '### ip -6 address show dev veth97 scope global' )
5664 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
5666 # address in IA_PD (Token=static)
5667 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5668 # address in IA_PD (Token=eui64)
5669 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5670 # address in IA_PD (temporary)
5671 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' )
5673 print ( '### ip -6 address show dev veth97-peer scope global' )
5674 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
5676 # NDisc address (Token=static)
5677 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5678 # NDisc address (Token=eui64)
5679 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5680 # NDisc address (temporary)
5681 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' )
5683 print ( '### ip -6 address show dev veth98 scope global' )
5684 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
5686 # address in IA_PD (Token=static)
5687 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5688 # address in IA_PD (Token=eui64)
5689 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5690 # address in IA_PD (temporary)
5691 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' )
5693 print ( '### ip -6 address show dev veth98-peer scope global' )
5694 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
5696 # NDisc address (Token=static)
5697 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5698 # NDisc address (Token=eui64)
5699 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5700 # NDisc address (temporary)
5701 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' )
5703 print ( '### ip -6 route show type unreachable' )
5704 output
= check_output ( 'ip -6 route show type unreachable' )
5706 self
. assertRegex ( output
, 'unreachable 2001:db8:6464:[0-9a-f]+00::/56 dev lo proto dhcp' )
5708 print ( '### ip -6 route show dev veth99' )
5709 output
= check_output ( 'ip -6 route show dev veth99' )
5711 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+10::/64 proto kernel metric [0-9]* expires' )
5713 print ( '### ip -6 route show dev test1' )
5714 output
= check_output ( 'ip -6 route show dev test1' )
5716 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
5718 print ( '### ip -6 route show dev dummy98' )
5719 output
= check_output ( 'ip -6 route show dev dummy98' )
5721 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
5723 print ( '### ip -6 route show dev dummy99' )
5724 output
= check_output ( 'ip -6 route show dev dummy99' )
5726 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto dhcp metric [0-9]* expires' )
5728 print ( '### ip -6 route show dev veth97' )
5729 output
= check_output ( 'ip -6 route show dev veth97' )
5731 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto kernel metric [0-9]* expires' )
5733 print ( '### ip -6 route show dev veth97-peer' )
5734 output
= check_output ( 'ip -6 route show dev veth97-peer' )
5736 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto ra metric [0-9]* expires' )
5738 print ( '### ip -6 route show dev veth98' )
5739 output
= check_output ( 'ip -6 route show dev veth98' )
5741 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto kernel metric [0-9]* expires' )
5743 print ( '### ip -6 route show dev veth98-peer' )
5744 output
= check_output ( 'ip -6 route show dev veth98-peer' )
5746 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto ra metric [0-9]* expires' )
5748 print ( '### ip -6 address show dev dummy97 scope global' )
5749 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
5751 # address in IA_PD (Token=static)
5752 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5753 # address in IA_PD (temporary)
5754 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' )
5756 print ( '### ip -6 route show dev dummy97' )
5757 output
= check_output ( 'ip -6 route show dev dummy97' )
5759 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+01::/64 proto kernel metric [0-9]* expires' )
5761 print ( f
'### ip -d link show dev {tunnel_name} ' )
5762 output
= check_output ( f
'ip -d link show dev {tunnel_name} ' )
5764 self
. assertIn ( 'link/sit 10.100.100.' , output
)
5765 self
. assertIn ( 'local 10.100.100.' , output
)
5766 self
. assertIn ( 'ttl 64' , output
)
5767 self
. assertIn ( '6rd-prefix 2001:db8::/32' , output
)
5768 self
. assertIn ( '6rd-relay_prefix 10.0.0.0/8' , output
)
5770 print ( f
'### ip -6 address show dev {tunnel_name} ' )
5771 output
= check_output ( f
'ip -6 address show dev {tunnel_name} ' )
5773 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+0[23]:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global dynamic' )
5774 self
. assertRegex ( output
, 'inet6 ::10.100.100.[0-9]+/96 scope global' )
5776 print ( f
'### ip -6 route show dev {tunnel_name} ' )
5777 output
= check_output ( f
'ip -6 route show dev {tunnel_name} ' )
5779 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto kernel metric [0-9]* expires' )
5780 self
. assertRegex ( output
, '::/96 proto kernel metric [0-9]*' )
5782 print ( '### ip -6 route show default' )
5783 output
= check_output ( 'ip -6 route show default' )
5785 self
. assertIn ( 'default' , output
)
5786 self
. assertIn ( f
'via ::10.0.0.1 dev {tunnel_name} ' , output
)
5788 def test_dhcp4_6rd ( self
):
5789 copy_network_unit ( '25-veth.netdev' , '25-dhcp4-6rd-server.network' , '25-dhcp4-6rd-upstream.network' ,
5790 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
5791 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
5792 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
5793 '25-dhcp-pd-downstream-dummy97.network' ,
5794 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
5795 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' ,
5796 '80-6rd-tunnel.network' )
5799 self
. wait_online ([ 'veth-peer:routable' ])
5802 # 6rd-prefix: 2001:db8::/32
5803 # br-addresss: 10.0.0.1
5805 start_dnsmasq ( '--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' ,
5806 ipv4_range
= '10.100.100.100,10.100.100.200' ,
5807 ipv4_router
= '10.0.0.1' )
5808 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5809 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5811 # Test case for a downstream which appears later
5812 check_output ( 'ip link add dummy97 type dummy' )
5813 self
. wait_online ([ 'dummy97:routable' ])
5817 for name
in os
. listdir ( '/sys/class/net/' ):
5818 if name
. startswith ( '6rd-' ):
5822 self
. wait_online ([ f
' {tunnel_name} :routable' ])
5824 self
. verify_dhcp4_6rd ( tunnel_name
)
5826 # Test case for reconfigure
5827 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
5828 self
. wait_online ([ 'dummy98:routable' , 'dummy99:degraded' ])
5830 self
. verify_dhcp4_6rd ( tunnel_name
)
5832 print ( 'Wait for the DHCP lease to be renewed/rebind' )
5835 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy97:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5836 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5838 self
. verify_dhcp4_6rd ( tunnel_name
)
5840 class NetworkdIPv6PrefixTests ( unittest
. TestCase
, Utilities
):
5848 def test_ipv6_route_prefix ( self
):
5849 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client.network' , '25-ipv6ra-prefix.network' ,
5850 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
5853 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
5855 output
= check_output ( 'ip address show dev veth-peer' )
5857 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
5858 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
5859 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
5861 output
= check_output ( 'ip -6 route show dev veth-peer' )
5863 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
5864 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
5865 self
. assertNotIn ( '2001:db8:0:3::/64 proto ra' , output
)
5866 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
5867 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
5868 self
. assertNotIn ( '2001:db2:fff::/64 via ' , output
)
5870 output
= check_output ( 'ip address show dev veth99' )
5872 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
5873 self
. assertIn ( 'inet6 2001:db8:0:2:1a:2b:3c:4d' , output
)
5874 self
. assertIn ( 'inet6 2001:db8:0:2:fa:de:ca:fe' , output
)
5875 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
5877 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth-peer' , env
= env
)
5879 self
. assertRegex ( output
, '2001:db8:1:1::2' )
5881 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth-peer' , env
= env
)
5883 self
. assertIn ( 'example.com' , output
)
5885 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5888 def test_ipv6_route_prefix_deny_list ( self
):
5889 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client-deny-list.network' , '25-ipv6ra-prefix.network' ,
5890 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
5893 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
5895 output
= check_output ( 'ip address show dev veth-peer' )
5897 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
5898 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
5900 output
= check_output ( 'ip -6 route show dev veth-peer' )
5902 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
5903 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
5904 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
5905 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
5907 output
= check_output ( 'ip address show dev veth99' )
5909 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
5910 self
. assertIn ( 'inet6 2001:db8:0:2:' , output
)
5912 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth-peer' , env
= env
)
5914 self
. assertRegex ( output
, '2001:db8:1:1::2' )
5916 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth-peer' , env
= env
)
5918 self
. assertIn ( 'example.com' , output
)
5920 class NetworkdMTUTests ( unittest
. TestCase
, Utilities
):
5928 def check_mtu ( self
, mtu
, ipv6_mtu
= None , reset
= True ):
5934 self
. wait_online ([ 'dummy98:routable' ])
5935 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
5936 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
5938 # test normal restart
5940 self
. wait_online ([ 'dummy98:routable' ])
5941 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
5942 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
5945 self
. reset_check_mtu ( mtu
, ipv6_mtu
)
5947 def reset_check_mtu ( self
, mtu
, ipv6_mtu
= None ):
5948 ''' test setting mtu/ipv6_mtu with interface already up '''
5951 # note - changing the device mtu resets the ipv6 mtu
5952 check_output ( 'ip link set up mtu 1501 dev dummy98' )
5953 check_output ( 'ip link set up mtu 1500 dev dummy98' )
5954 self
. check_link_attr ( 'dummy98' , 'mtu' , '1500' )
5955 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , '1500' )
5957 self
. check_mtu ( mtu
, ipv6_mtu
, reset
= False )
5959 def test_mtu_network ( self
):
5960 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' )
5961 self
. check_mtu ( '1600' )
5963 def test_mtu_netdev ( self
):
5964 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network' , copy_dropins
= False )
5965 # note - MTU set by .netdev happens ONLY at device creation!
5966 self
. check_mtu ( '1600' , reset
= False )
5968 def test_mtu_link ( self
):
5969 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network' , copy_dropins
= False )
5970 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
5971 self
. check_mtu ( '1600' , reset
= False )
5973 def test_ipv6_mtu ( self
):
5974 ''' set ipv6 mtu without setting device mtu '''
5975 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1400.conf' )
5976 self
. check_mtu ( '1500' , '1400' )
5978 def test_ipv6_mtu_toolarge ( self
):
5979 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
5980 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5981 self
. check_mtu ( '1500' , '1500' )
5983 def test_mtu_network_ipv6_mtu ( self
):
5984 ''' set ipv6 mtu and set device mtu via network file '''
5985 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5986 self
. check_mtu ( '1600' , '1550' )
5988 def test_mtu_netdev_ipv6_mtu ( self
):
5989 ''' set ipv6 mtu and set device mtu via netdev file '''
5990 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5991 self
. check_mtu ( '1600' , '1550' , reset
= False )
5993 def test_mtu_link_ipv6_mtu ( self
):
5994 ''' set ipv6 mtu and set device mtu via link file '''
5995 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5996 self
. check_mtu ( '1600' , '1550' , reset
= False )
5999 if __name__
== '__main__' :
6000 parser
= argparse
. ArgumentParser ()
6001 parser
. add_argument ( '--build-dir' , help = 'Path to build dir' , dest
= 'build_dir' )
6002 parser
. add_argument ( '--networkd' , help = 'Path to systemd-networkd' , dest
= 'networkd_bin' )
6003 parser
. add_argument ( '--resolved' , help = 'Path to systemd-resolved' , dest
= 'resolved_bin' )
6004 parser
. add_argument ( '--timesyncd' , help = 'Path to systemd-timesyncd' , dest
= 'timesyncd_bin' )
6005 parser
. add_argument ( '--udevd' , help = 'Path to systemd-udevd' , dest
= 'udevd_bin' )
6006 parser
. add_argument ( '--wait-online' , help = 'Path to systemd-networkd-wait-online' , dest
= 'wait_online_bin' )
6007 parser
. add_argument ( '--networkctl' , help = 'Path to networkctl' , dest
= 'networkctl_bin' )
6008 parser
. add_argument ( '--resolvectl' , help = 'Path to resolvectl' , dest
= 'resolvectl_bin' )
6009 parser
. add_argument ( '--timedatectl' , help = 'Path to timedatectl' , dest
= 'timedatectl_bin' )
6010 parser
. add_argument ( '--udevadm' , help = 'Path to udevadm' , dest
= 'udevadm_bin' )
6011 parser
. add_argument ( '--valgrind' , help = 'Enable valgrind' , dest
= 'use_valgrind' , type = bool , nargs
= '?' , const
= True , default
= use_valgrind
)
6012 parser
. add_argument ( '--debug' , help = 'Generate debugging logs' , dest
= 'enable_debug' , type = bool , nargs
= '?' , const
= True , default
= enable_debug
)
6013 parser
. add_argument ( '--asan-options' , help = 'ASAN options' , dest
= 'asan_options' )
6014 parser
. add_argument ( '--lsan-options' , help = 'LSAN options' , dest
= 'lsan_options' )
6015 parser
. add_argument ( '--ubsan-options' , help = 'UBSAN options' , dest
= 'ubsan_options' )
6016 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
)
6017 ns
, unknown_args
= parser
. parse_known_args ( namespace
= unittest
)
6020 if ns
. networkd_bin
or ns
. resolved_bin
or ns
. timesyncd_bin
or ns
. udevd_bin
or \
6021 ns
. wait_online_bin
or ns
. networkctl_bin
or ns
. resolvectl_bin
or ns
. timedatectl_bin
or ns
. udevadm_bin
:
6022 print ( 'WARNING: --networkd, --resolved, --timesyncd, --udevd, --wait-online, --networkctl, --resolvectl, --timedatectl, or --udevadm options are ignored when --build-dir is specified.' )
6023 networkd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd' )
6024 resolved_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-resolved' )
6025 timesyncd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-timesyncd' )
6026 udevd_bin
= os
. path
. join ( ns
. build_dir
, 'udevadm' )
6027 wait_online_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd-wait-online' )
6028 networkctl_bin
= os
. path
. join ( ns
. build_dir
, 'networkctl' )
6029 resolvectl_bin
= os
. path
. join ( ns
. build_dir
, 'resolvectl' )
6030 timedatectl_bin
= os
. path
. join ( ns
. build_dir
, 'timedatectl' )
6031 udevadm_bin
= os
. path
. join ( ns
. build_dir
, 'udevadm' )
6034 networkd_bin
= ns
. networkd_bin
6036 resolved_bin
= ns
. resolved_bin
6037 if ns
. timesyncd_bin
:
6038 timesyncd_bin
= ns
. timesyncd_bin
6040 udevd_bin
= ns
. udevd_bin
6041 if ns
. wait_online_bin
:
6042 wait_online_bin
= ns
. wait_online_bin
6043 if ns
. networkctl_bin
:
6044 networkctl_bin
= ns
. networkctl_bin
6045 if ns
. resolvectl_bin
:
6046 resolvectl_bin
= ns
. resolvectl_bin
6047 if ns
. timedatectl_bin
:
6048 timedatectl_bin
= ns
. timedatectl_bin
6050 udevadm_bin
= ns
. udevadm_bin
6052 use_valgrind
= ns
. use_valgrind
6053 enable_debug
= ns
. enable_debug
6054 asan_options
= ns
. asan_options
6055 lsan_options
= ns
. lsan_options
6056 ubsan_options
= ns
. ubsan_options
6057 with_coverage
= ns
. with_coverage
6060 # Do not forget the trailing space.
6061 valgrind_cmd
= 'valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all '
6063 networkctl_cmd
= valgrind_cmd
. split () + [ networkctl_bin
]
6064 resolvectl_cmd
= valgrind_cmd
. split () + [ resolvectl_bin
]
6065 timedatectl_cmd
= valgrind_cmd
. split () + [ timedatectl_bin
]
6066 udevadm_cmd
= valgrind_cmd
. split () + [ udevadm_bin
]
6067 wait_online_cmd
= valgrind_cmd
. split () + [ wait_online_bin
]
6070 env
. update ({ 'ASAN_OPTIONS' : asan_options
})
6072 env
. update ({ 'LSAN_OPTIONS' : lsan_options
})
6074 env
. update ({ 'UBSAN_OPTIONS' : ubsan_options
})
6076 env
. update ({ 'SYSTEMD_MEMPOOL' : '0' })
6078 wait_online_env
= env
. copy ()
6080 wait_online_env
. update ({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
6082 sys
. argv
[ 1 :] = unknown_args
6083 unittest
. main ( verbosity
= 3 )