]>
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' )
3254 copy_network_unit ( '25-sysctl.network.d/25-ipv6-privacy-extensions.conf' )
3256 self
. wait_online ([ 'dummy98:degraded' ])
3258 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'use_tempaddr' , '2' )
3260 def test_sysctl_disable_ipv6 ( self
):
3261 copy_network_unit ( '25-sysctl-disable-ipv6.network' , '12-dummy.netdev' )
3263 print ( '## Disable ipv6' )
3264 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=1' )
3265 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=1' )
3268 self
. wait_online ([ 'dummy98:routable' ])
3270 output
= check_output ( 'ip -4 address show dummy98' )
3272 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3273 output
= check_output ( 'ip -6 address show dummy98' )
3275 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3276 self
. assertRegex ( output
, 'inet6 .* scope link' )
3277 output
= check_output ( 'ip -4 route show dev dummy98' )
3279 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3280 output
= check_output ( 'ip -6 route show default' )
3282 self
. assertRegex ( output
, 'default' )
3283 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3285 remove_link ( 'dummy98' )
3287 print ( '## Enable ipv6' )
3288 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=0' )
3289 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=0' )
3292 self
. wait_online ([ 'dummy98:routable' ])
3294 output
= check_output ( 'ip -4 address show dummy98' )
3296 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3297 output
= check_output ( 'ip -6 address show dummy98' )
3299 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3300 self
. assertRegex ( output
, 'inet6 .* scope link' )
3301 output
= check_output ( 'ip -4 route show dev dummy98' )
3303 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3304 output
= check_output ( 'ip -6 route show default' )
3306 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3308 def test_bind_carrier ( self
):
3309 copy_network_unit ( '25-bind-carrier.network' , '11-dummy.netdev' )
3312 # no bound interface.
3313 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
3314 output
= check_output ( 'ip address show test1' )
3316 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3317 self
. assertIn ( 'DOWN' , output
)
3318 self
. assertNotIn ( '192.168.10' , output
)
3320 # add one bound interface. The interface will be up.
3321 check_output ( 'ip link add dummy98 type dummy' )
3322 check_output ( 'ip link set dummy98 up' )
3323 self
. wait_online ([ 'test1:routable' ])
3324 output
= check_output ( 'ip address show test1' )
3326 self
. assertIn ( 'UP,LOWER_UP' , output
)
3327 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3329 # add another bound interface. The interface is still up.
3330 check_output ( 'ip link add dummy99 type dummy' )
3331 check_output ( 'ip link set dummy99 up' )
3332 self
. wait_operstate ( 'dummy99' , 'degraded' , setup_state
= 'unmanaged' )
3333 output
= check_output ( 'ip address show test1' )
3335 self
. assertIn ( 'UP,LOWER_UP' , output
)
3336 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3338 # remove one of the bound interfaces. The interface is still up
3339 remove_link ( 'dummy98' )
3340 output
= check_output ( 'ip address show test1' )
3342 self
. assertIn ( 'UP,LOWER_UP' , output
)
3343 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3345 # bring down the remaining bound interface. The interface will be down.
3346 check_output ( 'ip link set dummy99 down' )
3347 self
. wait_operstate ( 'test1' , 'off' )
3348 self
. wait_address_dropped ( 'test1' , r
'192.168.10' , ipv
= '-4' , timeout_sec
= 10 )
3349 output
= check_output ( 'ip address show test1' )
3351 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3352 self
. assertIn ( 'DOWN' , output
)
3353 self
. assertNotIn ( '192.168.10' , output
)
3355 # bring up the bound interface. The interface will be up.
3356 check_output ( 'ip link set dummy99 up' )
3357 self
. wait_online ([ 'test1:routable' ])
3358 output
= check_output ( 'ip address show test1' )
3360 self
. assertIn ( 'UP,LOWER_UP' , output
)
3361 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3363 # remove the remaining bound interface. The interface will be down.
3364 remove_link ( 'dummy99' )
3365 self
. wait_operstate ( 'test1' , 'off' )
3366 self
. wait_address_dropped ( 'test1' , r
'192.168.10' , ipv
= '-4' , timeout_sec
= 10 )
3367 output
= check_output ( 'ip address show test1' )
3369 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3370 self
. assertIn ( 'DOWN' , output
)
3371 self
. assertNotIn ( '192.168.10' , output
)
3373 # re-add one bound interface. The interface will be up.
3374 check_output ( 'ip link add dummy98 type dummy' )
3375 check_output ( 'ip link set dummy98 up' )
3376 self
. wait_online ([ 'test1:routable' ])
3377 output
= check_output ( 'ip address show test1' )
3379 self
. assertIn ( 'UP,LOWER_UP' , output
)
3380 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3382 def _test_activation_policy ( self
, interface
, test
):
3383 conffile
= '25-activation-policy.network'
3385 conffile
= f
' {conffile} .d/ {test} .conf'
3386 if interface
== 'vlan99' :
3387 copy_network_unit ( '21-vlan.netdev' , '21-vlan-test1.network' )
3388 copy_network_unit ( '11-dummy.netdev' , conffile
, copy_dropins
= False )
3391 always
= test
. startswith ( 'always' )
3392 initial_up
= test
!= 'manual' and not test
. endswith ( 'down' ) # note: default is up
3393 expect_up
= initial_up
3394 next_up
= not expect_up
3396 if test
. endswith ( 'down' ):
3397 self
. wait_activated ( interface
)
3399 for iteration
in range ( 4 ):
3400 with self
. subTest ( iteration
= iteration
, expect_up
= expect_up
):
3401 operstate
= 'routable' if expect_up
else 'off'
3402 setup_state
= 'configured' if expect_up
else ( 'configuring' if iteration
== 0 else None )
3403 self
. wait_operstate ( interface
, operstate
, setup_state
= setup_state
, setup_timeout
= 20 )
3406 self
. assertIn ( 'UP' , check_output ( f
'ip link show {interface} ' ))
3407 self
. assertIn ( '192.168.10.30/24' , check_output ( f
'ip address show {interface} ' ))
3408 self
. assertIn ( 'default via 192.168.10.1' , check_output ( f
'ip route show dev {interface} ' ))
3410 self
. assertIn ( 'DOWN' , check_output ( f
'ip link show {interface} ' ))
3413 check_output ( f
'ip link set dev {interface} up' )
3415 check_output ( f
'ip link set dev {interface} down' )
3416 expect_up
= initial_up
if always
else next_up
3417 next_up
= not next_up
3421 def test_activation_policy ( self
):
3423 for interface
in [ 'test1' , 'vlan99' ]:
3424 for test
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , '' ]:
3430 print ( f
'### test_activation_policy(interface= {interface} , test= {test} )' )
3431 with self
. subTest ( interface
= interface
, test
= test
):
3432 self
._ test
_ activation
_ policy
( interface
, test
)
3434 def _test_activation_policy_required_for_online ( self
, policy
, required
):
3435 conffile
= '25-activation-policy.network'
3436 units
= [ '11-dummy.netdev' , '12-dummy.netdev' , '12-dummy.network' , conffile
]
3438 units
+= [ f
' {conffile} .d/ {policy} .conf' ]
3440 units
+= [ f
' {conffile} .d/required- {required} .conf' ]
3441 copy_network_unit (* units
, copy_dropins
= False )
3444 if policy
. endswith ( 'down' ):
3445 self
. wait_activated ( 'test1' )
3447 if policy
. endswith ( 'down' ) or policy
== 'manual' :
3448 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
3450 self
. wait_online ([ 'test1' ])
3452 if policy
== 'always-down' :
3453 # if always-down, required for online is forced to no
3456 # otherwise if required for online is specified, it should match that
3457 expected
= required
== 'yes'
3459 # otherwise if only policy specified, required for online defaults to
3460 # true if policy is up, always-up, or bound
3461 expected
= policy
. endswith ( 'up' ) or policy
== 'bound'
3463 # default is true, if neither are specified
3466 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
3469 yesno
= 'yes' if expected
else 'no'
3470 self
. assertRegex ( output
, f
'Required For Online: {yesno} ' )
3472 def test_activation_policy_required_for_online ( self
):
3474 for policy
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , 'bound' , '' ]:
3475 for required
in [ 'yes' , 'no' , '' ]:
3481 print ( f
'### test_activation_policy_required_for_online(policy= {policy} , required= {required} )' )
3482 with self
. subTest ( policy
= policy
, required
= required
):
3483 self
._ test
_ activation
_ policy
_ required
_ for
_ online
( policy
, required
)
3485 def test_domain ( self
):
3486 copy_network_unit ( '12-dummy.netdev' , '24-search-domain.network' )
3488 self
. wait_online ([ 'dummy98:routable' ])
3490 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
3492 self
. assertRegex ( output
, 'Address: 192.168.42.100' )
3493 self
. assertRegex ( output
, 'DNS: 192.168.42.1' )
3494 self
. assertRegex ( output
, 'Search Domains: one' )
3496 def test_keep_configuration_static ( self
):
3497 check_output ( 'ip link add name dummy98 type dummy' )
3498 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
3499 check_output ( 'ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500' )
3500 output
= check_output ( 'ip address show dummy98' )
3502 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
3503 self
. assertRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
3504 output
= check_output ( 'ip route show dev dummy98' )
3507 copy_network_unit ( '24-keep-configuration-static.network' )
3509 self
. wait_online ([ 'dummy98:routable' ])
3511 output
= check_output ( 'ip address show dummy98' )
3513 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
3514 self
. assertNotRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
3516 @expectedFailureIfNexthopIsNotAvailable ()
3517 def test_nexthop ( self
):
3518 def check_nexthop ( self
):
3519 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
3521 output
= check_output ( 'ip nexthop list dev veth99' )
3523 self
. assertIn ( 'id 1 via 192.168.5.1 dev veth99' , output
)
3524 self
. assertIn ( 'id 2 via 2001:1234:5:8f63::2 dev veth99' , output
)
3525 self
. assertIn ( 'id 3 dev veth99' , output
)
3526 self
. assertIn ( 'id 4 dev veth99' , output
)
3527 self
. assertRegex ( output
, 'id 5 via 192.168.10.1 dev veth99 .*onlink' )
3528 self
. assertIn ( 'id 8 via fe80:0:222:4dff:ff:ff:ff:ff dev veth99' , output
)
3529 self
. assertRegex ( output
, r
'id [0-9]* via 192.168.5.2 dev veth99' )
3531 output
= check_output ( 'ip nexthop list dev dummy98' )
3533 self
. assertIn ( 'id 20 via 192.168.20.1 dev dummy98' , output
)
3535 # kernel manages blackhole nexthops on lo
3536 output
= check_output ( 'ip nexthop list dev lo' )
3538 self
. assertIn ( 'id 6 blackhole' , output
)
3539 self
. assertIn ( 'id 7 blackhole' , output
)
3541 # group nexthops are shown with -0 option
3542 output
= check_output ( 'ip -0 nexthop list id 21' )
3544 self
. assertRegex ( output
, r
'id 21 group (1,3/20|20/1,3)' )
3546 output
= check_output ( 'ip route show dev veth99 10.10.10.10' )
3548 self
. assertEqual ( '10.10.10.10 nhid 1 via 192.168.5.1 proto static' , output
)
3550 output
= check_output ( 'ip route show dev veth99 10.10.10.11' )
3552 self
. assertEqual ( '10.10.10.11 nhid 2 via inet6 2001:1234:5:8f63::2 proto static' , output
)
3554 output
= check_output ( 'ip route show dev veth99 10.10.10.12' )
3556 self
. assertEqual ( '10.10.10.12 nhid 5 via 192.168.10.1 proto static onlink' , output
)
3558 output
= check_output ( 'ip -6 route show dev veth99 2001:1234:5:8f62::1' )
3560 self
. assertEqual ( '2001:1234:5:8f62::1 nhid 2 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium' , output
)
3562 output
= check_output ( 'ip route show 10.10.10.13' )
3564 self
. assertEqual ( 'blackhole 10.10.10.13 nhid 6 dev lo proto static' , output
)
3566 output
= check_output ( 'ip -6 route show 2001:1234:5:8f62::2' )
3568 self
. assertEqual ( 'blackhole 2001:1234:5:8f62::2 nhid 7 dev lo proto static metric 1024 pref medium' , output
)
3570 output
= check_output ( 'ip route show 10.10.10.14' )
3572 self
. assertIn ( '10.10.10.14 nhid 21 proto static' , output
)
3573 self
. assertIn ( 'nexthop via 192.168.20.1 dev dummy98 weight 1' , output
)
3574 self
. assertIn ( 'nexthop via 192.168.5.1 dev veth99 weight 3' , output
)
3576 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3579 copy_network_unit ( '25-nexthop.network' , '25-veth.netdev' , '25-veth-peer.network' ,
3580 '12-dummy.netdev' , '25-nexthop-dummy.network' )
3585 remove_network_unit ( '25-nexthop.network' )
3586 copy_network_unit ( '25-nexthop-nothing.network' )
3588 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
3590 output
= check_output ( 'ip nexthop list dev veth99' )
3592 self
. assertEqual ( output
, '' )
3593 output
= check_output ( 'ip nexthop list dev lo' )
3595 self
. assertEqual ( output
, '' )
3597 remove_network_unit ( '25-nexthop-nothing.network' )
3598 copy_network_unit ( '25-nexthop.network' )
3599 networkctl_reconfigure ( 'dummy98' )
3604 remove_link ( 'veth99' )
3607 output
= check_output ( 'ip nexthop list dev lo' )
3609 self
. assertEqual ( output
, '' )
3611 class NetworkdTCTests ( unittest
. TestCase
, Utilities
):
3619 @expectedFailureIfModuleIsNotAvailable ( 'sch_cake' )
3620 def test_qdisc_cake ( self
):
3621 copy_network_unit ( '25-qdisc-cake.network' , '12-dummy.netdev' )
3623 self
. wait_online ([ 'dummy98:routable' ])
3625 output
= check_output ( 'tc qdisc show dev dummy98' )
3627 self
. assertIn ( 'qdisc cake 3a: root' , output
)
3628 self
. assertIn ( 'bandwidth 500Mbit' , output
)
3629 self
. assertIn ( 'autorate-ingress' , output
)
3630 self
. assertIn ( 'diffserv8' , output
)
3631 self
. assertIn ( 'dual-dsthost' , output
)
3632 self
. assertIn ( ' nat' , output
)
3633 self
. assertIn ( ' wash' , output
)
3634 self
. assertIn ( ' split-gso' , output
)
3635 self
. assertIn ( ' raw' , output
)
3636 self
. assertIn ( ' atm' , output
)
3637 self
. assertIn ( 'overhead 128' , output
)
3638 self
. assertIn ( 'mpu 20' , output
)
3639 self
. assertIn ( 'fwmark 0xff00' , output
)
3640 self
. assertIn ( 'rtt 1s' , output
)
3641 self
. assertIn ( 'ack-filter-aggressive' , output
)
3643 @expectedFailureIfModuleIsNotAvailable ( 'sch_codel' )
3644 def test_qdisc_codel ( self
):
3645 copy_network_unit ( '25-qdisc-codel.network' , '12-dummy.netdev' )
3647 self
. wait_online ([ 'dummy98:routable' ])
3649 output
= check_output ( 'tc qdisc show dev dummy98' )
3651 self
. assertRegex ( output
, 'qdisc codel 33: root' )
3652 self
. assertRegex ( output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn' )
3654 @expectedFailureIfModuleIsNotAvailable ( 'sch_drr' )
3655 def test_qdisc_drr ( self
):
3656 copy_network_unit ( '25-qdisc-drr.network' , '12-dummy.netdev' )
3658 self
. wait_online ([ 'dummy98:routable' ])
3660 output
= check_output ( 'tc qdisc show dev dummy98' )
3662 self
. assertRegex ( output
, 'qdisc drr 2: root' )
3663 output
= check_output ( 'tc class show dev dummy98' )
3665 self
. assertRegex ( output
, 'class drr 2:30 root quantum 2000b' )
3667 @expectedFailureIfModuleIsNotAvailable ( 'sch_ets' )
3668 def test_qdisc_ets ( self
):
3669 copy_network_unit ( '25-qdisc-ets.network' , '12-dummy.netdev' )
3671 self
. wait_online ([ 'dummy98:routable' ])
3673 output
= check_output ( 'tc qdisc show dev dummy98' )
3676 self
. assertRegex ( output
, 'qdisc ets 3a: root' )
3677 self
. assertRegex ( output
, 'bands 10 strict 3' )
3678 self
. assertRegex ( output
, 'quanta 1 2 3 4 5' )
3679 self
. assertRegex ( output
, 'priomap 3 4 5 6 7' )
3681 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq' )
3682 def test_qdisc_fq ( self
):
3683 copy_network_unit ( '25-qdisc-fq.network' , '12-dummy.netdev' )
3685 self
. wait_online ([ 'dummy98:routable' ])
3687 output
= check_output ( 'tc qdisc show dev dummy98' )
3689 self
. assertRegex ( output
, 'qdisc fq 32: root' )
3690 self
. assertRegex ( output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511' )
3691 self
. assertRegex ( output
, 'quantum 1500' )
3692 self
. assertRegex ( output
, 'initial_quantum 13000' )
3693 self
. assertRegex ( output
, 'maxrate 1Mbit' )
3695 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_codel' )
3696 def test_qdisc_fq_codel ( self
):
3697 copy_network_unit ( '25-qdisc-fq_codel.network' , '12-dummy.netdev' )
3699 self
. wait_online ([ 'dummy98:routable' ])
3701 output
= check_output ( 'tc qdisc show dev dummy98' )
3703 self
. assertRegex ( output
, 'qdisc fq_codel 34: root' )
3704 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' )
3706 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_pie' )
3707 def test_qdisc_fq_pie ( self
):
3708 copy_network_unit ( '25-qdisc-fq_pie.network' , '12-dummy.netdev' )
3710 self
. wait_online ([ 'dummy98:routable' ])
3712 output
= check_output ( 'tc qdisc show dev dummy98' )
3715 self
. assertRegex ( output
, 'qdisc fq_pie 3a: root' )
3716 self
. assertRegex ( output
, 'limit 200000p' )
3718 @expectedFailureIfModuleIsNotAvailable ( 'sch_gred' )
3719 def test_qdisc_gred ( self
):
3720 copy_network_unit ( '25-qdisc-gred.network' , '12-dummy.netdev' )
3722 self
. wait_online ([ 'dummy98:routable' ])
3724 output
= check_output ( 'tc qdisc show dev dummy98' )
3726 self
. assertRegex ( output
, 'qdisc gred 38: root' )
3727 self
. assertRegex ( output
, 'vqs 12 default 10 grio' )
3729 @expectedFailureIfModuleIsNotAvailable ( 'sch_hhf' )
3730 def test_qdisc_hhf ( self
):
3731 copy_network_unit ( '25-qdisc-hhf.network' , '12-dummy.netdev' )
3733 self
. wait_online ([ 'dummy98:routable' ])
3735 output
= check_output ( 'tc qdisc show dev dummy98' )
3737 self
. assertRegex ( output
, 'qdisc hhf 3a: root' )
3738 self
. assertRegex ( output
, 'limit 1022p' )
3740 @expectedFailureIfModuleIsNotAvailable ( 'sch_htb' )
3741 def test_qdisc_htb_fifo ( self
):
3742 copy_network_unit ( '25-qdisc-htb-fifo.network' , '12-dummy.netdev' )
3744 self
. wait_online ([ 'dummy98:routable' ])
3746 output
= check_output ( 'tc qdisc show dev dummy98' )
3748 self
. assertRegex ( output
, 'qdisc htb 2: root' )
3749 self
. assertRegex ( output
, r
'default (0x30|30)' )
3751 self
. assertRegex ( output
, 'qdisc pfifo 37: parent 2:37' )
3752 self
. assertRegex ( output
, 'limit 100000p' )
3754 self
. assertRegex ( output
, 'qdisc bfifo 3a: parent 2:3a' )
3755 self
. assertRegex ( output
, 'limit 1000000' )
3757 self
. assertRegex ( output
, 'qdisc pfifo_head_drop 3b: parent 2:3b' )
3758 self
. assertRegex ( output
, 'limit 1023p' )
3760 self
. assertRegex ( output
, 'qdisc pfifo_fast 3c: parent 2:3c' )
3762 output
= check_output ( 'tc -d class show dev dummy98' )
3764 # Here (:|prio) is a workaround for a bug in iproute2 v6.2.0 caused by
3765 # https://github.com/shemminger/iproute2/commit/010a8388aea11e767ba3a2506728b9ad9760df0e
3766 # which is fixed in v6.3.0 by
3767 # https://github.com/shemminger/iproute2/commit/4e0e56e0ef05387f7f5d8ab41fe6ec6a1897b26d
3768 self
. assertRegex ( output
, 'class htb 2:37 root leaf 37(:|prio) ' )
3769 self
. assertRegex ( output
, 'class htb 2:3a root leaf 3a(:|prio) ' )
3770 self
. assertRegex ( output
, 'class htb 2:3b root leaf 3b(:|prio) ' )
3771 self
. assertRegex ( output
, 'class htb 2:3c root leaf 3c(:|prio) ' )
3772 self
. assertRegex ( output
, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit' )
3773 self
. assertRegex ( output
, 'burst 123456' )
3774 self
. assertRegex ( output
, 'cburst 123457' )
3776 @expectedFailureIfModuleIsNotAvailable ( 'sch_ingress' )
3777 def test_qdisc_ingress ( self
):
3778 copy_network_unit ( '25-qdisc-clsact.network' , '12-dummy.netdev' ,
3779 '25-qdisc-ingress.network' , '11-dummy.netdev' )
3781 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' ])
3783 output
= check_output ( 'tc qdisc show dev dummy98' )
3785 self
. assertRegex ( output
, 'qdisc clsact' )
3787 output
= check_output ( 'tc qdisc show dev test1' )
3789 self
. assertRegex ( output
, 'qdisc ingress' )
3791 @expectedFailureIfModuleIsNotAvailable ( 'sch_netem' )
3792 def test_qdisc_netem ( self
):
3793 copy_network_unit ( '25-qdisc-netem.network' , '12-dummy.netdev' ,
3794 '25-qdisc-netem-compat.network' , '11-dummy.netdev' )
3796 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' ])
3798 output
= check_output ( 'tc qdisc show dev dummy98' )
3800 self
. assertRegex ( output
, 'qdisc netem 30: root' )
3801 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
3803 output
= check_output ( 'tc qdisc show dev test1' )
3805 self
. assertRegex ( output
, 'qdisc netem [0-9a-f]*: root' )
3806 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
3808 @expectedFailureIfModuleIsNotAvailable ( 'sch_pie' )
3809 def test_qdisc_pie ( self
):
3810 copy_network_unit ( '25-qdisc-pie.network' , '12-dummy.netdev' )
3812 self
. wait_online ([ 'dummy98:routable' ])
3814 output
= check_output ( 'tc qdisc show dev dummy98' )
3816 self
. assertRegex ( output
, 'qdisc pie 3a: root' )
3817 self
. assertRegex ( output
, 'limit 200000' )
3819 @expectedFailureIfModuleIsNotAvailable ( 'sch_qfq' )
3820 def test_qdisc_qfq ( self
):
3821 copy_network_unit ( '25-qdisc-qfq.network' , '12-dummy.netdev' )
3823 self
. wait_online ([ 'dummy98:routable' ])
3825 output
= check_output ( 'tc qdisc show dev dummy98' )
3827 self
. assertRegex ( output
, 'qdisc qfq 2: root' )
3828 output
= check_output ( 'tc class show dev dummy98' )
3830 self
. assertRegex ( output
, 'class qfq 2:30 root weight 2 maxpkt 16000' )
3831 self
. assertRegex ( output
, 'class qfq 2:31 root weight 10 maxpkt 8000' )
3833 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfb' )
3834 def test_qdisc_sfb ( self
):
3835 copy_network_unit ( '25-qdisc-sfb.network' , '12-dummy.netdev' )
3837 self
. wait_online ([ 'dummy98:routable' ])
3839 output
= check_output ( 'tc qdisc show dev dummy98' )
3841 self
. assertRegex ( output
, 'qdisc sfb 39: root' )
3842 self
. assertRegex ( output
, 'limit 200000' )
3844 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfq' )
3845 def test_qdisc_sfq ( self
):
3846 copy_network_unit ( '25-qdisc-sfq.network' , '12-dummy.netdev' )
3848 self
. wait_online ([ 'dummy98:routable' ])
3850 output
= check_output ( 'tc qdisc show dev dummy98' )
3852 self
. assertRegex ( output
, 'qdisc sfq 36: root' )
3853 self
. assertRegex ( output
, 'perturb 5sec' )
3855 @expectedFailureIfModuleIsNotAvailable ( 'sch_tbf' )
3856 def test_qdisc_tbf ( self
):
3857 copy_network_unit ( '25-qdisc-tbf.network' , '12-dummy.netdev' )
3859 self
. wait_online ([ 'dummy98:routable' ])
3861 output
= check_output ( 'tc qdisc show dev dummy98' )
3863 self
. assertRegex ( output
, 'qdisc tbf 35: root' )
3864 self
. assertRegex ( output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms' )
3866 @expectedFailureIfModuleIsNotAvailable ( 'sch_teql' )
3867 def test_qdisc_teql ( self
):
3868 call_quiet ( 'rmmod sch_teql' )
3870 copy_network_unit ( '25-qdisc-teql.network' , '12-dummy.netdev' )
3872 self
. wait_links ( 'dummy98' )
3873 check_output ( 'modprobe sch_teql max_equalizers=2' )
3874 self
. wait_online ([ 'dummy98:routable' ])
3876 output
= check_output ( 'tc qdisc show dev dummy98' )
3878 self
. assertRegex ( output
, 'qdisc teql1 31: root' )
3880 class NetworkdStateFileTests ( unittest
. TestCase
, Utilities
):
3888 def test_state_file ( self
):
3889 copy_network_unit ( '12-dummy.netdev' , '25-state-file-tests.network' )
3891 self
. wait_online ([ 'dummy98:routable' ])
3893 # make link state file updated
3894 check_output (* resolvectl_cmd
, 'revert' , 'dummy98' , env
= env
)
3896 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3899 output
= read_link_state_file ( 'dummy98' )
3901 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
3902 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
3903 self
. assertIn ( 'ADMIN_STATE=configured' , output
)
3904 self
. assertIn ( 'OPER_STATE=routable' , output
)
3905 self
. assertIn ( 'REQUIRED_FOR_ONLINE=yes' , output
)
3906 self
. assertIn ( 'REQUIRED_OPER_STATE_FOR_ONLINE=routable' , output
)
3907 self
. assertIn ( 'REQUIRED_FAMILY_FOR_ONLINE=both' , output
)
3908 self
. assertIn ( 'ACTIVATION_POLICY=up' , output
)
3909 self
. assertIn ( 'NETWORK_FILE=/run/systemd/network/25-state-file-tests.network' , output
)
3910 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
3911 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
3912 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
3913 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
3914 self
. assertIn ( 'LLMNR=no' , output
)
3915 self
. assertIn ( 'MDNS=yes' , output
)
3916 self
. assertIn ( 'DNSSEC=no' , output
)
3918 check_output (* resolvectl_cmd
, 'dns' , 'dummy98' , '10.10.10.12#ccc.com' , '10.10.10.13' , '1111:2222::3333' , env
= env
)
3919 check_output (* resolvectl_cmd
, 'domain' , 'dummy98' , 'hogehogehoge' , '~foofoofoo' , env
= env
)
3920 check_output (* resolvectl_cmd
, 'llmnr' , 'dummy98' , 'yes' , env
= env
)
3921 check_output (* resolvectl_cmd
, 'mdns' , 'dummy98' , 'no' , env
= env
)
3922 check_output (* resolvectl_cmd
, 'dnssec' , 'dummy98' , 'yes' , env
= env
)
3923 check_output (* timedatectl_cmd
, 'ntp-servers' , 'dummy98' , '2.fedora.pool.ntp.org' , '3.fedora.pool.ntp.org' , env
= env
)
3925 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3928 output
= read_link_state_file ( 'dummy98' )
3930 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
3931 self
. assertIn ( 'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org' , output
)
3932 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
3933 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
3934 self
. assertIn ( 'LLMNR=yes' , output
)
3935 self
. assertIn ( 'MDNS=no' , output
)
3936 self
. assertIn ( 'DNSSEC=yes' , output
)
3938 check_output (* timedatectl_cmd
, 'revert' , 'dummy98' , env
= env
)
3940 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3943 output
= read_link_state_file ( 'dummy98' )
3945 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
3946 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
3947 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
3948 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
3949 self
. assertIn ( 'LLMNR=yes' , output
)
3950 self
. assertIn ( 'MDNS=no' , output
)
3951 self
. assertIn ( 'DNSSEC=yes' , output
)
3953 check_output (* resolvectl_cmd
, 'revert' , 'dummy98' , env
= env
)
3955 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3958 output
= read_link_state_file ( 'dummy98' )
3960 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
3961 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
3962 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
3963 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
3964 self
. assertIn ( 'LLMNR=no' , output
)
3965 self
. assertIn ( 'MDNS=yes' , output
)
3966 self
. assertIn ( 'DNSSEC=no' , output
)
3968 def test_address_state ( self
):
3969 copy_network_unit ( '12-dummy.netdev' , '12-dummy-no-address.network' )
3972 self
. wait_online ([ 'dummy98:degraded' ])
3974 output
= read_link_state_file ( 'dummy98' )
3975 self
. assertIn ( 'IPV4_ADDRESS_STATE=off' , output
)
3976 self
. assertIn ( 'IPV6_ADDRESS_STATE=degraded' , output
)
3978 # with a routable IPv4 address
3979 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
3980 self
. wait_online ([ 'dummy98:routable' ], ipv4
= True )
3981 self
. wait_online ([ 'dummy98:routable' ])
3983 output
= read_link_state_file ( 'dummy98' )
3984 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
3985 self
. assertIn ( 'IPV6_ADDRESS_STATE=degraded' , output
)
3987 check_output ( 'ip address del 10.1.2.3/16 dev dummy98' )
3989 # with a routable IPv6 address
3990 check_output ( 'ip address add 2002:da8:1:0:1034:56ff:fe78:9abc/64 dev dummy98' )
3991 self
. wait_online ([ 'dummy98:routable' ], ipv6
= True )
3992 self
. wait_online ([ 'dummy98:routable' ])
3994 output
= read_link_state_file ( 'dummy98' )
3995 self
. assertIn ( 'IPV4_ADDRESS_STATE=off' , output
)
3996 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
3998 class NetworkdBondTests ( unittest
. TestCase
, Utilities
):
4006 def test_bond_keep_master ( self
):
4007 check_output ( 'ip link add bond199 type bond mode active-backup' )
4008 check_output ( 'ip link add dummy98 type dummy' )
4009 check_output ( 'ip link set dummy98 master bond199' )
4011 copy_network_unit ( '23-keep-master.network' )
4013 self
. wait_online ([ 'dummy98:enslaved' ])
4015 output
= check_output ( 'ip -d link show bond199' )
4017 self
. assertRegex ( output
, 'active_slave dummy98' )
4019 output
= check_output ( 'ip -d link show dummy98' )
4021 self
. assertRegex ( output
, 'master bond199' )
4023 def test_bond_active_slave ( self
):
4024 copy_network_unit ( '23-active-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
4026 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
4028 output
= check_output ( 'ip -d link show bond199' )
4030 self
. assertIn ( 'active_slave dummy98' , output
)
4032 def test_bond_primary_slave ( self
):
4033 copy_network_unit ( '23-primary-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
4035 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
4037 output
= check_output ( 'ip -d link show bond199' )
4039 self
. assertIn ( 'primary dummy98' , output
)
4042 mkdir_p ( os
. path
. join ( network_unit_dir
, '23-bond199.network.d' ))
4043 for mac
in [ '00:11:22:33:44:55' , '00:11:22:33:44:56' ]:
4044 with
open ( os
. path
. join ( network_unit_dir
, '23-bond199.network.d/mac.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
4045 f
. write ( f
'[Link] \n MACAddress= {mac} \n ' )
4048 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
4050 output
= check_output ( 'ip -d link show bond199' )
4052 self
. assertIn ( f
'link/ether {mac} ' , output
)
4054 def test_bond_operstate ( self
):
4055 copy_network_unit ( '25-bond.netdev' , '11-dummy.netdev' , '12-dummy.netdev' ,
4056 '25-bond99.network' , '25-bond-slave.network' )
4058 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bond99:routable' ])
4060 output
= check_output ( 'ip -d link show dummy98' )
4062 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
4064 output
= check_output ( 'ip -d link show test1' )
4066 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
4068 output
= check_output ( 'ip -d link show bond99' )
4070 self
. assertRegex ( output
, 'MASTER,UP,LOWER_UP' )
4072 self
. wait_operstate ( 'dummy98' , 'enslaved' )
4073 self
. wait_operstate ( 'test1' , 'enslaved' )
4074 self
. wait_operstate ( 'bond99' , 'routable' )
4076 check_output ( 'ip link set dummy98 down' )
4078 self
. wait_operstate ( 'dummy98' , 'off' )
4079 self
. wait_operstate ( 'test1' , 'enslaved' )
4080 self
. wait_operstate ( 'bond99' , 'routable' )
4082 check_output ( 'ip link set dummy98 up' )
4084 self
. wait_operstate ( 'dummy98' , 'enslaved' )
4085 self
. wait_operstate ( 'test1' , 'enslaved' )
4086 self
. wait_operstate ( 'bond99' , 'routable' )
4088 check_output ( 'ip link set dummy98 down' )
4089 check_output ( 'ip link set test1 down' )
4091 self
. wait_operstate ( 'dummy98' , 'off' )
4092 self
. wait_operstate ( 'test1' , 'off' )
4094 if not self
. wait_operstate ( 'bond99' , 'no-carrier' , setup_timeout
= 30 , fail_assert
= False ):
4095 # Huh? Kernel does not recognize that all slave interfaces are down?
4096 # Let's confirm that networkd's operstate is consistent with ip's result.
4097 self
. assertNotRegex ( output
, 'NO-CARRIER' )
4099 class NetworkdBridgeTests ( unittest
. TestCase
, Utilities
):
4107 def test_bridge_vlan ( self
):
4108 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave.network' ,
4109 '26-bridge.netdev' , '26-bridge-vlan-master.network' )
4111 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' ])
4113 output
= check_output ( 'bridge vlan show dev test1' )
4115 self
. assertNotRegex ( output
, '4063' )
4116 for i
in range ( 4064 , 4095 ):
4117 self
. assertRegex ( output
, f
' {i} ' )
4118 self
. assertNotRegex ( output
, '4095' )
4120 output
= check_output ( 'bridge vlan show dev bridge99' )
4122 self
. assertNotRegex ( output
, '4059' )
4123 for i
in range ( 4060 , 4095 ):
4124 self
. assertRegex ( output
, f
' {i} ' )
4125 self
. assertNotRegex ( output
, '4095' )
4127 def test_bridge_vlan_issue_20373 ( self
):
4128 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave-issue-20373.network' ,
4129 '26-bridge-issue-20373.netdev' , '26-bridge-vlan-master-issue-20373.network' ,
4130 '21-vlan.netdev' , '21-vlan.network' )
4132 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' , 'vlan99:routable' ])
4134 output
= check_output ( 'bridge vlan show dev test1' )
4136 self
. assertIn ( '100 PVID Egress Untagged' , output
)
4137 self
. assertIn ( '560' , output
)
4138 self
. assertIn ( '600' , output
)
4140 output
= check_output ( 'bridge vlan show dev bridge99' )
4142 self
. assertIn ( '1 PVID Egress Untagged' , output
)
4143 self
. assertIn ( '100' , output
)
4144 self
. assertIn ( '600' , output
)
4146 def test_bridge_mdb ( self
):
4147 copy_network_unit ( '11-dummy.netdev' , '26-bridge-mdb-slave.network' ,
4148 '26-bridge.netdev' , '26-bridge-mdb-master.network' )
4150 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' ])
4152 output
= check_output ( 'bridge mdb show dev bridge99' )
4154 self
. assertRegex ( output
, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064' )
4155 self
. assertRegex ( output
, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065' )
4157 # Old kernel may not support bridge MDB entries on bridge master
4158 if call_quiet ( 'bridge mdb add dev bridge99 port bridge99 grp 224.0.1.3 temp vid 4068' ) == 0 :
4159 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp ff02:aaaa:fee5::1:4 temp *vid 4066' )
4160 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp 224.0.1.2 temp *vid 4067' )
4162 def test_bridge_keep_master ( self
):
4163 check_output ( 'ip link add bridge99 type bridge' )
4164 check_output ( 'ip link set bridge99 up' )
4165 check_output ( 'ip link add dummy98 type dummy' )
4166 check_output ( 'ip link set dummy98 master bridge99' )
4168 copy_network_unit ( '23-keep-master.network' )
4170 self
. wait_online ([ 'dummy98:enslaved' ])
4172 output
= check_output ( 'ip -d link show dummy98' )
4174 self
. assertRegex ( output
, 'master bridge99' )
4175 self
. assertRegex ( output
, 'bridge' )
4177 output
= check_output ( 'bridge -d link show dummy98' )
4179 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
4180 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
4181 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
4182 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
4183 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
4184 # CONFIG_BRIDGE_IGMP_SNOOPING=y
4185 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
4186 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
4187 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
4188 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
4189 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
4190 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
4192 def test_bridge_property ( self
):
4193 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
4194 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
4195 '25-bridge99.network' )
4197 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' ])
4199 output
= check_output ( 'ip -d link show bridge99' )
4201 self
. assertIn ( 'mtu 9000 ' , output
)
4203 output
= check_output ( 'ip -d link show test1' )
4205 self
. assertIn ( 'master bridge99 ' , output
)
4206 self
. assertIn ( 'bridge_slave' , output
)
4207 self
. assertIn ( 'mtu 9000 ' , output
)
4209 output
= check_output ( 'ip -d link show dummy98' )
4211 self
. assertIn ( 'master bridge99 ' , output
)
4212 self
. assertIn ( 'bridge_slave' , output
)
4213 self
. assertIn ( 'mtu 9000 ' , output
)
4215 output
= check_output ( 'ip addr show bridge99' )
4217 self
. assertIn ( '192.168.0.15/24' , output
)
4219 output
= check_output ( 'bridge -d link show dummy98' )
4221 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
4222 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
4223 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'isolated' , '1' )
4224 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
4225 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
4226 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
4227 # CONFIG_BRIDGE_IGMP_SNOOPING=y
4228 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
4229 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
4230 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
4231 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
4232 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
4233 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
4235 output
= check_output ( 'bridge -d link show test1' )
4237 self
. check_bridge_port_attr ( 'bridge99' , 'test1' , 'priority' , '0' )
4239 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
4240 output
= check_output ( 'ip addr show bridge99' )
4242 self
. assertIn ( '192.168.0.16/24' , output
)
4245 print ( '### ip -6 route list table all dev bridge99' )
4246 output
= check_output ( 'ip -6 route list table all dev bridge99' )
4248 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
4250 remove_link ( 'test1' )
4251 self
. wait_operstate ( 'bridge99' , 'routable' )
4253 output
= check_output ( 'ip -d link show bridge99' )
4255 self
. assertIn ( 'mtu 9000 ' , output
)
4257 output
= check_output ( 'ip -d link show dummy98' )
4259 self
. assertIn ( 'master bridge99 ' , output
)
4260 self
. assertIn ( 'bridge_slave' , output
)
4261 self
. assertIn ( 'mtu 9000 ' , output
)
4263 remove_link ( 'dummy98' )
4264 self
. wait_operstate ( 'bridge99' , 'no-carrier' )
4266 output
= check_output ( 'ip -d link show bridge99' )
4268 # When no carrier, the kernel may reset the MTU
4269 self
. assertIn ( 'NO-CARRIER' , output
)
4271 output
= check_output ( 'ip address show bridge99' )
4273 self
. assertNotIn ( '192.168.0.15/24' , output
)
4274 self
. assertIn ( '192.168.0.16/24' , output
) # foreign address is kept
4276 print ( '### ip -6 route list table all dev bridge99' )
4277 output
= check_output ( 'ip -6 route list table all dev bridge99' )
4279 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
4281 check_output ( 'ip link add dummy98 type dummy' )
4282 self
. wait_online ([ 'dummy98:enslaved' , 'bridge99:routable' ])
4284 output
= check_output ( 'ip -d link show bridge99' )
4286 self
. assertIn ( 'mtu 9000 ' , output
)
4288 output
= check_output ( 'ip -d link show dummy98' )
4290 self
. assertIn ( 'master bridge99 ' , output
)
4291 self
. assertIn ( 'bridge_slave' , output
)
4292 self
. assertIn ( 'mtu 9000 ' , output
)
4294 def test_bridge_configure_without_carrier ( self
):
4295 copy_network_unit ( '26-bridge.netdev' , '26-bridge-configure-without-carrier.network' ,
4299 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
4300 for test
in [ 'no-slave' , 'add-slave' , 'slave-up' , 'slave-no-carrier' , 'slave-carrier' , 'slave-down' ]:
4301 with self
. subTest ( test
= test
):
4302 if test
== 'no-slave' :
4303 # bridge has no slaves; it's up but *might* not have carrier
4304 self
. wait_operstate ( 'bridge99' , operstate
= r
'(no-carrier|routable)' , setup_state
= None , setup_timeout
= 30 )
4305 # due to a bug in the kernel, newly-created bridges are brought up
4306 # *with* carrier, unless they have had any setting changed; e.g.
4307 # their mac set, priority set, etc. Then, they will lose carrier
4308 # as soon as a (down) slave interface is added, and regain carrier
4309 # again once the slave interface is brought up.
4310 #self.check_link_attr('bridge99', 'carrier', '0')
4311 elif test
== 'add-slave' :
4312 # add slave to bridge, but leave it down; bridge is definitely no-carrier
4313 self
. check_link_attr ( 'test1' , 'operstate' , 'down' )
4314 check_output ( 'ip link set dev test1 master bridge99' )
4315 self
. wait_operstate ( 'bridge99' , operstate
= 'no-carrier' , setup_state
= None )
4316 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4317 elif test
== 'slave-up' :
4318 # bring up slave, which will have carrier; bridge gains carrier
4319 check_output ( 'ip link set dev test1 up' )
4320 self
. wait_online ([ 'bridge99:routable' ])
4321 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
4322 elif test
== 'slave-no-carrier' :
4323 # drop slave carrier; bridge loses carrier
4324 check_output ( 'ip link set dev test1 carrier off' )
4325 self
. wait_online ([ 'bridge99:no-carrier:no-carrier' ])
4326 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4327 elif test
== 'slave-carrier' :
4328 # restore slave carrier; bridge gains carrier
4329 check_output ( 'ip link set dev test1 carrier on' )
4330 self
. wait_online ([ 'bridge99:routable' ])
4331 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
4332 elif test
== 'slave-down' :
4333 # bring down slave; bridge loses carrier
4334 check_output ( 'ip link set dev test1 down' )
4335 self
. wait_online ([ 'bridge99:no-carrier:no-carrier' ])
4336 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4338 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bridge99' , env
= env
)
4339 self
. assertRegex ( output
, '10.1.2.3' )
4340 self
. assertRegex ( output
, '10.1.2.1' )
4342 def test_bridge_ignore_carrier_loss ( self
):
4343 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
4344 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
4345 '25-bridge99-ignore-carrier-loss.network' )
4347 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' ])
4349 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
4350 remove_link ( 'test1' , 'dummy98' )
4353 output
= check_output ( 'ip address show bridge99' )
4355 self
. assertRegex ( output
, 'NO-CARRIER' )
4356 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
4357 self
. assertRegex ( output
, 'inet 192.168.0.16/24 scope global secondary bridge99' )
4359 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain ( self
):
4360 copy_network_unit ( '26-bridge.netdev' , '26-bridge-slave-interface-1.network' ,
4361 '25-bridge99-ignore-carrier-loss.network' )
4363 self
. wait_online ([ 'bridge99:no-carrier' ])
4365 for trial
in range ( 4 ):
4366 check_output ( 'ip link add dummy98 type dummy' )
4367 check_output ( 'ip link set dummy98 up' )
4369 remove_link ( 'dummy98' )
4371 self
. wait_online ([ 'bridge99:routable' , 'dummy98:enslaved' ])
4373 output
= check_output ( 'ip address show bridge99' )
4375 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
4377 output
= check_output ( 'ip rule list table 100' )
4379 self
. assertIn ( 'from all to 8.8.8.8 lookup 100' , output
)
4381 class NetworkdSRIOVTests ( unittest
. TestCase
, Utilities
):
4389 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
4390 def test_sriov ( self
):
4391 copy_network_unit ( '25-default.link' , '25-sriov.network' )
4393 call ( 'modprobe netdevsim' )
4395 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4398 with
open ( '/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4402 self
. wait_online ([ 'eni99np1:routable' ])
4404 output
= check_output ( 'ip link show dev eni99np1' )
4406 self
. assertRegex ( output
,
4407 '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 *'
4408 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4409 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4412 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
4413 def test_sriov_udev ( self
):
4414 copy_network_unit ( '25-sriov.link' , '25-sriov-udev.network' )
4416 call ( 'modprobe netdevsim' )
4418 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4422 self
. wait_online ([ 'eni99np1:routable' ])
4424 # the name eni99np1 may be an alternative name.
4425 ifname
= link_resolve ( 'eni99np1' )
4427 output
= check_output ( 'ip link show dev eni99np1' )
4429 self
. assertRegex ( output
,
4430 '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 *'
4431 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4432 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4434 self
. assertNotIn ( 'vf 3' , output
)
4435 self
. assertNotIn ( 'vf 4' , output
)
4437 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4438 f
. write ( '[Link] \n SR-IOVVirtualFunctions=4 \n ' )
4441 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4443 output
= check_output ( 'ip link show dev eni99np1' )
4445 self
. assertRegex ( output
,
4446 '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 *'
4447 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4448 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
4451 self
. assertNotIn ( 'vf 4' , output
)
4453 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4454 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
4457 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4459 output
= check_output ( 'ip link show dev eni99np1' )
4461 self
. assertRegex ( output
,
4462 '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 *'
4463 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4464 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
4467 self
. assertNotIn ( 'vf 4' , output
)
4469 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4470 f
. write ( '[Link] \n SR-IOVVirtualFunctions=2 \n ' )
4473 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4475 output
= check_output ( 'ip link show dev eni99np1' )
4477 self
. assertRegex ( output
,
4478 '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 *'
4479 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off'
4481 self
. assertNotIn ( 'vf 2' , output
)
4482 self
. assertNotIn ( 'vf 3' , output
)
4483 self
. assertNotIn ( 'vf 4' , output
)
4485 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4486 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
4489 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4491 output
= check_output ( 'ip link show dev eni99np1' )
4493 self
. assertRegex ( output
,
4494 '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 *'
4495 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4496 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4498 self
. assertNotIn ( 'vf 3' , output
)
4499 self
. assertNotIn ( 'vf 4' , output
)
4501 class NetworkdLLDPTests ( unittest
. TestCase
, Utilities
):
4509 def test_lldp ( self
):
4510 copy_network_unit ( '23-emit-lldp.network' , '24-lldp.network' , '25-veth.netdev' )
4512 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:degraded' ])
4514 for trial
in range ( 10 ):
4518 output
= check_output (* networkctl_cmd
, 'lldp' , env
= env
)
4520 if re
. search ( r
'veth99 .* veth-peer' , output
):
4525 class NetworkdRATests ( unittest
. TestCase
, Utilities
):
4533 def test_ipv6_prefix_delegation ( self
):
4534 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth.network' )
4536 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4538 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth99' , env
= env
)
4540 self
. assertRegex ( output
, 'fe80::' )
4541 self
. assertRegex ( output
, '2002:da8:1::1' )
4543 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth99' , env
= env
)
4545 self
. assertIn ( 'hogehoge.test' , output
)
4547 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4549 self
. assertRegex ( output
, '2002:da8:1:0' )
4551 self
. check_netlabel ( 'veth99' , '2002:da8:1::/64' )
4552 self
. check_netlabel ( 'veth99' , '2002:da8:2::/64' )
4554 def test_ipv6_token_static ( self
):
4555 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-static.network' )
4557 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4559 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4561 self
. assertRegex ( output
, '2002:da8:1:0:1a:2b:3c:4d' )
4562 self
. assertRegex ( output
, '2002:da8:1:0:fa:de:ca:fe' )
4563 self
. assertRegex ( output
, '2002:da8:2:0:1a:2b:3c:4d' )
4564 self
. assertRegex ( output
, '2002:da8:2:0:fa:de:ca:fe' )
4566 def test_ipv6_token_prefixstable ( self
):
4567 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable.network' )
4569 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4571 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4573 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
4574 self
. assertIn ( '2002:da8:2:0:1034:56ff:fe78:9abc' , output
) # EUI64
4576 def test_ipv6_token_prefixstable_without_address ( self
):
4577 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable-without-address.network' )
4579 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4581 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4583 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
4584 self
. assertIn ( '2002:da8:2:0:f689:561a:8eda:7443' , output
)
4586 def test_router_preference ( self
):
4587 copy_network_unit ( '25-veth-client.netdev' ,
4588 '25-veth-router-high.netdev' ,
4589 '25-veth-router-low.netdev' ,
4591 '25-veth-bridge.network' ,
4592 '25-veth-client.network' ,
4593 '25-veth-router-high.network' ,
4594 '25-veth-router-low.network' ,
4595 '25-bridge99.network' )
4597 self
. wait_online ([ 'client-p:enslaved' ,
4598 'router-high:degraded' , 'router-high-p:enslaved' ,
4599 'router-low:degraded' , 'router-low-p:enslaved' ,
4600 'bridge99:routable' ])
4602 networkctl_reconfigure ( 'client' )
4603 self
. wait_online ([ 'client:routable' ])
4605 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4606 self
. wait_address ( 'client' , '2002:da8:1:98:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4607 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 512' , ipv
= '-6' , timeout_sec
= 10 )
4608 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 2048' , ipv
= '-6' , timeout_sec
= 10 )
4610 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
4612 self
. assertIn ( 'pref high' , output
)
4613 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
4615 self
. assertIn ( 'pref low' , output
)
4617 with
open ( os
. path
. join ( network_unit_dir
, '25-veth-client.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4618 f
. write ( ' \n [Link] \n MACAddress=12:34:56:78:9a:01 \n [IPv6AcceptRA] \n RouteMetric=100:200:300 \n ' )
4621 self
. wait_online ([ 'client:routable' ])
4623 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a01/64' , ipv
= '-6' , timeout_sec
= 10 )
4624 self
. wait_address ( 'client' , '2002:da8:1:98:1034:56ff:fe78:9a01/64' , ipv
= '-6' , timeout_sec
= 10 )
4625 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 100' , ipv
= '-6' , timeout_sec
= 10 )
4626 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 300' , ipv
= '-6' , timeout_sec
= 10 )
4628 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
4630 self
. assertIn ( 'pref high' , output
)
4631 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
4633 self
. assertIn ( 'pref low' , output
)
4635 @unittest . skipUnless ( radvd_check_config ( 'captive-portal.conf' ), "Installed radvd doesn't support captive portals" )
4636 def test_captive_portal ( self
):
4637 copy_network_unit ( '25-veth-client.netdev' ,
4638 '25-veth-router-captive.netdev' ,
4640 '25-veth-client-captive.network' ,
4641 '25-veth-router-captive.network' ,
4642 '25-veth-bridge-captive.network' ,
4643 '25-bridge99.network' )
4645 self
. wait_online ([ 'bridge99:routable' , 'client-p:enslaved' ,
4646 'router-captive:degraded' , 'router-captivep:enslaved' ])
4648 start_radvd ( config_file
= 'captive-portal.conf' )
4649 networkctl_reconfigure ( 'client' )
4650 self
. wait_online ([ 'client:routable' ])
4652 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4653 output
= check_output (* networkctl_cmd
, 'status' , 'client' , env
= env
)
4655 self
. assertIn ( 'Captive Portal: http://systemd.io' , output
)
4657 @unittest . skipUnless ( radvd_check_config ( 'captive-portal.conf' ), "Installed radvd doesn't support captive portals" )
4658 def test_invalid_captive_portal ( self
):
4659 def radvd_write_config ( captive_portal_uri
):
4660 with
open ( os
. path
. join ( networkd_ci_temp_dir
, 'radvd/bogus-captive-portal.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
4661 f
. write ( f
'interface router-captive {{ AdvSendAdvert on; AdvCaptivePortalAPI " {captive_portal_uri} "; prefix 2002:da8:1:99::/64 {{ AdvOnLink on; AdvAutonomous on; }}; }};' )
4663 captive_portal_uris
= [
4664 "42ěščěškd ěšč ě s" ,
4669 copy_network_unit ( '25-veth-client.netdev' ,
4670 '25-veth-router-captive.netdev' ,
4672 '25-veth-client-captive.network' ,
4673 '25-veth-router-captive.network' ,
4674 '25-veth-bridge-captive.network' ,
4675 '25-bridge99.network' )
4677 self
. wait_online ([ 'bridge99:routable' , 'client-p:enslaved' ,
4678 'router-captive:degraded' , 'router-captivep:enslaved' ])
4680 for uri
in captive_portal_uris
:
4681 print ( f
"Captive portal: {uri} " )
4682 radvd_write_config ( uri
)
4684 start_radvd ( config_file
= 'bogus-captive-portal.conf' )
4685 networkctl_reconfigure ( 'client' )
4686 self
. wait_online ([ 'client:routable' ])
4688 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4689 output
= check_output (* networkctl_cmd
, 'status' , 'client' , env
= env
)
4691 self
. assertNotIn ( 'Captive Portal:' , output
)
4693 class NetworkdDHCPServerTests ( unittest
. TestCase
, Utilities
):
4701 def test_dhcp_server ( self
):
4702 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server.network' )
4704 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4706 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4708 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4709 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
4710 self
. assertRegex ( output
, 'DNS: 192.168.5.1 \n *192.168.5.10' )
4711 self
. assertRegex ( output
, 'NTP: 192.168.5.1 \n *192.168.5.11' )
4713 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth-peer' , env
= env
)
4714 self
. assertRegex ( output
, "Offered DHCP leases: 192.168.5.[0-9]*" )
4716 def test_dhcp_server_with_uplink ( self
):
4717 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-downstream.network' ,
4718 '12-dummy.netdev' , '25-dhcp-server-uplink.network' )
4720 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4722 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4724 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4725 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
4726 self
. assertIn ( 'DNS: 192.168.5.1' , output
)
4727 self
. assertIn ( 'NTP: 192.168.5.1' , output
)
4729 def test_emit_router_timezone ( self
):
4730 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-timezone-router.network' , '25-dhcp-server-timezone-router.network' )
4732 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4734 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4736 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4737 self
. assertIn ( 'Gateway: 192.168.5.1' , output
)
4738 self
. assertIn ( 'Time Zone: Europe/Berlin' , output
)
4740 def test_dhcp_server_static_lease ( self
):
4741 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-static-lease.network' , '25-dhcp-server-static-lease.network' )
4743 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4745 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4747 self
. assertIn ( 'Address: 10.1.1.200 (DHCP4 via 10.1.1.1)' , output
)
4748 self
. assertIn ( 'DHCP4 Client ID: 12:34:56:78:9a:bc' , output
)
4750 def test_dhcp_server_static_lease_default_client_id ( self
):
4751 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-static-lease.network' )
4753 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4755 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4757 self
. assertIn ( 'Address: 10.1.1.200 (DHCP4 via 10.1.1.1)' , output
)
4758 self
. assertRegex ( output
, 'DHCP4 Client ID: IAID:[0-9a-z]*/DUID' )
4760 class NetworkdDHCPServerRelayAgentTests ( unittest
. TestCase
, Utilities
):
4768 def test_relay_agent ( self
):
4769 copy_network_unit ( '25-agent-veth-client.netdev' ,
4770 '25-agent-veth-server.netdev' ,
4771 '25-agent-client.network' ,
4772 '25-agent-server.network' ,
4773 '25-agent-client-peer.network' ,
4774 '25-agent-server-peer.network' )
4777 self
. wait_online ([ 'client:routable' ])
4779 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'client' , env
= env
)
4781 self
. assertRegex ( output
, r
'Address: 192.168.5.150 \(DHCP4 via 192.168.5.1\)' )
4783 class NetworkdDHCPClientTests ( unittest
. TestCase
, Utilities
):
4791 def test_dhcp_client_ipv6_only ( self
):
4792 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv6-only.network' )
4795 self
. wait_online ([ 'veth-peer:carrier' ])
4797 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4800 output
= check_output ( 'ip address show dev veth99 scope global' )
4802 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
4803 self
. assertNotIn ( '192.168.5' , output
)
4805 # checking semi-static route
4806 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
4808 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
4810 # Confirm that ipv6 token is not set in the kernel
4811 output
= check_output ( 'ip token show dev veth99' )
4813 self
. assertRegex ( output
, 'token :: dev veth99' )
4815 print ( '## dnsmasq log' )
4816 output
= read_dnsmasq_log_file ()
4818 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
4819 self
. assertNotIn ( 'DHCPADVERTISE(veth-peer)' , output
)
4820 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
4821 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
4822 self
. assertIn ( 'sent size: 0 option: 14 rapid-commit' , output
)
4824 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-ipv6-only.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4825 f
. write ( ' \n [DHCPv6] \n RapidCommit=no \n ' )
4831 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4834 output
= check_output ( 'ip address show dev veth99 scope global' )
4836 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
4837 self
. assertNotIn ( '192.168.5' , output
)
4839 # checking semi-static route
4840 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
4842 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
4844 print ( '## dnsmasq log' )
4845 output
= read_dnsmasq_log_file ()
4847 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
4848 self
. assertIn ( 'DHCPADVERTISE(veth-peer)' , output
)
4849 self
. assertIn ( 'DHCPREQUEST(veth-peer)' , output
)
4850 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
4851 self
. assertNotIn ( 'rapid-commit' , output
)
4853 def test_dhcp_client_ipv4_only ( self
):
4854 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv4-only.network' )
4857 self
. wait_online ([ 'veth-peer:carrier' ])
4858 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7' ,
4859 '--dhcp-option=option:domain-search,example.com' ,
4860 '--dhcp-alternate-port=67,5555' ,
4861 ipv4_range
= '192.168.5.110,192.168.5.119' )
4862 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4863 self
. wait_address ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' )
4865 print ( '## ip address show dev veth99 scope global' )
4866 output
= check_output ( 'ip address show dev veth99 scope global' )
4868 self
. assertIn ( 'mtu 1492' , output
)
4869 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
4870 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' )
4871 self
. assertNotIn ( '2600::' , output
)
4873 print ( '## ip route show table main dev veth99' )
4874 output
= check_output ( 'ip route show table main dev veth99' )
4876 # no DHCP routes assigned to the main table
4877 self
. assertNotIn ( 'proto dhcp' , output
)
4879 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
4880 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
4881 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
4882 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
4884 print ( '## ip route show table 211 dev veth99' )
4885 output
= check_output ( 'ip route show table 211 dev veth99' )
4887 self
. assertRegex ( output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.11[0-9] metric 24' )
4888 self
. assertRegex ( output
, '192.168.5.0/24 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4889 self
. assertRegex ( output
, '192.168.5.1 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4890 self
. assertRegex ( output
, '192.168.5.6 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4891 self
. assertRegex ( output
, '192.168.5.7 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4892 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
4894 print ( '## link state file' )
4895 output
= read_link_state_file ( 'veth99' )
4897 # checking DNS server and Domains
4898 self
. assertIn ( 'DNS=192.168.5.6 192.168.5.7' , output
)
4899 self
. assertIn ( 'DOMAINS=example.com' , output
)
4901 print ( '## dnsmasq log' )
4902 output
= read_dnsmasq_log_file ()
4904 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
4905 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc' , output
)
4906 self
. assertIn ( 'client provides name: test-hostname' , output
)
4907 self
. assertIn ( '26:mtu' , output
)
4909 # change address range, DNS servers, and Domains
4911 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8' ,
4912 '--dhcp-option=option:domain-search,foo.example.com' ,
4913 '--dhcp-alternate-port=67,5555' ,
4914 ipv4_range
= '192.168.5.120,192.168.5.129' ,)
4916 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4917 print ( 'Wait for the DHCP lease to be expired' )
4918 self
. wait_address_dropped ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' , timeout_sec
= 120 )
4919 self
. wait_address ( 'veth99' , r
'inet 192.168.5.12[0-9]*/24' , ipv
= '-4' )
4921 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4923 print ( '## ip address show dev veth99 scope global' )
4924 output
= check_output ( 'ip address show dev veth99 scope global' )
4926 self
. assertIn ( 'mtu 1492' , output
)
4927 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
4928 self
. assertNotIn ( '192.168.5.11' , output
)
4929 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' )
4930 self
. assertNotIn ( '2600::' , output
)
4932 print ( '## ip route show table main dev veth99' )
4933 output
= check_output ( 'ip route show table main dev veth99' )
4935 # no DHCP routes assigned to the main table
4936 self
. assertNotIn ( 'proto dhcp' , output
)
4938 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
4939 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
4940 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
4941 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
4943 print ( '## ip route show table 211 dev veth99' )
4944 output
= check_output ( 'ip route show table 211 dev veth99' )
4946 self
. assertRegex ( output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.12[0-9] metric 24' )
4947 self
. assertRegex ( output
, '192.168.5.0/24 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4948 self
. assertRegex ( output
, '192.168.5.1 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4949 self
. assertNotIn ( '192.168.5.6' , output
)
4950 self
. assertRegex ( output
, '192.168.5.7 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4951 self
. assertRegex ( output
, '192.168.5.8 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4952 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
4954 print ( '## link state file' )
4955 output
= read_link_state_file ( 'veth99' )
4957 # checking DNS server and Domains
4958 self
. assertIn ( 'DNS=192.168.5.1 192.168.5.7 192.168.5.8' , output
)
4959 self
. assertIn ( 'DOMAINS=foo.example.com' , output
)
4961 print ( '## dnsmasq log' )
4962 output
= read_dnsmasq_log_file ()
4964 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
4965 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 192.168.5.11' , output
)
4966 self
. assertIn ( 'client provides name: test-hostname' , output
)
4967 self
. assertIn ( '26:mtu' , output
)
4969 self
. check_netlabel ( 'veth99' , r
'192\.168\.5\.0/24' )
4971 def test_dhcp_client_ipv4_use_routes_gateway ( self
):
4973 for ( routes
, gateway
, dns_and_ntp_routes
, classless
) in itertools
. product ([ True , False ], repeat
= 4 ):
4979 print ( f
'### test_dhcp_client_ipv4_use_routes_gateway(routes= {routes} , gateway= {gateway} , dns_and_ntp_routes= {dns_and_ntp_routes} , classless= {classless} )' )
4980 with self
. subTest ( routes
= routes
, gateway
= gateway
, dns_and_ntp_routes
= dns_and_ntp_routes
, classless
= classless
):
4981 self
._ test
_ dhcp
_ client
_ ipv
4_u se
_ routes
_ gateway
( routes
, gateway
, dns_and_ntp_routes
, classless
)
4983 def _test_dhcp_client_ipv4_use_routes_gateway ( self
, use_routes
, use_gateway
, dns_and_ntp_routes
, classless
):
4984 testunit
= '25-dhcp-client-ipv4-use-routes-use-gateway.network'
4985 testunits
= [ '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , testunit
]
4986 testunits
. append ( f
' {testunit} .d/use-routes- {use_routes} .conf' )
4987 testunits
. append ( f
' {testunit} .d/use-gateway- {use_gateway} .conf' )
4988 testunits
. append ( f
' {testunit} .d/use-dns-and-ntp-routes- {dns_and_ntp_routes} .conf' )
4989 copy_network_unit (* testunits
, copy_dropins
= False )
4992 self
. wait_online ([ 'veth-peer:carrier' ])
4993 additional_options
= [
4994 '--dhcp-option=option:dns-server,192.168.5.10,8.8.8.8' ,
4995 '--dhcp-option=option:ntp-server,192.168.5.11,9.9.9.9' ,
4996 '--dhcp-option=option:static-route,192.168.6.100,192.168.5.2,8.8.8.8,192.168.5.3'
4999 additional_options
+= [
5000 '--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'
5002 start_dnsmasq (* additional_options
)
5003 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5005 output
= check_output ( 'ip -4 route show dev veth99' )
5011 self
. assertRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5012 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5013 self
. assertRegex ( output
, r
'192.168.5.64/26 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5014 self
. assertRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5015 self
. assertRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5017 self
. assertRegex ( output
, r
'192.168.6.0/24 via 192.168.5.2 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5018 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5019 self
. assertRegex ( output
, r
'192.168.5.2 proto dhcp scope link 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.6.0/24 via 192.168.5.2 proto dhcp 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.2 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5029 self
. assertNotRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5032 if use_gateway
and ( not classless
or not use_routes
):
5033 self
. assertRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5035 self
. assertNotRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5037 # Check route to gateway
5038 if ( use_gateway
or dns_and_ntp_routes
) and ( not classless
or not use_routes
):
5039 self
. assertRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5041 self
. assertNotRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5043 # Check RoutesToDNS= and RoutesToNTP=
5044 if dns_and_ntp_routes
:
5045 self
. assertRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5046 self
. assertRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5049 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5050 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5052 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5053 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5055 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5056 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5058 self
. assertNotRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5059 self
. assertNotRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5060 self
. assertNotRegex ( output
, r
'8.8.8.8 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
5061 self
. assertNotRegex ( output
, r
'9.9.9.9 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
5063 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5066 def test_dhcp_client_settings_anonymize ( self
):
5067 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-anonymize.network' )
5069 self
. wait_online ([ 'veth-peer:carrier' ])
5071 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5073 print ( '## dnsmasq log' )
5074 output
= read_dnsmasq_log_file ()
5076 self
. assertNotIn ( 'VendorClassIdentifier=SusantVendorTest' , output
)
5077 self
. assertNotIn ( 'test-hostname' , output
)
5078 self
. assertNotIn ( '26:mtu' , output
)
5080 def test_dhcp_keep_configuration_dhcp ( self
):
5081 copy_network_unit ( '25-veth.netdev' ,
5082 '25-dhcp-server-veth-peer.network' ,
5083 '25-dhcp-client-keep-configuration-dhcp.network' )
5085 self
. wait_online ([ 'veth-peer:carrier' ])
5087 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5089 output
= check_output ( 'ip address show dev veth99 scope global' )
5091 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5092 'valid_lft forever preferred_lft forever' )
5094 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
5097 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
5098 print ( 'Wait for the DHCP lease to be expired' )
5101 # The lease address should be kept after the lease expired
5102 output
= check_output ( 'ip address show dev veth99 scope global' )
5104 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5105 'valid_lft forever preferred_lft forever' )
5109 # The lease address should be kept after networkd stopped
5110 output
= check_output ( 'ip address show dev veth99 scope global' )
5112 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5113 'valid_lft forever preferred_lft forever' )
5115 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-keep-configuration-dhcp.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5116 f
. write ( '[Network] \n DHCP=no \n ' )
5119 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5121 # Still the lease address should be kept after networkd restarted
5122 output
= check_output ( 'ip address show dev veth99 scope global' )
5124 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5125 'valid_lft forever preferred_lft forever' )
5127 def test_dhcp_keep_configuration_dhcp_on_stop ( self
):
5128 copy_network_unit ( '25-veth.netdev' ,
5129 '25-dhcp-server-veth-peer.network' ,
5130 '25-dhcp-client-keep-configuration-dhcp-on-stop.network' )
5132 self
. wait_online ([ 'veth-peer:carrier' ])
5134 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5136 output
= check_output ( 'ip address show dev veth99 scope global' )
5138 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5143 output
= check_output ( 'ip address show dev veth99 scope global' )
5145 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5148 self
. wait_online ([ 'veth-peer:routable' ])
5150 output
= check_output ( 'ip address show dev veth99 scope global' )
5152 self
. assertNotIn ( '192.168.5.' , output
)
5154 def test_dhcp_client_reuse_address_as_static ( self
):
5155 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' )
5157 self
. wait_online ([ 'veth-peer:carrier' ])
5159 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5161 # link become 'routable' when at least one protocol provide an valid address.
5162 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5163 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5165 output
= check_output ( 'ip address show dev veth99 scope global' )
5166 ipv4_address
= re
. search ( r
'192.168.5.[0-9]*/24' , output
). group ()
5167 ipv6_address
= re
. search ( r
'2600::[0-9a-f:]*/128' , output
). group ()
5168 static_network
= ' \n ' . join ([ '[Match]' , 'Name=veth99' , '[Network]' , 'IPv6AcceptRA=no' , 'Address=' + ipv4_address
, 'Address=' + ipv6_address
])
5169 print ( static_network
)
5171 remove_network_unit ( '25-dhcp-client.network' )
5173 with
open ( os
. path
. join ( network_unit_dir
, '25-static.network' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5174 f
. write ( static_network
)
5177 self
. wait_online ([ 'veth99:routable' ])
5179 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
5181 self
. assertRegex ( output
, f
'inet {ipv4_address} brd 192.168.5.255 scope global veth99 \n *'
5182 'valid_lft forever preferred_lft forever' )
5184 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5186 self
. assertRegex ( output
, f
'inet6 {ipv6_address} scope global * \n *'
5187 'valid_lft forever preferred_lft forever' )
5189 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
5190 def test_dhcp_client_vrf ( self
):
5191 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-vrf.network' ,
5192 '25-vrf.netdev' , '25-vrf.network' )
5194 self
. wait_online ([ 'veth-peer:carrier' ])
5196 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'vrf99:carrier' ])
5198 # link become 'routable' when at least one protocol provide an valid address.
5199 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5200 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5202 print ( '## ip -d link show dev vrf99' )
5203 output
= check_output ( 'ip -d link show dev vrf99' )
5205 self
. assertRegex ( output
, 'vrf table 42' )
5207 print ( '## ip address show vrf vrf99' )
5208 output
= check_output ( 'ip address show vrf vrf99' )
5210 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5211 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5212 self
. assertRegex ( output
, 'inet6 .* scope link' )
5214 print ( '## ip address show dev veth99' )
5215 output
= check_output ( 'ip address show dev veth99' )
5217 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5218 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5219 self
. assertRegex ( output
, 'inet6 .* scope link' )
5221 print ( '## ip route show vrf vrf99' )
5222 output
= check_output ( 'ip route show vrf vrf99' )
5224 self
. assertRegex ( output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.' )
5225 self
. assertRegex ( output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5' )
5226 self
. assertRegex ( output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5' )
5228 print ( '## ip route show table main dev veth99' )
5229 output
= check_output ( 'ip route show table main dev veth99' )
5231 self
. assertEqual ( output
, '' )
5233 def test_dhcp_client_gateway_onlink_implicit ( self
):
5234 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
5235 '25-dhcp-client-gateway-onlink-implicit.network' )
5237 self
. wait_online ([ 'veth-peer:carrier' ])
5239 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5241 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
5243 self
. assertRegex ( output
, '192.168.5' )
5245 output
= check_output ( 'ip route list dev veth99 10.0.0.0/8' )
5247 self
. assertRegex ( output
, 'onlink' )
5248 output
= check_output ( 'ip route list dev veth99 192.168.100.0/24' )
5250 self
. assertRegex ( output
, 'onlink' )
5252 def test_dhcp_client_with_ipv4ll ( self
):
5253 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
5254 '25-dhcp-client-with-ipv4ll.network' )
5256 # we need to increase timeout above default, as this will need to wait for
5257 # systemd-networkd to get the dhcpv4 transient failure event
5258 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:routable' ], timeout
= '60s' )
5260 output
= check_output ( 'ip -4 address show dev veth99' )
5262 self
. assertNotIn ( '192.168.5.' , output
)
5263 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
5266 print ( 'Wait for a DHCP lease to be acquired and the IPv4LL address to be dropped' )
5267 self
. wait_address ( 'veth99' , r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic' , ipv
= '-4' )
5268 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' )
5269 self
. wait_online ([ 'veth99:routable' ])
5271 output
= check_output ( 'ip -4 address show dev veth99' )
5273 self
. assertRegex ( output
, r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99' )
5274 self
. assertNotIn ( '169.254.' , output
)
5275 self
. assertNotIn ( 'scope link' , output
)
5278 print ( 'Wait for the DHCP lease to be expired and an IPv4LL address to be acquired' )
5279 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 )
5280 self
. wait_address ( 'veth99' , r
'inet 169\.254\.133\.11/16 metric 2048 brd 169\.254\.255\.255 scope link' , scope
= 'link' , ipv
= '-4' )
5282 output
= check_output ( 'ip -4 address show dev veth99' )
5284 self
. assertNotIn ( '192.168.5.' , output
)
5285 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
5287 def test_dhcp_client_use_dns ( self
):
5288 def check ( self
, ipv4
, ipv6
):
5289 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5290 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5291 f
. write ( '[DHCPv4] \n UseDNS=' )
5292 f
. write ( 'yes' if ipv4
else 'no' )
5293 f
. write ( ' \n [DHCPv6] \n UseDNS=' )
5294 f
. write ( 'yes' if ipv6
else 'no' )
5295 f
. write ( ' \n [IPv6AcceptRA] \n UseDNS=no' )
5298 self
. wait_online ([ 'veth99:routable' ])
5300 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5301 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5302 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5304 # make resolved re-read the link state file
5305 check_output (* resolvectl_cmd
, 'revert' , 'veth99' , env
= env
)
5307 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth99' , env
= env
)
5310 self
. assertIn ( '192.168.5.1' , output
)
5312 self
. assertNotIn ( '192.168.5.1' , output
)
5314 self
. assertIn ( '2600::1' , output
)
5316 self
. assertNotIn ( '2600::1' , output
)
5318 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5321 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5324 self
. wait_online ([ 'veth-peer:carrier' ])
5325 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1' ,
5326 '--dhcp-option=option6:dns-server,[2600::1]' )
5328 check ( self
, True , True )
5329 check ( self
, True , False )
5330 check ( self
, False , True )
5331 check ( self
, False , False )
5333 def test_dhcp_client_use_captive_portal ( self
):
5334 def check ( self
, ipv4
, ipv6
):
5335 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5336 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5337 f
. write ( '[DHCPv4] \n UseCaptivePortal=' )
5338 f
. write ( 'yes' if ipv4
else 'no' )
5339 f
. write ( ' \n [DHCPv6] \n UseCaptivePortal=' )
5340 f
. write ( 'yes' if ipv6
else 'no' )
5341 f
. write ( ' \n [IPv6AcceptRA] \n UseCaptivePortal=no' )
5344 self
. wait_online ([ 'veth99:routable' ])
5346 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5347 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5348 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5350 output
= check_output (* networkctl_cmd
, 'status' , 'veth99' , env
= env
)
5353 self
. assertIn ( 'Captive Portal: http://systemd.io' , output
)
5355 self
. assertNotIn ( 'Captive Portal: http://systemd.io' , output
)
5357 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5360 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5363 self
. wait_online ([ 'veth-peer:carrier' ])
5364 start_dnsmasq ( '--dhcp-option=114,http://systemd.io' ,
5365 '--dhcp-option=option6:103,http://systemd.io' )
5367 check ( self
, True , True )
5368 check ( self
, True , False )
5369 check ( self
, False , True )
5370 check ( self
, False , False )
5372 def test_dhcp_client_reject_captive_portal ( self
):
5373 def check ( self
, ipv4
, ipv6
):
5374 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5375 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5376 f
. write ( '[DHCPv4] \n UseCaptivePortal=' )
5377 f
. write ( 'yes' if ipv4
else 'no' )
5378 f
. write ( ' \n [DHCPv6] \n UseCaptivePortal=' )
5379 f
. write ( 'yes' if ipv6
else 'no' )
5380 f
. write ( ' \n [IPv6AcceptRA] \n UseCaptivePortal=no' )
5383 self
. wait_online ([ 'veth99:routable' ])
5385 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5386 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5387 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5389 output
= check_output (* networkctl_cmd
, 'status' , 'veth99' , env
= env
)
5391 self
. assertNotIn ( 'Captive Portal: ' , output
)
5392 self
. assertNotIn ( 'invalid/url' , output
)
5394 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5397 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5400 self
. wait_online ([ 'veth-peer:carrier' ])
5401 masq
= lambda bs
: ':' . join ( f
'{b:02x}' for b
in bs
)
5402 start_dnsmasq ( '--dhcp-option=114,' + masq ( b
'http:// \x00 invalid/url' ),
5403 '--dhcp-option=option6:103,' + masq ( b
'http:// \x00 /invalid/url' ))
5405 check ( self
, True , True )
5406 check ( self
, True , False )
5407 check ( self
, False , True )
5408 check ( self
, False , False )
5410 class NetworkdDHCPPDTests ( unittest
. TestCase
, Utilities
):
5418 def test_dhcp6pd ( self
):
5419 copy_network_unit ( '25-veth.netdev' , '25-dhcp6pd-server.network' , '25-dhcp6pd-upstream.network' ,
5420 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
5421 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
5422 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
5423 '25-dhcp-pd-downstream-dummy97.network' ,
5424 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
5425 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' )
5428 self
. wait_online ([ 'veth-peer:routable' ])
5429 start_isc_dhcpd ( conf_file
= 'isc-dhcpd-dhcp6pd.conf' , ipv
= '-6' )
5430 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5431 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5433 print ( '### ip -6 address show dev veth-peer scope global' )
5434 output
= check_output ( 'ip -6 address show dev veth-peer scope global' )
5436 self
. assertIn ( 'inet6 3ffe:501:ffff:100::1/64 scope global' , output
)
5440 # dummy97: 0x01 (The link will appear later)
5442 # dummy99: auto -> 0x02 (No address assignment)
5447 print ( '### ip -6 address show dev veth99 scope global' )
5448 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5451 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:100::[0-9]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5452 # address in IA_PD (Token=static)
5453 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic' )
5454 # address in IA_PD (Token=eui64)
5455 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic' )
5456 # address in IA_PD (temporary)
5457 # Note that the temporary addresses may appear after the link enters configured state
5458 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' )
5460 print ( '### ip -6 address show dev test1 scope global' )
5461 output
= check_output ( 'ip -6 address show dev test1 scope global' )
5463 # address in IA_PD (Token=static)
5464 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5465 # address in IA_PD (temporary)
5466 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' )
5468 print ( '### ip -6 address show dev dummy98 scope global' )
5469 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5471 # address in IA_PD (Token=static)
5472 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5473 # address in IA_PD (temporary)
5474 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' )
5476 print ( '### ip -6 address show dev dummy99 scope global' )
5477 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5480 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
5482 print ( '### ip -6 address show dev veth97 scope global' )
5483 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
5485 # address in IA_PD (Token=static)
5486 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5487 # address in IA_PD (Token=eui64)
5488 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5489 # address in IA_PD (temporary)
5490 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' )
5492 print ( '### ip -6 address show dev veth97-peer scope global' )
5493 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
5495 # NDisc address (Token=static)
5496 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5497 # NDisc address (Token=eui64)
5498 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5499 # NDisc address (temporary)
5500 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' )
5502 print ( '### ip -6 address show dev veth98 scope global' )
5503 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
5505 # address in IA_PD (Token=static)
5506 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5507 # address in IA_PD (Token=eui64)
5508 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5509 # address in IA_PD (temporary)
5510 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' )
5512 print ( '### ip -6 address show dev veth98-peer scope global' )
5513 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
5515 # NDisc address (Token=static)
5516 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5517 # NDisc address (Token=eui64)
5518 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5519 # NDisc address (temporary)
5520 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' )
5522 print ( '### ip -6 route show type unreachable' )
5523 output
= check_output ( 'ip -6 route show type unreachable' )
5525 self
. assertRegex ( output
, 'unreachable 3ffe:501:ffff:[2-9a-f]00::/56 dev lo proto dhcp' )
5527 print ( '### ip -6 route show dev veth99' )
5528 output
= check_output ( 'ip -6 route show dev veth99' )
5530 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]10::/64 proto kernel metric [0-9]* expires' )
5532 print ( '### ip -6 route show dev test1' )
5533 output
= check_output ( 'ip -6 route show dev test1' )
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 dummy98' )
5538 output
= check_output ( 'ip -6 route show dev dummy98' )
5540 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5542 print ( '### ip -6 route show dev dummy99' )
5543 output
= check_output ( 'ip -6 route show dev dummy99' )
5545 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
5547 print ( '### ip -6 route show dev veth97' )
5548 output
= check_output ( 'ip -6 route show dev veth97' )
5550 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto kernel metric [0-9]* expires' )
5552 print ( '### ip -6 route show dev veth97-peer' )
5553 output
= check_output ( 'ip -6 route show dev veth97-peer' )
5555 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto ra metric [0-9]* expires' )
5557 print ( '### ip -6 route show dev veth98' )
5558 output
= check_output ( 'ip -6 route show dev veth98' )
5560 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto kernel metric [0-9]* expires' )
5562 print ( '### ip -6 route show dev veth98-peer' )
5563 output
= check_output ( 'ip -6 route show dev veth98-peer' )
5565 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto ra metric [0-9]* expires' )
5567 # Test case for a downstream which appears later
5568 check_output ( 'ip link add dummy97 type dummy' )
5569 self
. wait_online ([ 'dummy97:routable' ])
5571 print ( '### ip -6 address show dev dummy97 scope global' )
5572 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
5574 # address in IA_PD (Token=static)
5575 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5576 # address in IA_PD (temporary)
5577 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' )
5579 print ( '### ip -6 route show dev dummy97' )
5580 output
= check_output ( 'ip -6 route show dev dummy97' )
5582 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]01::/64 proto kernel metric [0-9]* expires' )
5584 # Test case for reconfigure
5585 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
5586 self
. wait_online ([ 'dummy98:routable' , 'dummy99:degraded' ])
5588 print ( '### ip -6 address show dev dummy98 scope global' )
5589 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5591 # address in IA_PD (Token=static)
5592 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5593 # address in IA_PD (temporary)
5594 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' )
5596 print ( '### ip -6 address show dev dummy99 scope global' )
5597 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5600 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
5602 print ( '### ip -6 route show dev dummy98' )
5603 output
= check_output ( 'ip -6 route show dev dummy98' )
5605 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5607 print ( '### ip -6 route show dev dummy99' )
5608 output
= check_output ( 'ip -6 route show dev dummy99' )
5610 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
5612 self
. check_netlabel ( 'dummy98' , '3ffe:501:ffff:[2-9a-f]00::/64' )
5614 def verify_dhcp4_6rd ( self
, tunnel_name
):
5615 print ( '### ip -4 address show dev veth-peer scope global' )
5616 output
= check_output ( 'ip -4 address show dev veth-peer scope global' )
5618 self
. assertIn ( 'inet 10.0.0.1/8 brd 10.255.255.255 scope global veth-peer' , output
)
5622 # dummy97: 0x01 (The link will appear later)
5624 # dummy99: auto -> 0x0[23] (No address assignment)
5625 # 6rd-XXX: auto -> 0x0[23]
5630 print ( '### ip -4 address show dev veth99 scope global' )
5631 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
5633 self
. assertRegex ( output
, 'inet 10.100.100.[0-9]*/8 (metric 1024 |)brd 10.255.255.255 scope global dynamic veth99' )
5635 print ( '### ip -6 address show dev veth99 scope global' )
5636 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5638 # address in IA_PD (Token=static)
5639 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5640 # address in IA_PD (Token=eui64)
5641 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5642 # address in IA_PD (temporary)
5643 # Note that the temporary addresses may appear after the link enters configured state
5644 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' )
5646 print ( '### ip -6 address show dev test1 scope global' )
5647 output
= check_output ( 'ip -6 address show dev test1 scope global' )
5649 # address in IA_PD (Token=static)
5650 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5651 # address in IA_PD (temporary)
5652 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' )
5654 print ( '### ip -6 address show dev dummy98 scope global' )
5655 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5657 # address in IA_PD (Token=static)
5658 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5659 # address in IA_PD (temporary)
5660 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' )
5662 print ( '### ip -6 address show dev dummy99 scope global' )
5663 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5666 self
. assertNotRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+0[23]' )
5668 print ( '### ip -6 address show dev veth97 scope global' )
5669 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
5671 # address in IA_PD (Token=static)
5672 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5673 # address in IA_PD (Token=eui64)
5674 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5675 # address in IA_PD (temporary)
5676 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' )
5678 print ( '### ip -6 address show dev veth97-peer scope global' )
5679 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
5681 # NDisc address (Token=static)
5682 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5683 # NDisc address (Token=eui64)
5684 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5685 # NDisc address (temporary)
5686 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' )
5688 print ( '### ip -6 address show dev veth98 scope global' )
5689 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
5691 # address in IA_PD (Token=static)
5692 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5693 # address in IA_PD (Token=eui64)
5694 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5695 # address in IA_PD (temporary)
5696 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' )
5698 print ( '### ip -6 address show dev veth98-peer scope global' )
5699 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
5701 # NDisc address (Token=static)
5702 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5703 # NDisc address (Token=eui64)
5704 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5705 # NDisc address (temporary)
5706 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' )
5708 print ( '### ip -6 route show type unreachable' )
5709 output
= check_output ( 'ip -6 route show type unreachable' )
5711 self
. assertRegex ( output
, 'unreachable 2001:db8:6464:[0-9a-f]+00::/56 dev lo proto dhcp' )
5713 print ( '### ip -6 route show dev veth99' )
5714 output
= check_output ( 'ip -6 route show dev veth99' )
5716 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+10::/64 proto kernel metric [0-9]* expires' )
5718 print ( '### ip -6 route show dev test1' )
5719 output
= check_output ( 'ip -6 route show dev test1' )
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 dummy98' )
5724 output
= check_output ( 'ip -6 route show dev dummy98' )
5726 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
5728 print ( '### ip -6 route show dev dummy99' )
5729 output
= check_output ( 'ip -6 route show dev dummy99' )
5731 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto dhcp metric [0-9]* expires' )
5733 print ( '### ip -6 route show dev veth97' )
5734 output
= check_output ( 'ip -6 route show dev veth97' )
5736 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto kernel metric [0-9]* expires' )
5738 print ( '### ip -6 route show dev veth97-peer' )
5739 output
= check_output ( 'ip -6 route show dev veth97-peer' )
5741 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto ra metric [0-9]* expires' )
5743 print ( '### ip -6 route show dev veth98' )
5744 output
= check_output ( 'ip -6 route show dev veth98' )
5746 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto kernel metric [0-9]* expires' )
5748 print ( '### ip -6 route show dev veth98-peer' )
5749 output
= check_output ( 'ip -6 route show dev veth98-peer' )
5751 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto ra metric [0-9]* expires' )
5753 print ( '### ip -6 address show dev dummy97 scope global' )
5754 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
5756 # address in IA_PD (Token=static)
5757 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5758 # address in IA_PD (temporary)
5759 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' )
5761 print ( '### ip -6 route show dev dummy97' )
5762 output
= check_output ( 'ip -6 route show dev dummy97' )
5764 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+01::/64 proto kernel metric [0-9]* expires' )
5766 print ( f
'### ip -d link show dev {tunnel_name} ' )
5767 output
= check_output ( f
'ip -d link show dev {tunnel_name} ' )
5769 self
. assertIn ( 'link/sit 10.100.100.' , output
)
5770 self
. assertIn ( 'local 10.100.100.' , output
)
5771 self
. assertIn ( 'ttl 64' , output
)
5772 self
. assertIn ( '6rd-prefix 2001:db8::/32' , output
)
5773 self
. assertIn ( '6rd-relay_prefix 10.0.0.0/8' , output
)
5775 print ( f
'### ip -6 address show dev {tunnel_name} ' )
5776 output
= check_output ( f
'ip -6 address show dev {tunnel_name} ' )
5778 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' )
5779 self
. assertRegex ( output
, 'inet6 ::10.100.100.[0-9]+/96 scope global' )
5781 print ( f
'### ip -6 route show dev {tunnel_name} ' )
5782 output
= check_output ( f
'ip -6 route show dev {tunnel_name} ' )
5784 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto kernel metric [0-9]* expires' )
5785 self
. assertRegex ( output
, '::/96 proto kernel metric [0-9]*' )
5787 print ( '### ip -6 route show default' )
5788 output
= check_output ( 'ip -6 route show default' )
5790 self
. assertIn ( 'default' , output
)
5791 self
. assertIn ( f
'via ::10.0.0.1 dev {tunnel_name} ' , output
)
5793 def test_dhcp4_6rd ( self
):
5794 copy_network_unit ( '25-veth.netdev' , '25-dhcp4-6rd-server.network' , '25-dhcp4-6rd-upstream.network' ,
5795 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
5796 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
5797 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
5798 '25-dhcp-pd-downstream-dummy97.network' ,
5799 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
5800 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' ,
5801 '80-6rd-tunnel.network' )
5804 self
. wait_online ([ 'veth-peer:routable' ])
5807 # 6rd-prefix: 2001:db8::/32
5808 # br-addresss: 10.0.0.1
5810 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' ,
5811 ipv4_range
= '10.100.100.100,10.100.100.200' ,
5812 ipv4_router
= '10.0.0.1' )
5813 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5814 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5816 # Test case for a downstream which appears later
5817 check_output ( 'ip link add dummy97 type dummy' )
5818 self
. wait_online ([ 'dummy97:routable' ])
5822 for name
in os
. listdir ( '/sys/class/net/' ):
5823 if name
. startswith ( '6rd-' ):
5827 self
. wait_online ([ f
' {tunnel_name} :routable' ])
5829 self
. verify_dhcp4_6rd ( tunnel_name
)
5831 # Test case for reconfigure
5832 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
5833 self
. wait_online ([ 'dummy98:routable' , 'dummy99:degraded' ])
5835 self
. verify_dhcp4_6rd ( tunnel_name
)
5837 print ( 'Wait for the DHCP lease to be renewed/rebind' )
5840 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy97:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5841 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5843 self
. verify_dhcp4_6rd ( tunnel_name
)
5845 class NetworkdIPv6PrefixTests ( unittest
. TestCase
, Utilities
):
5853 def test_ipv6_route_prefix ( self
):
5854 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client.network' , '25-ipv6ra-prefix.network' ,
5855 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
5858 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
5860 output
= check_output ( 'ip address show dev veth-peer' )
5862 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
5863 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
5864 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
5866 output
= check_output ( 'ip -6 route show dev veth-peer' )
5868 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
5869 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
5870 self
. assertNotIn ( '2001:db8:0:3::/64 proto ra' , output
)
5871 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
5872 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
5873 self
. assertNotIn ( '2001:db2:fff::/64 via ' , output
)
5875 output
= check_output ( 'ip address show dev veth99' )
5877 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
5878 self
. assertIn ( 'inet6 2001:db8:0:2:1a:2b:3c:4d' , output
)
5879 self
. assertIn ( 'inet6 2001:db8:0:2:fa:de:ca:fe' , output
)
5880 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
5882 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth-peer' , env
= env
)
5884 self
. assertRegex ( output
, '2001:db8:1:1::2' )
5886 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth-peer' , env
= env
)
5888 self
. assertIn ( 'example.com' , output
)
5890 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5893 def test_ipv6_route_prefix_deny_list ( self
):
5894 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client-deny-list.network' , '25-ipv6ra-prefix.network' ,
5895 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
5898 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
5900 output
= check_output ( 'ip address show dev veth-peer' )
5902 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
5903 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
5905 output
= check_output ( 'ip -6 route show dev veth-peer' )
5907 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
5908 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
5909 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
5910 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
5912 output
= check_output ( 'ip address show dev veth99' )
5914 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
5915 self
. assertIn ( 'inet6 2001:db8:0:2:' , output
)
5917 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth-peer' , env
= env
)
5919 self
. assertRegex ( output
, '2001:db8:1:1::2' )
5921 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth-peer' , env
= env
)
5923 self
. assertIn ( 'example.com' , output
)
5925 class NetworkdMTUTests ( unittest
. TestCase
, Utilities
):
5933 def check_mtu ( self
, mtu
, ipv6_mtu
= None , reset
= True ):
5939 self
. wait_online ([ 'dummy98:routable' ])
5940 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
5941 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
5943 # test normal restart
5945 self
. wait_online ([ 'dummy98:routable' ])
5946 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
5947 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
5950 self
. reset_check_mtu ( mtu
, ipv6_mtu
)
5952 def reset_check_mtu ( self
, mtu
, ipv6_mtu
= None ):
5953 ''' test setting mtu/ipv6_mtu with interface already up '''
5956 # note - changing the device mtu resets the ipv6 mtu
5957 check_output ( 'ip link set up mtu 1501 dev dummy98' )
5958 check_output ( 'ip link set up mtu 1500 dev dummy98' )
5959 self
. check_link_attr ( 'dummy98' , 'mtu' , '1500' )
5960 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , '1500' )
5962 self
. check_mtu ( mtu
, ipv6_mtu
, reset
= False )
5964 def test_mtu_network ( self
):
5965 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' )
5966 self
. check_mtu ( '1600' )
5968 def test_mtu_netdev ( self
):
5969 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network' , copy_dropins
= False )
5970 # note - MTU set by .netdev happens ONLY at device creation!
5971 self
. check_mtu ( '1600' , reset
= False )
5973 def test_mtu_link ( self
):
5974 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network' , copy_dropins
= False )
5975 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
5976 self
. check_mtu ( '1600' , reset
= False )
5978 def test_ipv6_mtu ( self
):
5979 ''' set ipv6 mtu without setting device mtu '''
5980 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1400.conf' )
5981 self
. check_mtu ( '1500' , '1400' )
5983 def test_ipv6_mtu_toolarge ( self
):
5984 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
5985 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5986 self
. check_mtu ( '1500' , '1500' )
5988 def test_mtu_network_ipv6_mtu ( self
):
5989 ''' set ipv6 mtu and set device mtu via network file '''
5990 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5991 self
. check_mtu ( '1600' , '1550' )
5993 def test_mtu_netdev_ipv6_mtu ( self
):
5994 ''' set ipv6 mtu and set device mtu via netdev file '''
5995 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5996 self
. check_mtu ( '1600' , '1550' , reset
= False )
5998 def test_mtu_link_ipv6_mtu ( self
):
5999 ''' set ipv6 mtu and set device mtu via link file '''
6000 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
6001 self
. check_mtu ( '1600' , '1550' , reset
= False )
6004 if __name__
== '__main__' :
6005 parser
= argparse
. ArgumentParser ()
6006 parser
. add_argument ( '--build-dir' , help = 'Path to build dir' , dest
= 'build_dir' )
6007 parser
. add_argument ( '--networkd' , help = 'Path to systemd-networkd' , dest
= 'networkd_bin' )
6008 parser
. add_argument ( '--resolved' , help = 'Path to systemd-resolved' , dest
= 'resolved_bin' )
6009 parser
. add_argument ( '--timesyncd' , help = 'Path to systemd-timesyncd' , dest
= 'timesyncd_bin' )
6010 parser
. add_argument ( '--udevd' , help = 'Path to systemd-udevd' , dest
= 'udevd_bin' )
6011 parser
. add_argument ( '--wait-online' , help = 'Path to systemd-networkd-wait-online' , dest
= 'wait_online_bin' )
6012 parser
. add_argument ( '--networkctl' , help = 'Path to networkctl' , dest
= 'networkctl_bin' )
6013 parser
. add_argument ( '--resolvectl' , help = 'Path to resolvectl' , dest
= 'resolvectl_bin' )
6014 parser
. add_argument ( '--timedatectl' , help = 'Path to timedatectl' , dest
= 'timedatectl_bin' )
6015 parser
. add_argument ( '--udevadm' , help = 'Path to udevadm' , dest
= 'udevadm_bin' )
6016 parser
. add_argument ( '--valgrind' , help = 'Enable valgrind' , dest
= 'use_valgrind' , type = bool , nargs
= '?' , const
= True , default
= use_valgrind
)
6017 parser
. add_argument ( '--debug' , help = 'Generate debugging logs' , dest
= 'enable_debug' , type = bool , nargs
= '?' , const
= True , default
= enable_debug
)
6018 parser
. add_argument ( '--asan-options' , help = 'ASAN options' , dest
= 'asan_options' )
6019 parser
. add_argument ( '--lsan-options' , help = 'LSAN options' , dest
= 'lsan_options' )
6020 parser
. add_argument ( '--ubsan-options' , help = 'UBSAN options' , dest
= 'ubsan_options' )
6021 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
)
6022 ns
, unknown_args
= parser
. parse_known_args ( namespace
= unittest
)
6025 if ns
. networkd_bin
or ns
. resolved_bin
or ns
. timesyncd_bin
or ns
. udevd_bin
or \
6026 ns
. wait_online_bin
or ns
. networkctl_bin
or ns
. resolvectl_bin
or ns
. timedatectl_bin
or ns
. udevadm_bin
:
6027 print ( 'WARNING: --networkd, --resolved, --timesyncd, --udevd, --wait-online, --networkctl, --resolvectl, --timedatectl, or --udevadm options are ignored when --build-dir is specified.' )
6028 networkd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd' )
6029 resolved_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-resolved' )
6030 timesyncd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-timesyncd' )
6031 udevd_bin
= os
. path
. join ( ns
. build_dir
, 'udevadm' )
6032 wait_online_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd-wait-online' )
6033 networkctl_bin
= os
. path
. join ( ns
. build_dir
, 'networkctl' )
6034 resolvectl_bin
= os
. path
. join ( ns
. build_dir
, 'resolvectl' )
6035 timedatectl_bin
= os
. path
. join ( ns
. build_dir
, 'timedatectl' )
6036 udevadm_bin
= os
. path
. join ( ns
. build_dir
, 'udevadm' )
6039 networkd_bin
= ns
. networkd_bin
6041 resolved_bin
= ns
. resolved_bin
6042 if ns
. timesyncd_bin
:
6043 timesyncd_bin
= ns
. timesyncd_bin
6045 udevd_bin
= ns
. udevd_bin
6046 if ns
. wait_online_bin
:
6047 wait_online_bin
= ns
. wait_online_bin
6048 if ns
. networkctl_bin
:
6049 networkctl_bin
= ns
. networkctl_bin
6050 if ns
. resolvectl_bin
:
6051 resolvectl_bin
= ns
. resolvectl_bin
6052 if ns
. timedatectl_bin
:
6053 timedatectl_bin
= ns
. timedatectl_bin
6055 udevadm_bin
= ns
. udevadm_bin
6057 use_valgrind
= ns
. use_valgrind
6058 enable_debug
= ns
. enable_debug
6059 asan_options
= ns
. asan_options
6060 lsan_options
= ns
. lsan_options
6061 ubsan_options
= ns
. ubsan_options
6062 with_coverage
= ns
. with_coverage
6065 # Do not forget the trailing space.
6066 valgrind_cmd
= 'valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all '
6068 networkctl_cmd
= valgrind_cmd
. split () + [ networkctl_bin
]
6069 resolvectl_cmd
= valgrind_cmd
. split () + [ resolvectl_bin
]
6070 timedatectl_cmd
= valgrind_cmd
. split () + [ timedatectl_bin
]
6071 udevadm_cmd
= valgrind_cmd
. split () + [ udevadm_bin
]
6072 wait_online_cmd
= valgrind_cmd
. split () + [ wait_online_bin
]
6075 env
. update ({ 'ASAN_OPTIONS' : asan_options
})
6077 env
. update ({ 'LSAN_OPTIONS' : lsan_options
})
6079 env
. update ({ 'UBSAN_OPTIONS' : ubsan_options
})
6081 env
. update ({ 'SYSTEMD_MEMPOOL' : '0' })
6083 wait_online_env
= env
. copy ()
6085 wait_online_env
. update ({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
6087 sys
. argv
[ 1 :] = unknown_args
6088 unittest
. main ( verbosity
= 3 )