]>
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 # systemd-networkd tests
5 # These tests can be executed in the systemd mkosi image when booted in QEMU. After booting the QEMU VM,
6 # simply run this file which can be found in the VM at /usr/lib/systemd/tests/testdata/test-network/systemd-networkd-tests.py.
24 network_unit_dir
= '/run/systemd/network'
25 networkd_conf_dropin_dir
= '/run/systemd/networkd.conf.d'
26 networkd_ci_temp_dir
= '/run/networkd-ci'
27 udev_rules_dir
= '/run/udev/rules.d'
29 dnsmasq_pid_file
= '/run/networkd-ci/test-dnsmasq.pid'
30 dnsmasq_log_file
= '/run/networkd-ci/test-dnsmasq.log'
31 dnsmasq_lease_file
= '/run/networkd-ci/test-dnsmasq.lease'
33 isc_dhcpd_pid_file
= '/run/networkd-ci/test-isc-dhcpd.pid'
34 isc_dhcpd_lease_file
= '/run/networkd-ci/test-isc-dhcpd.lease'
36 radvd_pid_file
= '/run/networkd-ci/test-radvd.pid'
38 systemd_lib_paths
= [ '/usr/lib/systemd' , '/lib/systemd' ]
39 which_paths
= ':' . join ( systemd_lib_paths
+ os
. getenv ( 'PATH' , os
. defpath
). lstrip ( ':' ). split ( ':' ))
41 networkd_bin
= shutil
. which ( 'systemd-networkd' , path
= which_paths
)
42 resolved_bin
= shutil
. which ( 'systemd-resolved' , path
= which_paths
)
43 timesyncd_bin
= shutil
. which ( 'systemd-timesyncd' , path
= which_paths
)
44 udevd_bin
= shutil
. which ( 'systemd-udevd' , path
= which_paths
)
45 wait_online_bin
= shutil
. which ( 'systemd-networkd-wait-online' , path
= which_paths
)
46 networkctl_bin
= shutil
. which ( 'networkctl' , path
= which_paths
)
47 resolvectl_bin
= shutil
. which ( 'resolvectl' , path
= which_paths
)
48 timedatectl_bin
= shutil
. which ( 'timedatectl' , path
= which_paths
)
49 udevadm_bin
= shutil
. which ( 'udevadm' , path
= which_paths
)
77 saved_ipv4_rules
= None
78 saved_ipv6_rules
= None
82 if os
. path
. exists ( path
):
86 shutil
. rmtree ( path
, ignore_errors
= True )
92 shutil
. copytree ( src
, dst
, copy_function
= shutil
. copy
)
95 os
. makedirs ( path
, exist_ok
= True )
98 pathlib
. Path ( path
). touch ()
100 # pylint: disable=R1710
101 def check_output (* command
, ** kwargs
):
102 # This checks the result and returns stdout (and stderr) on success.
103 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
104 ret
= subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. PIPE
, stderr
= subprocess
. STDOUT
, ** kwargs
)
105 if ret
. returncode
== 0 :
106 return ret
. stdout
. rstrip ()
107 # When returncode != 0, print stdout and stderr, then trigger CalledProcessError.
109 ret
. check_returncode ()
111 def call (* command
, ** kwargs
):
112 # This returns returncode. stdout and stderr are merged and shown in console
113 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
114 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stderr
= subprocess
. STDOUT
, ** kwargs
). returncode
116 def call_check (* command
, ** kwargs
):
117 # Same as call() above, but it triggers CalledProcessError if rc != 0
118 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
119 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stderr
= subprocess
. STDOUT
, ** kwargs
). check_returncode ()
121 def call_quiet (* command
, ** kwargs
):
122 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
123 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. DEVNULL
, stderr
= subprocess
. DEVNULL
, ** kwargs
). returncode
125 def run (* command
, ** kwargs
):
126 # This returns CompletedProcess instance.
127 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
128 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. PIPE
, stderr
= subprocess
. PIPE
, ** kwargs
)
130 def check_json ( string
):
133 except json
. JSONDecodeError
:
134 print ( f
"String is not a valid JSON: ' {string} '" )
137 def is_module_available (* module_names
):
138 for module_name
in module_names
:
139 lsmod_output
= check_output ( 'lsmod' )
140 module_re
= re
. compile ( rf
'^{re.escape(module_name)} \b ' , re
. MULTILINE
)
141 if not module_re
. search ( lsmod_output
) and call_quiet ( 'modprobe' , module_name
) != 0 :
145 def expectedFailureIfModuleIsNotAvailable (* module_names
):
147 return func
if is_module_available (* module_names
) else unittest
. expectedFailure ( func
)
151 def expectedFailureIfERSPANv0IsNotSupported ():
152 # erspan version 0 is supported since f989d546a2d5a9f001f6f8be49d98c10ab9b1897 (v5.8)
154 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' )
155 remove_link ( 'erspan99' )
156 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
160 def expectedFailureIfERSPANv2IsNotSupported ():
161 # erspan version 2 is supported since f551c91de262ba36b20c3ac19538afb4f4507441 (v4.16)
163 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' )
164 remove_link ( 'erspan99' )
165 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
169 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable ():
171 rc
= call_quiet ( 'ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7' )
172 call_quiet ( 'ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7' )
173 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
177 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable ():
179 rc
= call_quiet ( 'ip rule add not from 192.168.100.19 ipproto tcp table 7' )
180 call_quiet ( 'ip rule del not from 192.168.100.19 ipproto tcp table 7' )
181 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
185 def expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable ():
188 if call_quiet ( 'ip rule add from 192.168.100.19 table 7 uidrange 200-300' ) == 0 :
189 ret
= run ( 'ip rule list from 192.168.100.19 table 7' )
190 supported
= ret
. returncode
== 0 and 'uidrange 200-300' in ret
. stdout
191 call_quiet ( 'ip rule del from 192.168.100.19 table 7 uidrange 200-300' )
192 return func
if supported
else unittest
. expectedFailure ( func
)
196 def expectedFailureIfNexthopIsNotAvailable ():
198 rc
= call_quiet ( 'ip nexthop list' )
199 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
203 def expectedFailureIfRTA_VIAIsNotSupported ():
205 call_quiet ( 'ip link add dummy98 type dummy' )
206 call_quiet ( 'ip link set up dev dummy98' )
207 call_quiet ( 'ip route add 2001:1234:5:8fff:ff:ff:ff:fe/128 dev dummy98' )
208 rc
= call_quiet ( 'ip route add 10.10.10.10 via inet6 2001:1234:5:8fff:ff:ff:ff:fe dev dummy98' )
209 remove_link ( 'dummy98' )
210 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
214 def expectedFailureIfAlternativeNameIsNotAvailable ():
216 call_quiet ( 'ip link add dummy98 type dummy' )
218 call_quiet ( 'ip link prop add dev dummy98 altname hogehogehogehogehoge' ) == 0 and \
219 call_quiet ( 'ip link show dev hogehogehogehogehoge' ) == 0
220 remove_link ( 'dummy98' )
221 return func
if supported
else unittest
. expectedFailure ( func
)
225 def expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ():
227 def finalize ( func
, supported
):
228 call_quiet ( 'rmmod netdevsim' )
229 return func
if supported
else unittest
. expectedFailure ( func
)
231 call_quiet ( 'rmmod netdevsim' )
232 if call_quiet ( 'modprobe netdevsim' ) != 0 :
233 return finalize ( func
, False )
236 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
239 return finalize ( func
, False )
241 return finalize ( func
, os
. path
. exists ( '/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs' ))
245 # pylint: disable=C0415
246 def compare_kernel_version ( min_kernel_version
):
249 from packaging
import version
251 print ( 'Failed to import either platform or packaging module, assuming the comparison failed' )
254 # Get only the actual kernel version without any build/distro/arch stuff
255 # e.g. '5.18.5-200.fc36.x86_64' -> '5.18.5'
256 kver
= platform
. release (). split ( '-' )[ 0 ]
258 return version
. parse ( kver
) >= version
. parse ( min_kernel_version
)
261 check_output (* udevadm_cmd
, 'control' , '--reload' )
263 def copy_network_unit (* units
, copy_dropins
= True ):
265 Copy networkd unit files into the testbed.
267 Any networkd unit file type can be specified, as well as drop-in files.
269 By default, all drop-ins for a specified unit file are copied in;
270 to avoid that specify dropins=False.
272 When a drop-in file is specified, its unit file is also copied in automatically.
275 mkdir_p ( network_unit_dir
)
277 if copy_dropins
and os
. path
. exists ( os
. path
. join ( networkd_ci_temp_dir
, unit
+ '.d' )):
278 cp_r ( os
. path
. join ( networkd_ci_temp_dir
, unit
+ '.d' ), os
. path
. join ( network_unit_dir
, unit
+ '.d' ))
280 if unit
. endswith ( '.conf' ):
282 unit
= os
. path
. dirname ( dropin
). rstrip ( '.d' )
283 dropindir
= os
. path
. join ( network_unit_dir
, unit
+ '.d' )
285 cp ( os
. path
. join ( networkd_ci_temp_dir
, dropin
), dropindir
)
287 cp ( os
. path
. join ( networkd_ci_temp_dir
, unit
), network_unit_dir
)
289 if unit
. endswith ( '.link' ):
295 def remove_network_unit (* units
):
297 Remove previously copied unit files from the testbed.
299 Drop-ins will be removed automatically.
303 rm_f ( os
. path
. join ( network_unit_dir
, unit
))
304 rm_rf ( os
. path
. join ( network_unit_dir
, unit
+ '.d' ))
306 if unit
. endswith ( '.link' ) or unit
. endswith ( '.link.d' ):
312 def clear_network_units ():
314 if os
. path
. exists ( network_unit_dir
):
315 units
= os
. listdir ( network_unit_dir
)
317 if unit
. endswith ( '.link' ) or unit
. endswith ( '.link.d' ):
320 rm_rf ( network_unit_dir
)
325 def copy_networkd_conf_dropin (* dropins
):
326 """Copy networkd.conf dropin files into the testbed."""
327 mkdir_p ( networkd_conf_dropin_dir
)
328 for dropin
in dropins
:
329 cp ( os
. path
. join ( networkd_ci_temp_dir
, dropin
), networkd_conf_dropin_dir
)
331 def remove_networkd_conf_dropin (* dropins
):
332 """Remove previously copied networkd.conf dropin files from the testbed."""
333 for dropin
in dropins
:
334 rm_f ( os
. path
. join ( networkd_conf_dropin_dir
, dropin
))
336 def clear_networkd_conf_dropins ():
337 rm_rf ( networkd_conf_dropin_dir
)
339 def copy_udev_rule (* rules
):
340 """Copy udev rules"""
341 mkdir_p ( udev_rules_dir
)
343 cp ( os
. path
. join ( networkd_ci_temp_dir
, rule
), udev_rules_dir
)
345 def remove_udev_rule (* rules
):
346 """Remove previously copied udev rules"""
348 rm_f ( os
. path
. join ( udev_rules_dir
, rule
))
350 def clear_udev_rules ():
351 rm_rf ( udev_rules_dir
)
353 def save_active_units ():
354 for u
in [ 'systemd-networkd.socket' , 'systemd-networkd.service' ,
355 'systemd-resolved.service' , 'systemd-timesyncd.service' ,
356 'firewalld.service' ]:
357 if call ( f
'systemctl is-active --quiet {u} ' ) == 0 :
358 call ( f
'systemctl stop {u} ' )
359 active_units
. append ( u
)
361 def restore_active_units ():
362 if 'systemd-networkd.socket' in active_units
:
363 call ( 'systemctl stop systemd-networkd.socket systemd-networkd.service' )
364 for u
in active_units
:
365 call ( f
'systemctl restart {u} ' )
367 def create_unit_dropin ( unit
, contents
):
368 mkdir_p ( f
'/run/systemd/system/ {unit} .d' )
369 with
open ( f
'/run/systemd/system/ {unit} .d/00-override.conf' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
370 f
. write ( ' \n ' . join ( contents
))
372 def create_service_dropin ( service
, command
, additional_settings
= None ):
376 f
'ExecStart=!! {valgrind_cmd}{command} ' ,
379 drop_in
+= [ 'Environment=SYSTEMD_LOG_LEVEL=debug' ]
381 drop_in
+= [ f
'Environment=ASAN_OPTIONS=" {asan_options} "' ]
383 drop_in
+= [ f
'Environment=LSAN_OPTIONS=" {lsan_options} "' ]
385 drop_in
+= [ f
'Environment=UBSAN_OPTIONS=" {ubsan_options} "' ]
386 if asan_options
or lsan_options
or ubsan_options
:
387 drop_in
+= [ 'SystemCallFilter=' ]
388 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
389 drop_in
+= [ 'MemoryDenyWriteExecute=no' ]
392 'Environment=SYSTEMD_MEMPOOL=0' ,
400 if additional_settings
:
401 drop_in
+= additional_settings
403 create_unit_dropin ( f
' {service} .service' , drop_in
)
405 def link_exists ( link
):
406 return call_quiet ( f
'ip link show {link} ' ) == 0
408 def link_resolve ( link
):
409 return check_output ( f
'ip link show {link} ' ). split ( ':' )[ 1 ]. strip ()
411 def remove_link (* links
, protect
= False ):
413 if protect
and link
in protected_links
:
415 if link_exists ( link
):
416 call ( f
'ip link del dev {link} ' )
418 def save_existing_links ():
419 links
= os
. listdir ( '/sys/class/net' )
421 if link_exists ( link
):
422 protected_links
. add ( link
)
424 print ( '### The following links will be protected:' )
425 print ( ', ' . join ( sorted ( list ( protected_links
))))
428 links
= os
. listdir ( '/sys/class/net' )
429 remove_link (* links
, protect
= True )
431 def flush_nexthops ():
432 # Currently, the 'ip nexthop' command does not have 'save' and 'restore'.
433 # Hence, we cannot restore nexthops in a simple way.
434 # Let's assume there is no nexthop used in the system
435 call_quiet ( 'ip nexthop flush' )
438 # pylint: disable=global-statement
440 saved_routes
= check_output ( 'ip route show table all' )
441 print ( '### The following routes will be protected:' )
446 output
= check_output ( 'ip route show table all' )
447 for line
in output
. splitlines ():
448 if line
in saved_routes
:
450 if 'proto kernel' in line
:
452 if ' dev ' in line
and not ' dev lo ' in line
:
456 print ( '### Removing routes that did not exist when the test started.' )
458 call ( f
'ip route del {line} ' )
460 def save_routing_policy_rules ():
461 # pylint: disable=global-statement
462 global saved_ipv4_rules
, saved_ipv6_rules
464 output
= check_output ( f
'ip - {ipv} rule show' )
465 print ( f
'### The following IPv {ipv} routing policy rules will be protected:' )
469 saved_ipv4_rules
= save ( 4 )
470 saved_ipv6_rules
= save ( 6 )
472 def flush_routing_policy_rules ():
473 def flush ( ipv
, saved_rules
):
475 output
= check_output ( f
'ip - {ipv} rule show' )
476 for line
in output
. splitlines ():
477 if line
in saved_rules
:
481 print ( f
'### Removing IPv {ipv} routing policy rules that did not exist when the test started.' )
483 words
= line
. replace ( 'lookup [l3mdev-table]' , 'l3mdev' ). split ()
484 priority
= words
[ 0 ]. rstrip ( ':' )
485 call ( f
'ip - {ipv} rule del priority {priority} ' + ' ' . join ( words
[ 1 :]))
487 flush ( 4 , saved_ipv4_rules
)
488 flush ( 6 , saved_ipv6_rules
)
490 def flush_fou_ports ():
491 ret
= run ( 'ip fou show' )
492 if ret
. returncode
!= 0 :
493 return # fou may not be supported
494 for line
in ret
. stdout
. splitlines ():
495 port
= line
. split ()[ 1 ]
496 call ( f
'ip fou del port {port} ' )
498 def flush_l2tp_tunnels ():
500 ret
= run ( 'ip l2tp show tunnel' )
501 if ret
. returncode
!= 0 :
502 return # l2tp may not be supported
503 for line
in ret
. stdout
. splitlines ():
505 if words
[ 0 ] == 'Tunnel' :
506 tid
= words
[ 1 ]. rstrip ( ',' )
507 call ( f
'ip l2tp del tunnel tunnel_id {tid} ' )
510 # Removing L2TP tunnel is asynchronous and slightly takes a time.
513 r
= run ( f
'ip l2tp show tunnel tunnel_id {tid} ' )
514 if r
. returncode
!= 0 or len ( r
. stdout
. rstrip ()) == 0 :
518 print ( f
'Cannot remove L2TP tunnel {tid} , ignoring.' )
521 # pylint: disable=global-statement
522 global saved_timezone
523 r
= run (* timedatectl_cmd
, 'show' , '--value' , '--property' , 'Timezone' , env
= env
)
524 if r
. returncode
== 0 :
525 saved_timezone
= r
. stdout
. rstrip ()
526 print ( f
'### Saved timezone: {saved_timezone} ' )
528 def restore_timezone ():
530 call (* timedatectl_cmd
, 'set-timezone' , f
' {saved_timezone} ' , env
= env
)
532 def read_link_attr (* args
):
533 with
open ( os
. path
. join ( '/sys/class/net' , * args
), encoding
= 'utf-8' ) as f
:
534 return f
. readline (). strip ()
536 def read_link_state_file ( link
):
537 ifindex
= read_link_attr ( link
, 'ifindex' )
538 path
= os
. path
. join ( '/run/systemd/netif/links' , ifindex
)
539 with
open ( path
, encoding
= 'utf-8' ) as f
:
542 def read_ip_sysctl_attr ( link
, attribute
, ipv
):
543 with
open ( os
. path
. join ( '/proc/sys/net' , ipv
, 'conf' , link
, attribute
), encoding
= 'utf-8' ) as f
:
544 return f
. readline (). strip ()
546 def read_ipv6_sysctl_attr ( link
, attribute
):
547 return read_ip_sysctl_attr ( link
, attribute
, 'ipv6' )
549 def read_ipv4_sysctl_attr ( link
, attribute
):
550 return read_ip_sysctl_attr ( link
, attribute
, 'ipv4' )
552 def stop_by_pid_file ( pid_file
):
553 if not os
. path
. exists ( pid_file
):
555 with
open ( pid_file
, 'r' , encoding
= 'utf-8' ) as f
:
556 pid
= f
. read (). rstrip ( ' \t\r\n \0' )
557 os
. kill ( int ( pid
), signal
. SIGTERM
)
561 print ( f
"PID {pid} is still alive, waiting..." )
564 if e
. errno
== errno
. ESRCH
:
566 print ( f
"Unexpected exception when waiting for {pid} to die: {e.errno}" )
569 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' ):
572 f
'--log-facility= {dnsmasq_log_file} ' ,
573 '--log-queries=extra' ,
575 f
'--pid-file= {dnsmasq_pid_file} ' ,
576 '--conf-file=/dev/null' ,
578 f
'--interface= {interface} ' ,
579 f
'--dhcp-leasefile= {dnsmasq_lease_file} ' ,
581 f
'--dhcp-range= {ipv6_range} , {lease_time} ' ,
582 f
'--dhcp-range= {ipv4_range} , {lease_time} ' ,
583 '--dhcp-option=option:mtu,1492' ,
584 f
'--dhcp-option=option:router, {ipv4_router} ' ,
587 ) + additional_options
588 check_output (* command
)
591 stop_by_pid_file ( dnsmasq_pid_file
)
592 rm_f ( dnsmasq_lease_file
)
593 rm_f ( dnsmasq_log_file
)
595 def read_dnsmasq_log_file ():
596 with
open ( dnsmasq_log_file
, encoding
= 'utf-8' ) as f
:
599 def start_isc_dhcpd ( conf_file
, ipv
, interface
= 'veth-peer' ):
600 conf_file_path
= os
. path
. join ( networkd_ci_temp_dir
, conf_file
)
601 isc_dhcpd_command
= f
'dhcpd {ipv} -cf {conf_file_path} -lf {isc_dhcpd_lease_file} -pf {isc_dhcpd_pid_file} {interface} '
602 touch ( isc_dhcpd_lease_file
)
603 check_output ( isc_dhcpd_command
)
605 def stop_isc_dhcpd ():
606 stop_by_pid_file ( isc_dhcpd_pid_file
)
607 rm_f ( isc_dhcpd_lease_file
)
609 def start_radvd (* additional_options
, config_file
):
610 config_file_path
= os
. path
. join ( networkd_ci_temp_dir
, 'radvd' , config_file
)
613 f
'--pidfile= {radvd_pid_file} ' ,
614 f
'--config= {config_file_path} ' ,
615 '--logmethod=stderr' ,
616 ) + additional_options
617 check_output (* command
)
620 stop_by_pid_file ( radvd_pid_file
)
622 def radvd_check_config ( config_file
):
623 if not shutil
. which ( 'radvd' ):
624 print ( 'radvd is not installed, assuming the config check failed' )
627 # Note: can't use networkd_ci_temp_dir here, as this command may run before that dir is
628 # set up (one instance is @unittest.skipX())
629 config_file_path
= os
. path
. join ( os
. path
. dirname ( os
. path
. abspath ( __file__
)), 'conf/radvd' , config_file
)
630 return call ( f
'radvd --config= {config_file_path} --configtest' ) == 0
632 def networkd_invocation_id ():
633 return check_output ( 'systemctl show --value -p InvocationID systemd-networkd.service' )
635 def read_networkd_log ( invocation_id
= None ):
636 if not invocation_id
:
637 invocation_id
= networkd_invocation_id ()
638 return check_output ( 'journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
)
640 def stop_networkd ( show_logs
= True ):
642 invocation_id
= networkd_invocation_id ()
643 check_output ( 'systemctl stop systemd-networkd.socket' )
644 check_output ( 'systemctl stop systemd-networkd.service' )
646 print ( read_networkd_log ( invocation_id
))
648 def start_networkd ():
649 check_output ( 'systemctl start systemd-networkd' )
651 def restart_networkd ( show_logs
= True ):
653 invocation_id
= networkd_invocation_id ()
654 check_output ( 'systemctl restart systemd-networkd.service' )
656 print ( read_networkd_log ( invocation_id
))
659 return int ( check_output ( 'systemctl show --value -p MainPID systemd-networkd.service' ))
661 def networkctl_reconfigure (* links
):
662 check_output (* networkctl_cmd
, 'reconfigure' , * links
, env
= env
)
664 def networkctl_reload ( sleep_time
= 1 ):
665 check_output (* networkctl_cmd
, 'reload' , env
= env
)
666 # 'networkctl reload' asynchronously reconfigure links.
667 # Hence, we need to wait for a short time for link to be in configuring state.
669 time
. sleep ( sleep_time
)
674 def tear_down_common ():
675 # 1. stop DHCP/RA servers
681 call_quiet ( 'rmmod netdevsim' )
682 call_quiet ( 'rmmod sch_teql' )
684 # 3. remove network namespace
685 call_quiet ( 'ip netns del ns99' )
695 clear_network_units ()
696 clear_networkd_conf_dropins ()
701 flush_routing_policy_rules ()
705 rm_rf ( networkd_ci_temp_dir
)
706 cp_r ( os
. path
. join ( os
. path
. dirname ( os
. path
. abspath ( __file__
)), 'conf' ), networkd_ci_temp_dir
)
708 clear_network_units ()
709 clear_networkd_conf_dropins ()
712 copy_udev_rule ( '00-debug-net.rules' )
716 save_existing_links ()
718 save_routing_policy_rules ()
721 create_service_dropin ( 'systemd-networkd' , networkd_bin
,
722 [ '[Service]' , 'Restart=no' , '[Unit]' , 'StartLimitIntervalSec=0' ])
723 create_service_dropin ( 'systemd-resolved' , resolved_bin
)
724 create_service_dropin ( 'systemd-timesyncd' , timesyncd_bin
)
726 # TODO: also run udevd with sanitizers, valgrind, or coverage
727 #create_service_dropin('systemd-udevd', udevd_bin,
728 # f'{udevadm_bin} control --reload --timeout 0')
730 'systemd-udevd.service' ,
734 f
'ExecStart=!!@ {udevd_bin} systemd-udevd' ,
738 'systemd-networkd.socket' ,
741 'StartLimitIntervalSec=0' ,
745 check_output ( 'systemctl daemon-reload' )
746 print ( check_output ( 'systemctl cat systemd-networkd.service' ))
747 print ( check_output ( 'systemctl cat systemd-resolved.service' ))
748 print ( check_output ( 'systemctl cat systemd-timesyncd.service' ))
749 print ( check_output ( 'systemctl cat systemd-udevd.service' ))
750 check_output ( 'systemctl restart systemd-resolved.service' )
751 check_output ( 'systemctl restart systemd-timesyncd.service' )
752 check_output ( 'systemctl restart systemd-udevd.service' )
754 def tearDownModule ():
755 rm_rf ( networkd_ci_temp_dir
)
757 clear_network_units ()
758 clear_networkd_conf_dropins ()
762 rm_rf ( '/run/systemd/system/systemd-networkd.service.d' )
763 rm_rf ( '/run/systemd/system/systemd-networkd.socket.d' )
764 rm_rf ( '/run/systemd/system/systemd-resolved.service.d' )
765 rm_rf ( '/run/systemd/system/systemd-timesyncd.service.d' )
766 rm_rf ( '/run/systemd/system/systemd-udevd.service.d' )
767 check_output ( 'systemctl daemon-reload' )
768 check_output ( 'systemctl restart systemd-udevd.service' )
769 restore_active_units ()
772 # pylint: disable=no-member
774 def check_link_exists ( self
, link
, expected
= True ):
776 self
. assertTrue ( link_exists ( link
))
778 self
. assertFalse ( link_exists ( link
))
780 def check_link_attr ( self
, * args
):
781 self
. assertEqual ( read_link_attr (* args
[:- 1 ]), args
[- 1 ])
783 def check_bridge_port_attr ( self
, master
, port
, attribute
, expected
, allow_enoent
= False ):
784 path
= os
. path
. join ( '/sys/devices/virtual/net' , master
, 'lower_' + port
, 'brport' , attribute
)
785 if allow_enoent
and not os
. path
. exists ( path
):
787 with
open ( path
, encoding
= 'utf-8' ) as f
:
788 self
. assertEqual ( f
. readline (). strip (), expected
)
790 def check_ipv4_sysctl_attr ( self
, link
, attribute
, expected
):
791 self
. assertEqual ( read_ipv4_sysctl_attr ( link
, attribute
), expected
)
793 def check_ipv6_sysctl_attr ( self
, link
, attribute
, expected
):
794 self
. assertEqual ( read_ipv6_sysctl_attr ( link
, attribute
), expected
)
796 def wait_links ( self
, * links
, timeout
= 20 , fail_assert
= True ):
797 def links_exist (* links
):
799 if not link_exists ( link
):
803 for iteration
in range ( timeout
+ 1 ):
807 if links_exist (* links
):
810 self
. fail ( 'Timed out waiting for all links to be created: ' + ', ' . join ( list ( links
)))
813 def wait_activated ( self
, link
, state
= 'down' , timeout
= 20 , fail_assert
= True ):
814 # wait for the interface is activated.
815 invocation_id
= check_output ( 'systemctl show systemd-networkd -p InvocationID --value' )
816 needle
= f
' {link} : Bringing link {state} '
818 for iteration
in range ( timeout
+ 1 ):
821 if not link_exists ( link
):
823 output
= check_output ( 'journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
)
824 if needle
in output
and flag
in check_output ( f
'ip link show {link} ' ):
827 self
. fail ( f
'Timed out waiting for {link} activated.' )
830 def wait_operstate ( self
, link
, operstate
= 'degraded' , setup_state
= 'configured' , setup_timeout
= 5 , fail_assert
= True ):
831 """Wait for the link to reach the specified operstate and/or setup state.
833 Specify None or '' for either operstate or setup_state to ignore that state.
834 This will recheck until the state conditions are met or the timeout expires.
836 If the link successfully matches the requested state, this returns True.
837 If this times out waiting for the link to match, the behavior depends on the
838 'fail_assert' parameter; if True, this causes a test assertion failure,
839 otherwise this returns False. The default is to cause assertion failure.
841 Note that this function matches on *exactly* the given operstate and setup_state.
842 To wait for a link to reach *or exceed* a given operstate, use wait_online().
849 for secs
in range ( setup_timeout
+ 1 ):
852 if not link_exists ( link
):
854 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , link
, env
= env
)
855 if re
. search ( rf
'(?m)^\s*State:\s+ {operstate} \s+\( {setup_state} \)\s*$' , output
):
859 self
. fail ( f
'Timed out waiting for {link} to reach state {operstate} / {setup_state} ' )
862 def wait_online ( self
, links_with_operstate
, timeout
= '20s' , bool_any
= False , ipv4
= False , ipv6
= False , setup_state
= 'configured' , setup_timeout
= 5 ):
863 """Wait for the links to reach the specified operstate and/or setup state.
865 This is similar to wait_operstate() but can be used for multiple links,
866 and it also calls systemd-networkd-wait-online to wait for the given operstate.
867 The operstate should be specified in the link name, like 'eth0:degraded'.
868 If just a link name is provided, wait-online's default operstate to wait for is degraded.
870 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
871 'setup_timeout' controls the per-link timeout waiting for the setup_state.
873 Set 'bool_any' to True to wait for any (instead of all) of the given links.
874 If this is set, no setup_state checks are done.
876 Set 'ipv4' or 'ipv6' to True to wait for IPv4 address or IPv6 address, respectively, of each of the given links.
877 This is applied only for the operational state 'degraded' or above.
879 Note that this function waits for the links to reach *or exceed* the given operstate.
880 However, the setup_state, if specified, must be matched *exactly*.
882 This returns if the links reached the requested operstate/setup_state; otherwise it
883 raises CalledProcessError or fails test assertion.
885 args
= wait_online_cmd
+ [ f
'--timeout= {timeout} ' ] + [ f
'--interface= {link} ' for link
in links_with_operstate
] + [ f
'--ignore= {link} ' for link
in protected_links
]
893 check_output (* args
, env
= wait_online_env
)
894 except subprocess
. CalledProcessError
:
895 # show detailed status on failure
896 for link
in links_with_operstate
:
897 name
= link
. split ( ':' )[ 0 ]
898 if link_exists ( name
):
899 call (* networkctl_cmd
, '-n' , '0' , 'status' , name
, env
= env
)
901 if not bool_any
and setup_state
:
902 for link
in links_with_operstate
:
903 self
. wait_operstate ( link
. split ( ':' )[ 0 ], None , setup_state
, setup_timeout
)
905 def wait_address ( self
, link
, address_regex
, scope
= 'global' , ipv
= '' , timeout_sec
= 100 ):
906 for i
in range ( timeout_sec
):
909 output
= check_output ( f
'ip {ipv} address show dev {link} scope {scope} ' )
910 if re
. search ( address_regex
, output
) and 'tentative' not in output
:
913 self
. assertRegex ( output
, address_regex
)
915 def wait_address_dropped ( self
, link
, address_regex
, scope
= 'global' , ipv
= '' , timeout_sec
= 100 ):
916 for i
in range ( timeout_sec
):
919 output
= check_output ( f
'ip {ipv} address show dev {link} scope {scope} ' )
920 if not re
. search ( address_regex
, output
):
923 self
. assertNotRegex ( output
, address_regex
)
925 def wait_route ( self
, link
, route_regex
, table
= 'main' , ipv
= '' , timeout_sec
= 100 ):
926 for i
in range ( timeout_sec
):
929 output
= check_output ( f
'ip {ipv} route show dev {link} table {table} ' )
930 if re
. search ( route_regex
, output
):
933 self
. assertRegex ( output
, route_regex
)
935 def check_netlabel ( self
, interface
, address
, label
= 'system_u:object_r:root_t:s0' ):
936 if not shutil
. which ( 'selinuxenabled' ):
937 print ( '## Checking NetLabel skipped: selinuxenabled command not found.' )
938 elif call_quiet ( 'selinuxenabled' ) != 0 :
939 print ( '## Checking NetLabel skipped: SELinux disabled.' )
940 elif not shutil
. which ( 'netlabelctl' ): # not packaged by all distros
941 print ( '## Checking NetLabel skipped: netlabelctl command not found.' )
943 output
= check_output ( 'netlabelctl unlbl list' )
945 self
. assertRegex ( output
, f
'interface: {interface} ,address: {address} ,label:" {label} "' )
947 class NetworkctlTests ( unittest
. TestCase
, Utilities
):
955 @expectedFailureIfAlternativeNameIsNotAvailable ()
956 def test_altname ( self
):
957 copy_network_unit ( '26-netdev-link-local-addressing-yes.network' , '12-dummy.netdev' , '12-dummy.link' )
959 self
. wait_online ([ 'dummy98:degraded' ])
961 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
962 self
. assertRegex ( output
, 'hogehogehogehogehogehoge' )
964 @expectedFailureIfAlternativeNameIsNotAvailable ()
965 def test_rename_to_altname ( self
):
966 copy_network_unit ( '26-netdev-link-local-addressing-yes.network' ,
967 '12-dummy.netdev' , '12-dummy-rename-to-altname.link' )
969 self
. wait_online ([ 'dummyalt:degraded' ])
971 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummyalt' , env
= env
)
972 self
. assertIn ( 'hogehogehogehogehogehoge' , output
)
973 self
. assertNotIn ( 'dummy98' , output
)
975 def test_reconfigure ( self
):
976 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' )
978 self
. wait_online ([ 'dummy98:routable' ])
980 output
= check_output ( 'ip -4 address show dev dummy98' )
982 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
983 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
984 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
986 check_output ( 'ip address del 10.1.2.3/16 dev dummy98' )
987 check_output ( 'ip address del 10.1.2.4/16 dev dummy98' )
988 check_output ( 'ip address del 10.2.2.4/16 dev dummy98' )
990 networkctl_reconfigure ( 'dummy98' )
991 self
. wait_online ([ 'dummy98:routable' ])
993 output
= check_output ( 'ip -4 address show dev dummy98' )
995 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
996 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
997 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
999 remove_network_unit ( '25-address-static.network' )
1002 self
. wait_operstate ( 'dummy98' , 'degraded' , setup_state
= 'unmanaged' )
1004 output
= check_output ( 'ip -4 address show dev dummy98' )
1006 self
. assertNotIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
1007 self
. assertNotIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
1008 self
. assertNotIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
1010 copy_network_unit ( '25-address-static.network' )
1012 self
. wait_online ([ 'dummy98:routable' ])
1014 output
= check_output ( 'ip -4 address show dev dummy98' )
1016 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
1017 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
1018 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
1020 def test_renew ( self
):
1022 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
1023 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
1025 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
1026 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
1027 self
. assertRegex ( output
, 'DNS: 192.168.5.1 \n *192.168.5.10' )
1028 self
. assertRegex ( output
, 'NTP: 192.168.5.1 \n *192.168.5.11' )
1030 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server.network' )
1033 output
= check_output (* networkctl_cmd
, '--lines=0' , '--stats' , '--all' , '--full' , '--json=short' , 'status' )
1036 for verb
in [ 'renew' , 'forcerenew' ]:
1037 call_check (* networkctl_cmd
, verb
, 'veth99' )
1039 call_check (* networkctl_cmd
, verb
, 'veth99' , 'veth99' , 'veth99' )
1042 def test_up_down ( self
):
1043 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' )
1045 self
. wait_online ([ 'dummy98:routable' ])
1047 call_check (* networkctl_cmd
, 'down' , 'dummy98' )
1048 self
. wait_online ([ 'dummy98:off' ])
1049 call_check (* networkctl_cmd
, 'up' , 'dummy98' )
1050 self
. wait_online ([ 'dummy98:routable' ])
1051 call_check (* networkctl_cmd
, 'down' , 'dummy98' , 'dummy98' , 'dummy98' )
1052 self
. wait_online ([ 'dummy98:off' ])
1053 call_check (* networkctl_cmd
, 'up' , 'dummy98' , 'dummy98' , 'dummy98' )
1054 self
. wait_online ([ 'dummy98:routable' ])
1056 def test_reload ( self
):
1059 copy_network_unit ( '11-dummy.netdev' )
1061 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'unmanaged' )
1063 copy_network_unit ( '11-dummy.network' )
1065 self
. wait_online ([ 'test1:degraded' ])
1067 remove_network_unit ( '11-dummy.network' )
1069 self
. wait_operstate ( 'test1' , 'degraded' , setup_state
= 'unmanaged' )
1071 remove_network_unit ( '11-dummy.netdev' )
1073 self
. wait_operstate ( 'test1' , 'degraded' , setup_state
= 'unmanaged' )
1075 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1077 self
. wait_operstate ( 'test1' , 'degraded' )
1079 def test_glob ( self
):
1080 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1083 self
. wait_online ([ 'test1:degraded' ])
1085 output
= check_output (* networkctl_cmd
, 'list' , env
= env
)
1086 self
. assertRegex ( output
, '1 lo ' )
1087 self
. assertRegex ( output
, 'test1' )
1089 output
= check_output (* networkctl_cmd
, 'list' , 'test1' , env
= env
)
1090 self
. assertNotRegex ( output
, '1 lo ' )
1091 self
. assertRegex ( output
, 'test1' )
1093 output
= check_output (* networkctl_cmd
, 'list' , 'te*' , env
= env
)
1094 self
. assertNotRegex ( output
, '1 lo ' )
1095 self
. assertRegex ( output
, 'test1' )
1097 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'te*' , env
= env
)
1098 self
. assertNotRegex ( output
, '1: lo ' )
1099 self
. assertRegex ( output
, 'test1' )
1101 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'tes[a-z][0-9]' , env
= env
)
1102 self
. assertNotRegex ( output
, '1: lo ' )
1103 self
. assertRegex ( output
, 'test1' )
1106 copy_network_unit ( '11-dummy-mtu.netdev' , '11-dummy.network' )
1109 self
. wait_online ([ 'test1:degraded' ])
1111 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
1112 self
. assertRegex ( output
, 'MTU: 1600' )
1114 def test_type ( self
):
1115 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1117 self
. wait_online ([ 'test1:degraded' ])
1119 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
1121 self
. assertRegex ( output
, 'Type: ether' )
1123 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'lo' , env
= env
)
1125 self
. assertRegex ( output
, 'Type: loopback' )
1127 def test_udev_link_file ( self
):
1128 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' , '25-default.link' )
1130 self
. wait_online ([ 'test1:degraded' ])
1132 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
1134 self
. assertRegex ( output
, r
'Link File: /run/systemd/network/25-default.link' )
1135 self
. assertRegex ( output
, r
'Network File: /run/systemd/network/11-dummy.network' )
1137 # This test may be run on the system that has older udevd than 70f32a260b5ebb68c19ecadf5d69b3844896ba55 (v249).
1138 # In that case, the udev DB for the loopback network interface may already have ID_NET_LINK_FILE property.
1139 # Let's reprocess the interface and drop the property.
1140 check_output (* udevadm_cmd
, 'trigger' , '--settle' , '--action=add' , '/sys/class/net/lo' )
1141 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'lo' , env
= env
)
1143 self
. assertRegex ( output
, r
'Link File: n/a' )
1144 self
. assertRegex ( output
, r
'Network File: n/a' )
1146 def test_delete_links ( self
):
1147 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' ,
1148 '25-veth.netdev' , '26-netdev-link-local-addressing-yes.network' )
1151 self
. wait_online ([ 'test1:degraded' , 'veth99:degraded' , 'veth-peer:degraded' ])
1153 check_output (* networkctl_cmd
, 'delete' , 'test1' , 'veth99' , env
= env
)
1154 self
. check_link_exists ( 'test1' , expected
= False )
1155 self
. check_link_exists ( 'veth99' , expected
= False )
1156 self
. check_link_exists ( 'veth-peer' , expected
= False )
1158 def test_label ( self
):
1159 call_check (* networkctl_cmd
, 'label' )
1161 class NetworkdMatchTests ( unittest
. TestCase
, Utilities
):
1169 @expectedFailureIfAlternativeNameIsNotAvailable ()
1170 def test_match ( self
):
1171 copy_network_unit ( '12-dummy-mac.netdev' ,
1172 '12-dummy-match-mac-01.network' ,
1173 '12-dummy-match-mac-02.network' ,
1174 '12-dummy-match-renamed.network' ,
1175 '12-dummy-match-altname.network' ,
1176 '12-dummy-altname.link' )
1179 self
. wait_online ([ 'dummy98:routable' ])
1180 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
1181 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-mac-01.network' , output
)
1182 output
= check_output ( 'ip -4 address show dev dummy98' )
1183 self
. assertIn ( '10.0.0.1/16' , output
)
1185 check_output ( 'ip link set dev dummy98 down' )
1186 check_output ( 'ip link set dev dummy98 address 12:34:56:78:9a:02' )
1188 self
. wait_address ( 'dummy98' , '10.0.0.2/16' , ipv
= '-4' , timeout_sec
= 10 )
1189 self
. wait_online ([ 'dummy98:routable' ])
1190 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
1191 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-mac-02.network' , output
)
1193 check_output ( 'ip link set dev dummy98 down' )
1194 check_output ( 'ip link set dev dummy98 name dummy98-1' )
1196 self
. wait_address ( 'dummy98-1' , '10.0.1.2/16' , ipv
= '-4' , timeout_sec
= 10 )
1197 self
. wait_online ([ 'dummy98-1:routable' ])
1198 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98-1' , env
= env
)
1199 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-renamed.network' , output
)
1201 check_output ( 'ip link set dev dummy98-1 down' )
1202 check_output ( 'ip link set dev dummy98-1 name dummy98-2' )
1203 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '/sys/class/net/dummy98-2' )
1205 self
. wait_address ( 'dummy98-2' , '10.0.2.2/16' , ipv
= '-4' , timeout_sec
= 10 )
1206 self
. wait_online ([ 'dummy98-2:routable' ])
1207 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98-2' , env
= env
)
1208 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-altname.network' , output
)
1210 def test_match_udev_property ( self
):
1211 copy_network_unit ( '12-dummy.netdev' , '13-not-match-udev-property.network' , '14-match-udev-property.network' )
1213 self
. wait_online ([ 'dummy98:routable' ])
1215 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
1217 self
. assertRegex ( output
, 'Network File: /run/systemd/network/14-match-udev-property' )
1219 class WaitOnlineTests ( unittest
. TestCase
, Utilities
):
1227 def test_wait_online_any ( self
):
1228 copy_network_unit ( '25-bridge.netdev' , '25-bridge.network' , '11-dummy.netdev' , '11-dummy.network' )
1231 self
. wait_online ([ 'bridge99' , 'test1:degraded' ], bool_any
= True )
1233 self
. wait_operstate ( 'bridge99' , '(off|no-carrier)' , setup_state
= 'configuring' )
1234 self
. wait_operstate ( 'test1' , 'degraded' )
1236 class NetworkdNetDevTests ( unittest
. TestCase
, Utilities
):
1244 def test_dropin_and_name_conflict ( self
):
1245 copy_network_unit ( '10-dropin-test.netdev' , '15-name-conflict-test.netdev' )
1248 self
. wait_online ([ 'dropin-test:off' ], setup_state
= 'unmanaged' )
1250 output
= check_output ( 'ip link show dropin-test' )
1252 self
. assertRegex ( output
, '00:50:56:c0:00:28' )
1254 @expectedFailureIfModuleIsNotAvailable ( 'bareudp' )
1255 def test_bareudp ( self
):
1256 copy_network_unit ( '25-bareudp.netdev' , '26-netdev-link-local-addressing-yes.network' )
1259 self
. wait_online ([ 'bareudp99:degraded' ])
1261 output
= check_output ( 'ip -d link show bareudp99' )
1263 self
. assertRegex ( output
, 'dstport 1000 ' )
1264 self
. assertRegex ( output
, 'ethertype ip ' )
1266 @expectedFailureIfModuleIsNotAvailable ( 'batman-adv' )
1267 def test_batadv ( self
):
1268 copy_network_unit ( '25-batadv.netdev' , '26-netdev-link-local-addressing-yes.network' )
1271 self
. wait_online ([ 'batadv99:degraded' ])
1273 output
= check_output ( 'ip -d link show batadv99' )
1275 self
. assertRegex ( output
, 'batadv' )
1277 def test_bridge ( self
):
1278 copy_network_unit ( '25-bridge.netdev' , '25-bridge-configure-without-carrier.network' )
1281 self
. wait_online ([ 'bridge99:no-carrier' ])
1283 tick
= os
. sysconf ( 'SC_CLK_TCK' )
1284 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'hello_time' )) / tick
))
1285 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'max_age' )) / tick
))
1286 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'forward_delay' )) / tick
))
1287 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'ageing_time' )) / tick
))
1288 self
. assertEqual ( 9 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'priority' )))
1289 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_querier' )))
1290 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_snooping' )))
1291 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'stp_state' )))
1292 self
. assertEqual ( 3 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_igmp_version' )))
1294 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bridge99' , env
= env
)
1296 self
. assertRegex ( output
, 'Priority: 9' )
1297 self
. assertRegex ( output
, 'STP: yes' )
1298 self
. assertRegex ( output
, 'Multicast IGMP Version: 3' )
1300 output
= check_output ( 'ip -d link show bridge99' )
1302 self
. assertIn ( 'vlan_filtering 1 ' , output
)
1303 self
. assertIn ( 'vlan_protocol 802.1ad ' , output
)
1304 self
. assertIn ( 'vlan_default_pvid 9 ' , output
)
1306 def test_bond ( self
):
1307 copy_network_unit ( '25-bond.netdev' , '25-bond-balanced-tlb.netdev' )
1310 self
. wait_online ([ 'bond99:off' , 'bond98:off' ], setup_state
= 'unmanaged' )
1312 self
. check_link_attr ( 'bond99' , 'bonding' , 'mode' , '802.3ad 4' )
1313 self
. check_link_attr ( 'bond99' , 'bonding' , 'xmit_hash_policy' , 'layer3+4 1' )
1314 self
. check_link_attr ( 'bond99' , 'bonding' , 'miimon' , '1000' )
1315 self
. check_link_attr ( 'bond99' , 'bonding' , 'lacp_rate' , 'fast 1' )
1316 self
. check_link_attr ( 'bond99' , 'bonding' , 'updelay' , '2000' )
1317 self
. check_link_attr ( 'bond99' , 'bonding' , 'downdelay' , '2000' )
1318 self
. check_link_attr ( 'bond99' , 'bonding' , 'resend_igmp' , '4' )
1319 self
. check_link_attr ( 'bond99' , 'bonding' , 'min_links' , '1' )
1320 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_actor_sys_prio' , '1218' )
1321 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_user_port_key' , '811' )
1322 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_actor_system' , '00:11:22:33:44:55' )
1324 self
. check_link_attr ( 'bond98' , 'bonding' , 'mode' , 'balance-tlb 5' )
1325 self
. check_link_attr ( 'bond98' , 'bonding' , 'tlb_dynamic_lb' , '1' )
1327 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bond99' , env
= env
)
1329 self
. assertIn ( 'Mode: 802.3ad' , output
)
1330 self
. assertIn ( 'Miimon: 1s' , output
)
1331 self
. assertIn ( 'Updelay: 2s' , output
)
1332 self
. assertIn ( 'Downdelay: 2s' , output
)
1334 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bond98' , env
= env
)
1336 self
. assertIn ( 'Mode: balance-tlb' , output
)
1338 def test_vlan ( self
):
1339 copy_network_unit ( '21-vlan.netdev' , '11-dummy.netdev' ,
1340 '21-vlan.network' , '21-vlan-test1.network' )
1343 self
. wait_online ([ 'test1:degraded' , 'vlan99:routable' ])
1345 output
= check_output ( 'ip -d link show test1' )
1347 self
. assertRegex ( output
, ' mtu 2000 ' )
1349 output
= check_output ( 'ip -d link show vlan99' )
1351 self
. assertIn ( ' mtu 2000 ' , output
)
1352 self
. assertIn ( 'REORDER_HDR' , output
)
1353 self
. assertIn ( 'LOOSE_BINDING' , output
)
1354 self
. assertIn ( 'GVRP' , output
)
1355 self
. assertIn ( 'MVRP' , output
)
1356 self
. assertIn ( ' id 99 ' , output
)
1357 self
. assertIn ( 'ingress-qos-map { 4:100 7:13 }' , output
)
1358 self
. assertIn ( 'egress-qos-map { 0:1 1:3 6:6 7:7 10:3 }' , output
)
1360 output
= check_output ( 'ip -4 address show dev test1' )
1362 self
. assertRegex ( output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1' )
1363 self
. assertRegex ( output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1' )
1365 output
= check_output ( 'ip -4 address show dev vlan99' )
1367 self
. assertRegex ( output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99' )
1369 def test_vlan_on_bond ( self
):
1370 # For issue #24377 (https://github.com/systemd/systemd/issues/24377),
1371 # which is fixed by b05e52000b4eee764b383cc3031da0a3739e996e (PR#24020).
1373 copy_network_unit ( '21-bond-802.3ad.netdev' , '21-bond-802.3ad.network' ,
1374 '21-vlan-on-bond.netdev' , '21-vlan-on-bond.network' )
1376 self
. wait_online ([ 'bond99:off' ])
1377 self
. wait_operstate ( 'vlan99' , operstate
= 'off' , setup_state
= 'configuring' , setup_timeout
= 10 )
1379 # The commit b05e52000b4eee764b383cc3031da0a3739e996e adds ", ignoring". To make it easily confirmed
1380 # that the issue is fixed by the commit, let's allow to match both string.
1381 log_re
= re
. compile ( 'vlan99: Could not bring up interface(, ignoring|): Network is down$' , re
. MULTILINE
)
1385 if log_re
. search ( read_networkd_log ()):
1390 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '21-dummy-bond-slave.network' )
1392 self
. wait_online ([ 'test1:enslaved' , 'dummy98:enslaved' , 'bond99:carrier' , 'vlan99:routable' ])
1394 def test_macvtap ( self
):
1396 for mode
in [ 'private' , 'vepa' , 'bridge' , 'passthru' ]:
1402 print ( f
'### test_macvtap(mode= {mode} )' )
1403 with self
. subTest ( mode
= mode
):
1404 copy_network_unit ( '21-macvtap.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1405 '11-dummy.netdev' , '25-macvtap.network' )
1406 with
open ( os
. path
. join ( network_unit_dir
, '21-macvtap.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1407 f
. write ( '[MACVTAP] \n Mode=' + mode
)
1410 self
. wait_online ([ 'macvtap99:degraded' ,
1411 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1413 output
= check_output ( 'ip -d link show macvtap99' )
1415 self
. assertRegex ( output
, 'macvtap mode ' + mode
+ ' ' )
1417 def test_macvlan ( self
):
1419 for mode
in [ 'private' , 'vepa' , 'bridge' , 'passthru' ]:
1425 print ( f
'### test_macvlan(mode= {mode} )' )
1426 with self
. subTest ( mode
= mode
):
1427 copy_network_unit ( '21-macvlan.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1428 '11-dummy.netdev' , '25-macvlan.network' )
1429 with
open ( os
. path
. join ( network_unit_dir
, '21-macvlan.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1430 f
. write ( '[MACVLAN] \n Mode=' + mode
)
1433 self
. wait_online ([ 'macvlan99:degraded' ,
1434 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1436 output
= check_output ( 'ip -d link show test1' )
1438 self
. assertRegex ( output
, ' mtu 2000 ' )
1440 output
= check_output ( 'ip -d link show macvlan99' )
1442 self
. assertRegex ( output
, ' mtu 2000 ' )
1443 self
. assertRegex ( output
, 'macvlan mode ' + mode
+ ' ' )
1445 remove_link ( 'test1' )
1448 check_output ( "ip link add test1 type dummy" )
1449 self
. wait_online ([ 'macvlan99:degraded' ,
1450 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1452 output
= check_output ( 'ip -d link show test1' )
1454 self
. assertRegex ( output
, ' mtu 2000 ' )
1456 output
= check_output ( 'ip -d link show macvlan99' )
1458 self
. assertRegex ( output
, ' mtu 2000 ' )
1459 self
. assertRegex ( output
, 'macvlan mode ' + mode
+ ' ' )
1461 @expectedFailureIfModuleIsNotAvailable ( 'ipvlan' )
1462 def test_ipvlan ( self
):
1464 for mode
, flag
in [[ 'L2' , 'private' ], [ 'L3' , 'vepa' ], [ 'L3S' , 'bridge' ]]:
1470 print ( f
'### test_ipvlan(mode= {mode} , flag= {flag} )' )
1471 with self
. subTest ( mode
= mode
, flag
= flag
):
1472 copy_network_unit ( '25-ipvlan.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1473 '11-dummy.netdev' , '25-ipvlan.network' )
1474 with
open ( os
. path
. join ( network_unit_dir
, '25-ipvlan.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1475 f
. write ( '[IPVLAN] \n Mode=' + mode
+ ' \n Flags=' + flag
)
1478 self
. wait_online ([ 'ipvlan99:degraded' , 'test1:degraded' ])
1480 output
= check_output ( 'ip -d link show ipvlan99' )
1482 self
. assertRegex ( output
, 'ipvlan *mode ' + mode
. lower () + ' ' + flag
)
1484 @expectedFailureIfModuleIsNotAvailable ( 'ipvtap' )
1485 def test_ipvtap ( self
):
1487 for mode
, flag
in [[ 'L2' , 'private' ], [ 'L3' , 'vepa' ], [ 'L3S' , 'bridge' ]]:
1493 print ( f
'### test_ipvtap(mode= {mode} , flag= {flag} )' )
1494 with self
. subTest ( mode
= mode
, flag
= flag
):
1495 copy_network_unit ( '25-ipvtap.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1496 '11-dummy.netdev' , '25-ipvtap.network' )
1497 with
open ( os
. path
. join ( network_unit_dir
, '25-ipvtap.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1498 f
. write ( '[IPVTAP] \n Mode=' + mode
+ ' \n Flags=' + flag
)
1501 self
. wait_online ([ 'ipvtap99:degraded' , 'test1:degraded' ])
1503 output
= check_output ( 'ip -d link show ipvtap99' )
1505 self
. assertRegex ( output
, 'ipvtap *mode ' + mode
. lower () + ' ' + flag
)
1507 def test_veth ( self
):
1508 copy_network_unit ( '25-veth.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1509 '25-veth-mtu.netdev' )
1512 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:degraded' , 'veth-mtu:degraded' , 'veth-mtu-peer:degraded' ])
1514 output
= check_output ( 'ip -d link show veth99' )
1516 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bc' )
1517 output
= check_output ( 'ip -d link show veth-peer' )
1519 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bd' )
1521 output
= check_output ( 'ip -d link show veth-mtu' )
1523 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:be' )
1524 self
. assertRegex ( output
, 'mtu 1800' )
1525 output
= check_output ( 'ip -d link show veth-mtu-peer' )
1527 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bf' )
1528 self
. assertRegex ( output
, 'mtu 1800' )
1530 def test_tuntap ( self
):
1531 copy_network_unit ( '25-tun.netdev' , '25-tap.netdev' , '26-netdev-link-local-addressing-yes.network' )
1534 self
. wait_online ([ 'testtun99:degraded' , 'testtap99:degraded' ])
1536 pid
= networkd_pid ()
1537 name
= psutil
. Process ( pid
). name ()[: 15 ]
1539 output
= check_output ( 'ip -d tuntap show' )
1541 self
. assertRegex ( output
, fr
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1542 self
. assertRegex ( output
, fr
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1544 output
= check_output ( 'ip -d link show testtun99' )
1546 # Old ip command does not support IFF_ flags
1547 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1548 self
. assertIn ( 'UP,LOWER_UP' , output
)
1550 output
= check_output ( 'ip -d link show testtap99' )
1552 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1553 self
. assertIn ( 'UP,LOWER_UP' , output
)
1555 remove_network_unit ( '26-netdev-link-local-addressing-yes.network' )
1558 self
. wait_online ([ 'testtun99:degraded' , 'testtap99:degraded' ], setup_state
= 'unmanaged' )
1560 pid
= networkd_pid ()
1561 name
= psutil
. Process ( pid
). name ()[: 15 ]
1563 output
= check_output ( 'ip -d tuntap show' )
1565 self
. assertRegex ( output
, fr
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1566 self
. assertRegex ( output
, fr
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1568 output
= check_output ( 'ip -d link show testtun99' )
1570 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1571 self
. assertIn ( 'UP,LOWER_UP' , output
)
1573 output
= check_output ( 'ip -d link show testtap99' )
1575 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1576 self
. assertIn ( 'UP,LOWER_UP' , output
)
1578 clear_network_units ()
1580 self
. wait_online ([ 'testtun99:off' , 'testtap99:off' ], setup_state
= 'unmanaged' )
1582 output
= check_output ( 'ip -d tuntap show' )
1584 self
. assertRegex ( output
, r
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$' )
1585 self
. assertRegex ( output
, r
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$' )
1590 output
= check_output ( 'ip -d link show testtun99' )
1592 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1593 if 'NO-CARRIER' in output
:
1601 output
= check_output ( 'ip -d link show testtap99' )
1603 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1604 if 'NO-CARRIER' in output
:
1609 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
1611 copy_network_unit ( '25-vrf.netdev' , '26-netdev-link-local-addressing-yes.network' )
1614 self
. wait_online ([ 'vrf99:carrier' ])
1616 @expectedFailureIfModuleIsNotAvailable ( 'vcan' )
1617 def test_vcan ( self
):
1618 copy_network_unit ( '25-vcan.netdev' , '26-netdev-link-local-addressing-yes.network' )
1621 self
. wait_online ([ 'vcan99:carrier' ])
1623 @expectedFailureIfModuleIsNotAvailable ( 'vxcan' )
1624 def test_vxcan ( self
):
1625 copy_network_unit ( '25-vxcan.netdev' , '26-netdev-link-local-addressing-yes.network' )
1628 self
. wait_online ([ 'vxcan99:carrier' , 'vxcan-peer:carrier' ])
1630 @expectedFailureIfModuleIsNotAvailable ( 'wireguard' )
1631 def test_wireguard ( self
):
1632 copy_network_unit ( '25-wireguard.netdev' , '25-wireguard.network' ,
1633 '25-wireguard-23-peers.netdev' , '25-wireguard-23-peers.network' ,
1634 '25-wireguard-preshared-key.txt' , '25-wireguard-private-key.txt' ,
1635 '25-wireguard-no-peer.netdev' , '25-wireguard-no-peer.network' )
1637 self
. wait_online ([ 'wg99:routable' , 'wg98:routable' , 'wg97:carrier' ])
1639 output
= check_output ( 'ip -4 address show dev wg99' )
1641 self
. assertIn ( 'inet 192.168.124.1/24 scope global wg99' , output
)
1643 output
= check_output ( 'ip -4 address show dev wg99' )
1645 self
. assertIn ( 'inet 169.254.11.1/24 scope link wg99' , output
)
1647 output
= check_output ( 'ip -6 address show dev wg99' )
1649 self
. assertIn ( 'inet6 fe80::1/64 scope link' , output
)
1651 output
= check_output ( 'ip -4 address show dev wg98' )
1653 self
. assertIn ( 'inet 192.168.123.123/24 scope global wg98' , output
)
1655 output
= check_output ( 'ip -6 address show dev wg98' )
1657 self
. assertIn ( 'inet6 fd8d:4d6d:3ccb:500::1/64 scope global' , output
)
1659 output
= check_output ( 'ip -4 route show dev wg99 table 1234' )
1661 self
. assertIn ( '192.168.26.0/24 proto static metric 123' , output
)
1663 output
= check_output ( 'ip -6 route show dev wg99 table 1234' )
1665 self
. assertIn ( 'fd31:bf08:57cb::/48 proto static metric 123 pref medium' , output
)
1667 output
= check_output ( 'ip -6 route show dev wg98 table 1234' )
1669 self
. assertIn ( 'fd8d:4d6d:3ccb:500:c79:2339:edce:ece1 proto static metric 123 pref medium' , output
)
1670 self
. assertIn ( 'fd8d:4d6d:3ccb:500:1dbf:ca8a:32d3:dd81 proto static metric 123 pref medium' , output
)
1671 self
. assertIn ( 'fd8d:4d6d:3ccb:500:1e54:1415:35d0:a47c proto static metric 123 pref medium' , output
)
1672 self
. assertIn ( 'fd8d:4d6d:3ccb:500:270d:b5dd:4a3f:8909 proto static metric 123 pref medium' , output
)
1673 self
. assertIn ( 'fd8d:4d6d:3ccb:500:5660:679d:3532:94d8 proto static metric 123 pref medium' , output
)
1674 self
. assertIn ( 'fd8d:4d6d:3ccb:500:6825:573f:30f3:9472 proto static metric 123 pref medium' , output
)
1675 self
. assertIn ( 'fd8d:4d6d:3ccb:500:6f2e:6888:c6fd:dfb9 proto static metric 123 pref medium' , output
)
1676 self
. assertIn ( 'fd8d:4d6d:3ccb:500:8d4d:bab:7280:a09a proto static metric 123 pref medium' , output
)
1677 self
. assertIn ( 'fd8d:4d6d:3ccb:500:900c:d437:ec27:8822 proto static metric 123 pref medium' , output
)
1678 self
. assertIn ( 'fd8d:4d6d:3ccb:500:9742:9931:5217:18d5 proto static metric 123 pref medium' , output
)
1679 self
. assertIn ( 'fd8d:4d6d:3ccb:500:9c11:d820:2e96:9be0 proto static metric 123 pref medium' , output
)
1680 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a072:80da:de4f:add1 proto static metric 123 pref medium' , output
)
1681 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a3f3:df38:19b0:721 proto static metric 123 pref medium' , output
)
1682 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a94b:cd6a:a32d:90e6 proto static metric 123 pref medium' , output
)
1683 self
. assertIn ( 'fd8d:4d6d:3ccb:500:b39c:9cdc:755a:ead3 proto static metric 123 pref medium' , output
)
1684 self
. assertIn ( 'fd8d:4d6d:3ccb:500:b684:4f81:2e3e:132e proto static metric 123 pref medium' , output
)
1685 self
. assertIn ( 'fd8d:4d6d:3ccb:500:bad5:495d:8e9c:3427 proto static metric 123 pref medium' , output
)
1686 self
. assertIn ( 'fd8d:4d6d:3ccb:500:bfe5:c3c3:5d77:fcb proto static metric 123 pref medium' , output
)
1687 self
. assertIn ( 'fd8d:4d6d:3ccb:500:c624:6bf7:4c09:3b59 proto static metric 123 pref medium' , output
)
1688 self
. assertIn ( 'fd8d:4d6d:3ccb:500:d4f9:5dc:9296:a1a proto static metric 123 pref medium' , output
)
1689 self
. assertIn ( 'fd8d:4d6d:3ccb:500:dcdd:d33b:90c9:6088 proto static metric 123 pref medium' , output
)
1690 self
. assertIn ( 'fd8d:4d6d:3ccb:500:e2e1:ae15:103f:f376 proto static metric 123 pref medium' , output
)
1691 self
. assertIn ( 'fd8d:4d6d:3ccb:500:f349:c4f0:10c1:6b4 proto static metric 123 pref medium' , output
)
1692 self
. assertIn ( 'fd8d:4d6d:3ccb:c79:2339:edce::/96 proto static metric 123 pref medium' , output
)
1693 self
. assertIn ( 'fd8d:4d6d:3ccb:1dbf:ca8a:32d3::/96 proto static metric 123 pref medium' , output
)
1694 self
. assertIn ( 'fd8d:4d6d:3ccb:1e54:1415:35d0::/96 proto static metric 123 pref medium' , output
)
1695 self
. assertIn ( 'fd8d:4d6d:3ccb:270d:b5dd:4a3f::/96 proto static metric 123 pref medium' , output
)
1696 self
. assertIn ( 'fd8d:4d6d:3ccb:5660:679d:3532::/96 proto static metric 123 pref medium' , output
)
1697 self
. assertIn ( 'fd8d:4d6d:3ccb:6825:573f:30f3::/96 proto static metric 123 pref medium' , output
)
1698 self
. assertIn ( 'fd8d:4d6d:3ccb:6f2e:6888:c6fd::/96 proto static metric 123 pref medium' , output
)
1699 self
. assertIn ( 'fd8d:4d6d:3ccb:8d4d:bab:7280::/96 proto static metric 123 pref medium' , output
)
1700 self
. assertIn ( 'fd8d:4d6d:3ccb:900c:d437:ec27::/96 proto static metric 123 pref medium' , output
)
1701 self
. assertIn ( 'fd8d:4d6d:3ccb:9742:9931:5217::/96 proto static metric 123 pref medium' , output
)
1702 self
. assertIn ( 'fd8d:4d6d:3ccb:9c11:d820:2e96::/96 proto static metric 123 pref medium' , output
)
1703 self
. assertIn ( 'fd8d:4d6d:3ccb:a072:80da:de4f::/96 proto static metric 123 pref medium' , output
)
1704 self
. assertIn ( 'fd8d:4d6d:3ccb:a3f3:df38:19b0::/96 proto static metric 123 pref medium' , output
)
1705 self
. assertIn ( 'fd8d:4d6d:3ccb:a94b:cd6a:a32d::/96 proto static metric 123 pref medium' , output
)
1706 self
. assertIn ( 'fd8d:4d6d:3ccb:b39c:9cdc:755a::/96 proto static metric 123 pref medium' , output
)
1707 self
. assertIn ( 'fd8d:4d6d:3ccb:b684:4f81:2e3e::/96 proto static metric 123 pref medium' , output
)
1708 self
. assertIn ( 'fd8d:4d6d:3ccb:bad5:495d:8e9c::/96 proto static metric 123 pref medium' , output
)
1709 self
. assertIn ( 'fd8d:4d6d:3ccb:bfe5:c3c3:5d77::/96 proto static metric 123 pref medium' , output
)
1710 self
. assertIn ( 'fd8d:4d6d:3ccb:c624:6bf7:4c09::/96 proto static metric 123 pref medium' , output
)
1711 self
. assertIn ( 'fd8d:4d6d:3ccb:d4f9:5dc:9296::/96 proto static metric 123 pref medium' , output
)
1712 self
. assertIn ( 'fd8d:4d6d:3ccb:dcdd:d33b:90c9::/96 proto static metric 123 pref medium' , output
)
1713 self
. assertIn ( 'fd8d:4d6d:3ccb:e2e1:ae15:103f::/96 proto static metric 123 pref medium' , output
)
1714 self
. assertIn ( 'fd8d:4d6d:3ccb:f349:c4f0:10c1::/96 proto static metric 123 pref medium' , output
)
1716 if shutil
. which ( 'wg' ):
1719 output
= check_output ( 'wg show wg99 listen-port' )
1720 self
. assertEqual ( output
, '51820' )
1721 output
= check_output ( 'wg show wg99 fwmark' )
1722 self
. assertEqual ( output
, '0x4d2' )
1723 output
= check_output ( 'wg show wg99 private-key' )
1724 self
. assertEqual ( output
, 'EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=' )
1725 output
= check_output ( 'wg show wg99 allowed-ips' )
1726 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t 192.168.124.3/32' , output
)
1727 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t 192.168.124.2/32' , output
)
1728 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t fdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128' , output
)
1729 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 192.168.26.0/24 fd31:bf08:57cb::/48' , output
)
1730 output
= check_output ( 'wg show wg99 persistent-keepalive' )
1731 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t off' , output
)
1732 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t off' , output
)
1733 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t off' , output
)
1734 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 20' , output
)
1735 output
= check_output ( 'wg show wg99 endpoints' )
1736 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t (none)' , output
)
1737 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t (none)' , output
)
1738 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t (none)' , output
)
1739 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 192.168.27.3:51820' , output
)
1740 output
= check_output ( 'wg show wg99 preshared-keys' )
1741 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t 6Fsg8XN0DE6aPQgAX4r2oazEYJOGqyHUz3QRH/jCB+I=' , output
)
1742 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t it7nd33chCT/tKT2ZZWfYyp43Zs+6oif72hexnSNMqA=' , output
)
1743 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=' , output
)
1744 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=' , output
)
1746 output
= check_output ( 'wg show wg98 private-key' )
1747 self
. assertEqual ( output
, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr+WHtZLZ90FU=' )
1749 output
= check_output ( 'wg show wg97 listen-port' )
1750 self
. assertEqual ( output
, '51821' )
1751 output
= check_output ( 'wg show wg97 fwmark' )
1752 self
. assertEqual ( output
, '0x4d3' )
1754 def test_geneve ( self
):
1755 copy_network_unit ( '25-geneve.netdev' , '26-netdev-link-local-addressing-yes.network' )
1758 self
. wait_online ([ 'geneve99:degraded' ])
1760 output
= check_output ( 'ip -d link show geneve99' )
1762 self
. assertRegex ( output
, '192.168.22.1' )
1763 self
. assertRegex ( output
, '6082' )
1764 self
. assertRegex ( output
, 'udpcsum' )
1765 self
. assertRegex ( output
, 'udp6zerocsumrx' )
1767 def test_ipip_tunnel ( self
):
1768 copy_network_unit ( '12-dummy.netdev' , '25-ipip.network' ,
1769 '25-ipip-tunnel.netdev' , '25-tunnel.network' ,
1770 '25-ipip-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1771 '25-ipip-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1772 '25-ipip-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1774 self
. wait_online ([ 'ipiptun99:routable' , 'ipiptun98:routable' , 'ipiptun97:routable' , 'ipiptun96:routable' , 'dummy98:degraded' ])
1776 output
= check_output ( 'ip -d link show ipiptun99' )
1778 self
. assertRegex ( output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98' )
1779 output
= check_output ( 'ip -d link show ipiptun98' )
1781 self
. assertRegex ( output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98' )
1782 output
= check_output ( 'ip -d link show ipiptun97' )
1784 self
. assertRegex ( output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98' )
1785 output
= check_output ( 'ip -d link show ipiptun96' )
1787 self
. assertRegex ( output
, 'ipip (ipip )?remote any local any dev dummy98' )
1789 def test_gre_tunnel ( self
):
1790 copy_network_unit ( '12-dummy.netdev' , '25-gretun.network' ,
1791 '25-gre-tunnel.netdev' , '25-tunnel.network' ,
1792 '25-gre-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1793 '25-gre-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1794 '25-gre-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1796 self
. wait_online ([ 'gretun99:routable' , 'gretun98:routable' , 'gretun97:routable' , 'gretun96:routable' , 'dummy98:degraded' ])
1798 output
= check_output ( 'ip -d link show gretun99' )
1800 self
. assertRegex ( output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1801 self
. assertRegex ( output
, 'ikey 1.2.3.103' )
1802 self
. assertRegex ( output
, 'okey 1.2.4.103' )
1803 self
. assertRegex ( output
, 'iseq' )
1804 self
. assertRegex ( output
, 'oseq' )
1805 output
= check_output ( 'ip -d link show gretun98' )
1807 self
. assertRegex ( output
, 'gre remote 10.65.223.239 local any dev dummy98' )
1808 self
. assertRegex ( output
, 'ikey 0.0.0.104' )
1809 self
. assertRegex ( output
, 'okey 0.0.0.104' )
1810 self
. assertNotRegex ( output
, 'iseq' )
1811 self
. assertNotRegex ( output
, 'oseq' )
1812 output
= check_output ( 'ip -d link show gretun97' )
1814 self
. assertRegex ( output
, 'gre remote any local 10.65.223.238 dev dummy98' )
1815 self
. assertRegex ( output
, 'ikey 0.0.0.105' )
1816 self
. assertRegex ( output
, 'okey 0.0.0.105' )
1817 self
. assertNotRegex ( output
, 'iseq' )
1818 self
. assertNotRegex ( output
, 'oseq' )
1819 output
= check_output ( 'ip -d link show gretun96' )
1821 self
. assertRegex ( output
, 'gre remote any local any dev dummy98' )
1822 self
. assertRegex ( output
, 'ikey 0.0.0.106' )
1823 self
. assertRegex ( output
, 'okey 0.0.0.106' )
1824 self
. assertNotRegex ( output
, 'iseq' )
1825 self
. assertNotRegex ( output
, 'oseq' )
1827 def test_ip6gre_tunnel ( self
):
1828 copy_network_unit ( '12-dummy.netdev' , '25-ip6gretun.network' ,
1829 '25-ip6gre-tunnel.netdev' , '25-tunnel.network' ,
1830 '25-ip6gre-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1831 '25-ip6gre-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1832 '25-ip6gre-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1835 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1837 self
. wait_links ( 'dummy98' , 'ip6gretun99' , 'ip6gretun98' , 'ip6gretun97' , 'ip6gretun96' )
1839 output
= check_output ( 'ip -d link show ip6gretun99' )
1841 self
. assertRegex ( output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1842 output
= check_output ( 'ip -d link show ip6gretun98' )
1844 self
. assertRegex ( output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98' )
1845 output
= check_output ( 'ip -d link show ip6gretun97' )
1847 self
. assertRegex ( output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98' )
1848 output
= check_output ( 'ip -d link show ip6gretun96' )
1850 self
. assertRegex ( output
, 'ip6gre remote any local any dev dummy98' )
1852 def test_gretap_tunnel ( self
):
1853 copy_network_unit ( '12-dummy.netdev' , '25-gretap.network' ,
1854 '25-gretap-tunnel.netdev' , '25-tunnel.network' ,
1855 '25-gretap-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1857 self
. wait_online ([ 'gretap99:routable' , 'gretap98:routable' , 'dummy98:degraded' ])
1859 output
= check_output ( 'ip -d link show gretap99' )
1861 self
. assertRegex ( output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1862 self
. assertRegex ( output
, 'ikey 0.0.0.106' )
1863 self
. assertRegex ( output
, 'okey 0.0.0.106' )
1864 self
. assertRegex ( output
, 'iseq' )
1865 self
. assertRegex ( output
, 'oseq' )
1866 self
. assertIn ( 'nopmtudisc' , output
)
1867 self
. assertIn ( 'ignore-df' , output
)
1868 output
= check_output ( 'ip -d link show gretap98' )
1870 self
. assertRegex ( output
, 'gretap remote 10.65.223.239 local any dev dummy98' )
1871 self
. assertRegex ( output
, 'ikey 0.0.0.107' )
1872 self
. assertRegex ( output
, 'okey 0.0.0.107' )
1873 self
. assertRegex ( output
, 'iseq' )
1874 self
. assertRegex ( output
, 'oseq' )
1876 def test_ip6gretap_tunnel ( self
):
1877 copy_network_unit ( '12-dummy.netdev' , '25-ip6gretap.network' ,
1878 '25-ip6gretap-tunnel.netdev' , '25-tunnel.network' ,
1879 '25-ip6gretap-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1881 self
. wait_online ([ 'ip6gretap99:routable' , 'ip6gretap98:routable' , 'dummy98:degraded' ])
1883 output
= check_output ( 'ip -d link show ip6gretap99' )
1885 self
. assertRegex ( output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1886 output
= check_output ( 'ip -d link show ip6gretap98' )
1888 self
. assertRegex ( output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98' )
1890 def test_vti_tunnel ( self
):
1891 copy_network_unit ( '12-dummy.netdev' , '25-vti.network' ,
1892 '25-vti-tunnel.netdev' , '25-tunnel.network' ,
1893 '25-vti-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1894 '25-vti-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1895 '25-vti-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1897 self
. wait_online ([ 'vtitun99:routable' , 'vtitun98:routable' , 'vtitun97:routable' , 'vtitun96:routable' , 'dummy98:degraded' ])
1899 output
= check_output ( 'ip -d link show vtitun99' )
1901 self
. assertRegex ( output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1902 output
= check_output ( 'ip -d link show vtitun98' )
1904 self
. assertRegex ( output
, 'vti remote 10.65.223.239 local any dev dummy98' )
1905 output
= check_output ( 'ip -d link show vtitun97' )
1907 self
. assertRegex ( output
, 'vti remote any local 10.65.223.238 dev dummy98' )
1908 output
= check_output ( 'ip -d link show vtitun96' )
1910 self
. assertRegex ( output
, 'vti remote any local any dev dummy98' )
1912 def test_vti6_tunnel ( self
):
1913 copy_network_unit ( '12-dummy.netdev' , '25-vti6.network' ,
1914 '25-vti6-tunnel.netdev' , '25-tunnel.network' ,
1915 '25-vti6-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1916 '25-vti6-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' )
1918 self
. wait_online ([ 'vti6tun99:routable' , 'vti6tun98:routable' , 'vti6tun97:routable' , 'dummy98:degraded' ])
1920 output
= check_output ( 'ip -d link show vti6tun99' )
1922 self
. assertRegex ( output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1923 output
= check_output ( 'ip -d link show vti6tun98' )
1925 self
. assertRegex ( output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98' )
1926 output
= check_output ( 'ip -d link show vti6tun97' )
1928 self
. assertRegex ( output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98' )
1930 def test_ip6tnl_tunnel ( self
):
1931 copy_network_unit ( '12-dummy.netdev' , '25-ip6tnl.network' ,
1932 '25-ip6tnl-tunnel.netdev' , '25-tunnel.network' ,
1933 '25-ip6tnl-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1934 '25-ip6tnl-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1935 '25-veth.netdev' , '25-ip6tnl-slaac.network' , '25-ipv6-prefix.network' ,
1936 '25-ip6tnl-tunnel-local-slaac.netdev' , '25-ip6tnl-tunnel-local-slaac.network' ,
1937 '25-ip6tnl-tunnel-external.netdev' , '26-netdev-link-local-addressing-yes.network' )
1939 self
. wait_online ([ 'ip6tnl99:routable' , 'ip6tnl98:routable' , 'ip6tnl97:routable' ,
1940 'ip6tnl-slaac:degraded' , 'ip6tnl-external:degraded' ,
1941 'dummy98:degraded' , 'veth99:routable' , 'veth-peer:degraded' ])
1943 output
= check_output ( 'ip -d link show ip6tnl99' )
1945 self
. assertIn ( 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' , output
)
1946 output
= check_output ( 'ip -d link show ip6tnl98' )
1948 self
. assertRegex ( output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98' )
1949 output
= check_output ( 'ip -d link show ip6tnl97' )
1951 self
. assertRegex ( output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98' )
1952 output
= check_output ( 'ip -d link show ip6tnl-external' )
1954 self
. assertIn ( 'ip6tnl-external@NONE:' , output
)
1955 self
. assertIn ( 'ip6tnl external ' , output
)
1956 output
= check_output ( 'ip -d link show ip6tnl-slaac' )
1958 self
. assertIn ( 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99' , output
)
1960 output
= check_output ( 'ip -6 address show veth99' )
1962 self
. assertIn ( 'inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic' , output
)
1964 output
= check_output ( 'ip -4 route show default' )
1966 self
. assertIn ( 'default dev ip6tnl-slaac proto static' , output
)
1968 def test_sit_tunnel ( self
):
1969 copy_network_unit ( '12-dummy.netdev' , '25-sit.network' ,
1970 '25-sit-tunnel.netdev' , '25-tunnel.network' ,
1971 '25-sit-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1972 '25-sit-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1973 '25-sit-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1975 self
. wait_online ([ 'sittun99:routable' , 'sittun98:routable' , 'sittun97:routable' , 'sittun96:routable' , 'dummy98:degraded' ])
1977 output
= check_output ( 'ip -d link show sittun99' )
1979 self
. assertRegex ( output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98" )
1980 output
= check_output ( 'ip -d link show sittun98' )
1982 self
. assertRegex ( output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98" )
1983 output
= check_output ( 'ip -d link show sittun97' )
1985 self
. assertRegex ( output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98" )
1986 output
= check_output ( 'ip -d link show sittun96' )
1988 self
. assertRegex ( output
, "sit (ip6ip )?remote any local any dev dummy98" )
1990 def test_isatap_tunnel ( self
):
1991 copy_network_unit ( '12-dummy.netdev' , '25-isatap.network' ,
1992 '25-isatap-tunnel.netdev' , '25-tunnel.network' )
1994 self
. wait_online ([ 'isataptun99:routable' , 'dummy98:degraded' ])
1996 output
= check_output ( 'ip -d link show isataptun99' )
1998 self
. assertRegex ( output
, "isatap " )
2000 def test_6rd_tunnel ( self
):
2001 copy_network_unit ( '12-dummy.netdev' , '25-6rd.network' ,
2002 '25-6rd-tunnel.netdev' , '25-tunnel.network' )
2004 self
. wait_online ([ 'sittun99:routable' , 'dummy98:degraded' ])
2006 output
= check_output ( 'ip -d link show sittun99' )
2008 self
. assertRegex ( output
, '6rd-prefix 2602::/24' )
2010 @expectedFailureIfERSPANv0IsNotSupported ()
2011 def test_erspan_tunnel_v0 ( self
):
2012 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
2013 '25-erspan0-tunnel.netdev' , '25-tunnel.network' ,
2014 '25-erspan0-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
2016 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
2018 output
= check_output ( 'ip -d link show erspan99' )
2020 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
2021 self
. assertIn ( 'erspan_ver 0' , output
)
2022 self
. assertNotIn ( 'erspan_index 123' , output
)
2023 self
. assertNotIn ( 'erspan_dir ingress' , output
)
2024 self
. assertNotIn ( 'erspan_hwid 1f' , output
)
2025 self
. assertIn ( 'ikey 0.0.0.101' , output
)
2026 self
. assertIn ( 'iseq' , output
)
2027 self
. assertIn ( 'nopmtudisc' , output
)
2028 self
. assertIn ( 'ignore-df' , output
)
2029 output
= check_output ( 'ip -d link show erspan98' )
2031 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
2032 self
. assertIn ( 'erspan_ver 0' , output
)
2033 self
. assertNotIn ( 'erspan_index 124' , output
)
2034 self
. assertNotIn ( 'erspan_dir egress' , output
)
2035 self
. assertNotIn ( 'erspan_hwid 2f' , output
)
2036 self
. assertIn ( 'ikey 0.0.0.102' , output
)
2037 self
. assertIn ( 'iseq' , output
)
2039 def test_erspan_tunnel_v1 ( self
):
2040 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
2041 '25-erspan1-tunnel.netdev' , '25-tunnel.network' ,
2042 '25-erspan1-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
2044 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
2046 output
= check_output ( 'ip -d link show erspan99' )
2048 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
2049 self
. assertIn ( 'erspan_ver 1' , output
)
2050 self
. assertIn ( 'erspan_index 123' , output
)
2051 self
. assertNotIn ( 'erspan_dir ingress' , output
)
2052 self
. assertNotIn ( 'erspan_hwid 1f' , output
)
2053 self
. assertIn ( 'ikey 0.0.0.101' , output
)
2054 self
. assertIn ( 'okey 0.0.0.101' , output
)
2055 self
. assertIn ( 'iseq' , output
)
2056 self
. assertIn ( 'oseq' , output
)
2057 output
= check_output ( 'ip -d link show erspan98' )
2059 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
2060 self
. assertIn ( 'erspan_ver 1' , output
)
2061 self
. assertIn ( 'erspan_index 124' , output
)
2062 self
. assertNotIn ( 'erspan_dir egress' , output
)
2063 self
. assertNotIn ( 'erspan_hwid 2f' , output
)
2064 self
. assertIn ( 'ikey 0.0.0.102' , output
)
2065 self
. assertIn ( 'okey 0.0.0.102' , output
)
2066 self
. assertIn ( 'iseq' , output
)
2067 self
. assertIn ( 'oseq' , output
)
2069 @expectedFailureIfERSPANv2IsNotSupported ()
2070 def test_erspan_tunnel_v2 ( self
):
2071 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
2072 '25-erspan2-tunnel.netdev' , '25-tunnel.network' ,
2073 '25-erspan2-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
2075 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
2077 output
= check_output ( 'ip -d link show erspan99' )
2079 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
2080 self
. assertIn ( 'erspan_ver 2' , output
)
2081 self
. assertNotIn ( 'erspan_index 123' , output
)
2082 self
. assertIn ( 'erspan_dir ingress' , output
)
2083 self
. assertIn ( 'erspan_hwid 0x1f' , output
)
2084 self
. assertIn ( 'ikey 0.0.0.101' , output
)
2085 self
. assertIn ( 'okey 0.0.0.101' , output
)
2086 self
. assertIn ( 'iseq' , output
)
2087 self
. assertIn ( 'oseq' , output
)
2088 output
= check_output ( 'ip -d link show erspan98' )
2090 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
2091 self
. assertIn ( 'erspan_ver 2' , output
)
2092 self
. assertNotIn ( 'erspan_index 124' , output
)
2093 self
. assertIn ( 'erspan_dir egress' , output
)
2094 self
. assertIn ( 'erspan_hwid 0x2f' , output
)
2095 self
. assertIn ( 'ikey 0.0.0.102' , output
)
2096 self
. assertIn ( 'okey 0.0.0.102' , output
)
2097 self
. assertIn ( 'iseq' , output
)
2098 self
. assertIn ( 'oseq' , output
)
2100 def test_tunnel_independent ( self
):
2101 copy_network_unit ( '25-ipip-tunnel-independent.netdev' , '26-netdev-link-local-addressing-yes.network' )
2104 self
. wait_online ([ 'ipiptun99:carrier' ])
2106 def test_tunnel_independent_loopback ( self
):
2107 copy_network_unit ( '25-ipip-tunnel-independent-loopback.netdev' , '26-netdev-link-local-addressing-yes.network' )
2110 self
. wait_online ([ 'ipiptun99:carrier' ])
2112 @expectedFailureIfModuleIsNotAvailable ( 'xfrm_interface' )
2113 def test_xfrm ( self
):
2114 copy_network_unit ( '12-dummy.netdev' , '25-xfrm.network' ,
2115 '25-xfrm.netdev' , '25-xfrm-independent.netdev' ,
2116 '26-netdev-link-local-addressing-yes.network' )
2119 self
. wait_online ([ 'dummy98:degraded' , 'xfrm98:degraded' , 'xfrm99:degraded' ])
2121 output
= check_output ( 'ip -d link show dev xfrm98' )
2123 self
. assertIn ( 'xfrm98@dummy98:' , output
)
2124 self
. assertIn ( 'xfrm if_id 0x98 ' , output
)
2126 output
= check_output ( 'ip -d link show dev xfrm99' )
2128 self
. assertIn ( 'xfrm99@lo:' , output
)
2129 self
. assertIn ( 'xfrm if_id 0x99 ' , output
)
2131 @expectedFailureIfModuleIsNotAvailable ( 'fou' )
2133 # The following redundant check is necessary for CentOS CI.
2134 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
2135 self
. assertTrue ( is_module_available ( 'fou' ))
2137 copy_network_unit ( '25-fou-ipproto-ipip.netdev' , '25-fou-ipproto-gre.netdev' ,
2138 '25-fou-ipip.netdev' , '25-fou-sit.netdev' ,
2139 '25-fou-gre.netdev' , '25-fou-gretap.netdev' )
2142 self
. wait_online ([ 'ipiptun96:off' , 'sittun96:off' , 'gretun96:off' , 'gretap96:off' ], setup_state
= 'unmanaged' )
2144 output
= check_output ( 'ip fou show' )
2146 self
. assertRegex ( output
, 'port 55555 ipproto 4' )
2147 self
. assertRegex ( output
, 'port 55556 ipproto 47' )
2149 output
= check_output ( 'ip -d link show ipiptun96' )
2151 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55555' )
2152 output
= check_output ( 'ip -d link show sittun96' )
2154 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55555' )
2155 output
= check_output ( 'ip -d link show gretun96' )
2157 self
. assertRegex ( output
, 'encap fou encap-sport 1001 encap-dport 55556' )
2158 output
= check_output ( 'ip -d link show gretap96' )
2160 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55556' )
2162 def test_vxlan ( self
):
2163 copy_network_unit ( '11-dummy.netdev' , '25-vxlan-test1.network' ,
2164 '25-vxlan.netdev' , '25-vxlan.network' ,
2165 '25-vxlan-ipv6.netdev' , '25-vxlan-ipv6.network' ,
2166 '25-vxlan-independent.netdev' , '26-netdev-link-local-addressing-yes.network' ,
2167 '25-veth.netdev' , '25-vxlan-veth99.network' , '25-ipv6-prefix.network' ,
2168 '25-vxlan-local-slaac.netdev' , '25-vxlan-local-slaac.network' )
2171 self
. wait_online ([ 'test1:degraded' , 'veth99:routable' , 'veth-peer:degraded' ,
2172 'vxlan99:degraded' , 'vxlan98:degraded' , 'vxlan97:degraded' , 'vxlan-slaac:degraded' ])
2174 output
= check_output ( 'ip -d -d link show vxlan99' )
2176 self
. assertIn ( '999' , output
)
2177 self
. assertIn ( '5555' , output
)
2178 self
. assertIn ( 'l2miss' , output
)
2179 self
. assertIn ( 'l3miss' , output
)
2180 self
. assertIn ( 'gbp' , output
)
2181 # Since [0] some of the options use slightly different names and some
2182 # options with default values are shown only if the -d(etails) setting
2184 # [0] https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit/?id=1215e9d3862387353d8672296cb4c6c16e8cbb72
2185 self
. assertRegex ( output
, '(udpcsum|udp_csum)' )
2186 self
. assertRegex ( output
, '(udp6zerocsumtx|udp_zero_csum6_tx)' )
2187 self
. assertRegex ( output
, '(udp6zerocsumrx|udp_zero_csum6_rx)' )
2188 self
. assertRegex ( output
, '(remcsumtx|remcsum_tx)' )
2189 self
. assertRegex ( output
, '(remcsumrx|remcsum_rx)' )
2191 output
= check_output ( 'bridge fdb show dev vxlan99' )
2193 self
. assertIn ( '00:11:22:33:44:55 dst 10.0.0.5 self permanent' , output
)
2194 self
. assertIn ( '00:11:22:33:44:66 dst 10.0.0.6 self permanent' , output
)
2195 self
. assertIn ( '00:11:22:33:44:77 dst 10.0.0.7 via test1 self permanent' , output
)
2197 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'vxlan99' , env
= env
)
2199 self
. assertIn ( 'VNI: 999' , output
)
2200 self
. assertIn ( 'Destination Port: 5555' , output
)
2201 self
. assertIn ( 'Underlying Device: test1' , output
)
2203 output
= check_output ( 'bridge fdb show dev vxlan97' )
2205 self
. assertIn ( '00:00:00:00:00:00 dst fe80::23b:d2ff:fe95:967f via test1 self permanent' , output
)
2206 self
. assertIn ( '00:00:00:00:00:00 dst fe80::27c:16ff:fec0:6c74 via test1 self permanent' , output
)
2207 self
. assertIn ( '00:00:00:00:00:00 dst fe80::2a2:e4ff:fef9:2269 via test1 self permanent' , output
)
2209 output
= check_output ( 'ip -d link show vxlan-slaac' )
2211 self
. assertIn ( 'vxlan id 4831584 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99' , output
)
2213 output
= check_output ( 'ip -6 address show veth99' )
2215 self
. assertIn ( 'inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic' , output
)
2217 @unittest . skipUnless ( compare_kernel_version ( "6" ), reason
= "Causes kernel panic on unpatched kernels: https://bugzilla.kernel.org/show_bug.cgi?id=208315" )
2218 def test_macsec ( self
):
2219 copy_network_unit ( '25-macsec.netdev' , '25-macsec.network' , '25-macsec.key' ,
2220 '26-macsec.network' , '12-dummy.netdev' )
2223 self
. wait_online ([ 'dummy98:degraded' , 'macsec99:routable' ])
2225 output
= check_output ( 'ip -d link show macsec99' )
2227 self
. assertRegex ( output
, 'macsec99@dummy98' )
2228 self
. assertRegex ( output
, 'macsec sci [0-9a-f]*000b' )
2229 self
. assertRegex ( output
, 'encrypt on' )
2231 output
= check_output ( 'ip macsec show macsec99' )
2233 self
. assertRegex ( output
, 'encrypt on' )
2234 self
. assertRegex ( output
, 'TXSC: [0-9a-f]*000b on SA 1' )
2235 self
. assertRegex ( output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000' )
2236 self
. assertRegex ( output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000' )
2237 self
. assertRegex ( output
, 'RXSC: c619528fe6a00100, state on' )
2238 self
. assertRegex ( output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000' )
2239 self
. assertRegex ( output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000' )
2240 self
. assertRegex ( output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000' )
2241 self
. assertRegex ( output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000' )
2242 self
. assertNotRegex ( output
, 'key 02030405067080900000000000000000' )
2243 self
. assertRegex ( output
, 'RXSC: 8c16456c83a90002, state on' )
2244 self
. assertRegex ( output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000' )
2246 def test_nlmon ( self
):
2247 copy_network_unit ( '25-nlmon.netdev' , '26-netdev-link-local-addressing-yes.network' )
2250 self
. wait_online ([ 'nlmon99:carrier' ])
2252 @expectedFailureIfModuleIsNotAvailable ( 'ifb' )
2254 copy_network_unit ( '25-ifb.netdev' , '26-netdev-link-local-addressing-yes.network' )
2257 self
. wait_online ([ 'ifb99:degraded' ])
2259 class NetworkdL2TPTests ( unittest
. TestCase
, Utilities
):
2267 @expectedFailureIfModuleIsNotAvailable ( 'l2tp_eth' , 'l2tp_netlink' )
2268 def test_l2tp_udp ( self
):
2269 copy_network_unit ( '11-dummy.netdev' , '25-l2tp-dummy.network' ,
2270 '25-l2tp-udp.netdev' , '25-l2tp.network' )
2273 self
. wait_online ([ 'test1:routable' , 'l2tp-ses1:degraded' , 'l2tp-ses2:degraded' ])
2275 output
= check_output ( 'ip l2tp show tunnel tunnel_id 10' )
2277 self
. assertRegex ( output
, "Tunnel 10, encap UDP" )
2278 self
. assertRegex ( output
, "From 192.168.30.100 to 192.168.30.101" )
2279 self
. assertRegex ( output
, "Peer tunnel 11" )
2280 self
. assertRegex ( output
, "UDP source / dest ports: 3000/4000" )
2281 self
. assertRegex ( output
, "UDP checksum: enabled" )
2283 output
= check_output ( 'ip l2tp show session tid 10 session_id 15' )
2285 self
. assertRegex ( output
, "Session 15 in tunnel 10" )
2286 self
. assertRegex ( output
, "Peer session 16, tunnel 11" )
2287 self
. assertRegex ( output
, "interface name: l2tp-ses1" )
2289 output
= check_output ( 'ip l2tp show session tid 10 session_id 17' )
2291 self
. assertRegex ( output
, "Session 17 in tunnel 10" )
2292 self
. assertRegex ( output
, "Peer session 18, tunnel 11" )
2293 self
. assertRegex ( output
, "interface name: l2tp-ses2" )
2295 @expectedFailureIfModuleIsNotAvailable ( 'l2tp_eth' , 'l2tp_ip' , 'l2tp_netlink' )
2296 def test_l2tp_ip ( self
):
2297 copy_network_unit ( '11-dummy.netdev' , '25-l2tp-dummy.network' ,
2298 '25-l2tp-ip.netdev' , '25-l2tp.network' )
2301 self
. wait_online ([ 'test1:routable' , 'l2tp-ses3:degraded' , 'l2tp-ses4:degraded' ])
2303 output
= check_output ( 'ip l2tp show tunnel tunnel_id 10' )
2305 self
. assertRegex ( output
, "Tunnel 10, encap IP" )
2306 self
. assertRegex ( output
, "From 192.168.30.100 to 192.168.30.101" )
2307 self
. assertRegex ( output
, "Peer tunnel 12" )
2309 output
= check_output ( 'ip l2tp show session tid 10 session_id 25' )
2311 self
. assertRegex ( output
, "Session 25 in tunnel 10" )
2312 self
. assertRegex ( output
, "Peer session 26, tunnel 12" )
2313 self
. assertRegex ( output
, "interface name: l2tp-ses3" )
2315 output
= check_output ( 'ip l2tp show session tid 10 session_id 27' )
2317 self
. assertRegex ( output
, "Session 27 in tunnel 10" )
2318 self
. assertRegex ( output
, "Peer session 28, tunnel 12" )
2319 self
. assertRegex ( output
, "interface name: l2tp-ses4" )
2321 class NetworkdNetworkTests ( unittest
. TestCase
, Utilities
):
2329 def verify_address_static (
2355 output
= check_output ( 'ip address show dev dummy98' )
2359 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
2360 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
2361 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
2362 self
. assertIn ( 'inet6 2001:db8:0:f101::15/64 scope global' , output
)
2363 self
. assertIn ( 'inet6 2001:db8:0:f101::16/64 scope global' , output
)
2364 self
. assertIn ( 'inet6 2001:db8:0:f102::15/64 scope global' , output
)
2367 self
. assertIn ( f
'inet 10.3.1.1/24 brd 10.3.1.255 scope global {label1} ' , output
)
2368 self
. assertIn ( f
'inet 10.3.2.1/24 brd 10.3.2.255 scope global {label2} ' , output
)
2369 self
. assertIn ( f
'inet 10.3.3.1/24 brd 10.3.3.255 scope global {label3} ' , output
)
2372 self
. assertIn ( f
'inet 10.4.1.1/24 {broadcast1} scope global dummy98' , output
)
2373 self
. assertIn ( f
'inet 10.4.2.1/24 {broadcast2} scope global dummy98' , output
)
2374 self
. assertIn ( f
'inet 10.4.3.1/24 {broadcast3} scope global dummy98' , output
)
2377 self
. assertIn ( f
'inet 10.5.1.1 {peer1} scope global dummy98' , output
)
2378 self
. assertIn ( f
'inet 10.5.2.1 {peer2} scope global dummy98' , output
)
2379 self
. assertIn ( f
'inet 10.5.3.1 {peer3} scope global dummy98' , output
)
2380 self
. assertIn ( f
'inet6 2001:db8:0:f103::1 {peer4} scope global' , output
)
2381 self
. assertIn ( f
'inet6 2001:db8:0:f103::2 {peer5} scope global' , output
)
2382 self
. assertIn ( f
'inet6 2001:db8:0:f103::3 {peer6} scope global' , output
)
2385 self
. assertIn ( f
'inet 10.6.1.1/24 brd 10.6.1.255 scope {scope1} dummy98' , output
)
2386 self
. assertIn ( f
'inet 10.6.2.1/24 brd 10.6.2.255 scope {scope2} dummy98' , output
)
2389 self
. assertIn ( f
'inet 10.7.1.1/24 brd 10.7.1.255 scope global {deprecated1} dummy98' , output
)
2390 self
. assertIn ( f
'inet 10.7.2.1/24 brd 10.7.2.255 scope global {deprecated2} dummy98' , output
)
2391 self
. assertIn ( f
'inet6 2001:db8:0:f104::1/64 scope global {deprecated3} ' , output
)
2392 self
. assertIn ( f
'inet6 2001:db8:0:f104::2/64 scope global {deprecated4} ' , output
)
2395 self
. assertRegex ( output
, rf
'inet 10.8.1.1/24 (metric {route_metric} |)brd 10.8.1.255 scope global dummy98' )
2396 self
. assertRegex ( output
, rf
'inet6 2001:db8:0:f105::1/64 (metric {route_metric} |)scope global' )
2398 output_route
= check_output ( 'ip -4 route show dev dummy98 10.8.1.0/24' )
2400 self
. assertIn ( f
'10.8.1.0/24 proto kernel scope link src 10.8.1.1 metric {route_metric} ' , output_route
)
2402 output_route
= check_output ( 'ip -6 route show dev dummy98 2001:db8:0:f105::/64' )
2404 self
. assertIn ( f
'2001:db8:0:f105::/64 proto kernel metric {route_metric} ' , output_route
)
2407 self
. assertIn ( f
'inet 10.9.1.1/24 brd 10.9.1.255 scope global {flag1} dummy98' , output
)
2408 self
. assertIn ( f
'inet 10.9.2.1/24 brd 10.9.2.255 scope global {flag2} dummy98' , output
)
2409 self
. assertIn ( f
'inet6 2001:db8:0:f106::1/64 scope global {flag3} ' , output
)
2410 self
. assertIn ( f
'inet6 2001:db8:0:f106::2/64 scope global {flag4} ' , output
)
2413 self
. assertRegex ( output
, r
'inet [0-9]*.[0-9]*.0.1/16 brd [0-9]*.[0-9]*.255.255 scope global subnet16' )
2414 self
. assertRegex ( output
, r
'inet [0-9]*.[0-9]*.[0-9]*.1/24 brd [0-9]*.[0-9]*.[0-9]*.255 scope global subnet24' )
2415 self
. assertRegex ( output
, r
'inet6 [0-9a-f:]*:1/73 scope global' )
2418 self
. assertNotIn ( '10.4.4.1' , output
)
2419 self
. assertNotIn ( '10.5.4.1' , output
)
2420 self
. assertNotIn ( '10.5.5.1' , output
)
2421 self
. assertNotIn ( '10.8.2.1' , output
)
2422 self
. assertNotIn ( '10.9.3.1' , output
)
2423 self
. assertNotIn ( '2001:db8:0:f101::2' , output
)
2424 self
. assertNotIn ( '2001:db8:0:f103::4' , output
)
2427 self
. check_netlabel ( 'dummy98' , r
'10\.10\.1\.0/24' )
2429 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2432 def test_address_static ( self
):
2433 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' , copy_dropins
= False )
2436 self
. wait_online ([ 'dummy98:routable' ])
2437 self
. verify_address_static (
2442 broadcast2
= ' brd 10.4.2.255' ,
2443 broadcast3
= ' brd 10.4.3.63' ,
2444 peer1
= ' peer 10.5.1.101/24' ,
2445 peer2
= ' peer 10.5.2.101/24' ,
2446 peer3
= '/24 brd 10.5.3.255' ,
2447 peer4
= ' peer 2001:db8:0:f103::101/128' ,
2448 peer5
= ' peer 2001:db8:0:f103::102/128' ,
2453 deprecated2
= ' deprecated' ,
2455 deprecated4
= ' deprecated' ,
2457 flag1
= ' noprefixroute' ,
2459 flag3
= ' noprefixroute' ,
2460 flag4
= ' home mngtmpaddr' ,
2463 copy_network_unit ( '25-address-static.network.d/10-override.conf' )
2465 self
. wait_online ([ 'dummy98:routable' ])
2466 self
. verify_address_static (
2467 label1
= 'new-label1' ,
2469 label3
= 'new-label3' ,
2470 broadcast1
= ' brd 10.4.1.255' ,
2472 broadcast3
= ' brd 10.4.3.31' ,
2473 peer1
= ' peer 10.5.1.102/24' ,
2474 peer2
= '/24 brd 10.5.2.255' ,
2475 peer3
= ' peer 10.5.3.102/24' ,
2476 peer4
= ' peer 2001:db8:0:f103::201/128' ,
2478 peer6
= ' peer 2001:db8:0:f103::203/128' ,
2481 deprecated1
= ' deprecated' ,
2483 deprecated3
= ' deprecated' ,
2487 flag2
= ' noprefixroute' ,
2488 flag3
= ' home mngtmpaddr' ,
2489 flag4
= ' noprefixroute' ,
2492 networkctl_reconfigure ( 'dummy98' )
2493 self
. wait_online ([ 'dummy98:routable' ])
2494 self
. verify_address_static (
2495 label1
= 'new-label1' ,
2497 label3
= 'new-label3' ,
2498 broadcast1
= ' brd 10.4.1.255' ,
2500 broadcast3
= ' brd 10.4.3.31' ,
2501 peer1
= ' peer 10.5.1.102/24' ,
2502 peer2
= '/24 brd 10.5.2.255' ,
2503 peer3
= ' peer 10.5.3.102/24' ,
2504 peer4
= ' peer 2001:db8:0:f103::201/128' ,
2506 peer6
= ' peer 2001:db8:0:f103::203/128' ,
2509 deprecated1
= ' deprecated' ,
2511 deprecated3
= ' deprecated' ,
2515 flag2
= ' noprefixroute' ,
2516 flag3
= ' home mngtmpaddr' ,
2517 flag4
= ' noprefixroute' ,
2521 # 1. set preferred lifetime forever to drop the deprecated flag for testing #20891.
2522 check_output ( 'ip address change 10.7.1.1/24 dev dummy98 preferred_lft forever' )
2523 check_output ( 'ip address change 2001:db8:0:f104::1/64 dev dummy98 preferred_lft forever' )
2524 output
= check_output ( 'ip address show dev dummy98' )
2526 self
. assertNotRegex ( output
, '10.7.1.1/24 .* deprecated' )
2527 self
. assertNotRegex ( output
, '2001:db8:0:f104::1/64 .* deprecated' )
2529 # 2. reconfigure the interface, and check the deprecated flag is set again
2530 networkctl_reconfigure ( 'dummy98' )
2531 self
. wait_online ([ 'dummy98:routable' ])
2532 self
. verify_address_static (
2533 label1
= 'new-label1' ,
2535 label3
= 'new-label3' ,
2536 broadcast1
= ' brd 10.4.1.255' ,
2538 broadcast3
= ' brd 10.4.3.31' ,
2539 peer1
= ' peer 10.5.1.102/24' ,
2540 peer2
= '/24 brd 10.5.2.255' ,
2541 peer3
= ' peer 10.5.3.102/24' ,
2542 peer4
= ' peer 2001:db8:0:f103::201/128' ,
2544 peer6
= ' peer 2001:db8:0:f103::203/128' ,
2547 deprecated1
= ' deprecated' ,
2549 deprecated3
= ' deprecated' ,
2553 flag2
= ' noprefixroute' ,
2554 flag3
= ' home mngtmpaddr' ,
2555 flag4
= ' noprefixroute' ,
2558 # test for ENOBUFS issue #17012 (with reload)
2559 copy_network_unit ( '25-address-static.network.d/10-many-address.conf' )
2561 self
. wait_online ([ 'dummy98:routable' ])
2562 output
= check_output ( 'ip -4 address show dev dummy98' )
2563 for i
in range ( 1 , 254 ):
2564 self
. assertIn ( f
'inet 10.3.3. {i} /16 brd 10.3.255.255' , output
)
2566 # (with reconfigure)
2567 networkctl_reconfigure ( 'dummy98' )
2568 self
. wait_online ([ 'dummy98:routable' ])
2569 output
= check_output ( 'ip -4 address show dev dummy98' )
2570 for i
in range ( 1 , 254 ):
2571 self
. assertIn ( f
'inet 10.3.3. {i} /16 brd 10.3.255.255' , output
)
2573 def test_address_null ( self
):
2574 copy_network_unit ( '25-address-null.network' , '12-dummy.netdev' )
2577 self
. wait_online ([ 'dummy98:routable' ])
2579 output
= check_output ( 'ip address show dev dummy98 scope global' )
2582 ipv4_address_16
= re
. findall ( r
'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255' , output
)
2583 self
. assertEqual ( len ( ipv4_address_16
), 1 )
2584 ipv4_address_24
= re
. findall ( r
'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255' , output
)
2585 self
. assertEqual ( len ( ipv4_address_24
), 1 )
2586 ipv4_address_30
= re
. findall ( r
'inet 192.168.[0-9]*.[0-9]*/30 brd 192.168.[0-9]*.[0-9]*' , output
)
2587 self
. assertEqual ( len ( ipv4_address_30
), 1 )
2588 ipv6_address
= re
. findall ( r
'inet6 fd[0-9a-f:]*/64' , output
)
2589 self
. assertEqual ( len ( ipv6_address
), 1 )
2591 networkctl_reconfigure ( 'dummy98' )
2592 self
. wait_online ([ 'dummy98:routable' ])
2594 output
= check_output ( 'ip address show dev dummy98 scope global' )
2596 self
. assertIn ( ipv4_address_16
[ 0 ], output
)
2597 self
. assertIn ( ipv4_address_24
[ 0 ], output
)
2598 self
. assertIn ( ipv4_address_30
[ 0 ], output
)
2599 self
. assertIn ( ipv6_address
[ 0 ], output
)
2601 def test_address_ipv4acd ( self
):
2602 check_output ( 'ip netns add ns99' )
2603 check_output ( 'ip link add veth99 type veth peer veth-peer' )
2604 check_output ( 'ip link set veth-peer netns ns99' )
2605 check_output ( 'ip link set veth99 up' )
2606 check_output ( 'ip netns exec ns99 ip link set veth-peer up' )
2607 check_output ( 'ip netns exec ns99 ip address add 192.168.100.10/24 dev veth-peer' )
2609 copy_network_unit ( '25-address-ipv4acd-veth99.network' , copy_dropins
= False )
2611 self
. wait_online ([ 'veth99:routable' ])
2613 output
= check_output ( 'ip -4 address show dev veth99' )
2615 self
. assertNotIn ( '192.168.100.10/24' , output
)
2616 self
. assertIn ( '192.168.100.11/24' , output
)
2618 copy_network_unit ( '25-address-ipv4acd-veth99.network.d/conflict-address.conf' )
2620 self
. wait_operstate ( 'veth99' , operstate
= 'routable' , setup_state
= 'configuring' , setup_timeout
= 10 )
2622 output
= check_output ( 'ip -4 address show dev veth99' )
2624 self
. assertNotIn ( '192.168.100.10/24' , output
)
2625 self
. assertIn ( '192.168.100.11/24' , output
)
2627 def test_address_peer_ipv4 ( self
):
2628 # test for issue #17304
2629 copy_network_unit ( '25-address-peer-ipv4.network' , '12-dummy.netdev' )
2631 for trial
in range ( 2 ):
2637 self
. wait_online ([ 'dummy98:routable' ])
2639 output
= check_output ( 'ip -4 address show dev dummy98' )
2640 self
. assertIn ( 'inet 100.64.0.1 peer 100.64.0.2/32 scope global' , output
)
2642 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
2643 def test_prefix_route ( self
):
2644 copy_network_unit ( '25-prefix-route-with-vrf.network' , '12-dummy.netdev' ,
2645 '25-prefix-route-without-vrf.network' , '11-dummy.netdev' ,
2646 '25-vrf.netdev' , '25-vrf.network' )
2647 for trial
in range ( 2 ):
2653 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' , 'vrf99:carrier' ])
2655 output
= check_output ( 'ip route show table 42 dev dummy98' )
2656 print ( '### ip route show table 42 dev dummy98' )
2658 self
. assertRegex ( output
, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1' )
2659 self
. assertRegex ( output
, '10.20.33.0/24 proto kernel scope link src 10.20.33.1' )
2660 self
. assertRegex ( output
, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1' )
2661 self
. assertRegex ( output
, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1' )
2662 self
. assertRegex ( output
, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1' )
2663 self
. assertRegex ( output
, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1' )
2664 self
. assertRegex ( output
, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1' )
2665 output
= check_output ( 'ip -6 route show table 42 dev dummy98' )
2666 print ( '### ip -6 route show table 42 dev dummy98' )
2670 self
. assertRegex ( output
, 'local fdde:11:22::1 proto kernel metric 0 pref medium' )
2671 #self.assertRegex(output, 'fdde:11:22::1 proto kernel metric 256 pref medium')
2672 self
. assertRegex ( output
, 'local fdde:11:33::1 proto kernel metric 0 pref medium' )
2673 self
. assertRegex ( output
, 'fdde:11:33::/64 proto kernel metric 256 pref medium' )
2674 self
. assertRegex ( output
, 'local fdde:11:44::1 proto kernel metric 0 pref medium' )
2675 self
. assertRegex ( output
, 'local fdde:11:55::1 proto kernel metric 0 pref medium' )
2676 self
. assertRegex ( output
, 'fe80::/64 proto kernel metric 256 pref medium' )
2677 self
. assertRegex ( output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium' )
2681 output
= check_output ( 'ip route show dev test1' )
2682 print ( '### ip route show dev test1' )
2684 self
. assertRegex ( output
, '10.21.33.0/24 proto kernel scope link src 10.21.33.1' )
2685 output
= check_output ( 'ip route show table local dev test1' )
2686 print ( '### ip route show table local dev test1' )
2688 self
. assertRegex ( output
, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1' )
2689 self
. assertRegex ( output
, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1' )
2690 self
. assertRegex ( output
, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1' )
2691 self
. assertRegex ( output
, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1' )
2692 self
. assertRegex ( output
, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1' )
2693 self
. assertRegex ( output
, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1' )
2694 output
= check_output ( 'ip -6 route show dev test1' )
2695 print ( '### ip -6 route show dev test1' )
2697 self
. assertRegex ( output
, 'fdde:12:22::1 proto kernel metric 256 pref medium' )
2698 self
. assertRegex ( output
, 'fdde:12:33::/64 proto kernel metric 256 pref medium' )
2699 self
. assertRegex ( output
, 'fe80::/64 proto kernel metric 256 pref medium' )
2700 output
= check_output ( 'ip -6 route show table local dev test1' )
2701 print ( '### ip -6 route show table local dev test1' )
2703 self
. assertRegex ( output
, 'local fdde:12:22::1 proto kernel metric 0 pref medium' )
2704 self
. assertRegex ( output
, 'local fdde:12:33::1 proto kernel metric 0 pref medium' )
2705 self
. assertRegex ( output
, 'local fdde:12:44::1 proto kernel metric 0 pref medium' )
2706 self
. assertRegex ( output
, 'local fdde:12:55::1 proto kernel metric 0 pref medium' )
2707 self
. assertRegex ( output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium' )
2709 def test_configure_without_carrier ( self
):
2710 copy_network_unit ( '11-dummy.netdev' )
2712 self
. wait_operstate ( 'test1' , 'off' , '' )
2713 check_output ( 'ip link set dev test1 up carrier off' )
2715 copy_network_unit ( '25-test1.network.d/configure-without-carrier.conf' , copy_dropins
= False )
2717 self
. wait_online ([ 'test1:no-carrier' ])
2719 carrier_map
= { 'on' : '1' , 'off' : '0' }
2720 routable_map
= { 'on' : 'routable' , 'off' : 'no-carrier' }
2721 for carrier
in [ 'off' , 'on' , 'off' ]:
2722 with self
. subTest ( carrier
= carrier
):
2723 if carrier_map
[ carrier
] != read_link_attr ( 'test1' , 'carrier' ):
2724 check_output ( f
'ip link set dev test1 carrier {carrier} ' )
2725 self
. wait_online ([ f
'test1:{routable_map[carrier]}:{routable_map[carrier]}' ])
2727 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
2729 self
. assertRegex ( output
, '192.168.0.15' )
2730 self
. assertRegex ( output
, '192.168.0.1' )
2731 self
. assertRegex ( output
, routable_map
[ carrier
])
2733 def test_configure_without_carrier_yes_ignore_carrier_loss_no ( self
):
2734 copy_network_unit ( '11-dummy.netdev' )
2736 self
. wait_operstate ( 'test1' , 'off' , '' )
2737 check_output ( 'ip link set dev test1 up carrier off' )
2739 copy_network_unit ( '25-test1.network' )
2741 self
. wait_online ([ 'test1:no-carrier' ])
2743 carrier_map
= { 'on' : '1' , 'off' : '0' }
2744 routable_map
= { 'on' : 'routable' , 'off' : 'no-carrier' }
2745 for ( carrier
, have_config
) in [( 'off' , True ), ( 'on' , True ), ( 'off' , False )]:
2746 with self
. subTest ( carrier
= carrier
, have_config
= have_config
):
2747 if carrier_map
[ carrier
] != read_link_attr ( 'test1' , 'carrier' ):
2748 check_output ( f
'ip link set dev test1 carrier {carrier} ' )
2749 self
. wait_online ([ f
'test1:{routable_map[carrier]}:{routable_map[carrier]}' ])
2751 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
2754 self
. assertRegex ( output
, '192.168.0.15' )
2755 self
. assertRegex ( output
, '192.168.0.1' )
2757 self
. assertNotRegex ( output
, '192.168.0.15' )
2758 self
. assertNotRegex ( output
, '192.168.0.1' )
2759 self
. assertRegex ( output
, routable_map
[ carrier
])
2761 def test_routing_policy_rule ( self
):
2762 copy_network_unit ( '25-routing-policy-rule-test1.network' , '11-dummy.netdev' )
2764 self
. wait_online ([ 'test1:degraded' ])
2766 output
= check_output ( 'ip rule list iif test1 priority 111' )
2768 self
. assertRegex ( output
, '111:' )
2769 self
. assertRegex ( output
, 'from 192.168.100.18' )
2770 self
. assertRegex ( output
, r
'tos (0x08|throughput)\s' )
2771 self
. assertRegex ( output
, 'iif test1' )
2772 self
. assertRegex ( output
, 'oif test1' )
2773 self
. assertRegex ( output
, 'lookup 7' )
2775 output
= check_output ( 'ip rule list iif test1 priority 101' )
2777 self
. assertRegex ( output
, '101:' )
2778 self
. assertRegex ( output
, 'from all' )
2779 self
. assertRegex ( output
, 'iif test1' )
2780 self
. assertRegex ( output
, 'lookup 9' )
2782 output
= check_output ( 'ip -6 rule list iif test1 priority 100' )
2784 self
. assertRegex ( output
, '100:' )
2785 self
. assertRegex ( output
, 'from all' )
2786 self
. assertRegex ( output
, 'iif test1' )
2787 self
. assertRegex ( output
, 'lookup 8' )
2789 output
= check_output ( 'ip rule list iif test1 priority 102' )
2791 self
. assertRegex ( output
, '102:' )
2792 self
. assertRegex ( output
, 'from 0.0.0.0/8' )
2793 self
. assertRegex ( output
, 'iif test1' )
2794 self
. assertRegex ( output
, 'lookup 10' )
2796 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2799 def test_routing_policy_rule_issue_11280 ( self
):
2800 copy_network_unit ( '25-routing-policy-rule-test1.network' , '11-dummy.netdev' ,
2801 '25-routing-policy-rule-dummy98.network' , '12-dummy.netdev' )
2803 for trial
in range ( 3 ):
2804 restart_networkd ( show_logs
=( trial
> 0 ))
2805 self
. wait_online ([ 'test1:degraded' , 'dummy98:degraded' ])
2807 output
= check_output ( 'ip rule list table 7' )
2809 self
. assertRegex ( output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7' )
2811 output
= check_output ( 'ip rule list table 8' )
2813 self
. assertRegex ( output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8' )
2815 def test_routing_policy_rule_reconfigure ( self
):
2816 copy_network_unit ( '25-routing-policy-rule-reconfigure2.network' , '11-dummy.netdev' )
2818 self
. wait_online ([ 'test1:degraded' ])
2820 output
= check_output ( 'ip rule list table 1011' )
2822 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2823 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2824 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2825 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2827 output
= check_output ( 'ip -6 rule list table 1011' )
2829 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2831 copy_network_unit ( '25-routing-policy-rule-reconfigure1.network' , '11-dummy.netdev' )
2833 self
. wait_online ([ 'test1:degraded' ])
2835 output
= check_output ( 'ip rule list table 1011' )
2837 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2838 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2839 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2840 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2842 output
= check_output ( 'ip -6 rule list table 1011' )
2844 self
. assertNotIn ( '10112: from all oif test1 lookup 1011' , output
)
2845 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2847 call ( 'ip rule delete priority 10111' )
2848 call ( 'ip rule delete priority 10112' )
2849 call ( 'ip rule delete priority 10113' )
2850 call ( 'ip rule delete priority 10114' )
2851 call ( 'ip -6 rule delete priority 10113' )
2853 output
= check_output ( 'ip rule list table 1011' )
2855 self
. assertEqual ( output
, '' )
2857 output
= check_output ( 'ip -6 rule list table 1011' )
2859 self
. assertEqual ( output
, '' )
2861 networkctl_reconfigure ( 'test1' )
2862 self
. wait_online ([ 'test1:degraded' ])
2864 output
= check_output ( 'ip rule list table 1011' )
2866 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2867 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2868 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2869 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2871 output
= check_output ( 'ip -6 rule list table 1011' )
2873 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2875 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable ()
2876 def test_routing_policy_rule_port_range ( self
):
2877 copy_network_unit ( '25-fibrule-port-range.network' , '11-dummy.netdev' )
2879 self
. wait_online ([ 'test1:degraded' ])
2881 output
= check_output ( 'ip rule' )
2883 self
. assertRegex ( output
, '111' )
2884 self
. assertRegex ( output
, 'from 192.168.100.18' )
2885 self
. assertRegex ( output
, '1123-1150' )
2886 self
. assertRegex ( output
, '3224-3290' )
2887 self
. assertRegex ( output
, 'tcp' )
2888 self
. assertRegex ( output
, 'lookup 7' )
2890 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable ()
2891 def test_routing_policy_rule_invert ( self
):
2892 copy_network_unit ( '25-fibrule-invert.network' , '11-dummy.netdev' )
2894 self
. wait_online ([ 'test1:degraded' ])
2896 output
= check_output ( 'ip rule' )
2898 self
. assertRegex ( output
, '111' )
2899 self
. assertRegex ( output
, 'not.*?from.*?192.168.100.18' )
2900 self
. assertRegex ( output
, 'tcp' )
2901 self
. assertRegex ( output
, 'lookup 7' )
2903 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable ()
2904 def test_routing_policy_rule_uidrange ( self
):
2905 copy_network_unit ( '25-fibrule-uidrange.network' , '11-dummy.netdev' )
2907 self
. wait_online ([ 'test1:degraded' ])
2909 output
= check_output ( 'ip rule' )
2911 self
. assertRegex ( output
, '111' )
2912 self
. assertRegex ( output
, 'from 192.168.100.18' )
2913 self
. assertRegex ( output
, 'lookup 7' )
2914 self
. assertRegex ( output
, 'uidrange 100-200' )
2916 def _test_route_static ( self
, manage_foreign_routes
):
2917 if not manage_foreign_routes
:
2918 copy_networkd_conf_dropin ( 'networkd-manage-foreign-routes-no.conf' )
2920 copy_network_unit ( '25-route-static.network' , '12-dummy.netdev' )
2922 self
. wait_online ([ 'dummy98:routable' ])
2924 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
2927 print ( '### ip -6 route show dev dummy98' )
2928 output
= check_output ( 'ip -6 route show dev dummy98' )
2930 self
. assertIn ( '2001:1234:5:8fff:ff:ff:ff:ff proto static' , output
)
2931 self
. assertIn ( '2001:1234:5:8f63::1 proto kernel' , output
)
2932 self
. assertIn ( '2001:1234:5:afff:ff:ff:ff:ff via fe80:0:222:4dff:ff:ff:ff:ff proto static' , output
)
2934 print ( '### ip -6 route show default' )
2935 output
= check_output ( 'ip -6 route show default' )
2937 self
. assertIn ( 'default' , output
)
2938 self
. assertIn ( 'via 2001:1234:5:8fff:ff:ff:ff:ff' , output
)
2940 print ( '### ip -4 route show dev dummy98' )
2941 output
= check_output ( 'ip -4 route show dev dummy98' )
2943 self
. assertIn ( '149.10.124.48/28 proto kernel scope link src 149.10.124.58' , output
)
2944 self
. assertIn ( '149.10.124.64 proto static scope link' , output
)
2945 self
. assertIn ( '169.254.0.0/16 proto static scope link metric 2048' , output
)
2946 self
. assertIn ( '192.168.1.1 proto static scope link initcwnd 20' , output
)
2947 self
. assertIn ( '192.168.1.2 proto static scope link initrwnd 30' , output
)
2948 self
. assertIn ( '192.168.1.3 proto static scope link advmss 30' , output
)
2949 self
. assertIn ( 'multicast 149.10.123.4 proto static' , output
)
2951 print ( '### ip -4 route show dev dummy98 default' )
2952 output
= check_output ( 'ip -4 route show dev dummy98 default' )
2954 self
. assertIn ( 'default via 149.10.125.65 proto static onlink' , output
)
2955 self
. assertIn ( 'default via 149.10.124.64 proto static' , output
)
2956 self
. assertIn ( 'default proto static' , output
)
2958 print ( '### ip -4 route show table local dev dummy98' )
2959 output
= check_output ( 'ip -4 route show table local dev dummy98' )
2961 self
. assertIn ( 'local 149.10.123.1 proto static scope host' , output
)
2962 self
. assertIn ( 'anycast 149.10.123.2 proto static scope link' , output
)
2963 self
. assertIn ( 'broadcast 149.10.123.3 proto static scope link' , output
)
2965 print ( '### ip -4 route show type blackhole' )
2966 output
= check_output ( 'ip -4 route show type blackhole' )
2968 self
. assertIn ( 'blackhole 202.54.1.2 proto static' , output
)
2970 print ( '### ip -4 route show type unreachable' )
2971 output
= check_output ( 'ip -4 route show type unreachable' )
2973 self
. assertIn ( 'unreachable 202.54.1.3 proto static' , output
)
2975 print ( '### ip -4 route show type prohibit' )
2976 output
= check_output ( 'ip -4 route show type prohibit' )
2978 self
. assertIn ( 'prohibit 202.54.1.4 proto static' , output
)
2980 print ( '### ip -6 route show type blackhole' )
2981 output
= check_output ( 'ip -6 route show type blackhole' )
2983 self
. assertIn ( 'blackhole 2001:1234:5678::2 dev lo proto static' , output
)
2985 print ( '### ip -6 route show type unreachable' )
2986 output
= check_output ( 'ip -6 route show type unreachable' )
2988 self
. assertIn ( 'unreachable 2001:1234:5678::3 dev lo proto static' , output
)
2990 print ( '### ip -6 route show type prohibit' )
2991 output
= check_output ( 'ip -6 route show type prohibit' )
2993 self
. assertIn ( 'prohibit 2001:1234:5678::4 dev lo proto static' , output
)
2995 print ( '### ip route show 192.168.10.1' )
2996 output
= check_output ( 'ip route show 192.168.10.1' )
2998 self
. assertIn ( '192.168.10.1 proto static' , output
)
2999 self
. assertIn ( 'nexthop via 149.10.124.59 dev dummy98 weight 10' , output
)
3000 self
. assertIn ( 'nexthop via 149.10.124.60 dev dummy98 weight 5' , output
)
3002 print ( '### ip route show 192.168.10.2' )
3003 output
= check_output ( 'ip route show 192.168.10.2' )
3005 # old ip command does not show IPv6 gateways...
3006 self
. assertIn ( '192.168.10.2 proto static' , output
)
3007 self
. assertIn ( 'nexthop' , output
)
3008 self
. assertIn ( 'dev dummy98 weight 10' , output
)
3009 self
. assertIn ( 'dev dummy98 weight 5' , output
)
3011 print ( '### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff' )
3012 output
= check_output ( 'ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff' )
3014 # old ip command does not show 'nexthop' keyword and weight...
3015 self
. assertIn ( '2001:1234:5:7fff:ff:ff:ff:ff' , output
)
3016 self
. assertIn ( 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98' , output
)
3017 self
. assertIn ( 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98' , output
)
3019 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3022 copy_network_unit ( '25-address-static.network' )
3024 self
. wait_online ([ 'dummy98:routable' ])
3026 # check all routes managed by Manager are removed
3027 print ( '### ip -4 route show type blackhole' )
3028 output
= check_output ( 'ip -4 route show type blackhole' )
3030 self
. assertEqual ( output
, '' )
3032 print ( '### ip -4 route show type unreachable' )
3033 output
= check_output ( 'ip -4 route show type unreachable' )
3035 self
. assertEqual ( output
, '' )
3037 print ( '### ip -4 route show type prohibit' )
3038 output
= check_output ( 'ip -4 route show type prohibit' )
3040 self
. assertEqual ( output
, '' )
3042 print ( '### ip -6 route show type blackhole' )
3043 output
= check_output ( 'ip -6 route show type blackhole' )
3045 self
. assertEqual ( output
, '' )
3047 print ( '### ip -6 route show type unreachable' )
3048 output
= check_output ( 'ip -6 route show type unreachable' )
3050 self
. assertEqual ( output
, '' )
3052 print ( '### ip -6 route show type prohibit' )
3053 output
= check_output ( 'ip -6 route show type prohibit' )
3055 self
. assertEqual ( output
, '' )
3057 remove_network_unit ( '25-address-static.network' )
3059 self
. wait_online ([ 'dummy98:routable' ])
3061 # check all routes managed by Manager are reconfigured
3062 print ( '### ip -4 route show type blackhole' )
3063 output
= check_output ( 'ip -4 route show type blackhole' )
3065 self
. assertIn ( 'blackhole 202.54.1.2 proto static' , output
)
3067 print ( '### ip -4 route show type unreachable' )
3068 output
= check_output ( 'ip -4 route show type unreachable' )
3070 self
. assertIn ( 'unreachable 202.54.1.3 proto static' , output
)
3072 print ( '### ip -4 route show type prohibit' )
3073 output
= check_output ( 'ip -4 route show type prohibit' )
3075 self
. assertIn ( 'prohibit 202.54.1.4 proto static' , output
)
3077 print ( '### ip -6 route show type blackhole' )
3078 output
= check_output ( 'ip -6 route show type blackhole' )
3080 self
. assertIn ( 'blackhole 2001:1234:5678::2 dev lo proto static' , output
)
3082 print ( '### ip -6 route show type unreachable' )
3083 output
= check_output ( 'ip -6 route show type unreachable' )
3085 self
. assertIn ( 'unreachable 2001:1234:5678::3 dev lo proto static' , output
)
3087 print ( '### ip -6 route show type prohibit' )
3088 output
= check_output ( 'ip -6 route show type prohibit' )
3090 self
. assertIn ( 'prohibit 2001:1234:5678::4 dev lo proto static' , output
)
3092 remove_link ( 'dummy98' )
3095 # check all routes managed by Manager are removed
3096 print ( '### ip -4 route show type blackhole' )
3097 output
= check_output ( 'ip -4 route show type blackhole' )
3099 self
. assertEqual ( output
, '' )
3101 print ( '### ip -4 route show type unreachable' )
3102 output
= check_output ( 'ip -4 route show type unreachable' )
3104 self
. assertEqual ( output
, '' )
3106 print ( '### ip -4 route show type prohibit' )
3107 output
= check_output ( 'ip -4 route show type prohibit' )
3109 self
. assertEqual ( output
, '' )
3111 print ( '### ip -6 route show type blackhole' )
3112 output
= check_output ( 'ip -6 route show type blackhole' )
3114 self
. assertEqual ( output
, '' )
3116 print ( '### ip -6 route show type unreachable' )
3117 output
= check_output ( 'ip -6 route show type unreachable' )
3119 self
. assertEqual ( output
, '' )
3121 print ( '### ip -6 route show type prohibit' )
3122 output
= check_output ( 'ip -6 route show type prohibit' )
3124 self
. assertEqual ( output
, '' )
3128 def test_route_static ( self
):
3130 for manage_foreign_routes
in [ True , False ]:
3136 print ( f
'### test_route_static(manage_foreign_routes= {manage_foreign_routes} )' )
3137 with self
. subTest ( manage_foreign_routes
= manage_foreign_routes
):
3138 self
._ test
_ route
_ static
( manage_foreign_routes
)
3140 @expectedFailureIfRTA_VIAIsNotSupported ()
3141 def test_route_via_ipv6 ( self
):
3142 copy_network_unit ( '25-route-via-ipv6.network' , '12-dummy.netdev' )
3144 self
. wait_online ([ 'dummy98:routable' ])
3146 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
3149 print ( '### ip -6 route show dev dummy98' )
3150 output
= check_output ( 'ip -6 route show dev dummy98' )
3152 self
. assertRegex ( output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static' )
3153 self
. assertRegex ( output
, '2001:1234:5:8f63::1 proto kernel' )
3155 print ( '### ip -4 route show dev dummy98' )
3156 output
= check_output ( 'ip -4 route show dev dummy98' )
3158 self
. assertRegex ( output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58' )
3159 self
. assertRegex ( output
, '149.10.124.66 via inet6 2001:1234:5:8fff:ff:ff:ff:ff proto static' )
3161 @expectedFailureIfModuleIsNotAvailable ( 'tcp_dctcp' )
3162 def test_route_congctl ( self
):
3163 copy_network_unit ( '25-route-congctl.network' , '12-dummy.netdev' )
3165 self
. wait_online ([ 'dummy98:routable' ])
3167 print ( '### ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff' )
3168 output
= check_output ( 'ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff' )
3170 self
. assertIn ( '2001:1234:5:8fff:ff:ff:ff:ff proto static' , output
)
3171 self
. assertIn ( 'congctl dctcp' , output
)
3173 print ( '### ip -4 route show dev dummy98 149.10.124.66' )
3174 output
= check_output ( 'ip -4 route show dev dummy98 149.10.124.66' )
3176 self
. assertIn ( '149.10.124.66 proto static' , output
)
3177 self
. assertIn ( 'congctl dctcp' , output
)
3179 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
3180 def test_route_vrf ( self
):
3181 copy_network_unit ( '25-route-vrf.network' , '12-dummy.netdev' ,
3182 '25-vrf.netdev' , '25-vrf.network' )
3184 self
. wait_online ([ 'dummy98:routable' , 'vrf99:carrier' ])
3186 output
= check_output ( 'ip route show vrf vrf99' )
3188 self
. assertRegex ( output
, 'default via 192.168.100.1' )
3190 output
= check_output ( 'ip route show' )
3192 self
. assertNotRegex ( output
, 'default via 192.168.100.1' )
3194 def test_gateway_reconfigure ( self
):
3195 copy_network_unit ( '25-gateway-static.network' , '12-dummy.netdev' )
3197 self
. wait_online ([ 'dummy98:routable' ])
3198 print ( '### ip -4 route show dev dummy98 default' )
3199 output
= check_output ( 'ip -4 route show dev dummy98 default' )
3201 self
. assertIn ( 'default via 149.10.124.59 proto static' , output
)
3202 self
. assertNotIn ( '149.10.124.60' , output
)
3204 remove_network_unit ( '25-gateway-static.network' )
3205 copy_network_unit ( '25-gateway-next-static.network' )
3207 self
. wait_online ([ 'dummy98:routable' ])
3208 print ( '### ip -4 route show dev dummy98 default' )
3209 output
= check_output ( 'ip -4 route show dev dummy98 default' )
3211 self
. assertNotIn ( '149.10.124.59' , output
)
3212 self
. assertIn ( 'default via 149.10.124.60 proto static' , output
)
3214 def test_ip_route_ipv6_src_route ( self
):
3215 # a dummy device does not make the addresses go through tentative state, so we
3216 # reuse a bond from an earlier test, which does make the addresses go through
3217 # tentative state, and do our test on that
3218 copy_network_unit ( '23-active-slave.network' , '25-route-ipv6-src.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
3220 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:routable' ])
3222 output
= check_output ( 'ip -6 route list dev bond199' )
3224 self
. assertIn ( 'abcd::/16 via 2001:1234:56:8f63::1:1 proto static src 2001:1234:56:8f63::2' , output
)
3226 def test_route_preferred_source_with_existing_address ( self
):
3228 copy_network_unit ( '25-route-preferred-source.network' , '12-dummy.netdev' )
3233 networkctl_reconfigure ( 'dummy98' )
3235 self
. wait_online ([ 'dummy98:routable' ])
3237 output
= check_output ( 'ip -6 route list dev dummy98' )
3239 self
. assertIn ( 'abcd::/16 via 2001:1234:56:8f63::1:1 proto static src 2001:1234:56:8f63::1' , output
)
3241 def test_ip_link_mac_address ( self
):
3242 copy_network_unit ( '25-address-link-section.network' , '12-dummy.netdev' )
3244 self
. wait_online ([ 'dummy98:degraded' ])
3246 output
= check_output ( 'ip link show dummy98' )
3248 self
. assertRegex ( output
, '00:01:02:aa:bb:cc' )
3250 def test_ip_link_unmanaged ( self
):
3251 copy_network_unit ( '25-link-section-unmanaged.network' , '12-dummy.netdev' )
3254 self
. wait_operstate ( 'dummy98' , 'off' , setup_state
= 'unmanaged' )
3256 def test_ipv6_address_label ( self
):
3257 copy_network_unit ( '25-ipv6-address-label-section.network' , '12-dummy.netdev' )
3259 self
. wait_online ([ 'dummy98:degraded' ])
3261 output
= check_output ( 'ip addrlabel list' )
3263 self
. assertRegex ( output
, '2004:da8:1::/64' )
3265 def test_ipv6_proxy_ndp ( self
):
3266 copy_network_unit ( '25-ipv6-proxy-ndp.network' , '12-dummy.netdev' )
3269 self
. wait_online ([ 'dummy98:routable' ])
3271 output
= check_output ( 'ip neighbor show proxy dev dummy98' )
3273 for i
in range ( 1 , 5 ):
3274 self
. assertRegex ( output
, f
'2607:5300:203:5215: {i} ::1 *proxy' )
3276 def test_neighbor_section ( self
):
3277 copy_network_unit ( '25-neighbor-section.network' , '12-dummy.netdev' , copy_dropins
= False )
3279 self
. wait_online ([ 'dummy98:degraded' ])
3281 print ( '### ip neigh list dev dummy98' )
3282 output
= check_output ( 'ip neigh list dev dummy98' )
3284 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:02:65 PERMANENT' , output
)
3285 self
. assertIn ( '2004:da8:1::1 lladdr 00:00:5e:00:02:66 PERMANENT' , output
)
3286 self
. assertNotIn ( '2004:da8:1:0::2' , output
)
3287 self
. assertNotIn ( '192.168.10.2' , output
)
3288 self
. assertNotIn ( '00:00:5e:00:02:67' , output
)
3290 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3293 copy_network_unit ( '25-neighbor-section.network.d/override.conf' )
3295 self
. wait_online ([ 'dummy98:degraded' ])
3297 print ( '### ip neigh list dev dummy98 (after reloading)' )
3298 output
= check_output ( 'ip neigh list dev dummy98' )
3300 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:03:65 PERMANENT' , output
)
3301 self
. assertIn ( '2004:da8:1::1 lladdr 00:00:5e:00:03:66 PERMANENT' , output
)
3302 self
. assertNotIn ( '2004:da8:1:0::2' , output
)
3303 self
. assertNotIn ( '192.168.10.2' , output
)
3304 self
. assertNotIn ( '00:00:5e:00:02' , output
)
3306 def test_neighbor_reconfigure ( self
):
3307 copy_network_unit ( '25-neighbor-section.network' , '12-dummy.netdev' , copy_dropins
= False )
3309 self
. wait_online ([ 'dummy98:degraded' ])
3311 print ( '### ip neigh list dev dummy98' )
3312 output
= check_output ( 'ip neigh list dev dummy98' )
3314 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:02:65 PERMANENT' , output
)
3315 self
. assertIn ( '2004:da8:1::1 lladdr 00:00:5e:00:02:66 PERMANENT' , output
)
3317 remove_network_unit ( '25-neighbor-section.network' )
3318 copy_network_unit ( '25-neighbor-next.network' )
3320 self
. wait_online ([ 'dummy98:degraded' ])
3321 print ( '### ip neigh list dev dummy98' )
3322 output
= check_output ( 'ip neigh list dev dummy98' )
3324 self
. assertNotIn ( '00:00:5e:00:02:65' , output
)
3325 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:02:66 PERMANENT' , output
)
3326 self
. assertNotIn ( '2004:da8:1::1' , output
)
3328 def test_neighbor_gre ( self
):
3329 copy_network_unit ( '25-neighbor-ip.network' , '25-neighbor-ipv6.network' , '25-neighbor-ip-dummy.network' ,
3330 '12-dummy.netdev' , '25-gre-tunnel-remote-any.netdev' , '25-ip6gre-tunnel-remote-any.netdev' )
3332 self
. wait_online ([ 'dummy98:degraded' , 'gretun97:routable' , 'ip6gretun97:routable' ], timeout
= '40s' )
3334 output
= check_output ( 'ip neigh list dev gretun97' )
3336 self
. assertIn ( '10.0.0.22 lladdr 10.65.223.239 PERMANENT' , output
)
3337 self
. assertNotIn ( '10.0.0.23' , output
)
3339 output
= check_output ( 'ip neigh list dev ip6gretun97' )
3341 self
. assertRegex ( output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT' )
3342 self
. assertNotIn ( '2001:db8:0:f102::18' , output
)
3344 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3347 def test_link_local_addressing ( self
):
3348 copy_network_unit ( '25-link-local-addressing-yes.network' , '11-dummy.netdev' ,
3349 '25-link-local-addressing-no.network' , '12-dummy.netdev' )
3351 self
. wait_online ([ 'test1:degraded' , 'dummy98:carrier' ])
3353 output
= check_output ( 'ip address show dev test1' )
3355 self
. assertRegex ( output
, 'inet .* scope link' )
3356 self
. assertRegex ( output
, 'inet6 .* scope link' )
3358 output
= check_output ( 'ip address show dev dummy98' )
3360 self
. assertNotRegex ( output
, 'inet6* .* scope link' )
3362 # Documentation/networking/ip-sysctl.txt
3364 # addr_gen_mode - INTEGER
3365 # Defines how link-local and autoconf addresses are generated.
3367 # 0: generate address based on EUI64 (default)
3368 # 1: do no generate a link-local address, use EUI64 for addresses generated
3370 # 2: generate stable privacy addresses, using the secret from
3371 # stable_secret (RFC7217)
3372 # 3: generate stable privacy addresses, using a random secret if unset
3374 self
. check_ipv6_sysctl_attr ( 'test1' , 'stable_secret' , '0123:4567:89ab:cdef:0123:4567:89ab:cdef' )
3375 self
. check_ipv6_sysctl_attr ( 'test1' , 'addr_gen_mode' , '2' )
3376 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'addr_gen_mode' , '1' )
3378 def test_link_local_addressing_ipv6ll ( self
):
3379 copy_network_unit ( '26-link-local-addressing-ipv6.network' , '12-dummy.netdev' )
3381 self
. wait_online ([ 'dummy98:degraded' ])
3383 # An IPv6LL address exists by default.
3384 output
= check_output ( 'ip address show dev dummy98' )
3386 self
. assertRegex ( output
, 'inet6 .* scope link' )
3388 copy_network_unit ( '25-link-local-addressing-no.network' )
3390 self
. wait_online ([ 'dummy98:carrier' ])
3392 # Check if the IPv6LL address is removed.
3393 output
= check_output ( 'ip address show dev dummy98' )
3395 self
. assertNotRegex ( output
, 'inet6 .* scope link' )
3397 remove_network_unit ( '25-link-local-addressing-no.network' )
3399 self
. wait_online ([ 'dummy98:degraded' ])
3401 # Check if a new IPv6LL address is assigned.
3402 output
= check_output ( 'ip address show dev dummy98' )
3404 self
. assertRegex ( output
, 'inet6 .* scope link' )
3406 def test_sysctl ( self
):
3407 copy_networkd_conf_dropin ( '25-global-ipv6-privacy-extensions.conf' )
3408 copy_network_unit ( '25-sysctl.network' , '12-dummy.netdev' , copy_dropins
= False )
3410 self
. wait_online ([ 'dummy98:degraded' ])
3412 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
3413 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'use_tempaddr' , '1' )
3414 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'dad_transmits' , '3' )
3415 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'hop_limit' , '5' )
3416 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'proxy_ndp' , '1' )
3417 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
3418 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'proxy_arp' , '1' )
3419 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'accept_local' , '1' )
3420 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'rp_filter' , '0' )
3422 copy_network_unit ( '25-sysctl.network.d/25-ipv6-privacy-extensions.conf' )
3424 self
. wait_online ([ 'dummy98:degraded' ])
3426 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'use_tempaddr' , '2' )
3428 def test_sysctl_disable_ipv6 ( self
):
3429 copy_network_unit ( '25-sysctl-disable-ipv6.network' , '12-dummy.netdev' )
3431 print ( '## Disable ipv6' )
3432 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=1' )
3433 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=1' )
3436 self
. wait_online ([ 'dummy98:routable' ])
3438 output
= check_output ( 'ip -4 address show dummy98' )
3440 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3441 output
= check_output ( 'ip -6 address show dummy98' )
3443 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3444 self
. assertRegex ( output
, 'inet6 .* scope link' )
3445 output
= check_output ( 'ip -4 route show dev dummy98' )
3447 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3448 output
= check_output ( 'ip -6 route show default' )
3450 self
. assertRegex ( output
, 'default' )
3451 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3453 remove_link ( 'dummy98' )
3455 print ( '## Enable ipv6' )
3456 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=0' )
3457 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=0' )
3460 self
. wait_online ([ 'dummy98:routable' ])
3462 output
= check_output ( 'ip -4 address show dummy98' )
3464 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3465 output
= check_output ( 'ip -6 address show dummy98' )
3467 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3468 self
. assertRegex ( output
, 'inet6 .* scope link' )
3469 output
= check_output ( 'ip -4 route show dev dummy98' )
3471 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3472 output
= check_output ( 'ip -6 route show default' )
3474 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3476 def test_bind_carrier ( self
):
3477 copy_network_unit ( '25-bind-carrier.network' , '11-dummy.netdev' )
3480 # no bound interface.
3481 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
3482 output
= check_output ( 'ip address show test1' )
3484 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3485 self
. assertIn ( 'DOWN' , output
)
3486 self
. assertNotIn ( '192.168.10' , output
)
3488 # add one bound interface. The interface will be up.
3489 check_output ( 'ip link add dummy98 type dummy' )
3490 check_output ( 'ip link set dummy98 up' )
3491 self
. wait_online ([ 'test1:routable' ])
3492 output
= check_output ( 'ip address show test1' )
3494 self
. assertIn ( 'UP,LOWER_UP' , output
)
3495 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3497 # add another bound interface. The interface is still up.
3498 check_output ( 'ip link add dummy99 type dummy' )
3499 check_output ( 'ip link set dummy99 up' )
3500 self
. wait_operstate ( 'dummy99' , 'degraded' , setup_state
= 'unmanaged' )
3501 output
= check_output ( 'ip address show test1' )
3503 self
. assertIn ( 'UP,LOWER_UP' , output
)
3504 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3506 # remove one of the bound interfaces. The interface is still up
3507 remove_link ( 'dummy98' )
3508 output
= check_output ( 'ip address show test1' )
3510 self
. assertIn ( 'UP,LOWER_UP' , output
)
3511 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3513 # bring down the remaining bound interface. The interface will be down.
3514 check_output ( 'ip link set dummy99 down' )
3515 self
. wait_operstate ( 'test1' , 'off' )
3516 self
. wait_address_dropped ( 'test1' , r
'192.168.10' , ipv
= '-4' , timeout_sec
= 10 )
3517 output
= check_output ( 'ip address show test1' )
3519 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3520 self
. assertIn ( 'DOWN' , output
)
3521 self
. assertNotIn ( '192.168.10' , output
)
3523 # bring up the bound interface. The interface will be up.
3524 check_output ( 'ip link set dummy99 up' )
3525 self
. wait_online ([ 'test1:routable' ])
3526 output
= check_output ( 'ip address show test1' )
3528 self
. assertIn ( 'UP,LOWER_UP' , output
)
3529 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3531 # remove the remaining bound interface. The interface will be down.
3532 remove_link ( 'dummy99' )
3533 self
. wait_operstate ( 'test1' , 'off' )
3534 self
. wait_address_dropped ( 'test1' , r
'192.168.10' , ipv
= '-4' , timeout_sec
= 10 )
3535 output
= check_output ( 'ip address show test1' )
3537 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3538 self
. assertIn ( 'DOWN' , output
)
3539 self
. assertNotIn ( '192.168.10' , output
)
3541 # re-add one bound interface. The interface will be up.
3542 check_output ( 'ip link add dummy98 type dummy' )
3543 check_output ( 'ip link set dummy98 up' )
3544 self
. wait_online ([ 'test1:routable' ])
3545 output
= check_output ( 'ip address show test1' )
3547 self
. assertIn ( 'UP,LOWER_UP' , output
)
3548 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3550 def _test_activation_policy ( self
, interface
, test
):
3551 conffile
= '25-activation-policy.network'
3553 conffile
= f
' {conffile} .d/ {test} .conf'
3554 if interface
== 'vlan99' :
3555 copy_network_unit ( '21-vlan.netdev' , '21-vlan-test1.network' )
3556 copy_network_unit ( '11-dummy.netdev' , conffile
, copy_dropins
= False )
3559 always
= test
. startswith ( 'always' )
3560 initial_up
= test
!= 'manual' and not test
. endswith ( 'down' ) # note: default is up
3561 expect_up
= initial_up
3562 next_up
= not expect_up
3564 if test
. endswith ( 'down' ):
3565 self
. wait_activated ( interface
)
3567 for iteration
in range ( 4 ):
3568 with self
. subTest ( iteration
= iteration
, expect_up
= expect_up
):
3569 operstate
= 'routable' if expect_up
else 'off'
3570 setup_state
= 'configured' if expect_up
else ( 'configuring' if iteration
== 0 else None )
3571 self
. wait_operstate ( interface
, operstate
, setup_state
= setup_state
, setup_timeout
= 20 )
3574 self
. assertIn ( 'UP' , check_output ( f
'ip link show {interface} ' ))
3575 self
. assertIn ( '192.168.10.30/24' , check_output ( f
'ip address show {interface} ' ))
3576 self
. assertIn ( 'default via 192.168.10.1' , check_output ( f
'ip route show dev {interface} ' ))
3578 self
. assertIn ( 'DOWN' , check_output ( f
'ip link show {interface} ' ))
3581 check_output ( f
'ip link set dev {interface} up' )
3583 check_output ( f
'ip link set dev {interface} down' )
3584 expect_up
= initial_up
if always
else next_up
3585 next_up
= not next_up
3589 def test_activation_policy ( self
):
3591 for interface
in [ 'test1' , 'vlan99' ]:
3592 for test
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , '' ]:
3598 print ( f
'### test_activation_policy(interface= {interface} , test= {test} )' )
3599 with self
. subTest ( interface
= interface
, test
= test
):
3600 self
._ test
_ activation
_ policy
( interface
, test
)
3602 def _test_activation_policy_required_for_online ( self
, policy
, required
):
3603 conffile
= '25-activation-policy.network'
3604 units
= [ '11-dummy.netdev' , '12-dummy.netdev' , '12-dummy.network' , conffile
]
3606 units
+= [ f
' {conffile} .d/ {policy} .conf' ]
3608 units
+= [ f
' {conffile} .d/required- {required} .conf' ]
3609 copy_network_unit (* units
, copy_dropins
= False )
3612 if policy
. endswith ( 'down' ):
3613 self
. wait_activated ( 'test1' )
3615 if policy
. endswith ( 'down' ) or policy
== 'manual' :
3616 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
3618 self
. wait_online ([ 'test1' ])
3620 if policy
== 'always-down' :
3621 # if always-down, required for online is forced to no
3624 # otherwise if required for online is specified, it should match that
3625 expected
= required
== 'yes'
3627 # otherwise if only policy specified, required for online defaults to
3628 # true if policy is up, always-up, or bound
3629 expected
= policy
. endswith ( 'up' ) or policy
== 'bound'
3631 # default is true, if neither are specified
3634 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
3637 yesno
= 'yes' if expected
else 'no'
3638 self
. assertRegex ( output
, f
'Required For Online: {yesno} ' )
3640 def test_activation_policy_required_for_online ( self
):
3642 for policy
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , 'bound' , '' ]:
3643 for required
in [ 'yes' , 'no' , '' ]:
3649 print ( f
'### test_activation_policy_required_for_online(policy= {policy} , required= {required} )' )
3650 with self
. subTest ( policy
= policy
, required
= required
):
3651 self
._ test
_ activation
_ policy
_ required
_ for
_ online
( policy
, required
)
3653 def test_domain ( self
):
3654 copy_network_unit ( '12-dummy.netdev' , '24-search-domain.network' )
3656 self
. wait_online ([ 'dummy98:routable' ])
3658 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
3660 self
. assertRegex ( output
, 'Address: 192.168.42.100' )
3661 self
. assertRegex ( output
, 'DNS: 192.168.42.1' )
3662 self
. assertRegex ( output
, 'Search Domains: one' )
3664 def test_keep_configuration_static ( self
):
3665 check_output ( 'ip link add name dummy98 type dummy' )
3666 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
3667 check_output ( 'ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500' )
3668 output
= check_output ( 'ip address show dummy98' )
3670 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
3671 self
. assertRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
3672 output
= check_output ( 'ip route show dev dummy98' )
3675 copy_network_unit ( '24-keep-configuration-static.network' )
3677 self
. wait_online ([ 'dummy98:routable' ])
3679 output
= check_output ( 'ip address show dummy98' )
3681 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
3682 self
. assertNotRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
3684 @expectedFailureIfNexthopIsNotAvailable ()
3685 def test_nexthop ( self
):
3686 def check_nexthop ( self
):
3687 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
3689 output
= check_output ( 'ip nexthop list dev veth99' )
3691 self
. assertIn ( 'id 1 via 192.168.5.1 dev veth99' , output
)
3692 self
. assertIn ( 'id 2 via 2001:1234:5:8f63::2 dev veth99' , output
)
3693 self
. assertIn ( 'id 3 dev veth99' , output
)
3694 self
. assertIn ( 'id 4 dev veth99' , output
)
3695 self
. assertRegex ( output
, 'id 5 via 192.168.10.1 dev veth99 .*onlink' )
3696 self
. assertIn ( 'id 8 via fe80:0:222:4dff:ff:ff:ff:ff dev veth99' , output
)
3697 self
. assertRegex ( output
, r
'id [0-9]* via 192.168.5.2 dev veth99' )
3699 output
= check_output ( 'ip nexthop list dev dummy98' )
3701 self
. assertIn ( 'id 20 via 192.168.20.1 dev dummy98' , output
)
3703 # kernel manages blackhole nexthops on lo
3704 output
= check_output ( 'ip nexthop list dev lo' )
3706 self
. assertIn ( 'id 6 blackhole' , output
)
3707 self
. assertIn ( 'id 7 blackhole' , output
)
3709 # group nexthops are shown with -0 option
3710 output
= check_output ( 'ip -0 nexthop list id 21' )
3712 self
. assertRegex ( output
, r
'id 21 group (1,3/20|20/1,3)' )
3714 output
= check_output ( 'ip route show dev veth99 10.10.10.10' )
3716 self
. assertEqual ( '10.10.10.10 nhid 1 via 192.168.5.1 proto static' , output
)
3718 output
= check_output ( 'ip route show dev veth99 10.10.10.11' )
3720 self
. assertEqual ( '10.10.10.11 nhid 2 via inet6 2001:1234:5:8f63::2 proto static' , output
)
3722 output
= check_output ( 'ip route show dev veth99 10.10.10.12' )
3724 self
. assertEqual ( '10.10.10.12 nhid 5 via 192.168.10.1 proto static onlink' , output
)
3726 output
= check_output ( 'ip -6 route show dev veth99 2001:1234:5:8f62::1' )
3728 self
. assertEqual ( '2001:1234:5:8f62::1 nhid 2 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium' , output
)
3730 output
= check_output ( 'ip route show 10.10.10.13' )
3732 self
. assertEqual ( 'blackhole 10.10.10.13 nhid 6 dev lo proto static' , output
)
3734 output
= check_output ( 'ip -6 route show 2001:1234:5:8f62::2' )
3736 self
. assertEqual ( 'blackhole 2001:1234:5:8f62::2 nhid 7 dev lo proto static metric 1024 pref medium' , output
)
3738 output
= check_output ( 'ip route show 10.10.10.14' )
3740 self
. assertIn ( '10.10.10.14 nhid 21 proto static' , output
)
3741 self
. assertIn ( 'nexthop via 192.168.20.1 dev dummy98 weight 1' , output
)
3742 self
. assertIn ( 'nexthop via 192.168.5.1 dev veth99 weight 3' , output
)
3744 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3747 copy_network_unit ( '25-nexthop.network' , '25-veth.netdev' , '25-veth-peer.network' ,
3748 '12-dummy.netdev' , '25-nexthop-dummy.network' )
3753 remove_network_unit ( '25-nexthop.network' )
3754 copy_network_unit ( '25-nexthop-nothing.network' )
3756 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
3758 output
= check_output ( 'ip nexthop list dev veth99' )
3760 self
. assertEqual ( output
, '' )
3761 output
= check_output ( 'ip nexthop list dev lo' )
3763 self
. assertEqual ( output
, '' )
3765 remove_network_unit ( '25-nexthop-nothing.network' )
3766 copy_network_unit ( '25-nexthop.network' )
3767 networkctl_reconfigure ( 'dummy98' )
3772 remove_link ( 'veth99' )
3775 output
= check_output ( 'ip nexthop list dev lo' )
3777 self
. assertEqual ( output
, '' )
3779 class NetworkdTCTests ( unittest
. TestCase
, Utilities
):
3787 @expectedFailureIfModuleIsNotAvailable ( 'sch_cake' )
3788 def test_qdisc_cake ( self
):
3789 copy_network_unit ( '25-qdisc-cake.network' , '12-dummy.netdev' )
3791 self
. wait_online ([ 'dummy98:routable' ])
3793 output
= check_output ( 'tc qdisc show dev dummy98' )
3795 self
. assertIn ( 'qdisc cake 3a: root' , output
)
3796 self
. assertIn ( 'bandwidth 500Mbit' , output
)
3797 self
. assertIn ( 'autorate-ingress' , output
)
3798 self
. assertIn ( 'diffserv8' , output
)
3799 self
. assertIn ( 'dual-dsthost' , output
)
3800 self
. assertIn ( ' nat' , output
)
3801 self
. assertIn ( ' wash' , output
)
3802 self
. assertIn ( ' split-gso' , output
)
3803 self
. assertIn ( ' raw' , output
)
3804 self
. assertIn ( ' atm' , output
)
3805 self
. assertIn ( 'overhead 128' , output
)
3806 self
. assertIn ( 'mpu 20' , output
)
3807 self
. assertIn ( 'fwmark 0xff00' , output
)
3808 self
. assertIn ( 'rtt 1s' , output
)
3809 self
. assertIn ( 'ack-filter-aggressive' , output
)
3811 @expectedFailureIfModuleIsNotAvailable ( 'sch_codel' )
3812 def test_qdisc_codel ( self
):
3813 copy_network_unit ( '25-qdisc-codel.network' , '12-dummy.netdev' )
3815 self
. wait_online ([ 'dummy98:routable' ])
3817 output
= check_output ( 'tc qdisc show dev dummy98' )
3819 self
. assertRegex ( output
, 'qdisc codel 33: root' )
3820 self
. assertRegex ( output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn' )
3822 @expectedFailureIfModuleIsNotAvailable ( 'sch_drr' )
3823 def test_qdisc_drr ( self
):
3824 copy_network_unit ( '25-qdisc-drr.network' , '12-dummy.netdev' )
3826 self
. wait_online ([ 'dummy98:routable' ])
3828 output
= check_output ( 'tc qdisc show dev dummy98' )
3830 self
. assertRegex ( output
, 'qdisc drr 2: root' )
3831 output
= check_output ( 'tc class show dev dummy98' )
3833 self
. assertRegex ( output
, 'class drr 2:30 root quantum 2000b' )
3835 @expectedFailureIfModuleIsNotAvailable ( 'sch_ets' )
3836 def test_qdisc_ets ( self
):
3837 copy_network_unit ( '25-qdisc-ets.network' , '12-dummy.netdev' )
3839 self
. wait_online ([ 'dummy98:routable' ])
3841 output
= check_output ( 'tc qdisc show dev dummy98' )
3844 self
. assertRegex ( output
, 'qdisc ets 3a: root' )
3845 self
. assertRegex ( output
, 'bands 10 strict 3' )
3846 self
. assertRegex ( output
, 'quanta 1 2 3 4 5' )
3847 self
. assertRegex ( output
, 'priomap 3 4 5 6 7' )
3849 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq' )
3850 def test_qdisc_fq ( self
):
3851 copy_network_unit ( '25-qdisc-fq.network' , '12-dummy.netdev' )
3853 self
. wait_online ([ 'dummy98:routable' ])
3855 output
= check_output ( 'tc qdisc show dev dummy98' )
3857 self
. assertRegex ( output
, 'qdisc fq 32: root' )
3858 self
. assertRegex ( output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511' )
3859 self
. assertRegex ( output
, 'quantum 1500' )
3860 self
. assertRegex ( output
, 'initial_quantum 13000' )
3861 self
. assertRegex ( output
, 'maxrate 1Mbit' )
3863 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_codel' )
3864 def test_qdisc_fq_codel ( self
):
3865 copy_network_unit ( '25-qdisc-fq_codel.network' , '12-dummy.netdev' )
3867 self
. wait_online ([ 'dummy98:routable' ])
3869 output
= check_output ( 'tc qdisc show dev dummy98' )
3871 self
. assertRegex ( output
, 'qdisc fq_codel 34: root' )
3872 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' )
3874 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_pie' )
3875 def test_qdisc_fq_pie ( self
):
3876 copy_network_unit ( '25-qdisc-fq_pie.network' , '12-dummy.netdev' )
3878 self
. wait_online ([ 'dummy98:routable' ])
3880 output
= check_output ( 'tc qdisc show dev dummy98' )
3883 self
. assertRegex ( output
, 'qdisc fq_pie 3a: root' )
3884 self
. assertRegex ( output
, 'limit 200000p' )
3886 @expectedFailureIfModuleIsNotAvailable ( 'sch_gred' )
3887 def test_qdisc_gred ( self
):
3888 copy_network_unit ( '25-qdisc-gred.network' , '12-dummy.netdev' )
3890 self
. wait_online ([ 'dummy98:routable' ])
3892 output
= check_output ( 'tc qdisc show dev dummy98' )
3894 self
. assertRegex ( output
, 'qdisc gred 38: root' )
3895 self
. assertRegex ( output
, 'vqs 12 default 10 grio' )
3897 @expectedFailureIfModuleIsNotAvailable ( 'sch_hhf' )
3898 def test_qdisc_hhf ( self
):
3899 copy_network_unit ( '25-qdisc-hhf.network' , '12-dummy.netdev' )
3901 self
. wait_online ([ 'dummy98:routable' ])
3903 output
= check_output ( 'tc qdisc show dev dummy98' )
3905 self
. assertRegex ( output
, 'qdisc hhf 3a: root' )
3906 self
. assertRegex ( output
, 'limit 1022p' )
3908 @expectedFailureIfModuleIsNotAvailable ( 'sch_htb' )
3909 def test_qdisc_htb_fifo ( self
):
3910 copy_network_unit ( '25-qdisc-htb-fifo.network' , '12-dummy.netdev' )
3912 self
. wait_online ([ 'dummy98:routable' ])
3914 output
= check_output ( 'tc qdisc show dev dummy98' )
3916 self
. assertRegex ( output
, 'qdisc htb 2: root' )
3917 self
. assertRegex ( output
, r
'default (0x30|30)' )
3919 self
. assertRegex ( output
, 'qdisc pfifo 37: parent 2:37' )
3920 self
. assertRegex ( output
, 'limit 100000p' )
3922 self
. assertRegex ( output
, 'qdisc bfifo 3a: parent 2:3a' )
3923 self
. assertRegex ( output
, 'limit 1000000' )
3925 self
. assertRegex ( output
, 'qdisc pfifo_head_drop 3b: parent 2:3b' )
3926 self
. assertRegex ( output
, 'limit 1023p' )
3928 self
. assertRegex ( output
, 'qdisc pfifo_fast 3c: parent 2:3c' )
3930 output
= check_output ( 'tc -d class show dev dummy98' )
3932 # Here (:|prio) is a workaround for a bug in iproute2 v6.2.0 caused by
3933 # https://github.com/shemminger/iproute2/commit/010a8388aea11e767ba3a2506728b9ad9760df0e
3934 # which is fixed in v6.3.0 by
3935 # https://github.com/shemminger/iproute2/commit/4e0e56e0ef05387f7f5d8ab41fe6ec6a1897b26d
3936 self
. assertRegex ( output
, 'class htb 2:37 root leaf 37(:|prio) ' )
3937 self
. assertRegex ( output
, 'class htb 2:3a root leaf 3a(:|prio) ' )
3938 self
. assertRegex ( output
, 'class htb 2:3b root leaf 3b(:|prio) ' )
3939 self
. assertRegex ( output
, 'class htb 2:3c root leaf 3c(:|prio) ' )
3940 self
. assertRegex ( output
, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit' )
3941 self
. assertRegex ( output
, 'burst 123456' )
3942 self
. assertRegex ( output
, 'cburst 123457' )
3944 @expectedFailureIfModuleIsNotAvailable ( 'sch_ingress' )
3945 def test_qdisc_ingress ( self
):
3946 copy_network_unit ( '25-qdisc-clsact.network' , '12-dummy.netdev' ,
3947 '25-qdisc-ingress.network' , '11-dummy.netdev' )
3949 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' ])
3951 output
= check_output ( 'tc qdisc show dev dummy98' )
3953 self
. assertRegex ( output
, 'qdisc clsact' )
3955 output
= check_output ( 'tc qdisc show dev test1' )
3957 self
. assertRegex ( output
, 'qdisc ingress' )
3959 @expectedFailureIfModuleIsNotAvailable ( 'sch_netem' )
3960 def test_qdisc_netem ( self
):
3961 copy_network_unit ( '25-qdisc-netem.network' , '12-dummy.netdev' ,
3962 '25-qdisc-netem-compat.network' , '11-dummy.netdev' )
3964 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' ])
3966 output
= check_output ( 'tc qdisc show dev dummy98' )
3968 self
. assertRegex ( output
, 'qdisc netem 30: root' )
3969 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
3971 output
= check_output ( 'tc qdisc show dev test1' )
3973 self
. assertRegex ( output
, 'qdisc netem [0-9a-f]*: root' )
3974 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
3976 @expectedFailureIfModuleIsNotAvailable ( 'sch_pie' )
3977 def test_qdisc_pie ( self
):
3978 copy_network_unit ( '25-qdisc-pie.network' , '12-dummy.netdev' )
3980 self
. wait_online ([ 'dummy98:routable' ])
3982 output
= check_output ( 'tc qdisc show dev dummy98' )
3984 self
. assertRegex ( output
, 'qdisc pie 3a: root' )
3985 self
. assertRegex ( output
, 'limit 200000' )
3987 @expectedFailureIfModuleIsNotAvailable ( 'sch_qfq' )
3988 def test_qdisc_qfq ( self
):
3989 copy_network_unit ( '25-qdisc-qfq.network' , '12-dummy.netdev' )
3991 self
. wait_online ([ 'dummy98:routable' ])
3993 output
= check_output ( 'tc qdisc show dev dummy98' )
3995 self
. assertRegex ( output
, 'qdisc qfq 2: root' )
3996 output
= check_output ( 'tc class show dev dummy98' )
3998 self
. assertRegex ( output
, 'class qfq 2:30 root weight 2 maxpkt 16000' )
3999 self
. assertRegex ( output
, 'class qfq 2:31 root weight 10 maxpkt 8000' )
4001 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfb' )
4002 def test_qdisc_sfb ( self
):
4003 copy_network_unit ( '25-qdisc-sfb.network' , '12-dummy.netdev' )
4005 self
. wait_online ([ 'dummy98:routable' ])
4007 output
= check_output ( 'tc qdisc show dev dummy98' )
4009 self
. assertRegex ( output
, 'qdisc sfb 39: root' )
4010 self
. assertRegex ( output
, 'limit 200000' )
4012 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfq' )
4013 def test_qdisc_sfq ( self
):
4014 copy_network_unit ( '25-qdisc-sfq.network' , '12-dummy.netdev' )
4016 self
. wait_online ([ 'dummy98:routable' ])
4018 output
= check_output ( 'tc qdisc show dev dummy98' )
4020 self
. assertRegex ( output
, 'qdisc sfq 36: root' )
4021 self
. assertRegex ( output
, 'perturb 5sec' )
4023 @expectedFailureIfModuleIsNotAvailable ( 'sch_tbf' )
4024 def test_qdisc_tbf ( self
):
4025 copy_network_unit ( '25-qdisc-tbf.network' , '12-dummy.netdev' )
4027 self
. wait_online ([ 'dummy98:routable' ])
4029 output
= check_output ( 'tc qdisc show dev dummy98' )
4031 self
. assertRegex ( output
, 'qdisc tbf 35: root' )
4032 self
. assertRegex ( output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms' )
4034 @expectedFailureIfModuleIsNotAvailable ( 'sch_teql' )
4035 def test_qdisc_teql ( self
):
4036 call_quiet ( 'rmmod sch_teql' )
4038 copy_network_unit ( '25-qdisc-teql.network' , '12-dummy.netdev' )
4040 self
. wait_links ( 'dummy98' )
4041 check_output ( 'modprobe sch_teql max_equalizers=2' )
4042 self
. wait_online ([ 'dummy98:routable' ])
4044 output
= check_output ( 'tc qdisc show dev dummy98' )
4046 self
. assertRegex ( output
, 'qdisc teql1 31: root' )
4048 class NetworkdStateFileTests ( unittest
. TestCase
, Utilities
):
4056 def test_state_file ( self
):
4057 copy_network_unit ( '12-dummy.netdev' , '25-state-file-tests.network' )
4059 self
. wait_online ([ 'dummy98:routable' ])
4061 # make link state file updated
4062 check_output (* resolvectl_cmd
, 'revert' , 'dummy98' , env
= env
)
4064 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
4067 output
= read_link_state_file ( 'dummy98' )
4069 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
4070 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
4071 self
. assertIn ( 'ADMIN_STATE=configured' , output
)
4072 self
. assertIn ( 'OPER_STATE=routable' , output
)
4073 self
. assertIn ( 'REQUIRED_FOR_ONLINE=yes' , output
)
4074 self
. assertIn ( 'REQUIRED_OPER_STATE_FOR_ONLINE=routable' , output
)
4075 self
. assertIn ( 'REQUIRED_FAMILY_FOR_ONLINE=both' , output
)
4076 self
. assertIn ( 'ACTIVATION_POLICY=up' , output
)
4077 self
. assertIn ( 'NETWORK_FILE=/run/systemd/network/25-state-file-tests.network' , output
)
4078 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
4079 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
4080 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
4081 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
4082 self
. assertIn ( 'LLMNR=no' , output
)
4083 self
. assertIn ( 'MDNS=yes' , output
)
4084 self
. assertIn ( 'DNSSEC=no' , output
)
4086 check_output (* resolvectl_cmd
, 'dns' , 'dummy98' , '10.10.10.12#ccc.com' , '10.10.10.13' , '1111:2222::3333' , env
= env
)
4087 check_output (* resolvectl_cmd
, 'domain' , 'dummy98' , 'hogehogehoge' , '~foofoofoo' , env
= env
)
4088 check_output (* resolvectl_cmd
, 'llmnr' , 'dummy98' , 'yes' , env
= env
)
4089 check_output (* resolvectl_cmd
, 'mdns' , 'dummy98' , 'no' , env
= env
)
4090 check_output (* resolvectl_cmd
, 'dnssec' , 'dummy98' , 'yes' , env
= env
)
4091 check_output (* timedatectl_cmd
, 'ntp-servers' , 'dummy98' , '2.fedora.pool.ntp.org' , '3.fedora.pool.ntp.org' , env
= env
)
4093 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
4096 output
= read_link_state_file ( 'dummy98' )
4098 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
4099 self
. assertIn ( 'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org' , output
)
4100 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
4101 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
4102 self
. assertIn ( 'LLMNR=yes' , output
)
4103 self
. assertIn ( 'MDNS=no' , output
)
4104 self
. assertIn ( 'DNSSEC=yes' , output
)
4106 check_output (* timedatectl_cmd
, 'revert' , 'dummy98' , env
= env
)
4108 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
4111 output
= read_link_state_file ( 'dummy98' )
4113 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
4114 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
4115 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
4116 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
4117 self
. assertIn ( 'LLMNR=yes' , output
)
4118 self
. assertIn ( 'MDNS=no' , output
)
4119 self
. assertIn ( 'DNSSEC=yes' , output
)
4121 check_output (* resolvectl_cmd
, 'revert' , 'dummy98' , env
= env
)
4123 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
4126 output
= read_link_state_file ( 'dummy98' )
4128 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
4129 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
4130 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
4131 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
4132 self
. assertIn ( 'LLMNR=no' , output
)
4133 self
. assertIn ( 'MDNS=yes' , output
)
4134 self
. assertIn ( 'DNSSEC=no' , output
)
4136 def test_address_state ( self
):
4137 copy_network_unit ( '12-dummy.netdev' , '12-dummy-no-address.network' )
4140 self
. wait_online ([ 'dummy98:degraded' ])
4142 output
= read_link_state_file ( 'dummy98' )
4143 self
. assertIn ( 'IPV4_ADDRESS_STATE=off' , output
)
4144 self
. assertIn ( 'IPV6_ADDRESS_STATE=degraded' , output
)
4146 # with a routable IPv4 address
4147 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
4148 self
. wait_online ([ 'dummy98:routable' ], ipv4
= True )
4149 self
. wait_online ([ 'dummy98:routable' ])
4151 output
= read_link_state_file ( 'dummy98' )
4152 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
4153 self
. assertIn ( 'IPV6_ADDRESS_STATE=degraded' , output
)
4155 check_output ( 'ip address del 10.1.2.3/16 dev dummy98' )
4157 # with a routable IPv6 address
4158 check_output ( 'ip address add 2002:da8:1:0:1034:56ff:fe78:9abc/64 dev dummy98' )
4159 self
. wait_online ([ 'dummy98:routable' ], ipv6
= True )
4160 self
. wait_online ([ 'dummy98:routable' ])
4162 output
= read_link_state_file ( 'dummy98' )
4163 self
. assertIn ( 'IPV4_ADDRESS_STATE=off' , output
)
4164 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
4166 class NetworkdBondTests ( unittest
. TestCase
, Utilities
):
4174 def test_bond_keep_master ( self
):
4175 check_output ( 'ip link add bond199 type bond mode active-backup' )
4176 check_output ( 'ip link add dummy98 type dummy' )
4177 check_output ( 'ip link set dummy98 master bond199' )
4179 copy_network_unit ( '23-keep-master.network' )
4181 self
. wait_online ([ 'dummy98:enslaved' ])
4183 output
= check_output ( 'ip -d link show bond199' )
4185 self
. assertRegex ( output
, 'active_slave dummy98' )
4187 output
= check_output ( 'ip -d link show dummy98' )
4189 self
. assertRegex ( output
, 'master bond199' )
4191 def test_bond_active_slave ( self
):
4192 copy_network_unit ( '23-active-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
4194 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
4196 output
= check_output ( 'ip -d link show bond199' )
4198 self
. assertIn ( 'active_slave dummy98' , output
)
4200 def test_bond_primary_slave ( self
):
4201 copy_network_unit ( '23-primary-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
4203 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
4205 output
= check_output ( 'ip -d link show bond199' )
4207 self
. assertIn ( 'primary dummy98' , output
)
4210 mkdir_p ( os
. path
. join ( network_unit_dir
, '23-bond199.network.d' ))
4211 for mac
in [ '00:11:22:33:44:55' , '00:11:22:33:44:56' ]:
4212 with
open ( os
. path
. join ( network_unit_dir
, '23-bond199.network.d/mac.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
4213 f
. write ( f
'[Link] \n MACAddress= {mac} \n ' )
4216 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
4218 output
= check_output ( 'ip -d link show bond199' )
4220 self
. assertIn ( f
'link/ether {mac} ' , output
)
4222 def test_bond_operstate ( self
):
4223 copy_network_unit ( '25-bond.netdev' , '11-dummy.netdev' , '12-dummy.netdev' ,
4224 '25-bond99.network' , '25-bond-slave.network' )
4226 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bond99:routable' ])
4228 output
= check_output ( 'ip -d link show dummy98' )
4230 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
4232 output
= check_output ( 'ip -d link show test1' )
4234 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
4236 output
= check_output ( 'ip -d link show bond99' )
4238 self
. assertRegex ( output
, 'MASTER,UP,LOWER_UP' )
4240 self
. wait_operstate ( 'dummy98' , 'enslaved' )
4241 self
. wait_operstate ( 'test1' , 'enslaved' )
4242 self
. wait_operstate ( 'bond99' , 'routable' )
4244 check_output ( 'ip link set dummy98 down' )
4246 self
. wait_operstate ( 'dummy98' , 'off' )
4247 self
. wait_operstate ( 'test1' , 'enslaved' )
4248 self
. wait_operstate ( 'bond99' , 'routable' )
4250 check_output ( 'ip link set dummy98 up' )
4252 self
. wait_operstate ( 'dummy98' , 'enslaved' )
4253 self
. wait_operstate ( 'test1' , 'enslaved' )
4254 self
. wait_operstate ( 'bond99' , 'routable' )
4256 check_output ( 'ip link set dummy98 down' )
4257 check_output ( 'ip link set test1 down' )
4259 self
. wait_operstate ( 'dummy98' , 'off' )
4260 self
. wait_operstate ( 'test1' , 'off' )
4262 if not self
. wait_operstate ( 'bond99' , 'no-carrier' , setup_timeout
= 30 , fail_assert
= False ):
4263 # Huh? Kernel does not recognize that all slave interfaces are down?
4264 # Let's confirm that networkd's operstate is consistent with ip's result.
4265 self
. assertNotRegex ( output
, 'NO-CARRIER' )
4267 class NetworkdBridgeTests ( unittest
. TestCase
, Utilities
):
4275 def test_bridge_vlan ( self
):
4276 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave.network' ,
4277 '26-bridge.netdev' , '26-bridge-vlan-master.network' )
4279 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' ])
4281 output
= check_output ( 'bridge vlan show dev test1' )
4283 self
. assertNotRegex ( output
, '4063' )
4284 for i
in range ( 4064 , 4095 ):
4285 self
. assertRegex ( output
, f
' {i} ' )
4286 self
. assertNotRegex ( output
, '4095' )
4288 output
= check_output ( 'bridge vlan show dev bridge99' )
4290 self
. assertNotRegex ( output
, '4059' )
4291 for i
in range ( 4060 , 4095 ):
4292 self
. assertRegex ( output
, f
' {i} ' )
4293 self
. assertNotRegex ( output
, '4095' )
4295 def test_bridge_vlan_issue_20373 ( self
):
4296 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave-issue-20373.network' ,
4297 '26-bridge-issue-20373.netdev' , '26-bridge-vlan-master-issue-20373.network' ,
4298 '21-vlan.netdev' , '21-vlan.network' )
4300 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' , 'vlan99:routable' ])
4302 output
= check_output ( 'bridge vlan show dev test1' )
4304 self
. assertIn ( '100 PVID Egress Untagged' , output
)
4305 self
. assertIn ( '560' , output
)
4306 self
. assertIn ( '600' , output
)
4308 output
= check_output ( 'bridge vlan show dev bridge99' )
4310 self
. assertIn ( '1 PVID Egress Untagged' , output
)
4311 self
. assertIn ( '100' , output
)
4312 self
. assertIn ( '600' , output
)
4314 def test_bridge_mdb ( self
):
4315 copy_network_unit ( '11-dummy.netdev' , '26-bridge-mdb-slave.network' ,
4316 '26-bridge.netdev' , '26-bridge-mdb-master.network' )
4318 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' ])
4320 output
= check_output ( 'bridge mdb show dev bridge99' )
4322 self
. assertRegex ( output
, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064' )
4323 self
. assertRegex ( output
, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065' )
4325 # Old kernel may not support bridge MDB entries on bridge master
4326 if call_quiet ( 'bridge mdb add dev bridge99 port bridge99 grp 224.0.1.3 temp vid 4068' ) == 0 :
4327 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp ff02:aaaa:fee5::1:4 temp *vid 4066' )
4328 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp 224.0.1.2 temp *vid 4067' )
4330 def test_bridge_keep_master ( self
):
4331 check_output ( 'ip link add bridge99 type bridge' )
4332 check_output ( 'ip link set bridge99 up' )
4333 check_output ( 'ip link add dummy98 type dummy' )
4334 check_output ( 'ip link set dummy98 master bridge99' )
4336 copy_network_unit ( '23-keep-master.network' )
4338 self
. wait_online ([ 'dummy98:enslaved' ])
4340 output
= check_output ( 'ip -d link show dummy98' )
4342 self
. assertRegex ( output
, 'master bridge99' )
4343 self
. assertRegex ( output
, 'bridge' )
4345 output
= check_output ( 'bridge -d link show dummy98' )
4347 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
4348 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
4349 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
4350 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
4351 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
4352 # CONFIG_BRIDGE_IGMP_SNOOPING=y
4353 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
4354 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
4355 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
4356 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
4357 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
4358 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
4360 def test_bridge_property ( self
):
4361 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
4362 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
4363 '25-bridge99.network' )
4365 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' ])
4367 output
= check_output ( 'ip -d link show bridge99' )
4369 self
. assertIn ( 'mtu 9000 ' , output
)
4371 output
= check_output ( 'ip -d link show test1' )
4373 self
. assertIn ( 'master bridge99 ' , output
)
4374 self
. assertIn ( 'bridge_slave' , output
)
4375 self
. assertIn ( 'mtu 9000 ' , output
)
4377 output
= check_output ( 'ip -d link show dummy98' )
4379 self
. assertIn ( 'master bridge99 ' , output
)
4380 self
. assertIn ( 'bridge_slave' , output
)
4381 self
. assertIn ( 'mtu 9000 ' , output
)
4383 output
= check_output ( 'ip addr show bridge99' )
4385 self
. assertIn ( '192.168.0.15/24' , output
)
4387 output
= check_output ( 'bridge -d link show dummy98' )
4389 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
4390 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
4391 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'isolated' , '1' )
4392 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
4393 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
4394 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
4395 # CONFIG_BRIDGE_IGMP_SNOOPING=y
4396 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
4397 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
4398 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
4399 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
4400 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
4401 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
4403 output
= check_output ( 'bridge -d link show test1' )
4405 self
. check_bridge_port_attr ( 'bridge99' , 'test1' , 'priority' , '0' )
4407 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
4408 output
= check_output ( 'ip addr show bridge99' )
4410 self
. assertIn ( '192.168.0.16/24' , output
)
4413 print ( '### ip -6 route list table all dev bridge99' )
4414 output
= check_output ( 'ip -6 route list table all dev bridge99' )
4416 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
4418 remove_link ( 'test1' )
4419 self
. wait_operstate ( 'bridge99' , 'routable' )
4421 output
= check_output ( 'ip -d link show bridge99' )
4423 self
. assertIn ( 'mtu 9000 ' , output
)
4425 output
= check_output ( 'ip -d link show dummy98' )
4427 self
. assertIn ( 'master bridge99 ' , output
)
4428 self
. assertIn ( 'bridge_slave' , output
)
4429 self
. assertIn ( 'mtu 9000 ' , output
)
4431 remove_link ( 'dummy98' )
4432 self
. wait_operstate ( 'bridge99' , 'no-carrier' )
4434 output
= check_output ( 'ip -d link show bridge99' )
4436 # When no carrier, the kernel may reset the MTU
4437 self
. assertIn ( 'NO-CARRIER' , output
)
4439 output
= check_output ( 'ip address show bridge99' )
4441 self
. assertNotIn ( '192.168.0.15/24' , output
)
4442 self
. assertIn ( '192.168.0.16/24' , output
) # foreign address is kept
4444 print ( '### ip -6 route list table all dev bridge99' )
4445 output
= check_output ( 'ip -6 route list table all dev bridge99' )
4447 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
4449 check_output ( 'ip link add dummy98 type dummy' )
4450 self
. wait_online ([ 'dummy98:enslaved' , 'bridge99:routable' ])
4452 output
= check_output ( 'ip -d link show bridge99' )
4454 self
. assertIn ( 'mtu 9000 ' , output
)
4456 output
= check_output ( 'ip -d link show dummy98' )
4458 self
. assertIn ( 'master bridge99 ' , output
)
4459 self
. assertIn ( 'bridge_slave' , output
)
4460 self
. assertIn ( 'mtu 9000 ' , output
)
4462 def test_bridge_configure_without_carrier ( self
):
4463 copy_network_unit ( '26-bridge.netdev' , '26-bridge-configure-without-carrier.network' ,
4467 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
4468 for test
in [ 'no-slave' , 'add-slave' , 'slave-up' , 'slave-no-carrier' , 'slave-carrier' , 'slave-down' ]:
4469 with self
. subTest ( test
= test
):
4470 if test
== 'no-slave' :
4471 # bridge has no slaves; it's up but *might* not have carrier
4472 self
. wait_operstate ( 'bridge99' , operstate
= r
'(no-carrier|routable)' , setup_state
= None , setup_timeout
= 30 )
4473 # due to a bug in the kernel, newly-created bridges are brought up
4474 # *with* carrier, unless they have had any setting changed; e.g.
4475 # their mac set, priority set, etc. Then, they will lose carrier
4476 # as soon as a (down) slave interface is added, and regain carrier
4477 # again once the slave interface is brought up.
4478 #self.check_link_attr('bridge99', 'carrier', '0')
4479 elif test
== 'add-slave' :
4480 # add slave to bridge, but leave it down; bridge is definitely no-carrier
4481 self
. check_link_attr ( 'test1' , 'operstate' , 'down' )
4482 check_output ( 'ip link set dev test1 master bridge99' )
4483 self
. wait_operstate ( 'bridge99' , operstate
= 'no-carrier' , setup_state
= None )
4484 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4485 elif test
== 'slave-up' :
4486 # bring up slave, which will have carrier; bridge gains carrier
4487 check_output ( 'ip link set dev test1 up' )
4488 self
. wait_online ([ 'bridge99:routable' ])
4489 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
4490 elif test
== 'slave-no-carrier' :
4491 # drop slave carrier; bridge loses carrier
4492 check_output ( 'ip link set dev test1 carrier off' )
4493 self
. wait_online ([ 'bridge99:no-carrier:no-carrier' ])
4494 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4495 elif test
== 'slave-carrier' :
4496 # restore slave carrier; bridge gains carrier
4497 check_output ( 'ip link set dev test1 carrier on' )
4498 self
. wait_online ([ 'bridge99:routable' ])
4499 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
4500 elif test
== 'slave-down' :
4501 # bring down slave; bridge loses carrier
4502 check_output ( 'ip link set dev test1 down' )
4503 self
. wait_online ([ 'bridge99:no-carrier:no-carrier' ])
4504 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4506 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bridge99' , env
= env
)
4507 self
. assertRegex ( output
, '10.1.2.3' )
4508 self
. assertRegex ( output
, '10.1.2.1' )
4510 def test_bridge_ignore_carrier_loss ( self
):
4511 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
4512 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
4513 '25-bridge99-ignore-carrier-loss.network' )
4515 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' ])
4517 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
4518 remove_link ( 'test1' , 'dummy98' )
4521 output
= check_output ( 'ip address show bridge99' )
4523 self
. assertRegex ( output
, 'NO-CARRIER' )
4524 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
4525 self
. assertRegex ( output
, 'inet 192.168.0.16/24 scope global secondary bridge99' )
4527 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain ( self
):
4528 copy_network_unit ( '26-bridge.netdev' , '26-bridge-slave-interface-1.network' ,
4529 '25-bridge99-ignore-carrier-loss.network' )
4531 self
. wait_online ([ 'bridge99:no-carrier' ])
4533 for trial
in range ( 4 ):
4534 check_output ( 'ip link add dummy98 type dummy' )
4535 check_output ( 'ip link set dummy98 up' )
4537 remove_link ( 'dummy98' )
4539 self
. wait_online ([ 'bridge99:routable' , 'dummy98:enslaved' ])
4541 output
= check_output ( 'ip address show bridge99' )
4543 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
4545 output
= check_output ( 'ip rule list table 100' )
4547 self
. assertIn ( 'from all to 8.8.8.8 lookup 100' , output
)
4549 class NetworkdSRIOVTests ( unittest
. TestCase
, Utilities
):
4557 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
4558 def test_sriov ( self
):
4559 copy_network_unit ( '25-default.link' , '25-sriov.network' )
4561 call ( 'modprobe netdevsim' )
4563 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4566 with
open ( '/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4570 self
. wait_online ([ 'eni99np1:routable' ])
4572 output
= check_output ( 'ip link show dev eni99np1' )
4574 self
. assertRegex ( output
,
4575 '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 *'
4576 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4577 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4580 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
4581 def test_sriov_udev ( self
):
4582 copy_network_unit ( '25-sriov.link' , '25-sriov-udev.network' )
4584 call ( 'modprobe netdevsim' )
4586 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4590 self
. wait_online ([ 'eni99np1:routable' ])
4592 # the name eni99np1 may be an alternative name.
4593 ifname
= link_resolve ( 'eni99np1' )
4595 output
= check_output ( 'ip link show dev eni99np1' )
4597 self
. assertRegex ( output
,
4598 '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 *'
4599 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4600 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4602 self
. assertNotIn ( 'vf 3' , output
)
4603 self
. assertNotIn ( 'vf 4' , output
)
4605 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4606 f
. write ( '[Link] \n SR-IOVVirtualFunctions=4 \n ' )
4609 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4611 output
= check_output ( 'ip link show dev eni99np1' )
4613 self
. assertRegex ( output
,
4614 '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 *'
4615 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4616 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
4619 self
. assertNotIn ( 'vf 4' , output
)
4621 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4622 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
4625 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4627 output
= check_output ( 'ip link show dev eni99np1' )
4629 self
. assertRegex ( output
,
4630 '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 *'
4631 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4632 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
4635 self
. assertNotIn ( 'vf 4' , output
)
4637 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4638 f
. write ( '[Link] \n SR-IOVVirtualFunctions=2 \n ' )
4641 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4643 output
= check_output ( 'ip link show dev eni99np1' )
4645 self
. assertRegex ( output
,
4646 '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 *'
4647 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off'
4649 self
. assertNotIn ( 'vf 2' , output
)
4650 self
. assertNotIn ( 'vf 3' , output
)
4651 self
. assertNotIn ( 'vf 4' , output
)
4653 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4654 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
4657 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4659 output
= check_output ( 'ip link show dev eni99np1' )
4661 self
. assertRegex ( output
,
4662 '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 *'
4663 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4664 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4666 self
. assertNotIn ( 'vf 3' , output
)
4667 self
. assertNotIn ( 'vf 4' , output
)
4669 class NetworkdLLDPTests ( unittest
. TestCase
, Utilities
):
4677 def test_lldp ( self
):
4678 copy_network_unit ( '23-emit-lldp.network' , '24-lldp.network' , '25-veth.netdev' )
4680 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:degraded' ])
4682 for trial
in range ( 10 ):
4686 output
= check_output (* networkctl_cmd
, 'lldp' , env
= env
)
4688 if re
. search ( r
'veth99 .* veth-peer' , output
):
4693 class NetworkdRATests ( unittest
. TestCase
, Utilities
):
4701 def test_ipv6_prefix_delegation ( self
):
4702 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth.network' )
4704 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4706 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth99' , env
= env
)
4708 self
. assertRegex ( output
, 'fe80::' )
4709 self
. assertRegex ( output
, '2002:da8:1::1' )
4711 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth99' , env
= env
)
4713 self
. assertIn ( 'hogehoge.test' , output
)
4715 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4717 self
. assertRegex ( output
, '2002:da8:1:0' )
4719 self
. check_netlabel ( 'veth99' , '2002:da8:1::/64' )
4720 self
. check_netlabel ( 'veth99' , '2002:da8:2::/64' )
4722 def test_ipv6_token_static ( self
):
4723 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-static.network' )
4725 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4727 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4729 self
. assertRegex ( output
, '2002:da8:1:0:1a:2b:3c:4d' )
4730 self
. assertRegex ( output
, '2002:da8:1:0:fa:de:ca:fe' )
4731 self
. assertRegex ( output
, '2002:da8:2:0:1a:2b:3c:4d' )
4732 self
. assertRegex ( output
, '2002:da8:2:0:fa:de:ca:fe' )
4734 def test_ipv6_token_prefixstable ( self
):
4735 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable.network' )
4737 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4739 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4741 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
4742 self
. assertIn ( '2002:da8:2:0:1034:56ff:fe78:9abc' , output
) # EUI64
4744 def test_ipv6_token_prefixstable_without_address ( self
):
4745 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable-without-address.network' )
4747 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4749 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4751 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
4752 self
. assertIn ( '2002:da8:2:0:f689:561a:8eda:7443' , output
)
4754 def test_router_preference ( self
):
4755 copy_network_unit ( '25-veth-client.netdev' ,
4756 '25-veth-router-high.netdev' ,
4757 '25-veth-router-low.netdev' ,
4759 '25-veth-bridge.network' ,
4760 '25-veth-client.network' ,
4761 '25-veth-router-high.network' ,
4762 '25-veth-router-low.network' ,
4763 '25-bridge99.network' )
4765 self
. wait_online ([ 'client-p:enslaved' ,
4766 'router-high:degraded' , 'router-high-p:enslaved' ,
4767 'router-low:degraded' , 'router-low-p:enslaved' ,
4768 'bridge99:routable' ])
4770 networkctl_reconfigure ( 'client' )
4771 self
. wait_online ([ 'client:routable' ])
4773 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4774 self
. wait_address ( 'client' , '2002:da8:1:98:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4775 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 512' , ipv
= '-6' , timeout_sec
= 10 )
4776 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 2048' , ipv
= '-6' , timeout_sec
= 10 )
4778 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
4780 self
. assertIn ( 'pref high' , output
)
4781 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
4783 self
. assertIn ( 'pref low' , output
)
4785 with
open ( os
. path
. join ( network_unit_dir
, '25-veth-client.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4786 f
. write ( ' \n [Link] \n MACAddress=12:34:56:78:9a:01 \n [IPv6AcceptRA] \n RouteMetric=100:200:300 \n ' )
4789 self
. wait_online ([ 'client:routable' ])
4791 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a01/64' , ipv
= '-6' , timeout_sec
= 10 )
4792 self
. wait_address ( 'client' , '2002:da8:1:98:1034:56ff:fe78:9a01/64' , ipv
= '-6' , timeout_sec
= 10 )
4793 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 100' , ipv
= '-6' , timeout_sec
= 10 )
4794 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 300' , ipv
= '-6' , timeout_sec
= 10 )
4796 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
4798 self
. assertIn ( 'pref high' , output
)
4799 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
4801 self
. assertIn ( 'pref low' , output
)
4803 @unittest . skipUnless ( radvd_check_config ( 'captive-portal.conf' ), "Installed radvd doesn't support captive portals" )
4804 def test_captive_portal ( self
):
4805 copy_network_unit ( '25-veth-client.netdev' ,
4806 '25-veth-router-captive.netdev' ,
4808 '25-veth-client-captive.network' ,
4809 '25-veth-router-captive.network' ,
4810 '25-veth-bridge-captive.network' ,
4811 '25-bridge99.network' )
4813 self
. wait_online ([ 'bridge99:routable' , 'client-p:enslaved' ,
4814 'router-captive:degraded' , 'router-captivep:enslaved' ])
4816 start_radvd ( config_file
= 'captive-portal.conf' )
4817 networkctl_reconfigure ( 'client' )
4818 self
. wait_online ([ 'client:routable' ])
4820 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4821 output
= check_output (* networkctl_cmd
, 'status' , 'client' , env
= env
)
4823 self
. assertIn ( 'Captive Portal: http://systemd.io' , output
)
4825 @unittest . skipUnless ( radvd_check_config ( 'captive-portal.conf' ), "Installed radvd doesn't support captive portals" )
4826 def test_invalid_captive_portal ( self
):
4827 def radvd_write_config ( captive_portal_uri
):
4828 with
open ( os
. path
. join ( networkd_ci_temp_dir
, 'radvd/bogus-captive-portal.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
4829 f
. write ( f
'interface router-captive {{ AdvSendAdvert on; AdvCaptivePortalAPI " {captive_portal_uri} "; prefix 2002:da8:1:99::/64 {{ AdvOnLink on; AdvAutonomous on; }}; }};' )
4831 captive_portal_uris
= [
4832 "42ěščěškd ěšč ě s" ,
4837 copy_network_unit ( '25-veth-client.netdev' ,
4838 '25-veth-router-captive.netdev' ,
4840 '25-veth-client-captive.network' ,
4841 '25-veth-router-captive.network' ,
4842 '25-veth-bridge-captive.network' ,
4843 '25-bridge99.network' )
4845 self
. wait_online ([ 'bridge99:routable' , 'client-p:enslaved' ,
4846 'router-captive:degraded' , 'router-captivep:enslaved' ])
4848 for uri
in captive_portal_uris
:
4849 print ( f
"Captive portal: {uri} " )
4850 radvd_write_config ( uri
)
4852 start_radvd ( config_file
= 'bogus-captive-portal.conf' )
4853 networkctl_reconfigure ( 'client' )
4854 self
. wait_online ([ 'client:routable' ])
4856 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4857 output
= check_output (* networkctl_cmd
, 'status' , 'client' , env
= env
)
4859 self
. assertNotIn ( 'Captive Portal:' , output
)
4861 class NetworkdDHCPServerTests ( unittest
. TestCase
, Utilities
):
4869 def test_dhcp_server ( self
):
4870 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server.network' )
4872 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4874 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4876 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4877 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
4878 self
. assertRegex ( output
, 'DNS: 192.168.5.1 \n *192.168.5.10' )
4879 self
. assertRegex ( output
, 'NTP: 192.168.5.1 \n *192.168.5.11' )
4881 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth-peer' , env
= env
)
4882 self
. assertRegex ( output
, "Offered DHCP leases: 192.168.5.[0-9]*" )
4884 def test_dhcp_server_with_uplink ( self
):
4885 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-downstream.network' ,
4886 '12-dummy.netdev' , '25-dhcp-server-uplink.network' )
4888 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4890 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4892 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4893 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
4894 self
. assertIn ( 'DNS: 192.168.5.1' , output
)
4895 self
. assertIn ( 'NTP: 192.168.5.1' , output
)
4897 def test_emit_router_timezone ( self
):
4898 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-timezone-router.network' , '25-dhcp-server-timezone-router.network' )
4900 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4902 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4904 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4905 self
. assertIn ( 'Gateway: 192.168.5.1' , output
)
4906 self
. assertIn ( 'Time Zone: Europe/Berlin' , output
)
4908 def test_dhcp_server_static_lease ( self
):
4909 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-static-lease.network' , '25-dhcp-server-static-lease.network' )
4911 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4913 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4915 self
. assertIn ( 'Address: 10.1.1.200 (DHCP4 via 10.1.1.1)' , output
)
4916 self
. assertIn ( 'DHCP4 Client ID: 12:34:56:78:9a:bc' , output
)
4918 def test_dhcp_server_static_lease_default_client_id ( self
):
4919 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-static-lease.network' )
4921 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4923 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4925 self
. assertIn ( 'Address: 10.1.1.200 (DHCP4 via 10.1.1.1)' , output
)
4926 self
. assertRegex ( output
, 'DHCP4 Client ID: IAID:[0-9a-z]*/DUID' )
4928 class NetworkdDHCPServerRelayAgentTests ( unittest
. TestCase
, Utilities
):
4936 def test_relay_agent ( self
):
4937 copy_network_unit ( '25-agent-veth-client.netdev' ,
4938 '25-agent-veth-server.netdev' ,
4939 '25-agent-client.network' ,
4940 '25-agent-server.network' ,
4941 '25-agent-client-peer.network' ,
4942 '25-agent-server-peer.network' )
4945 self
. wait_online ([ 'client:routable' ])
4947 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'client' , env
= env
)
4949 self
. assertRegex ( output
, r
'Address: 192.168.5.150 \(DHCP4 via 192.168.5.1\)' )
4951 class NetworkdDHCPClientTests ( unittest
. TestCase
, Utilities
):
4959 def test_dhcp_client_ipv6_only ( self
):
4960 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv6-only.network' )
4963 self
. wait_online ([ 'veth-peer:carrier' ])
4965 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4968 output
= check_output ( 'ip address show dev veth99 scope global' )
4970 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
4971 self
. assertNotIn ( '192.168.5' , output
)
4973 # checking semi-static route
4974 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
4976 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
4978 # Confirm that ipv6 token is not set in the kernel
4979 output
= check_output ( 'ip token show dev veth99' )
4981 self
. assertRegex ( output
, 'token :: dev veth99' )
4983 print ( '## dnsmasq log' )
4984 output
= read_dnsmasq_log_file ()
4986 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
4987 self
. assertNotIn ( 'DHCPADVERTISE(veth-peer)' , output
)
4988 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
4989 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
4990 self
. assertIn ( 'sent size: 0 option: 14 rapid-commit' , output
)
4992 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-ipv6-only.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4993 f
. write ( ' \n [DHCPv6] \n RapidCommit=no \n ' )
4999 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5002 output
= check_output ( 'ip address show dev veth99 scope global' )
5004 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
5005 self
. assertNotIn ( '192.168.5' , output
)
5007 # checking semi-static route
5008 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
5010 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
5012 print ( '## dnsmasq log' )
5013 output
= read_dnsmasq_log_file ()
5015 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
5016 self
. assertIn ( 'DHCPADVERTISE(veth-peer)' , output
)
5017 self
. assertIn ( 'DHCPREQUEST(veth-peer)' , output
)
5018 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
5019 self
. assertNotIn ( 'rapid-commit' , output
)
5021 def test_dhcp_client_ipv4_only ( self
):
5022 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv4-only.network' )
5025 self
. wait_online ([ 'veth-peer:carrier' ])
5026 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7' ,
5027 '--dhcp-option=option:domain-search,example.com' ,
5028 '--dhcp-alternate-port=67,5555' ,
5029 ipv4_range
= '192.168.5.110,192.168.5.119' )
5030 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5031 self
. wait_address ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' )
5033 print ( '## ip address show dev veth99 scope global' )
5034 output
= check_output ( 'ip address show dev veth99 scope global' )
5036 self
. assertIn ( 'mtu 1492' , output
)
5037 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
5038 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' )
5039 self
. assertNotIn ( '2600::' , output
)
5041 print ( '## ip route show table main dev veth99' )
5042 output
= check_output ( 'ip route show table main dev veth99' )
5044 # no DHCP routes assigned to the main table
5045 self
. assertNotIn ( 'proto dhcp' , output
)
5047 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
5048 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
5049 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
5050 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
5052 print ( '## ip route show table 211 dev veth99' )
5053 output
= check_output ( 'ip route show table 211 dev veth99' )
5055 self
. assertRegex ( output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.11[0-9] metric 24' )
5056 self
. assertRegex ( output
, '192.168.5.0/24 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
5057 self
. assertRegex ( output
, '192.168.5.1 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
5058 self
. assertRegex ( output
, '192.168.5.6 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
5059 self
. assertRegex ( output
, '192.168.5.7 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
5060 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
5062 print ( '## link state file' )
5063 output
= read_link_state_file ( 'veth99' )
5065 # checking DNS server and Domains
5066 self
. assertIn ( 'DNS=192.168.5.6 192.168.5.7' , output
)
5067 self
. assertIn ( 'DOMAINS=example.com' , output
)
5069 print ( '## dnsmasq log' )
5070 output
= read_dnsmasq_log_file ()
5072 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
5073 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc' , output
)
5074 self
. assertIn ( 'client provides name: test-hostname' , output
)
5075 self
. assertIn ( '26:mtu' , output
)
5077 # change address range, DNS servers, and Domains
5079 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8' ,
5080 '--dhcp-option=option:domain-search,foo.example.com' ,
5081 '--dhcp-alternate-port=67,5555' ,
5082 ipv4_range
= '192.168.5.120,192.168.5.129' ,)
5084 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
5085 print ( 'Wait for the DHCP lease to be expired' )
5086 self
. wait_address_dropped ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' , timeout_sec
= 120 )
5087 self
. wait_address ( 'veth99' , r
'inet 192.168.5.12[0-9]*/24' , ipv
= '-4' )
5089 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5091 print ( '## ip address show dev veth99 scope global' )
5092 output
= check_output ( 'ip address show dev veth99 scope global' )
5094 self
. assertIn ( 'mtu 1492' , output
)
5095 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
5096 self
. assertNotIn ( '192.168.5.11' , output
)
5097 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' )
5098 self
. assertNotIn ( '2600::' , output
)
5100 print ( '## ip route show table main dev veth99' )
5101 output
= check_output ( 'ip route show table main dev veth99' )
5103 # no DHCP routes assigned to the main table
5104 self
. assertNotIn ( 'proto dhcp' , output
)
5106 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
5107 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
5108 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
5109 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
5111 print ( '## ip route show table 211 dev veth99' )
5112 output
= check_output ( 'ip route show table 211 dev veth99' )
5114 self
. assertRegex ( output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.12[0-9] metric 24' )
5115 self
. assertRegex ( output
, '192.168.5.0/24 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
5116 self
. assertRegex ( output
, '192.168.5.1 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
5117 self
. assertNotIn ( '192.168.5.6' , output
)
5118 self
. assertRegex ( output
, '192.168.5.7 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
5119 self
. assertRegex ( output
, '192.168.5.8 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
5120 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
5122 print ( '## link state file' )
5123 output
= read_link_state_file ( 'veth99' )
5125 # checking DNS server and Domains
5126 self
. assertIn ( 'DNS=192.168.5.1 192.168.5.7 192.168.5.8' , output
)
5127 self
. assertIn ( 'DOMAINS=foo.example.com' , output
)
5129 print ( '## dnsmasq log' )
5130 output
= read_dnsmasq_log_file ()
5132 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
5133 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 192.168.5.11' , output
)
5134 self
. assertIn ( 'client provides name: test-hostname' , output
)
5135 self
. assertIn ( '26:mtu' , output
)
5137 self
. check_netlabel ( 'veth99' , r
'192\.168\.5\.0/24' )
5139 def test_dhcp_client_ipv4_use_routes_gateway ( self
):
5141 for ( routes
, gateway
, dns_and_ntp_routes
, classless
) in itertools
. product ([ True , False ], repeat
= 4 ):
5147 print ( f
'### test_dhcp_client_ipv4_use_routes_gateway(routes= {routes} , gateway= {gateway} , dns_and_ntp_routes= {dns_and_ntp_routes} , classless= {classless} )' )
5148 with self
. subTest ( routes
= routes
, gateway
= gateway
, dns_and_ntp_routes
= dns_and_ntp_routes
, classless
= classless
):
5149 self
._ test
_ dhcp
_ client
_ ipv
4_u se
_ routes
_ gateway
( routes
, gateway
, dns_and_ntp_routes
, classless
)
5151 def _test_dhcp_client_ipv4_use_routes_gateway ( self
, use_routes
, use_gateway
, dns_and_ntp_routes
, classless
):
5152 testunit
= '25-dhcp-client-ipv4-use-routes-use-gateway.network'
5153 testunits
= [ '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , testunit
]
5154 testunits
. append ( f
' {testunit} .d/use-routes- {use_routes} .conf' )
5155 testunits
. append ( f
' {testunit} .d/use-gateway- {use_gateway} .conf' )
5156 testunits
. append ( f
' {testunit} .d/use-dns-and-ntp-routes- {dns_and_ntp_routes} .conf' )
5157 copy_network_unit (* testunits
, copy_dropins
= False )
5160 self
. wait_online ([ 'veth-peer:carrier' ])
5161 additional_options
= [
5162 '--dhcp-option=option:dns-server,192.168.5.10,8.8.8.8' ,
5163 '--dhcp-option=option:ntp-server,192.168.5.11,9.9.9.9' ,
5164 '--dhcp-option=option:static-route,192.168.6.100,192.168.5.2,8.8.8.8,192.168.5.3'
5167 additional_options
+= [
5168 '--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'
5170 start_dnsmasq (* additional_options
)
5171 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5173 output
= check_output ( 'ip -4 route show dev veth99' )
5179 self
. assertRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5180 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5181 self
. assertRegex ( output
, r
'192.168.5.64/26 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5182 self
. assertRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5183 self
. assertRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5185 self
. assertRegex ( output
, r
'192.168.6.0/24 via 192.168.5.2 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5186 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5187 self
. assertRegex ( output
, r
'192.168.5.2 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5188 self
. assertRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5190 self
. assertNotRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5191 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5192 self
. assertNotRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5193 self
. assertNotRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5194 self
. assertNotRegex ( output
, r
'192.168.6.0/24 via 192.168.5.2 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5195 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5196 self
. assertNotRegex ( output
, r
'192.168.5.2 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5197 self
. assertNotRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5200 if use_gateway
and ( not classless
or not use_routes
):
5201 self
. assertRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5203 self
. assertNotRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5205 # Check route to gateway
5206 if ( use_gateway
or dns_and_ntp_routes
) and ( not classless
or not use_routes
):
5207 self
. assertRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5209 self
. assertNotRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5211 # Check RoutesToDNS= and RoutesToNTP=
5212 if dns_and_ntp_routes
:
5213 self
. assertRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5214 self
. assertRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5217 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5218 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5220 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5221 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5223 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5224 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5226 self
. assertNotRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5227 self
. assertNotRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5228 self
. assertNotRegex ( output
, r
'8.8.8.8 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
5229 self
. assertNotRegex ( output
, r
'9.9.9.9 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
5231 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5234 def test_dhcp_client_settings_anonymize ( self
):
5235 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-anonymize.network' )
5237 self
. wait_online ([ 'veth-peer:carrier' ])
5239 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5241 print ( '## dnsmasq log' )
5242 output
= read_dnsmasq_log_file ()
5244 self
. assertNotIn ( 'VendorClassIdentifier=SusantVendorTest' , output
)
5245 self
. assertNotIn ( 'test-hostname' , output
)
5246 self
. assertNotIn ( '26:mtu' , output
)
5248 def test_dhcp_keep_configuration_dhcp ( self
):
5249 copy_network_unit ( '25-veth.netdev' ,
5250 '25-dhcp-server-veth-peer.network' ,
5251 '25-dhcp-client-keep-configuration-dhcp.network' )
5253 self
. wait_online ([ 'veth-peer:carrier' ])
5255 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5257 output
= check_output ( 'ip address show dev veth99 scope global' )
5259 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5260 'valid_lft forever preferred_lft forever' )
5262 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
5265 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
5266 print ( 'Wait for the DHCP lease to be expired' )
5269 # The lease address should be kept after the lease expired
5270 output
= check_output ( 'ip address show dev veth99 scope global' )
5272 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5273 'valid_lft forever preferred_lft forever' )
5277 # The lease address should be kept after networkd stopped
5278 output
= check_output ( 'ip address show dev veth99 scope global' )
5280 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5281 'valid_lft forever preferred_lft forever' )
5283 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-keep-configuration-dhcp.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5284 f
. write ( '[Network] \n DHCP=no \n ' )
5287 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5289 # Still the lease address should be kept after networkd restarted
5290 output
= check_output ( 'ip address show dev veth99 scope global' )
5292 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5293 'valid_lft forever preferred_lft forever' )
5295 def test_dhcp_keep_configuration_dhcp_on_stop ( self
):
5296 copy_network_unit ( '25-veth.netdev' ,
5297 '25-dhcp-server-veth-peer.network' ,
5298 '25-dhcp-client-keep-configuration-dhcp-on-stop.network' )
5300 self
. wait_online ([ 'veth-peer:carrier' ])
5302 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5304 output
= check_output ( 'ip address show dev veth99 scope global' )
5306 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5311 output
= check_output ( 'ip address show dev veth99 scope global' )
5313 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5316 self
. wait_online ([ 'veth-peer:routable' ])
5318 output
= check_output ( 'ip address show dev veth99 scope global' )
5320 self
. assertNotIn ( '192.168.5.' , output
)
5322 def test_dhcp_client_reuse_address_as_static ( self
):
5323 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' )
5325 self
. wait_online ([ 'veth-peer:carrier' ])
5327 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5329 # link become 'routable' when at least one protocol provide an valid address.
5330 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5331 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5333 output
= check_output ( 'ip address show dev veth99 scope global' )
5334 ipv4_address
= re
. search ( r
'192.168.5.[0-9]*/24' , output
). group ()
5335 ipv6_address
= re
. search ( r
'2600::[0-9a-f:]*/128' , output
). group ()
5336 static_network
= ' \n ' . join ([ '[Match]' , 'Name=veth99' , '[Network]' , 'IPv6AcceptRA=no' , 'Address=' + ipv4_address
, 'Address=' + ipv6_address
])
5337 print ( static_network
)
5339 remove_network_unit ( '25-dhcp-client.network' )
5341 with
open ( os
. path
. join ( network_unit_dir
, '25-static.network' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5342 f
. write ( static_network
)
5345 self
. wait_online ([ 'veth99:routable' ])
5347 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
5349 self
. assertRegex ( output
, f
'inet {ipv4_address} brd 192.168.5.255 scope global veth99 \n *'
5350 'valid_lft forever preferred_lft forever' )
5352 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5354 self
. assertRegex ( output
, f
'inet6 {ipv6_address} scope global * \n *'
5355 'valid_lft forever preferred_lft forever' )
5357 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
5358 def test_dhcp_client_vrf ( self
):
5359 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-vrf.network' ,
5360 '25-vrf.netdev' , '25-vrf.network' )
5362 self
. wait_online ([ 'veth-peer:carrier' ])
5364 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'vrf99:carrier' ])
5366 # link become 'routable' when at least one protocol provide an valid address.
5367 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5368 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5370 print ( '## ip -d link show dev vrf99' )
5371 output
= check_output ( 'ip -d link show dev vrf99' )
5373 self
. assertRegex ( output
, 'vrf table 42' )
5375 print ( '## ip address show vrf vrf99' )
5376 output
= check_output ( 'ip address show vrf vrf99' )
5378 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5379 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5380 self
. assertRegex ( output
, 'inet6 .* scope link' )
5382 print ( '## ip address show dev veth99' )
5383 output
= check_output ( 'ip address show dev veth99' )
5385 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5386 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5387 self
. assertRegex ( output
, 'inet6 .* scope link' )
5389 print ( '## ip route show vrf vrf99' )
5390 output
= check_output ( 'ip route show vrf vrf99' )
5392 self
. assertRegex ( output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.' )
5393 self
. assertRegex ( output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5' )
5394 self
. assertRegex ( output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5' )
5396 print ( '## ip route show table main dev veth99' )
5397 output
= check_output ( 'ip route show table main dev veth99' )
5399 self
. assertEqual ( output
, '' )
5401 def test_dhcp_client_gateway_onlink_implicit ( self
):
5402 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
5403 '25-dhcp-client-gateway-onlink-implicit.network' )
5405 self
. wait_online ([ 'veth-peer:carrier' ])
5407 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5409 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
5411 self
. assertRegex ( output
, '192.168.5' )
5413 output
= check_output ( 'ip route list dev veth99 10.0.0.0/8' )
5415 self
. assertRegex ( output
, 'onlink' )
5416 output
= check_output ( 'ip route list dev veth99 192.168.100.0/24' )
5418 self
. assertRegex ( output
, 'onlink' )
5420 def test_dhcp_client_with_ipv4ll ( self
):
5421 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
5422 '25-dhcp-client-with-ipv4ll.network' )
5424 # we need to increase timeout above default, as this will need to wait for
5425 # systemd-networkd to get the dhcpv4 transient failure event
5426 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:routable' ], timeout
= '60s' )
5428 output
= check_output ( 'ip -4 address show dev veth99' )
5430 self
. assertNotIn ( '192.168.5.' , output
)
5431 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
5434 print ( 'Wait for a DHCP lease to be acquired and the IPv4LL address to be dropped' )
5435 self
. wait_address ( 'veth99' , r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic' , ipv
= '-4' )
5436 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' )
5437 self
. wait_online ([ 'veth99:routable' ])
5439 output
= check_output ( 'ip -4 address show dev veth99' )
5441 self
. assertRegex ( output
, r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99' )
5442 self
. assertNotIn ( '169.254.' , output
)
5443 self
. assertNotIn ( 'scope link' , output
)
5446 print ( 'Wait for the DHCP lease to be expired and an IPv4LL address to be acquired' )
5447 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 )
5448 self
. wait_address ( 'veth99' , r
'inet 169\.254\.133\.11/16 metric 2048 brd 169\.254\.255\.255 scope link' , scope
= 'link' , ipv
= '-4' )
5450 output
= check_output ( 'ip -4 address show dev veth99' )
5452 self
. assertNotIn ( '192.168.5.' , output
)
5453 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
5455 def test_dhcp_client_use_dns ( self
):
5456 def check ( self
, ipv4
, ipv6
):
5457 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5458 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5459 f
. write ( '[DHCPv4] \n UseDNS=' )
5460 f
. write ( 'yes' if ipv4
else 'no' )
5461 f
. write ( ' \n [DHCPv6] \n UseDNS=' )
5462 f
. write ( 'yes' if ipv6
else 'no' )
5463 f
. write ( ' \n [IPv6AcceptRA] \n UseDNS=no' )
5466 self
. wait_online ([ 'veth99:routable' ])
5468 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5469 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5470 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5472 # make resolved re-read the link state file
5473 check_output (* resolvectl_cmd
, 'revert' , 'veth99' , env
= env
)
5475 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth99' , env
= env
)
5478 self
. assertIn ( '192.168.5.1' , output
)
5480 self
. assertNotIn ( '192.168.5.1' , output
)
5482 self
. assertIn ( '2600::1' , output
)
5484 self
. assertNotIn ( '2600::1' , output
)
5486 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5489 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5492 self
. wait_online ([ 'veth-peer:carrier' ])
5493 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1' ,
5494 '--dhcp-option=option6:dns-server,[2600::1]' )
5496 check ( self
, True , True )
5497 check ( self
, True , False )
5498 check ( self
, False , True )
5499 check ( self
, False , False )
5501 def test_dhcp_client_use_captive_portal ( self
):
5502 def check ( self
, ipv4
, ipv6
):
5503 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5504 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5505 f
. write ( '[DHCPv4] \n UseCaptivePortal=' )
5506 f
. write ( 'yes' if ipv4
else 'no' )
5507 f
. write ( ' \n [DHCPv6] \n UseCaptivePortal=' )
5508 f
. write ( 'yes' if ipv6
else 'no' )
5509 f
. write ( ' \n [IPv6AcceptRA] \n UseCaptivePortal=no' )
5512 self
. wait_online ([ 'veth99:routable' ])
5514 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5515 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5516 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5518 output
= check_output (* networkctl_cmd
, 'status' , 'veth99' , env
= env
)
5521 self
. assertIn ( 'Captive Portal: http://systemd.io' , output
)
5523 self
. assertNotIn ( 'Captive Portal: http://systemd.io' , output
)
5525 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5528 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5531 self
. wait_online ([ 'veth-peer:carrier' ])
5532 start_dnsmasq ( '--dhcp-option=114,http://systemd.io' ,
5533 '--dhcp-option=option6:103,http://systemd.io' )
5535 check ( self
, True , True )
5536 check ( self
, True , False )
5537 check ( self
, False , True )
5538 check ( self
, False , False )
5540 def test_dhcp_client_reject_captive_portal ( self
):
5541 def check ( self
, ipv4
, ipv6
):
5542 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5543 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5544 f
. write ( '[DHCPv4] \n UseCaptivePortal=' )
5545 f
. write ( 'yes' if ipv4
else 'no' )
5546 f
. write ( ' \n [DHCPv6] \n UseCaptivePortal=' )
5547 f
. write ( 'yes' if ipv6
else 'no' )
5548 f
. write ( ' \n [IPv6AcceptRA] \n UseCaptivePortal=no' )
5551 self
. wait_online ([ 'veth99:routable' ])
5553 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5554 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5555 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5557 output
= check_output (* networkctl_cmd
, 'status' , 'veth99' , env
= env
)
5559 self
. assertNotIn ( 'Captive Portal: ' , output
)
5560 self
. assertNotIn ( 'invalid/url' , output
)
5562 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5565 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5568 self
. wait_online ([ 'veth-peer:carrier' ])
5569 masq
= lambda bs
: ':' . join ( f
'{b:02x}' for b
in bs
)
5570 start_dnsmasq ( '--dhcp-option=114,' + masq ( b
'http:// \x00 invalid/url' ),
5571 '--dhcp-option=option6:103,' + masq ( b
'http:// \x00 /invalid/url' ))
5573 check ( self
, True , True )
5574 check ( self
, True , False )
5575 check ( self
, False , True )
5576 check ( self
, False , False )
5578 class NetworkdDHCPPDTests ( unittest
. TestCase
, Utilities
):
5586 def test_dhcp6pd ( self
):
5587 copy_network_unit ( '25-veth.netdev' , '25-dhcp6pd-server.network' , '25-dhcp6pd-upstream.network' ,
5588 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
5589 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
5590 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
5591 '25-dhcp-pd-downstream-dummy97.network' ,
5592 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
5593 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' )
5596 self
. wait_online ([ 'veth-peer:routable' ])
5597 start_isc_dhcpd ( conf_file
= 'isc-dhcpd-dhcp6pd.conf' , ipv
= '-6' )
5598 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5599 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5601 print ( '### ip -6 address show dev veth-peer scope global' )
5602 output
= check_output ( 'ip -6 address show dev veth-peer scope global' )
5604 self
. assertIn ( 'inet6 3ffe:501:ffff:100::1/64 scope global' , output
)
5608 # dummy97: 0x01 (The link will appear later)
5610 # dummy99: auto -> 0x02 (No address assignment)
5615 print ( '### ip -6 address show dev veth99 scope global' )
5616 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5619 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:100::[0-9]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5620 # address in IA_PD (Token=static)
5621 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic' )
5622 # address in IA_PD (Token=eui64)
5623 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic' )
5624 # address in IA_PD (temporary)
5625 # Note that the temporary addresses may appear after the link enters configured state
5626 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' )
5628 print ( '### ip -6 address show dev test1 scope global' )
5629 output
= check_output ( 'ip -6 address show dev test1 scope global' )
5631 # address in IA_PD (Token=static)
5632 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5633 # address in IA_PD (temporary)
5634 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' )
5636 print ( '### ip -6 address show dev dummy98 scope global' )
5637 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5639 # address in IA_PD (Token=static)
5640 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5641 # address in IA_PD (temporary)
5642 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' )
5644 print ( '### ip -6 address show dev dummy99 scope global' )
5645 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5648 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
5650 print ( '### ip -6 address show dev veth97 scope global' )
5651 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
5653 # address in IA_PD (Token=static)
5654 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5655 # address in IA_PD (Token=eui64)
5656 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5657 # address in IA_PD (temporary)
5658 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' )
5660 print ( '### ip -6 address show dev veth97-peer scope global' )
5661 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
5663 # NDisc address (Token=static)
5664 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5665 # NDisc address (Token=eui64)
5666 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5667 # NDisc address (temporary)
5668 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' )
5670 print ( '### ip -6 address show dev veth98 scope global' )
5671 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
5673 # address in IA_PD (Token=static)
5674 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5675 # address in IA_PD (Token=eui64)
5676 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5677 # address in IA_PD (temporary)
5678 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' )
5680 print ( '### ip -6 address show dev veth98-peer scope global' )
5681 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
5683 # NDisc address (Token=static)
5684 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5685 # NDisc address (Token=eui64)
5686 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5687 # NDisc address (temporary)
5688 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' )
5690 print ( '### ip -6 route show type unreachable' )
5691 output
= check_output ( 'ip -6 route show type unreachable' )
5693 self
. assertRegex ( output
, 'unreachable 3ffe:501:ffff:[2-9a-f]00::/56 dev lo proto dhcp' )
5695 print ( '### ip -6 route show dev veth99' )
5696 output
= check_output ( 'ip -6 route show dev veth99' )
5698 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]10::/64 proto kernel metric [0-9]* expires' )
5700 print ( '### ip -6 route show dev test1' )
5701 output
= check_output ( 'ip -6 route show dev test1' )
5703 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5705 print ( '### ip -6 route show dev dummy98' )
5706 output
= check_output ( 'ip -6 route show dev dummy98' )
5708 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5710 print ( '### ip -6 route show dev dummy99' )
5711 output
= check_output ( 'ip -6 route show dev dummy99' )
5713 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
5715 print ( '### ip -6 route show dev veth97' )
5716 output
= check_output ( 'ip -6 route show dev veth97' )
5718 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto kernel metric [0-9]* expires' )
5720 print ( '### ip -6 route show dev veth97-peer' )
5721 output
= check_output ( 'ip -6 route show dev veth97-peer' )
5723 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto ra metric [0-9]* expires' )
5725 print ( '### ip -6 route show dev veth98' )
5726 output
= check_output ( 'ip -6 route show dev veth98' )
5728 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto kernel metric [0-9]* expires' )
5730 print ( '### ip -6 route show dev veth98-peer' )
5731 output
= check_output ( 'ip -6 route show dev veth98-peer' )
5733 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto ra metric [0-9]* expires' )
5735 # Test case for a downstream which appears later
5736 check_output ( 'ip link add dummy97 type dummy' )
5737 self
. wait_online ([ 'dummy97:routable' ])
5739 print ( '### ip -6 address show dev dummy97 scope global' )
5740 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
5742 # address in IA_PD (Token=static)
5743 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5744 # address in IA_PD (temporary)
5745 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' )
5747 print ( '### ip -6 route show dev dummy97' )
5748 output
= check_output ( 'ip -6 route show dev dummy97' )
5750 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]01::/64 proto kernel metric [0-9]* expires' )
5752 # Test case for reconfigure
5753 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
5754 self
. wait_online ([ 'dummy98:routable' , 'dummy99:degraded' ])
5756 print ( '### ip -6 address show dev dummy98 scope global' )
5757 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5759 # address in IA_PD (Token=static)
5760 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5761 # address in IA_PD (temporary)
5762 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' )
5764 print ( '### ip -6 address show dev dummy99 scope global' )
5765 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5768 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
5770 print ( '### ip -6 route show dev dummy98' )
5771 output
= check_output ( 'ip -6 route show dev dummy98' )
5773 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5775 print ( '### ip -6 route show dev dummy99' )
5776 output
= check_output ( 'ip -6 route show dev dummy99' )
5778 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
5780 self
. check_netlabel ( 'dummy98' , '3ffe:501:ffff:[2-9a-f]00::/64' )
5782 def verify_dhcp4_6rd ( self
, tunnel_name
):
5783 print ( '### ip -4 address show dev veth-peer scope global' )
5784 output
= check_output ( 'ip -4 address show dev veth-peer scope global' )
5786 self
. assertIn ( 'inet 10.0.0.1/8 brd 10.255.255.255 scope global veth-peer' , output
)
5790 # dummy97: 0x01 (The link will appear later)
5792 # dummy99: auto -> 0x0[23] (No address assignment)
5793 # 6rd-XXX: auto -> 0x0[23]
5798 print ( '### ip -4 address show dev veth99 scope global' )
5799 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
5801 self
. assertRegex ( output
, 'inet 10.100.100.[0-9]*/8 (metric 1024 |)brd 10.255.255.255 scope global dynamic veth99' )
5803 print ( '### ip -6 address show dev veth99 scope global' )
5804 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5806 # address in IA_PD (Token=static)
5807 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5808 # address in IA_PD (Token=eui64)
5809 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5810 # address in IA_PD (temporary)
5811 # Note that the temporary addresses may appear after the link enters configured state
5812 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' )
5814 print ( '### ip -6 address show dev test1 scope global' )
5815 output
= check_output ( 'ip -6 address show dev test1 scope global' )
5817 # address in IA_PD (Token=static)
5818 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5819 # address in IA_PD (temporary)
5820 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' )
5822 print ( '### ip -6 address show dev dummy98 scope global' )
5823 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5825 # address in IA_PD (Token=static)
5826 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5827 # address in IA_PD (temporary)
5828 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' )
5830 print ( '### ip -6 address show dev dummy99 scope global' )
5831 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5834 self
. assertNotRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+0[23]' )
5836 print ( '### ip -6 address show dev veth97 scope global' )
5837 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
5839 # address in IA_PD (Token=static)
5840 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5841 # address in IA_PD (Token=eui64)
5842 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5843 # address in IA_PD (temporary)
5844 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' )
5846 print ( '### ip -6 address show dev veth97-peer scope global' )
5847 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
5849 # NDisc address (Token=static)
5850 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5851 # NDisc address (Token=eui64)
5852 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5853 # NDisc address (temporary)
5854 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' )
5856 print ( '### ip -6 address show dev veth98 scope global' )
5857 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
5859 # address in IA_PD (Token=static)
5860 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5861 # address in IA_PD (Token=eui64)
5862 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5863 # address in IA_PD (temporary)
5864 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' )
5866 print ( '### ip -6 address show dev veth98-peer scope global' )
5867 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
5869 # NDisc address (Token=static)
5870 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5871 # NDisc address (Token=eui64)
5872 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5873 # NDisc address (temporary)
5874 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' )
5876 print ( '### ip -6 route show type unreachable' )
5877 output
= check_output ( 'ip -6 route show type unreachable' )
5879 self
. assertRegex ( output
, 'unreachable 2001:db8:6464:[0-9a-f]+00::/56 dev lo proto dhcp' )
5881 print ( '### ip -6 route show dev veth99' )
5882 output
= check_output ( 'ip -6 route show dev veth99' )
5884 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+10::/64 proto kernel metric [0-9]* expires' )
5886 print ( '### ip -6 route show dev test1' )
5887 output
= check_output ( 'ip -6 route show dev test1' )
5889 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
5891 print ( '### ip -6 route show dev dummy98' )
5892 output
= check_output ( 'ip -6 route show dev dummy98' )
5894 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
5896 print ( '### ip -6 route show dev dummy99' )
5897 output
= check_output ( 'ip -6 route show dev dummy99' )
5899 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto dhcp metric [0-9]* expires' )
5901 print ( '### ip -6 route show dev veth97' )
5902 output
= check_output ( 'ip -6 route show dev veth97' )
5904 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto kernel metric [0-9]* expires' )
5906 print ( '### ip -6 route show dev veth97-peer' )
5907 output
= check_output ( 'ip -6 route show dev veth97-peer' )
5909 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto ra metric [0-9]* expires' )
5911 print ( '### ip -6 route show dev veth98' )
5912 output
= check_output ( 'ip -6 route show dev veth98' )
5914 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto kernel metric [0-9]* expires' )
5916 print ( '### ip -6 route show dev veth98-peer' )
5917 output
= check_output ( 'ip -6 route show dev veth98-peer' )
5919 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto ra metric [0-9]* expires' )
5921 print ( '### ip -6 address show dev dummy97 scope global' )
5922 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
5924 # address in IA_PD (Token=static)
5925 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5926 # address in IA_PD (temporary)
5927 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' )
5929 print ( '### ip -6 route show dev dummy97' )
5930 output
= check_output ( 'ip -6 route show dev dummy97' )
5932 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+01::/64 proto kernel metric [0-9]* expires' )
5934 print ( f
'### ip -d link show dev {tunnel_name} ' )
5935 output
= check_output ( f
'ip -d link show dev {tunnel_name} ' )
5937 self
. assertIn ( 'link/sit 10.100.100.' , output
)
5938 self
. assertIn ( 'local 10.100.100.' , output
)
5939 self
. assertIn ( 'ttl 64' , output
)
5940 self
. assertIn ( '6rd-prefix 2001:db8::/32' , output
)
5941 self
. assertIn ( '6rd-relay_prefix 10.0.0.0/8' , output
)
5943 print ( f
'### ip -6 address show dev {tunnel_name} ' )
5944 output
= check_output ( f
'ip -6 address show dev {tunnel_name} ' )
5946 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' )
5947 self
. assertRegex ( output
, 'inet6 ::10.100.100.[0-9]+/96 scope global' )
5949 print ( f
'### ip -6 route show dev {tunnel_name} ' )
5950 output
= check_output ( f
'ip -6 route show dev {tunnel_name} ' )
5952 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto kernel metric [0-9]* expires' )
5953 self
. assertRegex ( output
, '::/96 proto kernel metric [0-9]*' )
5955 print ( '### ip -6 route show default' )
5956 output
= check_output ( 'ip -6 route show default' )
5958 self
. assertIn ( 'default' , output
)
5959 self
. assertIn ( f
'via ::10.0.0.1 dev {tunnel_name} ' , output
)
5961 def test_dhcp4_6rd ( self
):
5962 copy_network_unit ( '25-veth.netdev' , '25-dhcp4-6rd-server.network' , '25-dhcp4-6rd-upstream.network' ,
5963 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
5964 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
5965 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
5966 '25-dhcp-pd-downstream-dummy97.network' ,
5967 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
5968 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' ,
5969 '80-6rd-tunnel.network' )
5972 self
. wait_online ([ 'veth-peer:routable' ])
5975 # 6rd-prefix: 2001:db8::/32
5976 # br-addresss: 10.0.0.1
5978 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' ,
5979 ipv4_range
= '10.100.100.100,10.100.100.200' ,
5980 ipv4_router
= '10.0.0.1' )
5981 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5982 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5984 # Test case for a downstream which appears later
5985 check_output ( 'ip link add dummy97 type dummy' )
5986 self
. wait_online ([ 'dummy97:routable' ])
5990 for name
in os
. listdir ( '/sys/class/net/' ):
5991 if name
. startswith ( '6rd-' ):
5995 self
. wait_online ([ f
' {tunnel_name} :routable' ])
5997 self
. verify_dhcp4_6rd ( tunnel_name
)
5999 # Test case for reconfigure
6000 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
6001 self
. wait_online ([ 'dummy98:routable' , 'dummy99:degraded' ])
6003 self
. verify_dhcp4_6rd ( tunnel_name
)
6005 print ( 'Wait for the DHCP lease to be renewed/rebind' )
6008 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy97:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
6009 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
6011 self
. verify_dhcp4_6rd ( tunnel_name
)
6013 class NetworkdIPv6PrefixTests ( unittest
. TestCase
, Utilities
):
6021 def test_ipv6_route_prefix ( self
):
6022 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client.network' , '25-ipv6ra-prefix.network' ,
6023 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
6026 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
6028 output
= check_output ( 'ip address show dev veth-peer' )
6030 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
6031 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
6032 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
6034 output
= check_output ( 'ip -6 route show dev veth-peer' )
6036 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
6037 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
6038 self
. assertNotIn ( '2001:db8:0:3::/64 proto ra' , output
)
6039 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
6040 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
6041 self
. assertNotIn ( '2001:db2:fff::/64 via ' , output
)
6043 output
= check_output ( 'ip address show dev veth99' )
6045 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
6046 self
. assertIn ( 'inet6 2001:db8:0:2:1a:2b:3c:4d' , output
)
6047 self
. assertIn ( 'inet6 2001:db8:0:2:fa:de:ca:fe' , output
)
6048 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
6050 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth-peer' , env
= env
)
6052 self
. assertRegex ( output
, '2001:db8:1:1::2' )
6054 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth-peer' , env
= env
)
6056 self
. assertIn ( 'example.com' , output
)
6058 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
6061 def test_ipv6_route_prefix_deny_list ( self
):
6062 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client-deny-list.network' , '25-ipv6ra-prefix.network' ,
6063 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
6066 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
6068 output
= check_output ( 'ip address show dev veth-peer' )
6070 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
6071 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
6073 output
= check_output ( 'ip -6 route show dev veth-peer' )
6075 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
6076 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
6077 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
6078 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
6080 output
= check_output ( 'ip address show dev veth99' )
6082 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
6083 self
. assertIn ( 'inet6 2001:db8:0:2:' , output
)
6085 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth-peer' , env
= env
)
6087 self
. assertRegex ( output
, '2001:db8:1:1::2' )
6089 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth-peer' , env
= env
)
6091 self
. assertIn ( 'example.com' , output
)
6093 class NetworkdMTUTests ( unittest
. TestCase
, Utilities
):
6101 def check_mtu ( self
, mtu
, ipv6_mtu
= None , reset
= True ):
6107 self
. wait_online ([ 'dummy98:routable' ])
6108 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
6109 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
6111 # test normal restart
6113 self
. wait_online ([ 'dummy98:routable' ])
6114 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
6115 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
6118 self
. reset_check_mtu ( mtu
, ipv6_mtu
)
6120 def reset_check_mtu ( self
, mtu
, ipv6_mtu
= None ):
6121 ''' test setting mtu/ipv6_mtu with interface already up '''
6124 # note - changing the device mtu resets the ipv6 mtu
6125 check_output ( 'ip link set up mtu 1501 dev dummy98' )
6126 check_output ( 'ip link set up mtu 1500 dev dummy98' )
6127 self
. check_link_attr ( 'dummy98' , 'mtu' , '1500' )
6128 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , '1500' )
6130 self
. check_mtu ( mtu
, ipv6_mtu
, reset
= False )
6132 def test_mtu_network ( self
):
6133 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' )
6134 self
. check_mtu ( '1600' )
6136 def test_mtu_netdev ( self
):
6137 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network' , copy_dropins
= False )
6138 # note - MTU set by .netdev happens ONLY at device creation!
6139 self
. check_mtu ( '1600' , reset
= False )
6141 def test_mtu_link ( self
):
6142 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network' , copy_dropins
= False )
6143 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
6144 self
. check_mtu ( '1600' , reset
= False )
6146 def test_ipv6_mtu ( self
):
6147 ''' set ipv6 mtu without setting device mtu '''
6148 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1400.conf' )
6149 self
. check_mtu ( '1500' , '1400' )
6151 def test_ipv6_mtu_toolarge ( self
):
6152 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
6153 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
6154 self
. check_mtu ( '1500' , '1500' )
6156 def test_mtu_network_ipv6_mtu ( self
):
6157 ''' set ipv6 mtu and set device mtu via network file '''
6158 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
6159 self
. check_mtu ( '1600' , '1550' )
6161 def test_mtu_netdev_ipv6_mtu ( self
):
6162 ''' set ipv6 mtu and set device mtu via netdev file '''
6163 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
6164 self
. check_mtu ( '1600' , '1550' , reset
= False )
6166 def test_mtu_link_ipv6_mtu ( self
):
6167 ''' set ipv6 mtu and set device mtu via link file '''
6168 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
6169 self
. check_mtu ( '1600' , '1550' , reset
= False )
6172 if __name__
== '__main__' :
6173 parser
= argparse
. ArgumentParser ()
6174 parser
. add_argument ( '--build-dir' , help = 'Path to build dir' , dest
= 'build_dir' )
6175 parser
. add_argument ( '--networkd' , help = 'Path to systemd-networkd' , dest
= 'networkd_bin' )
6176 parser
. add_argument ( '--resolved' , help = 'Path to systemd-resolved' , dest
= 'resolved_bin' )
6177 parser
. add_argument ( '--timesyncd' , help = 'Path to systemd-timesyncd' , dest
= 'timesyncd_bin' )
6178 parser
. add_argument ( '--udevd' , help = 'Path to systemd-udevd' , dest
= 'udevd_bin' )
6179 parser
. add_argument ( '--wait-online' , help = 'Path to systemd-networkd-wait-online' , dest
= 'wait_online_bin' )
6180 parser
. add_argument ( '--networkctl' , help = 'Path to networkctl' , dest
= 'networkctl_bin' )
6181 parser
. add_argument ( '--resolvectl' , help = 'Path to resolvectl' , dest
= 'resolvectl_bin' )
6182 parser
. add_argument ( '--timedatectl' , help = 'Path to timedatectl' , dest
= 'timedatectl_bin' )
6183 parser
. add_argument ( '--udevadm' , help = 'Path to udevadm' , dest
= 'udevadm_bin' )
6184 parser
. add_argument ( '--valgrind' , help = 'Enable valgrind' , dest
= 'use_valgrind' , type = bool , nargs
= '?' , const
= True , default
= use_valgrind
)
6185 parser
. add_argument ( '--debug' , help = 'Generate debugging logs' , dest
= 'enable_debug' , type = bool , nargs
= '?' , const
= True , default
= enable_debug
)
6186 parser
. add_argument ( '--asan-options' , help = 'ASAN options' , dest
= 'asan_options' )
6187 parser
. add_argument ( '--lsan-options' , help = 'LSAN options' , dest
= 'lsan_options' )
6188 parser
. add_argument ( '--ubsan-options' , help = 'UBSAN options' , dest
= 'ubsan_options' )
6189 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
)
6190 ns
, unknown_args
= parser
. parse_known_args ( namespace
= unittest
)
6193 if ns
. networkd_bin
or ns
. resolved_bin
or ns
. timesyncd_bin
or ns
. udevd_bin
or \
6194 ns
. wait_online_bin
or ns
. networkctl_bin
or ns
. resolvectl_bin
or ns
. timedatectl_bin
or ns
. udevadm_bin
:
6195 print ( 'WARNING: --networkd, --resolved, --timesyncd, --udevd, --wait-online, --networkctl, --resolvectl, --timedatectl, or --udevadm options are ignored when --build-dir is specified.' )
6196 networkd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd' )
6197 resolved_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-resolved' )
6198 timesyncd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-timesyncd' )
6199 udevd_bin
= os
. path
. join ( ns
. build_dir
, 'udevadm' )
6200 wait_online_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd-wait-online' )
6201 networkctl_bin
= os
. path
. join ( ns
. build_dir
, 'networkctl' )
6202 resolvectl_bin
= os
. path
. join ( ns
. build_dir
, 'resolvectl' )
6203 timedatectl_bin
= os
. path
. join ( ns
. build_dir
, 'timedatectl' )
6204 udevadm_bin
= os
. path
. join ( ns
. build_dir
, 'udevadm' )
6207 networkd_bin
= ns
. networkd_bin
6209 resolved_bin
= ns
. resolved_bin
6210 if ns
. timesyncd_bin
:
6211 timesyncd_bin
= ns
. timesyncd_bin
6213 udevd_bin
= ns
. udevd_bin
6214 if ns
. wait_online_bin
:
6215 wait_online_bin
= ns
. wait_online_bin
6216 if ns
. networkctl_bin
:
6217 networkctl_bin
= ns
. networkctl_bin
6218 if ns
. resolvectl_bin
:
6219 resolvectl_bin
= ns
. resolvectl_bin
6220 if ns
. timedatectl_bin
:
6221 timedatectl_bin
= ns
. timedatectl_bin
6223 udevadm_bin
= ns
. udevadm_bin
6225 use_valgrind
= ns
. use_valgrind
6226 enable_debug
= ns
. enable_debug
6227 asan_options
= ns
. asan_options
6228 lsan_options
= ns
. lsan_options
6229 ubsan_options
= ns
. ubsan_options
6230 with_coverage
= ns
. with_coverage
6233 # Do not forget the trailing space.
6234 valgrind_cmd
= 'valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all '
6236 networkctl_cmd
= valgrind_cmd
. split () + [ networkctl_bin
]
6237 resolvectl_cmd
= valgrind_cmd
. split () + [ resolvectl_bin
]
6238 timedatectl_cmd
= valgrind_cmd
. split () + [ timedatectl_bin
]
6239 udevadm_cmd
= valgrind_cmd
. split () + [ udevadm_bin
]
6240 wait_online_cmd
= valgrind_cmd
. split () + [ wait_online_bin
]
6243 env
. update ({ 'ASAN_OPTIONS' : asan_options
})
6245 env
. update ({ 'LSAN_OPTIONS' : lsan_options
})
6247 env
. update ({ 'UBSAN_OPTIONS' : ubsan_options
})
6249 env
. update ({ 'SYSTEMD_MEMPOOL' : '0' })
6251 wait_online_env
= env
. copy ()
6253 wait_online_env
. update ({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
6255 sys
. argv
[ 1 :] = unknown_args
6256 unittest
. main ( verbosity
= 3 )