]>
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' , copy_dropins
= False )
3130 self
. wait_online ([ 'dummy98:degraded' ])
3132 print ( '### ip neigh list dev dummy98' )
3133 output
= check_output ( 'ip neigh list dev dummy98' )
3135 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:02:65 PERMANENT' , output
)
3136 self
. assertIn ( '2004:da8:1::1 lladdr 00:00:5e:00:02:66 PERMANENT' , output
)
3137 self
. assertNotIn ( '2004:da8:1:0::2' , output
)
3138 self
. assertNotIn ( '192.168.10.2' , output
)
3139 self
. assertNotIn ( '00:00:5e:00:02:67' , output
)
3141 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3144 copy_network_unit ( '25-neighbor-section.network.d/override.conf' )
3146 self
. wait_online ([ 'dummy98:degraded' ])
3148 print ( '### ip neigh list dev dummy98 (after reloading)' )
3149 output
= check_output ( 'ip neigh list dev dummy98' )
3151 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:03:65 PERMANENT' , output
)
3152 self
. assertIn ( '2004:da8:1::1 lladdr 00:00:5e:00:03:66 PERMANENT' , output
)
3153 self
. assertNotIn ( '2004:da8:1:0::2' , output
)
3154 self
. assertNotIn ( '192.168.10.2' , output
)
3155 self
. assertNotIn ( '00:00:5e:00:02' , output
)
3157 def test_neighbor_reconfigure ( self
):
3158 copy_network_unit ( '25-neighbor-section.network' , '12-dummy.netdev' , copy_dropins
= False )
3160 self
. wait_online ([ 'dummy98:degraded' ])
3162 print ( '### ip neigh list dev dummy98' )
3163 output
= check_output ( 'ip neigh list dev dummy98' )
3165 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:02:65 PERMANENT' , output
)
3166 self
. assertIn ( '2004:da8:1::1 lladdr 00:00:5e:00:02:66 PERMANENT' , output
)
3168 remove_network_unit ( '25-neighbor-section.network' )
3169 copy_network_unit ( '25-neighbor-next.network' )
3171 self
. wait_online ([ 'dummy98:degraded' ])
3172 print ( '### ip neigh list dev dummy98' )
3173 output
= check_output ( 'ip neigh list dev dummy98' )
3175 self
. assertNotIn ( '00:00:5e:00:02:65' , output
)
3176 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:02:66 PERMANENT' , output
)
3177 self
. assertNotIn ( '2004:da8:1::1' , output
)
3179 def test_neighbor_gre ( self
):
3180 copy_network_unit ( '25-neighbor-ip.network' , '25-neighbor-ipv6.network' , '25-neighbor-ip-dummy.network' ,
3181 '12-dummy.netdev' , '25-gre-tunnel-remote-any.netdev' , '25-ip6gre-tunnel-remote-any.netdev' )
3183 self
. wait_online ([ 'dummy98:degraded' , 'gretun97:routable' , 'ip6gretun97:routable' ], timeout
= '40s' )
3185 output
= check_output ( 'ip neigh list dev gretun97' )
3187 self
. assertIn ( '10.0.0.22 lladdr 10.65.223.239 PERMANENT' , output
)
3188 self
. assertNotIn ( '10.0.0.23' , output
)
3190 output
= check_output ( 'ip neigh list dev ip6gretun97' )
3192 self
. assertRegex ( output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT' )
3193 self
. assertNotIn ( '2001:db8:0:f102::18' , output
)
3195 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3198 def test_link_local_addressing ( self
):
3199 copy_network_unit ( '25-link-local-addressing-yes.network' , '11-dummy.netdev' ,
3200 '25-link-local-addressing-no.network' , '12-dummy.netdev' )
3202 self
. wait_online ([ 'test1:degraded' , 'dummy98:carrier' ])
3204 output
= check_output ( 'ip address show dev test1' )
3206 self
. assertRegex ( output
, 'inet .* scope link' )
3207 self
. assertRegex ( output
, 'inet6 .* scope link' )
3209 output
= check_output ( 'ip address show dev dummy98' )
3211 self
. assertNotRegex ( output
, 'inet6* .* scope link' )
3213 # Documentation/networking/ip-sysctl.txt
3215 # addr_gen_mode - INTEGER
3216 # Defines how link-local and autoconf addresses are generated.
3218 # 0: generate address based on EUI64 (default)
3219 # 1: do no generate a link-local address, use EUI64 for addresses generated
3221 # 2: generate stable privacy addresses, using the secret from
3222 # stable_secret (RFC7217)
3223 # 3: generate stable privacy addresses, using a random secret if unset
3225 self
. check_ipv6_sysctl_attr ( 'test1' , 'stable_secret' , '0123:4567:89ab:cdef:0123:4567:89ab:cdef' )
3226 self
. check_ipv6_sysctl_attr ( 'test1' , 'addr_gen_mode' , '2' )
3227 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'addr_gen_mode' , '1' )
3229 def test_link_local_addressing_ipv6ll ( self
):
3230 copy_network_unit ( '26-link-local-addressing-ipv6.network' , '12-dummy.netdev' )
3232 self
. wait_online ([ 'dummy98:degraded' ])
3234 # An IPv6LL address exists by default.
3235 output
= check_output ( 'ip address show dev dummy98' )
3237 self
. assertRegex ( output
, 'inet6 .* scope link' )
3239 copy_network_unit ( '25-link-local-addressing-no.network' )
3241 self
. wait_online ([ 'dummy98:carrier' ])
3243 # Check if the IPv6LL address is removed.
3244 output
= check_output ( 'ip address show dev dummy98' )
3246 self
. assertNotRegex ( output
, 'inet6 .* scope link' )
3248 remove_network_unit ( '25-link-local-addressing-no.network' )
3250 self
. wait_online ([ 'dummy98:degraded' ])
3252 # Check if a new IPv6LL address is assigned.
3253 output
= check_output ( 'ip address show dev dummy98' )
3255 self
. assertRegex ( output
, 'inet6 .* scope link' )
3257 def test_sysctl ( self
):
3258 copy_networkd_conf_dropin ( '25-global-ipv6-privacy-extensions.conf' )
3259 copy_network_unit ( '25-sysctl.network' , '12-dummy.netdev' , copy_dropins
= False )
3261 self
. wait_online ([ 'dummy98:degraded' ])
3263 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
3264 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'use_tempaddr' , '1' )
3265 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'dad_transmits' , '3' )
3266 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'hop_limit' , '5' )
3267 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'proxy_ndp' , '1' )
3268 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
3269 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'proxy_arp' , '1' )
3270 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'accept_local' , '1' )
3271 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'rp_filter' , '0' )
3273 copy_network_unit ( '25-sysctl.network.d/25-ipv6-privacy-extensions.conf' )
3275 self
. wait_online ([ 'dummy98:degraded' ])
3277 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'use_tempaddr' , '2' )
3279 def test_sysctl_disable_ipv6 ( self
):
3280 copy_network_unit ( '25-sysctl-disable-ipv6.network' , '12-dummy.netdev' )
3282 print ( '## Disable ipv6' )
3283 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=1' )
3284 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=1' )
3287 self
. wait_online ([ 'dummy98:routable' ])
3289 output
= check_output ( 'ip -4 address show dummy98' )
3291 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3292 output
= check_output ( 'ip -6 address show dummy98' )
3294 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3295 self
. assertRegex ( output
, 'inet6 .* scope link' )
3296 output
= check_output ( 'ip -4 route show dev dummy98' )
3298 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3299 output
= check_output ( 'ip -6 route show default' )
3301 self
. assertRegex ( output
, 'default' )
3302 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3304 remove_link ( 'dummy98' )
3306 print ( '## Enable ipv6' )
3307 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=0' )
3308 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=0' )
3311 self
. wait_online ([ 'dummy98:routable' ])
3313 output
= check_output ( 'ip -4 address show dummy98' )
3315 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3316 output
= check_output ( 'ip -6 address show dummy98' )
3318 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3319 self
. assertRegex ( output
, 'inet6 .* scope link' )
3320 output
= check_output ( 'ip -4 route show dev dummy98' )
3322 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3323 output
= check_output ( 'ip -6 route show default' )
3325 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3327 def test_bind_carrier ( self
):
3328 copy_network_unit ( '25-bind-carrier.network' , '11-dummy.netdev' )
3331 # no bound interface.
3332 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
3333 output
= check_output ( 'ip address show test1' )
3335 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3336 self
. assertIn ( 'DOWN' , output
)
3337 self
. assertNotIn ( '192.168.10' , output
)
3339 # add one bound interface. The interface will be up.
3340 check_output ( 'ip link add dummy98 type dummy' )
3341 check_output ( 'ip link set dummy98 up' )
3342 self
. wait_online ([ 'test1:routable' ])
3343 output
= check_output ( 'ip address show test1' )
3345 self
. assertIn ( 'UP,LOWER_UP' , output
)
3346 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3348 # add another bound interface. The interface is still up.
3349 check_output ( 'ip link add dummy99 type dummy' )
3350 check_output ( 'ip link set dummy99 up' )
3351 self
. wait_operstate ( 'dummy99' , 'degraded' , setup_state
= 'unmanaged' )
3352 output
= check_output ( 'ip address show test1' )
3354 self
. assertIn ( 'UP,LOWER_UP' , output
)
3355 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3357 # remove one of the bound interfaces. The interface is still up
3358 remove_link ( 'dummy98' )
3359 output
= check_output ( 'ip address show test1' )
3361 self
. assertIn ( 'UP,LOWER_UP' , output
)
3362 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3364 # bring down the remaining bound interface. The interface will be down.
3365 check_output ( 'ip link set dummy99 down' )
3366 self
. wait_operstate ( 'test1' , 'off' )
3367 self
. wait_address_dropped ( 'test1' , r
'192.168.10' , ipv
= '-4' , timeout_sec
= 10 )
3368 output
= check_output ( 'ip address show test1' )
3370 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3371 self
. assertIn ( 'DOWN' , output
)
3372 self
. assertNotIn ( '192.168.10' , output
)
3374 # bring up the bound interface. The interface will be up.
3375 check_output ( 'ip link set dummy99 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 # remove the remaining bound interface. The interface will be down.
3383 remove_link ( 'dummy99' )
3384 self
. wait_operstate ( 'test1' , 'off' )
3385 self
. wait_address_dropped ( 'test1' , r
'192.168.10' , ipv
= '-4' , timeout_sec
= 10 )
3386 output
= check_output ( 'ip address show test1' )
3388 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3389 self
. assertIn ( 'DOWN' , output
)
3390 self
. assertNotIn ( '192.168.10' , output
)
3392 # re-add one bound interface. The interface will be up.
3393 check_output ( 'ip link add dummy98 type dummy' )
3394 check_output ( 'ip link set dummy98 up' )
3395 self
. wait_online ([ 'test1:routable' ])
3396 output
= check_output ( 'ip address show test1' )
3398 self
. assertIn ( 'UP,LOWER_UP' , output
)
3399 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3401 def _test_activation_policy ( self
, interface
, test
):
3402 conffile
= '25-activation-policy.network'
3404 conffile
= f
' {conffile} .d/ {test} .conf'
3405 if interface
== 'vlan99' :
3406 copy_network_unit ( '21-vlan.netdev' , '21-vlan-test1.network' )
3407 copy_network_unit ( '11-dummy.netdev' , conffile
, copy_dropins
= False )
3410 always
= test
. startswith ( 'always' )
3411 initial_up
= test
!= 'manual' and not test
. endswith ( 'down' ) # note: default is up
3412 expect_up
= initial_up
3413 next_up
= not expect_up
3415 if test
. endswith ( 'down' ):
3416 self
. wait_activated ( interface
)
3418 for iteration
in range ( 4 ):
3419 with self
. subTest ( iteration
= iteration
, expect_up
= expect_up
):
3420 operstate
= 'routable' if expect_up
else 'off'
3421 setup_state
= 'configured' if expect_up
else ( 'configuring' if iteration
== 0 else None )
3422 self
. wait_operstate ( interface
, operstate
, setup_state
= setup_state
, setup_timeout
= 20 )
3425 self
. assertIn ( 'UP' , check_output ( f
'ip link show {interface} ' ))
3426 self
. assertIn ( '192.168.10.30/24' , check_output ( f
'ip address show {interface} ' ))
3427 self
. assertIn ( 'default via 192.168.10.1' , check_output ( f
'ip route show dev {interface} ' ))
3429 self
. assertIn ( 'DOWN' , check_output ( f
'ip link show {interface} ' ))
3432 check_output ( f
'ip link set dev {interface} up' )
3434 check_output ( f
'ip link set dev {interface} down' )
3435 expect_up
= initial_up
if always
else next_up
3436 next_up
= not next_up
3440 def test_activation_policy ( self
):
3442 for interface
in [ 'test1' , 'vlan99' ]:
3443 for test
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , '' ]:
3449 print ( f
'### test_activation_policy(interface= {interface} , test= {test} )' )
3450 with self
. subTest ( interface
= interface
, test
= test
):
3451 self
._ test
_ activation
_ policy
( interface
, test
)
3453 def _test_activation_policy_required_for_online ( self
, policy
, required
):
3454 conffile
= '25-activation-policy.network'
3455 units
= [ '11-dummy.netdev' , '12-dummy.netdev' , '12-dummy.network' , conffile
]
3457 units
+= [ f
' {conffile} .d/ {policy} .conf' ]
3459 units
+= [ f
' {conffile} .d/required- {required} .conf' ]
3460 copy_network_unit (* units
, copy_dropins
= False )
3463 if policy
. endswith ( 'down' ):
3464 self
. wait_activated ( 'test1' )
3466 if policy
. endswith ( 'down' ) or policy
== 'manual' :
3467 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
3469 self
. wait_online ([ 'test1' ])
3471 if policy
== 'always-down' :
3472 # if always-down, required for online is forced to no
3475 # otherwise if required for online is specified, it should match that
3476 expected
= required
== 'yes'
3478 # otherwise if only policy specified, required for online defaults to
3479 # true if policy is up, always-up, or bound
3480 expected
= policy
. endswith ( 'up' ) or policy
== 'bound'
3482 # default is true, if neither are specified
3485 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
3488 yesno
= 'yes' if expected
else 'no'
3489 self
. assertRegex ( output
, f
'Required For Online: {yesno} ' )
3491 def test_activation_policy_required_for_online ( self
):
3493 for policy
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , 'bound' , '' ]:
3494 for required
in [ 'yes' , 'no' , '' ]:
3500 print ( f
'### test_activation_policy_required_for_online(policy= {policy} , required= {required} )' )
3501 with self
. subTest ( policy
= policy
, required
= required
):
3502 self
._ test
_ activation
_ policy
_ required
_ for
_ online
( policy
, required
)
3504 def test_domain ( self
):
3505 copy_network_unit ( '12-dummy.netdev' , '24-search-domain.network' )
3507 self
. wait_online ([ 'dummy98:routable' ])
3509 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
3511 self
. assertRegex ( output
, 'Address: 192.168.42.100' )
3512 self
. assertRegex ( output
, 'DNS: 192.168.42.1' )
3513 self
. assertRegex ( output
, 'Search Domains: one' )
3515 def test_keep_configuration_static ( self
):
3516 check_output ( 'ip link add name dummy98 type dummy' )
3517 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
3518 check_output ( 'ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500' )
3519 output
= check_output ( 'ip address show dummy98' )
3521 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
3522 self
. assertRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
3523 output
= check_output ( 'ip route show dev dummy98' )
3526 copy_network_unit ( '24-keep-configuration-static.network' )
3528 self
. wait_online ([ 'dummy98:routable' ])
3530 output
= check_output ( 'ip address show dummy98' )
3532 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
3533 self
. assertNotRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
3535 @expectedFailureIfNexthopIsNotAvailable ()
3536 def test_nexthop ( self
):
3537 def check_nexthop ( self
):
3538 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
3540 output
= check_output ( 'ip nexthop list dev veth99' )
3542 self
. assertIn ( 'id 1 via 192.168.5.1 dev veth99' , output
)
3543 self
. assertIn ( 'id 2 via 2001:1234:5:8f63::2 dev veth99' , output
)
3544 self
. assertIn ( 'id 3 dev veth99' , output
)
3545 self
. assertIn ( 'id 4 dev veth99' , output
)
3546 self
. assertRegex ( output
, 'id 5 via 192.168.10.1 dev veth99 .*onlink' )
3547 self
. assertIn ( 'id 8 via fe80:0:222:4dff:ff:ff:ff:ff dev veth99' , output
)
3548 self
. assertRegex ( output
, r
'id [0-9]* via 192.168.5.2 dev veth99' )
3550 output
= check_output ( 'ip nexthop list dev dummy98' )
3552 self
. assertIn ( 'id 20 via 192.168.20.1 dev dummy98' , output
)
3554 # kernel manages blackhole nexthops on lo
3555 output
= check_output ( 'ip nexthop list dev lo' )
3557 self
. assertIn ( 'id 6 blackhole' , output
)
3558 self
. assertIn ( 'id 7 blackhole' , output
)
3560 # group nexthops are shown with -0 option
3561 output
= check_output ( 'ip -0 nexthop list id 21' )
3563 self
. assertRegex ( output
, r
'id 21 group (1,3/20|20/1,3)' )
3565 output
= check_output ( 'ip route show dev veth99 10.10.10.10' )
3567 self
. assertEqual ( '10.10.10.10 nhid 1 via 192.168.5.1 proto static' , output
)
3569 output
= check_output ( 'ip route show dev veth99 10.10.10.11' )
3571 self
. assertEqual ( '10.10.10.11 nhid 2 via inet6 2001:1234:5:8f63::2 proto static' , output
)
3573 output
= check_output ( 'ip route show dev veth99 10.10.10.12' )
3575 self
. assertEqual ( '10.10.10.12 nhid 5 via 192.168.10.1 proto static onlink' , output
)
3577 output
= check_output ( 'ip -6 route show dev veth99 2001:1234:5:8f62::1' )
3579 self
. assertEqual ( '2001:1234:5:8f62::1 nhid 2 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium' , output
)
3581 output
= check_output ( 'ip route show 10.10.10.13' )
3583 self
. assertEqual ( 'blackhole 10.10.10.13 nhid 6 dev lo proto static' , output
)
3585 output
= check_output ( 'ip -6 route show 2001:1234:5:8f62::2' )
3587 self
. assertEqual ( 'blackhole 2001:1234:5:8f62::2 nhid 7 dev lo proto static metric 1024 pref medium' , output
)
3589 output
= check_output ( 'ip route show 10.10.10.14' )
3591 self
. assertIn ( '10.10.10.14 nhid 21 proto static' , output
)
3592 self
. assertIn ( 'nexthop via 192.168.20.1 dev dummy98 weight 1' , output
)
3593 self
. assertIn ( 'nexthop via 192.168.5.1 dev veth99 weight 3' , output
)
3595 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3598 copy_network_unit ( '25-nexthop.network' , '25-veth.netdev' , '25-veth-peer.network' ,
3599 '12-dummy.netdev' , '25-nexthop-dummy.network' )
3604 remove_network_unit ( '25-nexthop.network' )
3605 copy_network_unit ( '25-nexthop-nothing.network' )
3607 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
3609 output
= check_output ( 'ip nexthop list dev veth99' )
3611 self
. assertEqual ( output
, '' )
3612 output
= check_output ( 'ip nexthop list dev lo' )
3614 self
. assertEqual ( output
, '' )
3616 remove_network_unit ( '25-nexthop-nothing.network' )
3617 copy_network_unit ( '25-nexthop.network' )
3618 networkctl_reconfigure ( 'dummy98' )
3623 remove_link ( 'veth99' )
3626 output
= check_output ( 'ip nexthop list dev lo' )
3628 self
. assertEqual ( output
, '' )
3630 class NetworkdTCTests ( unittest
. TestCase
, Utilities
):
3638 @expectedFailureIfModuleIsNotAvailable ( 'sch_cake' )
3639 def test_qdisc_cake ( self
):
3640 copy_network_unit ( '25-qdisc-cake.network' , '12-dummy.netdev' )
3642 self
. wait_online ([ 'dummy98:routable' ])
3644 output
= check_output ( 'tc qdisc show dev dummy98' )
3646 self
. assertIn ( 'qdisc cake 3a: root' , output
)
3647 self
. assertIn ( 'bandwidth 500Mbit' , output
)
3648 self
. assertIn ( 'autorate-ingress' , output
)
3649 self
. assertIn ( 'diffserv8' , output
)
3650 self
. assertIn ( 'dual-dsthost' , output
)
3651 self
. assertIn ( ' nat' , output
)
3652 self
. assertIn ( ' wash' , output
)
3653 self
. assertIn ( ' split-gso' , output
)
3654 self
. assertIn ( ' raw' , output
)
3655 self
. assertIn ( ' atm' , output
)
3656 self
. assertIn ( 'overhead 128' , output
)
3657 self
. assertIn ( 'mpu 20' , output
)
3658 self
. assertIn ( 'fwmark 0xff00' , output
)
3659 self
. assertIn ( 'rtt 1s' , output
)
3660 self
. assertIn ( 'ack-filter-aggressive' , output
)
3662 @expectedFailureIfModuleIsNotAvailable ( 'sch_codel' )
3663 def test_qdisc_codel ( self
):
3664 copy_network_unit ( '25-qdisc-codel.network' , '12-dummy.netdev' )
3666 self
. wait_online ([ 'dummy98:routable' ])
3668 output
= check_output ( 'tc qdisc show dev dummy98' )
3670 self
. assertRegex ( output
, 'qdisc codel 33: root' )
3671 self
. assertRegex ( output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn' )
3673 @expectedFailureIfModuleIsNotAvailable ( 'sch_drr' )
3674 def test_qdisc_drr ( self
):
3675 copy_network_unit ( '25-qdisc-drr.network' , '12-dummy.netdev' )
3677 self
. wait_online ([ 'dummy98:routable' ])
3679 output
= check_output ( 'tc qdisc show dev dummy98' )
3681 self
. assertRegex ( output
, 'qdisc drr 2: root' )
3682 output
= check_output ( 'tc class show dev dummy98' )
3684 self
. assertRegex ( output
, 'class drr 2:30 root quantum 2000b' )
3686 @expectedFailureIfModuleIsNotAvailable ( 'sch_ets' )
3687 def test_qdisc_ets ( self
):
3688 copy_network_unit ( '25-qdisc-ets.network' , '12-dummy.netdev' )
3690 self
. wait_online ([ 'dummy98:routable' ])
3692 output
= check_output ( 'tc qdisc show dev dummy98' )
3695 self
. assertRegex ( output
, 'qdisc ets 3a: root' )
3696 self
. assertRegex ( output
, 'bands 10 strict 3' )
3697 self
. assertRegex ( output
, 'quanta 1 2 3 4 5' )
3698 self
. assertRegex ( output
, 'priomap 3 4 5 6 7' )
3700 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq' )
3701 def test_qdisc_fq ( self
):
3702 copy_network_unit ( '25-qdisc-fq.network' , '12-dummy.netdev' )
3704 self
. wait_online ([ 'dummy98:routable' ])
3706 output
= check_output ( 'tc qdisc show dev dummy98' )
3708 self
. assertRegex ( output
, 'qdisc fq 32: root' )
3709 self
. assertRegex ( output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511' )
3710 self
. assertRegex ( output
, 'quantum 1500' )
3711 self
. assertRegex ( output
, 'initial_quantum 13000' )
3712 self
. assertRegex ( output
, 'maxrate 1Mbit' )
3714 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_codel' )
3715 def test_qdisc_fq_codel ( self
):
3716 copy_network_unit ( '25-qdisc-fq_codel.network' , '12-dummy.netdev' )
3718 self
. wait_online ([ 'dummy98:routable' ])
3720 output
= check_output ( 'tc qdisc show dev dummy98' )
3722 self
. assertRegex ( output
, 'qdisc fq_codel 34: root' )
3723 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' )
3725 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_pie' )
3726 def test_qdisc_fq_pie ( self
):
3727 copy_network_unit ( '25-qdisc-fq_pie.network' , '12-dummy.netdev' )
3729 self
. wait_online ([ 'dummy98:routable' ])
3731 output
= check_output ( 'tc qdisc show dev dummy98' )
3734 self
. assertRegex ( output
, 'qdisc fq_pie 3a: root' )
3735 self
. assertRegex ( output
, 'limit 200000p' )
3737 @expectedFailureIfModuleIsNotAvailable ( 'sch_gred' )
3738 def test_qdisc_gred ( self
):
3739 copy_network_unit ( '25-qdisc-gred.network' , '12-dummy.netdev' )
3741 self
. wait_online ([ 'dummy98:routable' ])
3743 output
= check_output ( 'tc qdisc show dev dummy98' )
3745 self
. assertRegex ( output
, 'qdisc gred 38: root' )
3746 self
. assertRegex ( output
, 'vqs 12 default 10 grio' )
3748 @expectedFailureIfModuleIsNotAvailable ( 'sch_hhf' )
3749 def test_qdisc_hhf ( self
):
3750 copy_network_unit ( '25-qdisc-hhf.network' , '12-dummy.netdev' )
3752 self
. wait_online ([ 'dummy98:routable' ])
3754 output
= check_output ( 'tc qdisc show dev dummy98' )
3756 self
. assertRegex ( output
, 'qdisc hhf 3a: root' )
3757 self
. assertRegex ( output
, 'limit 1022p' )
3759 @expectedFailureIfModuleIsNotAvailable ( 'sch_htb' )
3760 def test_qdisc_htb_fifo ( self
):
3761 copy_network_unit ( '25-qdisc-htb-fifo.network' , '12-dummy.netdev' )
3763 self
. wait_online ([ 'dummy98:routable' ])
3765 output
= check_output ( 'tc qdisc show dev dummy98' )
3767 self
. assertRegex ( output
, 'qdisc htb 2: root' )
3768 self
. assertRegex ( output
, r
'default (0x30|30)' )
3770 self
. assertRegex ( output
, 'qdisc pfifo 37: parent 2:37' )
3771 self
. assertRegex ( output
, 'limit 100000p' )
3773 self
. assertRegex ( output
, 'qdisc bfifo 3a: parent 2:3a' )
3774 self
. assertRegex ( output
, 'limit 1000000' )
3776 self
. assertRegex ( output
, 'qdisc pfifo_head_drop 3b: parent 2:3b' )
3777 self
. assertRegex ( output
, 'limit 1023p' )
3779 self
. assertRegex ( output
, 'qdisc pfifo_fast 3c: parent 2:3c' )
3781 output
= check_output ( 'tc -d class show dev dummy98' )
3783 # Here (:|prio) is a workaround for a bug in iproute2 v6.2.0 caused by
3784 # https://github.com/shemminger/iproute2/commit/010a8388aea11e767ba3a2506728b9ad9760df0e
3785 # which is fixed in v6.3.0 by
3786 # https://github.com/shemminger/iproute2/commit/4e0e56e0ef05387f7f5d8ab41fe6ec6a1897b26d
3787 self
. assertRegex ( output
, 'class htb 2:37 root leaf 37(:|prio) ' )
3788 self
. assertRegex ( output
, 'class htb 2:3a root leaf 3a(:|prio) ' )
3789 self
. assertRegex ( output
, 'class htb 2:3b root leaf 3b(:|prio) ' )
3790 self
. assertRegex ( output
, 'class htb 2:3c root leaf 3c(:|prio) ' )
3791 self
. assertRegex ( output
, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit' )
3792 self
. assertRegex ( output
, 'burst 123456' )
3793 self
. assertRegex ( output
, 'cburst 123457' )
3795 @expectedFailureIfModuleIsNotAvailable ( 'sch_ingress' )
3796 def test_qdisc_ingress ( self
):
3797 copy_network_unit ( '25-qdisc-clsact.network' , '12-dummy.netdev' ,
3798 '25-qdisc-ingress.network' , '11-dummy.netdev' )
3800 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' ])
3802 output
= check_output ( 'tc qdisc show dev dummy98' )
3804 self
. assertRegex ( output
, 'qdisc clsact' )
3806 output
= check_output ( 'tc qdisc show dev test1' )
3808 self
. assertRegex ( output
, 'qdisc ingress' )
3810 @expectedFailureIfModuleIsNotAvailable ( 'sch_netem' )
3811 def test_qdisc_netem ( self
):
3812 copy_network_unit ( '25-qdisc-netem.network' , '12-dummy.netdev' ,
3813 '25-qdisc-netem-compat.network' , '11-dummy.netdev' )
3815 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' ])
3817 output
= check_output ( 'tc qdisc show dev dummy98' )
3819 self
. assertRegex ( output
, 'qdisc netem 30: root' )
3820 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
3822 output
= check_output ( 'tc qdisc show dev test1' )
3824 self
. assertRegex ( output
, 'qdisc netem [0-9a-f]*: root' )
3825 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
3827 @expectedFailureIfModuleIsNotAvailable ( 'sch_pie' )
3828 def test_qdisc_pie ( self
):
3829 copy_network_unit ( '25-qdisc-pie.network' , '12-dummy.netdev' )
3831 self
. wait_online ([ 'dummy98:routable' ])
3833 output
= check_output ( 'tc qdisc show dev dummy98' )
3835 self
. assertRegex ( output
, 'qdisc pie 3a: root' )
3836 self
. assertRegex ( output
, 'limit 200000' )
3838 @expectedFailureIfModuleIsNotAvailable ( 'sch_qfq' )
3839 def test_qdisc_qfq ( self
):
3840 copy_network_unit ( '25-qdisc-qfq.network' , '12-dummy.netdev' )
3842 self
. wait_online ([ 'dummy98:routable' ])
3844 output
= check_output ( 'tc qdisc show dev dummy98' )
3846 self
. assertRegex ( output
, 'qdisc qfq 2: root' )
3847 output
= check_output ( 'tc class show dev dummy98' )
3849 self
. assertRegex ( output
, 'class qfq 2:30 root weight 2 maxpkt 16000' )
3850 self
. assertRegex ( output
, 'class qfq 2:31 root weight 10 maxpkt 8000' )
3852 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfb' )
3853 def test_qdisc_sfb ( self
):
3854 copy_network_unit ( '25-qdisc-sfb.network' , '12-dummy.netdev' )
3856 self
. wait_online ([ 'dummy98:routable' ])
3858 output
= check_output ( 'tc qdisc show dev dummy98' )
3860 self
. assertRegex ( output
, 'qdisc sfb 39: root' )
3861 self
. assertRegex ( output
, 'limit 200000' )
3863 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfq' )
3864 def test_qdisc_sfq ( self
):
3865 copy_network_unit ( '25-qdisc-sfq.network' , '12-dummy.netdev' )
3867 self
. wait_online ([ 'dummy98:routable' ])
3869 output
= check_output ( 'tc qdisc show dev dummy98' )
3871 self
. assertRegex ( output
, 'qdisc sfq 36: root' )
3872 self
. assertRegex ( output
, 'perturb 5sec' )
3874 @expectedFailureIfModuleIsNotAvailable ( 'sch_tbf' )
3875 def test_qdisc_tbf ( self
):
3876 copy_network_unit ( '25-qdisc-tbf.network' , '12-dummy.netdev' )
3878 self
. wait_online ([ 'dummy98:routable' ])
3880 output
= check_output ( 'tc qdisc show dev dummy98' )
3882 self
. assertRegex ( output
, 'qdisc tbf 35: root' )
3883 self
. assertRegex ( output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms' )
3885 @expectedFailureIfModuleIsNotAvailable ( 'sch_teql' )
3886 def test_qdisc_teql ( self
):
3887 call_quiet ( 'rmmod sch_teql' )
3889 copy_network_unit ( '25-qdisc-teql.network' , '12-dummy.netdev' )
3891 self
. wait_links ( 'dummy98' )
3892 check_output ( 'modprobe sch_teql max_equalizers=2' )
3893 self
. wait_online ([ 'dummy98:routable' ])
3895 output
= check_output ( 'tc qdisc show dev dummy98' )
3897 self
. assertRegex ( output
, 'qdisc teql1 31: root' )
3899 class NetworkdStateFileTests ( unittest
. TestCase
, Utilities
):
3907 def test_state_file ( self
):
3908 copy_network_unit ( '12-dummy.netdev' , '25-state-file-tests.network' )
3910 self
. wait_online ([ 'dummy98:routable' ])
3912 # make link state file updated
3913 check_output (* resolvectl_cmd
, 'revert' , 'dummy98' , env
= env
)
3915 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3918 output
= read_link_state_file ( 'dummy98' )
3920 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
3921 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
3922 self
. assertIn ( 'ADMIN_STATE=configured' , output
)
3923 self
. assertIn ( 'OPER_STATE=routable' , output
)
3924 self
. assertIn ( 'REQUIRED_FOR_ONLINE=yes' , output
)
3925 self
. assertIn ( 'REQUIRED_OPER_STATE_FOR_ONLINE=routable' , output
)
3926 self
. assertIn ( 'REQUIRED_FAMILY_FOR_ONLINE=both' , output
)
3927 self
. assertIn ( 'ACTIVATION_POLICY=up' , output
)
3928 self
. assertIn ( 'NETWORK_FILE=/run/systemd/network/25-state-file-tests.network' , output
)
3929 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
3930 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
3931 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
3932 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
3933 self
. assertIn ( 'LLMNR=no' , output
)
3934 self
. assertIn ( 'MDNS=yes' , output
)
3935 self
. assertIn ( 'DNSSEC=no' , output
)
3937 check_output (* resolvectl_cmd
, 'dns' , 'dummy98' , '10.10.10.12#ccc.com' , '10.10.10.13' , '1111:2222::3333' , env
= env
)
3938 check_output (* resolvectl_cmd
, 'domain' , 'dummy98' , 'hogehogehoge' , '~foofoofoo' , env
= env
)
3939 check_output (* resolvectl_cmd
, 'llmnr' , 'dummy98' , 'yes' , env
= env
)
3940 check_output (* resolvectl_cmd
, 'mdns' , 'dummy98' , 'no' , env
= env
)
3941 check_output (* resolvectl_cmd
, 'dnssec' , 'dummy98' , 'yes' , env
= env
)
3942 check_output (* timedatectl_cmd
, 'ntp-servers' , 'dummy98' , '2.fedora.pool.ntp.org' , '3.fedora.pool.ntp.org' , env
= env
)
3944 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3947 output
= read_link_state_file ( 'dummy98' )
3949 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
3950 self
. assertIn ( 'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org' , output
)
3951 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
3952 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
3953 self
. assertIn ( 'LLMNR=yes' , output
)
3954 self
. assertIn ( 'MDNS=no' , output
)
3955 self
. assertIn ( 'DNSSEC=yes' , output
)
3957 check_output (* timedatectl_cmd
, 'revert' , 'dummy98' , env
= env
)
3959 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3962 output
= read_link_state_file ( 'dummy98' )
3964 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
3965 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
3966 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
3967 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
3968 self
. assertIn ( 'LLMNR=yes' , output
)
3969 self
. assertIn ( 'MDNS=no' , output
)
3970 self
. assertIn ( 'DNSSEC=yes' , output
)
3972 check_output (* resolvectl_cmd
, 'revert' , 'dummy98' , env
= env
)
3974 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3977 output
= read_link_state_file ( 'dummy98' )
3979 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
3980 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
3981 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
3982 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
3983 self
. assertIn ( 'LLMNR=no' , output
)
3984 self
. assertIn ( 'MDNS=yes' , output
)
3985 self
. assertIn ( 'DNSSEC=no' , output
)
3987 def test_address_state ( self
):
3988 copy_network_unit ( '12-dummy.netdev' , '12-dummy-no-address.network' )
3991 self
. wait_online ([ 'dummy98:degraded' ])
3993 output
= read_link_state_file ( 'dummy98' )
3994 self
. assertIn ( 'IPV4_ADDRESS_STATE=off' , output
)
3995 self
. assertIn ( 'IPV6_ADDRESS_STATE=degraded' , output
)
3997 # with a routable IPv4 address
3998 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
3999 self
. wait_online ([ 'dummy98:routable' ], ipv4
= True )
4000 self
. wait_online ([ 'dummy98:routable' ])
4002 output
= read_link_state_file ( 'dummy98' )
4003 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
4004 self
. assertIn ( 'IPV6_ADDRESS_STATE=degraded' , output
)
4006 check_output ( 'ip address del 10.1.2.3/16 dev dummy98' )
4008 # with a routable IPv6 address
4009 check_output ( 'ip address add 2002:da8:1:0:1034:56ff:fe78:9abc/64 dev dummy98' )
4010 self
. wait_online ([ 'dummy98:routable' ], ipv6
= True )
4011 self
. wait_online ([ 'dummy98:routable' ])
4013 output
= read_link_state_file ( 'dummy98' )
4014 self
. assertIn ( 'IPV4_ADDRESS_STATE=off' , output
)
4015 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
4017 class NetworkdBondTests ( unittest
. TestCase
, Utilities
):
4025 def test_bond_keep_master ( self
):
4026 check_output ( 'ip link add bond199 type bond mode active-backup' )
4027 check_output ( 'ip link add dummy98 type dummy' )
4028 check_output ( 'ip link set dummy98 master bond199' )
4030 copy_network_unit ( '23-keep-master.network' )
4032 self
. wait_online ([ 'dummy98:enslaved' ])
4034 output
= check_output ( 'ip -d link show bond199' )
4036 self
. assertRegex ( output
, 'active_slave dummy98' )
4038 output
= check_output ( 'ip -d link show dummy98' )
4040 self
. assertRegex ( output
, 'master bond199' )
4042 def test_bond_active_slave ( self
):
4043 copy_network_unit ( '23-active-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
4045 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
4047 output
= check_output ( 'ip -d link show bond199' )
4049 self
. assertIn ( 'active_slave dummy98' , output
)
4051 def test_bond_primary_slave ( self
):
4052 copy_network_unit ( '23-primary-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
4054 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
4056 output
= check_output ( 'ip -d link show bond199' )
4058 self
. assertIn ( 'primary dummy98' , output
)
4061 mkdir_p ( os
. path
. join ( network_unit_dir
, '23-bond199.network.d' ))
4062 for mac
in [ '00:11:22:33:44:55' , '00:11:22:33:44:56' ]:
4063 with
open ( os
. path
. join ( network_unit_dir
, '23-bond199.network.d/mac.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
4064 f
. write ( f
'[Link] \n MACAddress= {mac} \n ' )
4067 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
4069 output
= check_output ( 'ip -d link show bond199' )
4071 self
. assertIn ( f
'link/ether {mac} ' , output
)
4073 def test_bond_operstate ( self
):
4074 copy_network_unit ( '25-bond.netdev' , '11-dummy.netdev' , '12-dummy.netdev' ,
4075 '25-bond99.network' , '25-bond-slave.network' )
4077 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bond99:routable' ])
4079 output
= check_output ( 'ip -d link show dummy98' )
4081 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
4083 output
= check_output ( 'ip -d link show test1' )
4085 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
4087 output
= check_output ( 'ip -d link show bond99' )
4089 self
. assertRegex ( output
, 'MASTER,UP,LOWER_UP' )
4091 self
. wait_operstate ( 'dummy98' , 'enslaved' )
4092 self
. wait_operstate ( 'test1' , 'enslaved' )
4093 self
. wait_operstate ( 'bond99' , 'routable' )
4095 check_output ( 'ip link set dummy98 down' )
4097 self
. wait_operstate ( 'dummy98' , 'off' )
4098 self
. wait_operstate ( 'test1' , 'enslaved' )
4099 self
. wait_operstate ( 'bond99' , 'routable' )
4101 check_output ( 'ip link set dummy98 up' )
4103 self
. wait_operstate ( 'dummy98' , 'enslaved' )
4104 self
. wait_operstate ( 'test1' , 'enslaved' )
4105 self
. wait_operstate ( 'bond99' , 'routable' )
4107 check_output ( 'ip link set dummy98 down' )
4108 check_output ( 'ip link set test1 down' )
4110 self
. wait_operstate ( 'dummy98' , 'off' )
4111 self
. wait_operstate ( 'test1' , 'off' )
4113 if not self
. wait_operstate ( 'bond99' , 'no-carrier' , setup_timeout
= 30 , fail_assert
= False ):
4114 # Huh? Kernel does not recognize that all slave interfaces are down?
4115 # Let's confirm that networkd's operstate is consistent with ip's result.
4116 self
. assertNotRegex ( output
, 'NO-CARRIER' )
4118 class NetworkdBridgeTests ( unittest
. TestCase
, Utilities
):
4126 def test_bridge_vlan ( self
):
4127 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave.network' ,
4128 '26-bridge.netdev' , '26-bridge-vlan-master.network' )
4130 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' ])
4132 output
= check_output ( 'bridge vlan show dev test1' )
4134 self
. assertNotRegex ( output
, '4063' )
4135 for i
in range ( 4064 , 4095 ):
4136 self
. assertRegex ( output
, f
' {i} ' )
4137 self
. assertNotRegex ( output
, '4095' )
4139 output
= check_output ( 'bridge vlan show dev bridge99' )
4141 self
. assertNotRegex ( output
, '4059' )
4142 for i
in range ( 4060 , 4095 ):
4143 self
. assertRegex ( output
, f
' {i} ' )
4144 self
. assertNotRegex ( output
, '4095' )
4146 def test_bridge_vlan_issue_20373 ( self
):
4147 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave-issue-20373.network' ,
4148 '26-bridge-issue-20373.netdev' , '26-bridge-vlan-master-issue-20373.network' ,
4149 '21-vlan.netdev' , '21-vlan.network' )
4151 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' , 'vlan99:routable' ])
4153 output
= check_output ( 'bridge vlan show dev test1' )
4155 self
. assertIn ( '100 PVID Egress Untagged' , output
)
4156 self
. assertIn ( '560' , output
)
4157 self
. assertIn ( '600' , output
)
4159 output
= check_output ( 'bridge vlan show dev bridge99' )
4161 self
. assertIn ( '1 PVID Egress Untagged' , output
)
4162 self
. assertIn ( '100' , output
)
4163 self
. assertIn ( '600' , output
)
4165 def test_bridge_mdb ( self
):
4166 copy_network_unit ( '11-dummy.netdev' , '26-bridge-mdb-slave.network' ,
4167 '26-bridge.netdev' , '26-bridge-mdb-master.network' )
4169 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' ])
4171 output
= check_output ( 'bridge mdb show dev bridge99' )
4173 self
. assertRegex ( output
, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064' )
4174 self
. assertRegex ( output
, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065' )
4176 # Old kernel may not support bridge MDB entries on bridge master
4177 if call_quiet ( 'bridge mdb add dev bridge99 port bridge99 grp 224.0.1.3 temp vid 4068' ) == 0 :
4178 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp ff02:aaaa:fee5::1:4 temp *vid 4066' )
4179 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp 224.0.1.2 temp *vid 4067' )
4181 def test_bridge_keep_master ( self
):
4182 check_output ( 'ip link add bridge99 type bridge' )
4183 check_output ( 'ip link set bridge99 up' )
4184 check_output ( 'ip link add dummy98 type dummy' )
4185 check_output ( 'ip link set dummy98 master bridge99' )
4187 copy_network_unit ( '23-keep-master.network' )
4189 self
. wait_online ([ 'dummy98:enslaved' ])
4191 output
= check_output ( 'ip -d link show dummy98' )
4193 self
. assertRegex ( output
, 'master bridge99' )
4194 self
. assertRegex ( output
, 'bridge' )
4196 output
= check_output ( 'bridge -d link show dummy98' )
4198 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
4199 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
4200 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
4201 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
4202 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
4203 # CONFIG_BRIDGE_IGMP_SNOOPING=y
4204 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
4205 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
4206 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
4207 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
4208 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
4209 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
4211 def test_bridge_property ( self
):
4212 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
4213 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
4214 '25-bridge99.network' )
4216 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' ])
4218 output
= check_output ( 'ip -d link show bridge99' )
4220 self
. assertIn ( 'mtu 9000 ' , output
)
4222 output
= check_output ( 'ip -d link show test1' )
4224 self
. assertIn ( 'master bridge99 ' , output
)
4225 self
. assertIn ( 'bridge_slave' , output
)
4226 self
. assertIn ( 'mtu 9000 ' , output
)
4228 output
= check_output ( 'ip -d link show dummy98' )
4230 self
. assertIn ( 'master bridge99 ' , output
)
4231 self
. assertIn ( 'bridge_slave' , output
)
4232 self
. assertIn ( 'mtu 9000 ' , output
)
4234 output
= check_output ( 'ip addr show bridge99' )
4236 self
. assertIn ( '192.168.0.15/24' , output
)
4238 output
= check_output ( 'bridge -d link show dummy98' )
4240 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
4241 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
4242 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'isolated' , '1' )
4243 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
4244 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
4245 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
4246 # CONFIG_BRIDGE_IGMP_SNOOPING=y
4247 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
4248 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
4249 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
4250 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
4251 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
4252 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
4254 output
= check_output ( 'bridge -d link show test1' )
4256 self
. check_bridge_port_attr ( 'bridge99' , 'test1' , 'priority' , '0' )
4258 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
4259 output
= check_output ( 'ip addr show bridge99' )
4261 self
. assertIn ( '192.168.0.16/24' , output
)
4264 print ( '### ip -6 route list table all dev bridge99' )
4265 output
= check_output ( 'ip -6 route list table all dev bridge99' )
4267 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
4269 remove_link ( 'test1' )
4270 self
. wait_operstate ( 'bridge99' , 'routable' )
4272 output
= check_output ( 'ip -d link show bridge99' )
4274 self
. assertIn ( 'mtu 9000 ' , output
)
4276 output
= check_output ( 'ip -d link show dummy98' )
4278 self
. assertIn ( 'master bridge99 ' , output
)
4279 self
. assertIn ( 'bridge_slave' , output
)
4280 self
. assertIn ( 'mtu 9000 ' , output
)
4282 remove_link ( 'dummy98' )
4283 self
. wait_operstate ( 'bridge99' , 'no-carrier' )
4285 output
= check_output ( 'ip -d link show bridge99' )
4287 # When no carrier, the kernel may reset the MTU
4288 self
. assertIn ( 'NO-CARRIER' , output
)
4290 output
= check_output ( 'ip address show bridge99' )
4292 self
. assertNotIn ( '192.168.0.15/24' , output
)
4293 self
. assertIn ( '192.168.0.16/24' , output
) # foreign address is kept
4295 print ( '### ip -6 route list table all dev bridge99' )
4296 output
= check_output ( 'ip -6 route list table all dev bridge99' )
4298 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
4300 check_output ( 'ip link add dummy98 type dummy' )
4301 self
. wait_online ([ 'dummy98:enslaved' , 'bridge99:routable' ])
4303 output
= check_output ( 'ip -d link show bridge99' )
4305 self
. assertIn ( 'mtu 9000 ' , output
)
4307 output
= check_output ( 'ip -d link show dummy98' )
4309 self
. assertIn ( 'master bridge99 ' , output
)
4310 self
. assertIn ( 'bridge_slave' , output
)
4311 self
. assertIn ( 'mtu 9000 ' , output
)
4313 def test_bridge_configure_without_carrier ( self
):
4314 copy_network_unit ( '26-bridge.netdev' , '26-bridge-configure-without-carrier.network' ,
4318 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
4319 for test
in [ 'no-slave' , 'add-slave' , 'slave-up' , 'slave-no-carrier' , 'slave-carrier' , 'slave-down' ]:
4320 with self
. subTest ( test
= test
):
4321 if test
== 'no-slave' :
4322 # bridge has no slaves; it's up but *might* not have carrier
4323 self
. wait_operstate ( 'bridge99' , operstate
= r
'(no-carrier|routable)' , setup_state
= None , setup_timeout
= 30 )
4324 # due to a bug in the kernel, newly-created bridges are brought up
4325 # *with* carrier, unless they have had any setting changed; e.g.
4326 # their mac set, priority set, etc. Then, they will lose carrier
4327 # as soon as a (down) slave interface is added, and regain carrier
4328 # again once the slave interface is brought up.
4329 #self.check_link_attr('bridge99', 'carrier', '0')
4330 elif test
== 'add-slave' :
4331 # add slave to bridge, but leave it down; bridge is definitely no-carrier
4332 self
. check_link_attr ( 'test1' , 'operstate' , 'down' )
4333 check_output ( 'ip link set dev test1 master bridge99' )
4334 self
. wait_operstate ( 'bridge99' , operstate
= 'no-carrier' , setup_state
= None )
4335 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4336 elif test
== 'slave-up' :
4337 # bring up slave, which will have carrier; bridge gains carrier
4338 check_output ( 'ip link set dev test1 up' )
4339 self
. wait_online ([ 'bridge99:routable' ])
4340 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
4341 elif test
== 'slave-no-carrier' :
4342 # drop slave carrier; bridge loses carrier
4343 check_output ( 'ip link set dev test1 carrier off' )
4344 self
. wait_online ([ 'bridge99:no-carrier:no-carrier' ])
4345 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4346 elif test
== 'slave-carrier' :
4347 # restore slave carrier; bridge gains carrier
4348 check_output ( 'ip link set dev test1 carrier on' )
4349 self
. wait_online ([ 'bridge99:routable' ])
4350 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
4351 elif test
== 'slave-down' :
4352 # bring down slave; bridge loses carrier
4353 check_output ( 'ip link set dev test1 down' )
4354 self
. wait_online ([ 'bridge99:no-carrier:no-carrier' ])
4355 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4357 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bridge99' , env
= env
)
4358 self
. assertRegex ( output
, '10.1.2.3' )
4359 self
. assertRegex ( output
, '10.1.2.1' )
4361 def test_bridge_ignore_carrier_loss ( self
):
4362 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
4363 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
4364 '25-bridge99-ignore-carrier-loss.network' )
4366 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' ])
4368 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
4369 remove_link ( 'test1' , 'dummy98' )
4372 output
= check_output ( 'ip address show bridge99' )
4374 self
. assertRegex ( output
, 'NO-CARRIER' )
4375 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
4376 self
. assertRegex ( output
, 'inet 192.168.0.16/24 scope global secondary bridge99' )
4378 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain ( self
):
4379 copy_network_unit ( '26-bridge.netdev' , '26-bridge-slave-interface-1.network' ,
4380 '25-bridge99-ignore-carrier-loss.network' )
4382 self
. wait_online ([ 'bridge99:no-carrier' ])
4384 for trial
in range ( 4 ):
4385 check_output ( 'ip link add dummy98 type dummy' )
4386 check_output ( 'ip link set dummy98 up' )
4388 remove_link ( 'dummy98' )
4390 self
. wait_online ([ 'bridge99:routable' , 'dummy98:enslaved' ])
4392 output
= check_output ( 'ip address show bridge99' )
4394 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
4396 output
= check_output ( 'ip rule list table 100' )
4398 self
. assertIn ( 'from all to 8.8.8.8 lookup 100' , output
)
4400 class NetworkdSRIOVTests ( unittest
. TestCase
, Utilities
):
4408 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
4409 def test_sriov ( self
):
4410 copy_network_unit ( '25-default.link' , '25-sriov.network' )
4412 call ( 'modprobe netdevsim' )
4414 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4417 with
open ( '/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4421 self
. wait_online ([ 'eni99np1:routable' ])
4423 output
= check_output ( 'ip link show dev eni99np1' )
4425 self
. assertRegex ( output
,
4426 '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 *'
4427 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4428 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4431 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
4432 def test_sriov_udev ( self
):
4433 copy_network_unit ( '25-sriov.link' , '25-sriov-udev.network' )
4435 call ( 'modprobe netdevsim' )
4437 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4441 self
. wait_online ([ 'eni99np1:routable' ])
4443 # the name eni99np1 may be an alternative name.
4444 ifname
= link_resolve ( 'eni99np1' )
4446 output
= check_output ( 'ip link show dev eni99np1' )
4448 self
. assertRegex ( output
,
4449 '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 *'
4450 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4451 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4453 self
. assertNotIn ( 'vf 3' , output
)
4454 self
. assertNotIn ( 'vf 4' , output
)
4456 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4457 f
. write ( '[Link] \n SR-IOVVirtualFunctions=4 \n ' )
4460 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4462 output
= check_output ( 'ip link show dev eni99np1' )
4464 self
. assertRegex ( output
,
4465 '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 *'
4466 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4467 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
4470 self
. assertNotIn ( 'vf 4' , output
)
4472 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4473 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
4476 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4478 output
= check_output ( 'ip link show dev eni99np1' )
4480 self
. assertRegex ( output
,
4481 '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 *'
4482 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4483 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
4486 self
. assertNotIn ( 'vf 4' , output
)
4488 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4489 f
. write ( '[Link] \n SR-IOVVirtualFunctions=2 \n ' )
4492 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4494 output
= check_output ( 'ip link show dev eni99np1' )
4496 self
. assertRegex ( output
,
4497 '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 *'
4498 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off'
4500 self
. assertNotIn ( 'vf 2' , output
)
4501 self
. assertNotIn ( 'vf 3' , output
)
4502 self
. assertNotIn ( 'vf 4' , output
)
4504 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4505 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
4508 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4510 output
= check_output ( 'ip link show dev eni99np1' )
4512 self
. assertRegex ( output
,
4513 '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 *'
4514 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4515 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4517 self
. assertNotIn ( 'vf 3' , output
)
4518 self
. assertNotIn ( 'vf 4' , output
)
4520 class NetworkdLLDPTests ( unittest
. TestCase
, Utilities
):
4528 def test_lldp ( self
):
4529 copy_network_unit ( '23-emit-lldp.network' , '24-lldp.network' , '25-veth.netdev' )
4531 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:degraded' ])
4533 for trial
in range ( 10 ):
4537 output
= check_output (* networkctl_cmd
, 'lldp' , env
= env
)
4539 if re
. search ( r
'veth99 .* veth-peer' , output
):
4544 class NetworkdRATests ( unittest
. TestCase
, Utilities
):
4552 def test_ipv6_prefix_delegation ( self
):
4553 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth.network' )
4555 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4557 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth99' , env
= env
)
4559 self
. assertRegex ( output
, 'fe80::' )
4560 self
. assertRegex ( output
, '2002:da8:1::1' )
4562 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth99' , env
= env
)
4564 self
. assertIn ( 'hogehoge.test' , output
)
4566 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4568 self
. assertRegex ( output
, '2002:da8:1:0' )
4570 self
. check_netlabel ( 'veth99' , '2002:da8:1::/64' )
4571 self
. check_netlabel ( 'veth99' , '2002:da8:2::/64' )
4573 def test_ipv6_token_static ( self
):
4574 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-static.network' )
4576 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4578 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4580 self
. assertRegex ( output
, '2002:da8:1:0:1a:2b:3c:4d' )
4581 self
. assertRegex ( output
, '2002:da8:1:0:fa:de:ca:fe' )
4582 self
. assertRegex ( output
, '2002:da8:2:0:1a:2b:3c:4d' )
4583 self
. assertRegex ( output
, '2002:da8:2:0:fa:de:ca:fe' )
4585 def test_ipv6_token_prefixstable ( self
):
4586 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable.network' )
4588 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4590 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4592 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
4593 self
. assertIn ( '2002:da8:2:0:1034:56ff:fe78:9abc' , output
) # EUI64
4595 def test_ipv6_token_prefixstable_without_address ( self
):
4596 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable-without-address.network' )
4598 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4600 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4602 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
4603 self
. assertIn ( '2002:da8:2:0:f689:561a:8eda:7443' , output
)
4605 def test_router_preference ( self
):
4606 copy_network_unit ( '25-veth-client.netdev' ,
4607 '25-veth-router-high.netdev' ,
4608 '25-veth-router-low.netdev' ,
4610 '25-veth-bridge.network' ,
4611 '25-veth-client.network' ,
4612 '25-veth-router-high.network' ,
4613 '25-veth-router-low.network' ,
4614 '25-bridge99.network' )
4616 self
. wait_online ([ 'client-p:enslaved' ,
4617 'router-high:degraded' , 'router-high-p:enslaved' ,
4618 'router-low:degraded' , 'router-low-p:enslaved' ,
4619 'bridge99:routable' ])
4621 networkctl_reconfigure ( 'client' )
4622 self
. wait_online ([ 'client:routable' ])
4624 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4625 self
. wait_address ( 'client' , '2002:da8:1:98:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4626 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 512' , ipv
= '-6' , timeout_sec
= 10 )
4627 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 2048' , ipv
= '-6' , timeout_sec
= 10 )
4629 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
4631 self
. assertIn ( 'pref high' , output
)
4632 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
4634 self
. assertIn ( 'pref low' , output
)
4636 with
open ( os
. path
. join ( network_unit_dir
, '25-veth-client.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4637 f
. write ( ' \n [Link] \n MACAddress=12:34:56:78:9a:01 \n [IPv6AcceptRA] \n RouteMetric=100:200:300 \n ' )
4640 self
. wait_online ([ 'client:routable' ])
4642 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a01/64' , ipv
= '-6' , timeout_sec
= 10 )
4643 self
. wait_address ( 'client' , '2002:da8:1:98:1034:56ff:fe78:9a01/64' , ipv
= '-6' , timeout_sec
= 10 )
4644 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 100' , ipv
= '-6' , timeout_sec
= 10 )
4645 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 300' , ipv
= '-6' , timeout_sec
= 10 )
4647 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
4649 self
. assertIn ( 'pref high' , output
)
4650 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
4652 self
. assertIn ( 'pref low' , output
)
4654 @unittest . skipUnless ( radvd_check_config ( 'captive-portal.conf' ), "Installed radvd doesn't support captive portals" )
4655 def test_captive_portal ( self
):
4656 copy_network_unit ( '25-veth-client.netdev' ,
4657 '25-veth-router-captive.netdev' ,
4659 '25-veth-client-captive.network' ,
4660 '25-veth-router-captive.network' ,
4661 '25-veth-bridge-captive.network' ,
4662 '25-bridge99.network' )
4664 self
. wait_online ([ 'bridge99:routable' , 'client-p:enslaved' ,
4665 'router-captive:degraded' , 'router-captivep:enslaved' ])
4667 start_radvd ( config_file
= 'captive-portal.conf' )
4668 networkctl_reconfigure ( 'client' )
4669 self
. wait_online ([ 'client:routable' ])
4671 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4672 output
= check_output (* networkctl_cmd
, 'status' , 'client' , env
= env
)
4674 self
. assertIn ( 'Captive Portal: http://systemd.io' , output
)
4676 @unittest . skipUnless ( radvd_check_config ( 'captive-portal.conf' ), "Installed radvd doesn't support captive portals" )
4677 def test_invalid_captive_portal ( self
):
4678 def radvd_write_config ( captive_portal_uri
):
4679 with
open ( os
. path
. join ( networkd_ci_temp_dir
, 'radvd/bogus-captive-portal.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
4680 f
. write ( f
'interface router-captive {{ AdvSendAdvert on; AdvCaptivePortalAPI " {captive_portal_uri} "; prefix 2002:da8:1:99::/64 {{ AdvOnLink on; AdvAutonomous on; }}; }};' )
4682 captive_portal_uris
= [
4683 "42ěščěškd ěšč ě s" ,
4688 copy_network_unit ( '25-veth-client.netdev' ,
4689 '25-veth-router-captive.netdev' ,
4691 '25-veth-client-captive.network' ,
4692 '25-veth-router-captive.network' ,
4693 '25-veth-bridge-captive.network' ,
4694 '25-bridge99.network' )
4696 self
. wait_online ([ 'bridge99:routable' , 'client-p:enslaved' ,
4697 'router-captive:degraded' , 'router-captivep:enslaved' ])
4699 for uri
in captive_portal_uris
:
4700 print ( f
"Captive portal: {uri} " )
4701 radvd_write_config ( uri
)
4703 start_radvd ( config_file
= 'bogus-captive-portal.conf' )
4704 networkctl_reconfigure ( 'client' )
4705 self
. wait_online ([ 'client:routable' ])
4707 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4708 output
= check_output (* networkctl_cmd
, 'status' , 'client' , env
= env
)
4710 self
. assertNotIn ( 'Captive Portal:' , output
)
4712 class NetworkdDHCPServerTests ( unittest
. TestCase
, Utilities
):
4720 def test_dhcp_server ( self
):
4721 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server.network' )
4723 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4725 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4727 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4728 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
4729 self
. assertRegex ( output
, 'DNS: 192.168.5.1 \n *192.168.5.10' )
4730 self
. assertRegex ( output
, 'NTP: 192.168.5.1 \n *192.168.5.11' )
4732 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth-peer' , env
= env
)
4733 self
. assertRegex ( output
, "Offered DHCP leases: 192.168.5.[0-9]*" )
4735 def test_dhcp_server_with_uplink ( self
):
4736 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-downstream.network' ,
4737 '12-dummy.netdev' , '25-dhcp-server-uplink.network' )
4739 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4741 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4743 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4744 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
4745 self
. assertIn ( 'DNS: 192.168.5.1' , output
)
4746 self
. assertIn ( 'NTP: 192.168.5.1' , output
)
4748 def test_emit_router_timezone ( self
):
4749 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-timezone-router.network' , '25-dhcp-server-timezone-router.network' )
4751 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4753 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4755 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4756 self
. assertIn ( 'Gateway: 192.168.5.1' , output
)
4757 self
. assertIn ( 'Time Zone: Europe/Berlin' , output
)
4759 def test_dhcp_server_static_lease ( self
):
4760 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-static-lease.network' , '25-dhcp-server-static-lease.network' )
4762 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4764 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4766 self
. assertIn ( 'Address: 10.1.1.200 (DHCP4 via 10.1.1.1)' , output
)
4767 self
. assertIn ( 'DHCP4 Client ID: 12:34:56:78:9a:bc' , output
)
4769 def test_dhcp_server_static_lease_default_client_id ( self
):
4770 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-static-lease.network' )
4772 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4774 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4776 self
. assertIn ( 'Address: 10.1.1.200 (DHCP4 via 10.1.1.1)' , output
)
4777 self
. assertRegex ( output
, 'DHCP4 Client ID: IAID:[0-9a-z]*/DUID' )
4779 class NetworkdDHCPServerRelayAgentTests ( unittest
. TestCase
, Utilities
):
4787 def test_relay_agent ( self
):
4788 copy_network_unit ( '25-agent-veth-client.netdev' ,
4789 '25-agent-veth-server.netdev' ,
4790 '25-agent-client.network' ,
4791 '25-agent-server.network' ,
4792 '25-agent-client-peer.network' ,
4793 '25-agent-server-peer.network' )
4796 self
. wait_online ([ 'client:routable' ])
4798 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'client' , env
= env
)
4800 self
. assertRegex ( output
, r
'Address: 192.168.5.150 \(DHCP4 via 192.168.5.1\)' )
4802 class NetworkdDHCPClientTests ( unittest
. TestCase
, Utilities
):
4810 def test_dhcp_client_ipv6_only ( self
):
4811 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv6-only.network' )
4814 self
. wait_online ([ 'veth-peer:carrier' ])
4816 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4819 output
= check_output ( 'ip address show dev veth99 scope global' )
4821 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
4822 self
. assertNotIn ( '192.168.5' , output
)
4824 # checking semi-static route
4825 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
4827 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
4829 # Confirm that ipv6 token is not set in the kernel
4830 output
= check_output ( 'ip token show dev veth99' )
4832 self
. assertRegex ( output
, 'token :: dev veth99' )
4834 print ( '## dnsmasq log' )
4835 output
= read_dnsmasq_log_file ()
4837 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
4838 self
. assertNotIn ( 'DHCPADVERTISE(veth-peer)' , output
)
4839 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
4840 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
4841 self
. assertIn ( 'sent size: 0 option: 14 rapid-commit' , output
)
4843 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-ipv6-only.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4844 f
. write ( ' \n [DHCPv6] \n RapidCommit=no \n ' )
4850 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4853 output
= check_output ( 'ip address show dev veth99 scope global' )
4855 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
4856 self
. assertNotIn ( '192.168.5' , output
)
4858 # checking semi-static route
4859 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
4861 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
4863 print ( '## dnsmasq log' )
4864 output
= read_dnsmasq_log_file ()
4866 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
4867 self
. assertIn ( 'DHCPADVERTISE(veth-peer)' , output
)
4868 self
. assertIn ( 'DHCPREQUEST(veth-peer)' , output
)
4869 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
4870 self
. assertNotIn ( 'rapid-commit' , output
)
4872 def test_dhcp_client_ipv4_only ( self
):
4873 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv4-only.network' )
4876 self
. wait_online ([ 'veth-peer:carrier' ])
4877 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7' ,
4878 '--dhcp-option=option:domain-search,example.com' ,
4879 '--dhcp-alternate-port=67,5555' ,
4880 ipv4_range
= '192.168.5.110,192.168.5.119' )
4881 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4882 self
. wait_address ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' )
4884 print ( '## ip address show dev veth99 scope global' )
4885 output
= check_output ( 'ip address show dev veth99 scope global' )
4887 self
. assertIn ( 'mtu 1492' , output
)
4888 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
4889 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' )
4890 self
. assertNotIn ( '2600::' , output
)
4892 print ( '## ip route show table main dev veth99' )
4893 output
= check_output ( 'ip route show table main dev veth99' )
4895 # no DHCP routes assigned to the main table
4896 self
. assertNotIn ( 'proto dhcp' , output
)
4898 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
4899 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
4900 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
4901 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
4903 print ( '## ip route show table 211 dev veth99' )
4904 output
= check_output ( 'ip route show table 211 dev veth99' )
4906 self
. assertRegex ( output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.11[0-9] metric 24' )
4907 self
. assertRegex ( output
, '192.168.5.0/24 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4908 self
. assertRegex ( output
, '192.168.5.1 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4909 self
. assertRegex ( output
, '192.168.5.6 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4910 self
. assertRegex ( output
, '192.168.5.7 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4911 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
4913 print ( '## link state file' )
4914 output
= read_link_state_file ( 'veth99' )
4916 # checking DNS server and Domains
4917 self
. assertIn ( 'DNS=192.168.5.6 192.168.5.7' , output
)
4918 self
. assertIn ( 'DOMAINS=example.com' , output
)
4920 print ( '## dnsmasq log' )
4921 output
= read_dnsmasq_log_file ()
4923 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
4924 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc' , output
)
4925 self
. assertIn ( 'client provides name: test-hostname' , output
)
4926 self
. assertIn ( '26:mtu' , output
)
4928 # change address range, DNS servers, and Domains
4930 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8' ,
4931 '--dhcp-option=option:domain-search,foo.example.com' ,
4932 '--dhcp-alternate-port=67,5555' ,
4933 ipv4_range
= '192.168.5.120,192.168.5.129' ,)
4935 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4936 print ( 'Wait for the DHCP lease to be expired' )
4937 self
. wait_address_dropped ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' , timeout_sec
= 120 )
4938 self
. wait_address ( 'veth99' , r
'inet 192.168.5.12[0-9]*/24' , ipv
= '-4' )
4940 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4942 print ( '## ip address show dev veth99 scope global' )
4943 output
= check_output ( 'ip address show dev veth99 scope global' )
4945 self
. assertIn ( 'mtu 1492' , output
)
4946 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
4947 self
. assertNotIn ( '192.168.5.11' , output
)
4948 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' )
4949 self
. assertNotIn ( '2600::' , output
)
4951 print ( '## ip route show table main dev veth99' )
4952 output
= check_output ( 'ip route show table main dev veth99' )
4954 # no DHCP routes assigned to the main table
4955 self
. assertNotIn ( 'proto dhcp' , output
)
4957 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
4958 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
4959 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
4960 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
4962 print ( '## ip route show table 211 dev veth99' )
4963 output
= check_output ( 'ip route show table 211 dev veth99' )
4965 self
. assertRegex ( output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.12[0-9] metric 24' )
4966 self
. assertRegex ( output
, '192.168.5.0/24 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4967 self
. assertRegex ( output
, '192.168.5.1 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4968 self
. assertNotIn ( '192.168.5.6' , output
)
4969 self
. assertRegex ( output
, '192.168.5.7 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4970 self
. assertRegex ( output
, '192.168.5.8 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4971 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
4973 print ( '## link state file' )
4974 output
= read_link_state_file ( 'veth99' )
4976 # checking DNS server and Domains
4977 self
. assertIn ( 'DNS=192.168.5.1 192.168.5.7 192.168.5.8' , output
)
4978 self
. assertIn ( 'DOMAINS=foo.example.com' , output
)
4980 print ( '## dnsmasq log' )
4981 output
= read_dnsmasq_log_file ()
4983 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
4984 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 192.168.5.11' , output
)
4985 self
. assertIn ( 'client provides name: test-hostname' , output
)
4986 self
. assertIn ( '26:mtu' , output
)
4988 self
. check_netlabel ( 'veth99' , r
'192\.168\.5\.0/24' )
4990 def test_dhcp_client_ipv4_use_routes_gateway ( self
):
4992 for ( routes
, gateway
, dns_and_ntp_routes
, classless
) in itertools
. product ([ True , False ], repeat
= 4 ):
4998 print ( f
'### test_dhcp_client_ipv4_use_routes_gateway(routes= {routes} , gateway= {gateway} , dns_and_ntp_routes= {dns_and_ntp_routes} , classless= {classless} )' )
4999 with self
. subTest ( routes
= routes
, gateway
= gateway
, dns_and_ntp_routes
= dns_and_ntp_routes
, classless
= classless
):
5000 self
._ test
_ dhcp
_ client
_ ipv
4_u se
_ routes
_ gateway
( routes
, gateway
, dns_and_ntp_routes
, classless
)
5002 def _test_dhcp_client_ipv4_use_routes_gateway ( self
, use_routes
, use_gateway
, dns_and_ntp_routes
, classless
):
5003 testunit
= '25-dhcp-client-ipv4-use-routes-use-gateway.network'
5004 testunits
= [ '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , testunit
]
5005 testunits
. append ( f
' {testunit} .d/use-routes- {use_routes} .conf' )
5006 testunits
. append ( f
' {testunit} .d/use-gateway- {use_gateway} .conf' )
5007 testunits
. append ( f
' {testunit} .d/use-dns-and-ntp-routes- {dns_and_ntp_routes} .conf' )
5008 copy_network_unit (* testunits
, copy_dropins
= False )
5011 self
. wait_online ([ 'veth-peer:carrier' ])
5012 additional_options
= [
5013 '--dhcp-option=option:dns-server,192.168.5.10,8.8.8.8' ,
5014 '--dhcp-option=option:ntp-server,192.168.5.11,9.9.9.9' ,
5015 '--dhcp-option=option:static-route,192.168.6.100,192.168.5.2,8.8.8.8,192.168.5.3'
5018 additional_options
+= [
5019 '--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'
5021 start_dnsmasq (* additional_options
)
5022 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5024 output
= check_output ( 'ip -4 route show dev veth99' )
5030 self
. assertRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5031 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5032 self
. assertRegex ( output
, r
'192.168.5.64/26 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5033 self
. assertRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5034 self
. assertRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5036 self
. assertRegex ( output
, r
'192.168.6.0/24 via 192.168.5.2 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5037 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5038 self
. assertRegex ( output
, r
'192.168.5.2 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5039 self
. assertRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5041 self
. assertNotRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5042 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5043 self
. assertNotRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5044 self
. assertNotRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5045 self
. assertNotRegex ( output
, r
'192.168.6.0/24 via 192.168.5.2 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5046 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5047 self
. assertNotRegex ( output
, r
'192.168.5.2 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5048 self
. assertNotRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5051 if use_gateway
and ( not classless
or not use_routes
):
5052 self
. assertRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5054 self
. assertNotRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5056 # Check route to gateway
5057 if ( use_gateway
or dns_and_ntp_routes
) and ( not classless
or not use_routes
):
5058 self
. assertRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5060 self
. assertNotRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5062 # Check RoutesToDNS= and RoutesToNTP=
5063 if dns_and_ntp_routes
:
5064 self
. assertRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5065 self
. assertRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5068 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5069 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5071 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5072 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5074 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5075 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5077 self
. assertNotRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5078 self
. assertNotRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5079 self
. assertNotRegex ( output
, r
'8.8.8.8 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
5080 self
. assertNotRegex ( output
, r
'9.9.9.9 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
5082 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5085 def test_dhcp_client_settings_anonymize ( self
):
5086 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-anonymize.network' )
5088 self
. wait_online ([ 'veth-peer:carrier' ])
5090 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5092 print ( '## dnsmasq log' )
5093 output
= read_dnsmasq_log_file ()
5095 self
. assertNotIn ( 'VendorClassIdentifier=SusantVendorTest' , output
)
5096 self
. assertNotIn ( 'test-hostname' , output
)
5097 self
. assertNotIn ( '26:mtu' , output
)
5099 def test_dhcp_keep_configuration_dhcp ( self
):
5100 copy_network_unit ( '25-veth.netdev' ,
5101 '25-dhcp-server-veth-peer.network' ,
5102 '25-dhcp-client-keep-configuration-dhcp.network' )
5104 self
. wait_online ([ 'veth-peer:carrier' ])
5106 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5108 output
= check_output ( 'ip address show dev veth99 scope global' )
5110 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5111 'valid_lft forever preferred_lft forever' )
5113 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
5116 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
5117 print ( 'Wait for the DHCP lease to be expired' )
5120 # The lease address should be kept after the lease expired
5121 output
= check_output ( 'ip address show dev veth99 scope global' )
5123 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5124 'valid_lft forever preferred_lft forever' )
5128 # The lease address should be kept after networkd stopped
5129 output
= check_output ( 'ip address show dev veth99 scope global' )
5131 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5132 'valid_lft forever preferred_lft forever' )
5134 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-keep-configuration-dhcp.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5135 f
. write ( '[Network] \n DHCP=no \n ' )
5138 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5140 # Still the lease address should be kept after networkd restarted
5141 output
= check_output ( 'ip address show dev veth99 scope global' )
5143 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5144 'valid_lft forever preferred_lft forever' )
5146 def test_dhcp_keep_configuration_dhcp_on_stop ( self
):
5147 copy_network_unit ( '25-veth.netdev' ,
5148 '25-dhcp-server-veth-peer.network' ,
5149 '25-dhcp-client-keep-configuration-dhcp-on-stop.network' )
5151 self
. wait_online ([ 'veth-peer:carrier' ])
5153 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5155 output
= check_output ( 'ip address show dev veth99 scope global' )
5157 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5162 output
= check_output ( 'ip address show dev veth99 scope global' )
5164 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5167 self
. wait_online ([ 'veth-peer:routable' ])
5169 output
= check_output ( 'ip address show dev veth99 scope global' )
5171 self
. assertNotIn ( '192.168.5.' , output
)
5173 def test_dhcp_client_reuse_address_as_static ( self
):
5174 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' )
5176 self
. wait_online ([ 'veth-peer:carrier' ])
5178 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5180 # link become 'routable' when at least one protocol provide an valid address.
5181 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5182 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5184 output
= check_output ( 'ip address show dev veth99 scope global' )
5185 ipv4_address
= re
. search ( r
'192.168.5.[0-9]*/24' , output
). group ()
5186 ipv6_address
= re
. search ( r
'2600::[0-9a-f:]*/128' , output
). group ()
5187 static_network
= ' \n ' . join ([ '[Match]' , 'Name=veth99' , '[Network]' , 'IPv6AcceptRA=no' , 'Address=' + ipv4_address
, 'Address=' + ipv6_address
])
5188 print ( static_network
)
5190 remove_network_unit ( '25-dhcp-client.network' )
5192 with
open ( os
. path
. join ( network_unit_dir
, '25-static.network' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5193 f
. write ( static_network
)
5196 self
. wait_online ([ 'veth99:routable' ])
5198 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
5200 self
. assertRegex ( output
, f
'inet {ipv4_address} brd 192.168.5.255 scope global veth99 \n *'
5201 'valid_lft forever preferred_lft forever' )
5203 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5205 self
. assertRegex ( output
, f
'inet6 {ipv6_address} scope global * \n *'
5206 'valid_lft forever preferred_lft forever' )
5208 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
5209 def test_dhcp_client_vrf ( self
):
5210 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-vrf.network' ,
5211 '25-vrf.netdev' , '25-vrf.network' )
5213 self
. wait_online ([ 'veth-peer:carrier' ])
5215 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'vrf99:carrier' ])
5217 # link become 'routable' when at least one protocol provide an valid address.
5218 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5219 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5221 print ( '## ip -d link show dev vrf99' )
5222 output
= check_output ( 'ip -d link show dev vrf99' )
5224 self
. assertRegex ( output
, 'vrf table 42' )
5226 print ( '## ip address show vrf vrf99' )
5227 output
= check_output ( 'ip address show vrf vrf99' )
5229 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5230 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5231 self
. assertRegex ( output
, 'inet6 .* scope link' )
5233 print ( '## ip address show dev veth99' )
5234 output
= check_output ( 'ip address show dev veth99' )
5236 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5237 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5238 self
. assertRegex ( output
, 'inet6 .* scope link' )
5240 print ( '## ip route show vrf vrf99' )
5241 output
= check_output ( 'ip route show vrf vrf99' )
5243 self
. assertRegex ( output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.' )
5244 self
. assertRegex ( output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5' )
5245 self
. assertRegex ( output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5' )
5247 print ( '## ip route show table main dev veth99' )
5248 output
= check_output ( 'ip route show table main dev veth99' )
5250 self
. assertEqual ( output
, '' )
5252 def test_dhcp_client_gateway_onlink_implicit ( self
):
5253 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
5254 '25-dhcp-client-gateway-onlink-implicit.network' )
5256 self
. wait_online ([ 'veth-peer:carrier' ])
5258 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5260 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
5262 self
. assertRegex ( output
, '192.168.5' )
5264 output
= check_output ( 'ip route list dev veth99 10.0.0.0/8' )
5266 self
. assertRegex ( output
, 'onlink' )
5267 output
= check_output ( 'ip route list dev veth99 192.168.100.0/24' )
5269 self
. assertRegex ( output
, 'onlink' )
5271 def test_dhcp_client_with_ipv4ll ( self
):
5272 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
5273 '25-dhcp-client-with-ipv4ll.network' )
5275 # we need to increase timeout above default, as this will need to wait for
5276 # systemd-networkd to get the dhcpv4 transient failure event
5277 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:routable' ], timeout
= '60s' )
5279 output
= check_output ( 'ip -4 address show dev veth99' )
5281 self
. assertNotIn ( '192.168.5.' , output
)
5282 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
5285 print ( 'Wait for a DHCP lease to be acquired and the IPv4LL address to be dropped' )
5286 self
. wait_address ( 'veth99' , r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic' , ipv
= '-4' )
5287 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' )
5288 self
. wait_online ([ 'veth99:routable' ])
5290 output
= check_output ( 'ip -4 address show dev veth99' )
5292 self
. assertRegex ( output
, r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99' )
5293 self
. assertNotIn ( '169.254.' , output
)
5294 self
. assertNotIn ( 'scope link' , output
)
5297 print ( 'Wait for the DHCP lease to be expired and an IPv4LL address to be acquired' )
5298 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 )
5299 self
. wait_address ( 'veth99' , r
'inet 169\.254\.133\.11/16 metric 2048 brd 169\.254\.255\.255 scope link' , scope
= 'link' , ipv
= '-4' )
5301 output
= check_output ( 'ip -4 address show dev veth99' )
5303 self
. assertNotIn ( '192.168.5.' , output
)
5304 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
5306 def test_dhcp_client_use_dns ( self
):
5307 def check ( self
, ipv4
, ipv6
):
5308 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5309 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5310 f
. write ( '[DHCPv4] \n UseDNS=' )
5311 f
. write ( 'yes' if ipv4
else 'no' )
5312 f
. write ( ' \n [DHCPv6] \n UseDNS=' )
5313 f
. write ( 'yes' if ipv6
else 'no' )
5314 f
. write ( ' \n [IPv6AcceptRA] \n UseDNS=no' )
5317 self
. wait_online ([ 'veth99:routable' ])
5319 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5320 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5321 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5323 # make resolved re-read the link state file
5324 check_output (* resolvectl_cmd
, 'revert' , 'veth99' , env
= env
)
5326 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth99' , env
= env
)
5329 self
. assertIn ( '192.168.5.1' , output
)
5331 self
. assertNotIn ( '192.168.5.1' , output
)
5333 self
. assertIn ( '2600::1' , output
)
5335 self
. assertNotIn ( '2600::1' , output
)
5337 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5340 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5343 self
. wait_online ([ 'veth-peer:carrier' ])
5344 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1' ,
5345 '--dhcp-option=option6:dns-server,[2600::1]' )
5347 check ( self
, True , True )
5348 check ( self
, True , False )
5349 check ( self
, False , True )
5350 check ( self
, False , False )
5352 def test_dhcp_client_use_captive_portal ( self
):
5353 def check ( self
, ipv4
, ipv6
):
5354 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5355 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5356 f
. write ( '[DHCPv4] \n UseCaptivePortal=' )
5357 f
. write ( 'yes' if ipv4
else 'no' )
5358 f
. write ( ' \n [DHCPv6] \n UseCaptivePortal=' )
5359 f
. write ( 'yes' if ipv6
else 'no' )
5360 f
. write ( ' \n [IPv6AcceptRA] \n UseCaptivePortal=no' )
5363 self
. wait_online ([ 'veth99:routable' ])
5365 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5366 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5367 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5369 output
= check_output (* networkctl_cmd
, 'status' , 'veth99' , env
= env
)
5372 self
. assertIn ( 'Captive Portal: http://systemd.io' , output
)
5374 self
. assertNotIn ( 'Captive Portal: http://systemd.io' , output
)
5376 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5379 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5382 self
. wait_online ([ 'veth-peer:carrier' ])
5383 start_dnsmasq ( '--dhcp-option=114,http://systemd.io' ,
5384 '--dhcp-option=option6:103,http://systemd.io' )
5386 check ( self
, True , True )
5387 check ( self
, True , False )
5388 check ( self
, False , True )
5389 check ( self
, False , False )
5391 def test_dhcp_client_reject_captive_portal ( self
):
5392 def check ( self
, ipv4
, ipv6
):
5393 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5394 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5395 f
. write ( '[DHCPv4] \n UseCaptivePortal=' )
5396 f
. write ( 'yes' if ipv4
else 'no' )
5397 f
. write ( ' \n [DHCPv6] \n UseCaptivePortal=' )
5398 f
. write ( 'yes' if ipv6
else 'no' )
5399 f
. write ( ' \n [IPv6AcceptRA] \n UseCaptivePortal=no' )
5402 self
. wait_online ([ 'veth99:routable' ])
5404 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5405 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5406 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5408 output
= check_output (* networkctl_cmd
, 'status' , 'veth99' , env
= env
)
5410 self
. assertNotIn ( 'Captive Portal: ' , output
)
5411 self
. assertNotIn ( 'invalid/url' , output
)
5413 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5416 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5419 self
. wait_online ([ 'veth-peer:carrier' ])
5420 masq
= lambda bs
: ':' . join ( f
'{b:02x}' for b
in bs
)
5421 start_dnsmasq ( '--dhcp-option=114,' + masq ( b
'http:// \x00 invalid/url' ),
5422 '--dhcp-option=option6:103,' + masq ( b
'http:// \x00 /invalid/url' ))
5424 check ( self
, True , True )
5425 check ( self
, True , False )
5426 check ( self
, False , True )
5427 check ( self
, False , False )
5429 class NetworkdDHCPPDTests ( unittest
. TestCase
, Utilities
):
5437 def test_dhcp6pd ( self
):
5438 copy_network_unit ( '25-veth.netdev' , '25-dhcp6pd-server.network' , '25-dhcp6pd-upstream.network' ,
5439 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
5440 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
5441 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
5442 '25-dhcp-pd-downstream-dummy97.network' ,
5443 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
5444 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' )
5447 self
. wait_online ([ 'veth-peer:routable' ])
5448 start_isc_dhcpd ( conf_file
= 'isc-dhcpd-dhcp6pd.conf' , ipv
= '-6' )
5449 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5450 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5452 print ( '### ip -6 address show dev veth-peer scope global' )
5453 output
= check_output ( 'ip -6 address show dev veth-peer scope global' )
5455 self
. assertIn ( 'inet6 3ffe:501:ffff:100::1/64 scope global' , output
)
5459 # dummy97: 0x01 (The link will appear later)
5461 # dummy99: auto -> 0x02 (No address assignment)
5466 print ( '### ip -6 address show dev veth99 scope global' )
5467 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5470 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:100::[0-9]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5471 # address in IA_PD (Token=static)
5472 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic' )
5473 # address in IA_PD (Token=eui64)
5474 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic' )
5475 # address in IA_PD (temporary)
5476 # Note that the temporary addresses may appear after the link enters configured state
5477 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' )
5479 print ( '### ip -6 address show dev test1 scope global' )
5480 output
= check_output ( 'ip -6 address show dev test1 scope global' )
5482 # address in IA_PD (Token=static)
5483 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5484 # address in IA_PD (temporary)
5485 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' )
5487 print ( '### ip -6 address show dev dummy98 scope global' )
5488 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5490 # address in IA_PD (Token=static)
5491 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5492 # address in IA_PD (temporary)
5493 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' )
5495 print ( '### ip -6 address show dev dummy99 scope global' )
5496 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5499 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
5501 print ( '### ip -6 address show dev veth97 scope global' )
5502 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
5504 # address in IA_PD (Token=static)
5505 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5506 # address in IA_PD (Token=eui64)
5507 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5508 # address in IA_PD (temporary)
5509 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' )
5511 print ( '### ip -6 address show dev veth97-peer scope global' )
5512 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
5514 # NDisc address (Token=static)
5515 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5516 # NDisc address (Token=eui64)
5517 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5518 # NDisc address (temporary)
5519 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' )
5521 print ( '### ip -6 address show dev veth98 scope global' )
5522 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
5524 # address in IA_PD (Token=static)
5525 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5526 # address in IA_PD (Token=eui64)
5527 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5528 # address in IA_PD (temporary)
5529 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' )
5531 print ( '### ip -6 address show dev veth98-peer scope global' )
5532 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
5534 # NDisc address (Token=static)
5535 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5536 # NDisc address (Token=eui64)
5537 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5538 # NDisc address (temporary)
5539 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' )
5541 print ( '### ip -6 route show type unreachable' )
5542 output
= check_output ( 'ip -6 route show type unreachable' )
5544 self
. assertRegex ( output
, 'unreachable 3ffe:501:ffff:[2-9a-f]00::/56 dev lo proto dhcp' )
5546 print ( '### ip -6 route show dev veth99' )
5547 output
= check_output ( 'ip -6 route show dev veth99' )
5549 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]10::/64 proto kernel metric [0-9]* expires' )
5551 print ( '### ip -6 route show dev test1' )
5552 output
= check_output ( 'ip -6 route show dev test1' )
5554 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5556 print ( '### ip -6 route show dev dummy98' )
5557 output
= check_output ( 'ip -6 route show dev dummy98' )
5559 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5561 print ( '### ip -6 route show dev dummy99' )
5562 output
= check_output ( 'ip -6 route show dev dummy99' )
5564 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
5566 print ( '### ip -6 route show dev veth97' )
5567 output
= check_output ( 'ip -6 route show dev veth97' )
5569 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto kernel metric [0-9]* expires' )
5571 print ( '### ip -6 route show dev veth97-peer' )
5572 output
= check_output ( 'ip -6 route show dev veth97-peer' )
5574 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto ra metric [0-9]* expires' )
5576 print ( '### ip -6 route show dev veth98' )
5577 output
= check_output ( 'ip -6 route show dev veth98' )
5579 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto kernel metric [0-9]* expires' )
5581 print ( '### ip -6 route show dev veth98-peer' )
5582 output
= check_output ( 'ip -6 route show dev veth98-peer' )
5584 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto ra metric [0-9]* expires' )
5586 # Test case for a downstream which appears later
5587 check_output ( 'ip link add dummy97 type dummy' )
5588 self
. wait_online ([ 'dummy97:routable' ])
5590 print ( '### ip -6 address show dev dummy97 scope global' )
5591 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
5593 # address in IA_PD (Token=static)
5594 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5595 # address in IA_PD (temporary)
5596 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' )
5598 print ( '### ip -6 route show dev dummy97' )
5599 output
= check_output ( 'ip -6 route show dev dummy97' )
5601 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]01::/64 proto kernel metric [0-9]* expires' )
5603 # Test case for reconfigure
5604 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
5605 self
. wait_online ([ 'dummy98:routable' , 'dummy99:degraded' ])
5607 print ( '### ip -6 address show dev dummy98 scope global' )
5608 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5610 # address in IA_PD (Token=static)
5611 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5612 # address in IA_PD (temporary)
5613 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' )
5615 print ( '### ip -6 address show dev dummy99 scope global' )
5616 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5619 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
5621 print ( '### ip -6 route show dev dummy98' )
5622 output
= check_output ( 'ip -6 route show dev dummy98' )
5624 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5626 print ( '### ip -6 route show dev dummy99' )
5627 output
= check_output ( 'ip -6 route show dev dummy99' )
5629 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
5631 self
. check_netlabel ( 'dummy98' , '3ffe:501:ffff:[2-9a-f]00::/64' )
5633 def verify_dhcp4_6rd ( self
, tunnel_name
):
5634 print ( '### ip -4 address show dev veth-peer scope global' )
5635 output
= check_output ( 'ip -4 address show dev veth-peer scope global' )
5637 self
. assertIn ( 'inet 10.0.0.1/8 brd 10.255.255.255 scope global veth-peer' , output
)
5641 # dummy97: 0x01 (The link will appear later)
5643 # dummy99: auto -> 0x0[23] (No address assignment)
5644 # 6rd-XXX: auto -> 0x0[23]
5649 print ( '### ip -4 address show dev veth99 scope global' )
5650 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
5652 self
. assertRegex ( output
, 'inet 10.100.100.[0-9]*/8 (metric 1024 |)brd 10.255.255.255 scope global dynamic veth99' )
5654 print ( '### ip -6 address show dev veth99 scope global' )
5655 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5657 # address in IA_PD (Token=static)
5658 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5659 # address in IA_PD (Token=eui64)
5660 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5661 # address in IA_PD (temporary)
5662 # Note that the temporary addresses may appear after the link enters configured state
5663 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' )
5665 print ( '### ip -6 address show dev test1 scope global' )
5666 output
= check_output ( 'ip -6 address show dev test1 scope global' )
5668 # address in IA_PD (Token=static)
5669 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5670 # address in IA_PD (temporary)
5671 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' )
5673 print ( '### ip -6 address show dev dummy98 scope global' )
5674 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5676 # address in IA_PD (Token=static)
5677 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5678 # address in IA_PD (temporary)
5679 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' )
5681 print ( '### ip -6 address show dev dummy99 scope global' )
5682 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5685 self
. assertNotRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+0[23]' )
5687 print ( '### ip -6 address show dev veth97 scope global' )
5688 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
5690 # address in IA_PD (Token=static)
5691 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5692 # address in IA_PD (Token=eui64)
5693 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5694 # address in IA_PD (temporary)
5695 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' )
5697 print ( '### ip -6 address show dev veth97-peer scope global' )
5698 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
5700 # NDisc address (Token=static)
5701 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5702 # NDisc address (Token=eui64)
5703 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5704 # NDisc address (temporary)
5705 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' )
5707 print ( '### ip -6 address show dev veth98 scope global' )
5708 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
5710 # address in IA_PD (Token=static)
5711 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5712 # address in IA_PD (Token=eui64)
5713 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5714 # address in IA_PD (temporary)
5715 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' )
5717 print ( '### ip -6 address show dev veth98-peer scope global' )
5718 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
5720 # NDisc address (Token=static)
5721 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5722 # NDisc address (Token=eui64)
5723 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5724 # NDisc address (temporary)
5725 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' )
5727 print ( '### ip -6 route show type unreachable' )
5728 output
= check_output ( 'ip -6 route show type unreachable' )
5730 self
. assertRegex ( output
, 'unreachable 2001:db8:6464:[0-9a-f]+00::/56 dev lo proto dhcp' )
5732 print ( '### ip -6 route show dev veth99' )
5733 output
= check_output ( 'ip -6 route show dev veth99' )
5735 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+10::/64 proto kernel metric [0-9]* expires' )
5737 print ( '### ip -6 route show dev test1' )
5738 output
= check_output ( 'ip -6 route show dev test1' )
5740 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
5742 print ( '### ip -6 route show dev dummy98' )
5743 output
= check_output ( 'ip -6 route show dev dummy98' )
5745 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
5747 print ( '### ip -6 route show dev dummy99' )
5748 output
= check_output ( 'ip -6 route show dev dummy99' )
5750 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto dhcp metric [0-9]* expires' )
5752 print ( '### ip -6 route show dev veth97' )
5753 output
= check_output ( 'ip -6 route show dev veth97' )
5755 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto kernel metric [0-9]* expires' )
5757 print ( '### ip -6 route show dev veth97-peer' )
5758 output
= check_output ( 'ip -6 route show dev veth97-peer' )
5760 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto ra metric [0-9]* expires' )
5762 print ( '### ip -6 route show dev veth98' )
5763 output
= check_output ( 'ip -6 route show dev veth98' )
5765 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto kernel metric [0-9]* expires' )
5767 print ( '### ip -6 route show dev veth98-peer' )
5768 output
= check_output ( 'ip -6 route show dev veth98-peer' )
5770 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto ra metric [0-9]* expires' )
5772 print ( '### ip -6 address show dev dummy97 scope global' )
5773 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
5775 # address in IA_PD (Token=static)
5776 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5777 # address in IA_PD (temporary)
5778 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' )
5780 print ( '### ip -6 route show dev dummy97' )
5781 output
= check_output ( 'ip -6 route show dev dummy97' )
5783 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+01::/64 proto kernel metric [0-9]* expires' )
5785 print ( f
'### ip -d link show dev {tunnel_name} ' )
5786 output
= check_output ( f
'ip -d link show dev {tunnel_name} ' )
5788 self
. assertIn ( 'link/sit 10.100.100.' , output
)
5789 self
. assertIn ( 'local 10.100.100.' , output
)
5790 self
. assertIn ( 'ttl 64' , output
)
5791 self
. assertIn ( '6rd-prefix 2001:db8::/32' , output
)
5792 self
. assertIn ( '6rd-relay_prefix 10.0.0.0/8' , output
)
5794 print ( f
'### ip -6 address show dev {tunnel_name} ' )
5795 output
= check_output ( f
'ip -6 address show dev {tunnel_name} ' )
5797 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' )
5798 self
. assertRegex ( output
, 'inet6 ::10.100.100.[0-9]+/96 scope global' )
5800 print ( f
'### ip -6 route show dev {tunnel_name} ' )
5801 output
= check_output ( f
'ip -6 route show dev {tunnel_name} ' )
5803 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto kernel metric [0-9]* expires' )
5804 self
. assertRegex ( output
, '::/96 proto kernel metric [0-9]*' )
5806 print ( '### ip -6 route show default' )
5807 output
= check_output ( 'ip -6 route show default' )
5809 self
. assertIn ( 'default' , output
)
5810 self
. assertIn ( f
'via ::10.0.0.1 dev {tunnel_name} ' , output
)
5812 def test_dhcp4_6rd ( self
):
5813 copy_network_unit ( '25-veth.netdev' , '25-dhcp4-6rd-server.network' , '25-dhcp4-6rd-upstream.network' ,
5814 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
5815 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
5816 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
5817 '25-dhcp-pd-downstream-dummy97.network' ,
5818 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
5819 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' ,
5820 '80-6rd-tunnel.network' )
5823 self
. wait_online ([ 'veth-peer:routable' ])
5826 # 6rd-prefix: 2001:db8::/32
5827 # br-addresss: 10.0.0.1
5829 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' ,
5830 ipv4_range
= '10.100.100.100,10.100.100.200' ,
5831 ipv4_router
= '10.0.0.1' )
5832 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5833 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5835 # Test case for a downstream which appears later
5836 check_output ( 'ip link add dummy97 type dummy' )
5837 self
. wait_online ([ 'dummy97:routable' ])
5841 for name
in os
. listdir ( '/sys/class/net/' ):
5842 if name
. startswith ( '6rd-' ):
5846 self
. wait_online ([ f
' {tunnel_name} :routable' ])
5848 self
. verify_dhcp4_6rd ( tunnel_name
)
5850 # Test case for reconfigure
5851 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
5852 self
. wait_online ([ 'dummy98:routable' , 'dummy99:degraded' ])
5854 self
. verify_dhcp4_6rd ( tunnel_name
)
5856 print ( 'Wait for the DHCP lease to be renewed/rebind' )
5859 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy97:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5860 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5862 self
. verify_dhcp4_6rd ( tunnel_name
)
5864 class NetworkdIPv6PrefixTests ( unittest
. TestCase
, Utilities
):
5872 def test_ipv6_route_prefix ( self
):
5873 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client.network' , '25-ipv6ra-prefix.network' ,
5874 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
5877 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
5879 output
= check_output ( 'ip address show dev veth-peer' )
5881 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
5882 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
5883 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
5885 output
= check_output ( 'ip -6 route show dev veth-peer' )
5887 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
5888 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
5889 self
. assertNotIn ( '2001:db8:0:3::/64 proto ra' , output
)
5890 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
5891 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
5892 self
. assertNotIn ( '2001:db2:fff::/64 via ' , output
)
5894 output
= check_output ( 'ip address show dev veth99' )
5896 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
5897 self
. assertIn ( 'inet6 2001:db8:0:2:1a:2b:3c:4d' , output
)
5898 self
. assertIn ( 'inet6 2001:db8:0:2:fa:de:ca:fe' , output
)
5899 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
5901 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth-peer' , env
= env
)
5903 self
. assertRegex ( output
, '2001:db8:1:1::2' )
5905 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth-peer' , env
= env
)
5907 self
. assertIn ( 'example.com' , output
)
5909 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5912 def test_ipv6_route_prefix_deny_list ( self
):
5913 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client-deny-list.network' , '25-ipv6ra-prefix.network' ,
5914 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
5917 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
5919 output
= check_output ( 'ip address show dev veth-peer' )
5921 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
5922 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
5924 output
= check_output ( 'ip -6 route show dev veth-peer' )
5926 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
5927 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
5928 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
5929 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
5931 output
= check_output ( 'ip address show dev veth99' )
5933 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
5934 self
. assertIn ( 'inet6 2001:db8:0:2:' , output
)
5936 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth-peer' , env
= env
)
5938 self
. assertRegex ( output
, '2001:db8:1:1::2' )
5940 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth-peer' , env
= env
)
5942 self
. assertIn ( 'example.com' , output
)
5944 class NetworkdMTUTests ( unittest
. TestCase
, Utilities
):
5952 def check_mtu ( self
, mtu
, ipv6_mtu
= None , reset
= True ):
5958 self
. wait_online ([ 'dummy98:routable' ])
5959 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
5960 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
5962 # test normal restart
5964 self
. wait_online ([ 'dummy98:routable' ])
5965 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
5966 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
5969 self
. reset_check_mtu ( mtu
, ipv6_mtu
)
5971 def reset_check_mtu ( self
, mtu
, ipv6_mtu
= None ):
5972 ''' test setting mtu/ipv6_mtu with interface already up '''
5975 # note - changing the device mtu resets the ipv6 mtu
5976 check_output ( 'ip link set up mtu 1501 dev dummy98' )
5977 check_output ( 'ip link set up mtu 1500 dev dummy98' )
5978 self
. check_link_attr ( 'dummy98' , 'mtu' , '1500' )
5979 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , '1500' )
5981 self
. check_mtu ( mtu
, ipv6_mtu
, reset
= False )
5983 def test_mtu_network ( self
):
5984 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' )
5985 self
. check_mtu ( '1600' )
5987 def test_mtu_netdev ( self
):
5988 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network' , copy_dropins
= False )
5989 # note - MTU set by .netdev happens ONLY at device creation!
5990 self
. check_mtu ( '1600' , reset
= False )
5992 def test_mtu_link ( self
):
5993 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network' , copy_dropins
= False )
5994 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
5995 self
. check_mtu ( '1600' , reset
= False )
5997 def test_ipv6_mtu ( self
):
5998 ''' set ipv6 mtu without setting device mtu '''
5999 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1400.conf' )
6000 self
. check_mtu ( '1500' , '1400' )
6002 def test_ipv6_mtu_toolarge ( self
):
6003 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
6004 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
6005 self
. check_mtu ( '1500' , '1500' )
6007 def test_mtu_network_ipv6_mtu ( self
):
6008 ''' set ipv6 mtu and set device mtu via network file '''
6009 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
6010 self
. check_mtu ( '1600' , '1550' )
6012 def test_mtu_netdev_ipv6_mtu ( self
):
6013 ''' set ipv6 mtu and set device mtu via netdev file '''
6014 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
6015 self
. check_mtu ( '1600' , '1550' , reset
= False )
6017 def test_mtu_link_ipv6_mtu ( self
):
6018 ''' set ipv6 mtu and set device mtu via link file '''
6019 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
6020 self
. check_mtu ( '1600' , '1550' , reset
= False )
6023 if __name__
== '__main__' :
6024 parser
= argparse
. ArgumentParser ()
6025 parser
. add_argument ( '--build-dir' , help = 'Path to build dir' , dest
= 'build_dir' )
6026 parser
. add_argument ( '--networkd' , help = 'Path to systemd-networkd' , dest
= 'networkd_bin' )
6027 parser
. add_argument ( '--resolved' , help = 'Path to systemd-resolved' , dest
= 'resolved_bin' )
6028 parser
. add_argument ( '--timesyncd' , help = 'Path to systemd-timesyncd' , dest
= 'timesyncd_bin' )
6029 parser
. add_argument ( '--udevd' , help = 'Path to systemd-udevd' , dest
= 'udevd_bin' )
6030 parser
. add_argument ( '--wait-online' , help = 'Path to systemd-networkd-wait-online' , dest
= 'wait_online_bin' )
6031 parser
. add_argument ( '--networkctl' , help = 'Path to networkctl' , dest
= 'networkctl_bin' )
6032 parser
. add_argument ( '--resolvectl' , help = 'Path to resolvectl' , dest
= 'resolvectl_bin' )
6033 parser
. add_argument ( '--timedatectl' , help = 'Path to timedatectl' , dest
= 'timedatectl_bin' )
6034 parser
. add_argument ( '--udevadm' , help = 'Path to udevadm' , dest
= 'udevadm_bin' )
6035 parser
. add_argument ( '--valgrind' , help = 'Enable valgrind' , dest
= 'use_valgrind' , type = bool , nargs
= '?' , const
= True , default
= use_valgrind
)
6036 parser
. add_argument ( '--debug' , help = 'Generate debugging logs' , dest
= 'enable_debug' , type = bool , nargs
= '?' , const
= True , default
= enable_debug
)
6037 parser
. add_argument ( '--asan-options' , help = 'ASAN options' , dest
= 'asan_options' )
6038 parser
. add_argument ( '--lsan-options' , help = 'LSAN options' , dest
= 'lsan_options' )
6039 parser
. add_argument ( '--ubsan-options' , help = 'UBSAN options' , dest
= 'ubsan_options' )
6040 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
)
6041 ns
, unknown_args
= parser
. parse_known_args ( namespace
= unittest
)
6044 if ns
. networkd_bin
or ns
. resolved_bin
or ns
. timesyncd_bin
or ns
. udevd_bin
or \
6045 ns
. wait_online_bin
or ns
. networkctl_bin
or ns
. resolvectl_bin
or ns
. timedatectl_bin
or ns
. udevadm_bin
:
6046 print ( 'WARNING: --networkd, --resolved, --timesyncd, --udevd, --wait-online, --networkctl, --resolvectl, --timedatectl, or --udevadm options are ignored when --build-dir is specified.' )
6047 networkd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd' )
6048 resolved_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-resolved' )
6049 timesyncd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-timesyncd' )
6050 udevd_bin
= os
. path
. join ( ns
. build_dir
, 'udevadm' )
6051 wait_online_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd-wait-online' )
6052 networkctl_bin
= os
. path
. join ( ns
. build_dir
, 'networkctl' )
6053 resolvectl_bin
= os
. path
. join ( ns
. build_dir
, 'resolvectl' )
6054 timedatectl_bin
= os
. path
. join ( ns
. build_dir
, 'timedatectl' )
6055 udevadm_bin
= os
. path
. join ( ns
. build_dir
, 'udevadm' )
6058 networkd_bin
= ns
. networkd_bin
6060 resolved_bin
= ns
. resolved_bin
6061 if ns
. timesyncd_bin
:
6062 timesyncd_bin
= ns
. timesyncd_bin
6064 udevd_bin
= ns
. udevd_bin
6065 if ns
. wait_online_bin
:
6066 wait_online_bin
= ns
. wait_online_bin
6067 if ns
. networkctl_bin
:
6068 networkctl_bin
= ns
. networkctl_bin
6069 if ns
. resolvectl_bin
:
6070 resolvectl_bin
= ns
. resolvectl_bin
6071 if ns
. timedatectl_bin
:
6072 timedatectl_bin
= ns
. timedatectl_bin
6074 udevadm_bin
= ns
. udevadm_bin
6076 use_valgrind
= ns
. use_valgrind
6077 enable_debug
= ns
. enable_debug
6078 asan_options
= ns
. asan_options
6079 lsan_options
= ns
. lsan_options
6080 ubsan_options
= ns
. ubsan_options
6081 with_coverage
= ns
. with_coverage
6084 # Do not forget the trailing space.
6085 valgrind_cmd
= 'valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all '
6087 networkctl_cmd
= valgrind_cmd
. split () + [ networkctl_bin
]
6088 resolvectl_cmd
= valgrind_cmd
. split () + [ resolvectl_bin
]
6089 timedatectl_cmd
= valgrind_cmd
. split () + [ timedatectl_bin
]
6090 udevadm_cmd
= valgrind_cmd
. split () + [ udevadm_bin
]
6091 wait_online_cmd
= valgrind_cmd
. split () + [ wait_online_bin
]
6094 env
. update ({ 'ASAN_OPTIONS' : asan_options
})
6096 env
. update ({ 'LSAN_OPTIONS' : lsan_options
})
6098 env
. update ({ 'UBSAN_OPTIONS' : ubsan_options
})
6100 env
. update ({ 'SYSTEMD_MEMPOOL' : '0' })
6102 wait_online_env
= env
. copy ()
6104 wait_online_env
. update ({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
6106 sys
. argv
[ 1 :] = unknown_args
6107 unittest
. main ( verbosity
= 3 )