]>
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 ( '192.168.1.4 proto static scope link hoplimit 122' , output
)
2950 self
. assertIn ( 'multicast 149.10.123.4 proto static' , output
)
2952 print ( '### ip -4 route show dev dummy98 default' )
2953 output
= check_output ( 'ip -4 route show dev dummy98 default' )
2955 self
. assertIn ( 'default via 149.10.125.65 proto static onlink' , output
)
2956 self
. assertIn ( 'default via 149.10.124.64 proto static' , output
)
2957 self
. assertIn ( 'default proto static' , output
)
2959 print ( '### ip -4 route show table local dev dummy98' )
2960 output
= check_output ( 'ip -4 route show table local dev dummy98' )
2962 self
. assertIn ( 'local 149.10.123.1 proto static scope host' , output
)
2963 self
. assertIn ( 'anycast 149.10.123.2 proto static scope link' , output
)
2964 self
. assertIn ( 'broadcast 149.10.123.3 proto static scope link' , output
)
2966 print ( '### ip -4 route show type blackhole' )
2967 output
= check_output ( 'ip -4 route show type blackhole' )
2969 self
. assertIn ( 'blackhole 202.54.1.2 proto static' , output
)
2971 print ( '### ip -4 route show type unreachable' )
2972 output
= check_output ( 'ip -4 route show type unreachable' )
2974 self
. assertIn ( 'unreachable 202.54.1.3 proto static' , output
)
2976 print ( '### ip -4 route show type prohibit' )
2977 output
= check_output ( 'ip -4 route show type prohibit' )
2979 self
. assertIn ( 'prohibit 202.54.1.4 proto static' , output
)
2981 print ( '### ip -6 route show type blackhole' )
2982 output
= check_output ( 'ip -6 route show type blackhole' )
2984 self
. assertIn ( 'blackhole 2001:1234:5678::2 dev lo proto static' , output
)
2986 print ( '### ip -6 route show type unreachable' )
2987 output
= check_output ( 'ip -6 route show type unreachable' )
2989 self
. assertIn ( 'unreachable 2001:1234:5678::3 dev lo proto static' , output
)
2991 print ( '### ip -6 route show type prohibit' )
2992 output
= check_output ( 'ip -6 route show type prohibit' )
2994 self
. assertIn ( 'prohibit 2001:1234:5678::4 dev lo proto static' , output
)
2996 print ( '### ip route show 192.168.10.1' )
2997 output
= check_output ( 'ip route show 192.168.10.1' )
2999 self
. assertIn ( '192.168.10.1 proto static' , output
)
3000 self
. assertIn ( 'nexthop via 149.10.124.59 dev dummy98 weight 10' , output
)
3001 self
. assertIn ( 'nexthop via 149.10.124.60 dev dummy98 weight 5' , output
)
3003 print ( '### ip route show 192.168.10.2' )
3004 output
= check_output ( 'ip route show 192.168.10.2' )
3006 # old ip command does not show IPv6 gateways...
3007 self
. assertIn ( '192.168.10.2 proto static' , output
)
3008 self
. assertIn ( 'nexthop' , output
)
3009 self
. assertIn ( 'dev dummy98 weight 10' , output
)
3010 self
. assertIn ( 'dev dummy98 weight 5' , output
)
3012 print ( '### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff' )
3013 output
= check_output ( 'ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff' )
3015 # old ip command does not show 'nexthop' keyword and weight...
3016 self
. assertIn ( '2001:1234:5:7fff:ff:ff:ff:ff' , output
)
3017 self
. assertIn ( 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98' , output
)
3018 self
. assertIn ( 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98' , output
)
3020 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3023 copy_network_unit ( '25-address-static.network' )
3025 self
. wait_online ([ 'dummy98:routable' ])
3027 # check all routes managed by Manager are removed
3028 print ( '### ip -4 route show type blackhole' )
3029 output
= check_output ( 'ip -4 route show type blackhole' )
3031 self
. assertEqual ( output
, '' )
3033 print ( '### ip -4 route show type unreachable' )
3034 output
= check_output ( 'ip -4 route show type unreachable' )
3036 self
. assertEqual ( output
, '' )
3038 print ( '### ip -4 route show type prohibit' )
3039 output
= check_output ( 'ip -4 route show type prohibit' )
3041 self
. assertEqual ( output
, '' )
3043 print ( '### ip -6 route show type blackhole' )
3044 output
= check_output ( 'ip -6 route show type blackhole' )
3046 self
. assertEqual ( output
, '' )
3048 print ( '### ip -6 route show type unreachable' )
3049 output
= check_output ( 'ip -6 route show type unreachable' )
3051 self
. assertEqual ( output
, '' )
3053 print ( '### ip -6 route show type prohibit' )
3054 output
= check_output ( 'ip -6 route show type prohibit' )
3056 self
. assertEqual ( output
, '' )
3058 remove_network_unit ( '25-address-static.network' )
3060 self
. wait_online ([ 'dummy98:routable' ])
3062 # check all routes managed by Manager are reconfigured
3063 print ( '### ip -4 route show type blackhole' )
3064 output
= check_output ( 'ip -4 route show type blackhole' )
3066 self
. assertIn ( 'blackhole 202.54.1.2 proto static' , output
)
3068 print ( '### ip -4 route show type unreachable' )
3069 output
= check_output ( 'ip -4 route show type unreachable' )
3071 self
. assertIn ( 'unreachable 202.54.1.3 proto static' , output
)
3073 print ( '### ip -4 route show type prohibit' )
3074 output
= check_output ( 'ip -4 route show type prohibit' )
3076 self
. assertIn ( 'prohibit 202.54.1.4 proto static' , output
)
3078 print ( '### ip -6 route show type blackhole' )
3079 output
= check_output ( 'ip -6 route show type blackhole' )
3081 self
. assertIn ( 'blackhole 2001:1234:5678::2 dev lo proto static' , output
)
3083 print ( '### ip -6 route show type unreachable' )
3084 output
= check_output ( 'ip -6 route show type unreachable' )
3086 self
. assertIn ( 'unreachable 2001:1234:5678::3 dev lo proto static' , output
)
3088 print ( '### ip -6 route show type prohibit' )
3089 output
= check_output ( 'ip -6 route show type prohibit' )
3091 self
. assertIn ( 'prohibit 2001:1234:5678::4 dev lo proto static' , output
)
3093 remove_link ( 'dummy98' )
3096 # check all routes managed by Manager are removed
3097 print ( '### ip -4 route show type blackhole' )
3098 output
= check_output ( 'ip -4 route show type blackhole' )
3100 self
. assertEqual ( output
, '' )
3102 print ( '### ip -4 route show type unreachable' )
3103 output
= check_output ( 'ip -4 route show type unreachable' )
3105 self
. assertEqual ( output
, '' )
3107 print ( '### ip -4 route show type prohibit' )
3108 output
= check_output ( 'ip -4 route show type prohibit' )
3110 self
. assertEqual ( output
, '' )
3112 print ( '### ip -6 route show type blackhole' )
3113 output
= check_output ( 'ip -6 route show type blackhole' )
3115 self
. assertEqual ( output
, '' )
3117 print ( '### ip -6 route show type unreachable' )
3118 output
= check_output ( 'ip -6 route show type unreachable' )
3120 self
. assertEqual ( output
, '' )
3122 print ( '### ip -6 route show type prohibit' )
3123 output
= check_output ( 'ip -6 route show type prohibit' )
3125 self
. assertEqual ( output
, '' )
3129 def test_route_static ( self
):
3131 for manage_foreign_routes
in [ True , False ]:
3137 print ( f
'### test_route_static(manage_foreign_routes= {manage_foreign_routes} )' )
3138 with self
. subTest ( manage_foreign_routes
= manage_foreign_routes
):
3139 self
._ test
_ route
_ static
( manage_foreign_routes
)
3141 @expectedFailureIfRTA_VIAIsNotSupported ()
3142 def test_route_via_ipv6 ( self
):
3143 copy_network_unit ( '25-route-via-ipv6.network' , '12-dummy.netdev' )
3145 self
. wait_online ([ 'dummy98:routable' ])
3147 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
3150 print ( '### ip -6 route show dev dummy98' )
3151 output
= check_output ( 'ip -6 route show dev dummy98' )
3153 self
. assertRegex ( output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static' )
3154 self
. assertRegex ( output
, '2001:1234:5:8f63::1 proto kernel' )
3156 print ( '### ip -4 route show dev dummy98' )
3157 output
= check_output ( 'ip -4 route show dev dummy98' )
3159 self
. assertRegex ( output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58' )
3160 self
. assertRegex ( output
, '149.10.124.66 via inet6 2001:1234:5:8fff:ff:ff:ff:ff proto static' )
3162 @expectedFailureIfModuleIsNotAvailable ( 'tcp_dctcp' )
3163 def test_route_congctl ( self
):
3164 copy_network_unit ( '25-route-congctl.network' , '12-dummy.netdev' )
3166 self
. wait_online ([ 'dummy98:routable' ])
3168 print ( '### ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff' )
3169 output
= check_output ( 'ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff' )
3171 self
. assertIn ( '2001:1234:5:8fff:ff:ff:ff:ff proto static' , output
)
3172 self
. assertIn ( 'congctl dctcp' , output
)
3174 print ( '### ip -4 route show dev dummy98 149.10.124.66' )
3175 output
= check_output ( 'ip -4 route show dev dummy98 149.10.124.66' )
3177 self
. assertIn ( '149.10.124.66 proto static' , output
)
3178 self
. assertIn ( 'congctl dctcp' , output
)
3179 self
. assertIn ( 'rto_min 300s' , output
)
3181 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
3182 def test_route_vrf ( self
):
3183 copy_network_unit ( '25-route-vrf.network' , '12-dummy.netdev' ,
3184 '25-vrf.netdev' , '25-vrf.network' )
3186 self
. wait_online ([ 'dummy98:routable' , 'vrf99:carrier' ])
3188 output
= check_output ( 'ip route show vrf vrf99' )
3190 self
. assertRegex ( output
, 'default via 192.168.100.1' )
3192 output
= check_output ( 'ip route show' )
3194 self
. assertNotRegex ( output
, 'default via 192.168.100.1' )
3196 def test_gateway_reconfigure ( self
):
3197 copy_network_unit ( '25-gateway-static.network' , '12-dummy.netdev' )
3199 self
. wait_online ([ 'dummy98:routable' ])
3200 print ( '### ip -4 route show dev dummy98 default' )
3201 output
= check_output ( 'ip -4 route show dev dummy98 default' )
3203 self
. assertIn ( 'default via 149.10.124.59 proto static' , output
)
3204 self
. assertNotIn ( '149.10.124.60' , output
)
3206 remove_network_unit ( '25-gateway-static.network' )
3207 copy_network_unit ( '25-gateway-next-static.network' )
3209 self
. wait_online ([ 'dummy98:routable' ])
3210 print ( '### ip -4 route show dev dummy98 default' )
3211 output
= check_output ( 'ip -4 route show dev dummy98 default' )
3213 self
. assertNotIn ( '149.10.124.59' , output
)
3214 self
. assertIn ( 'default via 149.10.124.60 proto static' , output
)
3216 def test_ip_route_ipv6_src_route ( self
):
3217 # a dummy device does not make the addresses go through tentative state, so we
3218 # reuse a bond from an earlier test, which does make the addresses go through
3219 # tentative state, and do our test on that
3220 copy_network_unit ( '23-active-slave.network' , '25-route-ipv6-src.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
3222 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:routable' ])
3224 output
= check_output ( 'ip -6 route list dev bond199' )
3226 self
. assertIn ( 'abcd::/16 via 2001:1234:56:8f63::1:1 proto static src 2001:1234:56:8f63::2' , output
)
3228 def test_route_preferred_source_with_existing_address ( self
):
3230 copy_network_unit ( '25-route-preferred-source.network' , '12-dummy.netdev' )
3235 networkctl_reconfigure ( 'dummy98' )
3237 self
. wait_online ([ 'dummy98:routable' ])
3239 output
= check_output ( 'ip -6 route list dev dummy98' )
3241 self
. assertIn ( 'abcd::/16 via 2001:1234:56:8f63::1:1 proto static src 2001:1234:56:8f63::1' , output
)
3243 def test_ip_link_mac_address ( self
):
3244 copy_network_unit ( '25-address-link-section.network' , '12-dummy.netdev' )
3246 self
. wait_online ([ 'dummy98:degraded' ])
3248 output
= check_output ( 'ip link show dummy98' )
3250 self
. assertRegex ( output
, '00:01:02:aa:bb:cc' )
3252 def test_ip_link_unmanaged ( self
):
3253 copy_network_unit ( '25-link-section-unmanaged.network' , '12-dummy.netdev' )
3256 self
. wait_operstate ( 'dummy98' , 'off' , setup_state
= 'unmanaged' )
3258 def test_ipv6_address_label ( self
):
3259 copy_network_unit ( '25-ipv6-address-label-section.network' , '12-dummy.netdev' )
3261 self
. wait_online ([ 'dummy98:degraded' ])
3263 output
= check_output ( 'ip addrlabel list' )
3265 self
. assertRegex ( output
, '2004:da8:1::/64' )
3267 def test_ipv6_proxy_ndp ( self
):
3268 copy_network_unit ( '25-ipv6-proxy-ndp.network' , '12-dummy.netdev' )
3271 self
. wait_online ([ 'dummy98:routable' ])
3273 output
= check_output ( 'ip neighbor show proxy dev dummy98' )
3275 for i
in range ( 1 , 5 ):
3276 self
. assertRegex ( output
, f
'2607:5300:203:5215: {i} ::1 *proxy' )
3278 def test_neighbor_section ( self
):
3279 copy_network_unit ( '25-neighbor-section.network' , '12-dummy.netdev' , copy_dropins
= False )
3281 self
. wait_online ([ 'dummy98:degraded' ])
3283 print ( '### ip neigh list dev dummy98' )
3284 output
= check_output ( 'ip neigh list dev dummy98' )
3286 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:02:65 PERMANENT' , output
)
3287 self
. assertIn ( '2004:da8:1::1 lladdr 00:00:5e:00:02:66 PERMANENT' , output
)
3288 self
. assertNotIn ( '2004:da8:1:0::2' , output
)
3289 self
. assertNotIn ( '192.168.10.2' , output
)
3290 self
. assertNotIn ( '00:00:5e:00:02:67' , output
)
3292 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3295 copy_network_unit ( '25-neighbor-section.network.d/override.conf' )
3297 self
. wait_online ([ 'dummy98:degraded' ])
3299 print ( '### ip neigh list dev dummy98 (after reloading)' )
3300 output
= check_output ( 'ip neigh list dev dummy98' )
3302 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:03:65 PERMANENT' , output
)
3303 self
. assertIn ( '2004:da8:1::1 lladdr 00:00:5e:00:03:66 PERMANENT' , output
)
3304 self
. assertNotIn ( '2004:da8:1:0::2' , output
)
3305 self
. assertNotIn ( '192.168.10.2' , output
)
3306 self
. assertNotIn ( '00:00:5e:00:02' , output
)
3308 def test_neighbor_reconfigure ( self
):
3309 copy_network_unit ( '25-neighbor-section.network' , '12-dummy.netdev' , copy_dropins
= False )
3311 self
. wait_online ([ 'dummy98:degraded' ])
3313 print ( '### ip neigh list dev dummy98' )
3314 output
= check_output ( 'ip neigh list dev dummy98' )
3316 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:02:65 PERMANENT' , output
)
3317 self
. assertIn ( '2004:da8:1::1 lladdr 00:00:5e:00:02:66 PERMANENT' , output
)
3319 remove_network_unit ( '25-neighbor-section.network' )
3320 copy_network_unit ( '25-neighbor-next.network' )
3322 self
. wait_online ([ 'dummy98:degraded' ])
3323 print ( '### ip neigh list dev dummy98' )
3324 output
= check_output ( 'ip neigh list dev dummy98' )
3326 self
. assertNotIn ( '00:00:5e:00:02:65' , output
)
3327 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:02:66 PERMANENT' , output
)
3328 self
. assertNotIn ( '2004:da8:1::1' , output
)
3330 def test_neighbor_gre ( self
):
3331 copy_network_unit ( '25-neighbor-ip.network' , '25-neighbor-ipv6.network' , '25-neighbor-ip-dummy.network' ,
3332 '12-dummy.netdev' , '25-gre-tunnel-remote-any.netdev' , '25-ip6gre-tunnel-remote-any.netdev' )
3334 self
. wait_online ([ 'dummy98:degraded' , 'gretun97:routable' , 'ip6gretun97:routable' ], timeout
= '40s' )
3336 output
= check_output ( 'ip neigh list dev gretun97' )
3338 self
. assertIn ( '10.0.0.22 lladdr 10.65.223.239 PERMANENT' , output
)
3339 self
. assertNotIn ( '10.0.0.23' , output
)
3341 output
= check_output ( 'ip neigh list dev ip6gretun97' )
3343 self
. assertRegex ( output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT' )
3344 self
. assertNotIn ( '2001:db8:0:f102::18' , output
)
3346 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3349 def test_link_local_addressing ( self
):
3350 copy_network_unit ( '25-link-local-addressing-yes.network' , '11-dummy.netdev' ,
3351 '25-link-local-addressing-no.network' , '12-dummy.netdev' )
3353 self
. wait_online ([ 'test1:degraded' , 'dummy98:carrier' ])
3355 output
= check_output ( 'ip address show dev test1' )
3357 self
. assertRegex ( output
, 'inet .* scope link' )
3358 self
. assertRegex ( output
, 'inet6 .* scope link' )
3360 output
= check_output ( 'ip address show dev dummy98' )
3362 self
. assertNotRegex ( output
, 'inet6* .* scope link' )
3364 # Documentation/networking/ip-sysctl.txt
3366 # addr_gen_mode - INTEGER
3367 # Defines how link-local and autoconf addresses are generated.
3369 # 0: generate address based on EUI64 (default)
3370 # 1: do no generate a link-local address, use EUI64 for addresses generated
3372 # 2: generate stable privacy addresses, using the secret from
3373 # stable_secret (RFC7217)
3374 # 3: generate stable privacy addresses, using a random secret if unset
3376 self
. check_ipv6_sysctl_attr ( 'test1' , 'stable_secret' , '0123:4567:89ab:cdef:0123:4567:89ab:cdef' )
3377 self
. check_ipv6_sysctl_attr ( 'test1' , 'addr_gen_mode' , '2' )
3378 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'addr_gen_mode' , '1' )
3380 def test_link_local_addressing_ipv6ll ( self
):
3381 copy_network_unit ( '26-link-local-addressing-ipv6.network' , '12-dummy.netdev' )
3383 self
. wait_online ([ 'dummy98:degraded' ])
3385 # An IPv6LL address exists by default.
3386 output
= check_output ( 'ip address show dev dummy98' )
3388 self
. assertRegex ( output
, 'inet6 .* scope link' )
3390 copy_network_unit ( '25-link-local-addressing-no.network' )
3392 self
. wait_online ([ 'dummy98:carrier' ])
3394 # Check if the IPv6LL address is removed.
3395 output
= check_output ( 'ip address show dev dummy98' )
3397 self
. assertNotRegex ( output
, 'inet6 .* scope link' )
3399 remove_network_unit ( '25-link-local-addressing-no.network' )
3401 self
. wait_online ([ 'dummy98:degraded' ])
3403 # Check if a new IPv6LL address is assigned.
3404 output
= check_output ( 'ip address show dev dummy98' )
3406 self
. assertRegex ( output
, 'inet6 .* scope link' )
3408 def test_sysctl ( self
):
3409 copy_networkd_conf_dropin ( '25-global-ipv6-privacy-extensions.conf' )
3410 copy_network_unit ( '25-sysctl.network' , '12-dummy.netdev' , copy_dropins
= False )
3412 self
. wait_online ([ 'dummy98:degraded' ])
3414 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
3415 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'use_tempaddr' , '1' )
3416 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'dad_transmits' , '3' )
3417 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'hop_limit' , '5' )
3418 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'proxy_ndp' , '1' )
3419 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
3420 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'proxy_arp' , '1' )
3421 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'accept_local' , '1' )
3422 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'rp_filter' , '0' )
3424 copy_network_unit ( '25-sysctl.network.d/25-ipv6-privacy-extensions.conf' )
3426 self
. wait_online ([ 'dummy98:degraded' ])
3428 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'use_tempaddr' , '2' )
3430 def test_sysctl_disable_ipv6 ( self
):
3431 copy_network_unit ( '25-sysctl-disable-ipv6.network' , '12-dummy.netdev' )
3433 print ( '## Disable ipv6' )
3434 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=1' )
3435 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=1' )
3438 self
. wait_online ([ 'dummy98:routable' ])
3440 output
= check_output ( 'ip -4 address show dummy98' )
3442 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3443 output
= check_output ( 'ip -6 address show dummy98' )
3445 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3446 self
. assertRegex ( output
, 'inet6 .* scope link' )
3447 output
= check_output ( 'ip -4 route show dev dummy98' )
3449 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3450 output
= check_output ( 'ip -6 route show default' )
3452 self
. assertRegex ( output
, 'default' )
3453 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3455 remove_link ( 'dummy98' )
3457 print ( '## Enable ipv6' )
3458 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=0' )
3459 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=0' )
3462 self
. wait_online ([ 'dummy98:routable' ])
3464 output
= check_output ( 'ip -4 address show dummy98' )
3466 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3467 output
= check_output ( 'ip -6 address show dummy98' )
3469 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3470 self
. assertRegex ( output
, 'inet6 .* scope link' )
3471 output
= check_output ( 'ip -4 route show dev dummy98' )
3473 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3474 output
= check_output ( 'ip -6 route show default' )
3476 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3478 def test_bind_carrier ( self
):
3479 copy_network_unit ( '25-bind-carrier.network' , '11-dummy.netdev' )
3482 # no bound interface.
3483 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
3484 output
= check_output ( 'ip address show test1' )
3486 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3487 self
. assertIn ( 'DOWN' , output
)
3488 self
. assertNotIn ( '192.168.10' , output
)
3490 # add one bound interface. The interface will be up.
3491 check_output ( 'ip link add dummy98 type dummy' )
3492 check_output ( 'ip link set dummy98 up' )
3493 self
. wait_online ([ 'test1:routable' ])
3494 output
= check_output ( 'ip address show test1' )
3496 self
. assertIn ( 'UP,LOWER_UP' , output
)
3497 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3499 # add another bound interface. The interface is still up.
3500 check_output ( 'ip link add dummy99 type dummy' )
3501 check_output ( 'ip link set dummy99 up' )
3502 self
. wait_operstate ( 'dummy99' , 'degraded' , setup_state
= 'unmanaged' )
3503 output
= check_output ( 'ip address show test1' )
3505 self
. assertIn ( 'UP,LOWER_UP' , output
)
3506 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3508 # remove one of the bound interfaces. The interface is still up
3509 remove_link ( 'dummy98' )
3510 output
= check_output ( 'ip address show test1' )
3512 self
. assertIn ( 'UP,LOWER_UP' , output
)
3513 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3515 # bring down the remaining bound interface. The interface will be down.
3516 check_output ( 'ip link set dummy99 down' )
3517 self
. wait_operstate ( 'test1' , 'off' )
3518 self
. wait_address_dropped ( 'test1' , r
'192.168.10' , ipv
= '-4' , timeout_sec
= 10 )
3519 output
= check_output ( 'ip address show test1' )
3521 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3522 self
. assertIn ( 'DOWN' , output
)
3523 self
. assertNotIn ( '192.168.10' , output
)
3525 # bring up the bound interface. The interface will be up.
3526 check_output ( 'ip link set dummy99 up' )
3527 self
. wait_online ([ 'test1:routable' ])
3528 output
= check_output ( 'ip address show test1' )
3530 self
. assertIn ( 'UP,LOWER_UP' , output
)
3531 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3533 # remove the remaining bound interface. The interface will be down.
3534 remove_link ( 'dummy99' )
3535 self
. wait_operstate ( 'test1' , 'off' )
3536 self
. wait_address_dropped ( 'test1' , r
'192.168.10' , ipv
= '-4' , timeout_sec
= 10 )
3537 output
= check_output ( 'ip address show test1' )
3539 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3540 self
. assertIn ( 'DOWN' , output
)
3541 self
. assertNotIn ( '192.168.10' , output
)
3543 # re-add one bound interface. The interface will be up.
3544 check_output ( 'ip link add dummy98 type dummy' )
3545 check_output ( 'ip link set dummy98 up' )
3546 self
. wait_online ([ 'test1:routable' ])
3547 output
= check_output ( 'ip address show test1' )
3549 self
. assertIn ( 'UP,LOWER_UP' , output
)
3550 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3552 def _test_activation_policy ( self
, interface
, test
):
3553 conffile
= '25-activation-policy.network'
3555 conffile
= f
' {conffile} .d/ {test} .conf'
3556 if interface
== 'vlan99' :
3557 copy_network_unit ( '21-vlan.netdev' , '21-vlan-test1.network' )
3558 copy_network_unit ( '11-dummy.netdev' , conffile
, copy_dropins
= False )
3561 always
= test
. startswith ( 'always' )
3562 initial_up
= test
!= 'manual' and not test
. endswith ( 'down' ) # note: default is up
3563 expect_up
= initial_up
3564 next_up
= not expect_up
3566 if test
. endswith ( 'down' ):
3567 self
. wait_activated ( interface
)
3569 for iteration
in range ( 4 ):
3570 with self
. subTest ( iteration
= iteration
, expect_up
= expect_up
):
3571 operstate
= 'routable' if expect_up
else 'off'
3572 setup_state
= 'configured' if expect_up
else ( 'configuring' if iteration
== 0 else None )
3573 self
. wait_operstate ( interface
, operstate
, setup_state
= setup_state
, setup_timeout
= 20 )
3576 self
. assertIn ( 'UP' , check_output ( f
'ip link show {interface} ' ))
3577 self
. assertIn ( '192.168.10.30/24' , check_output ( f
'ip address show {interface} ' ))
3578 self
. assertIn ( 'default via 192.168.10.1' , check_output ( f
'ip route show dev {interface} ' ))
3580 self
. assertIn ( 'DOWN' , check_output ( f
'ip link show {interface} ' ))
3583 check_output ( f
'ip link set dev {interface} up' )
3585 check_output ( f
'ip link set dev {interface} down' )
3586 expect_up
= initial_up
if always
else next_up
3587 next_up
= not next_up
3591 def test_activation_policy ( self
):
3593 for interface
in [ 'test1' , 'vlan99' ]:
3594 for test
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , '' ]:
3600 print ( f
'### test_activation_policy(interface= {interface} , test= {test} )' )
3601 with self
. subTest ( interface
= interface
, test
= test
):
3602 self
._ test
_ activation
_ policy
( interface
, test
)
3604 def _test_activation_policy_required_for_online ( self
, policy
, required
):
3605 conffile
= '25-activation-policy.network'
3606 units
= [ '11-dummy.netdev' , '12-dummy.netdev' , '12-dummy.network' , conffile
]
3608 units
+= [ f
' {conffile} .d/ {policy} .conf' ]
3610 units
+= [ f
' {conffile} .d/required- {required} .conf' ]
3611 copy_network_unit (* units
, copy_dropins
= False )
3614 if policy
. endswith ( 'down' ):
3615 self
. wait_activated ( 'test1' )
3617 if policy
. endswith ( 'down' ) or policy
== 'manual' :
3618 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
3620 self
. wait_online ([ 'test1' ])
3622 if policy
== 'always-down' :
3623 # if always-down, required for online is forced to no
3626 # otherwise if required for online is specified, it should match that
3627 expected
= required
== 'yes'
3629 # otherwise if only policy specified, required for online defaults to
3630 # true if policy is up, always-up, or bound
3631 expected
= policy
. endswith ( 'up' ) or policy
== 'bound'
3633 # default is true, if neither are specified
3636 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
3639 yesno
= 'yes' if expected
else 'no'
3640 self
. assertRegex ( output
, f
'Required For Online: {yesno} ' )
3642 def test_activation_policy_required_for_online ( self
):
3644 for policy
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , 'bound' , '' ]:
3645 for required
in [ 'yes' , 'no' , '' ]:
3651 print ( f
'### test_activation_policy_required_for_online(policy= {policy} , required= {required} )' )
3652 with self
. subTest ( policy
= policy
, required
= required
):
3653 self
._ test
_ activation
_ policy
_ required
_ for
_ online
( policy
, required
)
3655 def test_domain ( self
):
3656 copy_network_unit ( '12-dummy.netdev' , '24-search-domain.network' )
3658 self
. wait_online ([ 'dummy98:routable' ])
3660 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
3662 self
. assertRegex ( output
, 'Address: 192.168.42.100' )
3663 self
. assertRegex ( output
, 'DNS: 192.168.42.1' )
3664 self
. assertRegex ( output
, 'Search Domains: one' )
3666 def test_keep_configuration_static ( self
):
3667 check_output ( 'ip link add name dummy98 type dummy' )
3668 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
3669 check_output ( 'ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500' )
3670 output
= check_output ( 'ip address show dummy98' )
3672 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
3673 self
. assertRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
3674 output
= check_output ( 'ip route show dev dummy98' )
3677 copy_network_unit ( '24-keep-configuration-static.network' )
3679 self
. wait_online ([ 'dummy98:routable' ])
3681 output
= check_output ( 'ip address show dummy98' )
3683 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
3684 self
. assertNotRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
3686 @expectedFailureIfNexthopIsNotAvailable ()
3687 def test_nexthop ( self
):
3688 def check_nexthop ( self
):
3689 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
3691 output
= check_output ( 'ip nexthop list dev veth99' )
3693 self
. assertIn ( 'id 1 via 192.168.5.1 dev veth99' , output
)
3694 self
. assertIn ( 'id 2 via 2001:1234:5:8f63::2 dev veth99' , output
)
3695 self
. assertIn ( 'id 3 dev veth99' , output
)
3696 self
. assertIn ( 'id 4 dev veth99' , output
)
3697 self
. assertRegex ( output
, 'id 5 via 192.168.10.1 dev veth99 .*onlink' )
3698 self
. assertIn ( 'id 8 via fe80:0:222:4dff:ff:ff:ff:ff dev veth99' , output
)
3699 self
. assertRegex ( output
, r
'id [0-9]* via 192.168.5.2 dev veth99' )
3701 output
= check_output ( 'ip nexthop list dev dummy98' )
3703 self
. assertIn ( 'id 20 via 192.168.20.1 dev dummy98' , output
)
3705 # kernel manages blackhole nexthops on lo
3706 output
= check_output ( 'ip nexthop list dev lo' )
3708 self
. assertIn ( 'id 6 blackhole' , output
)
3709 self
. assertIn ( 'id 7 blackhole' , output
)
3711 # group nexthops are shown with -0 option
3712 output
= check_output ( 'ip -0 nexthop list id 21' )
3714 self
. assertRegex ( output
, r
'id 21 group (1,3/20|20/1,3)' )
3716 output
= check_output ( 'ip route show dev veth99 10.10.10.10' )
3718 self
. assertEqual ( '10.10.10.10 nhid 1 via 192.168.5.1 proto static' , output
)
3720 output
= check_output ( 'ip route show dev veth99 10.10.10.11' )
3722 self
. assertEqual ( '10.10.10.11 nhid 2 via inet6 2001:1234:5:8f63::2 proto static' , output
)
3724 output
= check_output ( 'ip route show dev veth99 10.10.10.12' )
3726 self
. assertEqual ( '10.10.10.12 nhid 5 via 192.168.10.1 proto static onlink' , output
)
3728 output
= check_output ( 'ip -6 route show dev veth99 2001:1234:5:8f62::1' )
3730 self
. assertEqual ( '2001:1234:5:8f62::1 nhid 2 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium' , output
)
3732 output
= check_output ( 'ip route show 10.10.10.13' )
3734 self
. assertEqual ( 'blackhole 10.10.10.13 nhid 6 dev lo proto static' , output
)
3736 output
= check_output ( 'ip -6 route show 2001:1234:5:8f62::2' )
3738 self
. assertEqual ( 'blackhole 2001:1234:5:8f62::2 nhid 7 dev lo proto static metric 1024 pref medium' , output
)
3740 output
= check_output ( 'ip route show 10.10.10.14' )
3742 self
. assertIn ( '10.10.10.14 nhid 21 proto static' , output
)
3743 self
. assertIn ( 'nexthop via 192.168.20.1 dev dummy98 weight 1' , output
)
3744 self
. assertIn ( 'nexthop via 192.168.5.1 dev veth99 weight 3' , output
)
3746 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3749 copy_network_unit ( '25-nexthop.network' , '25-veth.netdev' , '25-veth-peer.network' ,
3750 '12-dummy.netdev' , '25-nexthop-dummy.network' )
3755 remove_network_unit ( '25-nexthop.network' )
3756 copy_network_unit ( '25-nexthop-nothing.network' )
3758 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
3760 output
= check_output ( 'ip nexthop list dev veth99' )
3762 self
. assertEqual ( output
, '' )
3763 output
= check_output ( 'ip nexthop list dev lo' )
3765 self
. assertEqual ( output
, '' )
3767 remove_network_unit ( '25-nexthop-nothing.network' )
3768 copy_network_unit ( '25-nexthop.network' )
3769 networkctl_reconfigure ( 'dummy98' )
3774 remove_link ( 'veth99' )
3777 output
= check_output ( 'ip nexthop list dev lo' )
3779 self
. assertEqual ( output
, '' )
3781 class NetworkdTCTests ( unittest
. TestCase
, Utilities
):
3789 @expectedFailureIfModuleIsNotAvailable ( 'sch_cake' )
3790 def test_qdisc_cake ( self
):
3791 copy_network_unit ( '25-qdisc-cake.network' , '12-dummy.netdev' )
3793 self
. wait_online ([ 'dummy98:routable' ])
3795 output
= check_output ( 'tc qdisc show dev dummy98' )
3797 self
. assertIn ( 'qdisc cake 3a: root' , output
)
3798 self
. assertIn ( 'bandwidth 500Mbit' , output
)
3799 self
. assertIn ( 'autorate-ingress' , output
)
3800 self
. assertIn ( 'diffserv8' , output
)
3801 self
. assertIn ( 'dual-dsthost' , output
)
3802 self
. assertIn ( ' nat' , output
)
3803 self
. assertIn ( ' wash' , output
)
3804 self
. assertIn ( ' split-gso' , output
)
3805 self
. assertIn ( ' raw' , output
)
3806 self
. assertIn ( ' atm' , output
)
3807 self
. assertIn ( 'overhead 128' , output
)
3808 self
. assertIn ( 'mpu 20' , output
)
3809 self
. assertIn ( 'fwmark 0xff00' , output
)
3810 self
. assertIn ( 'rtt 1s' , output
)
3811 self
. assertIn ( 'ack-filter-aggressive' , output
)
3813 @expectedFailureIfModuleIsNotAvailable ( 'sch_codel' )
3814 def test_qdisc_codel ( self
):
3815 copy_network_unit ( '25-qdisc-codel.network' , '12-dummy.netdev' )
3817 self
. wait_online ([ 'dummy98:routable' ])
3819 output
= check_output ( 'tc qdisc show dev dummy98' )
3821 self
. assertRegex ( output
, 'qdisc codel 33: root' )
3822 self
. assertRegex ( output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn' )
3824 @expectedFailureIfModuleIsNotAvailable ( 'sch_drr' )
3825 def test_qdisc_drr ( self
):
3826 copy_network_unit ( '25-qdisc-drr.network' , '12-dummy.netdev' )
3828 self
. wait_online ([ 'dummy98:routable' ])
3830 output
= check_output ( 'tc qdisc show dev dummy98' )
3832 self
. assertRegex ( output
, 'qdisc drr 2: root' )
3833 output
= check_output ( 'tc class show dev dummy98' )
3835 self
. assertRegex ( output
, 'class drr 2:30 root quantum 2000b' )
3837 @expectedFailureIfModuleIsNotAvailable ( 'sch_ets' )
3838 def test_qdisc_ets ( self
):
3839 copy_network_unit ( '25-qdisc-ets.network' , '12-dummy.netdev' )
3841 self
. wait_online ([ 'dummy98:routable' ])
3843 output
= check_output ( 'tc qdisc show dev dummy98' )
3846 self
. assertRegex ( output
, 'qdisc ets 3a: root' )
3847 self
. assertRegex ( output
, 'bands 10 strict 3' )
3848 self
. assertRegex ( output
, 'quanta 1 2 3 4 5' )
3849 self
. assertRegex ( output
, 'priomap 3 4 5 6 7' )
3851 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq' )
3852 def test_qdisc_fq ( self
):
3853 copy_network_unit ( '25-qdisc-fq.network' , '12-dummy.netdev' )
3855 self
. wait_online ([ 'dummy98:routable' ])
3857 output
= check_output ( 'tc qdisc show dev dummy98' )
3859 self
. assertRegex ( output
, 'qdisc fq 32: root' )
3860 self
. assertRegex ( output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511' )
3861 self
. assertRegex ( output
, 'quantum 1500' )
3862 self
. assertRegex ( output
, 'initial_quantum 13000' )
3863 self
. assertRegex ( output
, 'maxrate 1Mbit' )
3865 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_codel' )
3866 def test_qdisc_fq_codel ( self
):
3867 copy_network_unit ( '25-qdisc-fq_codel.network' , '12-dummy.netdev' )
3869 self
. wait_online ([ 'dummy98:routable' ])
3871 output
= check_output ( 'tc qdisc show dev dummy98' )
3873 self
. assertRegex ( output
, 'qdisc fq_codel 34: root' )
3874 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' )
3876 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_pie' )
3877 def test_qdisc_fq_pie ( self
):
3878 copy_network_unit ( '25-qdisc-fq_pie.network' , '12-dummy.netdev' )
3880 self
. wait_online ([ 'dummy98:routable' ])
3882 output
= check_output ( 'tc qdisc show dev dummy98' )
3885 self
. assertRegex ( output
, 'qdisc fq_pie 3a: root' )
3886 self
. assertRegex ( output
, 'limit 200000p' )
3888 @expectedFailureIfModuleIsNotAvailable ( 'sch_gred' )
3889 def test_qdisc_gred ( self
):
3890 copy_network_unit ( '25-qdisc-gred.network' , '12-dummy.netdev' )
3892 self
. wait_online ([ 'dummy98:routable' ])
3894 output
= check_output ( 'tc qdisc show dev dummy98' )
3896 self
. assertRegex ( output
, 'qdisc gred 38: root' )
3897 self
. assertRegex ( output
, 'vqs 12 default 10 grio' )
3899 @expectedFailureIfModuleIsNotAvailable ( 'sch_hhf' )
3900 def test_qdisc_hhf ( self
):
3901 copy_network_unit ( '25-qdisc-hhf.network' , '12-dummy.netdev' )
3903 self
. wait_online ([ 'dummy98:routable' ])
3905 output
= check_output ( 'tc qdisc show dev dummy98' )
3907 self
. assertRegex ( output
, 'qdisc hhf 3a: root' )
3908 self
. assertRegex ( output
, 'limit 1022p' )
3910 @expectedFailureIfModuleIsNotAvailable ( 'sch_htb' )
3911 def test_qdisc_htb_fifo ( self
):
3912 copy_network_unit ( '25-qdisc-htb-fifo.network' , '12-dummy.netdev' )
3914 self
. wait_online ([ 'dummy98:routable' ])
3916 output
= check_output ( 'tc qdisc show dev dummy98' )
3918 self
. assertRegex ( output
, 'qdisc htb 2: root' )
3919 self
. assertRegex ( output
, r
'default (0x30|30)' )
3921 self
. assertRegex ( output
, 'qdisc pfifo 37: parent 2:37' )
3922 self
. assertRegex ( output
, 'limit 100000p' )
3924 self
. assertRegex ( output
, 'qdisc bfifo 3a: parent 2:3a' )
3925 self
. assertRegex ( output
, 'limit 1000000' )
3927 self
. assertRegex ( output
, 'qdisc pfifo_head_drop 3b: parent 2:3b' )
3928 self
. assertRegex ( output
, 'limit 1023p' )
3930 self
. assertRegex ( output
, 'qdisc pfifo_fast 3c: parent 2:3c' )
3932 output
= check_output ( 'tc -d class show dev dummy98' )
3934 # Here (:|prio) is a workaround for a bug in iproute2 v6.2.0 caused by
3935 # https://github.com/shemminger/iproute2/commit/010a8388aea11e767ba3a2506728b9ad9760df0e
3936 # which is fixed in v6.3.0 by
3937 # https://github.com/shemminger/iproute2/commit/4e0e56e0ef05387f7f5d8ab41fe6ec6a1897b26d
3938 self
. assertRegex ( output
, 'class htb 2:37 root leaf 37(:|prio) ' )
3939 self
. assertRegex ( output
, 'class htb 2:3a root leaf 3a(:|prio) ' )
3940 self
. assertRegex ( output
, 'class htb 2:3b root leaf 3b(:|prio) ' )
3941 self
. assertRegex ( output
, 'class htb 2:3c root leaf 3c(:|prio) ' )
3942 self
. assertRegex ( output
, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit' )
3943 self
. assertRegex ( output
, 'burst 123456' )
3944 self
. assertRegex ( output
, 'cburst 123457' )
3946 @expectedFailureIfModuleIsNotAvailable ( 'sch_ingress' )
3947 def test_qdisc_ingress ( self
):
3948 copy_network_unit ( '25-qdisc-clsact.network' , '12-dummy.netdev' ,
3949 '25-qdisc-ingress.network' , '11-dummy.netdev' )
3951 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' ])
3953 output
= check_output ( 'tc qdisc show dev dummy98' )
3955 self
. assertRegex ( output
, 'qdisc clsact' )
3957 output
= check_output ( 'tc qdisc show dev test1' )
3959 self
. assertRegex ( output
, 'qdisc ingress' )
3961 @expectedFailureIfModuleIsNotAvailable ( 'sch_netem' )
3962 def test_qdisc_netem ( self
):
3963 copy_network_unit ( '25-qdisc-netem.network' , '12-dummy.netdev' ,
3964 '25-qdisc-netem-compat.network' , '11-dummy.netdev' )
3966 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' ])
3968 output
= check_output ( 'tc qdisc show dev dummy98' )
3970 self
. assertRegex ( output
, 'qdisc netem 30: root' )
3971 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
3973 output
= check_output ( 'tc qdisc show dev test1' )
3975 self
. assertRegex ( output
, 'qdisc netem [0-9a-f]*: root' )
3976 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
3978 @expectedFailureIfModuleIsNotAvailable ( 'sch_pie' )
3979 def test_qdisc_pie ( self
):
3980 copy_network_unit ( '25-qdisc-pie.network' , '12-dummy.netdev' )
3982 self
. wait_online ([ 'dummy98:routable' ])
3984 output
= check_output ( 'tc qdisc show dev dummy98' )
3986 self
. assertRegex ( output
, 'qdisc pie 3a: root' )
3987 self
. assertRegex ( output
, 'limit 200000' )
3989 @expectedFailureIfModuleIsNotAvailable ( 'sch_qfq' )
3990 def test_qdisc_qfq ( self
):
3991 copy_network_unit ( '25-qdisc-qfq.network' , '12-dummy.netdev' )
3993 self
. wait_online ([ 'dummy98:routable' ])
3995 output
= check_output ( 'tc qdisc show dev dummy98' )
3997 self
. assertRegex ( output
, 'qdisc qfq 2: root' )
3998 output
= check_output ( 'tc class show dev dummy98' )
4000 self
. assertRegex ( output
, 'class qfq 2:30 root weight 2 maxpkt 16000' )
4001 self
. assertRegex ( output
, 'class qfq 2:31 root weight 10 maxpkt 8000' )
4003 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfb' )
4004 def test_qdisc_sfb ( self
):
4005 copy_network_unit ( '25-qdisc-sfb.network' , '12-dummy.netdev' )
4007 self
. wait_online ([ 'dummy98:routable' ])
4009 output
= check_output ( 'tc qdisc show dev dummy98' )
4011 self
. assertRegex ( output
, 'qdisc sfb 39: root' )
4012 self
. assertRegex ( output
, 'limit 200000' )
4014 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfq' )
4015 def test_qdisc_sfq ( self
):
4016 copy_network_unit ( '25-qdisc-sfq.network' , '12-dummy.netdev' )
4018 self
. wait_online ([ 'dummy98:routable' ])
4020 output
= check_output ( 'tc qdisc show dev dummy98' )
4022 self
. assertRegex ( output
, 'qdisc sfq 36: root' )
4023 self
. assertRegex ( output
, 'perturb 5sec' )
4025 @expectedFailureIfModuleIsNotAvailable ( 'sch_tbf' )
4026 def test_qdisc_tbf ( self
):
4027 copy_network_unit ( '25-qdisc-tbf.network' , '12-dummy.netdev' )
4029 self
. wait_online ([ 'dummy98:routable' ])
4031 output
= check_output ( 'tc qdisc show dev dummy98' )
4033 self
. assertRegex ( output
, 'qdisc tbf 35: root' )
4034 self
. assertRegex ( output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms' )
4036 @expectedFailureIfModuleIsNotAvailable ( 'sch_teql' )
4037 def test_qdisc_teql ( self
):
4038 call_quiet ( 'rmmod sch_teql' )
4040 copy_network_unit ( '25-qdisc-teql.network' , '12-dummy.netdev' )
4042 self
. wait_links ( 'dummy98' )
4043 check_output ( 'modprobe sch_teql max_equalizers=2' )
4044 self
. wait_online ([ 'dummy98:routable' ])
4046 output
= check_output ( 'tc qdisc show dev dummy98' )
4048 self
. assertRegex ( output
, 'qdisc teql1 31: root' )
4050 class NetworkdStateFileTests ( unittest
. TestCase
, Utilities
):
4058 def test_state_file ( self
):
4059 copy_network_unit ( '12-dummy.netdev' , '25-state-file-tests.network' )
4061 self
. wait_online ([ 'dummy98:routable' ])
4063 # make link state file updated
4064 check_output (* resolvectl_cmd
, 'revert' , 'dummy98' , env
= env
)
4066 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
4069 output
= read_link_state_file ( 'dummy98' )
4071 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
4072 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
4073 self
. assertIn ( 'ADMIN_STATE=configured' , output
)
4074 self
. assertIn ( 'OPER_STATE=routable' , output
)
4075 self
. assertIn ( 'REQUIRED_FOR_ONLINE=yes' , output
)
4076 self
. assertIn ( 'REQUIRED_OPER_STATE_FOR_ONLINE=routable' , output
)
4077 self
. assertIn ( 'REQUIRED_FAMILY_FOR_ONLINE=both' , output
)
4078 self
. assertIn ( 'ACTIVATION_POLICY=up' , output
)
4079 self
. assertIn ( 'NETWORK_FILE=/run/systemd/network/25-state-file-tests.network' , output
)
4080 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
4081 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
4082 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
4083 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
4084 self
. assertIn ( 'LLMNR=no' , output
)
4085 self
. assertIn ( 'MDNS=yes' , output
)
4086 self
. assertIn ( 'DNSSEC=no' , output
)
4088 check_output (* resolvectl_cmd
, 'dns' , 'dummy98' , '10.10.10.12#ccc.com' , '10.10.10.13' , '1111:2222::3333' , env
= env
)
4089 check_output (* resolvectl_cmd
, 'domain' , 'dummy98' , 'hogehogehoge' , '~foofoofoo' , env
= env
)
4090 check_output (* resolvectl_cmd
, 'llmnr' , 'dummy98' , 'yes' , env
= env
)
4091 check_output (* resolvectl_cmd
, 'mdns' , 'dummy98' , 'no' , env
= env
)
4092 check_output (* resolvectl_cmd
, 'dnssec' , 'dummy98' , 'yes' , env
= env
)
4093 check_output (* timedatectl_cmd
, 'ntp-servers' , 'dummy98' , '2.fedora.pool.ntp.org' , '3.fedora.pool.ntp.org' , env
= env
)
4095 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
4098 output
= read_link_state_file ( 'dummy98' )
4100 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
4101 self
. assertIn ( 'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org' , output
)
4102 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
4103 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
4104 self
. assertIn ( 'LLMNR=yes' , output
)
4105 self
. assertIn ( 'MDNS=no' , output
)
4106 self
. assertIn ( 'DNSSEC=yes' , output
)
4108 check_output (* timedatectl_cmd
, 'revert' , 'dummy98' , env
= env
)
4110 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
4113 output
= read_link_state_file ( 'dummy98' )
4115 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
4116 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
4117 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
4118 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
4119 self
. assertIn ( 'LLMNR=yes' , output
)
4120 self
. assertIn ( 'MDNS=no' , output
)
4121 self
. assertIn ( 'DNSSEC=yes' , output
)
4123 check_output (* resolvectl_cmd
, 'revert' , 'dummy98' , env
= env
)
4125 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
4128 output
= read_link_state_file ( 'dummy98' )
4130 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
4131 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
4132 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
4133 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
4134 self
. assertIn ( 'LLMNR=no' , output
)
4135 self
. assertIn ( 'MDNS=yes' , output
)
4136 self
. assertIn ( 'DNSSEC=no' , output
)
4138 def test_address_state ( self
):
4139 copy_network_unit ( '12-dummy.netdev' , '12-dummy-no-address.network' )
4142 self
. wait_online ([ 'dummy98:degraded' ])
4144 output
= read_link_state_file ( 'dummy98' )
4145 self
. assertIn ( 'IPV4_ADDRESS_STATE=off' , output
)
4146 self
. assertIn ( 'IPV6_ADDRESS_STATE=degraded' , output
)
4148 # with a routable IPv4 address
4149 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
4150 self
. wait_online ([ 'dummy98:routable' ], ipv4
= True )
4151 self
. wait_online ([ 'dummy98:routable' ])
4153 output
= read_link_state_file ( 'dummy98' )
4154 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
4155 self
. assertIn ( 'IPV6_ADDRESS_STATE=degraded' , output
)
4157 check_output ( 'ip address del 10.1.2.3/16 dev dummy98' )
4159 # with a routable IPv6 address
4160 check_output ( 'ip address add 2002:da8:1:0:1034:56ff:fe78:9abc/64 dev dummy98' )
4161 self
. wait_online ([ 'dummy98:routable' ], ipv6
= True )
4162 self
. wait_online ([ 'dummy98:routable' ])
4164 output
= read_link_state_file ( 'dummy98' )
4165 self
. assertIn ( 'IPV4_ADDRESS_STATE=off' , output
)
4166 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
4168 class NetworkdBondTests ( unittest
. TestCase
, Utilities
):
4176 def test_bond_keep_master ( self
):
4177 check_output ( 'ip link add bond199 type bond mode active-backup' )
4178 check_output ( 'ip link add dummy98 type dummy' )
4179 check_output ( 'ip link set dummy98 master bond199' )
4181 copy_network_unit ( '23-keep-master.network' )
4183 self
. wait_online ([ 'dummy98:enslaved' ])
4185 output
= check_output ( 'ip -d link show bond199' )
4187 self
. assertRegex ( output
, 'active_slave dummy98' )
4189 output
= check_output ( 'ip -d link show dummy98' )
4191 self
. assertRegex ( output
, 'master bond199' )
4193 def test_bond_active_slave ( self
):
4194 copy_network_unit ( '23-active-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
4196 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
4198 output
= check_output ( 'ip -d link show bond199' )
4200 self
. assertIn ( 'active_slave dummy98' , output
)
4202 def test_bond_primary_slave ( self
):
4203 copy_network_unit ( '23-primary-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
4205 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
4207 output
= check_output ( 'ip -d link show bond199' )
4209 self
. assertIn ( 'primary dummy98' , output
)
4212 mkdir_p ( os
. path
. join ( network_unit_dir
, '23-bond199.network.d' ))
4213 for mac
in [ '00:11:22:33:44:55' , '00:11:22:33:44:56' ]:
4214 with
open ( os
. path
. join ( network_unit_dir
, '23-bond199.network.d/mac.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
4215 f
. write ( f
'[Link] \n MACAddress= {mac} \n ' )
4218 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
4220 output
= check_output ( 'ip -d link show bond199' )
4222 self
. assertIn ( f
'link/ether {mac} ' , output
)
4224 def test_bond_operstate ( self
):
4225 copy_network_unit ( '25-bond.netdev' , '11-dummy.netdev' , '12-dummy.netdev' ,
4226 '25-bond99.network' , '25-bond-slave.network' )
4228 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bond99:routable' ])
4230 output
= check_output ( 'ip -d link show dummy98' )
4232 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
4234 output
= check_output ( 'ip -d link show test1' )
4236 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
4238 output
= check_output ( 'ip -d link show bond99' )
4240 self
. assertRegex ( output
, 'MASTER,UP,LOWER_UP' )
4242 self
. wait_operstate ( 'dummy98' , 'enslaved' )
4243 self
. wait_operstate ( 'test1' , 'enslaved' )
4244 self
. wait_operstate ( 'bond99' , 'routable' )
4246 check_output ( 'ip link set dummy98 down' )
4248 self
. wait_operstate ( 'dummy98' , 'off' )
4249 self
. wait_operstate ( 'test1' , 'enslaved' )
4250 self
. wait_operstate ( 'bond99' , 'routable' )
4252 check_output ( 'ip link set dummy98 up' )
4254 self
. wait_operstate ( 'dummy98' , 'enslaved' )
4255 self
. wait_operstate ( 'test1' , 'enslaved' )
4256 self
. wait_operstate ( 'bond99' , 'routable' )
4258 check_output ( 'ip link set dummy98 down' )
4259 check_output ( 'ip link set test1 down' )
4261 self
. wait_operstate ( 'dummy98' , 'off' )
4262 self
. wait_operstate ( 'test1' , 'off' )
4264 if not self
. wait_operstate ( 'bond99' , 'no-carrier' , setup_timeout
= 30 , fail_assert
= False ):
4265 # Huh? Kernel does not recognize that all slave interfaces are down?
4266 # Let's confirm that networkd's operstate is consistent with ip's result.
4267 self
. assertNotRegex ( output
, 'NO-CARRIER' )
4269 class NetworkdBridgeTests ( unittest
. TestCase
, Utilities
):
4277 def test_bridge_vlan ( self
):
4278 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave.network' ,
4279 '26-bridge.netdev' , '26-bridge-vlan-master.network' )
4281 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' ])
4283 output
= check_output ( 'bridge vlan show dev test1' )
4285 self
. assertNotRegex ( output
, '4063' )
4286 for i
in range ( 4064 , 4095 ):
4287 self
. assertRegex ( output
, f
' {i} ' )
4288 self
. assertNotRegex ( output
, '4095' )
4290 output
= check_output ( 'bridge vlan show dev bridge99' )
4292 self
. assertNotRegex ( output
, '4059' )
4293 for i
in range ( 4060 , 4095 ):
4294 self
. assertRegex ( output
, f
' {i} ' )
4295 self
. assertNotRegex ( output
, '4095' )
4297 def test_bridge_vlan_issue_20373 ( self
):
4298 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave-issue-20373.network' ,
4299 '26-bridge-issue-20373.netdev' , '26-bridge-vlan-master-issue-20373.network' ,
4300 '21-vlan.netdev' , '21-vlan.network' )
4302 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' , 'vlan99:routable' ])
4304 output
= check_output ( 'bridge vlan show dev test1' )
4306 self
. assertIn ( '100 PVID Egress Untagged' , output
)
4307 self
. assertIn ( '560' , output
)
4308 self
. assertIn ( '600' , output
)
4310 output
= check_output ( 'bridge vlan show dev bridge99' )
4312 self
. assertIn ( '1 PVID Egress Untagged' , output
)
4313 self
. assertIn ( '100' , output
)
4314 self
. assertIn ( '600' , output
)
4316 def test_bridge_mdb ( self
):
4317 copy_network_unit ( '11-dummy.netdev' , '26-bridge-mdb-slave.network' ,
4318 '26-bridge.netdev' , '26-bridge-mdb-master.network' )
4320 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' ])
4322 output
= check_output ( 'bridge mdb show dev bridge99' )
4324 self
. assertRegex ( output
, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064' )
4325 self
. assertRegex ( output
, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065' )
4327 # Old kernel may not support bridge MDB entries on bridge master
4328 if call_quiet ( 'bridge mdb add dev bridge99 port bridge99 grp 224.0.1.3 temp vid 4068' ) == 0 :
4329 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp ff02:aaaa:fee5::1:4 temp *vid 4066' )
4330 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp 224.0.1.2 temp *vid 4067' )
4332 def test_bridge_keep_master ( self
):
4333 check_output ( 'ip link add bridge99 type bridge' )
4334 check_output ( 'ip link set bridge99 up' )
4335 check_output ( 'ip link add dummy98 type dummy' )
4336 check_output ( 'ip link set dummy98 master bridge99' )
4338 copy_network_unit ( '23-keep-master.network' )
4340 self
. wait_online ([ 'dummy98:enslaved' ])
4342 output
= check_output ( 'ip -d link show dummy98' )
4344 self
. assertRegex ( output
, 'master bridge99' )
4345 self
. assertRegex ( output
, 'bridge' )
4347 output
= check_output ( 'bridge -d link show dummy98' )
4349 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
4350 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
4351 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
4352 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
4353 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
4354 # CONFIG_BRIDGE_IGMP_SNOOPING=y
4355 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
4356 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
4357 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
4358 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
4359 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
4360 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
4362 def test_bridge_property ( self
):
4363 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
4364 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
4365 '25-bridge99.network' )
4367 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' ])
4369 output
= check_output ( 'ip -d link show bridge99' )
4371 self
. assertIn ( 'mtu 9000 ' , output
)
4373 output
= check_output ( 'ip -d link show test1' )
4375 self
. assertIn ( 'master bridge99 ' , output
)
4376 self
. assertIn ( 'bridge_slave' , output
)
4377 self
. assertIn ( 'mtu 9000 ' , output
)
4379 output
= check_output ( 'ip -d link show dummy98' )
4381 self
. assertIn ( 'master bridge99 ' , output
)
4382 self
. assertIn ( 'bridge_slave' , output
)
4383 self
. assertIn ( 'mtu 9000 ' , output
)
4385 output
= check_output ( 'ip addr show bridge99' )
4387 self
. assertIn ( '192.168.0.15/24' , output
)
4389 output
= check_output ( 'bridge -d link show dummy98' )
4391 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
4392 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
4393 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'isolated' , '1' )
4394 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
4395 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
4396 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
4397 # CONFIG_BRIDGE_IGMP_SNOOPING=y
4398 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
4399 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
4400 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
4401 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
4402 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
4403 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
4405 output
= check_output ( 'bridge -d link show test1' )
4407 self
. check_bridge_port_attr ( 'bridge99' , 'test1' , 'priority' , '0' )
4409 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
4410 output
= check_output ( 'ip addr show bridge99' )
4412 self
. assertIn ( '192.168.0.16/24' , output
)
4415 print ( '### ip -6 route list table all dev bridge99' )
4416 output
= check_output ( 'ip -6 route list table all dev bridge99' )
4418 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
4420 remove_link ( 'test1' )
4421 self
. wait_operstate ( 'bridge99' , 'routable' )
4423 output
= check_output ( 'ip -d link show bridge99' )
4425 self
. assertIn ( 'mtu 9000 ' , output
)
4427 output
= check_output ( 'ip -d link show dummy98' )
4429 self
. assertIn ( 'master bridge99 ' , output
)
4430 self
. assertIn ( 'bridge_slave' , output
)
4431 self
. assertIn ( 'mtu 9000 ' , output
)
4433 remove_link ( 'dummy98' )
4434 self
. wait_operstate ( 'bridge99' , 'no-carrier' )
4436 output
= check_output ( 'ip -d link show bridge99' )
4438 # When no carrier, the kernel may reset the MTU
4439 self
. assertIn ( 'NO-CARRIER' , output
)
4441 output
= check_output ( 'ip address show bridge99' )
4443 self
. assertNotIn ( '192.168.0.15/24' , output
)
4444 self
. assertIn ( '192.168.0.16/24' , output
) # foreign address is kept
4446 print ( '### ip -6 route list table all dev bridge99' )
4447 output
= check_output ( 'ip -6 route list table all dev bridge99' )
4449 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
4451 check_output ( 'ip link add dummy98 type dummy' )
4452 self
. wait_online ([ 'dummy98:enslaved' , 'bridge99:routable' ])
4454 output
= check_output ( 'ip -d link show bridge99' )
4456 self
. assertIn ( 'mtu 9000 ' , output
)
4458 output
= check_output ( 'ip -d link show dummy98' )
4460 self
. assertIn ( 'master bridge99 ' , output
)
4461 self
. assertIn ( 'bridge_slave' , output
)
4462 self
. assertIn ( 'mtu 9000 ' , output
)
4464 def test_bridge_configure_without_carrier ( self
):
4465 copy_network_unit ( '26-bridge.netdev' , '26-bridge-configure-without-carrier.network' ,
4469 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
4470 for test
in [ 'no-slave' , 'add-slave' , 'slave-up' , 'slave-no-carrier' , 'slave-carrier' , 'slave-down' ]:
4471 with self
. subTest ( test
= test
):
4472 if test
== 'no-slave' :
4473 # bridge has no slaves; it's up but *might* not have carrier
4474 self
. wait_operstate ( 'bridge99' , operstate
= r
'(no-carrier|routable)' , setup_state
= None , setup_timeout
= 30 )
4475 # due to a bug in the kernel, newly-created bridges are brought up
4476 # *with* carrier, unless they have had any setting changed; e.g.
4477 # their mac set, priority set, etc. Then, they will lose carrier
4478 # as soon as a (down) slave interface is added, and regain carrier
4479 # again once the slave interface is brought up.
4480 #self.check_link_attr('bridge99', 'carrier', '0')
4481 elif test
== 'add-slave' :
4482 # add slave to bridge, but leave it down; bridge is definitely no-carrier
4483 self
. check_link_attr ( 'test1' , 'operstate' , 'down' )
4484 check_output ( 'ip link set dev test1 master bridge99' )
4485 self
. wait_operstate ( 'bridge99' , operstate
= 'no-carrier' , setup_state
= None )
4486 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4487 elif test
== 'slave-up' :
4488 # bring up slave, which will have carrier; bridge gains carrier
4489 check_output ( 'ip link set dev test1 up' )
4490 self
. wait_online ([ 'bridge99:routable' ])
4491 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
4492 elif test
== 'slave-no-carrier' :
4493 # drop slave carrier; bridge loses carrier
4494 check_output ( 'ip link set dev test1 carrier off' )
4495 self
. wait_online ([ 'bridge99:no-carrier:no-carrier' ])
4496 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4497 elif test
== 'slave-carrier' :
4498 # restore slave carrier; bridge gains carrier
4499 check_output ( 'ip link set dev test1 carrier on' )
4500 self
. wait_online ([ 'bridge99:routable' ])
4501 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
4502 elif test
== 'slave-down' :
4503 # bring down slave; bridge loses carrier
4504 check_output ( 'ip link set dev test1 down' )
4505 self
. wait_online ([ 'bridge99:no-carrier:no-carrier' ])
4506 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4508 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bridge99' , env
= env
)
4509 self
. assertRegex ( output
, '10.1.2.3' )
4510 self
. assertRegex ( output
, '10.1.2.1' )
4512 def test_bridge_ignore_carrier_loss ( self
):
4513 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
4514 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
4515 '25-bridge99-ignore-carrier-loss.network' )
4517 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' ])
4519 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
4520 remove_link ( 'test1' , 'dummy98' )
4523 output
= check_output ( 'ip address show bridge99' )
4525 self
. assertRegex ( output
, 'NO-CARRIER' )
4526 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
4527 self
. assertRegex ( output
, 'inet 192.168.0.16/24 scope global secondary bridge99' )
4529 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain ( self
):
4530 copy_network_unit ( '26-bridge.netdev' , '26-bridge-slave-interface-1.network' ,
4531 '25-bridge99-ignore-carrier-loss.network' )
4533 self
. wait_online ([ 'bridge99:no-carrier' ])
4535 for trial
in range ( 4 ):
4536 check_output ( 'ip link add dummy98 type dummy' )
4537 check_output ( 'ip link set dummy98 up' )
4539 remove_link ( 'dummy98' )
4541 self
. wait_online ([ 'bridge99:routable' , 'dummy98:enslaved' ])
4543 output
= check_output ( 'ip address show bridge99' )
4545 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
4547 output
= check_output ( 'ip rule list table 100' )
4549 self
. assertIn ( 'from all to 8.8.8.8 lookup 100' , output
)
4551 class NetworkdSRIOVTests ( unittest
. TestCase
, Utilities
):
4559 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
4560 def test_sriov ( self
):
4561 copy_network_unit ( '25-default.link' , '25-sriov.network' )
4563 call ( 'modprobe netdevsim' )
4565 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4568 with
open ( '/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4572 self
. wait_online ([ 'eni99np1:routable' ])
4574 output
= check_output ( 'ip link show dev eni99np1' )
4576 self
. assertRegex ( output
,
4577 '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 *'
4578 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4579 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4582 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
4583 def test_sriov_udev ( self
):
4584 copy_network_unit ( '25-sriov.link' , '25-sriov-udev.network' )
4586 call ( 'modprobe netdevsim' )
4588 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4592 self
. wait_online ([ 'eni99np1:routable' ])
4594 # the name eni99np1 may be an alternative name.
4595 ifname
= link_resolve ( 'eni99np1' )
4597 output
= check_output ( 'ip link show dev eni99np1' )
4599 self
. assertRegex ( output
,
4600 '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 *'
4601 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4602 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4604 self
. assertNotIn ( 'vf 3' , output
)
4605 self
. assertNotIn ( 'vf 4' , output
)
4607 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4608 f
. write ( '[Link] \n SR-IOVVirtualFunctions=4 \n ' )
4611 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4613 output
= check_output ( 'ip link show dev eni99np1' )
4615 self
. assertRegex ( output
,
4616 '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 *'
4617 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4618 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
4621 self
. assertNotIn ( 'vf 4' , output
)
4623 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4624 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
4627 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4629 output
= check_output ( 'ip link show dev eni99np1' )
4631 self
. assertRegex ( output
,
4632 '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 *'
4633 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4634 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
4637 self
. assertNotIn ( 'vf 4' , output
)
4639 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4640 f
. write ( '[Link] \n SR-IOVVirtualFunctions=2 \n ' )
4643 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4645 output
= check_output ( 'ip link show dev eni99np1' )
4647 self
. assertRegex ( output
,
4648 '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 *'
4649 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off'
4651 self
. assertNotIn ( 'vf 2' , output
)
4652 self
. assertNotIn ( 'vf 3' , output
)
4653 self
. assertNotIn ( 'vf 4' , output
)
4655 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4656 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
4659 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4661 output
= check_output ( 'ip link show dev eni99np1' )
4663 self
. assertRegex ( output
,
4664 '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 *'
4665 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4666 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4668 self
. assertNotIn ( 'vf 3' , output
)
4669 self
. assertNotIn ( 'vf 4' , output
)
4671 class NetworkdLLDPTests ( unittest
. TestCase
, Utilities
):
4679 def test_lldp ( self
):
4680 copy_network_unit ( '23-emit-lldp.network' , '24-lldp.network' , '25-veth.netdev' )
4682 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:degraded' ])
4684 for trial
in range ( 10 ):
4688 output
= check_output (* networkctl_cmd
, 'lldp' , env
= env
)
4690 if re
. search ( r
'veth99 .* veth-peer' , output
):
4695 class NetworkdRATests ( unittest
. TestCase
, Utilities
):
4703 def test_ipv6_prefix_delegation ( self
):
4704 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth.network' )
4706 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4708 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth99' , env
= env
)
4710 self
. assertRegex ( output
, 'fe80::' )
4711 self
. assertRegex ( output
, '2002:da8:1::1' )
4713 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth99' , env
= env
)
4715 self
. assertIn ( 'hogehoge.test' , output
)
4717 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4719 self
. assertRegex ( output
, '2002:da8:1:0' )
4721 self
. check_netlabel ( 'veth99' , '2002:da8:1::/64' )
4722 self
. check_netlabel ( 'veth99' , '2002:da8:2::/64' )
4724 def test_ipv6_token_static ( self
):
4725 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-static.network' )
4727 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4729 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4731 self
. assertRegex ( output
, '2002:da8:1:0:1a:2b:3c:4d' )
4732 self
. assertRegex ( output
, '2002:da8:1:0:fa:de:ca:fe' )
4733 self
. assertRegex ( output
, '2002:da8:2:0:1a:2b:3c:4d' )
4734 self
. assertRegex ( output
, '2002:da8:2:0:fa:de:ca:fe' )
4736 def test_ipv6_token_prefixstable ( self
):
4737 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable.network' )
4739 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4741 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4743 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
4744 self
. assertIn ( '2002:da8:2:0:1034:56ff:fe78:9abc' , output
) # EUI64
4746 def test_ipv6_token_prefixstable_without_address ( self
):
4747 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable-without-address.network' )
4749 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4751 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4753 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
4754 self
. assertIn ( '2002:da8:2:0:f689:561a:8eda:7443' , output
)
4756 def test_router_preference ( self
):
4757 copy_network_unit ( '25-veth-client.netdev' ,
4758 '25-veth-router-high.netdev' ,
4759 '25-veth-router-low.netdev' ,
4761 '25-veth-bridge.network' ,
4762 '25-veth-client.network' ,
4763 '25-veth-router-high.network' ,
4764 '25-veth-router-low.network' ,
4765 '25-bridge99.network' )
4767 self
. wait_online ([ 'client-p:enslaved' ,
4768 'router-high:degraded' , 'router-high-p:enslaved' ,
4769 'router-low:degraded' , 'router-low-p:enslaved' ,
4770 'bridge99:routable' ])
4772 networkctl_reconfigure ( 'client' )
4773 self
. wait_online ([ 'client:routable' ])
4775 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4776 self
. wait_address ( 'client' , '2002:da8:1:98:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4777 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 512' , ipv
= '-6' , timeout_sec
= 10 )
4778 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 2048' , ipv
= '-6' , timeout_sec
= 10 )
4780 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
4782 self
. assertIn ( 'pref high' , output
)
4783 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
4785 self
. assertIn ( 'pref low' , output
)
4787 with
open ( os
. path
. join ( network_unit_dir
, '25-veth-client.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4788 f
. write ( ' \n [Link] \n MACAddress=12:34:56:78:9a:01 \n [IPv6AcceptRA] \n RouteMetric=100:200:300 \n ' )
4791 self
. wait_online ([ 'client:routable' ])
4793 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a01/64' , ipv
= '-6' , timeout_sec
= 10 )
4794 self
. wait_address ( 'client' , '2002:da8:1:98:1034:56ff:fe78:9a01/64' , ipv
= '-6' , timeout_sec
= 10 )
4795 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 100' , ipv
= '-6' , timeout_sec
= 10 )
4796 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 300' , ipv
= '-6' , timeout_sec
= 10 )
4798 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
4800 self
. assertIn ( 'pref high' , output
)
4801 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
4803 self
. assertIn ( 'pref low' , output
)
4805 @unittest . skipUnless ( radvd_check_config ( 'captive-portal.conf' ), "Installed radvd doesn't support captive portals" )
4806 def test_captive_portal ( self
):
4807 copy_network_unit ( '25-veth-client.netdev' ,
4808 '25-veth-router-captive.netdev' ,
4810 '25-veth-client-captive.network' ,
4811 '25-veth-router-captive.network' ,
4812 '25-veth-bridge-captive.network' ,
4813 '25-bridge99.network' )
4815 self
. wait_online ([ 'bridge99:routable' , 'client-p:enslaved' ,
4816 'router-captive:degraded' , 'router-captivep:enslaved' ])
4818 start_radvd ( config_file
= 'captive-portal.conf' )
4819 networkctl_reconfigure ( 'client' )
4820 self
. wait_online ([ 'client:routable' ])
4822 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4823 output
= check_output (* networkctl_cmd
, 'status' , 'client' , env
= env
)
4825 self
. assertIn ( 'Captive Portal: http://systemd.io' , output
)
4827 @unittest . skipUnless ( radvd_check_config ( 'captive-portal.conf' ), "Installed radvd doesn't support captive portals" )
4828 def test_invalid_captive_portal ( self
):
4829 def radvd_write_config ( captive_portal_uri
):
4830 with
open ( os
. path
. join ( networkd_ci_temp_dir
, 'radvd/bogus-captive-portal.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
4831 f
. write ( f
'interface router-captive {{ AdvSendAdvert on; AdvCaptivePortalAPI " {captive_portal_uri} "; prefix 2002:da8:1:99::/64 {{ AdvOnLink on; AdvAutonomous on; }}; }};' )
4833 captive_portal_uris
= [
4834 "42ěščěškd ěšč ě s" ,
4839 copy_network_unit ( '25-veth-client.netdev' ,
4840 '25-veth-router-captive.netdev' ,
4842 '25-veth-client-captive.network' ,
4843 '25-veth-router-captive.network' ,
4844 '25-veth-bridge-captive.network' ,
4845 '25-bridge99.network' )
4847 self
. wait_online ([ 'bridge99:routable' , 'client-p:enslaved' ,
4848 'router-captive:degraded' , 'router-captivep:enslaved' ])
4850 for uri
in captive_portal_uris
:
4851 print ( f
"Captive portal: {uri} " )
4852 radvd_write_config ( uri
)
4854 start_radvd ( config_file
= 'bogus-captive-portal.conf' )
4855 networkctl_reconfigure ( 'client' )
4856 self
. wait_online ([ 'client:routable' ])
4858 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4859 output
= check_output (* networkctl_cmd
, 'status' , 'client' , env
= env
)
4861 self
. assertNotIn ( 'Captive Portal:' , output
)
4863 class NetworkdDHCPServerTests ( unittest
. TestCase
, Utilities
):
4871 def test_dhcp_server ( self
):
4872 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server.network' )
4874 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4876 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4878 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4879 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
4880 self
. assertRegex ( output
, 'DNS: 192.168.5.1 \n *192.168.5.10' )
4881 self
. assertRegex ( output
, 'NTP: 192.168.5.1 \n *192.168.5.11' )
4883 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth-peer' , env
= env
)
4884 self
. assertRegex ( output
, "Offered DHCP leases: 192.168.5.[0-9]*" )
4886 def test_dhcp_server_with_uplink ( self
):
4887 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-downstream.network' ,
4888 '12-dummy.netdev' , '25-dhcp-server-uplink.network' )
4890 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4892 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4894 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4895 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
4896 self
. assertIn ( 'DNS: 192.168.5.1' , output
)
4897 self
. assertIn ( 'NTP: 192.168.5.1' , output
)
4899 def test_emit_router_timezone ( self
):
4900 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-timezone-router.network' , '25-dhcp-server-timezone-router.network' )
4902 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4904 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4906 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4907 self
. assertIn ( 'Gateway: 192.168.5.1' , output
)
4908 self
. assertIn ( 'Time Zone: Europe/Berlin' , output
)
4910 def test_dhcp_server_static_lease ( self
):
4911 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-static-lease.network' , '25-dhcp-server-static-lease.network' )
4913 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4915 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4917 self
. assertIn ( 'Address: 10.1.1.200 (DHCP4 via 10.1.1.1)' , output
)
4918 self
. assertIn ( 'DHCP4 Client ID: 12:34:56:78:9a:bc' , output
)
4920 def test_dhcp_server_static_lease_default_client_id ( self
):
4921 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-static-lease.network' )
4923 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4925 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4927 self
. assertIn ( 'Address: 10.1.1.200 (DHCP4 via 10.1.1.1)' , output
)
4928 self
. assertRegex ( output
, 'DHCP4 Client ID: IAID:[0-9a-z]*/DUID' )
4930 class NetworkdDHCPServerRelayAgentTests ( unittest
. TestCase
, Utilities
):
4938 def test_relay_agent ( self
):
4939 copy_network_unit ( '25-agent-veth-client.netdev' ,
4940 '25-agent-veth-server.netdev' ,
4941 '25-agent-client.network' ,
4942 '25-agent-server.network' ,
4943 '25-agent-client-peer.network' ,
4944 '25-agent-server-peer.network' )
4947 self
. wait_online ([ 'client:routable' ])
4949 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'client' , env
= env
)
4951 self
. assertRegex ( output
, r
'Address: 192.168.5.150 \(DHCP4 via 192.168.5.1\)' )
4953 class NetworkdDHCPClientTests ( unittest
. TestCase
, Utilities
):
4961 def test_dhcp_client_ipv6_only ( self
):
4962 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv6-only.network' )
4965 self
. wait_online ([ 'veth-peer:carrier' ])
4967 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4970 output
= check_output ( 'ip address show dev veth99 scope global' )
4972 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
4973 self
. assertNotIn ( '192.168.5' , output
)
4975 # checking semi-static route
4976 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
4978 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
4980 # Confirm that ipv6 token is not set in the kernel
4981 output
= check_output ( 'ip token show dev veth99' )
4983 self
. assertRegex ( output
, 'token :: dev veth99' )
4985 print ( '## dnsmasq log' )
4986 output
= read_dnsmasq_log_file ()
4988 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
4989 self
. assertNotIn ( 'DHCPADVERTISE(veth-peer)' , output
)
4990 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
4991 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
4992 self
. assertIn ( 'sent size: 0 option: 14 rapid-commit' , output
)
4994 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-ipv6-only.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4995 f
. write ( ' \n [DHCPv6] \n RapidCommit=no \n ' )
5001 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5004 output
= check_output ( 'ip address show dev veth99 scope global' )
5006 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
5007 self
. assertNotIn ( '192.168.5' , output
)
5009 # checking semi-static route
5010 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
5012 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
5014 print ( '## dnsmasq log' )
5015 output
= read_dnsmasq_log_file ()
5017 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
5018 self
. assertIn ( 'DHCPADVERTISE(veth-peer)' , output
)
5019 self
. assertIn ( 'DHCPREQUEST(veth-peer)' , output
)
5020 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
5021 self
. assertNotIn ( 'rapid-commit' , output
)
5023 def test_dhcp_client_ipv6_only_with_custom_client_identifier ( self
):
5024 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv6-only-custom-client-identifier.network' )
5027 self
. wait_online ([ 'veth-peer:carrier' ])
5029 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5032 output
= check_output ( 'ip address show dev veth99 scope global' )
5034 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
5035 self
. assertNotIn ( '192.168.5' , output
)
5037 print ( '## dnsmasq log' )
5038 output
= read_dnsmasq_log_file ()
5040 self
. assertIn ( 'DHCPSOLICIT(veth-peer) 00:42:00:00:ab:11:f9:2a:c2:77:29:f9:5c:00' , output
)
5041 self
. assertNotIn ( 'DHCPADVERTISE(veth-peer)' , output
)
5042 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
5043 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
5044 self
. assertIn ( 'sent size: 0 option: 14 rapid-commit' , output
)
5048 def test_dhcp_client_ipv4_only ( self
):
5049 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv4-only.network' )
5052 self
. wait_online ([ 'veth-peer:carrier' ])
5053 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7' ,
5054 '--dhcp-option=option:domain-search,example.com' ,
5055 '--dhcp-alternate-port=67,5555' ,
5056 ipv4_range
= '192.168.5.110,192.168.5.119' )
5057 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5058 self
. wait_address ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' )
5060 print ( '## ip address show dev veth99 scope global' )
5061 output
= check_output ( 'ip address show dev veth99 scope global' )
5063 self
. assertIn ( 'mtu 1492' , output
)
5064 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
5065 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' )
5066 self
. assertNotIn ( '2600::' , output
)
5068 print ( '## ip route show table main dev veth99' )
5069 output
= check_output ( 'ip route show table main dev veth99' )
5071 # no DHCP routes assigned to the main table
5072 self
. assertNotIn ( 'proto dhcp' , output
)
5074 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
5075 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
5076 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
5077 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
5079 print ( '## ip route show table 211 dev veth99' )
5080 output
= check_output ( 'ip route show table 211 dev veth99' )
5082 self
. assertRegex ( output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.11[0-9] metric 24' )
5083 self
. assertRegex ( output
, '192.168.5.0/24 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
5084 self
. assertRegex ( output
, '192.168.5.1 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
5085 self
. assertRegex ( output
, '192.168.5.6 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
5086 self
. assertRegex ( output
, '192.168.5.7 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
5087 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
5089 print ( '## link state file' )
5090 output
= read_link_state_file ( 'veth99' )
5092 # checking DNS server and Domains
5093 self
. assertIn ( 'DNS=192.168.5.6 192.168.5.7' , output
)
5094 self
. assertIn ( 'DOMAINS=example.com' , output
)
5096 print ( '## dnsmasq log' )
5097 output
= read_dnsmasq_log_file ()
5099 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
5100 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc' , output
)
5101 self
. assertIn ( 'client provides name: test-hostname' , output
)
5102 self
. assertIn ( '26:mtu' , output
)
5104 # change address range, DNS servers, and Domains
5106 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8' ,
5107 '--dhcp-option=option:domain-search,foo.example.com' ,
5108 '--dhcp-alternate-port=67,5555' ,
5109 ipv4_range
= '192.168.5.120,192.168.5.129' ,)
5111 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
5112 print ( 'Wait for the DHCP lease to be expired' )
5113 self
. wait_address_dropped ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' , timeout_sec
= 120 )
5114 self
. wait_address ( 'veth99' , r
'inet 192.168.5.12[0-9]*/24' , ipv
= '-4' )
5116 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5118 print ( '## ip address show dev veth99 scope global' )
5119 output
= check_output ( 'ip address show dev veth99 scope global' )
5121 self
. assertIn ( 'mtu 1492' , output
)
5122 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
5123 self
. assertNotIn ( '192.168.5.11' , output
)
5124 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' )
5125 self
. assertNotIn ( '2600::' , output
)
5127 print ( '## ip route show table main dev veth99' )
5128 output
= check_output ( 'ip route show table main dev veth99' )
5130 # no DHCP routes assigned to the main table
5131 self
. assertNotIn ( 'proto dhcp' , output
)
5133 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
5134 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
5135 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
5136 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
5138 print ( '## ip route show table 211 dev veth99' )
5139 output
= check_output ( 'ip route show table 211 dev veth99' )
5141 self
. assertRegex ( output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.12[0-9] metric 24' )
5142 self
. assertRegex ( output
, '192.168.5.0/24 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
5143 self
. assertRegex ( output
, '192.168.5.1 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
5144 self
. assertNotIn ( '192.168.5.6' , output
)
5145 self
. assertRegex ( output
, '192.168.5.7 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
5146 self
. assertRegex ( output
, '192.168.5.8 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
5147 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
5149 print ( '## link state file' )
5150 output
= read_link_state_file ( 'veth99' )
5152 # checking DNS server and Domains
5153 self
. assertIn ( 'DNS=192.168.5.1 192.168.5.7 192.168.5.8' , output
)
5154 self
. assertIn ( 'DOMAINS=foo.example.com' , output
)
5156 print ( '## dnsmasq log' )
5157 output
= read_dnsmasq_log_file ()
5159 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
5160 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 192.168.5.11' , output
)
5161 self
. assertIn ( 'client provides name: test-hostname' , output
)
5162 self
. assertIn ( '26:mtu' , output
)
5164 self
. check_netlabel ( 'veth99' , r
'192\.168\.5\.0/24' )
5166 def test_dhcp_client_ipv4_use_routes_gateway ( self
):
5168 for ( routes
, gateway
, dns_and_ntp_routes
, classless
) in itertools
. product ([ True , False ], repeat
= 4 ):
5174 print ( f
'### test_dhcp_client_ipv4_use_routes_gateway(routes= {routes} , gateway= {gateway} , dns_and_ntp_routes= {dns_and_ntp_routes} , classless= {classless} )' )
5175 with self
. subTest ( routes
= routes
, gateway
= gateway
, dns_and_ntp_routes
= dns_and_ntp_routes
, classless
= classless
):
5176 self
._ test
_ dhcp
_ client
_ ipv
4_u se
_ routes
_ gateway
( routes
, gateway
, dns_and_ntp_routes
, classless
)
5178 def _test_dhcp_client_ipv4_use_routes_gateway ( self
, use_routes
, use_gateway
, dns_and_ntp_routes
, classless
):
5179 testunit
= '25-dhcp-client-ipv4-use-routes-use-gateway.network'
5180 testunits
= [ '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , testunit
]
5181 testunits
. append ( f
' {testunit} .d/use-routes- {use_routes} .conf' )
5182 testunits
. append ( f
' {testunit} .d/use-gateway- {use_gateway} .conf' )
5183 testunits
. append ( f
' {testunit} .d/use-dns-and-ntp-routes- {dns_and_ntp_routes} .conf' )
5184 copy_network_unit (* testunits
, copy_dropins
= False )
5187 self
. wait_online ([ 'veth-peer:carrier' ])
5188 additional_options
= [
5189 '--dhcp-option=option:dns-server,192.168.5.10,8.8.8.8' ,
5190 '--dhcp-option=option:ntp-server,192.168.5.11,9.9.9.9' ,
5191 '--dhcp-option=option:static-route,192.168.6.100,192.168.5.2,8.8.8.8,192.168.5.3'
5194 additional_options
+= [
5195 '--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'
5197 start_dnsmasq (* additional_options
)
5198 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5200 output
= check_output ( 'ip -4 route show dev veth99' )
5206 self
. assertRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5207 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5208 self
. assertRegex ( output
, r
'192.168.5.64/26 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5209 self
. assertRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5210 self
. assertRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5212 self
. assertRegex ( output
, r
'192.168.6.0/24 via 192.168.5.2 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5213 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5214 self
. assertRegex ( output
, r
'192.168.5.2 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5215 self
. assertRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5217 self
. assertNotRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5218 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5219 self
. assertNotRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5220 self
. assertNotRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5221 self
. assertNotRegex ( output
, r
'192.168.6.0/24 via 192.168.5.2 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5222 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5223 self
. assertNotRegex ( output
, r
'192.168.5.2 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5224 self
. assertNotRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5227 if use_gateway
and ( not classless
or not use_routes
):
5228 self
. assertRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5230 self
. assertNotRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5232 # Check route to gateway
5233 if ( use_gateway
or dns_and_ntp_routes
) and ( not classless
or not use_routes
):
5234 self
. assertRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5236 self
. assertNotRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5238 # Check RoutesToDNS= and RoutesToNTP=
5239 if dns_and_ntp_routes
:
5240 self
. assertRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5241 self
. assertRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5244 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5245 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5247 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5248 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5250 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5251 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5253 self
. assertNotRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5254 self
. assertNotRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5255 self
. assertNotRegex ( output
, r
'8.8.8.8 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
5256 self
. assertNotRegex ( output
, r
'9.9.9.9 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
5258 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5261 def test_dhcp_client_settings_anonymize ( self
):
5262 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-anonymize.network' )
5264 self
. wait_online ([ 'veth-peer:carrier' ])
5266 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5268 print ( '## dnsmasq log' )
5269 output
= read_dnsmasq_log_file ()
5271 self
. assertNotIn ( 'VendorClassIdentifier=SusantVendorTest' , output
)
5272 self
. assertNotIn ( 'test-hostname' , output
)
5273 self
. assertNotIn ( '26:mtu' , output
)
5275 def test_dhcp_keep_configuration_dhcp ( self
):
5276 copy_network_unit ( '25-veth.netdev' ,
5277 '25-dhcp-server-veth-peer.network' ,
5278 '25-dhcp-client-keep-configuration-dhcp.network' )
5280 self
. wait_online ([ 'veth-peer:carrier' ])
5282 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5284 output
= check_output ( 'ip address show dev veth99 scope global' )
5286 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5287 'valid_lft forever preferred_lft forever' )
5289 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
5292 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
5293 print ( 'Wait for the DHCP lease to be expired' )
5296 # The lease address should be kept after the lease expired
5297 output
= check_output ( 'ip address show dev veth99 scope global' )
5299 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5300 'valid_lft forever preferred_lft forever' )
5304 # The lease address should be kept after networkd stopped
5305 output
= check_output ( 'ip address show dev veth99 scope global' )
5307 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5308 'valid_lft forever preferred_lft forever' )
5310 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-keep-configuration-dhcp.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5311 f
. write ( '[Network] \n DHCP=no \n ' )
5314 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5316 # Still the lease address should be kept after networkd restarted
5317 output
= check_output ( 'ip address show dev veth99 scope global' )
5319 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5320 'valid_lft forever preferred_lft forever' )
5322 def test_dhcp_keep_configuration_dhcp_on_stop ( self
):
5323 copy_network_unit ( '25-veth.netdev' ,
5324 '25-dhcp-server-veth-peer.network' ,
5325 '25-dhcp-client-keep-configuration-dhcp-on-stop.network' )
5327 self
. wait_online ([ 'veth-peer:carrier' ])
5329 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5331 output
= check_output ( 'ip address show dev veth99 scope global' )
5333 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5338 output
= check_output ( 'ip address show dev veth99 scope global' )
5340 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5343 self
. wait_online ([ 'veth-peer:routable' ])
5345 output
= check_output ( 'ip address show dev veth99 scope global' )
5347 self
. assertNotIn ( '192.168.5.' , output
)
5349 def test_dhcp_client_reuse_address_as_static ( self
):
5350 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' )
5352 self
. wait_online ([ 'veth-peer:carrier' ])
5354 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5356 # link become 'routable' when at least one protocol provide an valid address.
5357 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5358 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5360 output
= check_output ( 'ip address show dev veth99 scope global' )
5361 ipv4_address
= re
. search ( r
'192.168.5.[0-9]*/24' , output
). group ()
5362 ipv6_address
= re
. search ( r
'2600::[0-9a-f:]*/128' , output
). group ()
5363 static_network
= ' \n ' . join ([ '[Match]' , 'Name=veth99' , '[Network]' , 'IPv6AcceptRA=no' , 'Address=' + ipv4_address
, 'Address=' + ipv6_address
])
5364 print ( static_network
)
5366 remove_network_unit ( '25-dhcp-client.network' )
5368 with
open ( os
. path
. join ( network_unit_dir
, '25-static.network' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5369 f
. write ( static_network
)
5372 self
. wait_online ([ 'veth99:routable' ])
5374 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
5376 self
. assertRegex ( output
, f
'inet {ipv4_address} brd 192.168.5.255 scope global veth99 \n *'
5377 'valid_lft forever preferred_lft forever' )
5379 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5381 self
. assertRegex ( output
, f
'inet6 {ipv6_address} scope global * \n *'
5382 'valid_lft forever preferred_lft forever' )
5384 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
5385 def test_dhcp_client_vrf ( self
):
5386 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-vrf.network' ,
5387 '25-vrf.netdev' , '25-vrf.network' )
5389 self
. wait_online ([ 'veth-peer:carrier' ])
5391 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'vrf99:carrier' ])
5393 # link become 'routable' when at least one protocol provide an valid address.
5394 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5395 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5397 print ( '## ip -d link show dev vrf99' )
5398 output
= check_output ( 'ip -d link show dev vrf99' )
5400 self
. assertRegex ( output
, 'vrf table 42' )
5402 print ( '## ip address show vrf vrf99' )
5403 output
= check_output ( 'ip address show vrf vrf99' )
5405 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5406 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5407 self
. assertRegex ( output
, 'inet6 .* scope link' )
5409 print ( '## ip address show dev veth99' )
5410 output
= check_output ( 'ip address show dev veth99' )
5412 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5413 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5414 self
. assertRegex ( output
, 'inet6 .* scope link' )
5416 print ( '## ip route show vrf vrf99' )
5417 output
= check_output ( 'ip route show vrf vrf99' )
5419 self
. assertRegex ( output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.' )
5420 self
. assertRegex ( output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5' )
5421 self
. assertRegex ( output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5' )
5423 print ( '## ip route show table main dev veth99' )
5424 output
= check_output ( 'ip route show table main dev veth99' )
5426 self
. assertEqual ( output
, '' )
5428 def test_dhcp_client_gateway_onlink_implicit ( self
):
5429 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
5430 '25-dhcp-client-gateway-onlink-implicit.network' )
5432 self
. wait_online ([ 'veth-peer:carrier' ])
5434 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5436 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
5438 self
. assertRegex ( output
, '192.168.5' )
5440 output
= check_output ( 'ip route list dev veth99 10.0.0.0/8' )
5442 self
. assertRegex ( output
, 'onlink' )
5443 output
= check_output ( 'ip route list dev veth99 192.168.100.0/24' )
5445 self
. assertRegex ( output
, 'onlink' )
5447 def test_dhcp_client_with_ipv4ll ( self
):
5448 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
5449 '25-dhcp-client-with-ipv4ll.network' )
5451 # we need to increase timeout above default, as this will need to wait for
5452 # systemd-networkd to get the dhcpv4 transient failure event
5453 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:routable' ], timeout
= '60s' )
5455 output
= check_output ( 'ip -4 address show dev veth99' )
5457 self
. assertNotIn ( '192.168.5.' , output
)
5458 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
5461 print ( 'Wait for a DHCP lease to be acquired and the IPv4LL address to be dropped' )
5462 self
. wait_address ( 'veth99' , r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic' , ipv
= '-4' )
5463 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' )
5464 self
. wait_online ([ 'veth99:routable' ])
5466 output
= check_output ( 'ip -4 address show dev veth99' )
5468 self
. assertRegex ( output
, r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99' )
5469 self
. assertNotIn ( '169.254.' , output
)
5470 self
. assertNotIn ( 'scope link' , output
)
5473 print ( 'Wait for the DHCP lease to be expired and an IPv4LL address to be acquired' )
5474 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 )
5475 self
. wait_address ( 'veth99' , r
'inet 169\.254\.133\.11/16 metric 2048 brd 169\.254\.255\.255 scope link' , scope
= 'link' , ipv
= '-4' )
5477 output
= check_output ( 'ip -4 address show dev veth99' )
5479 self
. assertNotIn ( '192.168.5.' , output
)
5480 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
5482 def test_dhcp_client_use_dns ( self
):
5483 def check ( self
, ipv4
, ipv6
):
5484 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5485 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5486 f
. write ( '[DHCPv4] \n UseDNS=' )
5487 f
. write ( 'yes' if ipv4
else 'no' )
5488 f
. write ( ' \n [DHCPv6] \n UseDNS=' )
5489 f
. write ( 'yes' if ipv6
else 'no' )
5490 f
. write ( ' \n [IPv6AcceptRA] \n UseDNS=no' )
5493 self
. wait_online ([ 'veth99:routable' ])
5495 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5496 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5497 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5499 # make resolved re-read the link state file
5500 check_output (* resolvectl_cmd
, 'revert' , 'veth99' , env
= env
)
5502 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth99' , env
= env
)
5505 self
. assertIn ( '192.168.5.1' , output
)
5507 self
. assertNotIn ( '192.168.5.1' , output
)
5509 self
. assertIn ( '2600::1' , output
)
5511 self
. assertNotIn ( '2600::1' , output
)
5513 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5516 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5519 self
. wait_online ([ 'veth-peer:carrier' ])
5520 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1' ,
5521 '--dhcp-option=option6:dns-server,[2600::1]' )
5523 check ( self
, True , True )
5524 check ( self
, True , False )
5525 check ( self
, False , True )
5526 check ( self
, False , False )
5528 def test_dhcp_client_use_captive_portal ( self
):
5529 def check ( self
, ipv4
, ipv6
):
5530 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5531 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5532 f
. write ( '[DHCPv4] \n UseCaptivePortal=' )
5533 f
. write ( 'yes' if ipv4
else 'no' )
5534 f
. write ( ' \n [DHCPv6] \n UseCaptivePortal=' )
5535 f
. write ( 'yes' if ipv6
else 'no' )
5536 f
. write ( ' \n [IPv6AcceptRA] \n UseCaptivePortal=no' )
5539 self
. wait_online ([ 'veth99:routable' ])
5541 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5542 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5543 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5545 output
= check_output (* networkctl_cmd
, 'status' , 'veth99' , env
= env
)
5548 self
. assertIn ( 'Captive Portal: http://systemd.io' , output
)
5550 self
. assertNotIn ( 'Captive Portal: http://systemd.io' , output
)
5552 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5555 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5558 self
. wait_online ([ 'veth-peer:carrier' ])
5559 start_dnsmasq ( '--dhcp-option=114,http://systemd.io' ,
5560 '--dhcp-option=option6:103,http://systemd.io' )
5562 check ( self
, True , True )
5563 check ( self
, True , False )
5564 check ( self
, False , True )
5565 check ( self
, False , False )
5567 def test_dhcp_client_reject_captive_portal ( self
):
5568 def check ( self
, ipv4
, ipv6
):
5569 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5570 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5571 f
. write ( '[DHCPv4] \n UseCaptivePortal=' )
5572 f
. write ( 'yes' if ipv4
else 'no' )
5573 f
. write ( ' \n [DHCPv6] \n UseCaptivePortal=' )
5574 f
. write ( 'yes' if ipv6
else 'no' )
5575 f
. write ( ' \n [IPv6AcceptRA] \n UseCaptivePortal=no' )
5578 self
. wait_online ([ 'veth99:routable' ])
5580 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5581 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5582 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5584 output
= check_output (* networkctl_cmd
, 'status' , 'veth99' , env
= env
)
5586 self
. assertNotIn ( 'Captive Portal: ' , output
)
5587 self
. assertNotIn ( 'invalid/url' , output
)
5589 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5592 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5595 self
. wait_online ([ 'veth-peer:carrier' ])
5596 masq
= lambda bs
: ':' . join ( f
'{b:02x}' for b
in bs
)
5597 start_dnsmasq ( '--dhcp-option=114,' + masq ( b
'http:// \x00 invalid/url' ),
5598 '--dhcp-option=option6:103,' + masq ( b
'http:// \x00 /invalid/url' ))
5600 check ( self
, True , True )
5601 check ( self
, True , False )
5602 check ( self
, False , True )
5603 check ( self
, False , False )
5605 class NetworkdDHCPPDTests ( unittest
. TestCase
, Utilities
):
5613 def test_dhcp6pd ( self
):
5614 copy_network_unit ( '25-veth.netdev' , '25-dhcp6pd-server.network' , '25-dhcp6pd-upstream.network' ,
5615 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
5616 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
5617 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
5618 '25-dhcp-pd-downstream-dummy97.network' ,
5619 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
5620 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' )
5623 self
. wait_online ([ 'veth-peer:routable' ])
5624 start_isc_dhcpd ( conf_file
= 'isc-dhcpd-dhcp6pd.conf' , ipv
= '-6' )
5625 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5626 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5628 print ( '### ip -6 address show dev veth-peer scope global' )
5629 output
= check_output ( 'ip -6 address show dev veth-peer scope global' )
5631 self
. assertIn ( 'inet6 3ffe:501:ffff:100::1/64 scope global' , output
)
5635 # dummy97: 0x01 (The link will appear later)
5637 # dummy99: auto -> 0x02 (No address assignment)
5642 print ( '### ip -6 address show dev veth99 scope global' )
5643 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5646 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:100::[0-9]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5647 # address in IA_PD (Token=static)
5648 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic' )
5649 # address in IA_PD (Token=eui64)
5650 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic' )
5651 # address in IA_PD (temporary)
5652 # Note that the temporary addresses may appear after the link enters configured state
5653 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' )
5655 print ( '### ip -6 address show dev test1 scope global' )
5656 output
= check_output ( 'ip -6 address show dev test1 scope global' )
5658 # address in IA_PD (Token=static)
5659 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5660 # address in IA_PD (temporary)
5661 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' )
5663 print ( '### ip -6 address show dev dummy98 scope global' )
5664 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5666 # address in IA_PD (Token=static)
5667 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5668 # address in IA_PD (temporary)
5669 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' )
5671 print ( '### ip -6 address show dev dummy99 scope global' )
5672 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5675 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
5677 print ( '### ip -6 address show dev veth97 scope global' )
5678 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
5680 # address in IA_PD (Token=static)
5681 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5682 # address in IA_PD (Token=eui64)
5683 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5684 # address in IA_PD (temporary)
5685 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' )
5687 print ( '### ip -6 address show dev veth97-peer scope global' )
5688 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
5690 # NDisc address (Token=static)
5691 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5692 # NDisc address (Token=eui64)
5693 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5694 # NDisc address (temporary)
5695 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' )
5697 print ( '### ip -6 address show dev veth98 scope global' )
5698 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
5700 # address in IA_PD (Token=static)
5701 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5702 # address in IA_PD (Token=eui64)
5703 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5704 # address in IA_PD (temporary)
5705 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' )
5707 print ( '### ip -6 address show dev veth98-peer scope global' )
5708 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
5710 # NDisc address (Token=static)
5711 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5712 # NDisc address (Token=eui64)
5713 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5714 # NDisc address (temporary)
5715 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' )
5717 print ( '### ip -6 route show type unreachable' )
5718 output
= check_output ( 'ip -6 route show type unreachable' )
5720 self
. assertRegex ( output
, 'unreachable 3ffe:501:ffff:[2-9a-f]00::/56 dev lo proto dhcp' )
5722 print ( '### ip -6 route show dev veth99' )
5723 output
= check_output ( 'ip -6 route show dev veth99' )
5725 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]10::/64 proto kernel metric [0-9]* expires' )
5727 print ( '### ip -6 route show dev test1' )
5728 output
= check_output ( 'ip -6 route show dev test1' )
5730 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5732 print ( '### ip -6 route show dev dummy98' )
5733 output
= check_output ( 'ip -6 route show dev dummy98' )
5735 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5737 print ( '### ip -6 route show dev dummy99' )
5738 output
= check_output ( 'ip -6 route show dev dummy99' )
5740 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
5742 print ( '### ip -6 route show dev veth97' )
5743 output
= check_output ( 'ip -6 route show dev veth97' )
5745 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto kernel metric [0-9]* expires' )
5747 print ( '### ip -6 route show dev veth97-peer' )
5748 output
= check_output ( 'ip -6 route show dev veth97-peer' )
5750 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto ra metric [0-9]* expires' )
5752 print ( '### ip -6 route show dev veth98' )
5753 output
= check_output ( 'ip -6 route show dev veth98' )
5755 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto kernel metric [0-9]* expires' )
5757 print ( '### ip -6 route show dev veth98-peer' )
5758 output
= check_output ( 'ip -6 route show dev veth98-peer' )
5760 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto ra metric [0-9]* expires' )
5762 # Test case for a downstream which appears later
5763 check_output ( 'ip link add dummy97 type dummy' )
5764 self
. wait_online ([ 'dummy97:routable' ])
5766 print ( '### ip -6 address show dev dummy97 scope global' )
5767 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
5769 # address in IA_PD (Token=static)
5770 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5771 # address in IA_PD (temporary)
5772 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' )
5774 print ( '### ip -6 route show dev dummy97' )
5775 output
= check_output ( 'ip -6 route show dev dummy97' )
5777 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]01::/64 proto kernel metric [0-9]* expires' )
5779 # Test case for reconfigure
5780 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
5781 self
. wait_online ([ 'dummy98:routable' , 'dummy99:degraded' ])
5783 print ( '### ip -6 address show dev dummy98 scope global' )
5784 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5786 # address in IA_PD (Token=static)
5787 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5788 # address in IA_PD (temporary)
5789 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' )
5791 print ( '### ip -6 address show dev dummy99 scope global' )
5792 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5795 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
5797 print ( '### ip -6 route show dev dummy98' )
5798 output
= check_output ( 'ip -6 route show dev dummy98' )
5800 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5802 print ( '### ip -6 route show dev dummy99' )
5803 output
= check_output ( 'ip -6 route show dev dummy99' )
5805 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
5807 self
. check_netlabel ( 'dummy98' , '3ffe:501:ffff:[2-9a-f]00::/64' )
5809 def verify_dhcp4_6rd ( self
, tunnel_name
):
5810 print ( '### ip -4 address show dev veth-peer scope global' )
5811 output
= check_output ( 'ip -4 address show dev veth-peer scope global' )
5813 self
. assertIn ( 'inet 10.0.0.1/8 brd 10.255.255.255 scope global veth-peer' , output
)
5817 # dummy97: 0x01 (The link will appear later)
5819 # dummy99: auto -> 0x0[23] (No address assignment)
5820 # 6rd-XXX: auto -> 0x0[23]
5825 print ( '### ip -4 address show dev veth99 scope global' )
5826 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
5828 self
. assertRegex ( output
, 'inet 10.100.100.[0-9]*/8 (metric 1024 |)brd 10.255.255.255 scope global dynamic veth99' )
5830 print ( '### ip -6 address show dev veth99 scope global' )
5831 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5833 # address in IA_PD (Token=static)
5834 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5835 # address in IA_PD (Token=eui64)
5836 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5837 # address in IA_PD (temporary)
5838 # Note that the temporary addresses may appear after the link enters configured state
5839 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' )
5841 print ( '### ip -6 address show dev test1 scope global' )
5842 output
= check_output ( 'ip -6 address show dev test1 scope global' )
5844 # address in IA_PD (Token=static)
5845 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5846 # address in IA_PD (temporary)
5847 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' )
5849 print ( '### ip -6 address show dev dummy98 scope global' )
5850 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5852 # address in IA_PD (Token=static)
5853 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5854 # address in IA_PD (temporary)
5855 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' )
5857 print ( '### ip -6 address show dev dummy99 scope global' )
5858 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5861 self
. assertNotRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+0[23]' )
5863 print ( '### ip -6 address show dev veth97 scope global' )
5864 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
5866 # address in IA_PD (Token=static)
5867 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5868 # address in IA_PD (Token=eui64)
5869 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5870 # address in IA_PD (temporary)
5871 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' )
5873 print ( '### ip -6 address show dev veth97-peer scope global' )
5874 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
5876 # NDisc address (Token=static)
5877 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5878 # NDisc address (Token=eui64)
5879 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5880 # NDisc address (temporary)
5881 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' )
5883 print ( '### ip -6 address show dev veth98 scope global' )
5884 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
5886 # address in IA_PD (Token=static)
5887 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5888 # address in IA_PD (Token=eui64)
5889 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5890 # address in IA_PD (temporary)
5891 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' )
5893 print ( '### ip -6 address show dev veth98-peer scope global' )
5894 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
5896 # NDisc address (Token=static)
5897 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5898 # NDisc address (Token=eui64)
5899 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5900 # NDisc address (temporary)
5901 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' )
5903 print ( '### ip -6 route show type unreachable' )
5904 output
= check_output ( 'ip -6 route show type unreachable' )
5906 self
. assertRegex ( output
, 'unreachable 2001:db8:6464:[0-9a-f]+00::/56 dev lo proto dhcp' )
5908 print ( '### ip -6 route show dev veth99' )
5909 output
= check_output ( 'ip -6 route show dev veth99' )
5911 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+10::/64 proto kernel metric [0-9]* expires' )
5913 print ( '### ip -6 route show dev test1' )
5914 output
= check_output ( 'ip -6 route show dev test1' )
5916 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
5918 print ( '### ip -6 route show dev dummy98' )
5919 output
= check_output ( 'ip -6 route show dev dummy98' )
5921 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
5923 print ( '### ip -6 route show dev dummy99' )
5924 output
= check_output ( 'ip -6 route show dev dummy99' )
5926 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto dhcp metric [0-9]* expires' )
5928 print ( '### ip -6 route show dev veth97' )
5929 output
= check_output ( 'ip -6 route show dev veth97' )
5931 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto kernel metric [0-9]* expires' )
5933 print ( '### ip -6 route show dev veth97-peer' )
5934 output
= check_output ( 'ip -6 route show dev veth97-peer' )
5936 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto ra metric [0-9]* expires' )
5938 print ( '### ip -6 route show dev veth98' )
5939 output
= check_output ( 'ip -6 route show dev veth98' )
5941 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto kernel metric [0-9]* expires' )
5943 print ( '### ip -6 route show dev veth98-peer' )
5944 output
= check_output ( 'ip -6 route show dev veth98-peer' )
5946 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto ra metric [0-9]* expires' )
5948 print ( '### ip -6 address show dev dummy97 scope global' )
5949 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
5951 # address in IA_PD (Token=static)
5952 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5953 # address in IA_PD (temporary)
5954 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' )
5956 print ( '### ip -6 route show dev dummy97' )
5957 output
= check_output ( 'ip -6 route show dev dummy97' )
5959 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+01::/64 proto kernel metric [0-9]* expires' )
5961 print ( f
'### ip -d link show dev {tunnel_name} ' )
5962 output
= check_output ( f
'ip -d link show dev {tunnel_name} ' )
5964 self
. assertIn ( 'link/sit 10.100.100.' , output
)
5965 self
. assertIn ( 'local 10.100.100.' , output
)
5966 self
. assertIn ( 'ttl 64' , output
)
5967 self
. assertIn ( '6rd-prefix 2001:db8::/32' , output
)
5968 self
. assertIn ( '6rd-relay_prefix 10.0.0.0/8' , output
)
5970 print ( f
'### ip -6 address show dev {tunnel_name} ' )
5971 output
= check_output ( f
'ip -6 address show dev {tunnel_name} ' )
5973 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' )
5974 self
. assertRegex ( output
, 'inet6 ::10.100.100.[0-9]+/96 scope global' )
5976 print ( f
'### ip -6 route show dev {tunnel_name} ' )
5977 output
= check_output ( f
'ip -6 route show dev {tunnel_name} ' )
5979 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto kernel metric [0-9]* expires' )
5980 self
. assertRegex ( output
, '::/96 proto kernel metric [0-9]*' )
5982 print ( '### ip -6 route show default' )
5983 output
= check_output ( 'ip -6 route show default' )
5985 self
. assertIn ( 'default' , output
)
5986 self
. assertIn ( f
'via ::10.0.0.1 dev {tunnel_name} ' , output
)
5988 def test_dhcp4_6rd ( self
):
5989 copy_network_unit ( '25-veth.netdev' , '25-dhcp4-6rd-server.network' , '25-dhcp4-6rd-upstream.network' ,
5990 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
5991 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
5992 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
5993 '25-dhcp-pd-downstream-dummy97.network' ,
5994 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
5995 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' ,
5996 '80-6rd-tunnel.network' )
5999 self
. wait_online ([ 'veth-peer:routable' ])
6002 # 6rd-prefix: 2001:db8::/32
6003 # br-addresss: 10.0.0.1
6005 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' ,
6006 ipv4_range
= '10.100.100.100,10.100.100.200' ,
6007 ipv4_router
= '10.0.0.1' )
6008 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
6009 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
6011 # Test case for a downstream which appears later
6012 check_output ( 'ip link add dummy97 type dummy' )
6013 self
. wait_online ([ 'dummy97:routable' ])
6017 for name
in os
. listdir ( '/sys/class/net/' ):
6018 if name
. startswith ( '6rd-' ):
6022 self
. wait_online ([ f
' {tunnel_name} :routable' ])
6024 self
. verify_dhcp4_6rd ( tunnel_name
)
6026 # Test case for reconfigure
6027 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
6028 self
. wait_online ([ 'dummy98:routable' , 'dummy99:degraded' ])
6030 self
. verify_dhcp4_6rd ( tunnel_name
)
6032 print ( 'Wait for the DHCP lease to be renewed/rebind' )
6035 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy97:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
6036 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
6038 self
. verify_dhcp4_6rd ( tunnel_name
)
6040 class NetworkdIPv6PrefixTests ( unittest
. TestCase
, Utilities
):
6048 def test_ipv6_route_prefix ( self
):
6049 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client.network' , '25-ipv6ra-prefix.network' ,
6050 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
6053 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
6055 output
= check_output ( 'ip address show dev veth-peer' )
6057 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
6058 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
6059 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
6061 output
= check_output ( 'ip -6 route show dev veth-peer' )
6063 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
6064 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
6065 self
. assertNotIn ( '2001:db8:0:3::/64 proto ra' , output
)
6066 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
6067 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
6068 self
. assertNotIn ( '2001:db2:fff::/64 via ' , output
)
6070 output
= check_output ( 'ip address show dev veth99' )
6072 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
6073 self
. assertIn ( 'inet6 2001:db8:0:2:1a:2b:3c:4d' , output
)
6074 self
. assertIn ( 'inet6 2001:db8:0:2:fa:de:ca:fe' , output
)
6075 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
6077 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth-peer' , env
= env
)
6079 self
. assertRegex ( output
, '2001:db8:1:1::2' )
6081 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth-peer' , env
= env
)
6083 self
. assertIn ( 'example.com' , output
)
6085 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
6088 def test_ipv6_route_prefix_deny_list ( self
):
6089 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client-deny-list.network' , '25-ipv6ra-prefix.network' ,
6090 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
6093 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
6095 output
= check_output ( 'ip address show dev veth-peer' )
6097 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
6098 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
6100 output
= check_output ( 'ip -6 route show dev veth-peer' )
6102 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
6103 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
6104 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
6105 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
6107 output
= check_output ( 'ip address show dev veth99' )
6109 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
6110 self
. assertIn ( 'inet6 2001:db8:0:2:' , output
)
6112 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth-peer' , env
= env
)
6114 self
. assertRegex ( output
, '2001:db8:1:1::2' )
6116 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth-peer' , env
= env
)
6118 self
. assertIn ( 'example.com' , output
)
6120 class NetworkdMTUTests ( unittest
. TestCase
, Utilities
):
6128 def check_mtu ( self
, mtu
, ipv6_mtu
= None , reset
= True ):
6134 self
. wait_online ([ 'dummy98:routable' ])
6135 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
6136 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
6138 # test normal restart
6140 self
. wait_online ([ 'dummy98:routable' ])
6141 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
6142 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
6145 self
. reset_check_mtu ( mtu
, ipv6_mtu
)
6147 def reset_check_mtu ( self
, mtu
, ipv6_mtu
= None ):
6148 ''' test setting mtu/ipv6_mtu with interface already up '''
6151 # note - changing the device mtu resets the ipv6 mtu
6152 check_output ( 'ip link set up mtu 1501 dev dummy98' )
6153 check_output ( 'ip link set up mtu 1500 dev dummy98' )
6154 self
. check_link_attr ( 'dummy98' , 'mtu' , '1500' )
6155 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , '1500' )
6157 self
. check_mtu ( mtu
, ipv6_mtu
, reset
= False )
6159 def test_mtu_network ( self
):
6160 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' )
6161 self
. check_mtu ( '1600' )
6163 def test_mtu_netdev ( self
):
6164 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network' , copy_dropins
= False )
6165 # note - MTU set by .netdev happens ONLY at device creation!
6166 self
. check_mtu ( '1600' , reset
= False )
6168 def test_mtu_link ( self
):
6169 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network' , copy_dropins
= False )
6170 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
6171 self
. check_mtu ( '1600' , reset
= False )
6173 def test_ipv6_mtu ( self
):
6174 ''' set ipv6 mtu without setting device mtu '''
6175 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1400.conf' )
6176 self
. check_mtu ( '1500' , '1400' )
6178 def test_ipv6_mtu_toolarge ( self
):
6179 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
6180 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
6181 self
. check_mtu ( '1500' , '1500' )
6183 def test_mtu_network_ipv6_mtu ( self
):
6184 ''' set ipv6 mtu and set device mtu via network file '''
6185 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
6186 self
. check_mtu ( '1600' , '1550' )
6188 def test_mtu_netdev_ipv6_mtu ( self
):
6189 ''' set ipv6 mtu and set device mtu via netdev file '''
6190 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
6191 self
. check_mtu ( '1600' , '1550' , reset
= False )
6193 def test_mtu_link_ipv6_mtu ( self
):
6194 ''' set ipv6 mtu and set device mtu via link file '''
6195 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
6196 self
. check_mtu ( '1600' , '1550' , reset
= False )
6199 if __name__
== '__main__' :
6200 parser
= argparse
. ArgumentParser ()
6201 parser
. add_argument ( '--build-dir' , help = 'Path to build dir' , dest
= 'build_dir' )
6202 parser
. add_argument ( '--networkd' , help = 'Path to systemd-networkd' , dest
= 'networkd_bin' )
6203 parser
. add_argument ( '--resolved' , help = 'Path to systemd-resolved' , dest
= 'resolved_bin' )
6204 parser
. add_argument ( '--timesyncd' , help = 'Path to systemd-timesyncd' , dest
= 'timesyncd_bin' )
6205 parser
. add_argument ( '--udevd' , help = 'Path to systemd-udevd' , dest
= 'udevd_bin' )
6206 parser
. add_argument ( '--wait-online' , help = 'Path to systemd-networkd-wait-online' , dest
= 'wait_online_bin' )
6207 parser
. add_argument ( '--networkctl' , help = 'Path to networkctl' , dest
= 'networkctl_bin' )
6208 parser
. add_argument ( '--resolvectl' , help = 'Path to resolvectl' , dest
= 'resolvectl_bin' )
6209 parser
. add_argument ( '--timedatectl' , help = 'Path to timedatectl' , dest
= 'timedatectl_bin' )
6210 parser
. add_argument ( '--udevadm' , help = 'Path to udevadm' , dest
= 'udevadm_bin' )
6211 parser
. add_argument ( '--valgrind' , help = 'Enable valgrind' , dest
= 'use_valgrind' , type = bool , nargs
= '?' , const
= True , default
= use_valgrind
)
6212 parser
. add_argument ( '--debug' , help = 'Generate debugging logs' , dest
= 'enable_debug' , type = bool , nargs
= '?' , const
= True , default
= enable_debug
)
6213 parser
. add_argument ( '--asan-options' , help = 'ASAN options' , dest
= 'asan_options' )
6214 parser
. add_argument ( '--lsan-options' , help = 'LSAN options' , dest
= 'lsan_options' )
6215 parser
. add_argument ( '--ubsan-options' , help = 'UBSAN options' , dest
= 'ubsan_options' )
6216 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
)
6217 ns
, unknown_args
= parser
. parse_known_args ( namespace
= unittest
)
6220 if ns
. networkd_bin
or ns
. resolved_bin
or ns
. timesyncd_bin
or ns
. udevd_bin
or \
6221 ns
. wait_online_bin
or ns
. networkctl_bin
or ns
. resolvectl_bin
or ns
. timedatectl_bin
or ns
. udevadm_bin
:
6222 print ( 'WARNING: --networkd, --resolved, --timesyncd, --udevd, --wait-online, --networkctl, --resolvectl, --timedatectl, or --udevadm options are ignored when --build-dir is specified.' )
6223 networkd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd' )
6224 resolved_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-resolved' )
6225 timesyncd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-timesyncd' )
6226 udevd_bin
= os
. path
. join ( ns
. build_dir
, 'udevadm' )
6227 wait_online_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd-wait-online' )
6228 networkctl_bin
= os
. path
. join ( ns
. build_dir
, 'networkctl' )
6229 resolvectl_bin
= os
. path
. join ( ns
. build_dir
, 'resolvectl' )
6230 timedatectl_bin
= os
. path
. join ( ns
. build_dir
, 'timedatectl' )
6231 udevadm_bin
= os
. path
. join ( ns
. build_dir
, 'udevadm' )
6234 networkd_bin
= ns
. networkd_bin
6236 resolved_bin
= ns
. resolved_bin
6237 if ns
. timesyncd_bin
:
6238 timesyncd_bin
= ns
. timesyncd_bin
6240 udevd_bin
= ns
. udevd_bin
6241 if ns
. wait_online_bin
:
6242 wait_online_bin
= ns
. wait_online_bin
6243 if ns
. networkctl_bin
:
6244 networkctl_bin
= ns
. networkctl_bin
6245 if ns
. resolvectl_bin
:
6246 resolvectl_bin
= ns
. resolvectl_bin
6247 if ns
. timedatectl_bin
:
6248 timedatectl_bin
= ns
. timedatectl_bin
6250 udevadm_bin
= ns
. udevadm_bin
6252 use_valgrind
= ns
. use_valgrind
6253 enable_debug
= ns
. enable_debug
6254 asan_options
= ns
. asan_options
6255 lsan_options
= ns
. lsan_options
6256 ubsan_options
= ns
. ubsan_options
6257 with_coverage
= ns
. with_coverage
6260 # Do not forget the trailing space.
6261 valgrind_cmd
= 'valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all '
6263 networkctl_cmd
= valgrind_cmd
. split () + [ networkctl_bin
]
6264 resolvectl_cmd
= valgrind_cmd
. split () + [ resolvectl_bin
]
6265 timedatectl_cmd
= valgrind_cmd
. split () + [ timedatectl_bin
]
6266 udevadm_cmd
= valgrind_cmd
. split () + [ udevadm_bin
]
6267 wait_online_cmd
= valgrind_cmd
. split () + [ wait_online_bin
]
6270 env
. update ({ 'ASAN_OPTIONS' : asan_options
})
6272 env
. update ({ 'LSAN_OPTIONS' : lsan_options
})
6274 env
. update ({ 'UBSAN_OPTIONS' : ubsan_options
})
6276 env
. update ({ 'SYSTEMD_MEMPOOL' : '0' })
6278 wait_online_env
= env
. copy ()
6280 wait_online_env
. update ({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
6282 sys
. argv
[ 1 :] = unknown_args
6283 unittest
. main ( verbosity
= 3 )