]>
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 def setup_nftset ( self
, filter_name
, filter_type
, flags
= '' ):
948 if not shutil
. which ( 'nft' ):
949 print ( '## Setting up NFT sets skipped: nft command not found.' )
951 if call ( f
'nft add table inet sd_test' ) != 0 :
952 print ( '## Setting up NFT table failed.' )
954 if call ( f
'nft add set inet sd_test {filter_name} {{ type {filter_type} ; {flags} }}' ) != 0 :
955 print ( '## Setting up NFT sets failed.' )
958 def teardown_nftset ( self
, * filters
):
959 if not shutil
. which ( 'nft' ):
960 print ( '## Tearing down NFT sets skipped: nft command not found.' )
962 for filter_name
in filters
:
963 if call ( f
'nft delete set inet sd_test {filter_name} ' ) != 0 :
964 print ( '## Tearing down NFT sets failed.' )
966 if call ( f
'nft delete table inet sd_test' ) != 0 :
967 print ( '## Tearing down NFT table failed.' )
970 def check_nftset ( self
, filter_name
, contents
):
971 if not shutil
. which ( 'nft' ):
972 print ( '## Checking NFT sets skipped: nft command not found.' )
974 output
= check_output ( f
'nft list set inet sd_test {filter_name} ' )
976 self
. assertRegex ( output
, r
'.*elements = { [^}]*' + contents
+ r
'[^}]* }.*' )
978 class NetworkctlTests ( unittest
. TestCase
, Utilities
):
986 @expectedFailureIfAlternativeNameIsNotAvailable ()
987 def test_altname ( self
):
988 copy_network_unit ( '26-netdev-link-local-addressing-yes.network' , '12-dummy.netdev' , '12-dummy.link' )
990 self
. wait_online ([ 'dummy98:degraded' ])
992 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
993 self
. assertRegex ( output
, 'hogehogehogehogehogehoge' )
995 @expectedFailureIfAlternativeNameIsNotAvailable ()
996 def test_rename_to_altname ( self
):
997 copy_network_unit ( '26-netdev-link-local-addressing-yes.network' ,
998 '12-dummy.netdev' , '12-dummy-rename-to-altname.link' )
1000 self
. wait_online ([ 'dummyalt:degraded' ])
1002 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummyalt' , env
= env
)
1003 self
. assertIn ( 'hogehogehogehogehogehoge' , output
)
1004 self
. assertNotIn ( 'dummy98' , output
)
1006 def test_reconfigure ( self
):
1007 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' )
1009 self
. wait_online ([ 'dummy98:routable' ])
1011 output
= check_output ( 'ip -4 address show dev dummy98' )
1013 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
1014 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
1015 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
1017 check_output ( 'ip address del 10.1.2.3/16 dev dummy98' )
1018 check_output ( 'ip address del 10.1.2.4/16 dev dummy98' )
1019 check_output ( 'ip address del 10.2.2.4/16 dev dummy98' )
1021 networkctl_reconfigure ( 'dummy98' )
1022 self
. wait_online ([ 'dummy98:routable' ])
1024 output
= check_output ( 'ip -4 address show dev dummy98' )
1026 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
1027 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
1028 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
1030 remove_network_unit ( '25-address-static.network' )
1033 self
. wait_operstate ( 'dummy98' , 'degraded' , setup_state
= 'unmanaged' )
1035 output
= check_output ( 'ip -4 address show dev dummy98' )
1037 self
. assertNotIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
1038 self
. assertNotIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
1039 self
. assertNotIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
1041 copy_network_unit ( '25-address-static.network' )
1043 self
. wait_online ([ 'dummy98:routable' ])
1045 output
= check_output ( 'ip -4 address show dev dummy98' )
1047 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
1048 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
1049 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
1051 def test_renew ( self
):
1053 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
1054 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
1056 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
1057 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
1058 self
. assertRegex ( output
, 'DNS: 192.168.5.1 \n *192.168.5.10' )
1059 self
. assertRegex ( output
, 'NTP: 192.168.5.1 \n *192.168.5.11' )
1061 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server.network' )
1064 output
= check_output (* networkctl_cmd
, '--lines=0' , '--stats' , '--all' , '--full' , '--json=short' , 'status' )
1067 for verb
in [ 'renew' , 'forcerenew' ]:
1068 call_check (* networkctl_cmd
, verb
, 'veth99' )
1070 call_check (* networkctl_cmd
, verb
, 'veth99' , 'veth99' , 'veth99' )
1073 def test_up_down ( self
):
1074 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' )
1076 self
. wait_online ([ 'dummy98:routable' ])
1078 call_check (* networkctl_cmd
, 'down' , 'dummy98' )
1079 self
. wait_online ([ 'dummy98:off' ])
1080 call_check (* networkctl_cmd
, 'up' , 'dummy98' )
1081 self
. wait_online ([ 'dummy98:routable' ])
1082 call_check (* networkctl_cmd
, 'down' , 'dummy98' , 'dummy98' , 'dummy98' )
1083 self
. wait_online ([ 'dummy98:off' ])
1084 call_check (* networkctl_cmd
, 'up' , 'dummy98' , 'dummy98' , 'dummy98' )
1085 self
. wait_online ([ 'dummy98:routable' ])
1087 def test_reload ( self
):
1090 copy_network_unit ( '11-dummy.netdev' )
1092 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'unmanaged' )
1094 copy_network_unit ( '11-dummy.network' )
1096 self
. wait_online ([ 'test1:degraded' ])
1098 remove_network_unit ( '11-dummy.network' )
1100 self
. wait_operstate ( 'test1' , 'degraded' , setup_state
= 'unmanaged' )
1102 remove_network_unit ( '11-dummy.netdev' )
1104 self
. wait_operstate ( 'test1' , 'degraded' , setup_state
= 'unmanaged' )
1106 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1108 self
. wait_operstate ( 'test1' , 'degraded' )
1110 def test_glob ( self
):
1111 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1114 self
. wait_online ([ 'test1:degraded' ])
1116 output
= check_output (* networkctl_cmd
, 'list' , env
= env
)
1117 self
. assertRegex ( output
, '1 lo ' )
1118 self
. assertRegex ( output
, 'test1' )
1120 output
= check_output (* networkctl_cmd
, 'list' , 'test1' , env
= env
)
1121 self
. assertNotRegex ( output
, '1 lo ' )
1122 self
. assertRegex ( output
, 'test1' )
1124 output
= check_output (* networkctl_cmd
, 'list' , 'te*' , env
= env
)
1125 self
. assertNotRegex ( output
, '1 lo ' )
1126 self
. assertRegex ( output
, 'test1' )
1128 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'te*' , env
= env
)
1129 self
. assertNotRegex ( output
, '1: lo ' )
1130 self
. assertRegex ( output
, 'test1' )
1132 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'tes[a-z][0-9]' , env
= env
)
1133 self
. assertNotRegex ( output
, '1: lo ' )
1134 self
. assertRegex ( output
, 'test1' )
1137 copy_network_unit ( '11-dummy-mtu.netdev' , '11-dummy.network' )
1140 self
. wait_online ([ 'test1:degraded' ])
1142 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
1143 self
. assertRegex ( output
, 'MTU: 1600' )
1145 def test_type ( self
):
1146 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1148 self
. wait_online ([ 'test1:degraded' ])
1150 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
1152 self
. assertRegex ( output
, 'Type: ether' )
1154 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'lo' , env
= env
)
1156 self
. assertRegex ( output
, 'Type: loopback' )
1158 def test_udev_link_file ( self
):
1159 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' , '25-default.link' )
1161 self
. wait_online ([ 'test1:degraded' ])
1163 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
1165 self
. assertRegex ( output
, r
'Link File: /run/systemd/network/25-default.link' )
1166 self
. assertRegex ( output
, r
'Network File: /run/systemd/network/11-dummy.network' )
1168 # This test may be run on the system that has older udevd than 70f32a260b5ebb68c19ecadf5d69b3844896ba55 (v249).
1169 # In that case, the udev DB for the loopback network interface may already have ID_NET_LINK_FILE property.
1170 # Let's reprocess the interface and drop the property.
1171 check_output (* udevadm_cmd
, 'trigger' , '--settle' , '--action=add' , '/sys/class/net/lo' )
1172 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'lo' , env
= env
)
1174 self
. assertRegex ( output
, r
'Link File: n/a' )
1175 self
. assertRegex ( output
, r
'Network File: n/a' )
1177 def test_delete_links ( self
):
1178 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' ,
1179 '25-veth.netdev' , '26-netdev-link-local-addressing-yes.network' )
1182 self
. wait_online ([ 'test1:degraded' , 'veth99:degraded' , 'veth-peer:degraded' ])
1184 check_output (* networkctl_cmd
, 'delete' , 'test1' , 'veth99' , env
= env
)
1185 self
. check_link_exists ( 'test1' , expected
= False )
1186 self
. check_link_exists ( 'veth99' , expected
= False )
1187 self
. check_link_exists ( 'veth-peer' , expected
= False )
1189 def test_label ( self
):
1190 call_check (* networkctl_cmd
, 'label' )
1192 class NetworkdMatchTests ( unittest
. TestCase
, Utilities
):
1200 @expectedFailureIfAlternativeNameIsNotAvailable ()
1201 def test_match ( self
):
1202 copy_network_unit ( '12-dummy-mac.netdev' ,
1203 '12-dummy-match-mac-01.network' ,
1204 '12-dummy-match-mac-02.network' ,
1205 '12-dummy-match-renamed.network' ,
1206 '12-dummy-match-altname.network' ,
1207 '12-dummy-altname.link' )
1210 self
. wait_online ([ 'dummy98:routable' ])
1211 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
1212 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-mac-01.network' , output
)
1213 output
= check_output ( 'ip -4 address show dev dummy98' )
1214 self
. assertIn ( '10.0.0.1/16' , output
)
1216 check_output ( 'ip link set dev dummy98 down' )
1217 check_output ( 'ip link set dev dummy98 address 12:34:56:78:9a:02' )
1219 self
. wait_address ( 'dummy98' , '10.0.0.2/16' , ipv
= '-4' , timeout_sec
= 10 )
1220 self
. wait_online ([ 'dummy98:routable' ])
1221 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
1222 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-mac-02.network' , output
)
1224 check_output ( 'ip link set dev dummy98 down' )
1225 check_output ( 'ip link set dev dummy98 name dummy98-1' )
1227 self
. wait_address ( 'dummy98-1' , '10.0.1.2/16' , ipv
= '-4' , timeout_sec
= 10 )
1228 self
. wait_online ([ 'dummy98-1:routable' ])
1229 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98-1' , env
= env
)
1230 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-renamed.network' , output
)
1232 check_output ( 'ip link set dev dummy98-1 down' )
1233 check_output ( 'ip link set dev dummy98-1 name dummy98-2' )
1234 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '/sys/class/net/dummy98-2' )
1236 self
. wait_address ( 'dummy98-2' , '10.0.2.2/16' , ipv
= '-4' , timeout_sec
= 10 )
1237 self
. wait_online ([ 'dummy98-2:routable' ])
1238 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98-2' , env
= env
)
1239 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-altname.network' , output
)
1241 def test_match_udev_property ( self
):
1242 copy_network_unit ( '12-dummy.netdev' , '13-not-match-udev-property.network' , '14-match-udev-property.network' )
1244 self
. wait_online ([ 'dummy98:routable' ])
1246 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
1248 self
. assertRegex ( output
, 'Network File: /run/systemd/network/14-match-udev-property' )
1250 class WaitOnlineTests ( unittest
. TestCase
, Utilities
):
1258 def test_wait_online_any ( self
):
1259 copy_network_unit ( '25-bridge.netdev' , '25-bridge.network' , '11-dummy.netdev' , '11-dummy.network' )
1262 self
. wait_online ([ 'bridge99' , 'test1:degraded' ], bool_any
= True )
1264 self
. wait_operstate ( 'bridge99' , '(off|no-carrier)' , setup_state
= 'configuring' )
1265 self
. wait_operstate ( 'test1' , 'degraded' )
1267 class NetworkdNetDevTests ( unittest
. TestCase
, Utilities
):
1275 def test_dropin_and_name_conflict ( self
):
1276 copy_network_unit ( '10-dropin-test.netdev' , '15-name-conflict-test.netdev' )
1279 self
. wait_online ([ 'dropin-test:off' ], setup_state
= 'unmanaged' )
1281 output
= check_output ( 'ip link show dropin-test' )
1283 self
. assertRegex ( output
, '00:50:56:c0:00:28' )
1285 @expectedFailureIfModuleIsNotAvailable ( 'bareudp' )
1286 def test_bareudp ( self
):
1287 copy_network_unit ( '25-bareudp.netdev' , '26-netdev-link-local-addressing-yes.network' )
1290 self
. wait_online ([ 'bareudp99:degraded' ])
1292 output
= check_output ( 'ip -d link show bareudp99' )
1294 self
. assertRegex ( output
, 'dstport 1000 ' )
1295 self
. assertRegex ( output
, 'ethertype ip ' )
1297 @expectedFailureIfModuleIsNotAvailable ( 'batman-adv' )
1298 def test_batadv ( self
):
1299 copy_network_unit ( '25-batadv.netdev' , '26-netdev-link-local-addressing-yes.network' )
1302 self
. wait_online ([ 'batadv99:degraded' ])
1304 output
= check_output ( 'ip -d link show batadv99' )
1306 self
. assertRegex ( output
, 'batadv' )
1308 def test_bridge ( self
):
1309 copy_network_unit ( '25-bridge.netdev' , '25-bridge-configure-without-carrier.network' )
1312 self
. wait_online ([ 'bridge99:no-carrier' ])
1314 tick
= os
. sysconf ( 'SC_CLK_TCK' )
1315 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'hello_time' )) / tick
))
1316 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'max_age' )) / tick
))
1317 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'forward_delay' )) / tick
))
1318 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'ageing_time' )) / tick
))
1319 self
. assertEqual ( 9 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'priority' )))
1320 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_querier' )))
1321 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_snooping' )))
1322 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'stp_state' )))
1323 self
. assertEqual ( 3 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_igmp_version' )))
1325 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bridge99' , env
= env
)
1327 self
. assertRegex ( output
, 'Priority: 9' )
1328 self
. assertRegex ( output
, 'STP: yes' )
1329 self
. assertRegex ( output
, 'Multicast IGMP Version: 3' )
1331 output
= check_output ( 'ip -d link show bridge99' )
1333 self
. assertIn ( 'vlan_filtering 1 ' , output
)
1334 self
. assertIn ( 'vlan_protocol 802.1ad ' , output
)
1335 self
. assertIn ( 'vlan_default_pvid 9 ' , output
)
1337 def test_bond ( self
):
1338 copy_network_unit ( '25-bond.netdev' , '25-bond-balanced-tlb.netdev' )
1341 self
. wait_online ([ 'bond99:off' , 'bond98:off' ], setup_state
= 'unmanaged' )
1343 self
. check_link_attr ( 'bond99' , 'bonding' , 'mode' , '802.3ad 4' )
1344 self
. check_link_attr ( 'bond99' , 'bonding' , 'xmit_hash_policy' , 'layer3+4 1' )
1345 self
. check_link_attr ( 'bond99' , 'bonding' , 'miimon' , '1000' )
1346 self
. check_link_attr ( 'bond99' , 'bonding' , 'lacp_rate' , 'fast 1' )
1347 self
. check_link_attr ( 'bond99' , 'bonding' , 'updelay' , '2000' )
1348 self
. check_link_attr ( 'bond99' , 'bonding' , 'downdelay' , '2000' )
1349 self
. check_link_attr ( 'bond99' , 'bonding' , 'resend_igmp' , '4' )
1350 self
. check_link_attr ( 'bond99' , 'bonding' , 'min_links' , '1' )
1351 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_actor_sys_prio' , '1218' )
1352 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_user_port_key' , '811' )
1353 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_actor_system' , '00:11:22:33:44:55' )
1355 self
. check_link_attr ( 'bond98' , 'bonding' , 'mode' , 'balance-tlb 5' )
1356 self
. check_link_attr ( 'bond98' , 'bonding' , 'tlb_dynamic_lb' , '1' )
1358 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bond99' , env
= env
)
1360 self
. assertIn ( 'Mode: 802.3ad' , output
)
1361 self
. assertIn ( 'Miimon: 1s' , output
)
1362 self
. assertIn ( 'Updelay: 2s' , output
)
1363 self
. assertIn ( 'Downdelay: 2s' , output
)
1365 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bond98' , env
= env
)
1367 self
. assertIn ( 'Mode: balance-tlb' , output
)
1369 def test_vlan ( self
):
1370 copy_network_unit ( '21-vlan.netdev' , '11-dummy.netdev' ,
1371 '21-vlan.network' , '21-vlan-test1.network' )
1374 self
. wait_online ([ 'test1:degraded' , 'vlan99:routable' ])
1376 output
= check_output ( 'ip -d link show test1' )
1378 self
. assertRegex ( output
, ' mtu 2000 ' )
1380 output
= check_output ( 'ip -d link show vlan99' )
1382 self
. assertIn ( ' mtu 2000 ' , output
)
1383 self
. assertIn ( 'REORDER_HDR' , output
)
1384 self
. assertIn ( 'LOOSE_BINDING' , output
)
1385 self
. assertIn ( 'GVRP' , output
)
1386 self
. assertIn ( 'MVRP' , output
)
1387 self
. assertIn ( ' id 99 ' , output
)
1388 self
. assertIn ( 'ingress-qos-map { 4:100 7:13 }' , output
)
1389 self
. assertIn ( 'egress-qos-map { 0:1 1:3 6:6 7:7 10:3 }' , output
)
1391 output
= check_output ( 'ip -4 address show dev test1' )
1393 self
. assertRegex ( output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1' )
1394 self
. assertRegex ( output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1' )
1396 output
= check_output ( 'ip -4 address show dev vlan99' )
1398 self
. assertRegex ( output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99' )
1400 def test_vlan_on_bond ( self
):
1401 # For issue #24377 (https://github.com/systemd/systemd/issues/24377),
1402 # which is fixed by b05e52000b4eee764b383cc3031da0a3739e996e (PR#24020).
1404 copy_network_unit ( '21-bond-802.3ad.netdev' , '21-bond-802.3ad.network' ,
1405 '21-vlan-on-bond.netdev' , '21-vlan-on-bond.network' )
1407 self
. wait_online ([ 'bond99:off' ])
1408 self
. wait_operstate ( 'vlan99' , operstate
= 'off' , setup_state
= 'configuring' , setup_timeout
= 10 )
1410 # The commit b05e52000b4eee764b383cc3031da0a3739e996e adds ", ignoring". To make it easily confirmed
1411 # that the issue is fixed by the commit, let's allow to match both string.
1412 log_re
= re
. compile ( 'vlan99: Could not bring up interface(, ignoring|): Network is down$' , re
. MULTILINE
)
1416 if log_re
. search ( read_networkd_log ()):
1421 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '21-dummy-bond-slave.network' )
1423 self
. wait_online ([ 'test1:enslaved' , 'dummy98:enslaved' , 'bond99:carrier' , 'vlan99:routable' ])
1425 def test_macvtap ( self
):
1427 for mode
in [ 'private' , 'vepa' , 'bridge' , 'passthru' ]:
1433 print ( f
'### test_macvtap(mode= {mode} )' )
1434 with self
. subTest ( mode
= mode
):
1435 copy_network_unit ( '21-macvtap.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1436 '11-dummy.netdev' , '25-macvtap.network' )
1437 with
open ( os
. path
. join ( network_unit_dir
, '21-macvtap.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1438 f
. write ( '[MACVTAP] \n Mode=' + mode
)
1441 self
. wait_online ([ 'macvtap99:degraded' ,
1442 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1444 output
= check_output ( 'ip -d link show macvtap99' )
1446 self
. assertRegex ( output
, 'macvtap mode ' + mode
+ ' ' )
1448 def test_macvlan ( self
):
1450 for mode
in [ 'private' , 'vepa' , 'bridge' , 'passthru' ]:
1456 print ( f
'### test_macvlan(mode= {mode} )' )
1457 with self
. subTest ( mode
= mode
):
1458 copy_network_unit ( '21-macvlan.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1459 '11-dummy.netdev' , '25-macvlan.network' )
1460 with
open ( os
. path
. join ( network_unit_dir
, '21-macvlan.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1461 f
. write ( '[MACVLAN] \n Mode=' + mode
)
1464 self
. wait_online ([ 'macvlan99:degraded' ,
1465 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1467 output
= check_output ( 'ip -d link show test1' )
1469 self
. assertRegex ( output
, ' mtu 2000 ' )
1471 output
= check_output ( 'ip -d link show macvlan99' )
1473 self
. assertRegex ( output
, ' mtu 2000 ' )
1474 self
. assertRegex ( output
, 'macvlan mode ' + mode
+ ' ' )
1476 remove_link ( 'test1' )
1479 check_output ( "ip link add test1 type dummy" )
1480 self
. wait_online ([ 'macvlan99:degraded' ,
1481 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1483 output
= check_output ( 'ip -d link show test1' )
1485 self
. assertRegex ( output
, ' mtu 2000 ' )
1487 output
= check_output ( 'ip -d link show macvlan99' )
1489 self
. assertRegex ( output
, ' mtu 2000 ' )
1490 self
. assertRegex ( output
, 'macvlan mode ' + mode
+ ' ' )
1492 @expectedFailureIfModuleIsNotAvailable ( 'ipvlan' )
1493 def test_ipvlan ( self
):
1495 for mode
, flag
in [[ 'L2' , 'private' ], [ 'L3' , 'vepa' ], [ 'L3S' , 'bridge' ]]:
1501 print ( f
'### test_ipvlan(mode= {mode} , flag= {flag} )' )
1502 with self
. subTest ( mode
= mode
, flag
= flag
):
1503 copy_network_unit ( '25-ipvlan.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1504 '11-dummy.netdev' , '25-ipvlan.network' )
1505 with
open ( os
. path
. join ( network_unit_dir
, '25-ipvlan.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1506 f
. write ( '[IPVLAN] \n Mode=' + mode
+ ' \n Flags=' + flag
)
1509 self
. wait_online ([ 'ipvlan99:degraded' , 'test1:degraded' ])
1511 output
= check_output ( 'ip -d link show ipvlan99' )
1513 self
. assertRegex ( output
, 'ipvlan *mode ' + mode
. lower () + ' ' + flag
)
1515 @expectedFailureIfModuleIsNotAvailable ( 'ipvtap' )
1516 def test_ipvtap ( self
):
1518 for mode
, flag
in [[ 'L2' , 'private' ], [ 'L3' , 'vepa' ], [ 'L3S' , 'bridge' ]]:
1524 print ( f
'### test_ipvtap(mode= {mode} , flag= {flag} )' )
1525 with self
. subTest ( mode
= mode
, flag
= flag
):
1526 copy_network_unit ( '25-ipvtap.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1527 '11-dummy.netdev' , '25-ipvtap.network' )
1528 with
open ( os
. path
. join ( network_unit_dir
, '25-ipvtap.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1529 f
. write ( '[IPVTAP] \n Mode=' + mode
+ ' \n Flags=' + flag
)
1532 self
. wait_online ([ 'ipvtap99:degraded' , 'test1:degraded' ])
1534 output
= check_output ( 'ip -d link show ipvtap99' )
1536 self
. assertRegex ( output
, 'ipvtap *mode ' + mode
. lower () + ' ' + flag
)
1538 def test_veth ( self
):
1539 copy_network_unit ( '25-veth.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1540 '25-veth-mtu.netdev' )
1543 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:degraded' , 'veth-mtu:degraded' , 'veth-mtu-peer:degraded' ])
1545 output
= check_output ( 'ip -d link show veth99' )
1547 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bc' )
1548 output
= check_output ( 'ip -d link show veth-peer' )
1550 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bd' )
1552 output
= check_output ( 'ip -d link show veth-mtu' )
1554 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:be' )
1555 self
. assertRegex ( output
, 'mtu 1800' )
1556 output
= check_output ( 'ip -d link show veth-mtu-peer' )
1558 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bf' )
1559 self
. assertRegex ( output
, 'mtu 1800' )
1561 def test_tuntap ( self
):
1562 copy_network_unit ( '25-tun.netdev' , '25-tap.netdev' , '26-netdev-link-local-addressing-yes.network' )
1565 self
. wait_online ([ 'testtun99:degraded' , 'testtap99:degraded' ])
1567 pid
= networkd_pid ()
1568 name
= psutil
. Process ( pid
). name ()[: 15 ]
1570 output
= check_output ( 'ip -d tuntap show' )
1572 self
. assertRegex ( output
, fr
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1573 self
. assertRegex ( output
, fr
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1575 output
= check_output ( 'ip -d link show testtun99' )
1577 # Old ip command does not support IFF_ flags
1578 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1579 self
. assertIn ( 'UP,LOWER_UP' , output
)
1581 output
= check_output ( 'ip -d link show testtap99' )
1583 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1584 self
. assertIn ( 'UP,LOWER_UP' , output
)
1586 remove_network_unit ( '26-netdev-link-local-addressing-yes.network' )
1589 self
. wait_online ([ 'testtun99:degraded' , 'testtap99:degraded' ], setup_state
= 'unmanaged' )
1591 pid
= networkd_pid ()
1592 name
= psutil
. Process ( pid
). name ()[: 15 ]
1594 output
= check_output ( 'ip -d tuntap show' )
1596 self
. assertRegex ( output
, fr
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1597 self
. assertRegex ( output
, fr
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1599 output
= check_output ( 'ip -d link show testtun99' )
1601 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1602 self
. assertIn ( 'UP,LOWER_UP' , output
)
1604 output
= check_output ( 'ip -d link show testtap99' )
1606 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1607 self
. assertIn ( 'UP,LOWER_UP' , output
)
1609 clear_network_units ()
1611 self
. wait_online ([ 'testtun99:off' , 'testtap99:off' ], setup_state
= 'unmanaged' )
1613 output
= check_output ( 'ip -d tuntap show' )
1615 self
. assertRegex ( output
, r
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$' )
1616 self
. assertRegex ( output
, r
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$' )
1621 output
= check_output ( 'ip -d link show testtun99' )
1623 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1624 if 'NO-CARRIER' in output
:
1632 output
= check_output ( 'ip -d link show testtap99' )
1634 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1635 if 'NO-CARRIER' in output
:
1640 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
1642 copy_network_unit ( '25-vrf.netdev' , '26-netdev-link-local-addressing-yes.network' )
1645 self
. wait_online ([ 'vrf99:carrier' ])
1647 @expectedFailureIfModuleIsNotAvailable ( 'vcan' )
1648 def test_vcan ( self
):
1649 copy_network_unit ( '25-vcan.netdev' , '26-netdev-link-local-addressing-yes.network' )
1652 self
. wait_online ([ 'vcan99:carrier' ])
1654 @expectedFailureIfModuleIsNotAvailable ( 'vxcan' )
1655 def test_vxcan ( self
):
1656 copy_network_unit ( '25-vxcan.netdev' , '26-netdev-link-local-addressing-yes.network' )
1659 self
. wait_online ([ 'vxcan99:carrier' , 'vxcan-peer:carrier' ])
1661 @expectedFailureIfModuleIsNotAvailable ( 'wireguard' )
1662 def test_wireguard ( self
):
1663 copy_network_unit ( '25-wireguard.netdev' , '25-wireguard.network' ,
1664 '25-wireguard-23-peers.netdev' , '25-wireguard-23-peers.network' ,
1665 '25-wireguard-preshared-key.txt' , '25-wireguard-private-key.txt' ,
1666 '25-wireguard-no-peer.netdev' , '25-wireguard-no-peer.network' )
1668 self
. wait_online ([ 'wg99:routable' , 'wg98:routable' , 'wg97:carrier' ])
1670 output
= check_output ( 'ip -4 address show dev wg99' )
1672 self
. assertIn ( 'inet 192.168.124.1/24 scope global wg99' , output
)
1674 output
= check_output ( 'ip -4 address show dev wg99' )
1676 self
. assertIn ( 'inet 169.254.11.1/24 scope link wg99' , output
)
1678 output
= check_output ( 'ip -6 address show dev wg99' )
1680 self
. assertIn ( 'inet6 fe80::1/64 scope link' , output
)
1682 output
= check_output ( 'ip -4 address show dev wg98' )
1684 self
. assertIn ( 'inet 192.168.123.123/24 scope global wg98' , output
)
1686 output
= check_output ( 'ip -6 address show dev wg98' )
1688 self
. assertIn ( 'inet6 fd8d:4d6d:3ccb:500::1/64 scope global' , output
)
1690 output
= check_output ( 'ip -4 route show dev wg99 table 1234' )
1692 self
. assertIn ( '192.168.26.0/24 proto static metric 123' , output
)
1694 output
= check_output ( 'ip -6 route show dev wg99 table 1234' )
1696 self
. assertIn ( 'fd31:bf08:57cb::/48 proto static metric 123 pref medium' , output
)
1698 output
= check_output ( 'ip -6 route show dev wg98 table 1234' )
1700 self
. assertIn ( 'fd8d:4d6d:3ccb:500:c79:2339:edce:ece1 proto static metric 123 pref medium' , output
)
1701 self
. assertIn ( 'fd8d:4d6d:3ccb:500:1dbf:ca8a:32d3:dd81 proto static metric 123 pref medium' , output
)
1702 self
. assertIn ( 'fd8d:4d6d:3ccb:500:1e54:1415:35d0:a47c proto static metric 123 pref medium' , output
)
1703 self
. assertIn ( 'fd8d:4d6d:3ccb:500:270d:b5dd:4a3f:8909 proto static metric 123 pref medium' , output
)
1704 self
. assertIn ( 'fd8d:4d6d:3ccb:500:5660:679d:3532:94d8 proto static metric 123 pref medium' , output
)
1705 self
. assertIn ( 'fd8d:4d6d:3ccb:500:6825:573f:30f3:9472 proto static metric 123 pref medium' , output
)
1706 self
. assertIn ( 'fd8d:4d6d:3ccb:500:6f2e:6888:c6fd:dfb9 proto static metric 123 pref medium' , output
)
1707 self
. assertIn ( 'fd8d:4d6d:3ccb:500:8d4d:bab:7280:a09a proto static metric 123 pref medium' , output
)
1708 self
. assertIn ( 'fd8d:4d6d:3ccb:500:900c:d437:ec27:8822 proto static metric 123 pref medium' , output
)
1709 self
. assertIn ( 'fd8d:4d6d:3ccb:500:9742:9931:5217:18d5 proto static metric 123 pref medium' , output
)
1710 self
. assertIn ( 'fd8d:4d6d:3ccb:500:9c11:d820:2e96:9be0 proto static metric 123 pref medium' , output
)
1711 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a072:80da:de4f:add1 proto static metric 123 pref medium' , output
)
1712 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a3f3:df38:19b0:721 proto static metric 123 pref medium' , output
)
1713 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a94b:cd6a:a32d:90e6 proto static metric 123 pref medium' , output
)
1714 self
. assertIn ( 'fd8d:4d6d:3ccb:500:b39c:9cdc:755a:ead3 proto static metric 123 pref medium' , output
)
1715 self
. assertIn ( 'fd8d:4d6d:3ccb:500:b684:4f81:2e3e:132e proto static metric 123 pref medium' , output
)
1716 self
. assertIn ( 'fd8d:4d6d:3ccb:500:bad5:495d:8e9c:3427 proto static metric 123 pref medium' , output
)
1717 self
. assertIn ( 'fd8d:4d6d:3ccb:500:bfe5:c3c3:5d77:fcb proto static metric 123 pref medium' , output
)
1718 self
. assertIn ( 'fd8d:4d6d:3ccb:500:c624:6bf7:4c09:3b59 proto static metric 123 pref medium' , output
)
1719 self
. assertIn ( 'fd8d:4d6d:3ccb:500:d4f9:5dc:9296:a1a proto static metric 123 pref medium' , output
)
1720 self
. assertIn ( 'fd8d:4d6d:3ccb:500:dcdd:d33b:90c9:6088 proto static metric 123 pref medium' , output
)
1721 self
. assertIn ( 'fd8d:4d6d:3ccb:500:e2e1:ae15:103f:f376 proto static metric 123 pref medium' , output
)
1722 self
. assertIn ( 'fd8d:4d6d:3ccb:500:f349:c4f0:10c1:6b4 proto static metric 123 pref medium' , output
)
1723 self
. assertIn ( 'fd8d:4d6d:3ccb:c79:2339:edce::/96 proto static metric 123 pref medium' , output
)
1724 self
. assertIn ( 'fd8d:4d6d:3ccb:1dbf:ca8a:32d3::/96 proto static metric 123 pref medium' , output
)
1725 self
. assertIn ( 'fd8d:4d6d:3ccb:1e54:1415:35d0::/96 proto static metric 123 pref medium' , output
)
1726 self
. assertIn ( 'fd8d:4d6d:3ccb:270d:b5dd:4a3f::/96 proto static metric 123 pref medium' , output
)
1727 self
. assertIn ( 'fd8d:4d6d:3ccb:5660:679d:3532::/96 proto static metric 123 pref medium' , output
)
1728 self
. assertIn ( 'fd8d:4d6d:3ccb:6825:573f:30f3::/96 proto static metric 123 pref medium' , output
)
1729 self
. assertIn ( 'fd8d:4d6d:3ccb:6f2e:6888:c6fd::/96 proto static metric 123 pref medium' , output
)
1730 self
. assertIn ( 'fd8d:4d6d:3ccb:8d4d:bab:7280::/96 proto static metric 123 pref medium' , output
)
1731 self
. assertIn ( 'fd8d:4d6d:3ccb:900c:d437:ec27::/96 proto static metric 123 pref medium' , output
)
1732 self
. assertIn ( 'fd8d:4d6d:3ccb:9742:9931:5217::/96 proto static metric 123 pref medium' , output
)
1733 self
. assertIn ( 'fd8d:4d6d:3ccb:9c11:d820:2e96::/96 proto static metric 123 pref medium' , output
)
1734 self
. assertIn ( 'fd8d:4d6d:3ccb:a072:80da:de4f::/96 proto static metric 123 pref medium' , output
)
1735 self
. assertIn ( 'fd8d:4d6d:3ccb:a3f3:df38:19b0::/96 proto static metric 123 pref medium' , output
)
1736 self
. assertIn ( 'fd8d:4d6d:3ccb:a94b:cd6a:a32d::/96 proto static metric 123 pref medium' , output
)
1737 self
. assertIn ( 'fd8d:4d6d:3ccb:b39c:9cdc:755a::/96 proto static metric 123 pref medium' , output
)
1738 self
. assertIn ( 'fd8d:4d6d:3ccb:b684:4f81:2e3e::/96 proto static metric 123 pref medium' , output
)
1739 self
. assertIn ( 'fd8d:4d6d:3ccb:bad5:495d:8e9c::/96 proto static metric 123 pref medium' , output
)
1740 self
. assertIn ( 'fd8d:4d6d:3ccb:bfe5:c3c3:5d77::/96 proto static metric 123 pref medium' , output
)
1741 self
. assertIn ( 'fd8d:4d6d:3ccb:c624:6bf7:4c09::/96 proto static metric 123 pref medium' , output
)
1742 self
. assertIn ( 'fd8d:4d6d:3ccb:d4f9:5dc:9296::/96 proto static metric 123 pref medium' , output
)
1743 self
. assertIn ( 'fd8d:4d6d:3ccb:dcdd:d33b:90c9::/96 proto static metric 123 pref medium' , output
)
1744 self
. assertIn ( 'fd8d:4d6d:3ccb:e2e1:ae15:103f::/96 proto static metric 123 pref medium' , output
)
1745 self
. assertIn ( 'fd8d:4d6d:3ccb:f349:c4f0:10c1::/96 proto static metric 123 pref medium' , output
)
1747 if shutil
. which ( 'wg' ):
1750 output
= check_output ( 'wg show wg99 listen-port' )
1751 self
. assertEqual ( output
, '51820' )
1752 output
= check_output ( 'wg show wg99 fwmark' )
1753 self
. assertEqual ( output
, '0x4d2' )
1754 output
= check_output ( 'wg show wg99 private-key' )
1755 self
. assertEqual ( output
, 'EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=' )
1756 output
= check_output ( 'wg show wg99 allowed-ips' )
1757 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t 192.168.124.3/32' , output
)
1758 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t 192.168.124.2/32' , output
)
1759 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t fdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128' , output
)
1760 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 192.168.26.0/24 fd31:bf08:57cb::/48' , output
)
1761 output
= check_output ( 'wg show wg99 persistent-keepalive' )
1762 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t off' , output
)
1763 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t off' , output
)
1764 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t off' , output
)
1765 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 20' , output
)
1766 output
= check_output ( 'wg show wg99 endpoints' )
1767 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t (none)' , output
)
1768 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t (none)' , output
)
1769 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t (none)' , output
)
1770 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 192.168.27.3:51820' , output
)
1771 output
= check_output ( 'wg show wg99 preshared-keys' )
1772 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t 6Fsg8XN0DE6aPQgAX4r2oazEYJOGqyHUz3QRH/jCB+I=' , output
)
1773 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t it7nd33chCT/tKT2ZZWfYyp43Zs+6oif72hexnSNMqA=' , output
)
1774 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=' , output
)
1775 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=' , output
)
1777 output
= check_output ( 'wg show wg98 private-key' )
1778 self
. assertEqual ( output
, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr+WHtZLZ90FU=' )
1780 output
= check_output ( 'wg show wg97 listen-port' )
1781 self
. assertEqual ( output
, '51821' )
1782 output
= check_output ( 'wg show wg97 fwmark' )
1783 self
. assertEqual ( output
, '0x4d3' )
1785 def test_geneve ( self
):
1786 copy_network_unit ( '25-geneve.netdev' , '26-netdev-link-local-addressing-yes.network' )
1789 self
. wait_online ([ 'geneve99:degraded' ])
1791 output
= check_output ( 'ip -d link show geneve99' )
1793 self
. assertRegex ( output
, '192.168.22.1' )
1794 self
. assertRegex ( output
, '6082' )
1795 self
. assertRegex ( output
, 'udpcsum' )
1796 self
. assertRegex ( output
, 'udp6zerocsumrx' )
1798 def test_ipip_tunnel ( self
):
1799 copy_network_unit ( '12-dummy.netdev' , '25-ipip.network' ,
1800 '25-ipip-tunnel.netdev' , '25-tunnel.network' ,
1801 '25-ipip-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1802 '25-ipip-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1803 '25-ipip-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1805 self
. wait_online ([ 'ipiptun99:routable' , 'ipiptun98:routable' , 'ipiptun97:routable' , 'ipiptun96:routable' , 'dummy98:degraded' ])
1807 output
= check_output ( 'ip -d link show ipiptun99' )
1809 self
. assertRegex ( output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98' )
1810 output
= check_output ( 'ip -d link show ipiptun98' )
1812 self
. assertRegex ( output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98' )
1813 output
= check_output ( 'ip -d link show ipiptun97' )
1815 self
. assertRegex ( output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98' )
1816 output
= check_output ( 'ip -d link show ipiptun96' )
1818 self
. assertRegex ( output
, 'ipip (ipip )?remote any local any dev dummy98' )
1820 def test_gre_tunnel ( self
):
1821 copy_network_unit ( '12-dummy.netdev' , '25-gretun.network' ,
1822 '25-gre-tunnel.netdev' , '25-tunnel.network' ,
1823 '25-gre-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1824 '25-gre-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1825 '25-gre-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1827 self
. wait_online ([ 'gretun99:routable' , 'gretun98:routable' , 'gretun97:routable' , 'gretun96:routable' , 'dummy98:degraded' ])
1829 output
= check_output ( 'ip -d link show gretun99' )
1831 self
. assertRegex ( output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1832 self
. assertRegex ( output
, 'ikey 1.2.3.103' )
1833 self
. assertRegex ( output
, 'okey 1.2.4.103' )
1834 self
. assertRegex ( output
, 'iseq' )
1835 self
. assertRegex ( output
, 'oseq' )
1836 output
= check_output ( 'ip -d link show gretun98' )
1838 self
. assertRegex ( output
, 'gre remote 10.65.223.239 local any dev dummy98' )
1839 self
. assertRegex ( output
, 'ikey 0.0.0.104' )
1840 self
. assertRegex ( output
, 'okey 0.0.0.104' )
1841 self
. assertNotRegex ( output
, 'iseq' )
1842 self
. assertNotRegex ( output
, 'oseq' )
1843 output
= check_output ( 'ip -d link show gretun97' )
1845 self
. assertRegex ( output
, 'gre remote any local 10.65.223.238 dev dummy98' )
1846 self
. assertRegex ( output
, 'ikey 0.0.0.105' )
1847 self
. assertRegex ( output
, 'okey 0.0.0.105' )
1848 self
. assertNotRegex ( output
, 'iseq' )
1849 self
. assertNotRegex ( output
, 'oseq' )
1850 output
= check_output ( 'ip -d link show gretun96' )
1852 self
. assertRegex ( output
, 'gre remote any local any dev dummy98' )
1853 self
. assertRegex ( output
, 'ikey 0.0.0.106' )
1854 self
. assertRegex ( output
, 'okey 0.0.0.106' )
1855 self
. assertNotRegex ( output
, 'iseq' )
1856 self
. assertNotRegex ( output
, 'oseq' )
1858 def test_ip6gre_tunnel ( self
):
1859 copy_network_unit ( '12-dummy.netdev' , '25-ip6gretun.network' ,
1860 '25-ip6gre-tunnel.netdev' , '25-tunnel.network' ,
1861 '25-ip6gre-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1862 '25-ip6gre-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1863 '25-ip6gre-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1866 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1868 self
. wait_links ( 'dummy98' , 'ip6gretun99' , 'ip6gretun98' , 'ip6gretun97' , 'ip6gretun96' )
1870 output
= check_output ( 'ip -d link show ip6gretun99' )
1872 self
. assertRegex ( output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1873 output
= check_output ( 'ip -d link show ip6gretun98' )
1875 self
. assertRegex ( output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98' )
1876 output
= check_output ( 'ip -d link show ip6gretun97' )
1878 self
. assertRegex ( output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98' )
1879 output
= check_output ( 'ip -d link show ip6gretun96' )
1881 self
. assertRegex ( output
, 'ip6gre remote any local any dev dummy98' )
1883 def test_gretap_tunnel ( self
):
1884 copy_network_unit ( '12-dummy.netdev' , '25-gretap.network' ,
1885 '25-gretap-tunnel.netdev' , '25-tunnel.network' ,
1886 '25-gretap-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1888 self
. wait_online ([ 'gretap99:routable' , 'gretap98:routable' , 'dummy98:degraded' ])
1890 output
= check_output ( 'ip -d link show gretap99' )
1892 self
. assertRegex ( output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1893 self
. assertRegex ( output
, 'ikey 0.0.0.106' )
1894 self
. assertRegex ( output
, 'okey 0.0.0.106' )
1895 self
. assertRegex ( output
, 'iseq' )
1896 self
. assertRegex ( output
, 'oseq' )
1897 self
. assertIn ( 'nopmtudisc' , output
)
1898 self
. assertIn ( 'ignore-df' , output
)
1899 output
= check_output ( 'ip -d link show gretap98' )
1901 self
. assertRegex ( output
, 'gretap remote 10.65.223.239 local any dev dummy98' )
1902 self
. assertRegex ( output
, 'ikey 0.0.0.107' )
1903 self
. assertRegex ( output
, 'okey 0.0.0.107' )
1904 self
. assertRegex ( output
, 'iseq' )
1905 self
. assertRegex ( output
, 'oseq' )
1907 def test_ip6gretap_tunnel ( self
):
1908 copy_network_unit ( '12-dummy.netdev' , '25-ip6gretap.network' ,
1909 '25-ip6gretap-tunnel.netdev' , '25-tunnel.network' ,
1910 '25-ip6gretap-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1912 self
. wait_online ([ 'ip6gretap99:routable' , 'ip6gretap98:routable' , 'dummy98:degraded' ])
1914 output
= check_output ( 'ip -d link show ip6gretap99' )
1916 self
. assertRegex ( output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1917 output
= check_output ( 'ip -d link show ip6gretap98' )
1919 self
. assertRegex ( output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98' )
1921 def test_vti_tunnel ( self
):
1922 copy_network_unit ( '12-dummy.netdev' , '25-vti.network' ,
1923 '25-vti-tunnel.netdev' , '25-tunnel.network' ,
1924 '25-vti-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1925 '25-vti-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1926 '25-vti-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1928 self
. wait_online ([ 'vtitun99:routable' , 'vtitun98:routable' , 'vtitun97:routable' , 'vtitun96:routable' , 'dummy98:degraded' ])
1930 output
= check_output ( 'ip -d link show vtitun99' )
1932 self
. assertRegex ( output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1933 output
= check_output ( 'ip -d link show vtitun98' )
1935 self
. assertRegex ( output
, 'vti remote 10.65.223.239 local any dev dummy98' )
1936 output
= check_output ( 'ip -d link show vtitun97' )
1938 self
. assertRegex ( output
, 'vti remote any local 10.65.223.238 dev dummy98' )
1939 output
= check_output ( 'ip -d link show vtitun96' )
1941 self
. assertRegex ( output
, 'vti remote any local any dev dummy98' )
1943 def test_vti6_tunnel ( self
):
1944 copy_network_unit ( '12-dummy.netdev' , '25-vti6.network' ,
1945 '25-vti6-tunnel.netdev' , '25-tunnel.network' ,
1946 '25-vti6-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1947 '25-vti6-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' )
1949 self
. wait_online ([ 'vti6tun99:routable' , 'vti6tun98:routable' , 'vti6tun97:routable' , 'dummy98:degraded' ])
1951 output
= check_output ( 'ip -d link show vti6tun99' )
1953 self
. assertRegex ( output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1954 output
= check_output ( 'ip -d link show vti6tun98' )
1956 self
. assertRegex ( output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98' )
1957 output
= check_output ( 'ip -d link show vti6tun97' )
1959 self
. assertRegex ( output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98' )
1961 def test_ip6tnl_tunnel ( self
):
1962 copy_network_unit ( '12-dummy.netdev' , '25-ip6tnl.network' ,
1963 '25-ip6tnl-tunnel.netdev' , '25-tunnel.network' ,
1964 '25-ip6tnl-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1965 '25-ip6tnl-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1966 '25-veth.netdev' , '25-ip6tnl-slaac.network' , '25-ipv6-prefix.network' ,
1967 '25-ip6tnl-tunnel-local-slaac.netdev' , '25-ip6tnl-tunnel-local-slaac.network' ,
1968 '25-ip6tnl-tunnel-external.netdev' , '26-netdev-link-local-addressing-yes.network' )
1970 self
. wait_online ([ 'ip6tnl99:routable' , 'ip6tnl98:routable' , 'ip6tnl97:routable' ,
1971 'ip6tnl-slaac:degraded' , 'ip6tnl-external:degraded' ,
1972 'dummy98:degraded' , 'veth99:routable' , 'veth-peer:degraded' ])
1974 output
= check_output ( 'ip -d link show ip6tnl99' )
1976 self
. assertIn ( 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' , output
)
1977 output
= check_output ( 'ip -d link show ip6tnl98' )
1979 self
. assertRegex ( output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98' )
1980 output
= check_output ( 'ip -d link show ip6tnl97' )
1982 self
. assertRegex ( output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98' )
1983 output
= check_output ( 'ip -d link show ip6tnl-external' )
1985 self
. assertIn ( 'ip6tnl-external@NONE:' , output
)
1986 self
. assertIn ( 'ip6tnl external ' , output
)
1987 output
= check_output ( 'ip -d link show ip6tnl-slaac' )
1989 self
. assertIn ( 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99' , output
)
1991 output
= check_output ( 'ip -6 address show veth99' )
1993 self
. assertIn ( 'inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic' , output
)
1995 output
= check_output ( 'ip -4 route show default' )
1997 self
. assertIn ( 'default dev ip6tnl-slaac proto static' , output
)
1999 def test_sit_tunnel ( self
):
2000 copy_network_unit ( '12-dummy.netdev' , '25-sit.network' ,
2001 '25-sit-tunnel.netdev' , '25-tunnel.network' ,
2002 '25-sit-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
2003 '25-sit-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
2004 '25-sit-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
2006 self
. wait_online ([ 'sittun99:routable' , 'sittun98:routable' , 'sittun97:routable' , 'sittun96:routable' , 'dummy98:degraded' ])
2008 output
= check_output ( 'ip -d link show sittun99' )
2010 self
. assertRegex ( output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98" )
2011 output
= check_output ( 'ip -d link show sittun98' )
2013 self
. assertRegex ( output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98" )
2014 output
= check_output ( 'ip -d link show sittun97' )
2016 self
. assertRegex ( output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98" )
2017 output
= check_output ( 'ip -d link show sittun96' )
2019 self
. assertRegex ( output
, "sit (ip6ip )?remote any local any dev dummy98" )
2021 def test_isatap_tunnel ( self
):
2022 copy_network_unit ( '12-dummy.netdev' , '25-isatap.network' ,
2023 '25-isatap-tunnel.netdev' , '25-tunnel.network' )
2025 self
. wait_online ([ 'isataptun99:routable' , 'dummy98:degraded' ])
2027 output
= check_output ( 'ip -d link show isataptun99' )
2029 self
. assertRegex ( output
, "isatap " )
2031 def test_6rd_tunnel ( self
):
2032 copy_network_unit ( '12-dummy.netdev' , '25-6rd.network' ,
2033 '25-6rd-tunnel.netdev' , '25-tunnel.network' )
2035 self
. wait_online ([ 'sittun99:routable' , 'dummy98:degraded' ])
2037 output
= check_output ( 'ip -d link show sittun99' )
2039 self
. assertRegex ( output
, '6rd-prefix 2602::/24' )
2041 @expectedFailureIfERSPANv0IsNotSupported ()
2042 def test_erspan_tunnel_v0 ( self
):
2043 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
2044 '25-erspan0-tunnel.netdev' , '25-tunnel.network' ,
2045 '25-erspan0-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
2047 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
2049 output
= check_output ( 'ip -d link show erspan99' )
2051 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
2052 self
. assertIn ( 'erspan_ver 0' , output
)
2053 self
. assertNotIn ( 'erspan_index 123' , output
)
2054 self
. assertNotIn ( 'erspan_dir ingress' , output
)
2055 self
. assertNotIn ( 'erspan_hwid 1f' , output
)
2056 self
. assertIn ( 'ikey 0.0.0.101' , output
)
2057 self
. assertIn ( 'iseq' , output
)
2058 self
. assertIn ( 'nopmtudisc' , output
)
2059 self
. assertIn ( 'ignore-df' , output
)
2060 output
= check_output ( 'ip -d link show erspan98' )
2062 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
2063 self
. assertIn ( 'erspan_ver 0' , output
)
2064 self
. assertNotIn ( 'erspan_index 124' , output
)
2065 self
. assertNotIn ( 'erspan_dir egress' , output
)
2066 self
. assertNotIn ( 'erspan_hwid 2f' , output
)
2067 self
. assertIn ( 'ikey 0.0.0.102' , output
)
2068 self
. assertIn ( 'iseq' , output
)
2070 def test_erspan_tunnel_v1 ( self
):
2071 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
2072 '25-erspan1-tunnel.netdev' , '25-tunnel.network' ,
2073 '25-erspan1-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 1' , output
)
2081 self
. assertIn ( 'erspan_index 123' , output
)
2082 self
. assertNotIn ( 'erspan_dir ingress' , output
)
2083 self
. assertNotIn ( 'erspan_hwid 1f' , 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 1' , output
)
2092 self
. assertIn ( 'erspan_index 124' , output
)
2093 self
. assertNotIn ( 'erspan_dir egress' , output
)
2094 self
. assertNotIn ( 'erspan_hwid 2f' , 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 @expectedFailureIfERSPANv2IsNotSupported ()
2101 def test_erspan_tunnel_v2 ( self
):
2102 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
2103 '25-erspan2-tunnel.netdev' , '25-tunnel.network' ,
2104 '25-erspan2-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
2106 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
2108 output
= check_output ( 'ip -d link show erspan99' )
2110 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
2111 self
. assertIn ( 'erspan_ver 2' , output
)
2112 self
. assertNotIn ( 'erspan_index 123' , output
)
2113 self
. assertIn ( 'erspan_dir ingress' , output
)
2114 self
. assertIn ( 'erspan_hwid 0x1f' , output
)
2115 self
. assertIn ( 'ikey 0.0.0.101' , output
)
2116 self
. assertIn ( 'okey 0.0.0.101' , output
)
2117 self
. assertIn ( 'iseq' , output
)
2118 self
. assertIn ( 'oseq' , output
)
2119 output
= check_output ( 'ip -d link show erspan98' )
2121 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
2122 self
. assertIn ( 'erspan_ver 2' , output
)
2123 self
. assertNotIn ( 'erspan_index 124' , output
)
2124 self
. assertIn ( 'erspan_dir egress' , output
)
2125 self
. assertIn ( 'erspan_hwid 0x2f' , output
)
2126 self
. assertIn ( 'ikey 0.0.0.102' , output
)
2127 self
. assertIn ( 'okey 0.0.0.102' , output
)
2128 self
. assertIn ( 'iseq' , output
)
2129 self
. assertIn ( 'oseq' , output
)
2131 def test_tunnel_independent ( self
):
2132 copy_network_unit ( '25-ipip-tunnel-independent.netdev' , '26-netdev-link-local-addressing-yes.network' )
2135 self
. wait_online ([ 'ipiptun99:carrier' ])
2137 def test_tunnel_independent_loopback ( self
):
2138 copy_network_unit ( '25-ipip-tunnel-independent-loopback.netdev' , '26-netdev-link-local-addressing-yes.network' )
2141 self
. wait_online ([ 'ipiptun99:carrier' ])
2143 @expectedFailureIfModuleIsNotAvailable ( 'xfrm_interface' )
2144 def test_xfrm ( self
):
2145 copy_network_unit ( '12-dummy.netdev' , '25-xfrm.network' ,
2146 '25-xfrm.netdev' , '25-xfrm-independent.netdev' ,
2147 '26-netdev-link-local-addressing-yes.network' )
2150 self
. wait_online ([ 'dummy98:degraded' , 'xfrm98:degraded' , 'xfrm99:degraded' ])
2152 output
= check_output ( 'ip -d link show dev xfrm98' )
2154 self
. assertIn ( 'xfrm98@dummy98:' , output
)
2155 self
. assertIn ( 'xfrm if_id 0x98 ' , output
)
2157 output
= check_output ( 'ip -d link show dev xfrm99' )
2159 self
. assertIn ( 'xfrm99@lo:' , output
)
2160 self
. assertIn ( 'xfrm if_id 0x99 ' , output
)
2162 @expectedFailureIfModuleIsNotAvailable ( 'fou' )
2164 # The following redundant check is necessary for CentOS CI.
2165 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
2166 self
. assertTrue ( is_module_available ( 'fou' ))
2168 copy_network_unit ( '25-fou-ipproto-ipip.netdev' , '25-fou-ipproto-gre.netdev' ,
2169 '25-fou-ipip.netdev' , '25-fou-sit.netdev' ,
2170 '25-fou-gre.netdev' , '25-fou-gretap.netdev' )
2173 self
. wait_online ([ 'ipiptun96:off' , 'sittun96:off' , 'gretun96:off' , 'gretap96:off' ], setup_state
= 'unmanaged' )
2175 output
= check_output ( 'ip fou show' )
2177 self
. assertRegex ( output
, 'port 55555 ipproto 4' )
2178 self
. assertRegex ( output
, 'port 55556 ipproto 47' )
2180 output
= check_output ( 'ip -d link show ipiptun96' )
2182 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55555' )
2183 output
= check_output ( 'ip -d link show sittun96' )
2185 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55555' )
2186 output
= check_output ( 'ip -d link show gretun96' )
2188 self
. assertRegex ( output
, 'encap fou encap-sport 1001 encap-dport 55556' )
2189 output
= check_output ( 'ip -d link show gretap96' )
2191 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55556' )
2193 def test_vxlan ( self
):
2194 copy_network_unit ( '11-dummy.netdev' , '25-vxlan-test1.network' ,
2195 '25-vxlan.netdev' , '25-vxlan.network' ,
2196 '25-vxlan-ipv6.netdev' , '25-vxlan-ipv6.network' ,
2197 '25-vxlan-independent.netdev' , '26-netdev-link-local-addressing-yes.network' ,
2198 '25-veth.netdev' , '25-vxlan-veth99.network' , '25-ipv6-prefix.network' ,
2199 '25-vxlan-local-slaac.netdev' , '25-vxlan-local-slaac.network' )
2202 self
. wait_online ([ 'test1:degraded' , 'veth99:routable' , 'veth-peer:degraded' ,
2203 'vxlan99:degraded' , 'vxlan98:degraded' , 'vxlan97:degraded' , 'vxlan-slaac:degraded' ])
2205 output
= check_output ( 'ip -d -d link show vxlan99' )
2207 self
. assertIn ( '999' , output
)
2208 self
. assertIn ( '5555' , output
)
2209 self
. assertIn ( 'l2miss' , output
)
2210 self
. assertIn ( 'l3miss' , output
)
2211 self
. assertIn ( 'gbp' , output
)
2212 # Since [0] some of the options use slightly different names and some
2213 # options with default values are shown only if the -d(etails) setting
2215 # [0] https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit/?id=1215e9d3862387353d8672296cb4c6c16e8cbb72
2216 self
. assertRegex ( output
, '(udpcsum|udp_csum)' )
2217 self
. assertRegex ( output
, '(udp6zerocsumtx|udp_zero_csum6_tx)' )
2218 self
. assertRegex ( output
, '(udp6zerocsumrx|udp_zero_csum6_rx)' )
2219 self
. assertRegex ( output
, '(remcsumtx|remcsum_tx)' )
2220 self
. assertRegex ( output
, '(remcsumrx|remcsum_rx)' )
2222 output
= check_output ( 'bridge fdb show dev vxlan99' )
2224 self
. assertIn ( '00:11:22:33:44:55 dst 10.0.0.5 self permanent' , output
)
2225 self
. assertIn ( '00:11:22:33:44:66 dst 10.0.0.6 self permanent' , output
)
2226 self
. assertIn ( '00:11:22:33:44:77 dst 10.0.0.7 via test1 self permanent' , output
)
2228 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'vxlan99' , env
= env
)
2230 self
. assertIn ( 'VNI: 999' , output
)
2231 self
. assertIn ( 'Destination Port: 5555' , output
)
2232 self
. assertIn ( 'Underlying Device: test1' , output
)
2234 output
= check_output ( 'bridge fdb show dev vxlan97' )
2236 self
. assertIn ( '00:00:00:00:00:00 dst fe80::23b:d2ff:fe95:967f via test1 self permanent' , output
)
2237 self
. assertIn ( '00:00:00:00:00:00 dst fe80::27c:16ff:fec0:6c74 via test1 self permanent' , output
)
2238 self
. assertIn ( '00:00:00:00:00:00 dst fe80::2a2:e4ff:fef9:2269 via test1 self permanent' , output
)
2240 output
= check_output ( 'ip -d link show vxlan-slaac' )
2242 self
. assertIn ( 'vxlan id 4831584 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99' , output
)
2244 output
= check_output ( 'ip -6 address show veth99' )
2246 self
. assertIn ( 'inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic' , output
)
2248 @unittest . skipUnless ( compare_kernel_version ( "6" ), reason
= "Causes kernel panic on unpatched kernels: https://bugzilla.kernel.org/show_bug.cgi?id=208315" )
2249 def test_macsec ( self
):
2250 copy_network_unit ( '25-macsec.netdev' , '25-macsec.network' , '25-macsec.key' ,
2251 '26-macsec.network' , '12-dummy.netdev' )
2254 self
. wait_online ([ 'dummy98:degraded' , 'macsec99:routable' ])
2256 output
= check_output ( 'ip -d link show macsec99' )
2258 self
. assertRegex ( output
, 'macsec99@dummy98' )
2259 self
. assertRegex ( output
, 'macsec sci [0-9a-f]*000b' )
2260 self
. assertRegex ( output
, 'encrypt on' )
2262 output
= check_output ( 'ip macsec show macsec99' )
2264 self
. assertRegex ( output
, 'encrypt on' )
2265 self
. assertRegex ( output
, 'TXSC: [0-9a-f]*000b on SA 1' )
2266 self
. assertRegex ( output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000' )
2267 self
. assertRegex ( output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000' )
2268 self
. assertRegex ( output
, 'RXSC: c619528fe6a00100, state on' )
2269 self
. assertRegex ( output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000' )
2270 self
. assertRegex ( output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000' )
2271 self
. assertRegex ( output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000' )
2272 self
. assertRegex ( output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000' )
2273 self
. assertNotRegex ( output
, 'key 02030405067080900000000000000000' )
2274 self
. assertRegex ( output
, 'RXSC: 8c16456c83a90002, state on' )
2275 self
. assertRegex ( output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000' )
2277 def test_nlmon ( self
):
2278 copy_network_unit ( '25-nlmon.netdev' , '26-netdev-link-local-addressing-yes.network' )
2281 self
. wait_online ([ 'nlmon99:carrier' ])
2283 @expectedFailureIfModuleIsNotAvailable ( 'ifb' )
2285 copy_network_unit ( '25-ifb.netdev' , '26-netdev-link-local-addressing-yes.network' )
2288 self
. wait_online ([ 'ifb99:degraded' ])
2290 class NetworkdL2TPTests ( unittest
. TestCase
, Utilities
):
2298 @expectedFailureIfModuleIsNotAvailable ( 'l2tp_eth' , 'l2tp_netlink' )
2299 def test_l2tp_udp ( self
):
2300 copy_network_unit ( '11-dummy.netdev' , '25-l2tp-dummy.network' ,
2301 '25-l2tp-udp.netdev' , '25-l2tp.network' )
2304 self
. wait_online ([ 'test1:routable' , 'l2tp-ses1:degraded' , 'l2tp-ses2:degraded' ])
2306 output
= check_output ( 'ip l2tp show tunnel tunnel_id 10' )
2308 self
. assertRegex ( output
, "Tunnel 10, encap UDP" )
2309 self
. assertRegex ( output
, "From 192.168.30.100 to 192.168.30.101" )
2310 self
. assertRegex ( output
, "Peer tunnel 11" )
2311 self
. assertRegex ( output
, "UDP source / dest ports: 3000/4000" )
2312 self
. assertRegex ( output
, "UDP checksum: enabled" )
2314 output
= check_output ( 'ip l2tp show session tid 10 session_id 15' )
2316 self
. assertRegex ( output
, "Session 15 in tunnel 10" )
2317 self
. assertRegex ( output
, "Peer session 16, tunnel 11" )
2318 self
. assertRegex ( output
, "interface name: l2tp-ses1" )
2320 output
= check_output ( 'ip l2tp show session tid 10 session_id 17' )
2322 self
. assertRegex ( output
, "Session 17 in tunnel 10" )
2323 self
. assertRegex ( output
, "Peer session 18, tunnel 11" )
2324 self
. assertRegex ( output
, "interface name: l2tp-ses2" )
2326 @expectedFailureIfModuleIsNotAvailable ( 'l2tp_eth' , 'l2tp_ip' , 'l2tp_netlink' )
2327 def test_l2tp_ip ( self
):
2328 copy_network_unit ( '11-dummy.netdev' , '25-l2tp-dummy.network' ,
2329 '25-l2tp-ip.netdev' , '25-l2tp.network' )
2332 self
. wait_online ([ 'test1:routable' , 'l2tp-ses3:degraded' , 'l2tp-ses4:degraded' ])
2334 output
= check_output ( 'ip l2tp show tunnel tunnel_id 10' )
2336 self
. assertRegex ( output
, "Tunnel 10, encap IP" )
2337 self
. assertRegex ( output
, "From 192.168.30.100 to 192.168.30.101" )
2338 self
. assertRegex ( output
, "Peer tunnel 12" )
2340 output
= check_output ( 'ip l2tp show session tid 10 session_id 25' )
2342 self
. assertRegex ( output
, "Session 25 in tunnel 10" )
2343 self
. assertRegex ( output
, "Peer session 26, tunnel 12" )
2344 self
. assertRegex ( output
, "interface name: l2tp-ses3" )
2346 output
= check_output ( 'ip l2tp show session tid 10 session_id 27' )
2348 self
. assertRegex ( output
, "Session 27 in tunnel 10" )
2349 self
. assertRegex ( output
, "Peer session 28, tunnel 12" )
2350 self
. assertRegex ( output
, "interface name: l2tp-ses4" )
2352 class NetworkdNetworkTests ( unittest
. TestCase
, Utilities
):
2360 def verify_address_static (
2386 output
= check_output ( 'ip address show dev dummy98' )
2390 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
2391 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
2392 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
2393 self
. assertIn ( 'inet6 2001:db8:0:f101::15/64 scope global' , output
)
2394 self
. assertIn ( 'inet6 2001:db8:0:f101::16/64 scope global' , output
)
2395 self
. assertIn ( 'inet6 2001:db8:0:f102::15/64 scope global' , output
)
2398 self
. assertIn ( f
'inet 10.3.1.1/24 brd 10.3.1.255 scope global {label1} ' , output
)
2399 self
. assertIn ( f
'inet 10.3.2.1/24 brd 10.3.2.255 scope global {label2} ' , output
)
2400 self
. assertIn ( f
'inet 10.3.3.1/24 brd 10.3.3.255 scope global {label3} ' , output
)
2403 self
. assertIn ( f
'inet 10.4.1.1/24 {broadcast1} scope global dummy98' , output
)
2404 self
. assertIn ( f
'inet 10.4.2.1/24 {broadcast2} scope global dummy98' , output
)
2405 self
. assertIn ( f
'inet 10.4.3.1/24 {broadcast3} scope global dummy98' , output
)
2408 self
. assertIn ( f
'inet 10.5.1.1 {peer1} scope global dummy98' , output
)
2409 self
. assertIn ( f
'inet 10.5.2.1 {peer2} scope global dummy98' , output
)
2410 self
. assertIn ( f
'inet 10.5.3.1 {peer3} scope global dummy98' , output
)
2411 self
. assertIn ( f
'inet6 2001:db8:0:f103::1 {peer4} scope global' , output
)
2412 self
. assertIn ( f
'inet6 2001:db8:0:f103::2 {peer5} scope global' , output
)
2413 self
. assertIn ( f
'inet6 2001:db8:0:f103::3 {peer6} scope global' , output
)
2416 self
. assertIn ( f
'inet 10.6.1.1/24 brd 10.6.1.255 scope {scope1} dummy98' , output
)
2417 self
. assertIn ( f
'inet 10.6.2.1/24 brd 10.6.2.255 scope {scope2} dummy98' , output
)
2420 self
. assertIn ( f
'inet 10.7.1.1/24 brd 10.7.1.255 scope global {deprecated1} dummy98' , output
)
2421 self
. assertIn ( f
'inet 10.7.2.1/24 brd 10.7.2.255 scope global {deprecated2} dummy98' , output
)
2422 self
. assertIn ( f
'inet6 2001:db8:0:f104::1/64 scope global {deprecated3} ' , output
)
2423 self
. assertIn ( f
'inet6 2001:db8:0:f104::2/64 scope global {deprecated4} ' , output
)
2426 self
. assertRegex ( output
, rf
'inet 10.8.1.1/24 (metric {route_metric} |)brd 10.8.1.255 scope global dummy98' )
2427 self
. assertRegex ( output
, rf
'inet6 2001:db8:0:f105::1/64 (metric {route_metric} |)scope global' )
2429 output_route
= check_output ( 'ip -4 route show dev dummy98 10.8.1.0/24' )
2431 self
. assertIn ( f
'10.8.1.0/24 proto kernel scope link src 10.8.1.1 metric {route_metric} ' , output_route
)
2433 output_route
= check_output ( 'ip -6 route show dev dummy98 2001:db8:0:f105::/64' )
2435 self
. assertIn ( f
'2001:db8:0:f105::/64 proto kernel metric {route_metric} ' , output_route
)
2438 self
. assertIn ( f
'inet 10.9.1.1/24 brd 10.9.1.255 scope global {flag1} dummy98' , output
)
2439 self
. assertIn ( f
'inet 10.9.2.1/24 brd 10.9.2.255 scope global {flag2} dummy98' , output
)
2440 self
. assertIn ( f
'inet6 2001:db8:0:f106::1/64 scope global {flag3} ' , output
)
2441 self
. assertIn ( f
'inet6 2001:db8:0:f106::2/64 scope global {flag4} ' , output
)
2444 self
. assertRegex ( output
, r
'inet [0-9]*.[0-9]*.0.1/16 brd [0-9]*.[0-9]*.255.255 scope global subnet16' )
2445 self
. assertRegex ( output
, r
'inet [0-9]*.[0-9]*.[0-9]*.1/24 brd [0-9]*.[0-9]*.[0-9]*.255 scope global subnet24' )
2446 self
. assertRegex ( output
, r
'inet6 [0-9a-f:]*:1/73 scope global' )
2449 self
. assertNotIn ( '10.4.4.1' , output
)
2450 self
. assertNotIn ( '10.5.4.1' , output
)
2451 self
. assertNotIn ( '10.5.5.1' , output
)
2452 self
. assertNotIn ( '10.8.2.1' , output
)
2453 self
. assertNotIn ( '10.9.3.1' , output
)
2454 self
. assertNotIn ( '2001:db8:0:f101::2' , output
)
2455 self
. assertNotIn ( '2001:db8:0:f103::4' , output
)
2458 self
. check_netlabel ( 'dummy98' , r
'10\.10\.1\.0/24' )
2460 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2463 def test_address_static ( self
):
2464 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' , copy_dropins
= False )
2466 self
. setup_nftset ( 'addr4' , 'ipv4_addr' )
2467 self
. setup_nftset ( 'network4' , 'ipv4_addr' , 'flags interval;' )
2468 self
. setup_nftset ( 'ifindex' , 'iface_index' )
2470 self
. wait_online ([ 'dummy98:routable' ])
2471 self
. verify_address_static (
2476 broadcast2
= ' brd 10.4.2.255' ,
2477 broadcast3
= ' brd 10.4.3.63' ,
2478 peer1
= ' peer 10.5.1.101/24' ,
2479 peer2
= ' peer 10.5.2.101/24' ,
2480 peer3
= '/24 brd 10.5.3.255' ,
2481 peer4
= ' peer 2001:db8:0:f103::101/128' ,
2482 peer5
= ' peer 2001:db8:0:f103::102/128' ,
2487 deprecated2
= ' deprecated' ,
2489 deprecated4
= ' deprecated' ,
2491 flag1
= ' noprefixroute' ,
2493 flag3
= ' noprefixroute' ,
2494 flag4
= ' home mngtmpaddr' ,
2497 self
. check_nftset ( 'addr4' , r
'10\.10\.1\.1' )
2498 self
. check_nftset ( 'network4' , r
'10\.10\.1\.0/24' )
2499 self
. check_nftset ( 'ifindex' , 'dummy98' )
2501 self
. teardown_nftset ( 'addr4' , 'network4' , 'ifindex' )
2503 copy_network_unit ( '25-address-static.network.d/10-override.conf' )
2505 self
. wait_online ([ 'dummy98:routable' ])
2506 self
. verify_address_static (
2507 label1
= 'new-label1' ,
2509 label3
= 'new-label3' ,
2510 broadcast1
= ' brd 10.4.1.255' ,
2512 broadcast3
= ' brd 10.4.3.31' ,
2513 peer1
= ' peer 10.5.1.102/24' ,
2514 peer2
= '/24 brd 10.5.2.255' ,
2515 peer3
= ' peer 10.5.3.102/24' ,
2516 peer4
= ' peer 2001:db8:0:f103::201/128' ,
2518 peer6
= ' peer 2001:db8:0:f103::203/128' ,
2521 deprecated1
= ' deprecated' ,
2523 deprecated3
= ' deprecated' ,
2527 flag2
= ' noprefixroute' ,
2528 flag3
= ' home mngtmpaddr' ,
2529 flag4
= ' noprefixroute' ,
2532 networkctl_reconfigure ( 'dummy98' )
2533 self
. wait_online ([ 'dummy98:routable' ])
2534 self
. verify_address_static (
2535 label1
= 'new-label1' ,
2537 label3
= 'new-label3' ,
2538 broadcast1
= ' brd 10.4.1.255' ,
2540 broadcast3
= ' brd 10.4.3.31' ,
2541 peer1
= ' peer 10.5.1.102/24' ,
2542 peer2
= '/24 brd 10.5.2.255' ,
2543 peer3
= ' peer 10.5.3.102/24' ,
2544 peer4
= ' peer 2001:db8:0:f103::201/128' ,
2546 peer6
= ' peer 2001:db8:0:f103::203/128' ,
2549 deprecated1
= ' deprecated' ,
2551 deprecated3
= ' deprecated' ,
2555 flag2
= ' noprefixroute' ,
2556 flag3
= ' home mngtmpaddr' ,
2557 flag4
= ' noprefixroute' ,
2561 # 1. set preferred lifetime forever to drop the deprecated flag for testing #20891.
2562 check_output ( 'ip address change 10.7.1.1/24 dev dummy98 preferred_lft forever' )
2563 check_output ( 'ip address change 2001:db8:0:f104::1/64 dev dummy98 preferred_lft forever' )
2564 output
= check_output ( 'ip address show dev dummy98' )
2566 self
. assertNotRegex ( output
, '10.7.1.1/24 .* deprecated' )
2567 self
. assertNotRegex ( output
, '2001:db8:0:f104::1/64 .* deprecated' )
2569 # 2. reconfigure the interface, and check the deprecated flag is set again
2570 networkctl_reconfigure ( 'dummy98' )
2571 self
. wait_online ([ 'dummy98:routable' ])
2572 self
. verify_address_static (
2573 label1
= 'new-label1' ,
2575 label3
= 'new-label3' ,
2576 broadcast1
= ' brd 10.4.1.255' ,
2578 broadcast3
= ' brd 10.4.3.31' ,
2579 peer1
= ' peer 10.5.1.102/24' ,
2580 peer2
= '/24 brd 10.5.2.255' ,
2581 peer3
= ' peer 10.5.3.102/24' ,
2582 peer4
= ' peer 2001:db8:0:f103::201/128' ,
2584 peer6
= ' peer 2001:db8:0:f103::203/128' ,
2587 deprecated1
= ' deprecated' ,
2589 deprecated3
= ' deprecated' ,
2593 flag2
= ' noprefixroute' ,
2594 flag3
= ' home mngtmpaddr' ,
2595 flag4
= ' noprefixroute' ,
2598 # test for ENOBUFS issue #17012 (with reload)
2599 copy_network_unit ( '25-address-static.network.d/10-many-address.conf' )
2601 self
. wait_online ([ 'dummy98:routable' ])
2602 output
= check_output ( 'ip -4 address show dev dummy98' )
2603 for i
in range ( 1 , 254 ):
2604 self
. assertIn ( f
'inet 10.3.3. {i} /16 brd 10.3.255.255' , output
)
2606 # (with reconfigure)
2607 networkctl_reconfigure ( 'dummy98' )
2608 self
. wait_online ([ 'dummy98:routable' ])
2609 output
= check_output ( 'ip -4 address show dev dummy98' )
2610 for i
in range ( 1 , 254 ):
2611 self
. assertIn ( f
'inet 10.3.3. {i} /16 brd 10.3.255.255' , output
)
2613 def test_address_null ( self
):
2614 copy_network_unit ( '25-address-null.network' , '12-dummy.netdev' )
2617 self
. wait_online ([ 'dummy98:routable' ])
2619 output
= check_output ( 'ip address show dev dummy98 scope global' )
2622 ipv4_address_16
= re
. findall ( r
'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255' , output
)
2623 self
. assertEqual ( len ( ipv4_address_16
), 1 )
2624 ipv4_address_24
= re
. findall ( r
'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255' , output
)
2625 self
. assertEqual ( len ( ipv4_address_24
), 1 )
2626 ipv4_address_30
= re
. findall ( r
'inet 192.168.[0-9]*.[0-9]*/30 brd 192.168.[0-9]*.[0-9]*' , output
)
2627 self
. assertEqual ( len ( ipv4_address_30
), 1 )
2628 ipv6_address
= re
. findall ( r
'inet6 fd[0-9a-f:]*/64' , output
)
2629 self
. assertEqual ( len ( ipv6_address
), 1 )
2631 networkctl_reconfigure ( 'dummy98' )
2632 self
. wait_online ([ 'dummy98:routable' ])
2634 output
= check_output ( 'ip address show dev dummy98 scope global' )
2636 self
. assertIn ( ipv4_address_16
[ 0 ], output
)
2637 self
. assertIn ( ipv4_address_24
[ 0 ], output
)
2638 self
. assertIn ( ipv4_address_30
[ 0 ], output
)
2639 self
. assertIn ( ipv6_address
[ 0 ], output
)
2641 def test_address_ipv4acd ( self
):
2642 check_output ( 'ip netns add ns99' )
2643 check_output ( 'ip link add veth99 type veth peer veth-peer' )
2644 check_output ( 'ip link set veth-peer netns ns99' )
2645 check_output ( 'ip link set veth99 up' )
2646 check_output ( 'ip netns exec ns99 ip link set veth-peer up' )
2647 check_output ( 'ip netns exec ns99 ip address add 192.168.100.10/24 dev veth-peer' )
2649 copy_network_unit ( '25-address-ipv4acd-veth99.network' , copy_dropins
= False )
2651 self
. wait_online ([ 'veth99:routable' ])
2653 output
= check_output ( 'ip -4 address show dev veth99' )
2655 self
. assertNotIn ( '192.168.100.10/24' , output
)
2656 self
. assertIn ( '192.168.100.11/24' , output
)
2658 copy_network_unit ( '25-address-ipv4acd-veth99.network.d/conflict-address.conf' )
2660 self
. wait_operstate ( 'veth99' , operstate
= 'routable' , setup_state
= 'configuring' , setup_timeout
= 10 )
2662 output
= check_output ( 'ip -4 address show dev veth99' )
2664 self
. assertNotIn ( '192.168.100.10/24' , output
)
2665 self
. assertIn ( '192.168.100.11/24' , output
)
2667 def test_address_peer_ipv4 ( self
):
2668 # test for issue #17304
2669 copy_network_unit ( '25-address-peer-ipv4.network' , '12-dummy.netdev' )
2671 for trial
in range ( 2 ):
2677 self
. wait_online ([ 'dummy98:routable' ])
2679 output
= check_output ( 'ip -4 address show dev dummy98' )
2680 self
. assertIn ( 'inet 100.64.0.1 peer 100.64.0.2/32 scope global' , output
)
2682 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
2683 def test_prefix_route ( self
):
2684 copy_network_unit ( '25-prefix-route-with-vrf.network' , '12-dummy.netdev' ,
2685 '25-prefix-route-without-vrf.network' , '11-dummy.netdev' ,
2686 '25-vrf.netdev' , '25-vrf.network' )
2687 for trial
in range ( 2 ):
2693 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' , 'vrf99:carrier' ])
2695 output
= check_output ( 'ip route show table 42 dev dummy98' )
2696 print ( '### ip route show table 42 dev dummy98' )
2698 self
. assertRegex ( output
, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1' )
2699 self
. assertRegex ( output
, '10.20.33.0/24 proto kernel scope link src 10.20.33.1' )
2700 self
. assertRegex ( output
, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1' )
2701 self
. assertRegex ( output
, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1' )
2702 self
. assertRegex ( output
, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1' )
2703 self
. assertRegex ( output
, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1' )
2704 self
. assertRegex ( output
, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1' )
2705 output
= check_output ( 'ip -6 route show table 42 dev dummy98' )
2706 print ( '### ip -6 route show table 42 dev dummy98' )
2710 self
. assertRegex ( output
, 'local fdde:11:22::1 proto kernel metric 0 pref medium' )
2711 #self.assertRegex(output, 'fdde:11:22::1 proto kernel metric 256 pref medium')
2712 self
. assertRegex ( output
, 'local fdde:11:33::1 proto kernel metric 0 pref medium' )
2713 self
. assertRegex ( output
, 'fdde:11:33::/64 proto kernel metric 256 pref medium' )
2714 self
. assertRegex ( output
, 'local fdde:11:44::1 proto kernel metric 0 pref medium' )
2715 self
. assertRegex ( output
, 'local fdde:11:55::1 proto kernel metric 0 pref medium' )
2716 self
. assertRegex ( output
, 'fe80::/64 proto kernel metric 256 pref medium' )
2717 self
. assertRegex ( output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium' )
2721 output
= check_output ( 'ip route show dev test1' )
2722 print ( '### ip route show dev test1' )
2724 self
. assertRegex ( output
, '10.21.33.0/24 proto kernel scope link src 10.21.33.1' )
2725 output
= check_output ( 'ip route show table local dev test1' )
2726 print ( '### ip route show table local dev test1' )
2728 self
. assertRegex ( output
, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1' )
2729 self
. assertRegex ( output
, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1' )
2730 self
. assertRegex ( output
, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1' )
2731 self
. assertRegex ( output
, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1' )
2732 self
. assertRegex ( output
, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1' )
2733 self
. assertRegex ( output
, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1' )
2734 output
= check_output ( 'ip -6 route show dev test1' )
2735 print ( '### ip -6 route show dev test1' )
2737 self
. assertRegex ( output
, 'fdde:12:22::1 proto kernel metric 256 pref medium' )
2738 self
. assertRegex ( output
, 'fdde:12:33::/64 proto kernel metric 256 pref medium' )
2739 self
. assertRegex ( output
, 'fe80::/64 proto kernel metric 256 pref medium' )
2740 output
= check_output ( 'ip -6 route show table local dev test1' )
2741 print ( '### ip -6 route show table local dev test1' )
2743 self
. assertRegex ( output
, 'local fdde:12:22::1 proto kernel metric 0 pref medium' )
2744 self
. assertRegex ( output
, 'local fdde:12:33::1 proto kernel metric 0 pref medium' )
2745 self
. assertRegex ( output
, 'local fdde:12:44::1 proto kernel metric 0 pref medium' )
2746 self
. assertRegex ( output
, 'local fdde:12:55::1 proto kernel metric 0 pref medium' )
2747 self
. assertRegex ( output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium' )
2749 def test_configure_without_carrier ( self
):
2750 copy_network_unit ( '11-dummy.netdev' )
2752 self
. wait_operstate ( 'test1' , 'off' , '' )
2753 check_output ( 'ip link set dev test1 up carrier off' )
2755 copy_network_unit ( '25-test1.network.d/configure-without-carrier.conf' , copy_dropins
= False )
2757 self
. wait_online ([ 'test1:no-carrier' ])
2759 carrier_map
= { 'on' : '1' , 'off' : '0' }
2760 routable_map
= { 'on' : 'routable' , 'off' : 'no-carrier' }
2761 for carrier
in [ 'off' , 'on' , 'off' ]:
2762 with self
. subTest ( carrier
= carrier
):
2763 if carrier_map
[ carrier
] != read_link_attr ( 'test1' , 'carrier' ):
2764 check_output ( f
'ip link set dev test1 carrier {carrier} ' )
2765 self
. wait_online ([ f
'test1:{routable_map[carrier]}:{routable_map[carrier]}' ])
2767 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
2769 self
. assertRegex ( output
, '192.168.0.15' )
2770 self
. assertRegex ( output
, '192.168.0.1' )
2771 self
. assertRegex ( output
, routable_map
[ carrier
])
2773 def test_configure_without_carrier_yes_ignore_carrier_loss_no ( self
):
2774 copy_network_unit ( '11-dummy.netdev' )
2776 self
. wait_operstate ( 'test1' , 'off' , '' )
2777 check_output ( 'ip link set dev test1 up carrier off' )
2779 copy_network_unit ( '25-test1.network' )
2781 self
. wait_online ([ 'test1:no-carrier' ])
2783 carrier_map
= { 'on' : '1' , 'off' : '0' }
2784 routable_map
= { 'on' : 'routable' , 'off' : 'no-carrier' }
2785 for ( carrier
, have_config
) in [( 'off' , True ), ( 'on' , True ), ( 'off' , False )]:
2786 with self
. subTest ( carrier
= carrier
, have_config
= have_config
):
2787 if carrier_map
[ carrier
] != read_link_attr ( 'test1' , 'carrier' ):
2788 check_output ( f
'ip link set dev test1 carrier {carrier} ' )
2789 self
. wait_online ([ f
'test1:{routable_map[carrier]}:{routable_map[carrier]}' ])
2791 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
2794 self
. assertRegex ( output
, '192.168.0.15' )
2795 self
. assertRegex ( output
, '192.168.0.1' )
2797 self
. assertNotRegex ( output
, '192.168.0.15' )
2798 self
. assertNotRegex ( output
, '192.168.0.1' )
2799 self
. assertRegex ( output
, routable_map
[ carrier
])
2801 def test_routing_policy_rule ( self
):
2802 copy_network_unit ( '25-routing-policy-rule-test1.network' , '11-dummy.netdev' )
2804 self
. wait_online ([ 'test1:degraded' ])
2806 output
= check_output ( 'ip rule list iif test1 priority 111' )
2808 self
. assertRegex ( output
, '111:' )
2809 self
. assertRegex ( output
, 'from 192.168.100.18' )
2810 self
. assertRegex ( output
, r
'tos (0x08|throughput)\s' )
2811 self
. assertRegex ( output
, 'iif test1' )
2812 self
. assertRegex ( output
, 'oif test1' )
2813 self
. assertRegex ( output
, 'lookup 7' )
2815 output
= check_output ( 'ip rule list iif test1 priority 101' )
2817 self
. assertRegex ( output
, '101:' )
2818 self
. assertRegex ( output
, 'from all' )
2819 self
. assertRegex ( output
, 'iif test1' )
2820 self
. assertRegex ( output
, 'lookup 9' )
2822 output
= check_output ( 'ip -6 rule list iif test1 priority 100' )
2824 self
. assertRegex ( output
, '100:' )
2825 self
. assertRegex ( output
, 'from all' )
2826 self
. assertRegex ( output
, 'iif test1' )
2827 self
. assertRegex ( output
, 'lookup 8' )
2829 output
= check_output ( 'ip rule list iif test1 priority 102' )
2831 self
. assertRegex ( output
, '102:' )
2832 self
. assertRegex ( output
, 'from 0.0.0.0/8' )
2833 self
. assertRegex ( output
, 'iif test1' )
2834 self
. assertRegex ( output
, 'lookup 10' )
2836 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2839 def test_routing_policy_rule_issue_11280 ( self
):
2840 copy_network_unit ( '25-routing-policy-rule-test1.network' , '11-dummy.netdev' ,
2841 '25-routing-policy-rule-dummy98.network' , '12-dummy.netdev' )
2843 for trial
in range ( 3 ):
2844 restart_networkd ( show_logs
=( trial
> 0 ))
2845 self
. wait_online ([ 'test1:degraded' , 'dummy98:degraded' ])
2847 output
= check_output ( 'ip rule list table 7' )
2849 self
. assertRegex ( output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7' )
2851 output
= check_output ( 'ip rule list table 8' )
2853 self
. assertRegex ( output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8' )
2855 def test_routing_policy_rule_reconfigure ( self
):
2856 copy_network_unit ( '25-routing-policy-rule-reconfigure2.network' , '11-dummy.netdev' )
2858 self
. wait_online ([ 'test1:degraded' ])
2860 output
= check_output ( 'ip rule list table 1011' )
2862 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2863 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2864 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2865 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2867 output
= check_output ( 'ip -6 rule list table 1011' )
2869 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2871 copy_network_unit ( '25-routing-policy-rule-reconfigure1.network' , '11-dummy.netdev' )
2873 self
. wait_online ([ 'test1:degraded' ])
2875 output
= check_output ( 'ip rule list table 1011' )
2877 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2878 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2879 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2880 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2882 output
= check_output ( 'ip -6 rule list table 1011' )
2884 self
. assertNotIn ( '10112: from all oif test1 lookup 1011' , output
)
2885 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2887 call ( 'ip rule delete priority 10111' )
2888 call ( 'ip rule delete priority 10112' )
2889 call ( 'ip rule delete priority 10113' )
2890 call ( 'ip rule delete priority 10114' )
2891 call ( 'ip -6 rule delete priority 10113' )
2893 output
= check_output ( 'ip rule list table 1011' )
2895 self
. assertEqual ( output
, '' )
2897 output
= check_output ( 'ip -6 rule list table 1011' )
2899 self
. assertEqual ( output
, '' )
2901 networkctl_reconfigure ( 'test1' )
2902 self
. wait_online ([ 'test1:degraded' ])
2904 output
= check_output ( 'ip rule list table 1011' )
2906 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2907 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2908 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2909 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2911 output
= check_output ( 'ip -6 rule list table 1011' )
2913 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2915 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable ()
2916 def test_routing_policy_rule_port_range ( self
):
2917 copy_network_unit ( '25-fibrule-port-range.network' , '11-dummy.netdev' )
2919 self
. wait_online ([ 'test1:degraded' ])
2921 output
= check_output ( 'ip rule' )
2923 self
. assertRegex ( output
, '111' )
2924 self
. assertRegex ( output
, 'from 192.168.100.18' )
2925 self
. assertRegex ( output
, '1123-1150' )
2926 self
. assertRegex ( output
, '3224-3290' )
2927 self
. assertRegex ( output
, 'tcp' )
2928 self
. assertRegex ( output
, 'lookup 7' )
2930 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable ()
2931 def test_routing_policy_rule_invert ( self
):
2932 copy_network_unit ( '25-fibrule-invert.network' , '11-dummy.netdev' )
2934 self
. wait_online ([ 'test1:degraded' ])
2936 output
= check_output ( 'ip rule' )
2938 self
. assertRegex ( output
, '111' )
2939 self
. assertRegex ( output
, 'not.*?from.*?192.168.100.18' )
2940 self
. assertRegex ( output
, 'tcp' )
2941 self
. assertRegex ( output
, 'lookup 7' )
2943 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable ()
2944 def test_routing_policy_rule_uidrange ( self
):
2945 copy_network_unit ( '25-fibrule-uidrange.network' , '11-dummy.netdev' )
2947 self
. wait_online ([ 'test1:degraded' ])
2949 output
= check_output ( 'ip rule' )
2951 self
. assertRegex ( output
, '111' )
2952 self
. assertRegex ( output
, 'from 192.168.100.18' )
2953 self
. assertRegex ( output
, 'lookup 7' )
2954 self
. assertRegex ( output
, 'uidrange 100-200' )
2956 def _test_route_static ( self
, manage_foreign_routes
):
2957 if not manage_foreign_routes
:
2958 copy_networkd_conf_dropin ( 'networkd-manage-foreign-routes-no.conf' )
2960 copy_network_unit ( '25-route-static.network' , '12-dummy.netdev' )
2962 self
. wait_online ([ 'dummy98:routable' ])
2964 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
2967 print ( '### ip -6 route show dev dummy98' )
2968 output
= check_output ( 'ip -6 route show dev dummy98' )
2970 self
. assertIn ( '2001:1234:5:8fff:ff:ff:ff:ff proto static' , output
)
2971 self
. assertIn ( '2001:1234:5:8f63::1 proto kernel' , output
)
2972 self
. assertIn ( '2001:1234:5:afff:ff:ff:ff:ff via fe80:0:222:4dff:ff:ff:ff:ff proto static' , output
)
2974 print ( '### ip -6 route show default' )
2975 output
= check_output ( 'ip -6 route show default' )
2977 self
. assertIn ( 'default' , output
)
2978 self
. assertIn ( 'via 2001:1234:5:8fff:ff:ff:ff:ff' , output
)
2980 print ( '### ip -4 route show dev dummy98' )
2981 output
= check_output ( 'ip -4 route show dev dummy98' )
2983 self
. assertIn ( '149.10.124.48/28 proto kernel scope link src 149.10.124.58' , output
)
2984 self
. assertIn ( '149.10.124.64 proto static scope link' , output
)
2985 self
. assertIn ( '169.254.0.0/16 proto static scope link metric 2048' , output
)
2986 self
. assertIn ( '192.168.1.1 proto static scope link initcwnd 20' , output
)
2987 self
. assertIn ( '192.168.1.2 proto static scope link initrwnd 30' , output
)
2988 self
. assertIn ( '192.168.1.3 proto static scope link advmss 30' , output
)
2989 self
. assertIn ( '192.168.1.4 proto static scope link hoplimit 122' , output
)
2990 self
. assertIn ( 'multicast 149.10.123.4 proto static' , output
)
2992 print ( '### ip -4 route show dev dummy98 default' )
2993 output
= check_output ( 'ip -4 route show dev dummy98 default' )
2995 self
. assertIn ( 'default via 149.10.125.65 proto static onlink' , output
)
2996 self
. assertIn ( 'default via 149.10.124.64 proto static' , output
)
2997 self
. assertIn ( 'default proto static' , output
)
2999 print ( '### ip -4 route show table local dev dummy98' )
3000 output
= check_output ( 'ip -4 route show table local dev dummy98' )
3002 self
. assertIn ( 'local 149.10.123.1 proto static scope host' , output
)
3003 self
. assertIn ( 'anycast 149.10.123.2 proto static scope link' , output
)
3004 self
. assertIn ( 'broadcast 149.10.123.3 proto static scope link' , output
)
3006 print ( '### ip -4 route show type blackhole' )
3007 output
= check_output ( 'ip -4 route show type blackhole' )
3009 self
. assertIn ( 'blackhole 202.54.1.2 proto static' , output
)
3011 print ( '### ip -4 route show type unreachable' )
3012 output
= check_output ( 'ip -4 route show type unreachable' )
3014 self
. assertIn ( 'unreachable 202.54.1.3 proto static' , output
)
3016 print ( '### ip -4 route show type prohibit' )
3017 output
= check_output ( 'ip -4 route show type prohibit' )
3019 self
. assertIn ( 'prohibit 202.54.1.4 proto static' , output
)
3021 print ( '### ip -6 route show type blackhole' )
3022 output
= check_output ( 'ip -6 route show type blackhole' )
3024 self
. assertIn ( 'blackhole 2001:1234:5678::2 dev lo proto static' , output
)
3026 print ( '### ip -6 route show type unreachable' )
3027 output
= check_output ( 'ip -6 route show type unreachable' )
3029 self
. assertIn ( 'unreachable 2001:1234:5678::3 dev lo proto static' , output
)
3031 print ( '### ip -6 route show type prohibit' )
3032 output
= check_output ( 'ip -6 route show type prohibit' )
3034 self
. assertIn ( 'prohibit 2001:1234:5678::4 dev lo proto static' , output
)
3036 print ( '### ip route show 192.168.10.1' )
3037 output
= check_output ( 'ip route show 192.168.10.1' )
3039 self
. assertIn ( '192.168.10.1 proto static' , output
)
3040 self
. assertIn ( 'nexthop via 149.10.124.59 dev dummy98 weight 10' , output
)
3041 self
. assertIn ( 'nexthop via 149.10.124.60 dev dummy98 weight 5' , output
)
3043 print ( '### ip route show 192.168.10.2' )
3044 output
= check_output ( 'ip route show 192.168.10.2' )
3046 # old ip command does not show IPv6 gateways...
3047 self
. assertIn ( '192.168.10.2 proto static' , output
)
3048 self
. assertIn ( 'nexthop' , output
)
3049 self
. assertIn ( 'dev dummy98 weight 10' , output
)
3050 self
. assertIn ( 'dev dummy98 weight 5' , output
)
3052 print ( '### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff' )
3053 output
= check_output ( 'ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff' )
3055 # old ip command does not show 'nexthop' keyword and weight...
3056 self
. assertIn ( '2001:1234:5:7fff:ff:ff:ff:ff' , output
)
3057 self
. assertIn ( 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98' , output
)
3058 self
. assertIn ( 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98' , output
)
3060 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3063 copy_network_unit ( '25-address-static.network' )
3065 self
. wait_online ([ 'dummy98:routable' ])
3067 # check all routes managed by Manager are removed
3068 print ( '### ip -4 route show type blackhole' )
3069 output
= check_output ( 'ip -4 route show type blackhole' )
3071 self
. assertEqual ( output
, '' )
3073 print ( '### ip -4 route show type unreachable' )
3074 output
= check_output ( 'ip -4 route show type unreachable' )
3076 self
. assertEqual ( output
, '' )
3078 print ( '### ip -4 route show type prohibit' )
3079 output
= check_output ( 'ip -4 route show type prohibit' )
3081 self
. assertEqual ( output
, '' )
3083 print ( '### ip -6 route show type blackhole' )
3084 output
= check_output ( 'ip -6 route show type blackhole' )
3086 self
. assertEqual ( output
, '' )
3088 print ( '### ip -6 route show type unreachable' )
3089 output
= check_output ( 'ip -6 route show type unreachable' )
3091 self
. assertEqual ( output
, '' )
3093 print ( '### ip -6 route show type prohibit' )
3094 output
= check_output ( 'ip -6 route show type prohibit' )
3096 self
. assertEqual ( output
, '' )
3098 remove_network_unit ( '25-address-static.network' )
3100 self
. wait_online ([ 'dummy98:routable' ])
3102 # check all routes managed by Manager are reconfigured
3103 print ( '### ip -4 route show type blackhole' )
3104 output
= check_output ( 'ip -4 route show type blackhole' )
3106 self
. assertIn ( 'blackhole 202.54.1.2 proto static' , output
)
3108 print ( '### ip -4 route show type unreachable' )
3109 output
= check_output ( 'ip -4 route show type unreachable' )
3111 self
. assertIn ( 'unreachable 202.54.1.3 proto static' , output
)
3113 print ( '### ip -4 route show type prohibit' )
3114 output
= check_output ( 'ip -4 route show type prohibit' )
3116 self
. assertIn ( 'prohibit 202.54.1.4 proto static' , output
)
3118 print ( '### ip -6 route show type blackhole' )
3119 output
= check_output ( 'ip -6 route show type blackhole' )
3121 self
. assertIn ( 'blackhole 2001:1234:5678::2 dev lo proto static' , output
)
3123 print ( '### ip -6 route show type unreachable' )
3124 output
= check_output ( 'ip -6 route show type unreachable' )
3126 self
. assertIn ( 'unreachable 2001:1234:5678::3 dev lo proto static' , output
)
3128 print ( '### ip -6 route show type prohibit' )
3129 output
= check_output ( 'ip -6 route show type prohibit' )
3131 self
. assertIn ( 'prohibit 2001:1234:5678::4 dev lo proto static' , output
)
3133 remove_link ( 'dummy98' )
3136 # check all routes managed by Manager are removed
3137 print ( '### ip -4 route show type blackhole' )
3138 output
= check_output ( 'ip -4 route show type blackhole' )
3140 self
. assertEqual ( output
, '' )
3142 print ( '### ip -4 route show type unreachable' )
3143 output
= check_output ( 'ip -4 route show type unreachable' )
3145 self
. assertEqual ( output
, '' )
3147 print ( '### ip -4 route show type prohibit' )
3148 output
= check_output ( 'ip -4 route show type prohibit' )
3150 self
. assertEqual ( output
, '' )
3152 print ( '### ip -6 route show type blackhole' )
3153 output
= check_output ( 'ip -6 route show type blackhole' )
3155 self
. assertEqual ( output
, '' )
3157 print ( '### ip -6 route show type unreachable' )
3158 output
= check_output ( 'ip -6 route show type unreachable' )
3160 self
. assertEqual ( output
, '' )
3162 print ( '### ip -6 route show type prohibit' )
3163 output
= check_output ( 'ip -6 route show type prohibit' )
3165 self
. assertEqual ( output
, '' )
3169 def test_route_static ( self
):
3171 for manage_foreign_routes
in [ True , False ]:
3177 print ( f
'### test_route_static(manage_foreign_routes= {manage_foreign_routes} )' )
3178 with self
. subTest ( manage_foreign_routes
= manage_foreign_routes
):
3179 self
._ test
_ route
_ static
( manage_foreign_routes
)
3181 @expectedFailureIfRTA_VIAIsNotSupported ()
3182 def test_route_via_ipv6 ( self
):
3183 copy_network_unit ( '25-route-via-ipv6.network' , '12-dummy.netdev' )
3185 self
. wait_online ([ 'dummy98:routable' ])
3187 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
3190 print ( '### ip -6 route show dev dummy98' )
3191 output
= check_output ( 'ip -6 route show dev dummy98' )
3193 self
. assertRegex ( output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static' )
3194 self
. assertRegex ( output
, '2001:1234:5:8f63::1 proto kernel' )
3196 print ( '### ip -4 route show dev dummy98' )
3197 output
= check_output ( 'ip -4 route show dev dummy98' )
3199 self
. assertRegex ( output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58' )
3200 self
. assertRegex ( output
, '149.10.124.66 via inet6 2001:1234:5:8fff:ff:ff:ff:ff proto static' )
3202 @expectedFailureIfModuleIsNotAvailable ( 'tcp_dctcp' )
3203 def test_route_congctl ( self
):
3204 copy_network_unit ( '25-route-congctl.network' , '12-dummy.netdev' )
3206 self
. wait_online ([ 'dummy98:routable' ])
3208 print ( '### ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff' )
3209 output
= check_output ( 'ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff' )
3211 self
. assertIn ( '2001:1234:5:8fff:ff:ff:ff:ff proto static' , output
)
3212 self
. assertIn ( 'congctl dctcp' , output
)
3214 print ( '### ip -4 route show dev dummy98 149.10.124.66' )
3215 output
= check_output ( 'ip -4 route show dev dummy98 149.10.124.66' )
3217 self
. assertIn ( '149.10.124.66 proto static' , output
)
3218 self
. assertIn ( 'congctl dctcp' , output
)
3219 self
. assertIn ( 'rto_min 300s' , output
)
3221 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
3222 def test_route_vrf ( self
):
3223 copy_network_unit ( '25-route-vrf.network' , '12-dummy.netdev' ,
3224 '25-vrf.netdev' , '25-vrf.network' )
3226 self
. wait_online ([ 'dummy98:routable' , 'vrf99:carrier' ])
3228 output
= check_output ( 'ip route show vrf vrf99' )
3230 self
. assertRegex ( output
, 'default via 192.168.100.1' )
3232 output
= check_output ( 'ip route show' )
3234 self
. assertNotRegex ( output
, 'default via 192.168.100.1' )
3236 def test_gateway_reconfigure ( self
):
3237 copy_network_unit ( '25-gateway-static.network' , '12-dummy.netdev' )
3239 self
. wait_online ([ 'dummy98:routable' ])
3240 print ( '### ip -4 route show dev dummy98 default' )
3241 output
= check_output ( 'ip -4 route show dev dummy98 default' )
3243 self
. assertIn ( 'default via 149.10.124.59 proto static' , output
)
3244 self
. assertNotIn ( '149.10.124.60' , output
)
3246 remove_network_unit ( '25-gateway-static.network' )
3247 copy_network_unit ( '25-gateway-next-static.network' )
3249 self
. wait_online ([ 'dummy98:routable' ])
3250 print ( '### ip -4 route show dev dummy98 default' )
3251 output
= check_output ( 'ip -4 route show dev dummy98 default' )
3253 self
. assertNotIn ( '149.10.124.59' , output
)
3254 self
. assertIn ( 'default via 149.10.124.60 proto static' , output
)
3256 def test_ip_route_ipv6_src_route ( self
):
3257 # a dummy device does not make the addresses go through tentative state, so we
3258 # reuse a bond from an earlier test, which does make the addresses go through
3259 # tentative state, and do our test on that
3260 copy_network_unit ( '23-active-slave.network' , '25-route-ipv6-src.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
3262 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:routable' ])
3264 output
= check_output ( 'ip -6 route list dev bond199' )
3266 self
. assertIn ( 'abcd::/16 via 2001:1234:56:8f63::1:1 proto static src 2001:1234:56:8f63::2' , output
)
3268 def test_route_preferred_source_with_existing_address ( self
):
3270 copy_network_unit ( '25-route-preferred-source.network' , '12-dummy.netdev' )
3275 networkctl_reconfigure ( 'dummy98' )
3277 self
. wait_online ([ 'dummy98:routable' ])
3279 output
= check_output ( 'ip -6 route list dev dummy98' )
3281 self
. assertIn ( 'abcd::/16 via 2001:1234:56:8f63::1:1 proto static src 2001:1234:56:8f63::1' , output
)
3283 def test_ip_link_mac_address ( self
):
3284 copy_network_unit ( '25-address-link-section.network' , '12-dummy.netdev' )
3286 self
. wait_online ([ 'dummy98:degraded' ])
3288 output
= check_output ( 'ip link show dummy98' )
3290 self
. assertRegex ( output
, '00:01:02:aa:bb:cc' )
3292 def test_ip_link_unmanaged ( self
):
3293 copy_network_unit ( '25-link-section-unmanaged.network' , '12-dummy.netdev' )
3296 self
. wait_operstate ( 'dummy98' , 'off' , setup_state
= 'unmanaged' )
3298 def test_ipv6_address_label ( self
):
3299 copy_network_unit ( '25-ipv6-address-label-section.network' , '12-dummy.netdev' )
3301 self
. wait_online ([ 'dummy98:degraded' ])
3303 output
= check_output ( 'ip addrlabel list' )
3305 self
. assertRegex ( output
, '2004:da8:1::/64' )
3307 def test_ipv6_proxy_ndp ( self
):
3308 copy_network_unit ( '25-ipv6-proxy-ndp.network' , '12-dummy.netdev' )
3311 self
. wait_online ([ 'dummy98:routable' ])
3313 output
= check_output ( 'ip neighbor show proxy dev dummy98' )
3315 for i
in range ( 1 , 5 ):
3316 self
. assertRegex ( output
, f
'2607:5300:203:5215: {i} ::1 *proxy' )
3318 def test_neighbor_section ( self
):
3319 copy_network_unit ( '25-neighbor-section.network' , '12-dummy.netdev' , copy_dropins
= False )
3321 self
. wait_online ([ 'dummy98:degraded' ])
3323 print ( '### ip neigh list dev dummy98' )
3324 output
= check_output ( 'ip neigh list dev dummy98' )
3326 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:02:65 PERMANENT' , output
)
3327 self
. assertIn ( '2004:da8:1::1 lladdr 00:00:5e:00:02:66 PERMANENT' , output
)
3328 self
. assertNotIn ( '2004:da8:1:0::2' , output
)
3329 self
. assertNotIn ( '192.168.10.2' , output
)
3330 self
. assertNotIn ( '00:00:5e:00:02:67' , output
)
3332 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3335 copy_network_unit ( '25-neighbor-section.network.d/override.conf' )
3337 self
. wait_online ([ 'dummy98:degraded' ])
3339 print ( '### ip neigh list dev dummy98 (after reloading)' )
3340 output
= check_output ( 'ip neigh list dev dummy98' )
3342 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:03:65 PERMANENT' , output
)
3343 self
. assertIn ( '2004:da8:1::1 lladdr 00:00:5e:00:03:66 PERMANENT' , output
)
3344 self
. assertNotIn ( '2004:da8:1:0::2' , output
)
3345 self
. assertNotIn ( '192.168.10.2' , output
)
3346 self
. assertNotIn ( '00:00:5e:00:02' , output
)
3348 def test_neighbor_reconfigure ( self
):
3349 copy_network_unit ( '25-neighbor-section.network' , '12-dummy.netdev' , copy_dropins
= False )
3351 self
. wait_online ([ 'dummy98:degraded' ])
3353 print ( '### ip neigh list dev dummy98' )
3354 output
= check_output ( 'ip neigh list dev dummy98' )
3356 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:02:65 PERMANENT' , output
)
3357 self
. assertIn ( '2004:da8:1::1 lladdr 00:00:5e:00:02:66 PERMANENT' , output
)
3359 remove_network_unit ( '25-neighbor-section.network' )
3360 copy_network_unit ( '25-neighbor-next.network' )
3362 self
. wait_online ([ 'dummy98:degraded' ])
3363 print ( '### ip neigh list dev dummy98' )
3364 output
= check_output ( 'ip neigh list dev dummy98' )
3366 self
. assertNotIn ( '00:00:5e:00:02:65' , output
)
3367 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:02:66 PERMANENT' , output
)
3368 self
. assertNotIn ( '2004:da8:1::1' , output
)
3370 def test_neighbor_gre ( self
):
3371 copy_network_unit ( '25-neighbor-ip.network' , '25-neighbor-ipv6.network' , '25-neighbor-ip-dummy.network' ,
3372 '12-dummy.netdev' , '25-gre-tunnel-remote-any.netdev' , '25-ip6gre-tunnel-remote-any.netdev' )
3374 self
. wait_online ([ 'dummy98:degraded' , 'gretun97:routable' , 'ip6gretun97:routable' ], timeout
= '40s' )
3376 output
= check_output ( 'ip neigh list dev gretun97' )
3378 self
. assertIn ( '10.0.0.22 lladdr 10.65.223.239 PERMANENT' , output
)
3379 self
. assertNotIn ( '10.0.0.23' , output
)
3381 output
= check_output ( 'ip neigh list dev ip6gretun97' )
3383 self
. assertRegex ( output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT' )
3384 self
. assertNotIn ( '2001:db8:0:f102::18' , output
)
3386 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3389 def test_link_local_addressing ( self
):
3390 copy_network_unit ( '25-link-local-addressing-yes.network' , '11-dummy.netdev' ,
3391 '25-link-local-addressing-no.network' , '12-dummy.netdev' )
3393 self
. wait_online ([ 'test1:degraded' , 'dummy98:carrier' ])
3395 output
= check_output ( 'ip address show dev test1' )
3397 self
. assertRegex ( output
, 'inet .* scope link' )
3398 self
. assertRegex ( output
, 'inet6 .* scope link' )
3400 output
= check_output ( 'ip address show dev dummy98' )
3402 self
. assertNotRegex ( output
, 'inet6* .* scope link' )
3404 # Documentation/networking/ip-sysctl.txt
3406 # addr_gen_mode - INTEGER
3407 # Defines how link-local and autoconf addresses are generated.
3409 # 0: generate address based on EUI64 (default)
3410 # 1: do no generate a link-local address, use EUI64 for addresses generated
3412 # 2: generate stable privacy addresses, using the secret from
3413 # stable_secret (RFC7217)
3414 # 3: generate stable privacy addresses, using a random secret if unset
3416 self
. check_ipv6_sysctl_attr ( 'test1' , 'stable_secret' , '0123:4567:89ab:cdef:0123:4567:89ab:cdef' )
3417 self
. check_ipv6_sysctl_attr ( 'test1' , 'addr_gen_mode' , '2' )
3418 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'addr_gen_mode' , '1' )
3420 def test_link_local_addressing_ipv6ll ( self
):
3421 copy_network_unit ( '26-link-local-addressing-ipv6.network' , '12-dummy.netdev' )
3423 self
. wait_online ([ 'dummy98:degraded' ])
3425 # An IPv6LL address exists by default.
3426 output
= check_output ( 'ip address show dev dummy98' )
3428 self
. assertRegex ( output
, 'inet6 .* scope link' )
3430 copy_network_unit ( '25-link-local-addressing-no.network' )
3432 self
. wait_online ([ 'dummy98:carrier' ])
3434 # Check if the IPv6LL address is removed.
3435 output
= check_output ( 'ip address show dev dummy98' )
3437 self
. assertNotRegex ( output
, 'inet6 .* scope link' )
3439 remove_network_unit ( '25-link-local-addressing-no.network' )
3441 self
. wait_online ([ 'dummy98:degraded' ])
3443 # Check if a new IPv6LL address is assigned.
3444 output
= check_output ( 'ip address show dev dummy98' )
3446 self
. assertRegex ( output
, 'inet6 .* scope link' )
3448 def test_sysctl ( self
):
3449 copy_networkd_conf_dropin ( '25-global-ipv6-privacy-extensions.conf' )
3450 copy_network_unit ( '25-sysctl.network' , '12-dummy.netdev' , copy_dropins
= False )
3452 self
. wait_online ([ 'dummy98:degraded' ])
3454 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
3455 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'use_tempaddr' , '1' )
3456 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'dad_transmits' , '3' )
3457 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'hop_limit' , '5' )
3458 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'proxy_ndp' , '1' )
3459 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
3460 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'proxy_arp' , '1' )
3461 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'accept_local' , '1' )
3462 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'rp_filter' , '0' )
3464 copy_network_unit ( '25-sysctl.network.d/25-ipv6-privacy-extensions.conf' )
3466 self
. wait_online ([ 'dummy98:degraded' ])
3468 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'use_tempaddr' , '2' )
3470 def test_sysctl_disable_ipv6 ( self
):
3471 copy_network_unit ( '25-sysctl-disable-ipv6.network' , '12-dummy.netdev' )
3473 print ( '## Disable ipv6' )
3474 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=1' )
3475 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=1' )
3478 self
. wait_online ([ 'dummy98:routable' ])
3480 output
= check_output ( 'ip -4 address show dummy98' )
3482 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3483 output
= check_output ( 'ip -6 address show dummy98' )
3485 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3486 self
. assertRegex ( output
, 'inet6 .* scope link' )
3487 output
= check_output ( 'ip -4 route show dev dummy98' )
3489 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3490 output
= check_output ( 'ip -6 route show default' )
3492 self
. assertRegex ( output
, 'default' )
3493 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3495 remove_link ( 'dummy98' )
3497 print ( '## Enable ipv6' )
3498 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=0' )
3499 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=0' )
3502 self
. wait_online ([ 'dummy98:routable' ])
3504 output
= check_output ( 'ip -4 address show dummy98' )
3506 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3507 output
= check_output ( 'ip -6 address show dummy98' )
3509 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3510 self
. assertRegex ( output
, 'inet6 .* scope link' )
3511 output
= check_output ( 'ip -4 route show dev dummy98' )
3513 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3514 output
= check_output ( 'ip -6 route show default' )
3516 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3518 def test_bind_carrier ( self
):
3519 copy_network_unit ( '25-bind-carrier.network' , '11-dummy.netdev' )
3522 # no bound interface.
3523 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
3524 output
= check_output ( 'ip address show test1' )
3526 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3527 self
. assertIn ( 'DOWN' , output
)
3528 self
. assertNotIn ( '192.168.10' , output
)
3530 # add one bound interface. The interface will be up.
3531 check_output ( 'ip link add dummy98 type dummy' )
3532 check_output ( 'ip link set dummy98 up' )
3533 self
. wait_online ([ 'test1:routable' ])
3534 output
= check_output ( 'ip address show test1' )
3536 self
. assertIn ( 'UP,LOWER_UP' , output
)
3537 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3539 # add another bound interface. The interface is still up.
3540 check_output ( 'ip link add dummy99 type dummy' )
3541 check_output ( 'ip link set dummy99 up' )
3542 self
. wait_operstate ( 'dummy99' , 'degraded' , setup_state
= 'unmanaged' )
3543 output
= check_output ( 'ip address show test1' )
3545 self
. assertIn ( 'UP,LOWER_UP' , output
)
3546 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3548 # remove one of the bound interfaces. The interface is still up
3549 remove_link ( 'dummy98' )
3550 output
= check_output ( 'ip address show test1' )
3552 self
. assertIn ( 'UP,LOWER_UP' , output
)
3553 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3555 # bring down the remaining bound interface. The interface will be down.
3556 check_output ( 'ip link set dummy99 down' )
3557 self
. wait_operstate ( 'test1' , 'off' )
3558 self
. wait_address_dropped ( 'test1' , r
'192.168.10' , ipv
= '-4' , timeout_sec
= 10 )
3559 output
= check_output ( 'ip address show test1' )
3561 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3562 self
. assertIn ( 'DOWN' , output
)
3563 self
. assertNotIn ( '192.168.10' , output
)
3565 # bring up the bound interface. The interface will be up.
3566 check_output ( 'ip link set dummy99 up' )
3567 self
. wait_online ([ 'test1:routable' ])
3568 output
= check_output ( 'ip address show test1' )
3570 self
. assertIn ( 'UP,LOWER_UP' , output
)
3571 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3573 # remove the remaining bound interface. The interface will be down.
3574 remove_link ( 'dummy99' )
3575 self
. wait_operstate ( 'test1' , 'off' )
3576 self
. wait_address_dropped ( 'test1' , r
'192.168.10' , ipv
= '-4' , timeout_sec
= 10 )
3577 output
= check_output ( 'ip address show test1' )
3579 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3580 self
. assertIn ( 'DOWN' , output
)
3581 self
. assertNotIn ( '192.168.10' , output
)
3583 # re-add one bound interface. The interface will be up.
3584 check_output ( 'ip link add dummy98 type dummy' )
3585 check_output ( 'ip link set dummy98 up' )
3586 self
. wait_online ([ 'test1:routable' ])
3587 output
= check_output ( 'ip address show test1' )
3589 self
. assertIn ( 'UP,LOWER_UP' , output
)
3590 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3592 def _test_activation_policy ( self
, interface
, test
):
3593 conffile
= '25-activation-policy.network'
3595 conffile
= f
' {conffile} .d/ {test} .conf'
3596 if interface
== 'vlan99' :
3597 copy_network_unit ( '21-vlan.netdev' , '21-vlan-test1.network' )
3598 copy_network_unit ( '11-dummy.netdev' , conffile
, copy_dropins
= False )
3601 always
= test
. startswith ( 'always' )
3602 initial_up
= test
!= 'manual' and not test
. endswith ( 'down' ) # note: default is up
3603 expect_up
= initial_up
3604 next_up
= not expect_up
3606 if test
. endswith ( 'down' ):
3607 self
. wait_activated ( interface
)
3609 for iteration
in range ( 4 ):
3610 with self
. subTest ( iteration
= iteration
, expect_up
= expect_up
):
3611 operstate
= 'routable' if expect_up
else 'off'
3612 setup_state
= 'configured' if expect_up
else ( 'configuring' if iteration
== 0 else None )
3613 self
. wait_operstate ( interface
, operstate
, setup_state
= setup_state
, setup_timeout
= 20 )
3616 self
. assertIn ( 'UP' , check_output ( f
'ip link show {interface} ' ))
3617 self
. assertIn ( '192.168.10.30/24' , check_output ( f
'ip address show {interface} ' ))
3618 self
. assertIn ( 'default via 192.168.10.1' , check_output ( f
'ip route show dev {interface} ' ))
3620 self
. assertIn ( 'DOWN' , check_output ( f
'ip link show {interface} ' ))
3623 check_output ( f
'ip link set dev {interface} up' )
3625 check_output ( f
'ip link set dev {interface} down' )
3626 expect_up
= initial_up
if always
else next_up
3627 next_up
= not next_up
3631 def test_activation_policy ( self
):
3633 for interface
in [ 'test1' , 'vlan99' ]:
3634 for test
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , '' ]:
3640 print ( f
'### test_activation_policy(interface= {interface} , test= {test} )' )
3641 with self
. subTest ( interface
= interface
, test
= test
):
3642 self
._ test
_ activation
_ policy
( interface
, test
)
3644 def _test_activation_policy_required_for_online ( self
, policy
, required
):
3645 conffile
= '25-activation-policy.network'
3646 units
= [ '11-dummy.netdev' , '12-dummy.netdev' , '12-dummy.network' , conffile
]
3648 units
+= [ f
' {conffile} .d/ {policy} .conf' ]
3650 units
+= [ f
' {conffile} .d/required- {required} .conf' ]
3651 copy_network_unit (* units
, copy_dropins
= False )
3654 if policy
. endswith ( 'down' ):
3655 self
. wait_activated ( 'test1' )
3657 if policy
. endswith ( 'down' ) or policy
== 'manual' :
3658 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
3660 self
. wait_online ([ 'test1' ])
3662 if policy
== 'always-down' :
3663 # if always-down, required for online is forced to no
3666 # otherwise if required for online is specified, it should match that
3667 expected
= required
== 'yes'
3669 # otherwise if only policy specified, required for online defaults to
3670 # true if policy is up, always-up, or bound
3671 expected
= policy
. endswith ( 'up' ) or policy
== 'bound'
3673 # default is true, if neither are specified
3676 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
3679 yesno
= 'yes' if expected
else 'no'
3680 self
. assertRegex ( output
, f
'Required For Online: {yesno} ' )
3682 def test_activation_policy_required_for_online ( self
):
3684 for policy
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , 'bound' , '' ]:
3685 for required
in [ 'yes' , 'no' , '' ]:
3691 print ( f
'### test_activation_policy_required_for_online(policy= {policy} , required= {required} )' )
3692 with self
. subTest ( policy
= policy
, required
= required
):
3693 self
._ test
_ activation
_ policy
_ required
_ for
_ online
( policy
, required
)
3695 def test_domain ( self
):
3696 copy_network_unit ( '12-dummy.netdev' , '24-search-domain.network' )
3698 self
. wait_online ([ 'dummy98:routable' ])
3700 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
3702 self
. assertRegex ( output
, 'Address: 192.168.42.100' )
3703 self
. assertRegex ( output
, 'DNS: 192.168.42.1' )
3704 self
. assertRegex ( output
, 'Search Domains: one' )
3706 def test_keep_configuration_static ( self
):
3707 check_output ( 'ip link add name dummy98 type dummy' )
3708 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
3709 check_output ( 'ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500' )
3710 output
= check_output ( 'ip address show dummy98' )
3712 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
3713 self
. assertRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
3714 output
= check_output ( 'ip route show dev dummy98' )
3717 copy_network_unit ( '24-keep-configuration-static.network' )
3719 self
. wait_online ([ 'dummy98:routable' ])
3721 output
= check_output ( 'ip address show dummy98' )
3723 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
3724 self
. assertNotRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
3726 @expectedFailureIfNexthopIsNotAvailable ()
3727 def test_nexthop ( self
):
3728 def check_nexthop ( self
):
3729 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
3731 output
= check_output ( 'ip nexthop list dev veth99' )
3733 self
. assertIn ( 'id 1 via 192.168.5.1 dev veth99' , output
)
3734 self
. assertIn ( 'id 2 via 2001:1234:5:8f63::2 dev veth99' , output
)
3735 self
. assertIn ( 'id 3 dev veth99' , output
)
3736 self
. assertIn ( 'id 4 dev veth99' , output
)
3737 self
. assertRegex ( output
, 'id 5 via 192.168.10.1 dev veth99 .*onlink' )
3738 self
. assertIn ( 'id 8 via fe80:0:222:4dff:ff:ff:ff:ff dev veth99' , output
)
3739 self
. assertRegex ( output
, r
'id [0-9]* via 192.168.5.2 dev veth99' )
3741 output
= check_output ( 'ip nexthop list dev dummy98' )
3743 self
. assertIn ( 'id 20 via 192.168.20.1 dev dummy98' , output
)
3745 # kernel manages blackhole nexthops on lo
3746 output
= check_output ( 'ip nexthop list dev lo' )
3748 self
. assertIn ( 'id 6 blackhole' , output
)
3749 self
. assertIn ( 'id 7 blackhole' , output
)
3751 # group nexthops are shown with -0 option
3752 output
= check_output ( 'ip -0 nexthop list id 21' )
3754 self
. assertRegex ( output
, r
'id 21 group (1,3/20|20/1,3)' )
3756 output
= check_output ( 'ip route show dev veth99 10.10.10.10' )
3758 self
. assertEqual ( '10.10.10.10 nhid 1 via 192.168.5.1 proto static' , output
)
3760 output
= check_output ( 'ip route show dev veth99 10.10.10.11' )
3762 self
. assertEqual ( '10.10.10.11 nhid 2 via inet6 2001:1234:5:8f63::2 proto static' , output
)
3764 output
= check_output ( 'ip route show dev veth99 10.10.10.12' )
3766 self
. assertEqual ( '10.10.10.12 nhid 5 via 192.168.10.1 proto static onlink' , output
)
3768 output
= check_output ( 'ip -6 route show dev veth99 2001:1234:5:8f62::1' )
3770 self
. assertEqual ( '2001:1234:5:8f62::1 nhid 2 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium' , output
)
3772 output
= check_output ( 'ip route show 10.10.10.13' )
3774 self
. assertEqual ( 'blackhole 10.10.10.13 nhid 6 dev lo proto static' , output
)
3776 output
= check_output ( 'ip -6 route show 2001:1234:5:8f62::2' )
3778 self
. assertEqual ( 'blackhole 2001:1234:5:8f62::2 nhid 7 dev lo proto static metric 1024 pref medium' , output
)
3780 output
= check_output ( 'ip route show 10.10.10.14' )
3782 self
. assertIn ( '10.10.10.14 nhid 21 proto static' , output
)
3783 self
. assertIn ( 'nexthop via 192.168.20.1 dev dummy98 weight 1' , output
)
3784 self
. assertIn ( 'nexthop via 192.168.5.1 dev veth99 weight 3' , output
)
3786 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3789 copy_network_unit ( '25-nexthop.network' , '25-veth.netdev' , '25-veth-peer.network' ,
3790 '12-dummy.netdev' , '25-nexthop-dummy.network' )
3795 remove_network_unit ( '25-nexthop.network' )
3796 copy_network_unit ( '25-nexthop-nothing.network' )
3798 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
3800 output
= check_output ( 'ip nexthop list dev veth99' )
3802 self
. assertEqual ( output
, '' )
3803 output
= check_output ( 'ip nexthop list dev lo' )
3805 self
. assertEqual ( output
, '' )
3807 remove_network_unit ( '25-nexthop-nothing.network' )
3808 copy_network_unit ( '25-nexthop.network' )
3809 networkctl_reconfigure ( 'dummy98' )
3814 remove_link ( 'veth99' )
3817 output
= check_output ( 'ip nexthop list dev lo' )
3819 self
. assertEqual ( output
, '' )
3821 class NetworkdTCTests ( unittest
. TestCase
, Utilities
):
3829 @expectedFailureIfModuleIsNotAvailable ( 'sch_cake' )
3830 def test_qdisc_cake ( self
):
3831 copy_network_unit ( '25-qdisc-cake.network' , '12-dummy.netdev' )
3833 self
. wait_online ([ 'dummy98:routable' ])
3835 output
= check_output ( 'tc qdisc show dev dummy98' )
3837 self
. assertIn ( 'qdisc cake 3a: root' , output
)
3838 self
. assertIn ( 'bandwidth 500Mbit' , output
)
3839 self
. assertIn ( 'autorate-ingress' , output
)
3840 self
. assertIn ( 'diffserv8' , output
)
3841 self
. assertIn ( 'dual-dsthost' , output
)
3842 self
. assertIn ( ' nat' , output
)
3843 self
. assertIn ( ' wash' , output
)
3844 self
. assertIn ( ' split-gso' , output
)
3845 self
. assertIn ( ' raw' , output
)
3846 self
. assertIn ( ' atm' , output
)
3847 self
. assertIn ( 'overhead 128' , output
)
3848 self
. assertIn ( 'mpu 20' , output
)
3849 self
. assertIn ( 'fwmark 0xff00' , output
)
3850 self
. assertIn ( 'rtt 1s' , output
)
3851 self
. assertIn ( 'ack-filter-aggressive' , output
)
3853 @expectedFailureIfModuleIsNotAvailable ( 'sch_codel' )
3854 def test_qdisc_codel ( self
):
3855 copy_network_unit ( '25-qdisc-codel.network' , '12-dummy.netdev' )
3857 self
. wait_online ([ 'dummy98:routable' ])
3859 output
= check_output ( 'tc qdisc show dev dummy98' )
3861 self
. assertRegex ( output
, 'qdisc codel 33: root' )
3862 self
. assertRegex ( output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn' )
3864 @expectedFailureIfModuleIsNotAvailable ( 'sch_drr' )
3865 def test_qdisc_drr ( self
):
3866 copy_network_unit ( '25-qdisc-drr.network' , '12-dummy.netdev' )
3868 self
. wait_online ([ 'dummy98:routable' ])
3870 output
= check_output ( 'tc qdisc show dev dummy98' )
3872 self
. assertRegex ( output
, 'qdisc drr 2: root' )
3873 output
= check_output ( 'tc class show dev dummy98' )
3875 self
. assertRegex ( output
, 'class drr 2:30 root quantum 2000b' )
3877 @expectedFailureIfModuleIsNotAvailable ( 'sch_ets' )
3878 def test_qdisc_ets ( self
):
3879 copy_network_unit ( '25-qdisc-ets.network' , '12-dummy.netdev' )
3881 self
. wait_online ([ 'dummy98:routable' ])
3883 output
= check_output ( 'tc qdisc show dev dummy98' )
3886 self
. assertRegex ( output
, 'qdisc ets 3a: root' )
3887 self
. assertRegex ( output
, 'bands 10 strict 3' )
3888 self
. assertRegex ( output
, 'quanta 1 2 3 4 5' )
3889 self
. assertRegex ( output
, 'priomap 3 4 5 6 7' )
3891 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq' )
3892 def test_qdisc_fq ( self
):
3893 copy_network_unit ( '25-qdisc-fq.network' , '12-dummy.netdev' )
3895 self
. wait_online ([ 'dummy98:routable' ])
3897 output
= check_output ( 'tc qdisc show dev dummy98' )
3899 self
. assertRegex ( output
, 'qdisc fq 32: root' )
3900 self
. assertRegex ( output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511' )
3901 self
. assertRegex ( output
, 'quantum 1500' )
3902 self
. assertRegex ( output
, 'initial_quantum 13000' )
3903 self
. assertRegex ( output
, 'maxrate 1Mbit' )
3905 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_codel' )
3906 def test_qdisc_fq_codel ( self
):
3907 copy_network_unit ( '25-qdisc-fq_codel.network' , '12-dummy.netdev' )
3909 self
. wait_online ([ 'dummy98:routable' ])
3911 output
= check_output ( 'tc qdisc show dev dummy98' )
3913 self
. assertRegex ( output
, 'qdisc fq_codel 34: root' )
3914 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' )
3916 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_pie' )
3917 def test_qdisc_fq_pie ( self
):
3918 copy_network_unit ( '25-qdisc-fq_pie.network' , '12-dummy.netdev' )
3920 self
. wait_online ([ 'dummy98:routable' ])
3922 output
= check_output ( 'tc qdisc show dev dummy98' )
3925 self
. assertRegex ( output
, 'qdisc fq_pie 3a: root' )
3926 self
. assertRegex ( output
, 'limit 200000p' )
3928 @expectedFailureIfModuleIsNotAvailable ( 'sch_gred' )
3929 def test_qdisc_gred ( self
):
3930 copy_network_unit ( '25-qdisc-gred.network' , '12-dummy.netdev' )
3932 self
. wait_online ([ 'dummy98:routable' ])
3934 output
= check_output ( 'tc qdisc show dev dummy98' )
3936 self
. assertRegex ( output
, 'qdisc gred 38: root' )
3937 self
. assertRegex ( output
, 'vqs 12 default 10 grio' )
3939 @expectedFailureIfModuleIsNotAvailable ( 'sch_hhf' )
3940 def test_qdisc_hhf ( self
):
3941 copy_network_unit ( '25-qdisc-hhf.network' , '12-dummy.netdev' )
3943 self
. wait_online ([ 'dummy98:routable' ])
3945 output
= check_output ( 'tc qdisc show dev dummy98' )
3947 self
. assertRegex ( output
, 'qdisc hhf 3a: root' )
3948 self
. assertRegex ( output
, 'limit 1022p' )
3950 @expectedFailureIfModuleIsNotAvailable ( 'sch_htb' )
3951 def test_qdisc_htb_fifo ( self
):
3952 copy_network_unit ( '25-qdisc-htb-fifo.network' , '12-dummy.netdev' )
3954 self
. wait_online ([ 'dummy98:routable' ])
3956 output
= check_output ( 'tc qdisc show dev dummy98' )
3958 self
. assertRegex ( output
, 'qdisc htb 2: root' )
3959 self
. assertRegex ( output
, r
'default (0x30|30)' )
3961 self
. assertRegex ( output
, 'qdisc pfifo 37: parent 2:37' )
3962 self
. assertRegex ( output
, 'limit 100000p' )
3964 self
. assertRegex ( output
, 'qdisc bfifo 3a: parent 2:3a' )
3965 self
. assertRegex ( output
, 'limit 1000000' )
3967 self
. assertRegex ( output
, 'qdisc pfifo_head_drop 3b: parent 2:3b' )
3968 self
. assertRegex ( output
, 'limit 1023p' )
3970 self
. assertRegex ( output
, 'qdisc pfifo_fast 3c: parent 2:3c' )
3972 output
= check_output ( 'tc -d class show dev dummy98' )
3974 # Here (:|prio) is a workaround for a bug in iproute2 v6.2.0 caused by
3975 # https://github.com/shemminger/iproute2/commit/010a8388aea11e767ba3a2506728b9ad9760df0e
3976 # which is fixed in v6.3.0 by
3977 # https://github.com/shemminger/iproute2/commit/4e0e56e0ef05387f7f5d8ab41fe6ec6a1897b26d
3978 self
. assertRegex ( output
, 'class htb 2:37 root leaf 37(:|prio) ' )
3979 self
. assertRegex ( output
, 'class htb 2:3a root leaf 3a(:|prio) ' )
3980 self
. assertRegex ( output
, 'class htb 2:3b root leaf 3b(:|prio) ' )
3981 self
. assertRegex ( output
, 'class htb 2:3c root leaf 3c(:|prio) ' )
3982 self
. assertRegex ( output
, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit' )
3983 self
. assertRegex ( output
, 'burst 123456' )
3984 self
. assertRegex ( output
, 'cburst 123457' )
3986 @expectedFailureIfModuleIsNotAvailable ( 'sch_ingress' )
3987 def test_qdisc_ingress ( self
):
3988 copy_network_unit ( '25-qdisc-clsact.network' , '12-dummy.netdev' ,
3989 '25-qdisc-ingress.network' , '11-dummy.netdev' )
3991 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' ])
3993 output
= check_output ( 'tc qdisc show dev dummy98' )
3995 self
. assertRegex ( output
, 'qdisc clsact' )
3997 output
= check_output ( 'tc qdisc show dev test1' )
3999 self
. assertRegex ( output
, 'qdisc ingress' )
4001 @expectedFailureIfModuleIsNotAvailable ( 'sch_netem' )
4002 def test_qdisc_netem ( self
):
4003 copy_network_unit ( '25-qdisc-netem.network' , '12-dummy.netdev' ,
4004 '25-qdisc-netem-compat.network' , '11-dummy.netdev' )
4006 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' ])
4008 output
= check_output ( 'tc qdisc show dev dummy98' )
4010 self
. assertRegex ( output
, 'qdisc netem 30: root' )
4011 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
4013 output
= check_output ( 'tc qdisc show dev test1' )
4015 self
. assertRegex ( output
, 'qdisc netem [0-9a-f]*: root' )
4016 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
4018 @expectedFailureIfModuleIsNotAvailable ( 'sch_pie' )
4019 def test_qdisc_pie ( self
):
4020 copy_network_unit ( '25-qdisc-pie.network' , '12-dummy.netdev' )
4022 self
. wait_online ([ 'dummy98:routable' ])
4024 output
= check_output ( 'tc qdisc show dev dummy98' )
4026 self
. assertRegex ( output
, 'qdisc pie 3a: root' )
4027 self
. assertRegex ( output
, 'limit 200000' )
4029 @expectedFailureIfModuleIsNotAvailable ( 'sch_qfq' )
4030 def test_qdisc_qfq ( self
):
4031 copy_network_unit ( '25-qdisc-qfq.network' , '12-dummy.netdev' )
4033 self
. wait_online ([ 'dummy98:routable' ])
4035 output
= check_output ( 'tc qdisc show dev dummy98' )
4037 self
. assertRegex ( output
, 'qdisc qfq 2: root' )
4038 output
= check_output ( 'tc class show dev dummy98' )
4040 self
. assertRegex ( output
, 'class qfq 2:30 root weight 2 maxpkt 16000' )
4041 self
. assertRegex ( output
, 'class qfq 2:31 root weight 10 maxpkt 8000' )
4043 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfb' )
4044 def test_qdisc_sfb ( self
):
4045 copy_network_unit ( '25-qdisc-sfb.network' , '12-dummy.netdev' )
4047 self
. wait_online ([ 'dummy98:routable' ])
4049 output
= check_output ( 'tc qdisc show dev dummy98' )
4051 self
. assertRegex ( output
, 'qdisc sfb 39: root' )
4052 self
. assertRegex ( output
, 'limit 200000' )
4054 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfq' )
4055 def test_qdisc_sfq ( self
):
4056 copy_network_unit ( '25-qdisc-sfq.network' , '12-dummy.netdev' )
4058 self
. wait_online ([ 'dummy98:routable' ])
4060 output
= check_output ( 'tc qdisc show dev dummy98' )
4062 self
. assertRegex ( output
, 'qdisc sfq 36: root' )
4063 self
. assertRegex ( output
, 'perturb 5sec' )
4065 @expectedFailureIfModuleIsNotAvailable ( 'sch_tbf' )
4066 def test_qdisc_tbf ( self
):
4067 copy_network_unit ( '25-qdisc-tbf.network' , '12-dummy.netdev' )
4069 self
. wait_online ([ 'dummy98:routable' ])
4071 output
= check_output ( 'tc qdisc show dev dummy98' )
4073 self
. assertRegex ( output
, 'qdisc tbf 35: root' )
4074 self
. assertRegex ( output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms' )
4076 @expectedFailureIfModuleIsNotAvailable ( 'sch_teql' )
4077 def test_qdisc_teql ( self
):
4078 call_quiet ( 'rmmod sch_teql' )
4080 copy_network_unit ( '25-qdisc-teql.network' , '12-dummy.netdev' )
4082 self
. wait_links ( 'dummy98' )
4083 check_output ( 'modprobe sch_teql max_equalizers=2' )
4084 self
. wait_online ([ 'dummy98:routable' ])
4086 output
= check_output ( 'tc qdisc show dev dummy98' )
4088 self
. assertRegex ( output
, 'qdisc teql1 31: root' )
4090 class NetworkdStateFileTests ( unittest
. TestCase
, Utilities
):
4098 def test_state_file ( self
):
4099 copy_network_unit ( '12-dummy.netdev' , '25-state-file-tests.network' )
4101 self
. wait_online ([ 'dummy98:routable' ])
4103 # make link state file updated
4104 check_output (* resolvectl_cmd
, 'revert' , 'dummy98' , env
= env
)
4106 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
4109 output
= read_link_state_file ( 'dummy98' )
4111 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
4112 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
4113 self
. assertIn ( 'ADMIN_STATE=configured' , output
)
4114 self
. assertIn ( 'OPER_STATE=routable' , output
)
4115 self
. assertIn ( 'REQUIRED_FOR_ONLINE=yes' , output
)
4116 self
. assertIn ( 'REQUIRED_OPER_STATE_FOR_ONLINE=routable' , output
)
4117 self
. assertIn ( 'REQUIRED_FAMILY_FOR_ONLINE=both' , output
)
4118 self
. assertIn ( 'ACTIVATION_POLICY=up' , output
)
4119 self
. assertIn ( 'NETWORK_FILE=/run/systemd/network/25-state-file-tests.network' , output
)
4120 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
4121 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
4122 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
4123 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
4124 self
. assertIn ( 'LLMNR=no' , output
)
4125 self
. assertIn ( 'MDNS=yes' , output
)
4126 self
. assertIn ( 'DNSSEC=no' , output
)
4128 check_output (* resolvectl_cmd
, 'dns' , 'dummy98' , '10.10.10.12#ccc.com' , '10.10.10.13' , '1111:2222::3333' , env
= env
)
4129 check_output (* resolvectl_cmd
, 'domain' , 'dummy98' , 'hogehogehoge' , '~foofoofoo' , env
= env
)
4130 check_output (* resolvectl_cmd
, 'llmnr' , 'dummy98' , 'yes' , env
= env
)
4131 check_output (* resolvectl_cmd
, 'mdns' , 'dummy98' , 'no' , env
= env
)
4132 check_output (* resolvectl_cmd
, 'dnssec' , 'dummy98' , 'yes' , env
= env
)
4133 check_output (* timedatectl_cmd
, 'ntp-servers' , 'dummy98' , '2.fedora.pool.ntp.org' , '3.fedora.pool.ntp.org' , env
= env
)
4135 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
4138 output
= read_link_state_file ( 'dummy98' )
4140 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
4141 self
. assertIn ( 'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org' , output
)
4142 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
4143 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
4144 self
. assertIn ( 'LLMNR=yes' , output
)
4145 self
. assertIn ( 'MDNS=no' , output
)
4146 self
. assertIn ( 'DNSSEC=yes' , output
)
4148 check_output (* timedatectl_cmd
, 'revert' , 'dummy98' , env
= env
)
4150 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
4153 output
= read_link_state_file ( 'dummy98' )
4155 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
4156 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
4157 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
4158 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
4159 self
. assertIn ( 'LLMNR=yes' , output
)
4160 self
. assertIn ( 'MDNS=no' , output
)
4161 self
. assertIn ( 'DNSSEC=yes' , output
)
4163 check_output (* resolvectl_cmd
, 'revert' , 'dummy98' , env
= env
)
4165 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
4168 output
= read_link_state_file ( 'dummy98' )
4170 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
4171 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
4172 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
4173 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
4174 self
. assertIn ( 'LLMNR=no' , output
)
4175 self
. assertIn ( 'MDNS=yes' , output
)
4176 self
. assertIn ( 'DNSSEC=no' , output
)
4178 def test_address_state ( self
):
4179 copy_network_unit ( '12-dummy.netdev' , '12-dummy-no-address.network' )
4182 self
. wait_online ([ 'dummy98:degraded' ])
4184 output
= read_link_state_file ( 'dummy98' )
4185 self
. assertIn ( 'IPV4_ADDRESS_STATE=off' , output
)
4186 self
. assertIn ( 'IPV6_ADDRESS_STATE=degraded' , output
)
4188 # with a routable IPv4 address
4189 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
4190 self
. wait_online ([ 'dummy98:routable' ], ipv4
= True )
4191 self
. wait_online ([ 'dummy98:routable' ])
4193 output
= read_link_state_file ( 'dummy98' )
4194 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
4195 self
. assertIn ( 'IPV6_ADDRESS_STATE=degraded' , output
)
4197 check_output ( 'ip address del 10.1.2.3/16 dev dummy98' )
4199 # with a routable IPv6 address
4200 check_output ( 'ip address add 2002:da8:1:0:1034:56ff:fe78:9abc/64 dev dummy98' )
4201 self
. wait_online ([ 'dummy98:routable' ], ipv6
= True )
4202 self
. wait_online ([ 'dummy98:routable' ])
4204 output
= read_link_state_file ( 'dummy98' )
4205 self
. assertIn ( 'IPV4_ADDRESS_STATE=off' , output
)
4206 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
4208 class NetworkdBondTests ( unittest
. TestCase
, Utilities
):
4216 def test_bond_keep_master ( self
):
4217 check_output ( 'ip link add bond199 type bond mode active-backup' )
4218 check_output ( 'ip link add dummy98 type dummy' )
4219 check_output ( 'ip link set dummy98 master bond199' )
4221 copy_network_unit ( '23-keep-master.network' )
4223 self
. wait_online ([ 'dummy98:enslaved' ])
4225 output
= check_output ( 'ip -d link show bond199' )
4227 self
. assertRegex ( output
, 'active_slave dummy98' )
4229 output
= check_output ( 'ip -d link show dummy98' )
4231 self
. assertRegex ( output
, 'master bond199' )
4233 def test_bond_active_slave ( self
):
4234 copy_network_unit ( '23-active-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
4236 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
4238 output
= check_output ( 'ip -d link show bond199' )
4240 self
. assertIn ( 'active_slave dummy98' , output
)
4242 def test_bond_primary_slave ( self
):
4243 copy_network_unit ( '23-primary-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
4245 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
4247 output
= check_output ( 'ip -d link show bond199' )
4249 self
. assertIn ( 'primary dummy98' , output
)
4252 mkdir_p ( os
. path
. join ( network_unit_dir
, '23-bond199.network.d' ))
4253 for mac
in [ '00:11:22:33:44:55' , '00:11:22:33:44:56' ]:
4254 with
open ( os
. path
. join ( network_unit_dir
, '23-bond199.network.d/mac.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
4255 f
. write ( f
'[Link] \n MACAddress= {mac} \n ' )
4258 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
4260 output
= check_output ( 'ip -d link show bond199' )
4262 self
. assertIn ( f
'link/ether {mac} ' , output
)
4264 def test_bond_operstate ( self
):
4265 copy_network_unit ( '25-bond.netdev' , '11-dummy.netdev' , '12-dummy.netdev' ,
4266 '25-bond99.network' , '25-bond-slave.network' )
4268 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bond99:routable' ])
4270 output
= check_output ( 'ip -d link show dummy98' )
4272 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
4274 output
= check_output ( 'ip -d link show test1' )
4276 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
4278 output
= check_output ( 'ip -d link show bond99' )
4280 self
. assertRegex ( output
, 'MASTER,UP,LOWER_UP' )
4282 self
. wait_operstate ( 'dummy98' , 'enslaved' )
4283 self
. wait_operstate ( 'test1' , 'enslaved' )
4284 self
. wait_operstate ( 'bond99' , 'routable' )
4286 check_output ( 'ip link set dummy98 down' )
4288 self
. wait_operstate ( 'dummy98' , 'off' )
4289 self
. wait_operstate ( 'test1' , 'enslaved' )
4290 self
. wait_operstate ( 'bond99' , 'routable' )
4292 check_output ( 'ip link set dummy98 up' )
4294 self
. wait_operstate ( 'dummy98' , 'enslaved' )
4295 self
. wait_operstate ( 'test1' , 'enslaved' )
4296 self
. wait_operstate ( 'bond99' , 'routable' )
4298 check_output ( 'ip link set dummy98 down' )
4299 check_output ( 'ip link set test1 down' )
4301 self
. wait_operstate ( 'dummy98' , 'off' )
4302 self
. wait_operstate ( 'test1' , 'off' )
4304 if not self
. wait_operstate ( 'bond99' , 'no-carrier' , setup_timeout
= 30 , fail_assert
= False ):
4305 # Huh? Kernel does not recognize that all slave interfaces are down?
4306 # Let's confirm that networkd's operstate is consistent with ip's result.
4307 self
. assertNotRegex ( output
, 'NO-CARRIER' )
4309 class NetworkdBridgeTests ( unittest
. TestCase
, Utilities
):
4317 def test_bridge_vlan ( self
):
4318 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave.network' ,
4319 '26-bridge.netdev' , '26-bridge-vlan-master.network' )
4321 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' ])
4323 output
= check_output ( 'bridge vlan show dev test1' )
4325 self
. assertNotRegex ( output
, '4063' )
4326 for i
in range ( 4064 , 4095 ):
4327 self
. assertRegex ( output
, f
' {i} ' )
4328 self
. assertNotRegex ( output
, '4095' )
4330 output
= check_output ( 'bridge vlan show dev bridge99' )
4332 self
. assertNotRegex ( output
, '4059' )
4333 for i
in range ( 4060 , 4095 ):
4334 self
. assertRegex ( output
, f
' {i} ' )
4335 self
. assertNotRegex ( output
, '4095' )
4337 def test_bridge_vlan_issue_20373 ( self
):
4338 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave-issue-20373.network' ,
4339 '26-bridge-issue-20373.netdev' , '26-bridge-vlan-master-issue-20373.network' ,
4340 '21-vlan.netdev' , '21-vlan.network' )
4342 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' , 'vlan99:routable' ])
4344 output
= check_output ( 'bridge vlan show dev test1' )
4346 self
. assertIn ( '100 PVID Egress Untagged' , output
)
4347 self
. assertIn ( '560' , output
)
4348 self
. assertIn ( '600' , output
)
4350 output
= check_output ( 'bridge vlan show dev bridge99' )
4352 self
. assertIn ( '1 PVID Egress Untagged' , output
)
4353 self
. assertIn ( '100' , output
)
4354 self
. assertIn ( '600' , output
)
4356 def test_bridge_mdb ( self
):
4357 copy_network_unit ( '11-dummy.netdev' , '26-bridge-mdb-slave.network' ,
4358 '26-bridge.netdev' , '26-bridge-mdb-master.network' )
4360 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' ])
4362 output
= check_output ( 'bridge mdb show dev bridge99' )
4364 self
. assertRegex ( output
, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064' )
4365 self
. assertRegex ( output
, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065' )
4367 # Old kernel may not support bridge MDB entries on bridge master
4368 if call_quiet ( 'bridge mdb add dev bridge99 port bridge99 grp 224.0.1.3 temp vid 4068' ) == 0 :
4369 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp ff02:aaaa:fee5::1:4 temp *vid 4066' )
4370 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp 224.0.1.2 temp *vid 4067' )
4372 def test_bridge_keep_master ( self
):
4373 check_output ( 'ip link add bridge99 type bridge' )
4374 check_output ( 'ip link set bridge99 up' )
4375 check_output ( 'ip link add dummy98 type dummy' )
4376 check_output ( 'ip link set dummy98 master bridge99' )
4378 copy_network_unit ( '23-keep-master.network' )
4380 self
. wait_online ([ 'dummy98:enslaved' ])
4382 output
= check_output ( 'ip -d link show dummy98' )
4384 self
. assertRegex ( output
, 'master bridge99' )
4385 self
. assertRegex ( output
, 'bridge' )
4387 output
= check_output ( 'bridge -d link show dummy98' )
4389 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
4390 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
4391 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
4392 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
4393 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
4394 # CONFIG_BRIDGE_IGMP_SNOOPING=y
4395 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
4396 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
4397 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
4398 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
4399 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
4400 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
4402 def test_bridge_property ( self
):
4403 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
4404 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
4405 '25-bridge99.network' )
4407 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' ])
4409 output
= check_output ( 'ip -d link show bridge99' )
4411 self
. assertIn ( 'mtu 9000 ' , output
)
4413 output
= check_output ( 'ip -d link show test1' )
4415 self
. assertIn ( 'master bridge99 ' , output
)
4416 self
. assertIn ( 'bridge_slave' , output
)
4417 self
. assertIn ( 'mtu 9000 ' , output
)
4419 output
= check_output ( 'ip -d link show dummy98' )
4421 self
. assertIn ( 'master bridge99 ' , output
)
4422 self
. assertIn ( 'bridge_slave' , output
)
4423 self
. assertIn ( 'mtu 9000 ' , output
)
4425 output
= check_output ( 'ip addr show bridge99' )
4427 self
. assertIn ( '192.168.0.15/24' , output
)
4429 output
= check_output ( 'bridge -d link show dummy98' )
4431 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
4432 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
4433 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'isolated' , '1' )
4434 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
4435 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
4436 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
4437 # CONFIG_BRIDGE_IGMP_SNOOPING=y
4438 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
4439 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
4440 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
4441 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
4442 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
4443 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
4445 output
= check_output ( 'bridge -d link show test1' )
4447 self
. check_bridge_port_attr ( 'bridge99' , 'test1' , 'priority' , '0' )
4449 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
4450 output
= check_output ( 'ip addr show bridge99' )
4452 self
. assertIn ( '192.168.0.16/24' , output
)
4455 print ( '### ip -6 route list table all dev bridge99' )
4456 output
= check_output ( 'ip -6 route list table all dev bridge99' )
4458 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
4460 remove_link ( 'test1' )
4461 self
. wait_operstate ( 'bridge99' , 'routable' )
4463 output
= check_output ( 'ip -d link show bridge99' )
4465 self
. assertIn ( 'mtu 9000 ' , output
)
4467 output
= check_output ( 'ip -d link show dummy98' )
4469 self
. assertIn ( 'master bridge99 ' , output
)
4470 self
. assertIn ( 'bridge_slave' , output
)
4471 self
. assertIn ( 'mtu 9000 ' , output
)
4473 remove_link ( 'dummy98' )
4474 self
. wait_operstate ( 'bridge99' , 'no-carrier' )
4476 output
= check_output ( 'ip -d link show bridge99' )
4478 # When no carrier, the kernel may reset the MTU
4479 self
. assertIn ( 'NO-CARRIER' , output
)
4481 output
= check_output ( 'ip address show bridge99' )
4483 self
. assertNotIn ( '192.168.0.15/24' , output
)
4484 self
. assertIn ( '192.168.0.16/24' , output
) # foreign address is kept
4486 print ( '### ip -6 route list table all dev bridge99' )
4487 output
= check_output ( 'ip -6 route list table all dev bridge99' )
4489 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
4491 check_output ( 'ip link add dummy98 type dummy' )
4492 self
. wait_online ([ 'dummy98:enslaved' , 'bridge99:routable' ])
4494 output
= check_output ( 'ip -d link show bridge99' )
4496 self
. assertIn ( 'mtu 9000 ' , output
)
4498 output
= check_output ( 'ip -d link show dummy98' )
4500 self
. assertIn ( 'master bridge99 ' , output
)
4501 self
. assertIn ( 'bridge_slave' , output
)
4502 self
. assertIn ( 'mtu 9000 ' , output
)
4504 def test_bridge_configure_without_carrier ( self
):
4505 copy_network_unit ( '26-bridge.netdev' , '26-bridge-configure-without-carrier.network' ,
4509 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
4510 for test
in [ 'no-slave' , 'add-slave' , 'slave-up' , 'slave-no-carrier' , 'slave-carrier' , 'slave-down' ]:
4511 with self
. subTest ( test
= test
):
4512 if test
== 'no-slave' :
4513 # bridge has no slaves; it's up but *might* not have carrier
4514 self
. wait_operstate ( 'bridge99' , operstate
= r
'(no-carrier|routable)' , setup_state
= None , setup_timeout
= 30 )
4515 # due to a bug in the kernel, newly-created bridges are brought up
4516 # *with* carrier, unless they have had any setting changed; e.g.
4517 # their mac set, priority set, etc. Then, they will lose carrier
4518 # as soon as a (down) slave interface is added, and regain carrier
4519 # again once the slave interface is brought up.
4520 #self.check_link_attr('bridge99', 'carrier', '0')
4521 elif test
== 'add-slave' :
4522 # add slave to bridge, but leave it down; bridge is definitely no-carrier
4523 self
. check_link_attr ( 'test1' , 'operstate' , 'down' )
4524 check_output ( 'ip link set dev test1 master bridge99' )
4525 self
. wait_operstate ( 'bridge99' , operstate
= 'no-carrier' , setup_state
= None )
4526 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4527 elif test
== 'slave-up' :
4528 # bring up slave, which will have carrier; bridge gains carrier
4529 check_output ( 'ip link set dev test1 up' )
4530 self
. wait_online ([ 'bridge99:routable' ])
4531 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
4532 elif test
== 'slave-no-carrier' :
4533 # drop slave carrier; bridge loses carrier
4534 check_output ( 'ip link set dev test1 carrier off' )
4535 self
. wait_online ([ 'bridge99:no-carrier:no-carrier' ])
4536 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4537 elif test
== 'slave-carrier' :
4538 # restore slave carrier; bridge gains carrier
4539 check_output ( 'ip link set dev test1 carrier on' )
4540 self
. wait_online ([ 'bridge99:routable' ])
4541 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
4542 elif test
== 'slave-down' :
4543 # bring down slave; bridge loses carrier
4544 check_output ( 'ip link set dev test1 down' )
4545 self
. wait_online ([ 'bridge99:no-carrier:no-carrier' ])
4546 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4548 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bridge99' , env
= env
)
4549 self
. assertRegex ( output
, '10.1.2.3' )
4550 self
. assertRegex ( output
, '10.1.2.1' )
4552 def test_bridge_ignore_carrier_loss ( self
):
4553 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
4554 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
4555 '25-bridge99-ignore-carrier-loss.network' )
4557 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' ])
4559 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
4560 remove_link ( 'test1' , 'dummy98' )
4563 output
= check_output ( 'ip address show bridge99' )
4565 self
. assertRegex ( output
, 'NO-CARRIER' )
4566 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
4567 self
. assertRegex ( output
, 'inet 192.168.0.16/24 scope global secondary bridge99' )
4569 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain ( self
):
4570 copy_network_unit ( '26-bridge.netdev' , '26-bridge-slave-interface-1.network' ,
4571 '25-bridge99-ignore-carrier-loss.network' )
4573 self
. wait_online ([ 'bridge99:no-carrier' ])
4575 for trial
in range ( 4 ):
4576 check_output ( 'ip link add dummy98 type dummy' )
4577 check_output ( 'ip link set dummy98 up' )
4579 remove_link ( 'dummy98' )
4581 self
. wait_online ([ 'bridge99:routable' , 'dummy98:enslaved' ])
4583 output
= check_output ( 'ip address show bridge99' )
4585 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
4587 output
= check_output ( 'ip rule list table 100' )
4589 self
. assertIn ( 'from all to 8.8.8.8 lookup 100' , output
)
4591 class NetworkdSRIOVTests ( unittest
. TestCase
, Utilities
):
4599 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
4600 def test_sriov ( self
):
4601 copy_network_unit ( '25-default.link' , '25-sriov.network' )
4603 call ( 'modprobe netdevsim' )
4605 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4608 with
open ( '/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4612 self
. wait_online ([ 'eni99np1:routable' ])
4614 output
= check_output ( 'ip link show dev eni99np1' )
4616 self
. assertRegex ( output
,
4617 '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 *'
4618 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4619 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4622 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
4623 def test_sriov_udev ( self
):
4624 copy_network_unit ( '25-sriov.link' , '25-sriov-udev.network' )
4626 call ( 'modprobe netdevsim' )
4628 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4632 self
. wait_online ([ 'eni99np1:routable' ])
4634 # the name eni99np1 may be an alternative name.
4635 ifname
= link_resolve ( 'eni99np1' )
4637 output
= check_output ( 'ip link show dev eni99np1' )
4639 self
. assertRegex ( output
,
4640 '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 *'
4641 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4642 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4644 self
. assertNotIn ( 'vf 3' , output
)
4645 self
. assertNotIn ( 'vf 4' , output
)
4647 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4648 f
. write ( '[Link] \n SR-IOVVirtualFunctions=4 \n ' )
4651 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4653 output
= check_output ( 'ip link show dev eni99np1' )
4655 self
. assertRegex ( output
,
4656 '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 *'
4657 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4658 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
4661 self
. assertNotIn ( 'vf 4' , output
)
4663 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4664 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
4667 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4669 output
= check_output ( 'ip link show dev eni99np1' )
4671 self
. assertRegex ( output
,
4672 '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 *'
4673 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4674 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
4677 self
. assertNotIn ( 'vf 4' , output
)
4679 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4680 f
. write ( '[Link] \n SR-IOVVirtualFunctions=2 \n ' )
4683 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4685 output
= check_output ( 'ip link show dev eni99np1' )
4687 self
. assertRegex ( output
,
4688 '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 *'
4689 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off'
4691 self
. assertNotIn ( 'vf 2' , output
)
4692 self
. assertNotIn ( 'vf 3' , output
)
4693 self
. assertNotIn ( 'vf 4' , output
)
4695 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4696 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
4699 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4701 output
= check_output ( 'ip link show dev eni99np1' )
4703 self
. assertRegex ( output
,
4704 '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 *'
4705 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4706 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4708 self
. assertNotIn ( 'vf 3' , output
)
4709 self
. assertNotIn ( 'vf 4' , output
)
4711 class NetworkdLLDPTests ( unittest
. TestCase
, Utilities
):
4719 def test_lldp ( self
):
4720 copy_network_unit ( '23-emit-lldp.network' , '24-lldp.network' , '25-veth.netdev' )
4722 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:degraded' ])
4724 for trial
in range ( 10 ):
4728 output
= check_output (* networkctl_cmd
, 'lldp' , env
= env
)
4730 if re
. search ( r
'veth99 .* veth-peer' , output
):
4735 class NetworkdRATests ( unittest
. TestCase
, Utilities
):
4743 def test_ipv6_prefix_delegation ( self
):
4744 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth.network' )
4745 self
. setup_nftset ( 'addr6' , 'ipv6_addr' )
4746 self
. setup_nftset ( 'network6' , 'ipv6_addr' , 'flags interval;' )
4747 self
. setup_nftset ( 'ifindex' , 'iface_index' )
4749 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4751 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth99' , env
= env
)
4753 self
. assertRegex ( output
, 'fe80::' )
4754 self
. assertRegex ( output
, '2002:da8:1::1' )
4756 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth99' , env
= env
)
4758 self
. assertIn ( 'hogehoge.test' , output
)
4760 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4762 self
. assertRegex ( output
, '2002:da8:1:0' )
4764 self
. check_netlabel ( 'veth99' , '2002:da8:1::/64' )
4765 self
. check_netlabel ( 'veth99' , '2002:da8:2::/64' )
4767 self
. check_nftset ( 'addr6' , '2002:da8:1:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*' )
4768 self
. check_nftset ( 'addr6' , '2002:da8:2:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*' )
4769 self
. check_nftset ( 'network6' , '2002:da8:1::/64' )
4770 self
. check_nftset ( 'network6' , '2002:da8:2::/64' )
4771 self
. check_nftset ( 'ifindex' , 'veth99' )
4773 self
. teardown_nftset ( 'addr6' , 'network6' , 'ifindex' )
4775 def test_ipv6_token_static ( self
):
4776 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-static.network' )
4778 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4780 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4782 self
. assertRegex ( output
, '2002:da8:1:0:1a:2b:3c:4d' )
4783 self
. assertRegex ( output
, '2002:da8:1:0:fa:de:ca:fe' )
4784 self
. assertRegex ( output
, '2002:da8:2:0:1a:2b:3c:4d' )
4785 self
. assertRegex ( output
, '2002:da8:2:0:fa:de:ca:fe' )
4787 def test_ipv6_token_prefixstable ( self
):
4788 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable.network' )
4790 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4792 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4794 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
4795 self
. assertIn ( '2002:da8:2:0:1034:56ff:fe78:9abc' , output
) # EUI64
4797 def test_ipv6_token_prefixstable_without_address ( self
):
4798 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable-without-address.network' )
4800 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4802 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4804 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
4805 self
. assertIn ( '2002:da8:2:0:f689:561a:8eda:7443' , output
)
4807 def test_router_preference ( self
):
4808 copy_network_unit ( '25-veth-client.netdev' ,
4809 '25-veth-router-high.netdev' ,
4810 '25-veth-router-low.netdev' ,
4812 '25-veth-bridge.network' ,
4813 '25-veth-client.network' ,
4814 '25-veth-router-high.network' ,
4815 '25-veth-router-low.network' ,
4816 '25-bridge99.network' )
4818 self
. wait_online ([ 'client-p:enslaved' ,
4819 'router-high:degraded' , 'router-high-p:enslaved' ,
4820 'router-low:degraded' , 'router-low-p:enslaved' ,
4821 'bridge99:routable' ])
4823 networkctl_reconfigure ( 'client' )
4824 self
. wait_online ([ 'client:routable' ])
4826 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4827 self
. wait_address ( 'client' , '2002:da8:1:98:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4828 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 512' , ipv
= '-6' , timeout_sec
= 10 )
4829 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 2048' , ipv
= '-6' , timeout_sec
= 10 )
4831 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
4833 self
. assertIn ( 'pref high' , output
)
4834 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
4836 self
. assertIn ( 'pref low' , output
)
4838 with
open ( os
. path
. join ( network_unit_dir
, '25-veth-client.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4839 f
. write ( ' \n [Link] \n MACAddress=12:34:56:78:9a:01 \n [IPv6AcceptRA] \n RouteMetric=100:200:300 \n ' )
4842 self
. wait_online ([ 'client:routable' ])
4844 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a01/64' , ipv
= '-6' , timeout_sec
= 10 )
4845 self
. wait_address ( 'client' , '2002:da8:1:98:1034:56ff:fe78:9a01/64' , ipv
= '-6' , timeout_sec
= 10 )
4846 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 100' , ipv
= '-6' , timeout_sec
= 10 )
4847 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 300' , ipv
= '-6' , timeout_sec
= 10 )
4849 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
4851 self
. assertIn ( 'pref high' , output
)
4852 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
4854 self
. assertIn ( 'pref low' , output
)
4856 @unittest . skipUnless ( radvd_check_config ( 'captive-portal.conf' ), "Installed radvd doesn't support captive portals" )
4857 def test_captive_portal ( self
):
4858 copy_network_unit ( '25-veth-client.netdev' ,
4859 '25-veth-router-captive.netdev' ,
4861 '25-veth-client-captive.network' ,
4862 '25-veth-router-captive.network' ,
4863 '25-veth-bridge-captive.network' ,
4864 '25-bridge99.network' )
4866 self
. wait_online ([ 'bridge99:routable' , 'client-p:enslaved' ,
4867 'router-captive:degraded' , 'router-captivep:enslaved' ])
4869 start_radvd ( config_file
= 'captive-portal.conf' )
4870 networkctl_reconfigure ( 'client' )
4871 self
. wait_online ([ 'client:routable' ])
4873 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4874 output
= check_output (* networkctl_cmd
, 'status' , 'client' , env
= env
)
4876 self
. assertIn ( 'Captive Portal: http://systemd.io' , output
)
4878 @unittest . skipUnless ( radvd_check_config ( 'captive-portal.conf' ), "Installed radvd doesn't support captive portals" )
4879 def test_invalid_captive_portal ( self
):
4880 def radvd_write_config ( captive_portal_uri
):
4881 with
open ( os
. path
. join ( networkd_ci_temp_dir
, 'radvd/bogus-captive-portal.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
4882 f
. write ( f
'interface router-captive {{ AdvSendAdvert on; AdvCaptivePortalAPI " {captive_portal_uri} "; prefix 2002:da8:1:99::/64 {{ AdvOnLink on; AdvAutonomous on; }}; }};' )
4884 captive_portal_uris
= [
4885 "42ěščěškd ěšč ě s" ,
4890 copy_network_unit ( '25-veth-client.netdev' ,
4891 '25-veth-router-captive.netdev' ,
4893 '25-veth-client-captive.network' ,
4894 '25-veth-router-captive.network' ,
4895 '25-veth-bridge-captive.network' ,
4896 '25-bridge99.network' )
4898 self
. wait_online ([ 'bridge99:routable' , 'client-p:enslaved' ,
4899 'router-captive:degraded' , 'router-captivep:enslaved' ])
4901 for uri
in captive_portal_uris
:
4902 print ( f
"Captive portal: {uri} " )
4903 radvd_write_config ( uri
)
4905 start_radvd ( config_file
= 'bogus-captive-portal.conf' )
4906 networkctl_reconfigure ( 'client' )
4907 self
. wait_online ([ 'client:routable' ])
4909 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4910 output
= check_output (* networkctl_cmd
, 'status' , 'client' , env
= env
)
4912 self
. assertNotIn ( 'Captive Portal:' , output
)
4914 class NetworkdDHCPServerTests ( unittest
. TestCase
, Utilities
):
4922 def test_dhcp_server ( self
):
4923 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server.network' )
4925 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4927 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4929 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4930 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
4931 self
. assertRegex ( output
, 'DNS: 192.168.5.1 \n *192.168.5.10' )
4932 self
. assertRegex ( output
, 'NTP: 192.168.5.1 \n *192.168.5.11' )
4934 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth-peer' , env
= env
)
4935 self
. assertRegex ( output
, "Offered DHCP leases: 192.168.5.[0-9]*" )
4937 def test_dhcp_server_with_uplink ( self
):
4938 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-downstream.network' ,
4939 '12-dummy.netdev' , '25-dhcp-server-uplink.network' )
4941 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4943 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4945 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4946 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
4947 self
. assertIn ( 'DNS: 192.168.5.1' , output
)
4948 self
. assertIn ( 'NTP: 192.168.5.1' , output
)
4950 def test_emit_router_timezone ( self
):
4951 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-timezone-router.network' , '25-dhcp-server-timezone-router.network' )
4953 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4955 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4957 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4958 self
. assertIn ( 'Gateway: 192.168.5.1' , output
)
4959 self
. assertIn ( 'Time Zone: Europe/Berlin' , output
)
4961 def test_dhcp_server_static_lease ( self
):
4962 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-static-lease.network' , '25-dhcp-server-static-lease.network' )
4964 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4966 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4968 self
. assertIn ( 'Address: 10.1.1.200 (DHCP4 via 10.1.1.1)' , output
)
4969 self
. assertIn ( 'DHCP4 Client ID: 12:34:56:78:9a:bc' , output
)
4971 def test_dhcp_server_static_lease_default_client_id ( self
):
4972 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-static-lease.network' )
4974 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4976 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4978 self
. assertIn ( 'Address: 10.1.1.200 (DHCP4 via 10.1.1.1)' , output
)
4979 self
. assertRegex ( output
, 'DHCP4 Client ID: IAID:[0-9a-z]*/DUID' )
4981 class NetworkdDHCPServerRelayAgentTests ( unittest
. TestCase
, Utilities
):
4989 def test_relay_agent ( self
):
4990 copy_network_unit ( '25-agent-veth-client.netdev' ,
4991 '25-agent-veth-server.netdev' ,
4992 '25-agent-client.network' ,
4993 '25-agent-server.network' ,
4994 '25-agent-client-peer.network' ,
4995 '25-agent-server-peer.network' )
4998 self
. wait_online ([ 'client:routable' ])
5000 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'client' , env
= env
)
5002 self
. assertRegex ( output
, r
'Address: 192.168.5.150 \(DHCP4 via 192.168.5.1\)' )
5004 class NetworkdDHCPClientTests ( unittest
. TestCase
, Utilities
):
5012 def test_dhcp_client_ipv6_only ( self
):
5013 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv6-only.network' )
5016 self
. wait_online ([ 'veth-peer:carrier' ])
5018 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5021 output
= check_output ( 'ip address show dev veth99 scope global' )
5023 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
5024 self
. assertNotIn ( '192.168.5' , output
)
5026 # checking semi-static route
5027 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
5029 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
5031 # Confirm that ipv6 token is not set in the kernel
5032 output
= check_output ( 'ip token show dev veth99' )
5034 self
. assertRegex ( output
, 'token :: dev veth99' )
5036 print ( '## dnsmasq log' )
5037 output
= read_dnsmasq_log_file ()
5039 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
5040 self
. assertNotIn ( 'DHCPADVERTISE(veth-peer)' , output
)
5041 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
5042 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
5043 self
. assertIn ( 'sent size: 0 option: 14 rapid-commit' , output
)
5045 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-ipv6-only.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5046 f
. write ( ' \n [DHCPv6] \n RapidCommit=no \n ' )
5052 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5055 output
= check_output ( 'ip address show dev veth99 scope global' )
5057 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
5058 self
. assertNotIn ( '192.168.5' , output
)
5060 # checking semi-static route
5061 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
5063 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
5065 print ( '## dnsmasq log' )
5066 output
= read_dnsmasq_log_file ()
5068 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
5069 self
. assertIn ( 'DHCPADVERTISE(veth-peer)' , output
)
5070 self
. assertIn ( 'DHCPREQUEST(veth-peer)' , output
)
5071 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
5072 self
. assertNotIn ( 'rapid-commit' , output
)
5074 def test_dhcp_client_ipv6_only_with_custom_client_identifier ( self
):
5075 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv6-only-custom-client-identifier.network' )
5078 self
. wait_online ([ 'veth-peer:carrier' ])
5080 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5083 output
= check_output ( 'ip address show dev veth99 scope global' )
5085 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
5086 self
. assertNotIn ( '192.168.5' , output
)
5088 print ( '## dnsmasq log' )
5089 output
= read_dnsmasq_log_file ()
5091 self
. assertIn ( 'DHCPSOLICIT(veth-peer) 00:42:00:00:ab:11:f9:2a:c2:77:29:f9:5c:00' , output
)
5092 self
. assertNotIn ( 'DHCPADVERTISE(veth-peer)' , output
)
5093 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
5094 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
5095 self
. assertIn ( 'sent size: 0 option: 14 rapid-commit' , output
)
5099 def test_dhcp_client_ipv4_only ( self
):
5100 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv4-only.network' )
5102 self
. setup_nftset ( 'addr4' , 'ipv4_addr' )
5103 self
. setup_nftset ( 'network4' , 'ipv4_addr' , 'flags interval;' )
5104 self
. setup_nftset ( 'ifindex' , 'iface_index' )
5107 self
. wait_online ([ 'veth-peer:carrier' ])
5108 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7' ,
5109 '--dhcp-option=option:domain-search,example.com' ,
5110 '--dhcp-alternate-port=67,5555' ,
5111 ipv4_range
= '192.168.5.110,192.168.5.119' )
5112 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5113 self
. wait_address ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' )
5115 print ( '## ip address show dev veth99 scope global' )
5116 output
= check_output ( 'ip address show dev veth99 scope global' )
5118 self
. assertIn ( 'mtu 1492' , output
)
5119 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
5120 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' )
5121 self
. assertNotIn ( '2600::' , output
)
5123 print ( '## ip route show table main dev veth99' )
5124 output
= check_output ( 'ip route show table main dev veth99' )
5126 # no DHCP routes assigned to the main table
5127 self
. assertNotIn ( 'proto dhcp' , output
)
5129 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
5130 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
5131 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
5132 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
5134 print ( '## ip route show table 211 dev veth99' )
5135 output
= check_output ( 'ip route show table 211 dev veth99' )
5137 self
. assertRegex ( output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.11[0-9] metric 24' )
5138 self
. assertRegex ( output
, '192.168.5.0/24 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
5139 self
. assertRegex ( output
, '192.168.5.1 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
5140 self
. assertRegex ( output
, '192.168.5.6 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
5141 self
. assertRegex ( output
, '192.168.5.7 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
5142 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
5144 print ( '## link state file' )
5145 output
= read_link_state_file ( 'veth99' )
5147 # checking DNS server and Domains
5148 self
. assertIn ( 'DNS=192.168.5.6 192.168.5.7' , output
)
5149 self
. assertIn ( 'DOMAINS=example.com' , output
)
5151 print ( '## dnsmasq log' )
5152 output
= read_dnsmasq_log_file ()
5154 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
5155 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc' , output
)
5156 self
. assertIn ( 'client provides name: test-hostname' , output
)
5157 self
. assertIn ( '26:mtu' , output
)
5159 # change address range, DNS servers, and Domains
5161 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8' ,
5162 '--dhcp-option=option:domain-search,foo.example.com' ,
5163 '--dhcp-alternate-port=67,5555' ,
5164 ipv4_range
= '192.168.5.120,192.168.5.129' ,)
5166 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
5167 print ( 'Wait for the DHCP lease to be expired' )
5168 self
. wait_address_dropped ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' , timeout_sec
= 120 )
5169 self
. wait_address ( 'veth99' , r
'inet 192.168.5.12[0-9]*/24' , ipv
= '-4' )
5171 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5173 print ( '## ip address show dev veth99 scope global' )
5174 output
= check_output ( 'ip address show dev veth99 scope global' )
5176 self
. assertIn ( 'mtu 1492' , output
)
5177 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
5178 self
. assertNotIn ( '192.168.5.11' , output
)
5179 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' )
5180 self
. assertNotIn ( '2600::' , output
)
5182 print ( '## ip route show table main dev veth99' )
5183 output
= check_output ( 'ip route show table main dev veth99' )
5185 # no DHCP routes assigned to the main table
5186 self
. assertNotIn ( 'proto dhcp' , output
)
5188 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
5189 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
5190 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
5191 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
5193 print ( '## ip route show table 211 dev veth99' )
5194 output
= check_output ( 'ip route show table 211 dev veth99' )
5196 self
. assertRegex ( output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.12[0-9] metric 24' )
5197 self
. assertRegex ( output
, '192.168.5.0/24 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
5198 self
. assertRegex ( output
, '192.168.5.1 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
5199 self
. assertNotIn ( '192.168.5.6' , output
)
5200 self
. assertRegex ( output
, '192.168.5.7 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
5201 self
. assertRegex ( output
, '192.168.5.8 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
5202 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
5204 print ( '## link state file' )
5205 output
= read_link_state_file ( 'veth99' )
5207 # checking DNS server and Domains
5208 self
. assertIn ( 'DNS=192.168.5.1 192.168.5.7 192.168.5.8' , output
)
5209 self
. assertIn ( 'DOMAINS=foo.example.com' , output
)
5211 print ( '## dnsmasq log' )
5212 output
= read_dnsmasq_log_file ()
5214 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
5215 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 192.168.5.11' , output
)
5216 self
. assertIn ( 'client provides name: test-hostname' , output
)
5217 self
. assertIn ( '26:mtu' , output
)
5219 self
. check_netlabel ( 'veth99' , r
'192\.168\.5\.0/24' )
5221 self
. check_nftset ( 'addr4' , r
'192\.168\.5\.1' )
5222 self
. check_nftset ( 'network4' , r
'192\.168\.5\.0/24' )
5223 self
. check_nftset ( 'ifindex' , 'veth99' )
5225 self
. teardown_nftset ( 'addr4' , 'network4' , 'ifindex' )
5227 def test_dhcp_client_ipv4_use_routes_gateway ( self
):
5229 for ( routes
, gateway
, dns_and_ntp_routes
, classless
) in itertools
. product ([ True , False ], repeat
= 4 ):
5235 print ( f
'### test_dhcp_client_ipv4_use_routes_gateway(routes= {routes} , gateway= {gateway} , dns_and_ntp_routes= {dns_and_ntp_routes} , classless= {classless} )' )
5236 with self
. subTest ( routes
= routes
, gateway
= gateway
, dns_and_ntp_routes
= dns_and_ntp_routes
, classless
= classless
):
5237 self
._ test
_ dhcp
_ client
_ ipv
4_u se
_ routes
_ gateway
( routes
, gateway
, dns_and_ntp_routes
, classless
)
5239 def _test_dhcp_client_ipv4_use_routes_gateway ( self
, use_routes
, use_gateway
, dns_and_ntp_routes
, classless
):
5240 testunit
= '25-dhcp-client-ipv4-use-routes-use-gateway.network'
5241 testunits
= [ '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , testunit
]
5242 testunits
. append ( f
' {testunit} .d/use-routes- {use_routes} .conf' )
5243 testunits
. append ( f
' {testunit} .d/use-gateway- {use_gateway} .conf' )
5244 testunits
. append ( f
' {testunit} .d/use-dns-and-ntp-routes- {dns_and_ntp_routes} .conf' )
5245 copy_network_unit (* testunits
, copy_dropins
= False )
5248 self
. wait_online ([ 'veth-peer:carrier' ])
5249 additional_options
= [
5250 '--dhcp-option=option:dns-server,192.168.5.10,8.8.8.8' ,
5251 '--dhcp-option=option:ntp-server,192.168.5.11,9.9.9.9' ,
5252 '--dhcp-option=option:static-route,192.168.6.100,192.168.5.2,8.8.8.8,192.168.5.3'
5255 additional_options
+= [
5256 '--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'
5258 start_dnsmasq (* additional_options
)
5259 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5261 output
= check_output ( 'ip -4 route show dev veth99' )
5267 self
. assertRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5268 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5269 self
. assertRegex ( output
, r
'192.168.5.64/26 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5270 self
. assertRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5271 self
. assertRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5273 self
. assertRegex ( output
, r
'192.168.6.0/24 via 192.168.5.2 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5274 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5275 self
. assertRegex ( output
, r
'192.168.5.2 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5276 self
. assertRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5278 self
. assertNotRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5279 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5280 self
. assertNotRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5281 self
. assertNotRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5282 self
. assertNotRegex ( output
, r
'192.168.6.0/24 via 192.168.5.2 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5283 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5284 self
. assertNotRegex ( output
, r
'192.168.5.2 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5285 self
. assertNotRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5288 if use_gateway
and ( not classless
or not use_routes
):
5289 self
. assertRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5291 self
. assertNotRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5293 # Check route to gateway
5294 if ( use_gateway
or dns_and_ntp_routes
) and ( not classless
or not use_routes
):
5295 self
. assertRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5297 self
. assertNotRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5299 # Check RoutesToDNS= and RoutesToNTP=
5300 if dns_and_ntp_routes
:
5301 self
. assertRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5302 self
. assertRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5305 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5306 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5308 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5309 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5311 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5312 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5314 self
. assertNotRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5315 self
. assertNotRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5316 self
. assertNotRegex ( output
, r
'8.8.8.8 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
5317 self
. assertNotRegex ( output
, r
'9.9.9.9 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
5319 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5322 def test_dhcp_client_settings_anonymize ( self
):
5323 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-anonymize.network' )
5325 self
. wait_online ([ 'veth-peer:carrier' ])
5327 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5329 print ( '## dnsmasq log' )
5330 output
= read_dnsmasq_log_file ()
5332 self
. assertNotIn ( 'VendorClassIdentifier=SusantVendorTest' , output
)
5333 self
. assertNotIn ( 'test-hostname' , output
)
5334 self
. assertNotIn ( '26:mtu' , output
)
5336 def test_dhcp_keep_configuration_dhcp ( self
):
5337 copy_network_unit ( '25-veth.netdev' ,
5338 '25-dhcp-server-veth-peer.network' ,
5339 '25-dhcp-client-keep-configuration-dhcp.network' )
5341 self
. wait_online ([ 'veth-peer:carrier' ])
5343 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5345 output
= check_output ( 'ip address show dev veth99 scope global' )
5347 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5348 'valid_lft forever preferred_lft forever' )
5350 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
5353 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
5354 print ( 'Wait for the DHCP lease to be expired' )
5357 # The lease address should be kept after the lease expired
5358 output
= check_output ( 'ip address show dev veth99 scope global' )
5360 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5361 'valid_lft forever preferred_lft forever' )
5365 # The lease address should be kept after networkd stopped
5366 output
= check_output ( 'ip address show dev veth99 scope global' )
5368 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5369 'valid_lft forever preferred_lft forever' )
5371 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-keep-configuration-dhcp.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5372 f
. write ( '[Network] \n DHCP=no \n ' )
5375 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5377 # Still the lease address should be kept after networkd restarted
5378 output
= check_output ( 'ip address show dev veth99 scope global' )
5380 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5381 'valid_lft forever preferred_lft forever' )
5383 def test_dhcp_keep_configuration_dhcp_on_stop ( self
):
5384 copy_network_unit ( '25-veth.netdev' ,
5385 '25-dhcp-server-veth-peer.network' ,
5386 '25-dhcp-client-keep-configuration-dhcp-on-stop.network' )
5388 self
. wait_online ([ 'veth-peer:carrier' ])
5390 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5392 output
= check_output ( 'ip address show dev veth99 scope global' )
5394 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5399 output
= check_output ( 'ip address show dev veth99 scope global' )
5401 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5404 self
. wait_online ([ 'veth-peer:routable' ])
5406 output
= check_output ( 'ip address show dev veth99 scope global' )
5408 self
. assertNotIn ( '192.168.5.' , output
)
5410 def test_dhcp_client_reuse_address_as_static ( self
):
5411 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' )
5413 self
. wait_online ([ 'veth-peer:carrier' ])
5415 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5417 # link become 'routable' when at least one protocol provide an valid address.
5418 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5419 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5421 output
= check_output ( 'ip address show dev veth99 scope global' )
5422 ipv4_address
= re
. search ( r
'192.168.5.[0-9]*/24' , output
). group ()
5423 ipv6_address
= re
. search ( r
'2600::[0-9a-f:]*/128' , output
). group ()
5424 static_network
= ' \n ' . join ([ '[Match]' , 'Name=veth99' , '[Network]' , 'IPv6AcceptRA=no' , 'Address=' + ipv4_address
, 'Address=' + ipv6_address
])
5425 print ( static_network
)
5427 remove_network_unit ( '25-dhcp-client.network' )
5429 with
open ( os
. path
. join ( network_unit_dir
, '25-static.network' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5430 f
. write ( static_network
)
5433 self
. wait_online ([ 'veth99:routable' ])
5435 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
5437 self
. assertRegex ( output
, f
'inet {ipv4_address} brd 192.168.5.255 scope global veth99 \n *'
5438 'valid_lft forever preferred_lft forever' )
5440 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5442 self
. assertRegex ( output
, f
'inet6 {ipv6_address} scope global * \n *'
5443 'valid_lft forever preferred_lft forever' )
5445 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
5446 def test_dhcp_client_vrf ( self
):
5447 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-vrf.network' ,
5448 '25-vrf.netdev' , '25-vrf.network' )
5450 self
. wait_online ([ 'veth-peer:carrier' ])
5452 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'vrf99:carrier' ])
5454 # link become 'routable' when at least one protocol provide an valid address.
5455 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5456 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5458 print ( '## ip -d link show dev vrf99' )
5459 output
= check_output ( 'ip -d link show dev vrf99' )
5461 self
. assertRegex ( output
, 'vrf table 42' )
5463 print ( '## ip address show vrf vrf99' )
5464 output
= check_output ( 'ip address show vrf vrf99' )
5466 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5467 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5468 self
. assertRegex ( output
, 'inet6 .* scope link' )
5470 print ( '## ip address show dev veth99' )
5471 output
= check_output ( 'ip address show dev veth99' )
5473 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5474 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5475 self
. assertRegex ( output
, 'inet6 .* scope link' )
5477 print ( '## ip route show vrf vrf99' )
5478 output
= check_output ( 'ip route show vrf vrf99' )
5480 self
. assertRegex ( output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.' )
5481 self
. assertRegex ( output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5' )
5482 self
. assertRegex ( output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5' )
5484 print ( '## ip route show table main dev veth99' )
5485 output
= check_output ( 'ip route show table main dev veth99' )
5487 self
. assertEqual ( output
, '' )
5489 def test_dhcp_client_gateway_onlink_implicit ( self
):
5490 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
5491 '25-dhcp-client-gateway-onlink-implicit.network' )
5493 self
. wait_online ([ 'veth-peer:carrier' ])
5495 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5497 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
5499 self
. assertRegex ( output
, '192.168.5' )
5501 output
= check_output ( 'ip route list dev veth99 10.0.0.0/8' )
5503 self
. assertRegex ( output
, 'onlink' )
5504 output
= check_output ( 'ip route list dev veth99 192.168.100.0/24' )
5506 self
. assertRegex ( output
, 'onlink' )
5508 def test_dhcp_client_with_ipv4ll ( self
):
5509 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
5510 '25-dhcp-client-with-ipv4ll.network' )
5512 # we need to increase timeout above default, as this will need to wait for
5513 # systemd-networkd to get the dhcpv4 transient failure event
5514 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:routable' ], timeout
= '60s' )
5516 output
= check_output ( 'ip -4 address show dev veth99' )
5518 self
. assertNotIn ( '192.168.5.' , output
)
5519 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
5522 print ( 'Wait for a DHCP lease to be acquired and the IPv4LL address to be dropped' )
5523 self
. wait_address ( 'veth99' , r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic' , ipv
= '-4' )
5524 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' )
5525 self
. wait_online ([ 'veth99:routable' ])
5527 output
= check_output ( 'ip -4 address show dev veth99' )
5529 self
. assertRegex ( output
, r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99' )
5530 self
. assertNotIn ( '169.254.' , output
)
5531 self
. assertNotIn ( 'scope link' , output
)
5534 print ( 'Wait for the DHCP lease to be expired and an IPv4LL address to be acquired' )
5535 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 )
5536 self
. wait_address ( 'veth99' , r
'inet 169\.254\.133\.11/16 metric 2048 brd 169\.254\.255\.255 scope link' , scope
= 'link' , ipv
= '-4' )
5538 output
= check_output ( 'ip -4 address show dev veth99' )
5540 self
. assertNotIn ( '192.168.5.' , output
)
5541 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
5543 def test_dhcp_client_use_dns ( self
):
5544 def check ( self
, ipv4
, ipv6
):
5545 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5546 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5547 f
. write ( '[DHCPv4] \n UseDNS=' )
5548 f
. write ( 'yes' if ipv4
else 'no' )
5549 f
. write ( ' \n [DHCPv6] \n UseDNS=' )
5550 f
. write ( 'yes' if ipv6
else 'no' )
5551 f
. write ( ' \n [IPv6AcceptRA] \n UseDNS=no' )
5554 self
. wait_online ([ 'veth99:routable' ])
5556 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5557 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5558 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5560 # make resolved re-read the link state file
5561 check_output (* resolvectl_cmd
, 'revert' , 'veth99' , env
= env
)
5563 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth99' , env
= env
)
5566 self
. assertIn ( '192.168.5.1' , output
)
5568 self
. assertNotIn ( '192.168.5.1' , output
)
5570 self
. assertIn ( '2600::1' , output
)
5572 self
. assertNotIn ( '2600::1' , output
)
5574 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5577 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5580 self
. wait_online ([ 'veth-peer:carrier' ])
5581 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1' ,
5582 '--dhcp-option=option6:dns-server,[2600::1]' )
5584 check ( self
, True , True )
5585 check ( self
, True , False )
5586 check ( self
, False , True )
5587 check ( self
, False , False )
5589 def test_dhcp_client_use_captive_portal ( self
):
5590 def check ( self
, ipv4
, ipv6
):
5591 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5592 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5593 f
. write ( '[DHCPv4] \n UseCaptivePortal=' )
5594 f
. write ( 'yes' if ipv4
else 'no' )
5595 f
. write ( ' \n [DHCPv6] \n UseCaptivePortal=' )
5596 f
. write ( 'yes' if ipv6
else 'no' )
5597 f
. write ( ' \n [IPv6AcceptRA] \n UseCaptivePortal=no' )
5600 self
. wait_online ([ 'veth99:routable' ])
5602 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5603 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5604 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5606 output
= check_output (* networkctl_cmd
, 'status' , 'veth99' , env
= env
)
5609 self
. assertIn ( 'Captive Portal: http://systemd.io' , output
)
5611 self
. assertNotIn ( 'Captive Portal: http://systemd.io' , output
)
5613 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5616 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5619 self
. wait_online ([ 'veth-peer:carrier' ])
5620 start_dnsmasq ( '--dhcp-option=114,http://systemd.io' ,
5621 '--dhcp-option=option6:103,http://systemd.io' )
5623 check ( self
, True , True )
5624 check ( self
, True , False )
5625 check ( self
, False , True )
5626 check ( self
, False , False )
5628 def test_dhcp_client_reject_captive_portal ( self
):
5629 def check ( self
, ipv4
, ipv6
):
5630 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5631 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5632 f
. write ( '[DHCPv4] \n UseCaptivePortal=' )
5633 f
. write ( 'yes' if ipv4
else 'no' )
5634 f
. write ( ' \n [DHCPv6] \n UseCaptivePortal=' )
5635 f
. write ( 'yes' if ipv6
else 'no' )
5636 f
. write ( ' \n [IPv6AcceptRA] \n UseCaptivePortal=no' )
5639 self
. wait_online ([ 'veth99:routable' ])
5641 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5642 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5643 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5645 output
= check_output (* networkctl_cmd
, 'status' , 'veth99' , env
= env
)
5647 self
. assertNotIn ( 'Captive Portal: ' , output
)
5648 self
. assertNotIn ( 'invalid/url' , output
)
5650 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5653 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5656 self
. wait_online ([ 'veth-peer:carrier' ])
5657 masq
= lambda bs
: ':' . join ( f
'{b:02x}' for b
in bs
)
5658 start_dnsmasq ( '--dhcp-option=114,' + masq ( b
'http:// \x00 invalid/url' ),
5659 '--dhcp-option=option6:103,' + masq ( b
'http:// \x00 /invalid/url' ))
5661 check ( self
, True , True )
5662 check ( self
, True , False )
5663 check ( self
, False , True )
5664 check ( self
, False , False )
5666 class NetworkdDHCPPDTests ( unittest
. TestCase
, Utilities
):
5674 def test_dhcp6pd ( self
):
5675 copy_network_unit ( '25-veth.netdev' , '25-dhcp6pd-server.network' , '25-dhcp6pd-upstream.network' ,
5676 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
5677 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
5678 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
5679 '25-dhcp-pd-downstream-dummy97.network' ,
5680 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
5681 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' )
5683 self
. setup_nftset ( 'addr6' , 'ipv6_addr' )
5684 self
. setup_nftset ( 'network6' , 'ipv6_addr' , 'flags interval;' )
5685 self
. setup_nftset ( 'ifindex' , 'iface_index' )
5688 self
. wait_online ([ 'veth-peer:routable' ])
5689 start_isc_dhcpd ( conf_file
= 'isc-dhcpd-dhcp6pd.conf' , ipv
= '-6' )
5690 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5691 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5693 print ( '### ip -6 address show dev veth-peer scope global' )
5694 output
= check_output ( 'ip -6 address show dev veth-peer scope global' )
5696 self
. assertIn ( 'inet6 3ffe:501:ffff:100::1/64 scope global' , output
)
5700 # dummy97: 0x01 (The link will appear later)
5702 # dummy99: auto -> 0x02 (No address assignment)
5707 print ( '### ip -6 address show dev veth99 scope global' )
5708 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5711 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:100::[0-9]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5712 # address in IA_PD (Token=static)
5713 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic' )
5714 # address in IA_PD (Token=eui64)
5715 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic' )
5716 # address in IA_PD (temporary)
5717 # Note that the temporary addresses may appear after the link enters configured state
5718 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' )
5720 print ( '### ip -6 address show dev test1 scope global' )
5721 output
= check_output ( 'ip -6 address show dev test1 scope global' )
5723 # address in IA_PD (Token=static)
5724 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5725 # address in IA_PD (temporary)
5726 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' )
5728 print ( '### ip -6 address show dev dummy98 scope global' )
5729 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5731 # address in IA_PD (Token=static)
5732 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5733 # address in IA_PD (temporary)
5734 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' )
5736 print ( '### ip -6 address show dev dummy99 scope global' )
5737 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5740 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
5742 print ( '### ip -6 address show dev veth97 scope global' )
5743 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
5745 # address in IA_PD (Token=static)
5746 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5747 # address in IA_PD (Token=eui64)
5748 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5749 # address in IA_PD (temporary)
5750 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' )
5752 print ( '### ip -6 address show dev veth97-peer scope global' )
5753 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
5755 # NDisc address (Token=static)
5756 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5757 # NDisc address (Token=eui64)
5758 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5759 # NDisc address (temporary)
5760 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' )
5762 print ( '### ip -6 address show dev veth98 scope global' )
5763 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
5765 # address in IA_PD (Token=static)
5766 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5767 # address in IA_PD (Token=eui64)
5768 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5769 # address in IA_PD (temporary)
5770 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' )
5772 print ( '### ip -6 address show dev veth98-peer scope global' )
5773 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
5775 # NDisc address (Token=static)
5776 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5777 # NDisc address (Token=eui64)
5778 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5779 # NDisc address (temporary)
5780 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' )
5782 print ( '### ip -6 route show type unreachable' )
5783 output
= check_output ( 'ip -6 route show type unreachable' )
5785 self
. assertRegex ( output
, 'unreachable 3ffe:501:ffff:[2-9a-f]00::/56 dev lo proto dhcp' )
5787 print ( '### ip -6 route show dev veth99' )
5788 output
= check_output ( 'ip -6 route show dev veth99' )
5790 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]10::/64 proto kernel metric [0-9]* expires' )
5792 print ( '### ip -6 route show dev test1' )
5793 output
= check_output ( 'ip -6 route show dev test1' )
5795 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
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 print ( '### ip -6 route show dev veth97' )
5808 output
= check_output ( 'ip -6 route show dev veth97' )
5810 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto kernel metric [0-9]* expires' )
5812 print ( '### ip -6 route show dev veth97-peer' )
5813 output
= check_output ( 'ip -6 route show dev veth97-peer' )
5815 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto ra metric [0-9]* expires' )
5817 print ( '### ip -6 route show dev veth98' )
5818 output
= check_output ( 'ip -6 route show dev veth98' )
5820 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto kernel metric [0-9]* expires' )
5822 print ( '### ip -6 route show dev veth98-peer' )
5823 output
= check_output ( 'ip -6 route show dev veth98-peer' )
5825 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto ra metric [0-9]* expires' )
5827 # Test case for a downstream which appears later
5828 check_output ( 'ip link add dummy97 type dummy' )
5829 self
. wait_online ([ 'dummy97:routable' ])
5831 print ( '### ip -6 address show dev dummy97 scope global' )
5832 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
5834 # address in IA_PD (Token=static)
5835 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5836 # address in IA_PD (temporary)
5837 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' )
5839 print ( '### ip -6 route show dev dummy97' )
5840 output
= check_output ( 'ip -6 route show dev dummy97' )
5842 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]01::/64 proto kernel metric [0-9]* expires' )
5844 # Test case for reconfigure
5845 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
5846 self
. wait_online ([ 'dummy98:routable' , 'dummy99:degraded' ])
5848 print ( '### ip -6 address show dev dummy98 scope global' )
5849 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5851 # address in IA_PD (Token=static)
5852 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5853 # address in IA_PD (temporary)
5854 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' )
5856 print ( '### ip -6 address show dev dummy99 scope global' )
5857 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5860 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
5862 print ( '### ip -6 route show dev dummy98' )
5863 output
= check_output ( 'ip -6 route show dev dummy98' )
5865 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5867 print ( '### ip -6 route show dev dummy99' )
5868 output
= check_output ( 'ip -6 route show dev dummy99' )
5870 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
5872 self
. check_netlabel ( 'dummy98' , '3ffe:501:ffff:[2-9a-f]00::/64' )
5874 self
. check_nftset ( 'addr6' , '3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d' )
5875 self
. check_nftset ( 'addr6' , '3ffe:501:ffff:[2-9a-f]00:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*' )
5876 self
. check_nftset ( 'network6' , '3ffe:501:ffff:[2-9a-f]00::/64' )
5877 self
. check_nftset ( 'ifindex' , 'dummy98' )
5879 self
. teardown_nftset ( 'addr6' , 'network6' , 'ifindex' )
5881 def verify_dhcp4_6rd ( self
, tunnel_name
):
5882 print ( '### ip -4 address show dev veth-peer scope global' )
5883 output
= check_output ( 'ip -4 address show dev veth-peer scope global' )
5885 self
. assertIn ( 'inet 10.0.0.1/8 brd 10.255.255.255 scope global veth-peer' , output
)
5889 # dummy97: 0x01 (The link will appear later)
5891 # dummy99: auto -> 0x0[23] (No address assignment)
5892 # 6rd-XXX: auto -> 0x0[23]
5897 print ( '### ip -4 address show dev veth99 scope global' )
5898 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
5900 self
. assertRegex ( output
, 'inet 10.100.100.[0-9]*/8 (metric 1024 |)brd 10.255.255.255 scope global dynamic veth99' )
5902 print ( '### ip -6 address show dev veth99 scope global' )
5903 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5905 # address in IA_PD (Token=static)
5906 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5907 # address in IA_PD (Token=eui64)
5908 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5909 # address in IA_PD (temporary)
5910 # Note that the temporary addresses may appear after the link enters configured state
5911 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' )
5913 print ( '### ip -6 address show dev test1 scope global' )
5914 output
= check_output ( 'ip -6 address show dev test1 scope global' )
5916 # address in IA_PD (Token=static)
5917 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5918 # address in IA_PD (temporary)
5919 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' )
5921 print ( '### ip -6 address show dev dummy98 scope global' )
5922 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5924 # address in IA_PD (Token=static)
5925 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5926 # address in IA_PD (temporary)
5927 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' )
5929 print ( '### ip -6 address show dev dummy99 scope global' )
5930 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5933 self
. assertNotRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+0[23]' )
5935 print ( '### ip -6 address show dev veth97 scope global' )
5936 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
5938 # address in IA_PD (Token=static)
5939 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5940 # address in IA_PD (Token=eui64)
5941 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5942 # address in IA_PD (temporary)
5943 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' )
5945 print ( '### ip -6 address show dev veth97-peer scope global' )
5946 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
5948 # NDisc address (Token=static)
5949 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5950 # NDisc address (Token=eui64)
5951 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5952 # NDisc address (temporary)
5953 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' )
5955 print ( '### ip -6 address show dev veth98 scope global' )
5956 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
5958 # address in IA_PD (Token=static)
5959 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5960 # address in IA_PD (Token=eui64)
5961 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5962 # address in IA_PD (temporary)
5963 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' )
5965 print ( '### ip -6 address show dev veth98-peer scope global' )
5966 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
5968 # NDisc address (Token=static)
5969 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5970 # NDisc address (Token=eui64)
5971 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5972 # NDisc address (temporary)
5973 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' )
5975 print ( '### ip -6 route show type unreachable' )
5976 output
= check_output ( 'ip -6 route show type unreachable' )
5978 self
. assertRegex ( output
, 'unreachable 2001:db8:6464:[0-9a-f]+00::/56 dev lo proto dhcp' )
5980 print ( '### ip -6 route show dev veth99' )
5981 output
= check_output ( 'ip -6 route show dev veth99' )
5983 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+10::/64 proto kernel metric [0-9]* expires' )
5985 print ( '### ip -6 route show dev test1' )
5986 output
= check_output ( 'ip -6 route show dev test1' )
5988 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
5990 print ( '### ip -6 route show dev dummy98' )
5991 output
= check_output ( 'ip -6 route show dev dummy98' )
5993 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
5995 print ( '### ip -6 route show dev dummy99' )
5996 output
= check_output ( 'ip -6 route show dev dummy99' )
5998 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto dhcp metric [0-9]* expires' )
6000 print ( '### ip -6 route show dev veth97' )
6001 output
= check_output ( 'ip -6 route show dev veth97' )
6003 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto kernel metric [0-9]* expires' )
6005 print ( '### ip -6 route show dev veth97-peer' )
6006 output
= check_output ( 'ip -6 route show dev veth97-peer' )
6008 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto ra metric [0-9]* expires' )
6010 print ( '### ip -6 route show dev veth98' )
6011 output
= check_output ( 'ip -6 route show dev veth98' )
6013 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto kernel metric [0-9]* expires' )
6015 print ( '### ip -6 route show dev veth98-peer' )
6016 output
= check_output ( 'ip -6 route show dev veth98-peer' )
6018 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto ra metric [0-9]* expires' )
6020 print ( '### ip -6 address show dev dummy97 scope global' )
6021 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
6023 # address in IA_PD (Token=static)
6024 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6025 # address in IA_PD (temporary)
6026 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' )
6028 print ( '### ip -6 route show dev dummy97' )
6029 output
= check_output ( 'ip -6 route show dev dummy97' )
6031 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+01::/64 proto kernel metric [0-9]* expires' )
6033 print ( f
'### ip -d link show dev {tunnel_name} ' )
6034 output
= check_output ( f
'ip -d link show dev {tunnel_name} ' )
6036 self
. assertIn ( 'link/sit 10.100.100.' , output
)
6037 self
. assertIn ( 'local 10.100.100.' , output
)
6038 self
. assertIn ( 'ttl 64' , output
)
6039 self
. assertIn ( '6rd-prefix 2001:db8::/32' , output
)
6040 self
. assertIn ( '6rd-relay_prefix 10.0.0.0/8' , output
)
6042 print ( f
'### ip -6 address show dev {tunnel_name} ' )
6043 output
= check_output ( f
'ip -6 address show dev {tunnel_name} ' )
6045 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' )
6046 self
. assertRegex ( output
, 'inet6 ::10.100.100.[0-9]+/96 scope global' )
6048 print ( f
'### ip -6 route show dev {tunnel_name} ' )
6049 output
= check_output ( f
'ip -6 route show dev {tunnel_name} ' )
6051 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto kernel metric [0-9]* expires' )
6052 self
. assertRegex ( output
, '::/96 proto kernel metric [0-9]*' )
6054 print ( '### ip -6 route show default' )
6055 output
= check_output ( 'ip -6 route show default' )
6057 self
. assertIn ( 'default' , output
)
6058 self
. assertIn ( f
'via ::10.0.0.1 dev {tunnel_name} ' , output
)
6060 def test_dhcp4_6rd ( self
):
6061 copy_network_unit ( '25-veth.netdev' , '25-dhcp4-6rd-server.network' , '25-dhcp4-6rd-upstream.network' ,
6062 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
6063 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
6064 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
6065 '25-dhcp-pd-downstream-dummy97.network' ,
6066 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
6067 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' ,
6068 '80-6rd-tunnel.network' )
6071 self
. wait_online ([ 'veth-peer:routable' ])
6074 # 6rd-prefix: 2001:db8::/32
6075 # br-addresss: 10.0.0.1
6077 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' ,
6078 ipv4_range
= '10.100.100.100,10.100.100.200' ,
6079 ipv4_router
= '10.0.0.1' )
6080 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
6081 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
6083 # Test case for a downstream which appears later
6084 check_output ( 'ip link add dummy97 type dummy' )
6085 self
. wait_online ([ 'dummy97:routable' ])
6089 for name
in os
. listdir ( '/sys/class/net/' ):
6090 if name
. startswith ( '6rd-' ):
6094 self
. wait_online ([ f
' {tunnel_name} :routable' ])
6096 self
. verify_dhcp4_6rd ( tunnel_name
)
6098 # Test case for reconfigure
6099 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
6100 self
. wait_online ([ 'dummy98:routable' , 'dummy99:degraded' ])
6102 self
. verify_dhcp4_6rd ( tunnel_name
)
6104 print ( 'Wait for the DHCP lease to be renewed/rebind' )
6107 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy97:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
6108 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
6110 self
. verify_dhcp4_6rd ( tunnel_name
)
6112 class NetworkdIPv6PrefixTests ( unittest
. TestCase
, Utilities
):
6120 def test_ipv6_route_prefix ( self
):
6121 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client.network' , '25-ipv6ra-prefix.network' ,
6122 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
6125 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
6127 output
= check_output ( 'ip address show dev veth-peer' )
6129 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
6130 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
6131 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
6133 output
= check_output ( 'ip -6 route show dev veth-peer' )
6135 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
6136 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
6137 self
. assertNotIn ( '2001:db8:0:3::/64 proto ra' , output
)
6138 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
6139 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
6140 self
. assertNotIn ( '2001:db2:fff::/64 via ' , output
)
6142 output
= check_output ( 'ip address show dev veth99' )
6144 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
6145 self
. assertIn ( 'inet6 2001:db8:0:2:1a:2b:3c:4d' , output
)
6146 self
. assertIn ( 'inet6 2001:db8:0:2:fa:de:ca:fe' , output
)
6147 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
6149 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth-peer' , env
= env
)
6151 self
. assertRegex ( output
, '2001:db8:1:1::2' )
6153 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth-peer' , env
= env
)
6155 self
. assertIn ( 'example.com' , output
)
6157 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
6160 def test_ipv6_route_prefix_deny_list ( self
):
6161 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client-deny-list.network' , '25-ipv6ra-prefix.network' ,
6162 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
6165 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
6167 output
= check_output ( 'ip address show dev veth-peer' )
6169 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
6170 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
6172 output
= check_output ( 'ip -6 route show dev veth-peer' )
6174 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
6175 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
6176 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
6177 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
6179 output
= check_output ( 'ip address show dev veth99' )
6181 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
6182 self
. assertIn ( 'inet6 2001:db8:0:2:' , output
)
6184 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth-peer' , env
= env
)
6186 self
. assertRegex ( output
, '2001:db8:1:1::2' )
6188 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth-peer' , env
= env
)
6190 self
. assertIn ( 'example.com' , output
)
6192 class NetworkdMTUTests ( unittest
. TestCase
, Utilities
):
6200 def check_mtu ( self
, mtu
, ipv6_mtu
= None , reset
= True ):
6206 self
. wait_online ([ 'dummy98:routable' ])
6207 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
6208 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
6210 # test normal restart
6212 self
. wait_online ([ 'dummy98:routable' ])
6213 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
6214 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
6217 self
. reset_check_mtu ( mtu
, ipv6_mtu
)
6219 def reset_check_mtu ( self
, mtu
, ipv6_mtu
= None ):
6220 ''' test setting mtu/ipv6_mtu with interface already up '''
6223 # note - changing the device mtu resets the ipv6 mtu
6224 check_output ( 'ip link set up mtu 1501 dev dummy98' )
6225 check_output ( 'ip link set up mtu 1500 dev dummy98' )
6226 self
. check_link_attr ( 'dummy98' , 'mtu' , '1500' )
6227 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , '1500' )
6229 self
. check_mtu ( mtu
, ipv6_mtu
, reset
= False )
6231 def test_mtu_network ( self
):
6232 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' )
6233 self
. check_mtu ( '1600' )
6235 def test_mtu_netdev ( self
):
6236 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network' , copy_dropins
= False )
6237 # note - MTU set by .netdev happens ONLY at device creation!
6238 self
. check_mtu ( '1600' , reset
= False )
6240 def test_mtu_link ( self
):
6241 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network' , copy_dropins
= False )
6242 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
6243 self
. check_mtu ( '1600' , reset
= False )
6245 def test_ipv6_mtu ( self
):
6246 ''' set ipv6 mtu without setting device mtu '''
6247 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1400.conf' )
6248 self
. check_mtu ( '1500' , '1400' )
6250 def test_ipv6_mtu_toolarge ( self
):
6251 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
6252 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
6253 self
. check_mtu ( '1500' , '1500' )
6255 def test_mtu_network_ipv6_mtu ( self
):
6256 ''' set ipv6 mtu and set device mtu via network file '''
6257 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
6258 self
. check_mtu ( '1600' , '1550' )
6260 def test_mtu_netdev_ipv6_mtu ( self
):
6261 ''' set ipv6 mtu and set device mtu via netdev file '''
6262 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
6263 self
. check_mtu ( '1600' , '1550' , reset
= False )
6265 def test_mtu_link_ipv6_mtu ( self
):
6266 ''' set ipv6 mtu and set device mtu via link file '''
6267 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
6268 self
. check_mtu ( '1600' , '1550' , reset
= False )
6271 if __name__
== '__main__' :
6272 parser
= argparse
. ArgumentParser ()
6273 parser
. add_argument ( '--build-dir' , help = 'Path to build dir' , dest
= 'build_dir' )
6274 parser
. add_argument ( '--networkd' , help = 'Path to systemd-networkd' , dest
= 'networkd_bin' )
6275 parser
. add_argument ( '--resolved' , help = 'Path to systemd-resolved' , dest
= 'resolved_bin' )
6276 parser
. add_argument ( '--timesyncd' , help = 'Path to systemd-timesyncd' , dest
= 'timesyncd_bin' )
6277 parser
. add_argument ( '--udevd' , help = 'Path to systemd-udevd' , dest
= 'udevd_bin' )
6278 parser
. add_argument ( '--wait-online' , help = 'Path to systemd-networkd-wait-online' , dest
= 'wait_online_bin' )
6279 parser
. add_argument ( '--networkctl' , help = 'Path to networkctl' , dest
= 'networkctl_bin' )
6280 parser
. add_argument ( '--resolvectl' , help = 'Path to resolvectl' , dest
= 'resolvectl_bin' )
6281 parser
. add_argument ( '--timedatectl' , help = 'Path to timedatectl' , dest
= 'timedatectl_bin' )
6282 parser
. add_argument ( '--udevadm' , help = 'Path to udevadm' , dest
= 'udevadm_bin' )
6283 parser
. add_argument ( '--valgrind' , help = 'Enable valgrind' , dest
= 'use_valgrind' , type = bool , nargs
= '?' , const
= True , default
= use_valgrind
)
6284 parser
. add_argument ( '--debug' , help = 'Generate debugging logs' , dest
= 'enable_debug' , type = bool , nargs
= '?' , const
= True , default
= enable_debug
)
6285 parser
. add_argument ( '--asan-options' , help = 'ASAN options' , dest
= 'asan_options' )
6286 parser
. add_argument ( '--lsan-options' , help = 'LSAN options' , dest
= 'lsan_options' )
6287 parser
. add_argument ( '--ubsan-options' , help = 'UBSAN options' , dest
= 'ubsan_options' )
6288 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
)
6289 ns
, unknown_args
= parser
. parse_known_args ( namespace
= unittest
)
6292 if ns
. networkd_bin
or ns
. resolved_bin
or ns
. timesyncd_bin
or ns
. udevd_bin
or \
6293 ns
. wait_online_bin
or ns
. networkctl_bin
or ns
. resolvectl_bin
or ns
. timedatectl_bin
or ns
. udevadm_bin
:
6294 print ( 'WARNING: --networkd, --resolved, --timesyncd, --udevd, --wait-online, --networkctl, --resolvectl, --timedatectl, or --udevadm options are ignored when --build-dir is specified.' )
6295 networkd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd' )
6296 resolved_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-resolved' )
6297 timesyncd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-timesyncd' )
6298 udevd_bin
= os
. path
. join ( ns
. build_dir
, 'udevadm' )
6299 wait_online_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd-wait-online' )
6300 networkctl_bin
= os
. path
. join ( ns
. build_dir
, 'networkctl' )
6301 resolvectl_bin
= os
. path
. join ( ns
. build_dir
, 'resolvectl' )
6302 timedatectl_bin
= os
. path
. join ( ns
. build_dir
, 'timedatectl' )
6303 udevadm_bin
= os
. path
. join ( ns
. build_dir
, 'udevadm' )
6306 networkd_bin
= ns
. networkd_bin
6308 resolved_bin
= ns
. resolved_bin
6309 if ns
. timesyncd_bin
:
6310 timesyncd_bin
= ns
. timesyncd_bin
6312 udevd_bin
= ns
. udevd_bin
6313 if ns
. wait_online_bin
:
6314 wait_online_bin
= ns
. wait_online_bin
6315 if ns
. networkctl_bin
:
6316 networkctl_bin
= ns
. networkctl_bin
6317 if ns
. resolvectl_bin
:
6318 resolvectl_bin
= ns
. resolvectl_bin
6319 if ns
. timedatectl_bin
:
6320 timedatectl_bin
= ns
. timedatectl_bin
6322 udevadm_bin
= ns
. udevadm_bin
6324 use_valgrind
= ns
. use_valgrind
6325 enable_debug
= ns
. enable_debug
6326 asan_options
= ns
. asan_options
6327 lsan_options
= ns
. lsan_options
6328 ubsan_options
= ns
. ubsan_options
6329 with_coverage
= ns
. with_coverage
6332 # Do not forget the trailing space.
6333 valgrind_cmd
= 'valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all '
6335 networkctl_cmd
= valgrind_cmd
. split () + [ networkctl_bin
]
6336 resolvectl_cmd
= valgrind_cmd
. split () + [ resolvectl_bin
]
6337 timedatectl_cmd
= valgrind_cmd
. split () + [ timedatectl_bin
]
6338 udevadm_cmd
= valgrind_cmd
. split () + [ udevadm_bin
]
6339 wait_online_cmd
= valgrind_cmd
. split () + [ wait_online_bin
]
6342 env
. update ({ 'ASAN_OPTIONS' : asan_options
})
6344 env
. update ({ 'LSAN_OPTIONS' : lsan_options
})
6346 env
. update ({ 'UBSAN_OPTIONS' : ubsan_options
})
6348 env
. update ({ 'SYSTEMD_MEMPOOL' : '0' })
6350 wait_online_env
= env
. copy ()
6352 wait_online_env
. update ({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
6354 sys
. argv
[ 1 :] = unknown_args
6355 unittest
. main ( verbosity
= 3 )