]>
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.
25 network_unit_dir
= '/run/systemd/network'
26 networkd_conf_dropin_dir
= '/run/systemd/networkd.conf.d'
27 networkd_ci_temp_dir
= '/run/networkd-ci'
28 udev_rules_dir
= '/run/udev/rules.d'
30 dnsmasq_pid_file
= '/run/networkd-ci/test-dnsmasq.pid'
31 dnsmasq_log_file
= '/run/networkd-ci/test-dnsmasq.log'
32 dnsmasq_lease_file
= '/run/networkd-ci/test-dnsmasq.lease'
34 isc_dhcpd_pid_file
= '/run/networkd-ci/test-isc-dhcpd.pid'
35 isc_dhcpd_lease_file
= '/run/networkd-ci/test-isc-dhcpd.lease'
37 radvd_pid_file
= '/run/networkd-ci/test-radvd.pid'
39 systemd_lib_paths
= [ '/usr/lib/systemd' , '/lib/systemd' ]
40 which_paths
= ':' . join ( systemd_lib_paths
+ os
. getenv ( 'PATH' , os
. defpath
). lstrip ( ':' ). split ( ':' ))
42 networkd_bin
= shutil
. which ( 'systemd-networkd' , path
= which_paths
)
43 resolved_bin
= shutil
. which ( 'systemd-resolved' , path
= which_paths
)
44 timesyncd_bin
= shutil
. which ( 'systemd-timesyncd' , path
= which_paths
)
45 udevd_bin
= shutil
. which ( 'systemd-udevd' , path
= which_paths
)
46 wait_online_bin
= shutil
. which ( 'systemd-networkd-wait-online' , path
= which_paths
)
47 networkctl_bin
= shutil
. which ( 'networkctl' , path
= which_paths
)
48 resolvectl_bin
= shutil
. which ( 'resolvectl' , path
= which_paths
)
49 timedatectl_bin
= shutil
. which ( 'timedatectl' , path
= which_paths
)
50 udevadm_bin
= shutil
. which ( 'udevadm' , path
= which_paths
)
78 saved_ipv4_rules
= None
79 saved_ipv6_rules
= None
83 if os
. path
. exists ( path
):
87 shutil
. rmtree ( path
, ignore_errors
= True )
93 shutil
. copytree ( src
, dst
, copy_function
= shutil
. copy
)
96 os
. makedirs ( path
, exist_ok
= True )
99 pathlib
. Path ( path
). touch ()
101 # pylint: disable=R1710
102 def check_output (* command
, ** kwargs
):
103 # This checks the result and returns stdout (and stderr) on success.
104 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
105 ret
= subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. PIPE
, stderr
= subprocess
. STDOUT
, ** kwargs
)
106 if ret
. returncode
== 0 :
107 return ret
. stdout
. rstrip ()
108 # When returncode != 0, print stdout and stderr, then trigger CalledProcessError.
110 ret
. check_returncode ()
112 def call (* command
, ** kwargs
):
113 # This returns returncode. stdout and stderr are merged and shown in console
114 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
115 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stderr
= subprocess
. STDOUT
, ** kwargs
). returncode
117 def call_check (* command
, ** kwargs
):
118 # Same as call() above, but it triggers CalledProcessError if rc != 0
119 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
120 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stderr
= subprocess
. STDOUT
, ** kwargs
). check_returncode ()
122 def call_quiet (* command
, ** kwargs
):
123 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
124 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. DEVNULL
, stderr
= subprocess
. DEVNULL
, ** kwargs
). returncode
126 def run (* command
, ** kwargs
):
127 # This returns CompletedProcess instance.
128 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
129 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. PIPE
, stderr
= subprocess
. PIPE
, ** kwargs
)
131 def check_json ( string
):
134 except json
. JSONDecodeError
:
135 print ( f
"String is not a valid JSON: ' {string} '" )
138 def is_module_available (* module_names
):
139 for module_name
in module_names
:
140 lsmod_output
= check_output ( 'lsmod' )
141 module_re
= re
. compile ( rf
'^{re.escape(module_name)} \b ' , re
. MULTILINE
)
142 if not module_re
. search ( lsmod_output
) and call_quiet ( 'modprobe' , module_name
) != 0 :
146 def expectedFailureIfModuleIsNotAvailable (* module_names
):
148 return func
if is_module_available (* module_names
) else unittest
. expectedFailure ( func
)
152 def expectedFailureIfERSPANv0IsNotSupported ():
153 # erspan version 0 is supported since f989d546a2d5a9f001f6f8be49d98c10ab9b1897 (v5.8)
155 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' )
156 remove_link ( 'erspan99' )
157 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
161 def expectedFailureIfERSPANv2IsNotSupported ():
162 # erspan version 2 is supported since f551c91de262ba36b20c3ac19538afb4f4507441 (v4.16)
164 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' )
165 remove_link ( 'erspan99' )
166 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
170 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable ():
172 rc
= call_quiet ( 'ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7' )
173 call_quiet ( 'ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7' )
174 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
178 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable ():
180 rc
= call_quiet ( 'ip rule add not from 192.168.100.19 ipproto tcp table 7' )
181 call_quiet ( 'ip rule del not from 192.168.100.19 ipproto tcp table 7' )
182 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
186 def expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable ():
189 if call_quiet ( 'ip rule add from 192.168.100.19 table 7 uidrange 200-300' ) == 0 :
190 ret
= run ( 'ip rule list from 192.168.100.19 table 7' )
191 supported
= ret
. returncode
== 0 and 'uidrange 200-300' in ret
. stdout
192 call_quiet ( 'ip rule del from 192.168.100.19 table 7 uidrange 200-300' )
193 return func
if supported
else unittest
. expectedFailure ( func
)
197 def expectedFailureIfNexthopIsNotAvailable ():
199 rc
= call_quiet ( 'ip nexthop list' )
200 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
204 def expectedFailureIfRTA_VIAIsNotSupported ():
206 call_quiet ( 'ip link add dummy98 type dummy' )
207 call_quiet ( 'ip link set up dev dummy98' )
208 call_quiet ( 'ip route add 2001:1234:5:8fff:ff:ff:ff:fe/128 dev dummy98' )
209 rc
= call_quiet ( 'ip route add 10.10.10.10 via inet6 2001:1234:5:8fff:ff:ff:ff:fe dev dummy98' )
210 remove_link ( 'dummy98' )
211 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
215 def expectedFailureIfAlternativeNameIsNotAvailable ():
217 call_quiet ( 'ip link add dummy98 type dummy' )
219 call_quiet ( 'ip link prop add dev dummy98 altname hogehogehogehogehoge' ) == 0 and \
220 call_quiet ( 'ip link show dev hogehogehogehogehoge' ) == 0
221 remove_link ( 'dummy98' )
222 return func
if supported
else unittest
. expectedFailure ( func
)
226 def expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ():
228 def finalize ( func
, supported
):
229 call_quiet ( 'rmmod netdevsim' )
230 return func
if supported
else unittest
. expectedFailure ( func
)
232 call_quiet ( 'rmmod netdevsim' )
233 if call_quiet ( 'modprobe netdevsim' ) != 0 :
234 return finalize ( func
, False )
237 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
240 return finalize ( func
, False )
242 return finalize ( func
, os
. path
. exists ( '/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs' ))
246 # pylint: disable=C0415
247 def compare_kernel_version ( min_kernel_version
):
250 from packaging
import version
252 print ( 'Failed to import either platform or packaging module, assuming the comparison failed' )
255 # Get only the actual kernel version without any build/distro/arch stuff
256 # e.g. '5.18.5-200.fc36.x86_64' -> '5.18.5'
257 kver
= platform
. release (). split ( '-' )[ 0 ]
259 return version
. parse ( kver
) >= version
. parse ( min_kernel_version
)
262 check_output (* udevadm_cmd
, 'control' , '--reload' )
264 def copy_network_unit (* units
, copy_dropins
= True ):
266 Copy networkd unit files into the testbed.
268 Any networkd unit file type can be specified, as well as drop-in files.
270 By default, all drop-ins for a specified unit file are copied in;
271 to avoid that specify dropins=False.
273 When a drop-in file is specified, its unit file is also copied in automatically.
276 mkdir_p ( network_unit_dir
)
278 if copy_dropins
and os
. path
. exists ( os
. path
. join ( networkd_ci_temp_dir
, unit
+ '.d' )):
279 cp_r ( os
. path
. join ( networkd_ci_temp_dir
, unit
+ '.d' ), os
. path
. join ( network_unit_dir
, unit
+ '.d' ))
281 if unit
. endswith ( '.conf' ):
283 unit
= os
. path
. dirname ( dropin
). rstrip ( '.d' )
284 dropindir
= os
. path
. join ( network_unit_dir
, unit
+ '.d' )
286 cp ( os
. path
. join ( networkd_ci_temp_dir
, dropin
), dropindir
)
288 cp ( os
. path
. join ( networkd_ci_temp_dir
, unit
), network_unit_dir
)
290 if unit
. endswith ( '.link' ):
296 def remove_network_unit (* units
):
298 Remove previously copied unit files from the testbed.
300 Drop-ins will be removed automatically.
304 rm_f ( os
. path
. join ( network_unit_dir
, unit
))
305 rm_rf ( os
. path
. join ( network_unit_dir
, unit
+ '.d' ))
307 if unit
. endswith ( '.link' ) or unit
. endswith ( '.link.d' ):
313 def clear_network_units ():
315 if os
. path
. exists ( network_unit_dir
):
316 units
= os
. listdir ( network_unit_dir
)
318 if unit
. endswith ( '.link' ) or unit
. endswith ( '.link.d' ):
321 rm_rf ( network_unit_dir
)
326 def copy_networkd_conf_dropin (* dropins
):
327 """Copy networkd.conf dropin files into the testbed."""
328 mkdir_p ( networkd_conf_dropin_dir
)
329 for dropin
in dropins
:
330 cp ( os
. path
. join ( networkd_ci_temp_dir
, dropin
), networkd_conf_dropin_dir
)
332 def remove_networkd_conf_dropin (* dropins
):
333 """Remove previously copied networkd.conf dropin files from the testbed."""
334 for dropin
in dropins
:
335 rm_f ( os
. path
. join ( networkd_conf_dropin_dir
, dropin
))
337 def clear_networkd_conf_dropins ():
338 rm_rf ( networkd_conf_dropin_dir
)
340 def copy_udev_rule (* rules
):
341 """Copy udev rules"""
342 mkdir_p ( udev_rules_dir
)
344 cp ( os
. path
. join ( networkd_ci_temp_dir
, rule
), udev_rules_dir
)
346 def remove_udev_rule (* rules
):
347 """Remove previously copied udev rules"""
349 rm_f ( os
. path
. join ( udev_rules_dir
, rule
))
351 def clear_udev_rules ():
352 rm_rf ( udev_rules_dir
)
354 def save_active_units ():
355 for u
in [ 'systemd-networkd.socket' , 'systemd-networkd.service' ,
356 'systemd-resolved.service' , 'systemd-timesyncd.service' ,
357 'firewalld.service' ]:
358 if call ( f
'systemctl is-active --quiet {u} ' ) == 0 :
359 call ( f
'systemctl stop {u} ' )
360 active_units
. append ( u
)
362 def restore_active_units ():
363 if 'systemd-networkd.socket' in active_units
:
364 call ( 'systemctl stop systemd-networkd.socket systemd-networkd.service' )
365 for u
in active_units
:
366 call ( f
'systemctl restart {u} ' )
368 def create_unit_dropin ( unit
, contents
):
369 mkdir_p ( f
'/run/systemd/system/ {unit} .d' )
370 with
open ( f
'/run/systemd/system/ {unit} .d/00-override.conf' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
371 f
. write ( ' \n ' . join ( contents
))
373 def create_service_dropin ( service
, command
, additional_settings
= None ):
377 f
'ExecStart=!! {valgrind_cmd}{command} ' ,
380 drop_in
+= [ 'Environment=SYSTEMD_LOG_LEVEL=debug' ]
382 drop_in
+= [ f
'Environment=ASAN_OPTIONS=" {asan_options} "' ]
384 drop_in
+= [ f
'Environment=LSAN_OPTIONS=" {lsan_options} "' ]
386 drop_in
+= [ f
'Environment=UBSAN_OPTIONS=" {ubsan_options} "' ]
387 if asan_options
or lsan_options
or ubsan_options
:
388 drop_in
+= [ 'SystemCallFilter=' ]
389 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
390 drop_in
+= [ 'MemoryDenyWriteExecute=no' ]
393 'Environment=SYSTEMD_MEMPOOL=0' ,
401 if additional_settings
:
402 drop_in
+= additional_settings
404 create_unit_dropin ( f
' {service} .service' , drop_in
)
406 def link_exists ( link
):
407 return call_quiet ( f
'ip link show {link} ' ) == 0
409 def link_resolve ( link
):
410 return check_output ( f
'ip link show {link} ' ). split ( ':' )[ 1 ]. strip ()
412 def remove_link (* links
, protect
= False ):
414 if protect
and link
in protected_links
:
416 if link_exists ( link
):
417 call ( f
'ip link del dev {link} ' )
419 def save_existing_links ():
420 links
= os
. listdir ( '/sys/class/net' )
422 if link_exists ( link
):
423 protected_links
. add ( link
)
425 print ( '### The following links will be protected:' )
426 print ( ', ' . join ( sorted ( list ( protected_links
))))
429 links
= os
. listdir ( '/sys/class/net' )
430 remove_link (* links
, protect
= True )
432 def flush_nexthops ():
433 # Currently, the 'ip nexthop' command does not have 'save' and 'restore'.
434 # Hence, we cannot restore nexthops in a simple way.
435 # Let's assume there is no nexthop used in the system
436 call_quiet ( 'ip nexthop flush' )
439 # pylint: disable=global-statement
441 saved_routes
= check_output ( 'ip route show table all' )
442 print ( '### The following routes will be protected:' )
447 output
= check_output ( 'ip route show table all' )
448 for line
in output
. splitlines ():
449 if line
in saved_routes
:
451 if 'proto kernel' in line
:
453 if ' dev ' in line
and not ' dev lo ' in line
:
457 print ( '### Removing routes that did not exist when the test started.' )
459 call ( f
'ip route del {line} ' )
461 def save_routing_policy_rules ():
462 # pylint: disable=global-statement
463 global saved_ipv4_rules
, saved_ipv6_rules
465 output
= check_output ( f
'ip - {ipv} rule show' )
466 print ( f
'### The following IPv {ipv} routing policy rules will be protected:' )
470 saved_ipv4_rules
= save ( 4 )
471 saved_ipv6_rules
= save ( 6 )
473 def flush_routing_policy_rules ():
474 def flush ( ipv
, saved_rules
):
476 output
= check_output ( f
'ip - {ipv} rule show' )
477 for line
in output
. splitlines ():
478 if line
in saved_rules
:
482 print ( f
'### Removing IPv {ipv} routing policy rules that did not exist when the test started.' )
484 words
= line
. replace ( 'lookup [l3mdev-table]' , 'l3mdev' ). split ()
485 priority
= words
[ 0 ]. rstrip ( ':' )
486 call ( f
'ip - {ipv} rule del priority {priority} ' + ' ' . join ( words
[ 1 :]))
488 flush ( 4 , saved_ipv4_rules
)
489 flush ( 6 , saved_ipv6_rules
)
491 def flush_fou_ports ():
492 ret
= run ( 'ip fou show' )
493 if ret
. returncode
!= 0 :
494 return # fou may not be supported
495 for line
in ret
. stdout
. splitlines ():
496 port
= line
. split ()[ 1 ]
497 call ( f
'ip fou del port {port} ' )
499 def flush_l2tp_tunnels ():
501 ret
= run ( 'ip l2tp show tunnel' )
502 if ret
. returncode
!= 0 :
503 return # l2tp may not be supported
504 for line
in ret
. stdout
. splitlines ():
506 if words
[ 0 ] == 'Tunnel' :
507 tid
= words
[ 1 ]. rstrip ( ',' )
508 call ( f
'ip l2tp del tunnel tunnel_id {tid} ' )
511 # Removing L2TP tunnel is asynchronous and slightly takes a time.
514 r
= run ( f
'ip l2tp show tunnel tunnel_id {tid} ' )
515 if r
. returncode
!= 0 or len ( r
. stdout
. rstrip ()) == 0 :
519 print ( f
'Cannot remove L2TP tunnel {tid} , ignoring.' )
522 # pylint: disable=global-statement
523 global saved_timezone
524 r
= run (* timedatectl_cmd
, 'show' , '--value' , '--property' , 'Timezone' , env
= env
)
525 if r
. returncode
== 0 :
526 saved_timezone
= r
. stdout
. rstrip ()
527 print ( f
'### Saved timezone: {saved_timezone} ' )
529 def restore_timezone ():
531 call (* timedatectl_cmd
, 'set-timezone' , f
' {saved_timezone} ' , env
= env
)
533 def read_link_attr (* args
):
534 with
open ( os
. path
. join ( '/sys/class/net' , * args
), encoding
= 'utf-8' ) as f
:
535 return f
. readline (). strip ()
537 def read_manager_state_file ():
538 with
open ( '/run/systemd/netif/state' , encoding
= 'utf-8' ) as f
:
541 def read_link_state_file ( link
):
542 ifindex
= read_link_attr ( link
, 'ifindex' )
543 path
= os
. path
. join ( '/run/systemd/netif/links' , ifindex
)
544 with
open ( path
, encoding
= 'utf-8' ) as f
:
547 def read_ip_sysctl_attr ( link
, attribute
, ipv
):
548 with
open ( os
. path
. join ( '/proc/sys/net' , ipv
, 'conf' , link
, attribute
), encoding
= 'utf-8' ) as f
:
549 return f
. readline (). strip ()
551 def read_ipv6_sysctl_attr ( link
, attribute
):
552 return read_ip_sysctl_attr ( link
, attribute
, 'ipv6' )
554 def read_ipv4_sysctl_attr ( link
, attribute
):
555 return read_ip_sysctl_attr ( link
, attribute
, 'ipv4' )
557 def stop_by_pid_file ( pid_file
):
558 if not os
. path
. exists ( pid_file
):
560 with
open ( pid_file
, 'r' , encoding
= 'utf-8' ) as f
:
561 pid
= f
. read (). rstrip ( ' \t\r\n \0' )
562 os
. kill ( int ( pid
), signal
. SIGTERM
)
566 print ( f
"PID {pid} is still alive, waiting..." )
569 if e
. errno
== errno
. ESRCH
:
571 print ( f
"Unexpected exception when waiting for {pid} to die: {e.errno}" )
574 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' ):
577 f
'--log-facility= {dnsmasq_log_file} ' ,
578 '--log-queries=extra' ,
580 f
'--pid-file= {dnsmasq_pid_file} ' ,
581 '--conf-file=/dev/null' ,
583 f
'--interface= {interface} ' ,
584 f
'--dhcp-leasefile= {dnsmasq_lease_file} ' ,
586 f
'--dhcp-range= {ipv6_range} , {lease_time} ' ,
587 f
'--dhcp-range= {ipv4_range} , {lease_time} ' ,
588 '--dhcp-option=option:mtu,1492' ,
589 f
'--dhcp-option=option:router, {ipv4_router} ' ,
592 ) + additional_options
593 check_output (* command
)
596 stop_by_pid_file ( dnsmasq_pid_file
)
597 rm_f ( dnsmasq_lease_file
)
598 rm_f ( dnsmasq_log_file
)
600 def read_dnsmasq_log_file ():
601 with
open ( dnsmasq_log_file
, encoding
= 'utf-8' ) as f
:
604 def start_isc_dhcpd ( conf_file
, ipv
, interface
= 'veth-peer' ):
605 conf_file_path
= os
. path
. join ( networkd_ci_temp_dir
, conf_file
)
606 isc_dhcpd_command
= f
'dhcpd {ipv} -cf {conf_file_path} -lf {isc_dhcpd_lease_file} -pf {isc_dhcpd_pid_file} {interface} '
607 touch ( isc_dhcpd_lease_file
)
608 check_output ( isc_dhcpd_command
)
610 def stop_isc_dhcpd ():
611 stop_by_pid_file ( isc_dhcpd_pid_file
)
612 rm_f ( isc_dhcpd_lease_file
)
614 def get_dbus_link_path ( link
):
615 out
= subprocess
. check_output ([ 'busctl' , 'call' , 'org.freedesktop.network1' ,
616 '/org/freedesktop/network1' , 'org.freedesktop.network1.Manager' ,
617 'GetLinkByName' , 's' , link
])
619 assert out
. startswith ( b
'io ' )
621 assert out
. endswith ( b
'"' )
623 return out
[:- 1 ]. split ( '"' )[ 1 ]
625 def get_dhcp_client_state ( link
, family
):
626 link_path
= get_dbus_link_path ( link
)
628 out
= subprocess
. check_output ([ 'busctl' , 'get-property' , 'org.freedesktop.network1' ,
629 link_path
, f
'org.freedesktop.network1.DHCPv {family} Client' , 'State' ])
630 assert out
. startswith ( b
's "' )
632 assert out
. endswith ( b
'"' )
633 return out
[ 3 :- 1 ]. decode ()
635 def get_dhcp4_client_state ( link
):
636 return get_dhcp_client_state ( link
, '4' )
638 def get_dhcp6_client_state ( link
):
639 return get_dhcp_client_state ( link
, '6' )
641 def get_link_description ( link
):
642 link_path
= get_dbus_link_path ( link
)
644 out
= subprocess
. check_output ([ 'busctl' , 'call' , 'org.freedesktop.network1' ,
645 link_path
, 'org.freedesktop.network1.Link' , 'Describe' ])
646 assert out
. startswith ( b
's "' )
648 assert out
. endswith ( b
'"' )
649 json_raw
= out
[ 2 :]. decode ()
651 description
= json
. loads ( json_raw
) # Convert from escaped sequences to json
652 check_json ( description
)
653 return json
. loads ( description
) # Now parse the json
655 def start_radvd (* additional_options
, config_file
):
656 config_file_path
= os
. path
. join ( networkd_ci_temp_dir
, 'radvd' , config_file
)
659 f
'--pidfile= {radvd_pid_file} ' ,
660 f
'--config= {config_file_path} ' ,
661 '--logmethod=stderr' ,
662 ) + additional_options
663 check_output (* command
)
666 stop_by_pid_file ( radvd_pid_file
)
668 def radvd_check_config ( config_file
):
669 if not shutil
. which ( 'radvd' ):
670 print ( 'radvd is not installed, assuming the config check failed' )
673 # Note: can't use networkd_ci_temp_dir here, as this command may run before that dir is
674 # set up (one instance is @unittest.skipX())
675 config_file_path
= os
. path
. join ( os
. path
. dirname ( os
. path
. abspath ( __file__
)), 'conf/radvd' , config_file
)
676 return call ( f
'radvd --config= {config_file_path} --configtest' ) == 0
678 def networkd_invocation_id ():
679 return check_output ( 'systemctl show --value -p InvocationID systemd-networkd.service' )
681 def read_networkd_log ( invocation_id
= None ):
682 if not invocation_id
:
683 invocation_id
= networkd_invocation_id ()
684 return check_output ( 'journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
)
686 def stop_networkd ( show_logs
= True ):
688 invocation_id
= networkd_invocation_id ()
689 check_output ( 'systemctl stop systemd-networkd.socket' )
690 check_output ( 'systemctl stop systemd-networkd.service' )
692 print ( read_networkd_log ( invocation_id
))
694 def start_networkd ():
695 check_output ( 'systemctl start systemd-networkd' )
697 def restart_networkd ( show_logs
= True ):
699 invocation_id
= networkd_invocation_id ()
700 check_output ( 'systemctl restart systemd-networkd.service' )
702 print ( read_networkd_log ( invocation_id
))
705 return int ( check_output ( 'systemctl show --value -p MainPID systemd-networkd.service' ))
707 def networkctl_reconfigure (* links
):
708 check_output (* networkctl_cmd
, 'reconfigure' , * links
, env
= env
)
710 def networkctl_reload ( sleep_time
= 1 ):
711 check_output (* networkctl_cmd
, 'reload' , env
= env
)
712 # 'networkctl reload' asynchronously reconfigure links.
713 # Hence, we need to wait for a short time for link to be in configuring state.
715 time
. sleep ( sleep_time
)
720 def tear_down_common ():
721 # 1. stop DHCP/RA servers
727 call_quiet ( 'rmmod netdevsim' )
728 call_quiet ( 'rmmod sch_teql' )
730 # 3. remove network namespace
731 call_quiet ( 'ip netns del ns99' )
741 clear_network_units ()
742 clear_networkd_conf_dropins ()
747 flush_routing_policy_rules ()
751 rm_rf ( networkd_ci_temp_dir
)
752 cp_r ( os
. path
. join ( os
. path
. dirname ( os
. path
. abspath ( __file__
)), 'conf' ), networkd_ci_temp_dir
)
754 clear_network_units ()
755 clear_networkd_conf_dropins ()
758 copy_udev_rule ( '00-debug-net.rules' )
762 save_existing_links ()
764 save_routing_policy_rules ()
767 create_service_dropin ( 'systemd-networkd' , networkd_bin
,
768 [ '[Service]' , 'Restart=no' , '[Unit]' , 'StartLimitIntervalSec=0' ])
769 create_service_dropin ( 'systemd-resolved' , resolved_bin
)
770 create_service_dropin ( 'systemd-timesyncd' , timesyncd_bin
)
772 # TODO: also run udevd with sanitizers, valgrind, or coverage
773 #create_service_dropin('systemd-udevd', udevd_bin,
774 # f'{udevadm_bin} control --reload --timeout 0')
776 'systemd-udevd.service' ,
780 f
'ExecStart=!!@ {udevd_bin} systemd-udevd' ,
784 'systemd-networkd.socket' ,
787 'StartLimitIntervalSec=0' ,
791 check_output ( 'systemctl daemon-reload' )
792 print ( check_output ( 'systemctl cat systemd-networkd.service' ))
793 print ( check_output ( 'systemctl cat systemd-resolved.service' ))
794 print ( check_output ( 'systemctl cat systemd-timesyncd.service' ))
795 print ( check_output ( 'systemctl cat systemd-udevd.service' ))
796 check_output ( 'systemctl restart systemd-resolved.service' )
797 check_output ( 'systemctl restart systemd-timesyncd.service' )
798 check_output ( 'systemctl restart systemd-udevd.service' )
800 def tearDownModule ():
801 rm_rf ( networkd_ci_temp_dir
)
803 clear_network_units ()
804 clear_networkd_conf_dropins ()
808 rm_rf ( '/run/systemd/system/systemd-networkd.service.d' )
809 rm_rf ( '/run/systemd/system/systemd-networkd.socket.d' )
810 rm_rf ( '/run/systemd/system/systemd-resolved.service.d' )
811 rm_rf ( '/run/systemd/system/systemd-timesyncd.service.d' )
812 rm_rf ( '/run/systemd/system/systemd-udevd.service.d' )
813 check_output ( 'systemctl daemon-reload' )
814 check_output ( 'systemctl restart systemd-udevd.service' )
815 restore_active_units ()
818 # pylint: disable=no-member
820 def check_link_exists ( self
, link
, expected
= True ):
822 self
. assertTrue ( link_exists ( link
))
824 self
. assertFalse ( link_exists ( link
))
826 def check_link_attr ( self
, * args
):
827 self
. assertEqual ( read_link_attr (* args
[:- 1 ]), args
[- 1 ])
829 def check_bridge_port_attr ( self
, master
, port
, attribute
, expected
, allow_enoent
= False ):
830 path
= os
. path
. join ( '/sys/devices/virtual/net' , master
, 'lower_' + port
, 'brport' , attribute
)
831 if allow_enoent
and not os
. path
. exists ( path
):
833 with
open ( path
, encoding
= 'utf-8' ) as f
:
834 self
. assertEqual ( f
. readline (). strip (), expected
)
836 def check_ipv4_sysctl_attr ( self
, link
, attribute
, expected
):
837 self
. assertEqual ( read_ipv4_sysctl_attr ( link
, attribute
), expected
)
839 def check_ipv6_sysctl_attr ( self
, link
, attribute
, expected
):
840 self
. assertEqual ( read_ipv6_sysctl_attr ( link
, attribute
), expected
)
842 def wait_links ( self
, * links
, timeout
= 20 , fail_assert
= True ):
843 def links_exist (* links
):
845 if not link_exists ( link
):
849 for iteration
in range ( timeout
+ 1 ):
853 if links_exist (* links
):
856 self
. fail ( 'Timed out waiting for all links to be created: ' + ', ' . join ( list ( links
)))
859 def wait_activated ( self
, link
, state
= 'down' , timeout
= 20 , fail_assert
= True ):
860 # wait for the interface is activated.
861 invocation_id
= check_output ( 'systemctl show systemd-networkd -p InvocationID --value' )
862 needle
= f
' {link} : Bringing link {state} '
864 for iteration
in range ( timeout
+ 1 ):
867 if not link_exists ( link
):
869 output
= check_output ( 'journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
)
870 if needle
in output
and flag
in check_output ( f
'ip link show {link} ' ):
873 self
. fail ( f
'Timed out waiting for {link} activated.' )
876 def wait_operstate ( self
, link
, operstate
= 'degraded' , setup_state
= 'configured' , setup_timeout
= 5 , fail_assert
= True ):
877 """Wait for the link to reach the specified operstate and/or setup state.
879 Specify None or '' for either operstate or setup_state to ignore that state.
880 This will recheck until the state conditions are met or the timeout expires.
882 If the link successfully matches the requested state, this returns True.
883 If this times out waiting for the link to match, the behavior depends on the
884 'fail_assert' parameter; if True, this causes a test assertion failure,
885 otherwise this returns False. The default is to cause assertion failure.
887 Note that this function matches on *exactly* the given operstate and setup_state.
888 To wait for a link to reach *or exceed* a given operstate, use wait_online().
895 for secs
in range ( setup_timeout
+ 1 ):
898 if not link_exists ( link
):
900 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , link
, env
= env
)
901 if re
. search ( rf
'(?m)^\s*State:\s+ {operstate} \s+\( {setup_state} \)\s*$' , output
):
905 self
. fail ( f
'Timed out waiting for {link} to reach state {operstate} / {setup_state} ' )
908 def wait_online ( self
, links_with_operstate
, timeout
= '20s' , bool_any
= False , ipv4
= False , ipv6
= False , setup_state
= 'configured' , setup_timeout
= 5 ):
909 """Wait for the links to reach the specified operstate and/or setup state.
911 This is similar to wait_operstate() but can be used for multiple links,
912 and it also calls systemd-networkd-wait-online to wait for the given operstate.
913 The operstate should be specified in the link name, like 'eth0:degraded'.
914 If just a link name is provided, wait-online's default operstate to wait for is degraded.
916 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
917 'setup_timeout' controls the per-link timeout waiting for the setup_state.
919 Set 'bool_any' to True to wait for any (instead of all) of the given links.
920 If this is set, no setup_state checks are done.
922 Set 'ipv4' or 'ipv6' to True to wait for IPv4 address or IPv6 address, respectively, of each of the given links.
923 This is applied only for the operational state 'degraded' or above.
925 Note that this function waits for the links to reach *or exceed* the given operstate.
926 However, the setup_state, if specified, must be matched *exactly*.
928 This returns if the links reached the requested operstate/setup_state; otherwise it
929 raises CalledProcessError or fails test assertion.
931 args
= wait_online_cmd
+ [ f
'--timeout= {timeout} ' ] + [ f
'--interface= {link} ' for link
in links_with_operstate
] + [ f
'--ignore= {link} ' for link
in protected_links
]
939 check_output (* args
, env
= wait_online_env
)
940 except subprocess
. CalledProcessError
:
941 # show detailed status on failure
942 for link
in links_with_operstate
:
943 name
= link
. split ( ':' )[ 0 ]
944 if link_exists ( name
):
945 call (* networkctl_cmd
, '-n' , '0' , 'status' , name
, env
= env
)
947 if not bool_any
and setup_state
:
948 for link
in links_with_operstate
:
949 self
. wait_operstate ( link
. split ( ':' )[ 0 ], None , setup_state
, setup_timeout
)
951 def wait_address ( self
, link
, address_regex
, scope
= 'global' , ipv
= '' , timeout_sec
= 100 ):
952 for i
in range ( timeout_sec
):
955 output
= check_output ( f
'ip {ipv} address show dev {link} scope {scope} ' )
956 if re
. search ( address_regex
, output
) and 'tentative' not in output
:
959 self
. assertRegex ( output
, address_regex
)
961 def wait_address_dropped ( self
, link
, address_regex
, scope
= 'global' , ipv
= '' , timeout_sec
= 100 ):
962 for i
in range ( timeout_sec
):
965 output
= check_output ( f
'ip {ipv} address show dev {link} scope {scope} ' )
966 if not re
. search ( address_regex
, output
):
969 self
. assertNotRegex ( output
, address_regex
)
971 def wait_route ( self
, link
, route_regex
, table
= 'main' , ipv
= '' , timeout_sec
= 100 ):
972 for i
in range ( timeout_sec
):
975 output
= check_output ( f
'ip {ipv} route show dev {link} table {table} ' )
976 if re
. search ( route_regex
, output
):
979 self
. assertRegex ( output
, route_regex
)
981 def check_netlabel ( self
, interface
, address
, label
= 'system_u:object_r:root_t:s0' ):
982 if not shutil
. which ( 'selinuxenabled' ):
983 print ( '## Checking NetLabel skipped: selinuxenabled command not found.' )
984 elif call_quiet ( 'selinuxenabled' ) != 0 :
985 print ( '## Checking NetLabel skipped: SELinux disabled.' )
986 elif not shutil
. which ( 'netlabelctl' ): # not packaged by all distros
987 print ( '## Checking NetLabel skipped: netlabelctl command not found.' )
989 output
= check_output ( 'netlabelctl unlbl list' )
991 self
. assertRegex ( output
, f
'interface: {interface} ,address: {address} ,label:" {label} "' )
993 def setup_nftset ( self
, filter_name
, filter_type
, flags
= '' ):
994 if not shutil
. which ( 'nft' ):
995 print ( '## Setting up NFT sets skipped: nft command not found.' )
997 if call ( f
'nft add table inet sd_test' ) != 0 :
998 print ( '## Setting up NFT table failed.' )
1000 if call ( f
'nft add set inet sd_test {filter_name} {{ type {filter_type} ; {flags} }}' ) != 0 :
1001 print ( '## Setting up NFT sets failed.' )
1004 def teardown_nftset ( self
, * filters
):
1005 if not shutil
. which ( 'nft' ):
1006 print ( '## Tearing down NFT sets skipped: nft command not found.' )
1008 for filter_name
in filters
:
1009 if call ( f
'nft delete set inet sd_test {filter_name} ' ) != 0 :
1010 print ( '## Tearing down NFT sets failed.' )
1012 if call ( f
'nft delete table inet sd_test' ) != 0 :
1013 print ( '## Tearing down NFT table failed.' )
1016 def check_nftset ( self
, filter_name
, contents
):
1017 if not shutil
. which ( 'nft' ):
1018 print ( '## Checking NFT sets skipped: nft command not found.' )
1020 output
= check_output ( f
'nft list set inet sd_test {filter_name} ' )
1022 self
. assertRegex ( output
, r
'.*elements = { [^}]*' + contents
+ r
'[^}]* }.*' )
1024 class NetworkctlTests ( unittest
. TestCase
, Utilities
):
1032 @expectedFailureIfAlternativeNameIsNotAvailable ()
1033 def test_altname ( self
):
1034 copy_network_unit ( '26-netdev-link-local-addressing-yes.network' , '12-dummy.netdev' , '12-dummy.link' )
1036 self
. wait_online ([ 'dummy98:degraded' ])
1038 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
1039 self
. assertRegex ( output
, 'hogehogehogehogehogehoge' )
1041 @expectedFailureIfAlternativeNameIsNotAvailable ()
1042 def test_rename_to_altname ( self
):
1043 copy_network_unit ( '26-netdev-link-local-addressing-yes.network' ,
1044 '12-dummy.netdev' , '12-dummy-rename-to-altname.link' )
1046 self
. wait_online ([ 'dummyalt:degraded' ])
1048 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummyalt' , env
= env
)
1049 self
. assertIn ( 'hogehogehogehogehogehoge' , output
)
1050 self
. assertNotIn ( 'dummy98' , output
)
1052 def test_reconfigure ( self
):
1053 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' )
1055 self
. wait_online ([ 'dummy98:routable' ])
1057 output
= check_output ( 'ip -4 address show dev dummy98' )
1059 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
1060 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
1061 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
1063 check_output ( 'ip address del 10.1.2.3/16 dev dummy98' )
1064 check_output ( 'ip address del 10.1.2.4/16 dev dummy98' )
1065 check_output ( 'ip address del 10.2.2.4/16 dev dummy98' )
1067 networkctl_reconfigure ( 'dummy98' )
1068 self
. wait_online ([ 'dummy98:routable' ])
1070 output
= check_output ( 'ip -4 address show dev dummy98' )
1072 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
1073 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
1074 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
1076 remove_network_unit ( '25-address-static.network' )
1079 self
. wait_operstate ( 'dummy98' , 'degraded' , setup_state
= 'unmanaged' )
1081 output
= check_output ( 'ip -4 address show dev dummy98' )
1083 self
. assertNotIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
1084 self
. assertNotIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
1085 self
. assertNotIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
1087 copy_network_unit ( '25-address-static.network' )
1089 self
. wait_online ([ 'dummy98:routable' ])
1091 output
= check_output ( 'ip -4 address show dev dummy98' )
1093 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
1094 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
1095 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
1097 def test_renew ( self
):
1099 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
1100 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
1102 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
1103 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
1104 self
. assertRegex ( output
, 'DNS: 192.168.5.1 \n *192.168.5.10' )
1105 self
. assertRegex ( output
, 'NTP: 192.168.5.1 \n *192.168.5.11' )
1107 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server.network' )
1110 output
= check_output (* networkctl_cmd
, '--lines=0' , '--stats' , '--all' , '--full' , '--json=short' , 'status' )
1113 for verb
in [ 'renew' , 'forcerenew' ]:
1114 call_check (* networkctl_cmd
, verb
, 'veth99' )
1116 call_check (* networkctl_cmd
, verb
, 'veth99' , 'veth99' , 'veth99' )
1119 def test_up_down ( self
):
1120 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' )
1122 self
. wait_online ([ 'dummy98:routable' ])
1124 call_check (* networkctl_cmd
, 'down' , 'dummy98' )
1125 self
. wait_online ([ 'dummy98:off' ])
1126 call_check (* networkctl_cmd
, 'up' , 'dummy98' )
1127 self
. wait_online ([ 'dummy98:routable' ])
1128 call_check (* networkctl_cmd
, 'down' , 'dummy98' , 'dummy98' , 'dummy98' )
1129 self
. wait_online ([ 'dummy98:off' ])
1130 call_check (* networkctl_cmd
, 'up' , 'dummy98' , 'dummy98' , 'dummy98' )
1131 self
. wait_online ([ 'dummy98:routable' ])
1133 def test_reload ( self
):
1136 copy_network_unit ( '11-dummy.netdev' )
1138 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'unmanaged' )
1140 copy_network_unit ( '11-dummy.network' )
1142 self
. wait_online ([ 'test1:degraded' ])
1144 remove_network_unit ( '11-dummy.network' )
1146 self
. wait_operstate ( 'test1' , 'degraded' , setup_state
= 'unmanaged' )
1148 remove_network_unit ( '11-dummy.netdev' )
1150 self
. wait_operstate ( 'test1' , 'degraded' , setup_state
= 'unmanaged' )
1152 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1154 self
. wait_operstate ( 'test1' , 'degraded' )
1156 def test_glob ( self
):
1157 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1160 self
. wait_online ([ 'test1:degraded' ])
1162 output
= check_output (* networkctl_cmd
, 'list' , env
= env
)
1163 self
. assertRegex ( output
, '1 lo ' )
1164 self
. assertRegex ( output
, 'test1' )
1166 output
= check_output (* networkctl_cmd
, 'list' , 'test1' , env
= env
)
1167 self
. assertNotRegex ( output
, '1 lo ' )
1168 self
. assertRegex ( output
, 'test1' )
1170 output
= check_output (* networkctl_cmd
, 'list' , 'te*' , env
= env
)
1171 self
. assertNotRegex ( output
, '1 lo ' )
1172 self
. assertRegex ( output
, 'test1' )
1174 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'te*' , env
= env
)
1175 self
. assertNotRegex ( output
, '1: lo ' )
1176 self
. assertRegex ( output
, 'test1' )
1178 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'tes[a-z][0-9]' , env
= env
)
1179 self
. assertNotRegex ( output
, '1: lo ' )
1180 self
. assertRegex ( output
, 'test1' )
1183 copy_network_unit ( '11-dummy-mtu.netdev' , '11-dummy.network' )
1186 self
. wait_online ([ 'test1:degraded' ])
1188 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
1189 self
. assertRegex ( output
, 'MTU: 1600' )
1191 def test_type ( self
):
1192 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1194 self
. wait_online ([ 'test1:degraded' ])
1196 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
1198 self
. assertRegex ( output
, 'Type: ether' )
1200 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'lo' , env
= env
)
1202 self
. assertRegex ( output
, 'Type: loopback' )
1204 def test_udev_link_file ( self
):
1205 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' , '25-default.link' )
1207 self
. wait_online ([ 'test1:degraded' ])
1209 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
1211 self
. assertRegex ( output
, r
'Link File: /run/systemd/network/25-default.link' )
1212 self
. assertRegex ( output
, r
'Network File: /run/systemd/network/11-dummy.network' )
1214 # This test may be run on the system that has older udevd than 70f32a260b5ebb68c19ecadf5d69b3844896ba55 (v249).
1215 # In that case, the udev DB for the loopback network interface may already have ID_NET_LINK_FILE property.
1216 # Let's reprocess the interface and drop the property.
1217 check_output (* udevadm_cmd
, 'trigger' , '--settle' , '--action=add' , '/sys/class/net/lo' )
1218 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'lo' , env
= env
)
1220 self
. assertRegex ( output
, r
'Link File: n/a' )
1221 self
. assertRegex ( output
, r
'Network File: n/a' )
1223 def test_delete_links ( self
):
1224 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' ,
1225 '25-veth.netdev' , '26-netdev-link-local-addressing-yes.network' )
1228 self
. wait_online ([ 'test1:degraded' , 'veth99:degraded' , 'veth-peer:degraded' ])
1230 check_output (* networkctl_cmd
, 'delete' , 'test1' , 'veth99' , env
= env
)
1231 self
. check_link_exists ( 'test1' , expected
= False )
1232 self
. check_link_exists ( 'veth99' , expected
= False )
1233 self
. check_link_exists ( 'veth-peer' , expected
= False )
1235 def test_label ( self
):
1236 call_check (* networkctl_cmd
, 'label' )
1238 class NetworkdMatchTests ( unittest
. TestCase
, Utilities
):
1246 @expectedFailureIfAlternativeNameIsNotAvailable ()
1247 def test_match ( self
):
1248 copy_network_unit ( '12-dummy-mac.netdev' ,
1249 '12-dummy-match-mac-01.network' ,
1250 '12-dummy-match-mac-02.network' ,
1251 '12-dummy-match-renamed.network' ,
1252 '12-dummy-match-altname.network' ,
1253 '12-dummy-altname.link' )
1256 self
. wait_online ([ 'dummy98:routable' ])
1257 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
1258 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-mac-01.network' , output
)
1259 output
= check_output ( 'ip -4 address show dev dummy98' )
1260 self
. assertIn ( '10.0.0.1/16' , output
)
1262 check_output ( 'ip link set dev dummy98 down' )
1263 check_output ( 'ip link set dev dummy98 address 12:34:56:78:9a:02' )
1265 self
. wait_address ( 'dummy98' , '10.0.0.2/16' , ipv
= '-4' , timeout_sec
= 10 )
1266 self
. wait_online ([ 'dummy98:routable' ])
1267 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
1268 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-mac-02.network' , output
)
1270 check_output ( 'ip link set dev dummy98 down' )
1271 check_output ( 'ip link set dev dummy98 name dummy98-1' )
1273 self
. wait_address ( 'dummy98-1' , '10.0.1.2/16' , ipv
= '-4' , timeout_sec
= 10 )
1274 self
. wait_online ([ 'dummy98-1:routable' ])
1275 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98-1' , env
= env
)
1276 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-renamed.network' , output
)
1278 check_output ( 'ip link set dev dummy98-1 down' )
1279 check_output ( 'ip link set dev dummy98-1 name dummy98-2' )
1280 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '/sys/class/net/dummy98-2' )
1282 self
. wait_address ( 'dummy98-2' , '10.0.2.2/16' , ipv
= '-4' , timeout_sec
= 10 )
1283 self
. wait_online ([ 'dummy98-2:routable' ])
1284 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98-2' , env
= env
)
1285 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-altname.network' , output
)
1287 def test_match_udev_property ( self
):
1288 copy_network_unit ( '12-dummy.netdev' , '13-not-match-udev-property.network' , '14-match-udev-property.network' )
1290 self
. wait_online ([ 'dummy98:routable' ])
1292 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
1294 self
. assertRegex ( output
, 'Network File: /run/systemd/network/14-match-udev-property' )
1296 class WaitOnlineTests ( unittest
. TestCase
, Utilities
):
1304 def test_wait_online_any ( self
):
1305 copy_network_unit ( '25-bridge.netdev' , '25-bridge.network' , '11-dummy.netdev' , '11-dummy.network' )
1308 self
. wait_online ([ 'bridge99' , 'test1:degraded' ], bool_any
= True )
1310 self
. wait_operstate ( 'bridge99' , '(off|no-carrier)' , setup_state
= 'configuring' )
1311 self
. wait_operstate ( 'test1' , 'degraded' )
1313 class NetworkdNetDevTests ( unittest
. TestCase
, Utilities
):
1321 def test_dropin_and_name_conflict ( self
):
1322 copy_network_unit ( '10-dropin-test.netdev' , '15-name-conflict-test.netdev' )
1325 self
. wait_online ([ 'dropin-test:off' ], setup_state
= 'unmanaged' )
1327 output
= check_output ( 'ip link show dropin-test' )
1329 self
. assertRegex ( output
, '00:50:56:c0:00:28' )
1331 @expectedFailureIfModuleIsNotAvailable ( 'bareudp' )
1332 def test_bareudp ( self
):
1333 copy_network_unit ( '25-bareudp.netdev' , '26-netdev-link-local-addressing-yes.network' )
1336 self
. wait_online ([ 'bareudp99:degraded' ])
1338 output
= check_output ( 'ip -d link show bareudp99' )
1340 self
. assertRegex ( output
, 'dstport 1000 ' )
1341 self
. assertRegex ( output
, 'ethertype ip ' )
1343 @expectedFailureIfModuleIsNotAvailable ( 'batman-adv' )
1344 def test_batadv ( self
):
1345 copy_network_unit ( '25-batadv.netdev' , '26-netdev-link-local-addressing-yes.network' )
1348 self
. wait_online ([ 'batadv99:degraded' ])
1350 output
= check_output ( 'ip -d link show batadv99' )
1352 self
. assertRegex ( output
, 'batadv' )
1354 def test_bridge ( self
):
1355 copy_network_unit ( '25-bridge.netdev' , '25-bridge-configure-without-carrier.network' )
1358 self
. wait_online ([ 'bridge99:no-carrier' ])
1360 tick
= os
. sysconf ( 'SC_CLK_TCK' )
1361 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'hello_time' )) / tick
))
1362 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'max_age' )) / tick
))
1363 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'forward_delay' )) / tick
))
1364 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'ageing_time' )) / tick
))
1365 self
. assertEqual ( 9 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'priority' )))
1366 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_querier' )))
1367 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_snooping' )))
1368 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'stp_state' )))
1369 self
. assertEqual ( 3 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_igmp_version' )))
1371 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bridge99' , env
= env
)
1373 self
. assertRegex ( output
, 'Priority: 9' )
1374 self
. assertRegex ( output
, 'STP: yes' )
1375 self
. assertRegex ( output
, 'Multicast IGMP Version: 3' )
1377 output
= check_output ( 'ip -d link show bridge99' )
1379 self
. assertIn ( 'vlan_filtering 1 ' , output
)
1380 self
. assertIn ( 'vlan_protocol 802.1ad ' , output
)
1381 self
. assertIn ( 'vlan_default_pvid 9 ' , output
)
1383 def test_bond ( self
):
1384 copy_network_unit ( '25-bond.netdev' , '25-bond-balanced-tlb.netdev' )
1387 self
. wait_online ([ 'bond99:off' , 'bond98:off' ], setup_state
= 'unmanaged' )
1389 self
. check_link_attr ( 'bond99' , 'bonding' , 'mode' , '802.3ad 4' )
1390 self
. check_link_attr ( 'bond99' , 'bonding' , 'xmit_hash_policy' , 'layer3+4 1' )
1391 self
. check_link_attr ( 'bond99' , 'bonding' , 'miimon' , '1000' )
1392 self
. check_link_attr ( 'bond99' , 'bonding' , 'lacp_rate' , 'fast 1' )
1393 self
. check_link_attr ( 'bond99' , 'bonding' , 'updelay' , '2000' )
1394 self
. check_link_attr ( 'bond99' , 'bonding' , 'downdelay' , '2000' )
1395 self
. check_link_attr ( 'bond99' , 'bonding' , 'resend_igmp' , '4' )
1396 self
. check_link_attr ( 'bond99' , 'bonding' , 'min_links' , '1' )
1397 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_actor_sys_prio' , '1218' )
1398 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_user_port_key' , '811' )
1399 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_actor_system' , '00:11:22:33:44:55' )
1401 self
. check_link_attr ( 'bond98' , 'bonding' , 'mode' , 'balance-tlb 5' )
1402 self
. check_link_attr ( 'bond98' , 'bonding' , 'tlb_dynamic_lb' , '1' )
1404 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bond99' , env
= env
)
1406 self
. assertIn ( 'Mode: 802.3ad' , output
)
1407 self
. assertIn ( 'Miimon: 1s' , output
)
1408 self
. assertIn ( 'Updelay: 2s' , output
)
1409 self
. assertIn ( 'Downdelay: 2s' , output
)
1411 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bond98' , env
= env
)
1413 self
. assertIn ( 'Mode: balance-tlb' , output
)
1415 def test_vlan ( self
):
1416 copy_network_unit ( '21-vlan.netdev' , '11-dummy.netdev' ,
1417 '21-vlan.network' , '21-vlan-test1.network' )
1420 self
. wait_online ([ 'test1:degraded' , 'vlan99:routable' ])
1422 output
= check_output ( 'ip -d link show test1' )
1424 self
. assertRegex ( output
, ' mtu 2000 ' )
1426 output
= check_output ( 'ip -d link show vlan99' )
1428 self
. assertIn ( ' mtu 2000 ' , output
)
1429 self
. assertIn ( 'REORDER_HDR' , output
)
1430 self
. assertIn ( 'LOOSE_BINDING' , output
)
1431 self
. assertIn ( 'GVRP' , output
)
1432 self
. assertIn ( 'MVRP' , output
)
1433 self
. assertIn ( ' id 99 ' , output
)
1434 self
. assertIn ( 'ingress-qos-map { 4:100 7:13 }' , output
)
1435 self
. assertIn ( 'egress-qos-map { 0:1 1:3 6:6 7:7 10:3 }' , output
)
1437 output
= check_output ( 'ip -4 address show dev test1' )
1439 self
. assertRegex ( output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1' )
1440 self
. assertRegex ( output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1' )
1442 output
= check_output ( 'ip -4 address show dev vlan99' )
1444 self
. assertRegex ( output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99' )
1446 def test_vlan_on_bond ( self
):
1447 # For issue #24377 (https://github.com/systemd/systemd/issues/24377),
1448 # which is fixed by b05e52000b4eee764b383cc3031da0a3739e996e (PR#24020).
1450 copy_network_unit ( '21-bond-802.3ad.netdev' , '21-bond-802.3ad.network' ,
1451 '21-vlan-on-bond.netdev' , '21-vlan-on-bond.network' )
1453 self
. wait_online ([ 'bond99:off' ])
1454 self
. wait_operstate ( 'vlan99' , operstate
= 'off' , setup_state
= 'configuring' , setup_timeout
= 10 )
1456 # The commit b05e52000b4eee764b383cc3031da0a3739e996e adds ", ignoring". To make it easily confirmed
1457 # that the issue is fixed by the commit, let's allow to match both string.
1458 log_re
= re
. compile ( 'vlan99: Could not bring up interface(, ignoring|): Network is down$' , re
. MULTILINE
)
1462 if log_re
. search ( read_networkd_log ()):
1467 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '21-dummy-bond-slave.network' )
1469 self
. wait_online ([ 'test1:enslaved' , 'dummy98:enslaved' , 'bond99:carrier' , 'vlan99:routable' ])
1471 def test_macvtap ( self
):
1473 for mode
in [ 'private' , 'vepa' , 'bridge' , 'passthru' ]:
1479 print ( f
'### test_macvtap(mode= {mode} )' )
1480 with self
. subTest ( mode
= mode
):
1481 copy_network_unit ( '21-macvtap.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1482 '11-dummy.netdev' , '25-macvtap.network' )
1483 with
open ( os
. path
. join ( network_unit_dir
, '21-macvtap.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1484 f
. write ( '[MACVTAP] \n Mode=' + mode
)
1487 self
. wait_online ([ 'macvtap99:degraded' ,
1488 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1490 output
= check_output ( 'ip -d link show macvtap99' )
1492 self
. assertRegex ( output
, 'macvtap mode ' + mode
+ ' ' )
1494 def test_macvlan ( self
):
1496 for mode
in [ 'private' , 'vepa' , 'bridge' , 'passthru' ]:
1502 print ( f
'### test_macvlan(mode= {mode} )' )
1503 with self
. subTest ( mode
= mode
):
1504 copy_network_unit ( '21-macvlan.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1505 '11-dummy.netdev' , '25-macvlan.network' )
1506 with
open ( os
. path
. join ( network_unit_dir
, '21-macvlan.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1507 f
. write ( '[MACVLAN] \n Mode=' + mode
)
1510 self
. wait_online ([ 'macvlan99:degraded' ,
1511 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1513 output
= check_output ( 'ip -d link show test1' )
1515 self
. assertRegex ( output
, ' mtu 2000 ' )
1517 output
= check_output ( 'ip -d link show macvlan99' )
1519 self
. assertRegex ( output
, ' mtu 2000 ' )
1520 self
. assertRegex ( output
, 'macvlan mode ' + mode
+ ' ' )
1522 remove_link ( 'test1' )
1525 check_output ( "ip link add test1 type dummy" )
1526 self
. wait_online ([ 'macvlan99:degraded' ,
1527 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1529 output
= check_output ( 'ip -d link show test1' )
1531 self
. assertRegex ( output
, ' mtu 2000 ' )
1533 output
= check_output ( 'ip -d link show macvlan99' )
1535 self
. assertRegex ( output
, ' mtu 2000 ' )
1536 self
. assertRegex ( output
, 'macvlan mode ' + mode
+ ' ' )
1538 @expectedFailureIfModuleIsNotAvailable ( 'ipvlan' )
1539 def test_ipvlan ( self
):
1541 for mode
, flag
in [[ 'L2' , 'private' ], [ 'L3' , 'vepa' ], [ 'L3S' , 'bridge' ]]:
1547 print ( f
'### test_ipvlan(mode= {mode} , flag= {flag} )' )
1548 with self
. subTest ( mode
= mode
, flag
= flag
):
1549 copy_network_unit ( '25-ipvlan.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1550 '11-dummy.netdev' , '25-ipvlan.network' )
1551 with
open ( os
. path
. join ( network_unit_dir
, '25-ipvlan.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1552 f
. write ( '[IPVLAN] \n Mode=' + mode
+ ' \n Flags=' + flag
)
1555 self
. wait_online ([ 'ipvlan99:degraded' , 'test1:degraded' ])
1557 output
= check_output ( 'ip -d link show ipvlan99' )
1559 self
. assertRegex ( output
, 'ipvlan *mode ' + mode
. lower () + ' ' + flag
)
1561 @expectedFailureIfModuleIsNotAvailable ( 'ipvtap' )
1562 def test_ipvtap ( self
):
1564 for mode
, flag
in [[ 'L2' , 'private' ], [ 'L3' , 'vepa' ], [ 'L3S' , 'bridge' ]]:
1570 print ( f
'### test_ipvtap(mode= {mode} , flag= {flag} )' )
1571 with self
. subTest ( mode
= mode
, flag
= flag
):
1572 copy_network_unit ( '25-ipvtap.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1573 '11-dummy.netdev' , '25-ipvtap.network' )
1574 with
open ( os
. path
. join ( network_unit_dir
, '25-ipvtap.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1575 f
. write ( '[IPVTAP] \n Mode=' + mode
+ ' \n Flags=' + flag
)
1578 self
. wait_online ([ 'ipvtap99:degraded' , 'test1:degraded' ])
1580 output
= check_output ( 'ip -d link show ipvtap99' )
1582 self
. assertRegex ( output
, 'ipvtap *mode ' + mode
. lower () + ' ' + flag
)
1584 def test_veth ( self
):
1585 copy_network_unit ( '25-veth.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1586 '25-veth-mtu.netdev' )
1589 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:degraded' , 'veth-mtu:degraded' , 'veth-mtu-peer:degraded' ])
1591 output
= check_output ( 'ip -d link show veth99' )
1593 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bc' )
1594 output
= check_output ( 'ip -d link show veth-peer' )
1596 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bd' )
1598 output
= check_output ( 'ip -d link show veth-mtu' )
1600 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:be' )
1601 self
. assertRegex ( output
, 'mtu 1800' )
1602 output
= check_output ( 'ip -d link show veth-mtu-peer' )
1604 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bf' )
1605 self
. assertRegex ( output
, 'mtu 1800' )
1607 def test_tuntap ( self
):
1608 copy_network_unit ( '25-tun.netdev' , '25-tap.netdev' , '26-netdev-link-local-addressing-yes.network' )
1611 self
. wait_online ([ 'testtun99:degraded' , 'testtap99:degraded' ])
1613 pid
= networkd_pid ()
1614 name
= psutil
. Process ( pid
). name ()[: 15 ]
1616 output
= check_output ( 'ip -d tuntap show' )
1618 self
. assertRegex ( output
, fr
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1619 self
. assertRegex ( output
, fr
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1621 output
= check_output ( 'ip -d link show testtun99' )
1623 # Old ip command does not support IFF_ flags
1624 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1625 self
. assertIn ( 'UP,LOWER_UP' , output
)
1627 output
= check_output ( 'ip -d link show testtap99' )
1629 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1630 self
. assertIn ( 'UP,LOWER_UP' , output
)
1632 remove_network_unit ( '26-netdev-link-local-addressing-yes.network' )
1635 self
. wait_online ([ 'testtun99:degraded' , 'testtap99:degraded' ], setup_state
= 'unmanaged' )
1637 pid
= networkd_pid ()
1638 name
= psutil
. Process ( pid
). name ()[: 15 ]
1640 output
= check_output ( 'ip -d tuntap show' )
1642 self
. assertRegex ( output
, fr
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1643 self
. assertRegex ( output
, fr
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1645 output
= check_output ( 'ip -d link show testtun99' )
1647 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1648 self
. assertIn ( 'UP,LOWER_UP' , output
)
1650 output
= check_output ( 'ip -d link show testtap99' )
1652 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1653 self
. assertIn ( 'UP,LOWER_UP' , output
)
1655 clear_network_units ()
1657 self
. wait_online ([ 'testtun99:off' , 'testtap99:off' ], setup_state
= 'unmanaged' )
1659 output
= check_output ( 'ip -d tuntap show' )
1661 self
. assertRegex ( output
, r
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$' )
1662 self
. assertRegex ( output
, r
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$' )
1667 output
= check_output ( 'ip -d link show testtun99' )
1669 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1670 if 'NO-CARRIER' in output
:
1678 output
= check_output ( 'ip -d link show testtap99' )
1680 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1681 if 'NO-CARRIER' in output
:
1686 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
1688 copy_network_unit ( '25-vrf.netdev' , '26-netdev-link-local-addressing-yes.network' )
1691 self
. wait_online ([ 'vrf99:carrier' ])
1693 @expectedFailureIfModuleIsNotAvailable ( 'vcan' )
1694 def test_vcan ( self
):
1695 copy_network_unit ( '25-vcan.netdev' , '26-netdev-link-local-addressing-yes.network' )
1698 self
. wait_online ([ 'vcan99:carrier' ])
1700 @expectedFailureIfModuleIsNotAvailable ( 'vxcan' )
1701 def test_vxcan ( self
):
1702 copy_network_unit ( '25-vxcan.netdev' , '26-netdev-link-local-addressing-yes.network' )
1705 self
. wait_online ([ 'vxcan99:carrier' , 'vxcan-peer:carrier' ])
1707 @expectedFailureIfModuleIsNotAvailable ( 'wireguard' )
1708 def test_wireguard ( self
):
1709 copy_network_unit ( '25-wireguard.netdev' , '25-wireguard.network' ,
1710 '25-wireguard-23-peers.netdev' , '25-wireguard-23-peers.network' ,
1711 '25-wireguard-preshared-key.txt' , '25-wireguard-private-key.txt' ,
1712 '25-wireguard-no-peer.netdev' , '25-wireguard-no-peer.network' )
1714 self
. wait_online ([ 'wg99:routable' , 'wg98:routable' , 'wg97:carrier' ])
1716 output
= check_output ( 'ip -4 address show dev wg99' )
1718 self
. assertIn ( 'inet 192.168.124.1/24 scope global wg99' , output
)
1720 output
= check_output ( 'ip -4 address show dev wg99' )
1722 self
. assertIn ( 'inet 169.254.11.1/24 scope link wg99' , output
)
1724 output
= check_output ( 'ip -6 address show dev wg99' )
1726 self
. assertIn ( 'inet6 fe80::1/64 scope link' , output
)
1728 output
= check_output ( 'ip -4 address show dev wg98' )
1730 self
. assertIn ( 'inet 192.168.123.123/24 scope global wg98' , output
)
1732 output
= check_output ( 'ip -6 address show dev wg98' )
1734 self
. assertIn ( 'inet6 fd8d:4d6d:3ccb:500::1/64 scope global' , output
)
1736 output
= check_output ( 'ip -4 route show dev wg99 table 1234' )
1738 self
. assertIn ( '192.168.26.0/24 proto static metric 123' , output
)
1740 output
= check_output ( 'ip -6 route show dev wg99 table 1234' )
1742 self
. assertIn ( 'fd31:bf08:57cb::/48 proto static metric 123 pref medium' , output
)
1744 output
= check_output ( 'ip -6 route show dev wg98 table 1234' )
1746 self
. assertIn ( 'fd8d:4d6d:3ccb:500:c79:2339:edce:ece1 proto static metric 123 pref medium' , output
)
1747 self
. assertIn ( 'fd8d:4d6d:3ccb:500:1dbf:ca8a:32d3:dd81 proto static metric 123 pref medium' , output
)
1748 self
. assertIn ( 'fd8d:4d6d:3ccb:500:1e54:1415:35d0:a47c proto static metric 123 pref medium' , output
)
1749 self
. assertIn ( 'fd8d:4d6d:3ccb:500:270d:b5dd:4a3f:8909 proto static metric 123 pref medium' , output
)
1750 self
. assertIn ( 'fd8d:4d6d:3ccb:500:5660:679d:3532:94d8 proto static metric 123 pref medium' , output
)
1751 self
. assertIn ( 'fd8d:4d6d:3ccb:500:6825:573f:30f3:9472 proto static metric 123 pref medium' , output
)
1752 self
. assertIn ( 'fd8d:4d6d:3ccb:500:6f2e:6888:c6fd:dfb9 proto static metric 123 pref medium' , output
)
1753 self
. assertIn ( 'fd8d:4d6d:3ccb:500:8d4d:bab:7280:a09a proto static metric 123 pref medium' , output
)
1754 self
. assertIn ( 'fd8d:4d6d:3ccb:500:900c:d437:ec27:8822 proto static metric 123 pref medium' , output
)
1755 self
. assertIn ( 'fd8d:4d6d:3ccb:500:9742:9931:5217:18d5 proto static metric 123 pref medium' , output
)
1756 self
. assertIn ( 'fd8d:4d6d:3ccb:500:9c11:d820:2e96:9be0 proto static metric 123 pref medium' , output
)
1757 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a072:80da:de4f:add1 proto static metric 123 pref medium' , output
)
1758 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a3f3:df38:19b0:721 proto static metric 123 pref medium' , output
)
1759 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a94b:cd6a:a32d:90e6 proto static metric 123 pref medium' , output
)
1760 self
. assertIn ( 'fd8d:4d6d:3ccb:500:b39c:9cdc:755a:ead3 proto static metric 123 pref medium' , output
)
1761 self
. assertIn ( 'fd8d:4d6d:3ccb:500:b684:4f81:2e3e:132e proto static metric 123 pref medium' , output
)
1762 self
. assertIn ( 'fd8d:4d6d:3ccb:500:bad5:495d:8e9c:3427 proto static metric 123 pref medium' , output
)
1763 self
. assertIn ( 'fd8d:4d6d:3ccb:500:bfe5:c3c3:5d77:fcb proto static metric 123 pref medium' , output
)
1764 self
. assertIn ( 'fd8d:4d6d:3ccb:500:c624:6bf7:4c09:3b59 proto static metric 123 pref medium' , output
)
1765 self
. assertIn ( 'fd8d:4d6d:3ccb:500:d4f9:5dc:9296:a1a proto static metric 123 pref medium' , output
)
1766 self
. assertIn ( 'fd8d:4d6d:3ccb:500:dcdd:d33b:90c9:6088 proto static metric 123 pref medium' , output
)
1767 self
. assertIn ( 'fd8d:4d6d:3ccb:500:e2e1:ae15:103f:f376 proto static metric 123 pref medium' , output
)
1768 self
. assertIn ( 'fd8d:4d6d:3ccb:500:f349:c4f0:10c1:6b4 proto static metric 123 pref medium' , output
)
1769 self
. assertIn ( 'fd8d:4d6d:3ccb:c79:2339:edce::/96 proto static metric 123 pref medium' , output
)
1770 self
. assertIn ( 'fd8d:4d6d:3ccb:1dbf:ca8a:32d3::/96 proto static metric 123 pref medium' , output
)
1771 self
. assertIn ( 'fd8d:4d6d:3ccb:1e54:1415:35d0::/96 proto static metric 123 pref medium' , output
)
1772 self
. assertIn ( 'fd8d:4d6d:3ccb:270d:b5dd:4a3f::/96 proto static metric 123 pref medium' , output
)
1773 self
. assertIn ( 'fd8d:4d6d:3ccb:5660:679d:3532::/96 proto static metric 123 pref medium' , output
)
1774 self
. assertIn ( 'fd8d:4d6d:3ccb:6825:573f:30f3::/96 proto static metric 123 pref medium' , output
)
1775 self
. assertIn ( 'fd8d:4d6d:3ccb:6f2e:6888:c6fd::/96 proto static metric 123 pref medium' , output
)
1776 self
. assertIn ( 'fd8d:4d6d:3ccb:8d4d:bab:7280::/96 proto static metric 123 pref medium' , output
)
1777 self
. assertIn ( 'fd8d:4d6d:3ccb:900c:d437:ec27::/96 proto static metric 123 pref medium' , output
)
1778 self
. assertIn ( 'fd8d:4d6d:3ccb:9742:9931:5217::/96 proto static metric 123 pref medium' , output
)
1779 self
. assertIn ( 'fd8d:4d6d:3ccb:9c11:d820:2e96::/96 proto static metric 123 pref medium' , output
)
1780 self
. assertIn ( 'fd8d:4d6d:3ccb:a072:80da:de4f::/96 proto static metric 123 pref medium' , output
)
1781 self
. assertIn ( 'fd8d:4d6d:3ccb:a3f3:df38:19b0::/96 proto static metric 123 pref medium' , output
)
1782 self
. assertIn ( 'fd8d:4d6d:3ccb:a94b:cd6a:a32d::/96 proto static metric 123 pref medium' , output
)
1783 self
. assertIn ( 'fd8d:4d6d:3ccb:b39c:9cdc:755a::/96 proto static metric 123 pref medium' , output
)
1784 self
. assertIn ( 'fd8d:4d6d:3ccb:b684:4f81:2e3e::/96 proto static metric 123 pref medium' , output
)
1785 self
. assertIn ( 'fd8d:4d6d:3ccb:bad5:495d:8e9c::/96 proto static metric 123 pref medium' , output
)
1786 self
. assertIn ( 'fd8d:4d6d:3ccb:bfe5:c3c3:5d77::/96 proto static metric 123 pref medium' , output
)
1787 self
. assertIn ( 'fd8d:4d6d:3ccb:c624:6bf7:4c09::/96 proto static metric 123 pref medium' , output
)
1788 self
. assertIn ( 'fd8d:4d6d:3ccb:d4f9:5dc:9296::/96 proto static metric 123 pref medium' , output
)
1789 self
. assertIn ( 'fd8d:4d6d:3ccb:dcdd:d33b:90c9::/96 proto static metric 123 pref medium' , output
)
1790 self
. assertIn ( 'fd8d:4d6d:3ccb:e2e1:ae15:103f::/96 proto static metric 123 pref medium' , output
)
1791 self
. assertIn ( 'fd8d:4d6d:3ccb:f349:c4f0:10c1::/96 proto static metric 123 pref medium' , output
)
1793 if shutil
. which ( 'wg' ):
1796 output
= check_output ( 'wg show wg99 listen-port' )
1797 self
. assertEqual ( output
, '51820' )
1798 output
= check_output ( 'wg show wg99 fwmark' )
1799 self
. assertEqual ( output
, '0x4d2' )
1800 output
= check_output ( 'wg show wg99 private-key' )
1801 self
. assertEqual ( output
, 'EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=' )
1802 output
= check_output ( 'wg show wg99 allowed-ips' )
1803 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t 192.168.124.3/32' , output
)
1804 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t 192.168.124.2/32' , output
)
1805 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t fdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128' , output
)
1806 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 192.168.26.0/24 fd31:bf08:57cb::/48' , output
)
1807 output
= check_output ( 'wg show wg99 persistent-keepalive' )
1808 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t off' , output
)
1809 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t off' , output
)
1810 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t off' , output
)
1811 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 20' , output
)
1812 output
= check_output ( 'wg show wg99 endpoints' )
1813 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t (none)' , output
)
1814 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t (none)' , output
)
1815 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t (none)' , output
)
1816 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 192.168.27.3:51820' , output
)
1817 output
= check_output ( 'wg show wg99 preshared-keys' )
1818 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t 6Fsg8XN0DE6aPQgAX4r2oazEYJOGqyHUz3QRH/jCB+I=' , output
)
1819 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t it7nd33chCT/tKT2ZZWfYyp43Zs+6oif72hexnSNMqA=' , output
)
1820 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=' , output
)
1821 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=' , output
)
1823 output
= check_output ( 'wg show wg98 private-key' )
1824 self
. assertEqual ( output
, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr+WHtZLZ90FU=' )
1826 output
= check_output ( 'wg show wg97 listen-port' )
1827 self
. assertEqual ( output
, '51821' )
1828 output
= check_output ( 'wg show wg97 fwmark' )
1829 self
. assertEqual ( output
, '0x4d3' )
1831 def test_geneve ( self
):
1832 copy_network_unit ( '25-geneve.netdev' , '26-netdev-link-local-addressing-yes.network' )
1835 self
. wait_online ([ 'geneve99:degraded' ])
1837 output
= check_output ( 'ip -d link show geneve99' )
1839 self
. assertRegex ( output
, '192.168.22.1' )
1840 self
. assertRegex ( output
, '6082' )
1841 self
. assertRegex ( output
, 'udpcsum' )
1842 self
. assertRegex ( output
, 'udp6zerocsumrx' )
1844 def test_ipip_tunnel ( self
):
1845 copy_network_unit ( '12-dummy.netdev' , '25-ipip.network' ,
1846 '25-ipip-tunnel.netdev' , '25-tunnel.network' ,
1847 '25-ipip-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1848 '25-ipip-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1849 '25-ipip-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1851 self
. wait_online ([ 'ipiptun99:routable' , 'ipiptun98:routable' , 'ipiptun97:routable' , 'ipiptun96:routable' , 'dummy98:degraded' ])
1853 output
= check_output ( 'ip -d link show ipiptun99' )
1855 self
. assertRegex ( output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98' )
1856 output
= check_output ( 'ip -d link show ipiptun98' )
1858 self
. assertRegex ( output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98' )
1859 output
= check_output ( 'ip -d link show ipiptun97' )
1861 self
. assertRegex ( output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98' )
1862 output
= check_output ( 'ip -d link show ipiptun96' )
1864 self
. assertRegex ( output
, 'ipip (ipip )?remote any local any dev dummy98' )
1866 def test_gre_tunnel ( self
):
1867 copy_network_unit ( '12-dummy.netdev' , '25-gretun.network' ,
1868 '25-gre-tunnel.netdev' , '25-tunnel.network' ,
1869 '25-gre-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1870 '25-gre-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1871 '25-gre-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1873 self
. wait_online ([ 'gretun99:routable' , 'gretun98:routable' , 'gretun97:routable' , 'gretun96:routable' , 'dummy98:degraded' ])
1875 output
= check_output ( 'ip -d link show gretun99' )
1877 self
. assertRegex ( output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1878 self
. assertRegex ( output
, 'ikey 1.2.3.103' )
1879 self
. assertRegex ( output
, 'okey 1.2.4.103' )
1880 self
. assertRegex ( output
, 'iseq' )
1881 self
. assertRegex ( output
, 'oseq' )
1882 output
= check_output ( 'ip -d link show gretun98' )
1884 self
. assertRegex ( output
, 'gre remote 10.65.223.239 local any dev dummy98' )
1885 self
. assertRegex ( output
, 'ikey 0.0.0.104' )
1886 self
. assertRegex ( output
, 'okey 0.0.0.104' )
1887 self
. assertNotRegex ( output
, 'iseq' )
1888 self
. assertNotRegex ( output
, 'oseq' )
1889 output
= check_output ( 'ip -d link show gretun97' )
1891 self
. assertRegex ( output
, 'gre remote any local 10.65.223.238 dev dummy98' )
1892 self
. assertRegex ( output
, 'ikey 0.0.0.105' )
1893 self
. assertRegex ( output
, 'okey 0.0.0.105' )
1894 self
. assertNotRegex ( output
, 'iseq' )
1895 self
. assertNotRegex ( output
, 'oseq' )
1896 output
= check_output ( 'ip -d link show gretun96' )
1898 self
. assertRegex ( output
, 'gre remote any local any dev dummy98' )
1899 self
. assertRegex ( output
, 'ikey 0.0.0.106' )
1900 self
. assertRegex ( output
, 'okey 0.0.0.106' )
1901 self
. assertNotRegex ( output
, 'iseq' )
1902 self
. assertNotRegex ( output
, 'oseq' )
1904 def test_ip6gre_tunnel ( self
):
1905 copy_network_unit ( '12-dummy.netdev' , '25-ip6gretun.network' ,
1906 '25-ip6gre-tunnel.netdev' , '25-tunnel.network' ,
1907 '25-ip6gre-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1908 '25-ip6gre-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1909 '25-ip6gre-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1912 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1914 self
. wait_links ( 'dummy98' , 'ip6gretun99' , 'ip6gretun98' , 'ip6gretun97' , 'ip6gretun96' )
1916 output
= check_output ( 'ip -d link show ip6gretun99' )
1918 self
. assertRegex ( output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1919 output
= check_output ( 'ip -d link show ip6gretun98' )
1921 self
. assertRegex ( output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98' )
1922 output
= check_output ( 'ip -d link show ip6gretun97' )
1924 self
. assertRegex ( output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98' )
1925 output
= check_output ( 'ip -d link show ip6gretun96' )
1927 self
. assertRegex ( output
, 'ip6gre remote any local any dev dummy98' )
1929 def test_gretap_tunnel ( self
):
1930 copy_network_unit ( '12-dummy.netdev' , '25-gretap.network' ,
1931 '25-gretap-tunnel.netdev' , '25-tunnel.network' ,
1932 '25-gretap-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1934 self
. wait_online ([ 'gretap99:routable' , 'gretap98:routable' , 'dummy98:degraded' ])
1936 output
= check_output ( 'ip -d link show gretap99' )
1938 self
. assertRegex ( output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1939 self
. assertRegex ( output
, 'ikey 0.0.0.106' )
1940 self
. assertRegex ( output
, 'okey 0.0.0.106' )
1941 self
. assertRegex ( output
, 'iseq' )
1942 self
. assertRegex ( output
, 'oseq' )
1943 self
. assertIn ( 'nopmtudisc' , output
)
1944 self
. assertIn ( 'ignore-df' , output
)
1945 output
= check_output ( 'ip -d link show gretap98' )
1947 self
. assertRegex ( output
, 'gretap remote 10.65.223.239 local any dev dummy98' )
1948 self
. assertRegex ( output
, 'ikey 0.0.0.107' )
1949 self
. assertRegex ( output
, 'okey 0.0.0.107' )
1950 self
. assertRegex ( output
, 'iseq' )
1951 self
. assertRegex ( output
, 'oseq' )
1953 def test_ip6gretap_tunnel ( self
):
1954 copy_network_unit ( '12-dummy.netdev' , '25-ip6gretap.network' ,
1955 '25-ip6gretap-tunnel.netdev' , '25-tunnel.network' ,
1956 '25-ip6gretap-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1958 self
. wait_online ([ 'ip6gretap99:routable' , 'ip6gretap98:routable' , 'dummy98:degraded' ])
1960 output
= check_output ( 'ip -d link show ip6gretap99' )
1962 self
. assertRegex ( output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1963 output
= check_output ( 'ip -d link show ip6gretap98' )
1965 self
. assertRegex ( output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98' )
1967 def test_vti_tunnel ( self
):
1968 copy_network_unit ( '12-dummy.netdev' , '25-vti.network' ,
1969 '25-vti-tunnel.netdev' , '25-tunnel.network' ,
1970 '25-vti-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1971 '25-vti-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1972 '25-vti-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1974 self
. wait_online ([ 'vtitun99:routable' , 'vtitun98:routable' , 'vtitun97:routable' , 'vtitun96:routable' , 'dummy98:degraded' ])
1976 output
= check_output ( 'ip -d link show vtitun99' )
1978 self
. assertRegex ( output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1979 output
= check_output ( 'ip -d link show vtitun98' )
1981 self
. assertRegex ( output
, 'vti remote 10.65.223.239 local any dev dummy98' )
1982 output
= check_output ( 'ip -d link show vtitun97' )
1984 self
. assertRegex ( output
, 'vti remote any local 10.65.223.238 dev dummy98' )
1985 output
= check_output ( 'ip -d link show vtitun96' )
1987 self
. assertRegex ( output
, 'vti remote any local any dev dummy98' )
1989 def test_vti6_tunnel ( self
):
1990 copy_network_unit ( '12-dummy.netdev' , '25-vti6.network' ,
1991 '25-vti6-tunnel.netdev' , '25-tunnel.network' ,
1992 '25-vti6-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1993 '25-vti6-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' )
1995 self
. wait_online ([ 'vti6tun99:routable' , 'vti6tun98:routable' , 'vti6tun97:routable' , 'dummy98:degraded' ])
1997 output
= check_output ( 'ip -d link show vti6tun99' )
1999 self
. assertRegex ( output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
2000 output
= check_output ( 'ip -d link show vti6tun98' )
2002 self
. assertRegex ( output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98' )
2003 output
= check_output ( 'ip -d link show vti6tun97' )
2005 self
. assertRegex ( output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98' )
2007 def test_ip6tnl_tunnel ( self
):
2008 copy_network_unit ( '12-dummy.netdev' , '25-ip6tnl.network' ,
2009 '25-ip6tnl-tunnel.netdev' , '25-tunnel.network' ,
2010 '25-ip6tnl-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
2011 '25-ip6tnl-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
2012 '25-veth.netdev' , '25-ip6tnl-slaac.network' , '25-ipv6-prefix.network' ,
2013 '25-ip6tnl-tunnel-local-slaac.netdev' , '25-ip6tnl-tunnel-local-slaac.network' ,
2014 '25-ip6tnl-tunnel-external.netdev' , '26-netdev-link-local-addressing-yes.network' )
2016 self
. wait_online ([ 'ip6tnl99:routable' , 'ip6tnl98:routable' , 'ip6tnl97:routable' ,
2017 'ip6tnl-slaac:degraded' , 'ip6tnl-external:degraded' ,
2018 'dummy98:degraded' , 'veth99:routable' , 'veth-peer:degraded' ])
2020 output
= check_output ( 'ip -d link show ip6tnl99' )
2022 self
. assertIn ( 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' , output
)
2023 output
= check_output ( 'ip -d link show ip6tnl98' )
2025 self
. assertRegex ( output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98' )
2026 output
= check_output ( 'ip -d link show ip6tnl97' )
2028 self
. assertRegex ( output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98' )
2029 output
= check_output ( 'ip -d link show ip6tnl-external' )
2031 self
. assertIn ( 'ip6tnl-external@NONE:' , output
)
2032 self
. assertIn ( 'ip6tnl external ' , output
)
2033 output
= check_output ( 'ip -d link show ip6tnl-slaac' )
2035 self
. assertIn ( 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99' , output
)
2037 output
= check_output ( 'ip -6 address show veth99' )
2039 self
. assertIn ( 'inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic' , output
)
2041 output
= check_output ( 'ip -4 route show default' )
2043 self
. assertIn ( 'default dev ip6tnl-slaac proto static' , output
)
2045 def test_sit_tunnel ( self
):
2046 copy_network_unit ( '12-dummy.netdev' , '25-sit.network' ,
2047 '25-sit-tunnel.netdev' , '25-tunnel.network' ,
2048 '25-sit-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
2049 '25-sit-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
2050 '25-sit-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
2052 self
. wait_online ([ 'sittun99:routable' , 'sittun98:routable' , 'sittun97:routable' , 'sittun96:routable' , 'dummy98:degraded' ])
2054 output
= check_output ( 'ip -d link show sittun99' )
2056 self
. assertRegex ( output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98" )
2057 output
= check_output ( 'ip -d link show sittun98' )
2059 self
. assertRegex ( output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98" )
2060 output
= check_output ( 'ip -d link show sittun97' )
2062 self
. assertRegex ( output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98" )
2063 output
= check_output ( 'ip -d link show sittun96' )
2065 self
. assertRegex ( output
, "sit (ip6ip )?remote any local any dev dummy98" )
2067 def test_isatap_tunnel ( self
):
2068 copy_network_unit ( '12-dummy.netdev' , '25-isatap.network' ,
2069 '25-isatap-tunnel.netdev' , '25-tunnel.network' )
2071 self
. wait_online ([ 'isataptun99:routable' , 'dummy98:degraded' ])
2073 output
= check_output ( 'ip -d link show isataptun99' )
2075 self
. assertRegex ( output
, "isatap " )
2077 def test_6rd_tunnel ( self
):
2078 copy_network_unit ( '12-dummy.netdev' , '25-6rd.network' ,
2079 '25-6rd-tunnel.netdev' , '25-tunnel.network' )
2081 self
. wait_online ([ 'sittun99:routable' , 'dummy98:degraded' ])
2083 output
= check_output ( 'ip -d link show sittun99' )
2085 self
. assertRegex ( output
, '6rd-prefix 2602::/24' )
2087 @expectedFailureIfERSPANv0IsNotSupported ()
2088 def test_erspan_tunnel_v0 ( self
):
2089 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
2090 '25-erspan0-tunnel.netdev' , '25-tunnel.network' ,
2091 '25-erspan0-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
2093 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
2095 output
= check_output ( 'ip -d link show erspan99' )
2097 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
2098 self
. assertIn ( 'erspan_ver 0' , output
)
2099 self
. assertNotIn ( 'erspan_index 123' , output
)
2100 self
. assertNotIn ( 'erspan_dir ingress' , output
)
2101 self
. assertNotIn ( 'erspan_hwid 1f' , output
)
2102 self
. assertIn ( 'ikey 0.0.0.101' , output
)
2103 self
. assertIn ( 'iseq' , output
)
2104 self
. assertIn ( 'nopmtudisc' , output
)
2105 self
. assertIn ( 'ignore-df' , output
)
2106 output
= check_output ( 'ip -d link show erspan98' )
2108 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
2109 self
. assertIn ( 'erspan_ver 0' , output
)
2110 self
. assertNotIn ( 'erspan_index 124' , output
)
2111 self
. assertNotIn ( 'erspan_dir egress' , output
)
2112 self
. assertNotIn ( 'erspan_hwid 2f' , output
)
2113 self
. assertIn ( 'ikey 0.0.0.102' , output
)
2114 self
. assertIn ( 'iseq' , output
)
2116 def test_erspan_tunnel_v1 ( self
):
2117 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
2118 '25-erspan1-tunnel.netdev' , '25-tunnel.network' ,
2119 '25-erspan1-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
2121 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
2123 output
= check_output ( 'ip -d link show erspan99' )
2125 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
2126 self
. assertIn ( 'erspan_ver 1' , output
)
2127 self
. assertIn ( 'erspan_index 123' , output
)
2128 self
. assertNotIn ( 'erspan_dir ingress' , output
)
2129 self
. assertNotIn ( 'erspan_hwid 1f' , output
)
2130 self
. assertIn ( 'ikey 0.0.0.101' , output
)
2131 self
. assertIn ( 'okey 0.0.0.101' , output
)
2132 self
. assertIn ( 'iseq' , output
)
2133 self
. assertIn ( 'oseq' , output
)
2134 output
= check_output ( 'ip -d link show erspan98' )
2136 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
2137 self
. assertIn ( 'erspan_ver 1' , output
)
2138 self
. assertIn ( 'erspan_index 124' , output
)
2139 self
. assertNotIn ( 'erspan_dir egress' , output
)
2140 self
. assertNotIn ( 'erspan_hwid 2f' , output
)
2141 self
. assertIn ( 'ikey 0.0.0.102' , output
)
2142 self
. assertIn ( 'okey 0.0.0.102' , output
)
2143 self
. assertIn ( 'iseq' , output
)
2144 self
. assertIn ( 'oseq' , output
)
2146 @expectedFailureIfERSPANv2IsNotSupported ()
2147 def test_erspan_tunnel_v2 ( self
):
2148 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
2149 '25-erspan2-tunnel.netdev' , '25-tunnel.network' ,
2150 '25-erspan2-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
2152 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
2154 output
= check_output ( 'ip -d link show erspan99' )
2156 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
2157 self
. assertIn ( 'erspan_ver 2' , output
)
2158 self
. assertNotIn ( 'erspan_index 123' , output
)
2159 self
. assertIn ( 'erspan_dir ingress' , output
)
2160 self
. assertIn ( 'erspan_hwid 0x1f' , output
)
2161 self
. assertIn ( 'ikey 0.0.0.101' , output
)
2162 self
. assertIn ( 'okey 0.0.0.101' , output
)
2163 self
. assertIn ( 'iseq' , output
)
2164 self
. assertIn ( 'oseq' , output
)
2165 output
= check_output ( 'ip -d link show erspan98' )
2167 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
2168 self
. assertIn ( 'erspan_ver 2' , output
)
2169 self
. assertNotIn ( 'erspan_index 124' , output
)
2170 self
. assertIn ( 'erspan_dir egress' , output
)
2171 self
. assertIn ( 'erspan_hwid 0x2f' , output
)
2172 self
. assertIn ( 'ikey 0.0.0.102' , output
)
2173 self
. assertIn ( 'okey 0.0.0.102' , output
)
2174 self
. assertIn ( 'iseq' , output
)
2175 self
. assertIn ( 'oseq' , output
)
2177 def test_tunnel_independent ( self
):
2178 copy_network_unit ( '25-ipip-tunnel-independent.netdev' , '26-netdev-link-local-addressing-yes.network' )
2181 self
. wait_online ([ 'ipiptun99:carrier' ])
2183 def test_tunnel_independent_loopback ( self
):
2184 copy_network_unit ( '25-ipip-tunnel-independent-loopback.netdev' , '26-netdev-link-local-addressing-yes.network' )
2187 self
. wait_online ([ 'ipiptun99:carrier' ])
2189 @expectedFailureIfModuleIsNotAvailable ( 'xfrm_interface' )
2190 def test_xfrm ( self
):
2191 copy_network_unit ( '12-dummy.netdev' , '25-xfrm.network' ,
2192 '25-xfrm.netdev' , '25-xfrm-independent.netdev' ,
2193 '26-netdev-link-local-addressing-yes.network' )
2196 self
. wait_online ([ 'dummy98:degraded' , 'xfrm98:degraded' , 'xfrm99:degraded' ])
2198 output
= check_output ( 'ip -d link show dev xfrm98' )
2200 self
. assertIn ( 'xfrm98@dummy98:' , output
)
2201 self
. assertIn ( 'xfrm if_id 0x98 ' , output
)
2203 output
= check_output ( 'ip -d link show dev xfrm99' )
2205 self
. assertIn ( 'xfrm99@lo:' , output
)
2206 self
. assertIn ( 'xfrm if_id 0x99 ' , output
)
2208 @expectedFailureIfModuleIsNotAvailable ( 'fou' )
2210 # The following redundant check is necessary for CentOS CI.
2211 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
2212 self
. assertTrue ( is_module_available ( 'fou' ))
2214 copy_network_unit ( '25-fou-ipproto-ipip.netdev' , '25-fou-ipproto-gre.netdev' ,
2215 '25-fou-ipip.netdev' , '25-fou-sit.netdev' ,
2216 '25-fou-gre.netdev' , '25-fou-gretap.netdev' )
2219 self
. wait_online ([ 'ipiptun96:off' , 'sittun96:off' , 'gretun96:off' , 'gretap96:off' ], setup_state
= 'unmanaged' )
2221 output
= check_output ( 'ip fou show' )
2223 self
. assertRegex ( output
, 'port 55555 ipproto 4' )
2224 self
. assertRegex ( output
, 'port 55556 ipproto 47' )
2226 output
= check_output ( 'ip -d link show ipiptun96' )
2228 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55555' )
2229 output
= check_output ( 'ip -d link show sittun96' )
2231 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55555' )
2232 output
= check_output ( 'ip -d link show gretun96' )
2234 self
. assertRegex ( output
, 'encap fou encap-sport 1001 encap-dport 55556' )
2235 output
= check_output ( 'ip -d link show gretap96' )
2237 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55556' )
2239 def test_vxlan ( self
):
2240 copy_network_unit ( '11-dummy.netdev' , '25-vxlan-test1.network' ,
2241 '25-vxlan.netdev' , '25-vxlan.network' ,
2242 '25-vxlan-ipv6.netdev' , '25-vxlan-ipv6.network' ,
2243 '25-vxlan-independent.netdev' , '26-netdev-link-local-addressing-yes.network' ,
2244 '25-veth.netdev' , '25-vxlan-veth99.network' , '25-ipv6-prefix.network' ,
2245 '25-vxlan-local-slaac.netdev' , '25-vxlan-local-slaac.network' )
2248 self
. wait_online ([ 'test1:degraded' , 'veth99:routable' , 'veth-peer:degraded' ,
2249 'vxlan99:degraded' , 'vxlan98:degraded' , 'vxlan97:degraded' , 'vxlan-slaac:degraded' ])
2251 output
= check_output ( 'ip -d -d link show vxlan99' )
2253 self
. assertIn ( '999' , output
)
2254 self
. assertIn ( '5555' , output
)
2255 self
. assertIn ( 'l2miss' , output
)
2256 self
. assertIn ( 'l3miss' , output
)
2257 self
. assertIn ( 'gbp' , output
)
2258 # Since [0] some of the options use slightly different names and some
2259 # options with default values are shown only if the -d(etails) setting
2261 # [0] https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit/?id=1215e9d3862387353d8672296cb4c6c16e8cbb72
2262 self
. assertRegex ( output
, '(udpcsum|udp_csum)' )
2263 self
. assertRegex ( output
, '(udp6zerocsumtx|udp_zero_csum6_tx)' )
2264 self
. assertRegex ( output
, '(udp6zerocsumrx|udp_zero_csum6_rx)' )
2265 self
. assertRegex ( output
, '(remcsumtx|remcsum_tx)' )
2266 self
. assertRegex ( output
, '(remcsumrx|remcsum_rx)' )
2268 output
= check_output ( 'bridge fdb show dev vxlan99' )
2270 self
. assertIn ( '00:11:22:33:44:55 dst 10.0.0.5 self permanent' , output
)
2271 self
. assertIn ( '00:11:22:33:44:66 dst 10.0.0.6 self permanent' , output
)
2272 self
. assertIn ( '00:11:22:33:44:77 dst 10.0.0.7 via test1 self permanent' , output
)
2274 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'vxlan99' , env
= env
)
2276 self
. assertIn ( 'VNI: 999' , output
)
2277 self
. assertIn ( 'Destination Port: 5555' , output
)
2278 self
. assertIn ( 'Underlying Device: test1' , output
)
2280 output
= check_output ( 'bridge fdb show dev vxlan97' )
2282 self
. assertIn ( '00:00:00:00:00:00 dst fe80::23b:d2ff:fe95:967f via test1 self permanent' , output
)
2283 self
. assertIn ( '00:00:00:00:00:00 dst fe80::27c:16ff:fec0:6c74 via test1 self permanent' , output
)
2284 self
. assertIn ( '00:00:00:00:00:00 dst fe80::2a2:e4ff:fef9:2269 via test1 self permanent' , output
)
2286 output
= check_output ( 'ip -d link show vxlan-slaac' )
2288 self
. assertIn ( 'vxlan id 4831584 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99' , output
)
2290 output
= check_output ( 'ip -6 address show veth99' )
2292 self
. assertIn ( 'inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic' , output
)
2294 @unittest . skipUnless ( compare_kernel_version ( "6" ), reason
= "Causes kernel panic on unpatched kernels: https://bugzilla.kernel.org/show_bug.cgi?id=208315" )
2295 def test_macsec ( self
):
2296 copy_network_unit ( '25-macsec.netdev' , '25-macsec.network' , '25-macsec.key' ,
2297 '26-macsec.network' , '12-dummy.netdev' )
2300 self
. wait_online ([ 'dummy98:degraded' , 'macsec99:routable' ])
2302 output
= check_output ( 'ip -d link show macsec99' )
2304 self
. assertRegex ( output
, 'macsec99@dummy98' )
2305 self
. assertRegex ( output
, 'macsec sci [0-9a-f]*000b' )
2306 self
. assertRegex ( output
, 'encrypt on' )
2308 output
= check_output ( 'ip macsec show macsec99' )
2310 self
. assertRegex ( output
, 'encrypt on' )
2311 self
. assertRegex ( output
, 'TXSC: [0-9a-f]*000b on SA 1' )
2312 self
. assertRegex ( output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000' )
2313 self
. assertRegex ( output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000' )
2314 self
. assertRegex ( output
, 'RXSC: c619528fe6a00100, state on' )
2315 self
. assertRegex ( output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000' )
2316 self
. assertRegex ( output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000' )
2317 self
. assertRegex ( output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000' )
2318 self
. assertRegex ( output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000' )
2319 self
. assertNotRegex ( output
, 'key 02030405067080900000000000000000' )
2320 self
. assertRegex ( output
, 'RXSC: 8c16456c83a90002, state on' )
2321 self
. assertRegex ( output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000' )
2323 def test_nlmon ( self
):
2324 copy_network_unit ( '25-nlmon.netdev' , '26-netdev-link-local-addressing-yes.network' )
2327 self
. wait_online ([ 'nlmon99:carrier' ])
2329 @expectedFailureIfModuleIsNotAvailable ( 'ifb' )
2331 copy_network_unit ( '25-ifb.netdev' , '26-netdev-link-local-addressing-yes.network' )
2334 self
. wait_online ([ 'ifb99:degraded' ])
2336 class NetworkdL2TPTests ( unittest
. TestCase
, Utilities
):
2344 @expectedFailureIfModuleIsNotAvailable ( 'l2tp_eth' , 'l2tp_netlink' )
2345 def test_l2tp_udp ( self
):
2346 copy_network_unit ( '11-dummy.netdev' , '25-l2tp-dummy.network' ,
2347 '25-l2tp-udp.netdev' , '25-l2tp.network' )
2350 self
. wait_online ([ 'test1:routable' , 'l2tp-ses1:degraded' , 'l2tp-ses2:degraded' ])
2352 output
= check_output ( 'ip l2tp show tunnel tunnel_id 10' )
2354 self
. assertRegex ( output
, "Tunnel 10, encap UDP" )
2355 self
. assertRegex ( output
, "From 192.168.30.100 to 192.168.30.101" )
2356 self
. assertRegex ( output
, "Peer tunnel 11" )
2357 self
. assertRegex ( output
, "UDP source / dest ports: 3000/4000" )
2358 self
. assertRegex ( output
, "UDP checksum: enabled" )
2360 output
= check_output ( 'ip l2tp show session tid 10 session_id 15' )
2362 self
. assertRegex ( output
, "Session 15 in tunnel 10" )
2363 self
. assertRegex ( output
, "Peer session 16, tunnel 11" )
2364 self
. assertRegex ( output
, "interface name: l2tp-ses1" )
2366 output
= check_output ( 'ip l2tp show session tid 10 session_id 17' )
2368 self
. assertRegex ( output
, "Session 17 in tunnel 10" )
2369 self
. assertRegex ( output
, "Peer session 18, tunnel 11" )
2370 self
. assertRegex ( output
, "interface name: l2tp-ses2" )
2372 @expectedFailureIfModuleIsNotAvailable ( 'l2tp_eth' , 'l2tp_ip' , 'l2tp_netlink' )
2373 def test_l2tp_ip ( self
):
2374 copy_network_unit ( '11-dummy.netdev' , '25-l2tp-dummy.network' ,
2375 '25-l2tp-ip.netdev' , '25-l2tp.network' )
2378 self
. wait_online ([ 'test1:routable' , 'l2tp-ses3:degraded' , 'l2tp-ses4:degraded' ])
2380 output
= check_output ( 'ip l2tp show tunnel tunnel_id 10' )
2382 self
. assertRegex ( output
, "Tunnel 10, encap IP" )
2383 self
. assertRegex ( output
, "From 192.168.30.100 to 192.168.30.101" )
2384 self
. assertRegex ( output
, "Peer tunnel 12" )
2386 output
= check_output ( 'ip l2tp show session tid 10 session_id 25' )
2388 self
. assertRegex ( output
, "Session 25 in tunnel 10" )
2389 self
. assertRegex ( output
, "Peer session 26, tunnel 12" )
2390 self
. assertRegex ( output
, "interface name: l2tp-ses3" )
2392 output
= check_output ( 'ip l2tp show session tid 10 session_id 27' )
2394 self
. assertRegex ( output
, "Session 27 in tunnel 10" )
2395 self
. assertRegex ( output
, "Peer session 28, tunnel 12" )
2396 self
. assertRegex ( output
, "interface name: l2tp-ses4" )
2398 class NetworkdNetworkTests ( unittest
. TestCase
, Utilities
):
2406 def verify_address_static (
2436 output
= check_output ( 'ip address show dev dummy98' )
2440 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
2441 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
2442 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
2443 self
. assertIn ( 'inet6 2001:db8:0:f101::15/64 scope global' , output
)
2444 self
. assertIn ( 'inet6 2001:db8:0:f101::16/64 scope global' , output
)
2445 self
. assertIn ( 'inet6 2001:db8:0:f102::15/64 scope global' , output
)
2448 self
. assertIn ( f
'inet 10.3.1.1/24 brd 10.3.1.255 scope global {label1} ' , output
)
2449 self
. assertIn ( f
'inet 10.3.2.1/24 brd 10.3.2.255 scope global {label2} ' , output
)
2450 self
. assertIn ( f
'inet 10.3.3.1/24 brd 10.3.3.255 scope global {label3} ' , output
)
2453 self
. assertIn ( f
'inet 10.4.1.1/24 {broadcast1} scope global dummy98' , output
)
2454 self
. assertIn ( f
'inet 10.4.2.1/24 {broadcast2} scope global dummy98' , output
)
2455 self
. assertIn ( f
'inet 10.4.3.1/24 {broadcast3} scope global dummy98' , output
)
2458 self
. assertIn ( f
'inet 10.5.1.1 {peer1} scope global dummy98' , output
)
2459 self
. assertIn ( f
'inet 10.5.2.1 {peer2} scope global dummy98' , output
)
2460 self
. assertIn ( f
'inet 10.5.3.1 {peer3} scope global dummy98' , output
)
2461 self
. assertIn ( f
'inet6 2001:db8:0:f103::1 {peer4} scope global' , output
)
2462 self
. assertIn ( f
'inet6 2001:db8:0:f103::2 {peer5} scope global' , output
)
2463 self
. assertIn ( f
'inet6 2001:db8:0:f103::3 {peer6} scope global' , output
)
2466 self
. assertIn ( f
'inet 10.6.1.1/24 brd 10.6.1.255 scope {scope1} dummy98' , output
)
2467 self
. assertIn ( f
'inet 10.6.2.1/24 brd 10.6.2.255 scope {scope2} dummy98' , output
)
2470 self
. assertIn ( f
'inet 10.7.1.1/24 brd 10.7.1.255 scope global {deprecated1} dummy98' , output
)
2471 self
. assertIn ( f
'inet 10.7.2.1/24 brd 10.7.2.255 scope global {deprecated2} dummy98' , output
)
2472 self
. assertIn ( f
'inet6 2001:db8:0:f104::1/64 scope global {deprecated3} ' , output
)
2473 self
. assertIn ( f
'inet6 2001:db8:0:f104::2/64 scope global {deprecated4} ' , output
)
2476 self
. assertRegex ( output
, rf
'inet 10.8.1.1/24 (metric {route_metric} |)brd 10.8.1.255 scope global dummy98' )
2477 self
. assertRegex ( output
, rf
'inet6 2001:db8:0:f105::1/64 (metric {route_metric} |)scope global' )
2479 output_route
= check_output ( 'ip -4 route show dev dummy98 10.8.1.0/24' )
2481 self
. assertIn ( f
'10.8.1.0/24 proto kernel scope link src 10.8.1.1 metric {route_metric} ' , output_route
)
2483 output_route
= check_output ( 'ip -6 route show dev dummy98 2001:db8:0:f105::/64' )
2485 self
. assertIn ( f
'2001:db8:0:f105::/64 proto kernel metric {route_metric} ' , output_route
)
2488 self
. assertIn ( f
'inet 10.9.1.1/24 brd 10.9.1.255 scope global {flag1} dummy98' , output
)
2489 self
. assertIn ( f
'inet 10.9.2.1/24 brd 10.9.2.255 scope global {flag2} dummy98' , output
)
2490 self
. assertIn ( f
'inet6 2001:db8:0:f106::1/64 scope global {flag3} ' , output
)
2491 self
. assertIn ( f
'inet6 2001:db8:0:f106::2/64 scope global {flag4} ' , output
)
2494 self
. assertTrue ( ip4_null_16
. endswith ( '.0.1' ))
2495 prefix16
= ip4_null_16
[:- len ( '.0.1' )]
2496 self
. assertTrue ( ip4_null_24
. endswith ( '.1' ))
2497 prefix24
= ip4_null_24
[:- len ( '.1' )]
2498 self
. assertIn ( f
'inet {ip4_null_16} /16 brd {prefix16} .255.255 scope global subnet16' , output
)
2499 self
. assertIn ( f
'inet {ip4_null_24} /24 brd {prefix24} .255 scope global subnet24' , output
)
2500 self
. assertIn ( f
'inet6 {ip6_null_73} /73 scope global' , output
)
2501 self
. assertIn ( f
'inet6 {ip6_null_74} /74 scope global' , output
)
2504 self
. assertNotIn ( '10.4.4.1' , output
)
2505 self
. assertNotIn ( '10.5.4.1' , output
)
2506 self
. assertNotIn ( '10.5.5.1' , output
)
2507 self
. assertNotIn ( '10.8.2.1' , output
)
2508 self
. assertNotIn ( '10.9.3.1' , output
)
2509 self
. assertNotIn ( '2001:db8:0:f101::2' , output
)
2510 self
. assertNotIn ( '2001:db8:0:f103::4' , output
)
2513 self
. check_netlabel ( 'dummy98' , r
'10\.10\.1\.0/24' )
2515 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2518 def test_address_static ( self
):
2519 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' , copy_dropins
= False )
2521 self
. setup_nftset ( 'addr4' , 'ipv4_addr' )
2522 self
. setup_nftset ( 'network4' , 'ipv4_addr' , 'flags interval;' )
2523 self
. setup_nftset ( 'ifindex' , 'iface_index' )
2525 self
. wait_online ([ 'dummy98:routable' ])
2529 output
= check_output ( 'ip -4 --json address show dev dummy98' )
2530 for i
in json
. loads ( output
)[ 0 ][ 'addr_info' ]:
2531 if i
[ 'label' ] == 'subnet16' :
2532 ip4_null_16
= i
[ 'local' ]
2533 elif i
[ 'label' ] == 'subnet24' :
2534 ip4_null_24
= i
[ 'local' ]
2535 self
. assertTrue ( ip4_null_16
. endswith ( '.0.1' ))
2536 self
. assertTrue ( ip4_null_24
. endswith ( '.1' ))
2540 output
= check_output ( 'ip -6 --json address show dev dummy98' )
2541 for i
in json
. loads ( output
)[ 0 ][ 'addr_info' ]:
2542 if i
[ 'prefixlen' ] == 73 :
2543 ip6_null_73
= i
[ 'local' ]
2544 elif i
[ 'prefixlen' ] == 74 :
2545 ip6_null_74
= i
[ 'local' ]
2546 self
. assertTrue ( ip6_null_73
. endswith ( ':1' ))
2547 self
. assertTrue ( ip6_null_74
. endswith ( ':1' ))
2549 self
. verify_address_static (
2554 broadcast2
= ' brd 10.4.2.255' ,
2555 broadcast3
= ' brd 10.4.3.63' ,
2556 peer1
= ' peer 10.5.1.101/24' ,
2557 peer2
= ' peer 10.5.2.101/24' ,
2558 peer3
= '/24 brd 10.5.3.255' ,
2559 peer4
= ' peer 2001:db8:0:f103::101/128' ,
2560 peer5
= ' peer 2001:db8:0:f103::102/128' ,
2565 deprecated2
= ' deprecated' ,
2567 deprecated4
= ' deprecated' ,
2569 flag1
= ' noprefixroute' ,
2571 flag3
= ' noprefixroute' ,
2572 flag4
= ' home mngtmpaddr' ,
2573 ip4_null_16
= ip4_null_16
,
2574 ip4_null_24
= ip4_null_24
,
2575 ip6_null_73
= ip6_null_73
,
2576 ip6_null_74
= ip6_null_74
,
2579 self
. check_nftset ( 'addr4' , r
'10\.10\.1\.1' )
2580 self
. check_nftset ( 'network4' , r
'10\.10\.1\.0/24' )
2581 self
. check_nftset ( 'ifindex' , 'dummy98' )
2583 self
. teardown_nftset ( 'addr4' , 'network4' , 'ifindex' )
2585 copy_network_unit ( '25-address-static.network.d/10-override.conf' )
2587 self
. wait_online ([ 'dummy98:routable' ])
2588 self
. verify_address_static (
2589 label1
= 'new-label1' ,
2591 label3
= 'new-label3' ,
2592 broadcast1
= ' brd 10.4.1.255' ,
2594 broadcast3
= ' brd 10.4.3.31' ,
2595 peer1
= ' peer 10.5.1.102/24' ,
2596 peer2
= '/24 brd 10.5.2.255' ,
2597 peer3
= ' peer 10.5.3.102/24' ,
2598 peer4
= ' peer 2001:db8:0:f103::201/128' ,
2600 peer6
= ' peer 2001:db8:0:f103::203/128' ,
2603 deprecated1
= ' deprecated' ,
2605 deprecated3
= ' deprecated' ,
2609 flag2
= ' noprefixroute' ,
2610 flag3
= ' home mngtmpaddr' ,
2611 flag4
= ' noprefixroute' ,
2612 ip4_null_16
= ip4_null_16
,
2613 ip4_null_24
= ip4_null_24
,
2614 ip6_null_73
= ip6_null_73
,
2615 ip6_null_74
= ip6_null_74
,
2618 networkctl_reconfigure ( 'dummy98' )
2619 self
. wait_online ([ 'dummy98:routable' ])
2620 self
. verify_address_static (
2621 label1
= 'new-label1' ,
2623 label3
= 'new-label3' ,
2624 broadcast1
= ' brd 10.4.1.255' ,
2626 broadcast3
= ' brd 10.4.3.31' ,
2627 peer1
= ' peer 10.5.1.102/24' ,
2628 peer2
= '/24 brd 10.5.2.255' ,
2629 peer3
= ' peer 10.5.3.102/24' ,
2630 peer4
= ' peer 2001:db8:0:f103::201/128' ,
2632 peer6
= ' peer 2001:db8:0:f103::203/128' ,
2635 deprecated1
= ' deprecated' ,
2637 deprecated3
= ' deprecated' ,
2641 flag2
= ' noprefixroute' ,
2642 flag3
= ' home mngtmpaddr' ,
2643 flag4
= ' noprefixroute' ,
2644 ip4_null_16
= ip4_null_16
,
2645 ip4_null_24
= ip4_null_24
,
2646 ip6_null_73
= ip6_null_73
,
2647 ip6_null_74
= ip6_null_74
,
2651 # 1. set preferred lifetime forever to drop the deprecated flag for testing #20891.
2652 check_output ( 'ip address change 10.7.1.1/24 dev dummy98 preferred_lft forever' )
2653 check_output ( 'ip address change 2001:db8:0:f104::1/64 dev dummy98 preferred_lft forever' )
2654 output
= check_output ( 'ip address show dev dummy98' )
2656 self
. assertNotRegex ( output
, '10.7.1.1/24 .* deprecated' )
2657 self
. assertNotRegex ( output
, '2001:db8:0:f104::1/64 .* deprecated' )
2659 # 2. reconfigure the interface, and check the deprecated flag is set again
2660 networkctl_reconfigure ( 'dummy98' )
2661 self
. wait_online ([ 'dummy98:routable' ])
2662 self
. verify_address_static (
2663 label1
= 'new-label1' ,
2665 label3
= 'new-label3' ,
2666 broadcast1
= ' brd 10.4.1.255' ,
2668 broadcast3
= ' brd 10.4.3.31' ,
2669 peer1
= ' peer 10.5.1.102/24' ,
2670 peer2
= '/24 brd 10.5.2.255' ,
2671 peer3
= ' peer 10.5.3.102/24' ,
2672 peer4
= ' peer 2001:db8:0:f103::201/128' ,
2674 peer6
= ' peer 2001:db8:0:f103::203/128' ,
2677 deprecated1
= ' deprecated' ,
2679 deprecated3
= ' deprecated' ,
2683 flag2
= ' noprefixroute' ,
2684 flag3
= ' home mngtmpaddr' ,
2685 flag4
= ' noprefixroute' ,
2686 ip4_null_16
= ip4_null_16
,
2687 ip4_null_24
= ip4_null_24
,
2688 ip6_null_73
= ip6_null_73
,
2689 ip6_null_74
= ip6_null_74
,
2692 # test for ENOBUFS issue #17012 (with reload)
2693 copy_network_unit ( '25-address-static.network.d/10-many-address.conf' )
2695 self
. wait_online ([ 'dummy98:routable' ])
2696 output
= check_output ( 'ip -4 address show dev dummy98' )
2697 for i
in range ( 1 , 254 ):
2698 self
. assertIn ( f
'inet 10.3.3. {i} /16 brd 10.3.255.255' , output
)
2700 # (with reconfigure)
2701 networkctl_reconfigure ( 'dummy98' )
2702 self
. wait_online ([ 'dummy98:routable' ])
2703 output
= check_output ( 'ip -4 address show dev dummy98' )
2704 for i
in range ( 1 , 254 ):
2705 self
. assertIn ( f
'inet 10.3.3. {i} /16 brd 10.3.255.255' , output
)
2707 def test_address_ipv4acd ( self
):
2708 check_output ( 'ip netns add ns99' )
2709 check_output ( 'ip link add veth99 type veth peer veth-peer' )
2710 check_output ( 'ip link set veth-peer netns ns99' )
2711 check_output ( 'ip link set veth99 up' )
2712 check_output ( 'ip netns exec ns99 ip link set veth-peer up' )
2713 check_output ( 'ip netns exec ns99 ip address add 192.168.100.10/24 dev veth-peer' )
2715 copy_network_unit ( '25-address-ipv4acd-veth99.network' , copy_dropins
= False )
2717 self
. wait_online ([ 'veth99:routable' ])
2719 output
= check_output ( 'ip -4 address show dev veth99' )
2721 self
. assertNotIn ( '192.168.100.10/24' , output
)
2722 self
. assertIn ( '192.168.100.11/24' , output
)
2724 copy_network_unit ( '25-address-ipv4acd-veth99.network.d/conflict-address.conf' )
2726 self
. wait_operstate ( 'veth99' , operstate
= 'routable' , setup_state
= 'configuring' , setup_timeout
= 10 )
2728 output
= check_output ( 'ip -4 address show dev veth99' )
2730 self
. assertNotIn ( '192.168.100.10/24' , output
)
2731 self
. assertIn ( '192.168.100.11/24' , output
)
2733 def test_address_peer_ipv4 ( self
):
2734 # test for issue #17304
2735 copy_network_unit ( '25-address-peer-ipv4.network' , '12-dummy.netdev' )
2737 for trial
in range ( 2 ):
2743 self
. wait_online ([ 'dummy98:routable' ])
2745 output
= check_output ( 'ip -4 address show dev dummy98' )
2746 self
. assertIn ( 'inet 100.64.0.1 peer 100.64.0.2/32 scope global' , output
)
2748 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
2749 def test_prefix_route ( self
):
2750 copy_network_unit ( '25-prefix-route-with-vrf.network' , '12-dummy.netdev' ,
2751 '25-prefix-route-without-vrf.network' , '11-dummy.netdev' ,
2752 '25-vrf.netdev' , '25-vrf.network' )
2753 for trial
in range ( 2 ):
2759 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' , 'vrf99:carrier' ])
2761 output
= check_output ( 'ip route show table 42 dev dummy98' )
2762 print ( '### ip route show table 42 dev dummy98' )
2764 self
. assertRegex ( output
, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1' )
2765 self
. assertRegex ( output
, '10.20.33.0/24 proto kernel scope link src 10.20.33.1' )
2766 self
. assertRegex ( output
, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1' )
2767 self
. assertRegex ( output
, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1' )
2768 self
. assertRegex ( output
, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1' )
2769 self
. assertRegex ( output
, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1' )
2770 self
. assertRegex ( output
, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1' )
2771 output
= check_output ( 'ip -6 route show table 42 dev dummy98' )
2772 print ( '### ip -6 route show table 42 dev dummy98' )
2776 self
. assertRegex ( output
, 'local fdde:11:22::1 proto kernel metric 0 pref medium' )
2777 #self.assertRegex(output, 'fdde:11:22::1 proto kernel metric 256 pref medium')
2778 self
. assertRegex ( output
, 'local fdde:11:33::1 proto kernel metric 0 pref medium' )
2779 self
. assertRegex ( output
, 'fdde:11:33::/64 proto kernel metric 256 pref medium' )
2780 self
. assertRegex ( output
, 'local fdde:11:44::1 proto kernel metric 0 pref medium' )
2781 self
. assertRegex ( output
, 'local fdde:11:55::1 proto kernel metric 0 pref medium' )
2782 self
. assertRegex ( output
, 'fe80::/64 proto kernel metric 256 pref medium' )
2783 self
. assertRegex ( output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium' )
2787 output
= check_output ( 'ip route show dev test1' )
2788 print ( '### ip route show dev test1' )
2790 self
. assertRegex ( output
, '10.21.33.0/24 proto kernel scope link src 10.21.33.1' )
2791 output
= check_output ( 'ip route show table local dev test1' )
2792 print ( '### ip route show table local dev test1' )
2794 self
. assertRegex ( output
, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1' )
2795 self
. assertRegex ( output
, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1' )
2796 self
. assertRegex ( output
, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1' )
2797 self
. assertRegex ( output
, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1' )
2798 self
. assertRegex ( output
, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1' )
2799 self
. assertRegex ( output
, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1' )
2800 output
= check_output ( 'ip -6 route show dev test1' )
2801 print ( '### ip -6 route show dev test1' )
2803 self
. assertRegex ( output
, 'fdde:12:22::1 proto kernel metric 256 pref medium' )
2804 self
. assertRegex ( output
, 'fdde:12:33::/64 proto kernel metric 256 pref medium' )
2805 self
. assertRegex ( output
, 'fe80::/64 proto kernel metric 256 pref medium' )
2806 output
= check_output ( 'ip -6 route show table local dev test1' )
2807 print ( '### ip -6 route show table local dev test1' )
2809 self
. assertRegex ( output
, 'local fdde:12:22::1 proto kernel metric 0 pref medium' )
2810 self
. assertRegex ( output
, 'local fdde:12:33::1 proto kernel metric 0 pref medium' )
2811 self
. assertRegex ( output
, 'local fdde:12:44::1 proto kernel metric 0 pref medium' )
2812 self
. assertRegex ( output
, 'local fdde:12:55::1 proto kernel metric 0 pref medium' )
2813 self
. assertRegex ( output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium' )
2815 def test_configure_without_carrier ( self
):
2816 copy_network_unit ( '11-dummy.netdev' )
2818 self
. wait_operstate ( 'test1' , 'off' , '' )
2819 check_output ( 'ip link set dev test1 up carrier off' )
2821 copy_network_unit ( '25-test1.network.d/configure-without-carrier.conf' , copy_dropins
= False )
2823 self
. wait_online ([ 'test1:no-carrier' ])
2825 carrier_map
= { 'on' : '1' , 'off' : '0' }
2826 routable_map
= { 'on' : 'routable' , 'off' : 'no-carrier' }
2827 for carrier
in [ 'off' , 'on' , 'off' ]:
2828 with self
. subTest ( carrier
= carrier
):
2829 if carrier_map
[ carrier
] != read_link_attr ( 'test1' , 'carrier' ):
2830 check_output ( f
'ip link set dev test1 carrier {carrier} ' )
2831 self
. wait_online ([ f
'test1:{routable_map[carrier]}:{routable_map[carrier]}' ])
2833 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
2835 self
. assertRegex ( output
, '192.168.0.15' )
2836 self
. assertRegex ( output
, '192.168.0.1' )
2837 self
. assertRegex ( output
, routable_map
[ carrier
])
2839 def test_configure_without_carrier_yes_ignore_carrier_loss_no ( self
):
2840 copy_network_unit ( '11-dummy.netdev' )
2842 self
. wait_operstate ( 'test1' , 'off' , '' )
2843 check_output ( 'ip link set dev test1 up carrier off' )
2845 copy_network_unit ( '25-test1.network' )
2847 self
. wait_online ([ 'test1:no-carrier' ])
2849 carrier_map
= { 'on' : '1' , 'off' : '0' }
2850 routable_map
= { 'on' : 'routable' , 'off' : 'no-carrier' }
2851 for ( carrier
, have_config
) in [( 'off' , True ), ( 'on' , True ), ( 'off' , False )]:
2852 with self
. subTest ( carrier
= carrier
, have_config
= have_config
):
2853 if carrier_map
[ carrier
] != read_link_attr ( 'test1' , 'carrier' ):
2854 check_output ( f
'ip link set dev test1 carrier {carrier} ' )
2855 self
. wait_online ([ f
'test1:{routable_map[carrier]}:{routable_map[carrier]}' ])
2857 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
2860 self
. assertRegex ( output
, '192.168.0.15' )
2861 self
. assertRegex ( output
, '192.168.0.1' )
2863 self
. assertNotRegex ( output
, '192.168.0.15' )
2864 self
. assertNotRegex ( output
, '192.168.0.1' )
2865 self
. assertRegex ( output
, routable_map
[ carrier
])
2867 def test_routing_policy_rule ( self
):
2868 copy_network_unit ( '25-routing-policy-rule-test1.network' , '11-dummy.netdev' )
2870 self
. wait_online ([ 'test1:degraded' ])
2872 output
= check_output ( 'ip rule list iif test1 priority 111' )
2874 self
. assertRegex ( output
, '111:' )
2875 self
. assertRegex ( output
, 'from 192.168.100.18' )
2876 self
. assertRegex ( output
, r
'tos (0x08|throughput)\s' )
2877 self
. assertRegex ( output
, 'iif test1' )
2878 self
. assertRegex ( output
, 'oif test1' )
2879 self
. assertRegex ( output
, 'lookup 7' )
2881 output
= check_output ( 'ip rule list iif test1 priority 101' )
2883 self
. assertRegex ( output
, '101:' )
2884 self
. assertRegex ( output
, 'from all' )
2885 self
. assertRegex ( output
, 'iif test1' )
2886 self
. assertRegex ( output
, 'lookup 9' )
2888 output
= check_output ( 'ip -6 rule list iif test1 priority 100' )
2890 self
. assertRegex ( output
, '100:' )
2891 self
. assertRegex ( output
, 'from all' )
2892 self
. assertRegex ( output
, 'iif test1' )
2893 self
. assertRegex ( output
, 'lookup 8' )
2895 output
= check_output ( 'ip rule list iif test1 priority 102' )
2897 self
. assertRegex ( output
, '102:' )
2898 self
. assertRegex ( output
, 'from 0.0.0.0/8' )
2899 self
. assertRegex ( output
, 'iif test1' )
2900 self
. assertRegex ( output
, 'lookup 10' )
2902 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2905 def test_routing_policy_rule_issue_11280 ( self
):
2906 copy_network_unit ( '25-routing-policy-rule-test1.network' , '11-dummy.netdev' ,
2907 '25-routing-policy-rule-dummy98.network' , '12-dummy.netdev' )
2909 for trial
in range ( 3 ):
2910 restart_networkd ( show_logs
=( trial
> 0 ))
2911 self
. wait_online ([ 'test1:degraded' , 'dummy98:degraded' ])
2913 output
= check_output ( 'ip rule list table 7' )
2915 self
. assertRegex ( output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7' )
2917 output
= check_output ( 'ip rule list table 8' )
2919 self
. assertRegex ( output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8' )
2921 def test_routing_policy_rule_reconfigure ( self
):
2922 copy_network_unit ( '25-routing-policy-rule-reconfigure2.network' , '11-dummy.netdev' )
2924 self
. wait_online ([ 'test1:degraded' ])
2926 output
= check_output ( 'ip rule list table 1011' )
2928 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2929 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2930 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2931 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2933 output
= check_output ( 'ip -6 rule list table 1011' )
2935 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2937 copy_network_unit ( '25-routing-policy-rule-reconfigure1.network' , '11-dummy.netdev' )
2939 self
. wait_online ([ 'test1:degraded' ])
2941 output
= check_output ( 'ip rule list table 1011' )
2943 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2944 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2945 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2946 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2948 output
= check_output ( 'ip -6 rule list table 1011' )
2950 self
. assertNotIn ( '10112: from all oif test1 lookup 1011' , output
)
2951 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2953 call ( 'ip rule delete priority 10111' )
2954 call ( 'ip rule delete priority 10112' )
2955 call ( 'ip rule delete priority 10113' )
2956 call ( 'ip rule delete priority 10114' )
2957 call ( 'ip -6 rule delete priority 10113' )
2959 output
= check_output ( 'ip rule list table 1011' )
2961 self
. assertEqual ( output
, '' )
2963 output
= check_output ( 'ip -6 rule list table 1011' )
2965 self
. assertEqual ( output
, '' )
2967 networkctl_reconfigure ( 'test1' )
2968 self
. wait_online ([ 'test1:degraded' ])
2970 output
= check_output ( 'ip rule list table 1011' )
2972 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2973 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2974 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2975 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2977 output
= check_output ( 'ip -6 rule list table 1011' )
2979 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2981 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable ()
2982 def test_routing_policy_rule_port_range ( self
):
2983 copy_network_unit ( '25-fibrule-port-range.network' , '11-dummy.netdev' )
2985 self
. wait_online ([ 'test1:degraded' ])
2987 output
= check_output ( 'ip rule' )
2989 self
. assertRegex ( output
, '111' )
2990 self
. assertRegex ( output
, 'from 192.168.100.18' )
2991 self
. assertRegex ( output
, '1123-1150' )
2992 self
. assertRegex ( output
, '3224-3290' )
2993 self
. assertRegex ( output
, 'tcp' )
2994 self
. assertRegex ( output
, 'lookup 7' )
2996 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable ()
2997 def test_routing_policy_rule_invert ( self
):
2998 copy_network_unit ( '25-fibrule-invert.network' , '11-dummy.netdev' )
3000 self
. wait_online ([ 'test1:degraded' ])
3002 output
= check_output ( 'ip rule' )
3004 self
. assertRegex ( output
, '111' )
3005 self
. assertRegex ( output
, 'not.*?from.*?192.168.100.18' )
3006 self
. assertRegex ( output
, 'tcp' )
3007 self
. assertRegex ( output
, 'lookup 7' )
3009 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable ()
3010 def test_routing_policy_rule_uidrange ( self
):
3011 copy_network_unit ( '25-fibrule-uidrange.network' , '11-dummy.netdev' )
3013 self
. wait_online ([ 'test1:degraded' ])
3015 output
= check_output ( 'ip rule' )
3017 self
. assertRegex ( output
, '111' )
3018 self
. assertRegex ( output
, 'from 192.168.100.18' )
3019 self
. assertRegex ( output
, 'lookup 7' )
3020 self
. assertRegex ( output
, 'uidrange 100-200' )
3022 def _test_route_static ( self
, manage_foreign_routes
):
3023 if not manage_foreign_routes
:
3024 copy_networkd_conf_dropin ( 'networkd-manage-foreign-routes-no.conf' )
3026 copy_network_unit ( '25-route-static.network' , '12-dummy.netdev' )
3028 self
. wait_online ([ 'dummy98:routable' ])
3030 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
3033 print ( '### ip -6 route show dev dummy98' )
3034 output
= check_output ( 'ip -6 route show dev dummy98' )
3036 self
. assertIn ( '2001:1234:5:8fff:ff:ff:ff:ff proto static' , output
)
3037 self
. assertIn ( '2001:1234:5:8f63::1 proto kernel' , output
)
3038 self
. assertIn ( '2001:1234:5:afff:ff:ff:ff:ff via fe80:0:222:4dff:ff:ff:ff:ff proto static' , output
)
3040 print ( '### ip -6 route show default' )
3041 output
= check_output ( 'ip -6 route show default' )
3043 self
. assertIn ( 'default' , output
)
3044 self
. assertIn ( 'via 2001:1234:5:8fff:ff:ff:ff:ff' , output
)
3046 print ( '### ip -4 route show dev dummy98' )
3047 output
= check_output ( 'ip -4 route show dev dummy98' )
3049 self
. assertIn ( '149.10.124.48/28 proto kernel scope link src 149.10.124.58' , output
)
3050 self
. assertIn ( '149.10.124.64 proto static scope link' , output
)
3051 self
. assertIn ( '169.254.0.0/16 proto static scope link metric 2048' , output
)
3052 self
. assertIn ( '192.168.1.1 proto static scope link initcwnd 20' , output
)
3053 self
. assertIn ( '192.168.1.2 proto static scope link initrwnd 30' , output
)
3054 self
. assertIn ( '192.168.1.3 proto static scope link advmss 30' , output
)
3055 self
. assertIn ( '192.168.1.4 proto static scope link hoplimit 122' , output
)
3056 self
. assertIn ( 'multicast 149.10.123.4 proto static' , output
)
3058 print ( '### ip -4 route show dev dummy98 default' )
3059 output
= check_output ( 'ip -4 route show dev dummy98 default' )
3061 self
. assertIn ( 'default via 149.10.125.65 proto static onlink' , output
)
3062 self
. assertIn ( 'default via 149.10.124.64 proto static' , output
)
3063 self
. assertIn ( 'default proto static' , output
)
3065 print ( '### ip -4 route show table local dev dummy98' )
3066 output
= check_output ( 'ip -4 route show table local dev dummy98' )
3068 self
. assertIn ( 'local 149.10.123.1 proto static scope host' , output
)
3069 self
. assertIn ( 'anycast 149.10.123.2 proto static scope link' , output
)
3070 self
. assertIn ( 'broadcast 149.10.123.3 proto static scope link' , output
)
3072 print ( '### ip -4 route show type blackhole' )
3073 output
= check_output ( 'ip -4 route show type blackhole' )
3075 self
. assertIn ( 'blackhole 202.54.1.2 proto static' , output
)
3077 print ( '### ip -4 route show type unreachable' )
3078 output
= check_output ( 'ip -4 route show type unreachable' )
3080 self
. assertIn ( 'unreachable 202.54.1.3 proto static' , output
)
3082 print ( '### ip -4 route show type prohibit' )
3083 output
= check_output ( 'ip -4 route show type prohibit' )
3085 self
. assertIn ( 'prohibit 202.54.1.4 proto static' , output
)
3087 print ( '### ip -6 route show type blackhole' )
3088 output
= check_output ( 'ip -6 route show type blackhole' )
3090 self
. assertIn ( 'blackhole 2001:1234:5678::2 dev lo proto static' , output
)
3092 print ( '### ip -6 route show type unreachable' )
3093 output
= check_output ( 'ip -6 route show type unreachable' )
3095 self
. assertIn ( 'unreachable 2001:1234:5678::3 dev lo proto static' , output
)
3097 print ( '### ip -6 route show type prohibit' )
3098 output
= check_output ( 'ip -6 route show type prohibit' )
3100 self
. assertIn ( 'prohibit 2001:1234:5678::4 dev lo proto static' , output
)
3102 print ( '### ip route show 192.168.10.1' )
3103 output
= check_output ( 'ip route show 192.168.10.1' )
3105 self
. assertIn ( '192.168.10.1 proto static' , output
)
3106 self
. assertIn ( 'nexthop via 149.10.124.59 dev dummy98 weight 10' , output
)
3107 self
. assertIn ( 'nexthop via 149.10.124.60 dev dummy98 weight 5' , output
)
3109 print ( '### ip route show 192.168.10.2' )
3110 output
= check_output ( 'ip route show 192.168.10.2' )
3112 # old ip command does not show IPv6 gateways...
3113 self
. assertIn ( '192.168.10.2 proto static' , output
)
3114 self
. assertIn ( 'nexthop' , output
)
3115 self
. assertIn ( 'dev dummy98 weight 10' , output
)
3116 self
. assertIn ( 'dev dummy98 weight 5' , output
)
3118 print ( '### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff' )
3119 output
= check_output ( 'ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff' )
3121 # old ip command does not show 'nexthop' keyword and weight...
3122 self
. assertIn ( '2001:1234:5:7fff:ff:ff:ff:ff' , output
)
3123 self
. assertIn ( 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98' , output
)
3124 self
. assertIn ( 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98' , output
)
3126 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3129 copy_network_unit ( '25-address-static.network' )
3131 self
. wait_online ([ 'dummy98:routable' ])
3133 # check all routes managed by Manager are removed
3134 print ( '### ip -4 route show type blackhole' )
3135 output
= check_output ( 'ip -4 route show type blackhole' )
3137 self
. assertEqual ( output
, '' )
3139 print ( '### ip -4 route show type unreachable' )
3140 output
= check_output ( 'ip -4 route show type unreachable' )
3142 self
. assertEqual ( output
, '' )
3144 print ( '### ip -4 route show type prohibit' )
3145 output
= check_output ( 'ip -4 route show type prohibit' )
3147 self
. assertEqual ( output
, '' )
3149 print ( '### ip -6 route show type blackhole' )
3150 output
= check_output ( 'ip -6 route show type blackhole' )
3152 self
. assertEqual ( output
, '' )
3154 print ( '### ip -6 route show type unreachable' )
3155 output
= check_output ( 'ip -6 route show type unreachable' )
3157 self
. assertEqual ( output
, '' )
3159 print ( '### ip -6 route show type prohibit' )
3160 output
= check_output ( 'ip -6 route show type prohibit' )
3162 self
. assertEqual ( output
, '' )
3164 remove_network_unit ( '25-address-static.network' )
3166 self
. wait_online ([ 'dummy98:routable' ])
3168 # check all routes managed by Manager are reconfigured
3169 print ( '### ip -4 route show type blackhole' )
3170 output
= check_output ( 'ip -4 route show type blackhole' )
3172 self
. assertIn ( 'blackhole 202.54.1.2 proto static' , output
)
3174 print ( '### ip -4 route show type unreachable' )
3175 output
= check_output ( 'ip -4 route show type unreachable' )
3177 self
. assertIn ( 'unreachable 202.54.1.3 proto static' , output
)
3179 print ( '### ip -4 route show type prohibit' )
3180 output
= check_output ( 'ip -4 route show type prohibit' )
3182 self
. assertIn ( 'prohibit 202.54.1.4 proto static' , output
)
3184 print ( '### ip -6 route show type blackhole' )
3185 output
= check_output ( 'ip -6 route show type blackhole' )
3187 self
. assertIn ( 'blackhole 2001:1234:5678::2 dev lo proto static' , output
)
3189 print ( '### ip -6 route show type unreachable' )
3190 output
= check_output ( 'ip -6 route show type unreachable' )
3192 self
. assertIn ( 'unreachable 2001:1234:5678::3 dev lo proto static' , output
)
3194 print ( '### ip -6 route show type prohibit' )
3195 output
= check_output ( 'ip -6 route show type prohibit' )
3197 self
. assertIn ( 'prohibit 2001:1234:5678::4 dev lo proto static' , output
)
3199 remove_link ( 'dummy98' )
3202 # check all routes managed by Manager are removed
3203 print ( '### ip -4 route show type blackhole' )
3204 output
= check_output ( 'ip -4 route show type blackhole' )
3206 self
. assertEqual ( output
, '' )
3208 print ( '### ip -4 route show type unreachable' )
3209 output
= check_output ( 'ip -4 route show type unreachable' )
3211 self
. assertEqual ( output
, '' )
3213 print ( '### ip -4 route show type prohibit' )
3214 output
= check_output ( 'ip -4 route show type prohibit' )
3216 self
. assertEqual ( output
, '' )
3218 print ( '### ip -6 route show type blackhole' )
3219 output
= check_output ( 'ip -6 route show type blackhole' )
3221 self
. assertEqual ( output
, '' )
3223 print ( '### ip -6 route show type unreachable' )
3224 output
= check_output ( 'ip -6 route show type unreachable' )
3226 self
. assertEqual ( output
, '' )
3228 print ( '### ip -6 route show type prohibit' )
3229 output
= check_output ( 'ip -6 route show type prohibit' )
3231 self
. assertEqual ( output
, '' )
3235 def test_route_static ( self
):
3237 for manage_foreign_routes
in [ True , False ]:
3243 print ( f
'### test_route_static(manage_foreign_routes= {manage_foreign_routes} )' )
3244 with self
. subTest ( manage_foreign_routes
= manage_foreign_routes
):
3245 self
._ test
_ route
_ static
( manage_foreign_routes
)
3247 @expectedFailureIfRTA_VIAIsNotSupported ()
3248 def test_route_via_ipv6 ( self
):
3249 copy_network_unit ( '25-route-via-ipv6.network' , '12-dummy.netdev' )
3251 self
. wait_online ([ 'dummy98:routable' ])
3253 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
3256 print ( '### ip -6 route show dev dummy98' )
3257 output
= check_output ( 'ip -6 route show dev dummy98' )
3259 self
. assertRegex ( output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static' )
3260 self
. assertRegex ( output
, '2001:1234:5:8f63::1 proto kernel' )
3262 print ( '### ip -4 route show dev dummy98' )
3263 output
= check_output ( 'ip -4 route show dev dummy98' )
3265 self
. assertRegex ( output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58' )
3266 self
. assertRegex ( output
, '149.10.124.66 via inet6 2001:1234:5:8fff:ff:ff:ff:ff proto static' )
3268 @expectedFailureIfModuleIsNotAvailable ( 'tcp_dctcp' )
3269 def test_route_congctl ( self
):
3270 copy_network_unit ( '25-route-congctl.network' , '12-dummy.netdev' )
3272 self
. wait_online ([ 'dummy98:routable' ])
3274 print ( '### ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff' )
3275 output
= check_output ( 'ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff' )
3277 self
. assertIn ( '2001:1234:5:8fff:ff:ff:ff:ff proto static' , output
)
3278 self
. assertIn ( 'congctl dctcp' , output
)
3280 print ( '### ip -4 route show dev dummy98 149.10.124.66' )
3281 output
= check_output ( 'ip -4 route show dev dummy98 149.10.124.66' )
3283 self
. assertIn ( '149.10.124.66 proto static' , output
)
3284 self
. assertIn ( 'congctl dctcp' , output
)
3285 self
. assertIn ( 'rto_min 300s' , output
)
3287 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
3288 def test_route_vrf ( self
):
3289 copy_network_unit ( '25-route-vrf.network' , '12-dummy.netdev' ,
3290 '25-vrf.netdev' , '25-vrf.network' )
3292 self
. wait_online ([ 'dummy98:routable' , 'vrf99:carrier' ])
3294 output
= check_output ( 'ip route show vrf vrf99' )
3296 self
. assertRegex ( output
, 'default via 192.168.100.1' )
3298 output
= check_output ( 'ip route show' )
3300 self
. assertNotRegex ( output
, 'default via 192.168.100.1' )
3302 def test_gateway_reconfigure ( self
):
3303 copy_network_unit ( '25-gateway-static.network' , '12-dummy.netdev' )
3305 self
. wait_online ([ 'dummy98:routable' ])
3306 print ( '### ip -4 route show dev dummy98 default' )
3307 output
= check_output ( 'ip -4 route show dev dummy98 default' )
3309 self
. assertIn ( 'default via 149.10.124.59 proto static' , output
)
3310 self
. assertNotIn ( '149.10.124.60' , output
)
3312 remove_network_unit ( '25-gateway-static.network' )
3313 copy_network_unit ( '25-gateway-next-static.network' )
3315 self
. wait_online ([ 'dummy98:routable' ])
3316 print ( '### ip -4 route show dev dummy98 default' )
3317 output
= check_output ( 'ip -4 route show dev dummy98 default' )
3319 self
. assertNotIn ( '149.10.124.59' , output
)
3320 self
. assertIn ( 'default via 149.10.124.60 proto static' , output
)
3322 def test_ip_route_ipv6_src_route ( self
):
3323 # a dummy device does not make the addresses go through tentative state, so we
3324 # reuse a bond from an earlier test, which does make the addresses go through
3325 # tentative state, and do our test on that
3326 copy_network_unit ( '23-active-slave.network' , '25-route-ipv6-src.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
3328 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:routable' ])
3330 output
= check_output ( 'ip -6 route list dev bond199' )
3332 self
. assertIn ( 'abcd::/16 via 2001:1234:56:8f63::1:1 proto static src 2001:1234:56:8f63::2' , output
)
3334 def test_route_preferred_source_with_existing_address ( self
):
3336 copy_network_unit ( '25-route-preferred-source.network' , '12-dummy.netdev' )
3341 networkctl_reconfigure ( 'dummy98' )
3343 self
. wait_online ([ 'dummy98:routable' ])
3345 output
= check_output ( 'ip -6 route list dev dummy98' )
3347 self
. assertIn ( 'abcd::/16 via 2001:1234:56:8f63::1:1 proto static src 2001:1234:56:8f63::1' , output
)
3349 def test_ip_link_mac_address ( self
):
3350 copy_network_unit ( '25-address-link-section.network' , '12-dummy.netdev' )
3352 self
. wait_online ([ 'dummy98:degraded' ])
3354 output
= check_output ( 'ip link show dummy98' )
3356 self
. assertRegex ( output
, '00:01:02:aa:bb:cc' )
3358 def test_ip_link_unmanaged ( self
):
3359 copy_network_unit ( '25-link-section-unmanaged.network' , '12-dummy.netdev' )
3362 self
. wait_operstate ( 'dummy98' , 'off' , setup_state
= 'unmanaged' )
3364 def test_ipv6_address_label ( self
):
3365 copy_network_unit ( '25-ipv6-address-label-section.network' , '12-dummy.netdev' )
3367 self
. wait_online ([ 'dummy98:degraded' ])
3369 output
= check_output ( 'ip addrlabel list' )
3371 self
. assertRegex ( output
, '2004:da8:1::/64' )
3373 def test_ipv6_proxy_ndp ( self
):
3374 copy_network_unit ( '25-ipv6-proxy-ndp.network' , '12-dummy.netdev' )
3377 self
. wait_online ([ 'dummy98:routable' ])
3379 output
= check_output ( 'ip neighbor show proxy dev dummy98' )
3381 for i
in range ( 1 , 5 ):
3382 self
. assertRegex ( output
, f
'2607:5300:203:5215: {i} ::1 *proxy' )
3384 def test_neighbor_section ( self
):
3385 copy_network_unit ( '25-neighbor-section.network' , '12-dummy.netdev' , copy_dropins
= False )
3387 self
. wait_online ([ 'dummy98:degraded' ])
3389 print ( '### ip neigh list dev dummy98' )
3390 output
= check_output ( 'ip neigh list dev dummy98' )
3392 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:02:65 PERMANENT' , output
)
3393 self
. assertIn ( '2004:da8:1::1 lladdr 00:00:5e:00:02:66 PERMANENT' , output
)
3394 self
. assertNotIn ( '2004:da8:1:0::2' , output
)
3395 self
. assertNotIn ( '192.168.10.2' , output
)
3396 self
. assertNotIn ( '00:00:5e:00:02:67' , output
)
3398 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3401 copy_network_unit ( '25-neighbor-section.network.d/override.conf' )
3403 self
. wait_online ([ 'dummy98:degraded' ])
3405 print ( '### ip neigh list dev dummy98 (after reloading)' )
3406 output
= check_output ( 'ip neigh list dev dummy98' )
3408 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:03:65 PERMANENT' , output
)
3409 self
. assertIn ( '2004:da8:1::1 lladdr 00:00:5e:00:03:66 PERMANENT' , output
)
3410 self
. assertNotIn ( '2004:da8:1:0::2' , output
)
3411 self
. assertNotIn ( '192.168.10.2' , output
)
3412 self
. assertNotIn ( '00:00:5e:00:02' , output
)
3414 def test_neighbor_reconfigure ( self
):
3415 copy_network_unit ( '25-neighbor-section.network' , '12-dummy.netdev' , copy_dropins
= False )
3417 self
. wait_online ([ 'dummy98:degraded' ])
3419 print ( '### ip neigh list dev dummy98' )
3420 output
= check_output ( 'ip neigh list dev dummy98' )
3422 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:02:65 PERMANENT' , output
)
3423 self
. assertIn ( '2004:da8:1::1 lladdr 00:00:5e:00:02:66 PERMANENT' , output
)
3425 remove_network_unit ( '25-neighbor-section.network' )
3426 copy_network_unit ( '25-neighbor-next.network' )
3428 self
. wait_online ([ 'dummy98:degraded' ])
3429 print ( '### ip neigh list dev dummy98' )
3430 output
= check_output ( 'ip neigh list dev dummy98' )
3432 self
. assertNotIn ( '00:00:5e:00:02:65' , output
)
3433 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:02:66 PERMANENT' , output
)
3434 self
. assertNotIn ( '2004:da8:1::1' , output
)
3436 def test_neighbor_gre ( self
):
3437 copy_network_unit ( '25-neighbor-ip.network' , '25-neighbor-ipv6.network' , '25-neighbor-ip-dummy.network' ,
3438 '12-dummy.netdev' , '25-gre-tunnel-remote-any.netdev' , '25-ip6gre-tunnel-remote-any.netdev' )
3440 self
. wait_online ([ 'dummy98:degraded' , 'gretun97:routable' , 'ip6gretun97:routable' ], timeout
= '40s' )
3442 output
= check_output ( 'ip neigh list dev gretun97' )
3444 self
. assertIn ( '10.0.0.22 lladdr 10.65.223.239 PERMANENT' , output
)
3445 self
. assertNotIn ( '10.0.0.23' , output
)
3447 output
= check_output ( 'ip neigh list dev ip6gretun97' )
3449 self
. assertRegex ( output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT' )
3450 self
. assertNotIn ( '2001:db8:0:f102::18' , output
)
3452 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3455 def test_link_local_addressing ( self
):
3456 copy_network_unit ( '25-link-local-addressing-yes.network' , '11-dummy.netdev' ,
3457 '25-link-local-addressing-no.network' , '12-dummy.netdev' )
3459 self
. wait_online ([ 'test1:degraded' , 'dummy98:carrier' ])
3461 output
= check_output ( 'ip address show dev test1' )
3463 self
. assertRegex ( output
, 'inet .* scope link' )
3464 self
. assertRegex ( output
, 'inet6 .* scope link' )
3466 output
= check_output ( 'ip address show dev dummy98' )
3468 self
. assertNotRegex ( output
, 'inet6* .* scope link' )
3470 # Documentation/networking/ip-sysctl.txt
3472 # addr_gen_mode - INTEGER
3473 # Defines how link-local and autoconf addresses are generated.
3475 # 0: generate address based on EUI64 (default)
3476 # 1: do no generate a link-local address, use EUI64 for addresses generated
3478 # 2: generate stable privacy addresses, using the secret from
3479 # stable_secret (RFC7217)
3480 # 3: generate stable privacy addresses, using a random secret if unset
3482 self
. check_ipv6_sysctl_attr ( 'test1' , 'stable_secret' , '0123:4567:89ab:cdef:0123:4567:89ab:cdef' )
3483 self
. check_ipv6_sysctl_attr ( 'test1' , 'addr_gen_mode' , '2' )
3484 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'addr_gen_mode' , '1' )
3486 def test_link_local_addressing_ipv6ll ( self
):
3487 copy_network_unit ( '26-link-local-addressing-ipv6.network' , '12-dummy.netdev' )
3489 self
. wait_online ([ 'dummy98:degraded' ])
3491 # An IPv6LL address exists by default.
3492 output
= check_output ( 'ip address show dev dummy98' )
3494 self
. assertRegex ( output
, 'inet6 .* scope link' )
3496 copy_network_unit ( '25-link-local-addressing-no.network' )
3498 self
. wait_online ([ 'dummy98:carrier' ])
3500 # Check if the IPv6LL address is removed.
3501 output
= check_output ( 'ip address show dev dummy98' )
3503 self
. assertNotRegex ( output
, 'inet6 .* scope link' )
3505 remove_network_unit ( '25-link-local-addressing-no.network' )
3507 self
. wait_online ([ 'dummy98:degraded' ])
3509 # Check if a new IPv6LL address is assigned.
3510 output
= check_output ( 'ip address show dev dummy98' )
3512 self
. assertRegex ( output
, 'inet6 .* scope link' )
3514 def test_sysctl ( self
):
3515 copy_networkd_conf_dropin ( '25-global-ipv6-privacy-extensions.conf' )
3516 copy_network_unit ( '25-sysctl.network' , '12-dummy.netdev' , copy_dropins
= False )
3518 self
. wait_online ([ 'dummy98:degraded' ])
3520 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
3521 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'use_tempaddr' , '1' )
3522 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'dad_transmits' , '3' )
3523 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'hop_limit' , '5' )
3524 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'proxy_ndp' , '1' )
3525 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
3526 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'proxy_arp' , '1' )
3527 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'accept_local' , '1' )
3528 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'rp_filter' , '0' )
3530 copy_network_unit ( '25-sysctl.network.d/25-ipv6-privacy-extensions.conf' )
3532 self
. wait_online ([ 'dummy98:degraded' ])
3534 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'use_tempaddr' , '2' )
3536 def test_sysctl_disable_ipv6 ( self
):
3537 copy_network_unit ( '25-sysctl-disable-ipv6.network' , '12-dummy.netdev' )
3539 print ( '## Disable ipv6' )
3540 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=1' )
3541 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=1' )
3544 self
. wait_online ([ 'dummy98:routable' ])
3546 output
= check_output ( 'ip -4 address show dummy98' )
3548 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3549 output
= check_output ( 'ip -6 address show dummy98' )
3551 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3552 self
. assertRegex ( output
, 'inet6 .* scope link' )
3553 output
= check_output ( 'ip -4 route show dev dummy98' )
3555 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3556 output
= check_output ( 'ip -6 route show default' )
3558 self
. assertRegex ( output
, 'default' )
3559 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3561 remove_link ( 'dummy98' )
3563 print ( '## Enable ipv6' )
3564 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=0' )
3565 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=0' )
3568 self
. wait_online ([ 'dummy98:routable' ])
3570 output
= check_output ( 'ip -4 address show dummy98' )
3572 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3573 output
= check_output ( 'ip -6 address show dummy98' )
3575 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3576 self
. assertRegex ( output
, 'inet6 .* scope link' )
3577 output
= check_output ( 'ip -4 route show dev dummy98' )
3579 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3580 output
= check_output ( 'ip -6 route show default' )
3582 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3584 def test_bind_carrier ( self
):
3585 copy_network_unit ( '25-bind-carrier.network' , '11-dummy.netdev' )
3588 # no bound interface.
3589 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
3590 output
= check_output ( 'ip address show test1' )
3592 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3593 self
. assertIn ( 'DOWN' , output
)
3594 self
. assertNotIn ( '192.168.10' , output
)
3596 # add one bound interface. The interface will be up.
3597 check_output ( 'ip link add dummy98 type dummy' )
3598 check_output ( 'ip link set dummy98 up' )
3599 self
. wait_online ([ 'test1:routable' ])
3600 output
= check_output ( 'ip address show test1' )
3602 self
. assertIn ( 'UP,LOWER_UP' , output
)
3603 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3605 # add another bound interface. The interface is still up.
3606 check_output ( 'ip link add dummy99 type dummy' )
3607 check_output ( 'ip link set dummy99 up' )
3608 self
. wait_operstate ( 'dummy99' , 'degraded' , setup_state
= 'unmanaged' )
3609 output
= check_output ( 'ip address show test1' )
3611 self
. assertIn ( 'UP,LOWER_UP' , output
)
3612 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3614 # remove one of the bound interfaces. The interface is still up
3615 remove_link ( 'dummy98' )
3616 output
= check_output ( 'ip address show test1' )
3618 self
. assertIn ( 'UP,LOWER_UP' , output
)
3619 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3621 # bring down the remaining bound interface. The interface will be down.
3622 check_output ( 'ip link set dummy99 down' )
3623 self
. wait_operstate ( 'test1' , 'off' )
3624 self
. wait_address_dropped ( 'test1' , r
'192.168.10' , ipv
= '-4' , timeout_sec
= 10 )
3625 output
= check_output ( 'ip address show test1' )
3627 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3628 self
. assertIn ( 'DOWN' , output
)
3629 self
. assertNotIn ( '192.168.10' , output
)
3631 # bring up the bound interface. The interface will be up.
3632 check_output ( 'ip link set dummy99 up' )
3633 self
. wait_online ([ 'test1:routable' ])
3634 output
= check_output ( 'ip address show test1' )
3636 self
. assertIn ( 'UP,LOWER_UP' , output
)
3637 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3639 # remove the remaining bound interface. The interface will be down.
3640 remove_link ( 'dummy99' )
3641 self
. wait_operstate ( 'test1' , 'off' )
3642 self
. wait_address_dropped ( 'test1' , r
'192.168.10' , ipv
= '-4' , timeout_sec
= 10 )
3643 output
= check_output ( 'ip address show test1' )
3645 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3646 self
. assertIn ( 'DOWN' , output
)
3647 self
. assertNotIn ( '192.168.10' , output
)
3649 # re-add one bound interface. The interface will be up.
3650 check_output ( 'ip link add dummy98 type dummy' )
3651 check_output ( 'ip link set dummy98 up' )
3652 self
. wait_online ([ 'test1:routable' ])
3653 output
= check_output ( 'ip address show test1' )
3655 self
. assertIn ( 'UP,LOWER_UP' , output
)
3656 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3658 def _test_activation_policy ( self
, interface
, test
):
3659 conffile
= '25-activation-policy.network'
3661 conffile
= f
' {conffile} .d/ {test} .conf'
3662 if interface
== 'vlan99' :
3663 copy_network_unit ( '21-vlan.netdev' , '21-vlan-test1.network' )
3664 copy_network_unit ( '11-dummy.netdev' , conffile
, copy_dropins
= False )
3667 always
= test
. startswith ( 'always' )
3668 initial_up
= test
!= 'manual' and not test
. endswith ( 'down' ) # note: default is up
3669 expect_up
= initial_up
3670 next_up
= not expect_up
3672 if test
. endswith ( 'down' ):
3673 self
. wait_activated ( interface
)
3675 for iteration
in range ( 4 ):
3676 with self
. subTest ( iteration
= iteration
, expect_up
= expect_up
):
3677 operstate
= 'routable' if expect_up
else 'off'
3678 setup_state
= 'configured' if expect_up
else ( 'configuring' if iteration
== 0 else None )
3679 self
. wait_operstate ( interface
, operstate
, setup_state
= setup_state
, setup_timeout
= 20 )
3682 self
. assertIn ( 'UP' , check_output ( f
'ip link show {interface} ' ))
3683 self
. assertIn ( '192.168.10.30/24' , check_output ( f
'ip address show {interface} ' ))
3684 self
. assertIn ( 'default via 192.168.10.1' , check_output ( f
'ip route show dev {interface} ' ))
3686 self
. assertIn ( 'DOWN' , check_output ( f
'ip link show {interface} ' ))
3689 check_output ( f
'ip link set dev {interface} up' )
3691 check_output ( f
'ip link set dev {interface} down' )
3692 expect_up
= initial_up
if always
else next_up
3693 next_up
= not next_up
3697 def test_activation_policy ( self
):
3699 for interface
in [ 'test1' , 'vlan99' ]:
3700 for test
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , '' ]:
3706 print ( f
'### test_activation_policy(interface= {interface} , test= {test} )' )
3707 with self
. subTest ( interface
= interface
, test
= test
):
3708 self
._ test
_ activation
_ policy
( interface
, test
)
3710 def _test_activation_policy_required_for_online ( self
, policy
, required
):
3711 conffile
= '25-activation-policy.network'
3712 units
= [ '11-dummy.netdev' , '12-dummy.netdev' , '12-dummy.network' , conffile
]
3714 units
+= [ f
' {conffile} .d/ {policy} .conf' ]
3716 units
+= [ f
' {conffile} .d/required- {required} .conf' ]
3717 copy_network_unit (* units
, copy_dropins
= False )
3720 if policy
. endswith ( 'down' ):
3721 self
. wait_activated ( 'test1' )
3723 if policy
. endswith ( 'down' ) or policy
== 'manual' :
3724 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
3726 self
. wait_online ([ 'test1' ])
3728 if policy
== 'always-down' :
3729 # if always-down, required for online is forced to no
3732 # otherwise if required for online is specified, it should match that
3733 expected
= required
== 'yes'
3735 # otherwise if only policy specified, required for online defaults to
3736 # true if policy is up, always-up, or bound
3737 expected
= policy
. endswith ( 'up' ) or policy
== 'bound'
3739 # default is true, if neither are specified
3742 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
3745 yesno
= 'yes' if expected
else 'no'
3746 self
. assertRegex ( output
, f
'Required For Online: {yesno} ' )
3748 def test_activation_policy_required_for_online ( self
):
3750 for policy
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , 'bound' , '' ]:
3751 for required
in [ 'yes' , 'no' , '' ]:
3757 print ( f
'### test_activation_policy_required_for_online(policy= {policy} , required= {required} )' )
3758 with self
. subTest ( policy
= policy
, required
= required
):
3759 self
._ test
_ activation
_ policy
_ required
_ for
_ online
( policy
, required
)
3761 def test_domain ( self
):
3762 copy_network_unit ( '12-dummy.netdev' , '24-search-domain.network' )
3764 self
. wait_online ([ 'dummy98:routable' ])
3766 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
3768 self
. assertRegex ( output
, 'Address: 192.168.42.100' )
3769 self
. assertRegex ( output
, 'DNS: 192.168.42.1' )
3770 self
. assertRegex ( output
, 'Search Domains: one' )
3772 def test_keep_configuration_static ( self
):
3773 check_output ( 'ip link add name dummy98 type dummy' )
3774 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
3775 check_output ( 'ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500' )
3776 output
= check_output ( 'ip address show dummy98' )
3778 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
3779 self
. assertRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
3780 output
= check_output ( 'ip route show dev dummy98' )
3783 copy_network_unit ( '24-keep-configuration-static.network' )
3785 self
. wait_online ([ 'dummy98:routable' ])
3787 output
= check_output ( 'ip address show dummy98' )
3789 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
3790 self
. assertNotRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
3792 @expectedFailureIfNexthopIsNotAvailable ()
3793 def test_nexthop ( self
):
3794 def check_nexthop ( self
):
3795 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
3797 output
= check_output ( 'ip nexthop list dev veth99' )
3799 self
. assertIn ( 'id 1 via 192.168.5.1 dev veth99' , output
)
3800 self
. assertIn ( 'id 2 via 2001:1234:5:8f63::2 dev veth99' , output
)
3801 self
. assertIn ( 'id 3 dev veth99' , output
)
3802 self
. assertIn ( 'id 4 dev veth99' , output
)
3803 self
. assertRegex ( output
, 'id 5 via 192.168.10.1 dev veth99 .*onlink' )
3804 self
. assertIn ( 'id 8 via fe80:0:222:4dff:ff:ff:ff:ff dev veth99' , output
)
3805 self
. assertRegex ( output
, r
'id [0-9]* via 192.168.5.2 dev veth99' )
3807 output
= check_output ( 'ip nexthop list dev dummy98' )
3809 self
. assertIn ( 'id 20 via 192.168.20.1 dev dummy98' , output
)
3811 # kernel manages blackhole nexthops on lo
3812 output
= check_output ( 'ip nexthop list dev lo' )
3814 self
. assertIn ( 'id 6 blackhole' , output
)
3815 self
. assertIn ( 'id 7 blackhole' , output
)
3817 # group nexthops are shown with -0 option
3818 output
= check_output ( 'ip -0 nexthop list id 21' )
3820 self
. assertRegex ( output
, r
'id 21 group (1,3/20|20/1,3)' )
3822 output
= check_output ( 'ip route show dev veth99 10.10.10.10' )
3824 self
. assertEqual ( '10.10.10.10 nhid 1 via 192.168.5.1 proto static' , output
)
3826 output
= check_output ( 'ip route show dev veth99 10.10.10.11' )
3828 self
. assertEqual ( '10.10.10.11 nhid 2 via inet6 2001:1234:5:8f63::2 proto static' , output
)
3830 output
= check_output ( 'ip route show dev veth99 10.10.10.12' )
3832 self
. assertEqual ( '10.10.10.12 nhid 5 via 192.168.10.1 proto static onlink' , output
)
3834 output
= check_output ( 'ip -6 route show dev veth99 2001:1234:5:8f62::1' )
3836 self
. assertEqual ( '2001:1234:5:8f62::1 nhid 2 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium' , output
)
3838 output
= check_output ( 'ip route show 10.10.10.13' )
3840 self
. assertEqual ( 'blackhole 10.10.10.13 nhid 6 dev lo proto static' , output
)
3842 output
= check_output ( 'ip -6 route show 2001:1234:5:8f62::2' )
3844 self
. assertEqual ( 'blackhole 2001:1234:5:8f62::2 nhid 7 dev lo proto static metric 1024 pref medium' , output
)
3846 output
= check_output ( 'ip route show 10.10.10.14' )
3848 self
. assertIn ( '10.10.10.14 nhid 21 proto static' , output
)
3849 self
. assertIn ( 'nexthop via 192.168.20.1 dev dummy98 weight 1' , output
)
3850 self
. assertIn ( 'nexthop via 192.168.5.1 dev veth99 weight 3' , output
)
3852 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3855 copy_network_unit ( '25-nexthop.network' , '25-veth.netdev' , '25-veth-peer.network' ,
3856 '12-dummy.netdev' , '25-nexthop-dummy.network' )
3861 remove_network_unit ( '25-nexthop.network' )
3862 copy_network_unit ( '25-nexthop-nothing.network' )
3864 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
3866 output
= check_output ( 'ip nexthop list dev veth99' )
3868 self
. assertEqual ( output
, '' )
3869 output
= check_output ( 'ip nexthop list dev lo' )
3871 self
. assertEqual ( output
, '' )
3873 remove_network_unit ( '25-nexthop-nothing.network' )
3874 copy_network_unit ( '25-nexthop.network' )
3875 networkctl_reconfigure ( 'dummy98' )
3880 remove_link ( 'veth99' )
3883 output
= check_output ( 'ip nexthop list dev lo' )
3885 self
. assertEqual ( output
, '' )
3887 class NetworkdTCTests ( unittest
. TestCase
, Utilities
):
3895 @expectedFailureIfModuleIsNotAvailable ( 'sch_cake' )
3896 def test_qdisc_cake ( self
):
3897 copy_network_unit ( '25-qdisc-cake.network' , '12-dummy.netdev' )
3899 self
. wait_online ([ 'dummy98:routable' ])
3901 output
= check_output ( 'tc qdisc show dev dummy98' )
3903 self
. assertIn ( 'qdisc cake 3a: root' , output
)
3904 self
. assertIn ( 'bandwidth 500Mbit' , output
)
3905 self
. assertIn ( 'autorate-ingress' , output
)
3906 self
. assertIn ( 'diffserv8' , output
)
3907 self
. assertIn ( 'dual-dsthost' , output
)
3908 self
. assertIn ( ' nat' , output
)
3909 self
. assertIn ( ' wash' , output
)
3910 self
. assertIn ( ' split-gso' , output
)
3911 self
. assertIn ( ' raw' , output
)
3912 self
. assertIn ( ' atm' , output
)
3913 self
. assertIn ( 'overhead 128' , output
)
3914 self
. assertIn ( 'mpu 20' , output
)
3915 self
. assertIn ( 'fwmark 0xff00' , output
)
3916 self
. assertIn ( 'rtt 1s' , output
)
3917 self
. assertIn ( 'ack-filter-aggressive' , output
)
3919 @expectedFailureIfModuleIsNotAvailable ( 'sch_codel' )
3920 def test_qdisc_codel ( self
):
3921 copy_network_unit ( '25-qdisc-codel.network' , '12-dummy.netdev' )
3923 self
. wait_online ([ 'dummy98:routable' ])
3925 output
= check_output ( 'tc qdisc show dev dummy98' )
3927 self
. assertRegex ( output
, 'qdisc codel 33: root' )
3928 self
. assertRegex ( output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn' )
3930 @expectedFailureIfModuleIsNotAvailable ( 'sch_drr' )
3931 def test_qdisc_drr ( self
):
3932 copy_network_unit ( '25-qdisc-drr.network' , '12-dummy.netdev' )
3934 self
. wait_online ([ 'dummy98:routable' ])
3936 output
= check_output ( 'tc qdisc show dev dummy98' )
3938 self
. assertRegex ( output
, 'qdisc drr 2: root' )
3939 output
= check_output ( 'tc class show dev dummy98' )
3941 self
. assertRegex ( output
, 'class drr 2:30 root quantum 2000b' )
3943 @expectedFailureIfModuleIsNotAvailable ( 'sch_ets' )
3944 def test_qdisc_ets ( self
):
3945 copy_network_unit ( '25-qdisc-ets.network' , '12-dummy.netdev' )
3947 self
. wait_online ([ 'dummy98:routable' ])
3949 output
= check_output ( 'tc qdisc show dev dummy98' )
3952 self
. assertRegex ( output
, 'qdisc ets 3a: root' )
3953 self
. assertRegex ( output
, 'bands 10 strict 3' )
3954 self
. assertRegex ( output
, 'quanta 1 2 3 4 5' )
3955 self
. assertRegex ( output
, 'priomap 3 4 5 6 7' )
3957 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq' )
3958 def test_qdisc_fq ( self
):
3959 copy_network_unit ( '25-qdisc-fq.network' , '12-dummy.netdev' )
3961 self
. wait_online ([ 'dummy98:routable' ])
3963 output
= check_output ( 'tc qdisc show dev dummy98' )
3965 self
. assertRegex ( output
, 'qdisc fq 32: root' )
3966 self
. assertRegex ( output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511' )
3967 self
. assertRegex ( output
, 'quantum 1500' )
3968 self
. assertRegex ( output
, 'initial_quantum 13000' )
3969 self
. assertRegex ( output
, 'maxrate 1Mbit' )
3971 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_codel' )
3972 def test_qdisc_fq_codel ( self
):
3973 copy_network_unit ( '25-qdisc-fq_codel.network' , '12-dummy.netdev' )
3975 self
. wait_online ([ 'dummy98:routable' ])
3977 output
= check_output ( 'tc qdisc show dev dummy98' )
3979 self
. assertRegex ( output
, 'qdisc fq_codel 34: root' )
3980 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' )
3982 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_pie' )
3983 def test_qdisc_fq_pie ( self
):
3984 copy_network_unit ( '25-qdisc-fq_pie.network' , '12-dummy.netdev' )
3986 self
. wait_online ([ 'dummy98:routable' ])
3988 output
= check_output ( 'tc qdisc show dev dummy98' )
3991 self
. assertRegex ( output
, 'qdisc fq_pie 3a: root' )
3992 self
. assertRegex ( output
, 'limit 200000p' )
3994 @expectedFailureIfModuleIsNotAvailable ( 'sch_gred' )
3995 def test_qdisc_gred ( self
):
3996 copy_network_unit ( '25-qdisc-gred.network' , '12-dummy.netdev' )
3998 self
. wait_online ([ 'dummy98:routable' ])
4000 output
= check_output ( 'tc qdisc show dev dummy98' )
4002 self
. assertRegex ( output
, 'qdisc gred 38: root' )
4003 self
. assertRegex ( output
, 'vqs 12 default 10 grio' )
4005 @expectedFailureIfModuleIsNotAvailable ( 'sch_hhf' )
4006 def test_qdisc_hhf ( self
):
4007 copy_network_unit ( '25-qdisc-hhf.network' , '12-dummy.netdev' )
4009 self
. wait_online ([ 'dummy98:routable' ])
4011 output
= check_output ( 'tc qdisc show dev dummy98' )
4013 self
. assertRegex ( output
, 'qdisc hhf 3a: root' )
4014 self
. assertRegex ( output
, 'limit 1022p' )
4016 @expectedFailureIfModuleIsNotAvailable ( 'sch_htb' )
4017 def test_qdisc_htb_fifo ( self
):
4018 copy_network_unit ( '25-qdisc-htb-fifo.network' , '12-dummy.netdev' )
4020 self
. wait_online ([ 'dummy98:routable' ])
4022 output
= check_output ( 'tc qdisc show dev dummy98' )
4024 self
. assertRegex ( output
, 'qdisc htb 2: root' )
4025 self
. assertRegex ( output
, r
'default (0x30|30)' )
4027 self
. assertRegex ( output
, 'qdisc pfifo 37: parent 2:37' )
4028 self
. assertRegex ( output
, 'limit 100000p' )
4030 self
. assertRegex ( output
, 'qdisc bfifo 3a: parent 2:3a' )
4031 self
. assertRegex ( output
, 'limit 1000000' )
4033 self
. assertRegex ( output
, 'qdisc pfifo_head_drop 3b: parent 2:3b' )
4034 self
. assertRegex ( output
, 'limit 1023p' )
4036 self
. assertRegex ( output
, 'qdisc pfifo_fast 3c: parent 2:3c' )
4038 output
= check_output ( 'tc -d class show dev dummy98' )
4040 # Here (:|prio) is a workaround for a bug in iproute2 v6.2.0 caused by
4041 # https://github.com/shemminger/iproute2/commit/010a8388aea11e767ba3a2506728b9ad9760df0e
4042 # which is fixed in v6.3.0 by
4043 # https://github.com/shemminger/iproute2/commit/4e0e56e0ef05387f7f5d8ab41fe6ec6a1897b26d
4044 self
. assertRegex ( output
, 'class htb 2:37 root leaf 37(:|prio) ' )
4045 self
. assertRegex ( output
, 'class htb 2:3a root leaf 3a(:|prio) ' )
4046 self
. assertRegex ( output
, 'class htb 2:3b root leaf 3b(:|prio) ' )
4047 self
. assertRegex ( output
, 'class htb 2:3c root leaf 3c(:|prio) ' )
4048 self
. assertRegex ( output
, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit' )
4049 self
. assertRegex ( output
, 'burst 123456' )
4050 self
. assertRegex ( output
, 'cburst 123457' )
4052 @expectedFailureIfModuleIsNotAvailable ( 'sch_ingress' )
4053 def test_qdisc_ingress ( self
):
4054 copy_network_unit ( '25-qdisc-clsact.network' , '12-dummy.netdev' ,
4055 '25-qdisc-ingress.network' , '11-dummy.netdev' )
4057 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' ])
4059 output
= check_output ( 'tc qdisc show dev dummy98' )
4061 self
. assertRegex ( output
, 'qdisc clsact' )
4063 output
= check_output ( 'tc qdisc show dev test1' )
4065 self
. assertRegex ( output
, 'qdisc ingress' )
4067 @expectedFailureIfModuleIsNotAvailable ( 'sch_netem' )
4068 def test_qdisc_netem ( self
):
4069 copy_network_unit ( '25-qdisc-netem.network' , '12-dummy.netdev' ,
4070 '25-qdisc-netem-compat.network' , '11-dummy.netdev' )
4072 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' ])
4074 output
= check_output ( 'tc qdisc show dev dummy98' )
4076 self
. assertRegex ( output
, 'qdisc netem 30: root' )
4077 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
4079 output
= check_output ( 'tc qdisc show dev test1' )
4081 self
. assertRegex ( output
, 'qdisc netem [0-9a-f]*: root' )
4082 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
4084 @expectedFailureIfModuleIsNotAvailable ( 'sch_pie' )
4085 def test_qdisc_pie ( self
):
4086 copy_network_unit ( '25-qdisc-pie.network' , '12-dummy.netdev' )
4088 self
. wait_online ([ 'dummy98:routable' ])
4090 output
= check_output ( 'tc qdisc show dev dummy98' )
4092 self
. assertRegex ( output
, 'qdisc pie 3a: root' )
4093 self
. assertRegex ( output
, 'limit 200000' )
4095 @expectedFailureIfModuleIsNotAvailable ( 'sch_qfq' )
4096 def test_qdisc_qfq ( self
):
4097 copy_network_unit ( '25-qdisc-qfq.network' , '12-dummy.netdev' )
4099 self
. wait_online ([ 'dummy98:routable' ])
4101 output
= check_output ( 'tc qdisc show dev dummy98' )
4103 self
. assertRegex ( output
, 'qdisc qfq 2: root' )
4104 output
= check_output ( 'tc class show dev dummy98' )
4106 self
. assertRegex ( output
, 'class qfq 2:30 root weight 2 maxpkt 16000' )
4107 self
. assertRegex ( output
, 'class qfq 2:31 root weight 10 maxpkt 8000' )
4109 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfb' )
4110 def test_qdisc_sfb ( self
):
4111 copy_network_unit ( '25-qdisc-sfb.network' , '12-dummy.netdev' )
4113 self
. wait_online ([ 'dummy98:routable' ])
4115 output
= check_output ( 'tc qdisc show dev dummy98' )
4117 self
. assertRegex ( output
, 'qdisc sfb 39: root' )
4118 self
. assertRegex ( output
, 'limit 200000' )
4120 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfq' )
4121 def test_qdisc_sfq ( self
):
4122 copy_network_unit ( '25-qdisc-sfq.network' , '12-dummy.netdev' )
4124 self
. wait_online ([ 'dummy98:routable' ])
4126 output
= check_output ( 'tc qdisc show dev dummy98' )
4128 self
. assertRegex ( output
, 'qdisc sfq 36: root' )
4129 self
. assertRegex ( output
, 'perturb 5sec' )
4131 @expectedFailureIfModuleIsNotAvailable ( 'sch_tbf' )
4132 def test_qdisc_tbf ( self
):
4133 copy_network_unit ( '25-qdisc-tbf.network' , '12-dummy.netdev' )
4135 self
. wait_online ([ 'dummy98:routable' ])
4137 output
= check_output ( 'tc qdisc show dev dummy98' )
4139 self
. assertRegex ( output
, 'qdisc tbf 35: root' )
4140 self
. assertRegex ( output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms' )
4142 @expectedFailureIfModuleIsNotAvailable ( 'sch_teql' )
4143 def test_qdisc_teql ( self
):
4144 call_quiet ( 'rmmod sch_teql' )
4146 copy_network_unit ( '25-qdisc-teql.network' , '12-dummy.netdev' )
4148 self
. wait_links ( 'dummy98' )
4149 check_output ( 'modprobe sch_teql max_equalizers=2' )
4150 self
. wait_online ([ 'dummy98:routable' ])
4152 output
= check_output ( 'tc qdisc show dev dummy98' )
4154 self
. assertRegex ( output
, 'qdisc teql1 31: root' )
4156 class NetworkdStateFileTests ( unittest
. TestCase
, Utilities
):
4164 def test_state_file ( self
):
4165 copy_network_unit ( '12-dummy.netdev' , '25-state-file-tests.network' )
4167 self
. wait_online ([ 'dummy98:routable' ])
4169 # make link state file updated
4170 check_output (* resolvectl_cmd
, 'revert' , 'dummy98' , env
= env
)
4172 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
4175 output
= read_link_state_file ( 'dummy98' )
4177 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
4178 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
4179 self
. assertIn ( 'ADMIN_STATE=configured' , output
)
4180 self
. assertIn ( 'OPER_STATE=routable' , output
)
4181 self
. assertIn ( 'REQUIRED_FOR_ONLINE=yes' , output
)
4182 self
. assertIn ( 'REQUIRED_OPER_STATE_FOR_ONLINE=routable' , output
)
4183 self
. assertIn ( 'REQUIRED_FAMILY_FOR_ONLINE=both' , output
)
4184 self
. assertIn ( 'ACTIVATION_POLICY=up' , output
)
4185 self
. assertIn ( 'NETWORK_FILE=/run/systemd/network/25-state-file-tests.network' , output
)
4186 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
4187 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
4188 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
4189 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
4190 self
. assertIn ( 'LLMNR=no' , output
)
4191 self
. assertIn ( 'MDNS=yes' , output
)
4192 self
. assertIn ( 'DNSSEC=no' , output
)
4194 check_output (* resolvectl_cmd
, 'dns' , 'dummy98' , '10.10.10.12#ccc.com' , '10.10.10.13' , '1111:2222::3333' , env
= env
)
4195 check_output (* resolvectl_cmd
, 'domain' , 'dummy98' , 'hogehogehoge' , '~foofoofoo' , env
= env
)
4196 check_output (* resolvectl_cmd
, 'llmnr' , 'dummy98' , 'yes' , env
= env
)
4197 check_output (* resolvectl_cmd
, 'mdns' , 'dummy98' , 'no' , env
= env
)
4198 check_output (* resolvectl_cmd
, 'dnssec' , 'dummy98' , 'yes' , env
= env
)
4199 check_output (* timedatectl_cmd
, 'ntp-servers' , 'dummy98' , '2.fedora.pool.ntp.org' , '3.fedora.pool.ntp.org' , env
= env
)
4201 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
4204 output
= read_link_state_file ( 'dummy98' )
4206 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
4207 self
. assertIn ( 'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org' , output
)
4208 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
4209 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
4210 self
. assertIn ( 'LLMNR=yes' , output
)
4211 self
. assertIn ( 'MDNS=no' , output
)
4212 self
. assertIn ( 'DNSSEC=yes' , output
)
4214 check_output (* timedatectl_cmd
, 'revert' , 'dummy98' , env
= env
)
4216 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
4219 output
= read_link_state_file ( 'dummy98' )
4221 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
4222 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
4223 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
4224 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
4225 self
. assertIn ( 'LLMNR=yes' , output
)
4226 self
. assertIn ( 'MDNS=no' , output
)
4227 self
. assertIn ( 'DNSSEC=yes' , output
)
4229 check_output (* resolvectl_cmd
, 'revert' , 'dummy98' , env
= env
)
4231 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
4234 output
= read_link_state_file ( 'dummy98' )
4236 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
4237 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
4238 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
4239 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
4240 self
. assertIn ( 'LLMNR=no' , output
)
4241 self
. assertIn ( 'MDNS=yes' , output
)
4242 self
. assertIn ( 'DNSSEC=no' , output
)
4244 def test_address_state ( self
):
4245 copy_network_unit ( '12-dummy.netdev' , '12-dummy-no-address.network' )
4248 self
. wait_online ([ 'dummy98:degraded' ])
4250 output
= read_link_state_file ( 'dummy98' )
4251 self
. assertIn ( 'IPV4_ADDRESS_STATE=off' , output
)
4252 self
. assertIn ( 'IPV6_ADDRESS_STATE=degraded' , output
)
4254 # with a routable IPv4 address
4255 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
4256 self
. wait_online ([ 'dummy98:routable' ], ipv4
= True )
4257 self
. wait_online ([ 'dummy98:routable' ])
4259 output
= read_link_state_file ( 'dummy98' )
4260 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
4261 self
. assertIn ( 'IPV6_ADDRESS_STATE=degraded' , output
)
4263 check_output ( 'ip address del 10.1.2.3/16 dev dummy98' )
4265 # with a routable IPv6 address
4266 check_output ( 'ip address add 2002:da8:1:0:1034:56ff:fe78:9abc/64 dev dummy98' )
4267 self
. wait_online ([ 'dummy98:routable' ], ipv6
= True )
4268 self
. wait_online ([ 'dummy98:routable' ])
4270 output
= read_link_state_file ( 'dummy98' )
4271 self
. assertIn ( 'IPV4_ADDRESS_STATE=off' , output
)
4272 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
4274 class NetworkdBondTests ( unittest
. TestCase
, Utilities
):
4282 def test_bond_keep_master ( self
):
4283 check_output ( 'ip link add bond199 type bond mode active-backup' )
4284 check_output ( 'ip link add dummy98 type dummy' )
4285 check_output ( 'ip link set dummy98 master bond199' )
4287 copy_network_unit ( '23-keep-master.network' )
4289 self
. wait_online ([ 'dummy98:enslaved' ])
4291 output
= check_output ( 'ip -d link show bond199' )
4293 self
. assertRegex ( output
, 'active_slave dummy98' )
4295 output
= check_output ( 'ip -d link show dummy98' )
4297 self
. assertRegex ( output
, 'master bond199' )
4299 def test_bond_active_slave ( self
):
4300 copy_network_unit ( '23-active-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
4302 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
4304 output
= check_output ( 'ip -d link show bond199' )
4306 self
. assertIn ( 'active_slave dummy98' , output
)
4308 def test_bond_primary_slave ( self
):
4309 copy_network_unit ( '23-primary-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
4311 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
4313 output
= check_output ( 'ip -d link show bond199' )
4315 self
. assertIn ( 'primary dummy98' , output
)
4318 mkdir_p ( os
. path
. join ( network_unit_dir
, '23-bond199.network.d' ))
4319 for mac
in [ '00:11:22:33:44:55' , '00:11:22:33:44:56' ]:
4320 with
open ( os
. path
. join ( network_unit_dir
, '23-bond199.network.d/mac.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
4321 f
. write ( f
'[Link] \n MACAddress= {mac} \n ' )
4324 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
4326 output
= check_output ( 'ip -d link show bond199' )
4328 self
. assertIn ( f
'link/ether {mac} ' , output
)
4330 def test_bond_operstate ( self
):
4331 copy_network_unit ( '25-bond.netdev' , '11-dummy.netdev' , '12-dummy.netdev' ,
4332 '25-bond99.network' , '25-bond-slave.network' )
4334 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bond99:routable' ])
4336 output
= check_output ( 'ip -d link show dummy98' )
4338 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
4340 output
= check_output ( 'ip -d link show test1' )
4342 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
4344 output
= check_output ( 'ip -d link show bond99' )
4346 self
. assertRegex ( output
, 'MASTER,UP,LOWER_UP' )
4348 self
. wait_operstate ( 'dummy98' , 'enslaved' )
4349 self
. wait_operstate ( 'test1' , 'enslaved' )
4350 self
. wait_operstate ( 'bond99' , 'routable' )
4352 check_output ( 'ip link set dummy98 down' )
4354 self
. wait_operstate ( 'dummy98' , 'off' )
4355 self
. wait_operstate ( 'test1' , 'enslaved' )
4356 self
. wait_operstate ( 'bond99' , 'routable' )
4358 check_output ( 'ip link set dummy98 up' )
4360 self
. wait_operstate ( 'dummy98' , 'enslaved' )
4361 self
. wait_operstate ( 'test1' , 'enslaved' )
4362 self
. wait_operstate ( 'bond99' , 'routable' )
4364 check_output ( 'ip link set dummy98 down' )
4365 check_output ( 'ip link set test1 down' )
4367 self
. wait_operstate ( 'dummy98' , 'off' )
4368 self
. wait_operstate ( 'test1' , 'off' )
4370 if not self
. wait_operstate ( 'bond99' , 'no-carrier' , setup_timeout
= 30 , fail_assert
= False ):
4371 # Huh? Kernel does not recognize that all slave interfaces are down?
4372 # Let's confirm that networkd's operstate is consistent with ip's result.
4373 self
. assertNotRegex ( output
, 'NO-CARRIER' )
4375 class NetworkdBridgeTests ( unittest
. TestCase
, Utilities
):
4383 def test_bridge_vlan ( self
):
4384 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave.network' ,
4385 '26-bridge.netdev' , '26-bridge-vlan-master.network' )
4387 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' ])
4389 output
= check_output ( 'bridge vlan show dev test1' )
4391 self
. assertNotRegex ( output
, '4063' )
4392 for i
in range ( 4064 , 4095 ):
4393 self
. assertRegex ( output
, f
' {i} ' )
4394 self
. assertNotRegex ( output
, '4095' )
4396 output
= check_output ( 'bridge vlan show dev bridge99' )
4398 self
. assertNotRegex ( output
, '4059' )
4399 for i
in range ( 4060 , 4095 ):
4400 self
. assertRegex ( output
, f
' {i} ' )
4401 self
. assertNotRegex ( output
, '4095' )
4403 def test_bridge_vlan_issue_20373 ( self
):
4404 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave-issue-20373.network' ,
4405 '26-bridge-issue-20373.netdev' , '26-bridge-vlan-master-issue-20373.network' ,
4406 '21-vlan.netdev' , '21-vlan.network' )
4408 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' , 'vlan99:routable' ])
4410 output
= check_output ( 'bridge vlan show dev test1' )
4412 self
. assertIn ( '100 PVID Egress Untagged' , output
)
4413 self
. assertIn ( '560' , output
)
4414 self
. assertIn ( '600' , output
)
4416 output
= check_output ( 'bridge vlan show dev bridge99' )
4418 self
. assertIn ( '1 PVID Egress Untagged' , output
)
4419 self
. assertIn ( '100' , output
)
4420 self
. assertIn ( '600' , output
)
4422 def test_bridge_mdb ( self
):
4423 copy_network_unit ( '11-dummy.netdev' , '26-bridge-mdb-slave.network' ,
4424 '26-bridge.netdev' , '26-bridge-mdb-master.network' )
4426 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' ])
4428 output
= check_output ( 'bridge mdb show dev bridge99' )
4430 self
. assertRegex ( output
, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064' )
4431 self
. assertRegex ( output
, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065' )
4433 # Old kernel may not support bridge MDB entries on bridge master
4434 if call_quiet ( 'bridge mdb add dev bridge99 port bridge99 grp 224.0.1.3 temp vid 4068' ) == 0 :
4435 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp ff02:aaaa:fee5::1:4 temp *vid 4066' )
4436 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp 224.0.1.2 temp *vid 4067' )
4438 def test_bridge_keep_master ( self
):
4439 check_output ( 'ip link add bridge99 type bridge' )
4440 check_output ( 'ip link set bridge99 up' )
4441 check_output ( 'ip link add dummy98 type dummy' )
4442 check_output ( 'ip link set dummy98 master bridge99' )
4444 copy_network_unit ( '23-keep-master.network' )
4446 self
. wait_online ([ 'dummy98:enslaved' ])
4448 output
= check_output ( 'ip -d link show dummy98' )
4450 self
. assertRegex ( output
, 'master bridge99' )
4451 self
. assertRegex ( output
, 'bridge' )
4453 output
= check_output ( 'bridge -d link show dummy98' )
4455 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
4456 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
4457 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
4458 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
4459 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
4460 # CONFIG_BRIDGE_IGMP_SNOOPING=y
4461 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
4462 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
4463 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
4464 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
4465 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
4466 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
4468 def test_bridge_property ( self
):
4469 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
4470 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
4471 '25-bridge99.network' )
4473 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' ])
4475 output
= check_output ( 'ip -d link show bridge99' )
4477 self
. assertIn ( 'mtu 9000 ' , output
)
4479 output
= check_output ( 'ip -d link show test1' )
4481 self
. assertIn ( 'master bridge99 ' , output
)
4482 self
. assertIn ( 'bridge_slave' , output
)
4483 self
. assertIn ( 'mtu 9000 ' , output
)
4485 output
= check_output ( 'ip -d link show dummy98' )
4487 self
. assertIn ( 'master bridge99 ' , output
)
4488 self
. assertIn ( 'bridge_slave' , output
)
4489 self
. assertIn ( 'mtu 9000 ' , output
)
4491 output
= check_output ( 'ip addr show bridge99' )
4493 self
. assertIn ( '192.168.0.15/24' , output
)
4495 output
= check_output ( 'bridge -d link show dummy98' )
4497 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
4498 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
4499 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'isolated' , '1' )
4500 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
4501 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
4502 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
4503 # CONFIG_BRIDGE_IGMP_SNOOPING=y
4504 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
4505 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
4506 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
4507 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
4508 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
4509 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
4511 output
= check_output ( 'bridge -d link show test1' )
4513 self
. check_bridge_port_attr ( 'bridge99' , 'test1' , 'priority' , '0' )
4515 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
4516 output
= check_output ( 'ip addr show bridge99' )
4518 self
. assertIn ( '192.168.0.16/24' , output
)
4521 print ( '### ip -6 route list table all dev bridge99' )
4522 output
= check_output ( 'ip -6 route list table all dev bridge99' )
4524 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
4526 remove_link ( 'test1' )
4527 self
. wait_operstate ( 'bridge99' , 'routable' )
4529 output
= check_output ( 'ip -d link show bridge99' )
4531 self
. assertIn ( 'mtu 9000 ' , output
)
4533 output
= check_output ( 'ip -d link show dummy98' )
4535 self
. assertIn ( 'master bridge99 ' , output
)
4536 self
. assertIn ( 'bridge_slave' , output
)
4537 self
. assertIn ( 'mtu 9000 ' , output
)
4539 remove_link ( 'dummy98' )
4540 self
. wait_operstate ( 'bridge99' , 'no-carrier' )
4542 output
= check_output ( 'ip -d link show bridge99' )
4544 # When no carrier, the kernel may reset the MTU
4545 self
. assertIn ( 'NO-CARRIER' , output
)
4547 output
= check_output ( 'ip address show bridge99' )
4549 self
. assertNotIn ( '192.168.0.15/24' , output
)
4550 self
. assertIn ( '192.168.0.16/24' , output
) # foreign address is kept
4552 print ( '### ip -6 route list table all dev bridge99' )
4553 output
= check_output ( 'ip -6 route list table all dev bridge99' )
4555 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
4557 check_output ( 'ip link add dummy98 type dummy' )
4558 self
. wait_online ([ 'dummy98:enslaved' , 'bridge99:routable' ])
4560 output
= check_output ( 'ip -d link show bridge99' )
4562 self
. assertIn ( 'mtu 9000 ' , output
)
4564 output
= check_output ( 'ip -d link show dummy98' )
4566 self
. assertIn ( 'master bridge99 ' , output
)
4567 self
. assertIn ( 'bridge_slave' , output
)
4568 self
. assertIn ( 'mtu 9000 ' , output
)
4570 def test_bridge_configure_without_carrier ( self
):
4571 copy_network_unit ( '26-bridge.netdev' , '26-bridge-configure-without-carrier.network' ,
4575 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
4576 for test
in [ 'no-slave' , 'add-slave' , 'slave-up' , 'slave-no-carrier' , 'slave-carrier' , 'slave-down' ]:
4577 with self
. subTest ( test
= test
):
4578 if test
== 'no-slave' :
4579 # bridge has no slaves; it's up but *might* not have carrier
4580 self
. wait_operstate ( 'bridge99' , operstate
= r
'(no-carrier|routable)' , setup_state
= None , setup_timeout
= 30 )
4581 # due to a bug in the kernel, newly-created bridges are brought up
4582 # *with* carrier, unless they have had any setting changed; e.g.
4583 # their mac set, priority set, etc. Then, they will lose carrier
4584 # as soon as a (down) slave interface is added, and regain carrier
4585 # again once the slave interface is brought up.
4586 #self.check_link_attr('bridge99', 'carrier', '0')
4587 elif test
== 'add-slave' :
4588 # add slave to bridge, but leave it down; bridge is definitely no-carrier
4589 self
. check_link_attr ( 'test1' , 'operstate' , 'down' )
4590 check_output ( 'ip link set dev test1 master bridge99' )
4591 self
. wait_operstate ( 'bridge99' , operstate
= 'no-carrier' , setup_state
= None )
4592 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4593 elif test
== 'slave-up' :
4594 # bring up slave, which will have carrier; bridge gains carrier
4595 check_output ( 'ip link set dev test1 up' )
4596 self
. wait_online ([ 'bridge99:routable' ])
4597 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
4598 elif test
== 'slave-no-carrier' :
4599 # drop slave carrier; bridge loses carrier
4600 check_output ( 'ip link set dev test1 carrier off' )
4601 self
. wait_online ([ 'bridge99:no-carrier:no-carrier' ])
4602 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4603 elif test
== 'slave-carrier' :
4604 # restore slave carrier; bridge gains carrier
4605 check_output ( 'ip link set dev test1 carrier on' )
4606 self
. wait_online ([ 'bridge99:routable' ])
4607 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
4608 elif test
== 'slave-down' :
4609 # bring down slave; bridge loses carrier
4610 check_output ( 'ip link set dev test1 down' )
4611 self
. wait_online ([ 'bridge99:no-carrier:no-carrier' ])
4612 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4614 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bridge99' , env
= env
)
4615 self
. assertRegex ( output
, '10.1.2.3' )
4616 self
. assertRegex ( output
, '10.1.2.1' )
4618 def test_bridge_ignore_carrier_loss ( self
):
4619 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
4620 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
4621 '25-bridge99-ignore-carrier-loss.network' )
4623 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' ])
4625 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
4626 remove_link ( 'test1' , 'dummy98' )
4629 output
= check_output ( 'ip address show bridge99' )
4631 self
. assertRegex ( output
, 'NO-CARRIER' )
4632 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
4633 self
. assertRegex ( output
, 'inet 192.168.0.16/24 scope global secondary bridge99' )
4635 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain ( self
):
4636 copy_network_unit ( '26-bridge.netdev' , '26-bridge-slave-interface-1.network' ,
4637 '25-bridge99-ignore-carrier-loss.network' )
4639 self
. wait_online ([ 'bridge99:no-carrier' ])
4641 for trial
in range ( 4 ):
4642 check_output ( 'ip link add dummy98 type dummy' )
4643 check_output ( 'ip link set dummy98 up' )
4645 remove_link ( 'dummy98' )
4647 self
. wait_online ([ 'bridge99:routable' , 'dummy98:enslaved' ])
4649 output
= check_output ( 'ip address show bridge99' )
4651 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
4653 output
= check_output ( 'ip rule list table 100' )
4655 self
. assertIn ( 'from all to 8.8.8.8 lookup 100' , output
)
4657 class NetworkdSRIOVTests ( unittest
. TestCase
, Utilities
):
4665 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
4666 def test_sriov ( self
):
4667 copy_network_unit ( '25-default.link' , '25-sriov.network' )
4669 call ( 'modprobe netdevsim' )
4671 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4674 with
open ( '/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4678 self
. wait_online ([ 'eni99np1:routable' ])
4680 output
= check_output ( 'ip link show dev eni99np1' )
4682 self
. assertRegex ( output
,
4683 '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 *'
4684 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4685 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4688 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
4689 def test_sriov_udev ( self
):
4690 copy_network_unit ( '25-sriov.link' , '25-sriov-udev.network' )
4692 call ( 'modprobe netdevsim' )
4694 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4698 self
. wait_online ([ 'eni99np1:routable' ])
4700 # the name eni99np1 may be an alternative name.
4701 ifname
= link_resolve ( 'eni99np1' )
4703 output
= check_output ( 'ip link show dev eni99np1' )
4705 self
. assertRegex ( output
,
4706 '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 *'
4707 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4708 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4710 self
. assertNotIn ( 'vf 3' , output
)
4711 self
. assertNotIn ( 'vf 4' , output
)
4713 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4714 f
. write ( '[Link] \n SR-IOVVirtualFunctions=4 \n ' )
4717 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4719 output
= check_output ( 'ip link show dev eni99np1' )
4721 self
. assertRegex ( output
,
4722 '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 *'
4723 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4724 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
4727 self
. assertNotIn ( 'vf 4' , output
)
4729 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4730 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
4733 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4735 output
= check_output ( 'ip link show dev eni99np1' )
4737 self
. assertRegex ( output
,
4738 '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 *'
4739 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4740 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
4743 self
. assertNotIn ( 'vf 4' , output
)
4745 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4746 f
. write ( '[Link] \n SR-IOVVirtualFunctions=2 \n ' )
4749 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4751 output
= check_output ( 'ip link show dev eni99np1' )
4753 self
. assertRegex ( output
,
4754 '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 *'
4755 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off'
4757 self
. assertNotIn ( 'vf 2' , output
)
4758 self
. assertNotIn ( 'vf 3' , output
)
4759 self
. assertNotIn ( 'vf 4' , output
)
4761 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4762 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
4765 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4767 output
= check_output ( 'ip link show dev eni99np1' )
4769 self
. assertRegex ( output
,
4770 '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 *'
4771 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4772 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4774 self
. assertNotIn ( 'vf 3' , output
)
4775 self
. assertNotIn ( 'vf 4' , output
)
4777 class NetworkdLLDPTests ( unittest
. TestCase
, Utilities
):
4785 def test_lldp ( self
):
4786 copy_network_unit ( '23-emit-lldp.network' , '24-lldp.network' , '25-veth.netdev' )
4788 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:degraded' ])
4790 for trial
in range ( 10 ):
4794 output
= check_output (* networkctl_cmd
, 'lldp' , env
= env
)
4796 if re
. search ( r
'veth99 .* veth-peer' , output
):
4801 class NetworkdRATests ( unittest
. TestCase
, Utilities
):
4809 def test_ipv6_prefix_delegation ( self
):
4810 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth.network' )
4811 self
. setup_nftset ( 'addr6' , 'ipv6_addr' )
4812 self
. setup_nftset ( 'network6' , 'ipv6_addr' , 'flags interval;' )
4813 self
. setup_nftset ( 'ifindex' , 'iface_index' )
4815 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4817 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth99' , env
= env
)
4819 self
. assertRegex ( output
, 'fe80::' )
4820 self
. assertRegex ( output
, '2002:da8:1::1' )
4822 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth99' , env
= env
)
4824 self
. assertIn ( 'hogehoge.test' , output
)
4826 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4828 self
. assertRegex ( output
, '2002:da8:1:0' )
4830 self
. check_netlabel ( 'veth99' , '2002:da8:1::/64' )
4831 self
. check_netlabel ( 'veth99' , '2002:da8:2::/64' )
4833 self
. check_nftset ( 'addr6' , '2002:da8:1:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*' )
4834 self
. check_nftset ( 'addr6' , '2002:da8:2:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*' )
4835 self
. check_nftset ( 'network6' , '2002:da8:1::/64' )
4836 self
. check_nftset ( 'network6' , '2002:da8:2::/64' )
4837 self
. check_nftset ( 'ifindex' , 'veth99' )
4839 self
. teardown_nftset ( 'addr6' , 'network6' , 'ifindex' )
4841 def test_ipv6_token_static ( self
):
4842 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-static.network' )
4844 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4846 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4848 self
. assertRegex ( output
, '2002:da8:1:0:1a:2b:3c:4d' )
4849 self
. assertRegex ( output
, '2002:da8:1:0:fa:de:ca:fe' )
4850 self
. assertRegex ( output
, '2002:da8:2:0:1a:2b:3c:4d' )
4851 self
. assertRegex ( output
, '2002:da8:2:0:fa:de:ca:fe' )
4853 def test_ipv6_token_prefixstable ( self
):
4854 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable.network' )
4856 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4858 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4860 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
4861 self
. assertIn ( '2002:da8:2:0:1034:56ff:fe78:9abc' , output
) # EUI64
4863 def test_ipv6_token_prefixstable_without_address ( self
):
4864 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable-without-address.network' )
4866 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4868 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4870 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
4871 self
. assertIn ( '2002:da8:2:0:f689:561a:8eda:7443' , output
)
4873 def test_router_preference ( self
):
4874 copy_network_unit ( '25-veth-client.netdev' ,
4875 '25-veth-router-high.netdev' ,
4876 '25-veth-router-low.netdev' ,
4878 '25-veth-bridge.network' ,
4879 '25-veth-client.network' ,
4880 '25-veth-router-high.network' ,
4881 '25-veth-router-low.network' ,
4882 '25-bridge99.network' )
4884 self
. wait_online ([ 'client-p:enslaved' ,
4885 'router-high:degraded' , 'router-high-p:enslaved' ,
4886 'router-low:degraded' , 'router-low-p:enslaved' ,
4887 'bridge99:routable' ])
4889 networkctl_reconfigure ( 'client' )
4890 self
. wait_online ([ 'client:routable' ])
4892 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4893 self
. wait_address ( 'client' , '2002:da8:1:98:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4894 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 512' , ipv
= '-6' , timeout_sec
= 10 )
4895 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 2048' , ipv
= '-6' , timeout_sec
= 10 )
4897 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
4899 self
. assertIn ( 'pref high' , output
)
4900 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
4902 self
. assertIn ( 'pref low' , output
)
4904 with
open ( os
. path
. join ( network_unit_dir
, '25-veth-client.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4905 f
. write ( ' \n [Link] \n MACAddress=12:34:56:78:9a:01 \n [IPv6AcceptRA] \n RouteMetric=100:200:300 \n ' )
4908 self
. wait_online ([ 'client:routable' ])
4910 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a01/64' , ipv
= '-6' , timeout_sec
= 10 )
4911 self
. wait_address ( 'client' , '2002:da8:1:98:1034:56ff:fe78:9a01/64' , ipv
= '-6' , timeout_sec
= 10 )
4912 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 100' , ipv
= '-6' , timeout_sec
= 10 )
4913 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 300' , ipv
= '-6' , timeout_sec
= 10 )
4915 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
4917 self
. assertIn ( 'pref high' , output
)
4918 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
4920 self
. assertIn ( 'pref low' , output
)
4922 @unittest . skipUnless ( radvd_check_config ( 'captive-portal.conf' ), "Installed radvd doesn't support captive portals" )
4923 def test_captive_portal ( self
):
4924 copy_network_unit ( '25-veth-client.netdev' ,
4925 '25-veth-router-captive.netdev' ,
4927 '25-veth-client-captive.network' ,
4928 '25-veth-router-captive.network' ,
4929 '25-veth-bridge-captive.network' ,
4930 '25-bridge99.network' )
4932 self
. wait_online ([ 'bridge99:routable' , 'client-p:enslaved' ,
4933 'router-captive:degraded' , 'router-captivep:enslaved' ])
4935 start_radvd ( config_file
= 'captive-portal.conf' )
4936 networkctl_reconfigure ( 'client' )
4937 self
. wait_online ([ 'client:routable' ])
4939 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4940 output
= check_output (* networkctl_cmd
, 'status' , 'client' , env
= env
)
4942 self
. assertIn ( 'Captive Portal: http://systemd.io' , output
)
4944 @unittest . skipUnless ( radvd_check_config ( 'captive-portal.conf' ), "Installed radvd doesn't support captive portals" )
4945 def test_invalid_captive_portal ( self
):
4946 def radvd_write_config ( captive_portal_uri
):
4947 with
open ( os
. path
. join ( networkd_ci_temp_dir
, 'radvd/bogus-captive-portal.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
4948 f
. write ( f
'interface router-captive {{ AdvSendAdvert on; AdvCaptivePortalAPI " {captive_portal_uri} "; prefix 2002:da8:1:99::/64 {{ AdvOnLink on; AdvAutonomous on; }}; }};' )
4950 captive_portal_uris
= [
4951 "42ěščěškd ěšč ě s" ,
4956 copy_network_unit ( '25-veth-client.netdev' ,
4957 '25-veth-router-captive.netdev' ,
4959 '25-veth-client-captive.network' ,
4960 '25-veth-router-captive.network' ,
4961 '25-veth-bridge-captive.network' ,
4962 '25-bridge99.network' )
4964 self
. wait_online ([ 'bridge99:routable' , 'client-p:enslaved' ,
4965 'router-captive:degraded' , 'router-captivep:enslaved' ])
4967 for uri
in captive_portal_uris
:
4968 print ( f
"Captive portal: {uri} " )
4969 radvd_write_config ( uri
)
4971 start_radvd ( config_file
= 'bogus-captive-portal.conf' )
4972 networkctl_reconfigure ( 'client' )
4973 self
. wait_online ([ 'client:routable' ])
4975 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4976 output
= check_output (* networkctl_cmd
, 'status' , 'client' , env
= env
)
4978 self
. assertNotIn ( 'Captive Portal:' , output
)
4980 class NetworkdDHCPServerTests ( unittest
. TestCase
, Utilities
):
4988 def test_dhcp_server ( self
):
4989 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server.network' )
4991 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4993 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4995 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4996 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
4997 self
. assertRegex ( output
, 'DNS: 192.168.5.1 \n *192.168.5.10' )
4998 self
. assertRegex ( output
, 'NTP: 192.168.5.1 \n *192.168.5.11' )
5000 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth-peer' , env
= env
)
5001 self
. assertRegex ( output
, "Offered DHCP leases: 192.168.5.[0-9]*" )
5003 def test_dhcp_server_null_server_address ( self
):
5004 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-null-server-address.network' )
5006 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5008 output
= check_output ( 'ip --json address show dev veth-peer' )
5009 server_address
= json
. loads ( output
)[ 0 ][ 'addr_info' ][ 0 ][ 'local' ]
5010 print ( server_address
)
5012 output
= check_output ( 'ip --json address show dev veth99' )
5013 client_address
= json
. loads ( output
)[ 0 ][ 'addr_info' ][ 0 ][ 'local' ]
5014 print ( client_address
)
5016 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
5018 self
. assertRegex ( output
, rf
'Address: {client_address} \(DHCP4 via {server_address} \)' )
5019 self
. assertIn ( f
'Gateway: {server_address} ' , output
)
5020 self
. assertIn ( f
'DNS: {server_address} ' , output
)
5021 self
. assertIn ( f
'NTP: {server_address} ' , output
)
5023 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth-peer' , env
= env
)
5024 self
. assertIn ( f
'Offered DHCP leases: {client_address} ' , output
)
5026 def test_dhcp_server_with_uplink ( self
):
5027 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-downstream.network' ,
5028 '12-dummy.netdev' , '25-dhcp-server-uplink.network' )
5030 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5032 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
5034 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
5035 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
5036 self
. assertIn ( 'DNS: 192.168.5.1' , output
)
5037 self
. assertIn ( 'NTP: 192.168.5.1' , output
)
5039 def test_emit_router_timezone ( self
):
5040 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-timezone-router.network' , '25-dhcp-server-timezone-router.network' )
5042 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5044 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
5046 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
5047 self
. assertIn ( 'Gateway: 192.168.5.1' , output
)
5048 self
. assertIn ( 'Time Zone: Europe/Berlin' , output
)
5050 def test_dhcp_server_static_lease ( self
):
5051 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-static-lease.network' , '25-dhcp-server-static-lease.network' )
5053 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5055 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
5057 self
. assertIn ( 'Address: 10.1.1.200 (DHCP4 via 10.1.1.1)' , output
)
5058 self
. assertIn ( 'DHCP4 Client ID: 12:34:56:78:9a:bc' , output
)
5060 def test_dhcp_server_static_lease_default_client_id ( self
):
5061 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-static-lease.network' )
5063 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5065 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
5067 self
. assertIn ( 'Address: 10.1.1.200 (DHCP4 via 10.1.1.1)' , output
)
5068 self
. assertRegex ( output
, 'DHCP4 Client ID: IAID:[0-9a-z]*/DUID' )
5070 class NetworkdDHCPServerRelayAgentTests ( unittest
. TestCase
, Utilities
):
5078 def test_relay_agent ( self
):
5079 copy_network_unit ( '25-agent-veth-client.netdev' ,
5080 '25-agent-veth-server.netdev' ,
5081 '25-agent-client.network' ,
5082 '25-agent-server.network' ,
5083 '25-agent-client-peer.network' ,
5084 '25-agent-server-peer.network' )
5087 self
. wait_online ([ 'client:routable' ])
5089 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'client' , env
= env
)
5091 self
. assertRegex ( output
, r
'Address: 192.168.5.150 \(DHCP4 via 192.168.5.1\)' )
5093 class NetworkdDHCPClientTests ( unittest
. TestCase
, Utilities
):
5101 def test_dhcp_client_ipv6_only ( self
):
5102 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv6-only.network' )
5105 self
. wait_online ([ 'veth-peer:carrier' ])
5106 start_dnsmasq ( '--dhcp-option=option6:dns-server,[2600::ee]' ,
5107 '--dhcp-option=option6:ntp-server,[2600::ff]' )
5108 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5111 output
= check_output ( 'ip address show dev veth99 scope global' )
5113 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
5114 self
. assertNotIn ( '192.168.5' , output
)
5116 # checking semi-static route
5117 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
5119 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
5121 # Confirm that ipv6 token is not set in the kernel
5122 output
= check_output ( 'ip token show dev veth99' )
5124 self
. assertRegex ( output
, 'token :: dev veth99' )
5126 # Check link state file
5127 print ( '## link state file' )
5128 output
= read_link_state_file ( 'veth99' )
5130 self
. assertIn ( 'DNS=2600::ee' , output
)
5131 self
. assertIn ( 'NTP=2600::ff' , output
)
5133 # Check manager state file
5134 print ( '## manager state file' )
5135 output
= read_manager_state_file ()
5137 self
. assertRegex ( output
, 'DNS=.*2600::ee' )
5138 self
. assertRegex ( output
, 'NTP=.*2600::ff' )
5140 print ( '## dnsmasq log' )
5141 output
= read_dnsmasq_log_file ()
5143 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
5144 self
. assertNotIn ( 'DHCPADVERTISE(veth-peer)' , output
)
5145 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
5146 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
5147 self
. assertIn ( 'sent size: 0 option: 14 rapid-commit' , output
)
5149 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-ipv6-only.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5150 f
. write ( ' \n [DHCPv6] \n RapidCommit=no \n ' )
5153 start_dnsmasq ( '--dhcp-option=option6:dns-server,[2600::ee]' ,
5154 '--dhcp-option=option6:ntp-server,[2600::ff]' )
5157 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5160 output
= check_output ( 'ip address show dev veth99 scope global' )
5162 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
5163 self
. assertNotIn ( '192.168.5' , output
)
5165 # checking semi-static route
5166 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
5168 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
5170 # Check link state file
5171 print ( '## link state file' )
5172 output
= read_link_state_file ( 'veth99' )
5174 self
. assertIn ( 'DNS=2600::ee' , output
)
5175 self
. assertIn ( 'NTP=2600::ff' , output
)
5177 # Check manager state file
5178 print ( '## manager state file' )
5179 output
= read_manager_state_file ()
5181 self
. assertRegex ( output
, 'DNS=.*2600::ee' )
5182 self
. assertRegex ( output
, 'NTP=.*2600::ff' )
5184 print ( '## dnsmasq log' )
5185 output
= read_dnsmasq_log_file ()
5187 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
5188 self
. assertIn ( 'DHCPADVERTISE(veth-peer)' , output
)
5189 self
. assertIn ( 'DHCPREQUEST(veth-peer)' , output
)
5190 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
5191 self
. assertNotIn ( 'rapid-commit' , output
)
5193 def test_dhcp_client_ipv6_dbus_status ( self
):
5194 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv6-only.network' )
5196 self
. wait_online ([ 'veth-peer:carrier' ])
5198 # Note that at this point the DHCPv6 client has not been started because no RA (with managed
5199 # bit set) has yet been received and the configuration does not include WithoutRA=true
5200 state
= get_dhcp6_client_state ( 'veth99' )
5201 print ( f
"State = {state} " )
5202 self
. assertEqual ( state
, 'stopped' )
5205 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5207 state
= get_dhcp6_client_state ( 'veth99' )
5208 print ( f
"State = {state} " )
5209 self
. assertEqual ( state
, 'bound' )
5211 def test_dhcp_client_ipv6_only_with_custom_client_identifier ( self
):
5212 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv6-only-custom-client-identifier.network' )
5215 self
. wait_online ([ 'veth-peer:carrier' ])
5217 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5220 output
= check_output ( 'ip address show dev veth99 scope global' )
5222 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
5223 self
. assertNotIn ( '192.168.5' , output
)
5225 print ( '## dnsmasq log' )
5226 output
= read_dnsmasq_log_file ()
5228 self
. assertIn ( 'DHCPSOLICIT(veth-peer) 00:42:00:00:ab:11:f9:2a:c2:77:29:f9:5c:00' , output
)
5229 self
. assertNotIn ( 'DHCPADVERTISE(veth-peer)' , output
)
5230 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
5231 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
5232 self
. assertIn ( 'sent size: 0 option: 14 rapid-commit' , output
)
5236 def test_dhcp_client_ipv4_only ( self
):
5237 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv4-only.network' )
5239 self
. setup_nftset ( 'addr4' , 'ipv4_addr' )
5240 self
. setup_nftset ( 'network4' , 'ipv4_addr' , 'flags interval;' )
5241 self
. setup_nftset ( 'ifindex' , 'iface_index' )
5244 self
. wait_online ([ 'veth-peer:carrier' ])
5245 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7' ,
5246 '--dhcp-option=option:sip-server,192.168.5.21,192.168.5.22' ,
5247 '--dhcp-option=option:domain-search,example.com' ,
5248 '--dhcp-alternate-port=67,5555' ,
5249 ipv4_range
= '192.168.5.110,192.168.5.119' )
5250 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5251 self
. wait_address ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' )
5253 print ( '## ip address show dev veth99 scope global' )
5254 output
= check_output ( 'ip address show dev veth99 scope global' )
5256 self
. assertIn ( 'mtu 1492' , output
)
5257 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
5258 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' )
5259 self
. assertNotIn ( '2600::' , output
)
5261 output
= check_output ( 'ip -4 --json address show dev veth99' )
5262 for i
in json
. loads ( output
)[ 0 ][ 'addr_info' ]:
5263 if i
[ 'label' ] == 'test-label' :
5264 address1
= i
[ 'local' ]
5267 self
. assertFalse ( True )
5269 self
. assertRegex ( address1
, r
'^192.168.5.11[0-9]$' )
5271 print ( '## ip route show table main dev veth99' )
5272 output
= check_output ( 'ip route show table main dev veth99' )
5274 # no DHCP routes assigned to the main table
5275 self
. assertNotIn ( 'proto dhcp' , output
)
5277 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
5278 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
5279 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
5280 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
5282 print ( '## ip route show table 211 dev veth99' )
5283 output
= check_output ( 'ip route show table 211 dev veth99' )
5285 self
. assertRegex ( output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 24' )
5286 self
. assertRegex ( output
, f
'192.168.5.0/24 proto dhcp scope link src {address1} metric 24' )
5287 self
. assertRegex ( output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 24' )
5288 self
. assertRegex ( output
, f
'192.168.5.6 proto dhcp scope link src {address1} metric 24' )
5289 self
. assertRegex ( output
, f
'192.168.5.7 proto dhcp scope link src {address1} metric 24' )
5290 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
5292 print ( '## link state file' )
5293 output
= read_link_state_file ( 'veth99' )
5295 # checking DNS server, SIP server, and Domains
5296 self
. assertIn ( 'DNS=192.168.5.6 192.168.5.7' , output
)
5297 self
. assertIn ( 'SIP=192.168.5.21 192.168.5.22' , output
)
5298 self
. assertIn ( 'DOMAINS=example.com' , output
)
5301 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , 'veth99' , env
= env
)
5302 j
= json
. loads ( output
)
5304 self
. assertEqual ( len ( j
[ 'DNS' ]), 2 )
5307 self
. assertEqual ( i
[ 'Family' ], 2 )
5308 a
= socket
. inet_ntop ( socket
. AF_INET
, bytearray ( i
[ 'Address' ]))
5309 self
. assertRegex ( a
, '^192.168.5.[67]$' )
5310 self
. assertEqual ( i
[ 'ConfigSource' ], 'DHCPv4' )
5311 a
= socket
. inet_ntop ( socket
. AF_INET
, bytearray ( i
[ 'ConfigProvider' ]))
5312 self
. assertEqual ( '192.168.5.1' , a
)
5314 self
. assertEqual ( len ( j
[ 'SIP' ]), 2 )
5317 self
. assertEqual ( i
[ 'Family' ], 2 )
5318 a
= socket
. inet_ntop ( socket
. AF_INET
, bytearray ( i
[ 'Address' ]))
5319 self
. assertRegex ( a
, '^192.168.5.2[12]$' )
5320 self
. assertEqual ( i
[ 'ConfigSource' ], 'DHCPv4' )
5321 a
= socket
. inet_ntop ( socket
. AF_INET
, bytearray ( i
[ 'ConfigProvider' ]))
5322 self
. assertEqual ( '192.168.5.1' , a
)
5324 print ( '## dnsmasq log' )
5325 output
= read_dnsmasq_log_file ()
5327 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
5328 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 192.168.5.110 12:34:56:78:9a:bc' , output
)
5329 self
. assertIn ( 'client provides name: test-hostname' , output
)
5330 self
. assertIn ( '26:mtu' , output
)
5332 # change address range, DNS servers, and Domains
5334 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8' ,
5335 '--dhcp-option=option:sip-server,192.168.5.23,192.168.5.24' ,
5336 '--dhcp-option=option:domain-search,foo.example.com' ,
5337 '--dhcp-alternate-port=67,5555' ,
5338 ipv4_range
= '192.168.5.120,192.168.5.129' ,)
5340 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
5341 print ( 'Wait for the DHCP lease to be expired' )
5342 self
. wait_address_dropped ( 'veth99' , f
'inet {address1} /24' , ipv
= '-4' , timeout_sec
= 120 )
5343 self
. wait_address ( 'veth99' , r
'inet 192.168.5.12[0-9]*/24' , ipv
= '-4' )
5345 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5347 print ( '## ip address show dev veth99 scope global' )
5348 output
= check_output ( 'ip address show dev veth99 scope global' )
5350 self
. assertIn ( 'mtu 1492' , output
)
5351 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
5352 self
. assertNotIn ( f
' {address1} ' , output
)
5353 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' )
5354 self
. assertNotIn ( '2600::' , output
)
5356 output
= check_output ( 'ip -4 --json address show dev veth99' )
5357 for i
in json
. loads ( output
)[ 0 ][ 'addr_info' ]:
5358 if i
[ 'label' ] == 'test-label' :
5359 address2
= i
[ 'local' ]
5362 self
. assertFalse ( True )
5364 self
. assertRegex ( address2
, r
'^192.168.5.12[0-9]$' )
5366 print ( '## ip route show table main dev veth99' )
5367 output
= check_output ( 'ip route show table main dev veth99' )
5369 # no DHCP routes assigned to the main table
5370 self
. assertNotIn ( 'proto dhcp' , output
)
5372 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
5373 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
5374 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
5375 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
5377 print ( '## ip route show table 211 dev veth99' )
5378 output
= check_output ( 'ip route show table 211 dev veth99' )
5380 self
. assertRegex ( output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 24' )
5381 self
. assertRegex ( output
, f
'192.168.5.0/24 proto dhcp scope link src {address2} metric 24' )
5382 self
. assertRegex ( output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 24' )
5383 self
. assertNotIn ( '192.168.5.6' , output
)
5384 self
. assertRegex ( output
, f
'192.168.5.7 proto dhcp scope link src {address2} metric 24' )
5385 self
. assertRegex ( output
, f
'192.168.5.8 proto dhcp scope link src {address2} metric 24' )
5386 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
5388 print ( '## link state file' )
5389 output
= read_link_state_file ( 'veth99' )
5391 # checking DNS server, SIP server, and Domains
5392 self
. assertIn ( 'DNS=192.168.5.1 192.168.5.7 192.168.5.8' , output
)
5393 self
. assertIn ( 'SIP=192.168.5.23 192.168.5.24' , output
)
5394 self
. assertIn ( 'DOMAINS=foo.example.com' , output
)
5397 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , 'veth99' , env
= env
)
5398 j
= json
. loads ( output
)
5400 self
. assertEqual ( len ( j
[ 'DNS' ]), 3 )
5403 self
. assertEqual ( i
[ 'Family' ], 2 )
5404 a
= socket
. inet_ntop ( socket
. AF_INET
, bytearray ( i
[ 'Address' ]))
5405 self
. assertRegex ( a
, '^192.168.5.[178]$' )
5406 self
. assertEqual ( i
[ 'ConfigSource' ], 'DHCPv4' )
5407 a
= socket
. inet_ntop ( socket
. AF_INET
, bytearray ( i
[ 'ConfigProvider' ]))
5408 self
. assertEqual ( '192.168.5.1' , a
)
5410 self
. assertEqual ( len ( j
[ 'SIP' ]), 2 )
5413 self
. assertEqual ( i
[ 'Family' ], 2 )
5414 a
= socket
. inet_ntop ( socket
. AF_INET
, bytearray ( i
[ 'Address' ]))
5415 self
. assertRegex ( a
, '^192.168.5.2[34]$' )
5416 self
. assertEqual ( i
[ 'ConfigSource' ], 'DHCPv4' )
5417 a
= socket
. inet_ntop ( socket
. AF_INET
, bytearray ( i
[ 'ConfigProvider' ]))
5418 self
. assertEqual ( '192.168.5.1' , a
)
5420 print ( '## dnsmasq log' )
5421 output
= read_dnsmasq_log_file ()
5423 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
5424 self
. assertIn ( f
'DHCPDISCOVER(veth-peer) {address1} 12:34:56:78:9a:bc' , output
)
5425 self
. assertIn ( 'client provides name: test-hostname' , output
)
5426 self
. assertIn ( '26:mtu' , output
)
5428 self
. check_netlabel ( 'veth99' , r
'192\.168\.5\.0/24' )
5430 self
. check_nftset ( 'addr4' , r
'192\.168\.5\.1' )
5431 self
. check_nftset ( 'network4' , r
'192\.168\.5\.0/24' )
5432 self
. check_nftset ( 'ifindex' , 'veth99' )
5434 self
. teardown_nftset ( 'addr4' , 'network4' , 'ifindex' )
5436 def test_dhcp_client_ipv4_dbus_status ( self
):
5437 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv4-only.network' )
5439 self
. wait_online ([ 'veth-peer:carrier' ])
5441 state
= get_dhcp4_client_state ( 'veth99' )
5442 print ( f
"State = {state} " )
5443 self
. assertEqual ( state
, 'rebooting' )
5445 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7' ,
5446 '--dhcp-option=option:domain-search,example.com' ,
5447 '--dhcp-alternate-port=67,5555' ,
5448 ipv4_range
= '192.168.5.110,192.168.5.119' )
5449 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5450 self
. wait_address ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' )
5452 state
= get_dhcp4_client_state ( 'veth99' )
5453 print ( f
"State = {state} " )
5454 self
. assertEqual ( state
, 'bound' )
5456 def test_dhcp_client_ipv4_use_routes_gateway ( self
):
5458 for ( routes
, gateway
, dns_and_ntp_routes
, classless
) in itertools
. product ([ True , False ], repeat
= 4 ):
5464 print ( f
'### test_dhcp_client_ipv4_use_routes_gateway(routes= {routes} , gateway= {gateway} , dns_and_ntp_routes= {dns_and_ntp_routes} , classless= {classless} )' )
5465 with self
. subTest ( routes
= routes
, gateway
= gateway
, dns_and_ntp_routes
= dns_and_ntp_routes
, classless
= classless
):
5466 self
._ test
_ dhcp
_ client
_ ipv
4_u se
_ routes
_ gateway
( routes
, gateway
, dns_and_ntp_routes
, classless
)
5468 def _test_dhcp_client_ipv4_use_routes_gateway ( self
, use_routes
, use_gateway
, dns_and_ntp_routes
, classless
):
5469 testunit
= '25-dhcp-client-ipv4-use-routes-use-gateway.network'
5470 testunits
= [ '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , testunit
]
5471 testunits
. append ( f
' {testunit} .d/use-routes- {use_routes} .conf' )
5472 testunits
. append ( f
' {testunit} .d/use-gateway- {use_gateway} .conf' )
5473 testunits
. append ( f
' {testunit} .d/use-dns-and-ntp-routes- {dns_and_ntp_routes} .conf' )
5474 copy_network_unit (* testunits
, copy_dropins
= False )
5477 self
. wait_online ([ 'veth-peer:carrier' ])
5478 additional_options
= [
5479 '--dhcp-option=option:dns-server,192.168.5.10,8.8.8.8' ,
5480 '--dhcp-option=option:ntp-server,192.168.5.11,9.9.9.9' ,
5481 '--dhcp-option=option:static-route,192.168.6.100,192.168.5.2,8.8.8.8,192.168.5.3'
5484 additional_options
+= [
5485 '--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'
5487 start_dnsmasq (* additional_options
)
5488 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5490 output
= check_output ( 'ip -4 route show dev veth99' )
5496 self
. assertRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5497 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5498 self
. assertRegex ( output
, r
'192.168.5.64/26 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5499 self
. assertRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5500 self
. assertRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5502 self
. assertRegex ( output
, r
'192.168.6.0/24 via 192.168.5.2 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5503 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5504 self
. assertRegex ( output
, r
'192.168.5.2 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5505 self
. assertRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5507 self
. assertNotRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5508 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5509 self
. assertNotRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5510 self
. assertNotRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5511 self
. assertNotRegex ( output
, r
'192.168.6.0/24 via 192.168.5.2 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5512 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5513 self
. assertNotRegex ( output
, r
'192.168.5.2 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5514 self
. assertNotRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5517 if use_gateway
and ( not classless
or not use_routes
):
5518 self
. assertRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5520 self
. assertNotRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5522 # Check route to gateway
5523 if ( use_gateway
or dns_and_ntp_routes
) and ( not classless
or not use_routes
):
5524 self
. assertRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5526 self
. assertNotRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5528 # Check RoutesToDNS= and RoutesToNTP=
5529 if dns_and_ntp_routes
:
5530 self
. assertRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5531 self
. assertRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5534 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5535 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5537 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5538 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5540 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5541 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
5543 self
. assertNotRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5544 self
. assertNotRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
5545 self
. assertNotRegex ( output
, r
'8.8.8.8 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
5546 self
. assertNotRegex ( output
, r
'9.9.9.9 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
5548 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5551 def test_dhcp_client_settings_anonymize ( self
):
5552 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-anonymize.network' )
5554 self
. wait_online ([ 'veth-peer:carrier' ])
5556 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5558 print ( '## dnsmasq log' )
5559 output
= read_dnsmasq_log_file ()
5561 self
. assertNotIn ( 'VendorClassIdentifier=SusantVendorTest' , output
)
5562 self
. assertNotIn ( 'test-hostname' , output
)
5563 self
. assertNotIn ( '26:mtu' , output
)
5565 def test_dhcp_keep_configuration_dhcp ( self
):
5566 copy_network_unit ( '25-veth.netdev' ,
5567 '25-dhcp-server-veth-peer.network' ,
5568 '25-dhcp-client-keep-configuration-dhcp.network' )
5570 self
. wait_online ([ 'veth-peer:carrier' ])
5572 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5574 output
= check_output ( 'ip address show dev veth99 scope global' )
5576 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5577 'valid_lft forever preferred_lft forever' )
5579 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
5582 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
5583 print ( 'Wait for the DHCP lease to be expired' )
5586 # The lease address should be kept after the lease expired
5587 output
= check_output ( 'ip address show dev veth99 scope global' )
5589 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5590 'valid_lft forever preferred_lft forever' )
5594 # The lease address should be kept after networkd stopped
5595 output
= check_output ( 'ip address show dev veth99 scope global' )
5597 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5598 'valid_lft forever preferred_lft forever' )
5600 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-keep-configuration-dhcp.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5601 f
. write ( '[Network] \n DHCP=no \n ' )
5604 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5606 # Still the lease address should be kept after networkd restarted
5607 output
= check_output ( 'ip address show dev veth99 scope global' )
5609 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5610 'valid_lft forever preferred_lft forever' )
5612 def test_dhcp_keep_configuration_dhcp_on_stop ( self
):
5613 copy_network_unit ( '25-veth.netdev' ,
5614 '25-dhcp-server-veth-peer.network' ,
5615 '25-dhcp-client-keep-configuration-dhcp-on-stop.network' )
5617 self
. wait_online ([ 'veth-peer:carrier' ])
5619 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5621 output
= check_output ( 'ip address show dev veth99 scope global' )
5623 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5628 output
= check_output ( 'ip address show dev veth99 scope global' )
5630 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5633 self
. wait_online ([ 'veth-peer:routable' ])
5635 output
= check_output ( 'ip address show dev veth99 scope global' )
5637 self
. assertNotIn ( '192.168.5.' , output
)
5639 def test_dhcp_client_reuse_address_as_static ( self
):
5640 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' )
5642 self
. wait_online ([ 'veth-peer:carrier' ])
5644 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5646 # link become 'routable' when at least one protocol provide an valid address.
5647 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5648 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5650 output
= check_output ( 'ip address show dev veth99 scope global' )
5651 ipv4_address
= re
. search ( r
'192.168.5.[0-9]*/24' , output
). group ()
5652 ipv6_address
= re
. search ( r
'2600::[0-9a-f:]*/128' , output
). group ()
5653 static_network
= ' \n ' . join ([ '[Match]' , 'Name=veth99' , '[Network]' , 'IPv6AcceptRA=no' , 'Address=' + ipv4_address
, 'Address=' + ipv6_address
])
5654 print ( static_network
)
5656 remove_network_unit ( '25-dhcp-client.network' )
5658 with
open ( os
. path
. join ( network_unit_dir
, '25-static.network' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5659 f
. write ( static_network
)
5662 self
. wait_online ([ 'veth99:routable' ])
5664 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
5666 self
. assertRegex ( output
, f
'inet {ipv4_address} brd 192.168.5.255 scope global veth99 \n *'
5667 'valid_lft forever preferred_lft forever' )
5669 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5671 self
. assertRegex ( output
, f
'inet6 {ipv6_address} scope global * \n *'
5672 'valid_lft forever preferred_lft forever' )
5674 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
5675 def test_dhcp_client_vrf ( self
):
5676 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-vrf.network' ,
5677 '25-vrf.netdev' , '25-vrf.network' )
5679 self
. wait_online ([ 'veth-peer:carrier' ])
5681 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'vrf99:carrier' ])
5683 # link become 'routable' when at least one protocol provide an valid address.
5684 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5685 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5687 print ( '## ip -d link show dev vrf99' )
5688 output
= check_output ( 'ip -d link show dev vrf99' )
5690 self
. assertRegex ( output
, 'vrf table 42' )
5692 print ( '## ip address show vrf vrf99' )
5693 output
= check_output ( 'ip address show vrf vrf99' )
5695 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5696 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5697 self
. assertRegex ( output
, 'inet6 .* scope link' )
5699 print ( '## ip address show dev veth99' )
5700 output
= check_output ( 'ip address show dev veth99' )
5702 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5703 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5704 self
. assertRegex ( output
, 'inet6 .* scope link' )
5706 print ( '## ip route show vrf vrf99' )
5707 output
= check_output ( 'ip route show vrf vrf99' )
5709 self
. assertRegex ( output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.' )
5710 self
. assertRegex ( output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5' )
5711 self
. assertRegex ( output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5' )
5713 print ( '## ip route show table main dev veth99' )
5714 output
= check_output ( 'ip route show table main dev veth99' )
5716 self
. assertEqual ( output
, '' )
5718 def test_dhcp_client_gateway_onlink_implicit ( self
):
5719 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
5720 '25-dhcp-client-gateway-onlink-implicit.network' )
5722 self
. wait_online ([ 'veth-peer:carrier' ])
5724 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5726 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
5728 self
. assertRegex ( output
, '192.168.5' )
5730 output
= check_output ( 'ip route list dev veth99 10.0.0.0/8' )
5732 self
. assertRegex ( output
, 'onlink' )
5733 output
= check_output ( 'ip route list dev veth99 192.168.100.0/24' )
5735 self
. assertRegex ( output
, 'onlink' )
5737 def test_dhcp_client_with_ipv4ll ( self
):
5738 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
5739 '25-dhcp-client-with-ipv4ll.network' )
5741 # we need to increase timeout above default, as this will need to wait for
5742 # systemd-networkd to get the dhcpv4 transient failure event
5743 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:routable' ], timeout
= '60s' )
5745 output
= check_output ( 'ip -4 address show dev veth99' )
5747 self
. assertNotIn ( '192.168.5.' , output
)
5748 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
5751 print ( 'Wait for a DHCP lease to be acquired and the IPv4LL address to be dropped' )
5752 self
. wait_address ( 'veth99' , r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic' , ipv
= '-4' )
5753 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' )
5754 self
. wait_online ([ 'veth99:routable' ])
5756 output
= check_output ( 'ip -4 address show dev veth99' )
5758 self
. assertRegex ( output
, r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99' )
5759 self
. assertNotIn ( '169.254.' , output
)
5760 self
. assertNotIn ( 'scope link' , output
)
5763 print ( 'Wait for the DHCP lease to be expired and an IPv4LL address to be acquired' )
5764 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 )
5765 self
. wait_address ( 'veth99' , r
'inet 169\.254\.133\.11/16 metric 2048 brd 169\.254\.255\.255 scope link' , scope
= 'link' , ipv
= '-4' )
5767 output
= check_output ( 'ip -4 address show dev veth99' )
5769 self
. assertNotIn ( '192.168.5.' , output
)
5770 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
5772 def test_dhcp_client_use_dns ( self
):
5773 def check ( self
, ipv4
, ipv6
):
5774 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5775 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5776 f
. write ( '[DHCPv4] \n UseDNS=' )
5777 f
. write ( 'yes' if ipv4
else 'no' )
5778 f
. write ( ' \n [DHCPv6] \n UseDNS=' )
5779 f
. write ( 'yes' if ipv6
else 'no' )
5780 f
. write ( ' \n [IPv6AcceptRA] \n UseDNS=no' )
5783 self
. wait_online ([ 'veth99:routable' ])
5785 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5786 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5787 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5789 # make resolved re-read the link state file
5790 check_output (* resolvectl_cmd
, 'revert' , 'veth99' , env
= env
)
5792 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth99' , env
= env
)
5795 self
. assertIn ( '192.168.5.1' , output
)
5797 self
. assertNotIn ( '192.168.5.1' , output
)
5799 self
. assertIn ( '2600::1' , output
)
5801 self
. assertNotIn ( '2600::1' , output
)
5803 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5806 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5809 self
. wait_online ([ 'veth-peer:carrier' ])
5810 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1' ,
5811 '--dhcp-option=option6:dns-server,[2600::1]' )
5813 check ( self
, True , True )
5814 check ( self
, True , False )
5815 check ( self
, False , True )
5816 check ( self
, False , False )
5818 def test_dhcp_client_use_captive_portal ( self
):
5819 def check ( self
, ipv4
, ipv6
):
5820 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5821 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5822 f
. write ( '[DHCPv4] \n UseCaptivePortal=' )
5823 f
. write ( 'yes' if ipv4
else 'no' )
5824 f
. write ( ' \n [DHCPv6] \n UseCaptivePortal=' )
5825 f
. write ( 'yes' if ipv6
else 'no' )
5826 f
. write ( ' \n [IPv6AcceptRA] \n UseCaptivePortal=no' )
5829 self
. wait_online ([ 'veth99:routable' ])
5831 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5832 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5833 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5835 output
= check_output (* networkctl_cmd
, 'status' , 'veth99' , env
= env
)
5838 self
. assertIn ( 'Captive Portal: http://systemd.io' , output
)
5840 self
. assertNotIn ( 'Captive Portal: http://systemd.io' , output
)
5842 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5845 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5848 self
. wait_online ([ 'veth-peer:carrier' ])
5849 start_dnsmasq ( '--dhcp-option=114,http://systemd.io' ,
5850 '--dhcp-option=option6:103,http://systemd.io' )
5852 check ( self
, True , True )
5853 check ( self
, True , False )
5854 check ( self
, False , True )
5855 check ( self
, False , False )
5857 def test_dhcp_client_reject_captive_portal ( self
):
5858 def check ( self
, ipv4
, ipv6
):
5859 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5860 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5861 f
. write ( '[DHCPv4] \n UseCaptivePortal=' )
5862 f
. write ( 'yes' if ipv4
else 'no' )
5863 f
. write ( ' \n [DHCPv6] \n UseCaptivePortal=' )
5864 f
. write ( 'yes' if ipv6
else 'no' )
5865 f
. write ( ' \n [IPv6AcceptRA] \n UseCaptivePortal=no' )
5868 self
. wait_online ([ 'veth99:routable' ])
5870 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5871 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5872 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5874 output
= check_output (* networkctl_cmd
, 'status' , 'veth99' , env
= env
)
5876 self
. assertNotIn ( 'Captive Portal: ' , output
)
5877 self
. assertNotIn ( 'invalid/url' , output
)
5879 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5882 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5885 self
. wait_online ([ 'veth-peer:carrier' ])
5886 masq
= lambda bs
: ':' . join ( f
'{b:02x}' for b
in bs
)
5887 start_dnsmasq ( '--dhcp-option=114,' + masq ( b
'http:// \x00 invalid/url' ),
5888 '--dhcp-option=option6:103,' + masq ( b
'http:// \x00 /invalid/url' ))
5890 check ( self
, True , True )
5891 check ( self
, True , False )
5892 check ( self
, False , True )
5893 check ( self
, False , False )
5895 class NetworkdDHCPPDTests ( unittest
. TestCase
, Utilities
):
5903 def test_dhcp6pd ( self
):
5904 def get_dhcp6_prefix ( link
):
5905 description
= get_link_description ( link
)
5907 self
. assertIn ( 'DHCPv6Client' , description
. keys ())
5908 self
. assertIn ( 'Prefixes' , description
[ 'DHCPv6Client' ])
5910 prefixInfo
= description
[ 'DHCPv6Client' ][ 'Prefixes' ]
5914 copy_network_unit ( '25-veth.netdev' , '25-dhcp6pd-server.network' , '25-dhcp6pd-upstream.network' ,
5915 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
5916 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
5917 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
5918 '25-dhcp-pd-downstream-dummy97.network' ,
5919 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
5920 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' )
5922 self
. setup_nftset ( 'addr6' , 'ipv6_addr' )
5923 self
. setup_nftset ( 'network6' , 'ipv6_addr' , 'flags interval;' )
5924 self
. setup_nftset ( 'ifindex' , 'iface_index' )
5927 self
. wait_online ([ 'veth-peer:routable' ])
5928 start_isc_dhcpd ( conf_file
= 'isc-dhcpd-dhcp6pd.conf' , ipv
= '-6' )
5929 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5930 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5932 # Check DBus assigned prefix information to veth99
5933 prefixInfo
= get_dhcp6_prefix ( 'veth99' )
5935 self
. assertEqual ( len ( prefixInfo
), 1 )
5936 prefixInfo
= prefixInfo
[ 0 ]
5938 self
. assertIn ( 'Prefix' , prefixInfo
. keys ())
5939 self
. assertIn ( 'PrefixLength' , prefixInfo
. keys ())
5940 self
. assertIn ( 'PreferredLifetimeUSec' , prefixInfo
. keys ())
5941 self
. assertIn ( 'ValidLifetimeUSec' , prefixInfo
. keys ())
5943 self
. assertEqual ( prefixInfo
[ 'Prefix' ][ 0 : 6 ], [ 63 , 254 , 5 , 1 , 255 , 255 ])
5944 self
. assertEqual ( prefixInfo
[ 'PrefixLength' ], 56 )
5945 self
. assertGreater ( prefixInfo
[ 'PreferredLifetimeUSec' ], 0 )
5946 self
. assertGreater ( prefixInfo
[ 'ValidLifetimeUSec' ], 0 )
5948 print ( '### ip -6 address show dev veth-peer scope global' )
5949 output
= check_output ( 'ip -6 address show dev veth-peer scope global' )
5951 self
. assertIn ( 'inet6 3ffe:501:ffff:100::1/64 scope global' , output
)
5955 # dummy97: 0x01 (The link will appear later)
5957 # dummy99: auto -> 0x02 (No address assignment)
5962 print ( '### ip -6 address show dev veth99 scope global' )
5963 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5966 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:100::[0-9]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5967 # address in IA_PD (Token=static)
5968 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic' )
5969 # address in IA_PD (Token=eui64)
5970 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic' )
5971 # address in IA_PD (temporary)
5972 # Note that the temporary addresses may appear after the link enters configured state
5973 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' )
5975 print ( '### ip -6 address show dev test1 scope global' )
5976 output
= check_output ( 'ip -6 address show dev test1 scope global' )
5978 # address in IA_PD (Token=static)
5979 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5980 # address in IA_PD (temporary)
5981 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' )
5983 print ( '### ip -6 address show dev dummy98 scope global' )
5984 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5986 # address in IA_PD (Token=static)
5987 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5988 # address in IA_PD (temporary)
5989 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' )
5991 print ( '### ip -6 address show dev dummy99 scope global' )
5992 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5995 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
5997 print ( '### ip -6 address show dev veth97 scope global' )
5998 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
6000 # address in IA_PD (Token=static)
6001 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6002 # address in IA_PD (Token=eui64)
6003 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6004 # address in IA_PD (temporary)
6005 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' )
6007 print ( '### ip -6 address show dev veth97-peer scope global' )
6008 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
6010 # NDisc address (Token=static)
6011 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6012 # NDisc address (Token=eui64)
6013 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6014 # NDisc address (temporary)
6015 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' )
6017 print ( '### ip -6 address show dev veth98 scope global' )
6018 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
6020 # address in IA_PD (Token=static)
6021 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6022 # address in IA_PD (Token=eui64)
6023 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6024 # address in IA_PD (temporary)
6025 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' )
6027 print ( '### ip -6 address show dev veth98-peer scope global' )
6028 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
6030 # NDisc address (Token=static)
6031 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6032 # NDisc address (Token=eui64)
6033 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6034 # NDisc address (temporary)
6035 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' )
6037 print ( '### ip -6 route show type unreachable' )
6038 output
= check_output ( 'ip -6 route show type unreachable' )
6040 self
. assertRegex ( output
, 'unreachable 3ffe:501:ffff:[2-9a-f]00::/56 dev lo proto dhcp' )
6042 print ( '### ip -6 route show dev veth99' )
6043 output
= check_output ( 'ip -6 route show dev veth99' )
6045 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]10::/64 proto kernel metric [0-9]* expires' )
6047 print ( '### ip -6 route show dev test1' )
6048 output
= check_output ( 'ip -6 route show dev test1' )
6050 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
6052 print ( '### ip -6 route show dev dummy98' )
6053 output
= check_output ( 'ip -6 route show dev dummy98' )
6055 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
6057 print ( '### ip -6 route show dev dummy99' )
6058 output
= check_output ( 'ip -6 route show dev dummy99' )
6060 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
6062 print ( '### ip -6 route show dev veth97' )
6063 output
= check_output ( 'ip -6 route show dev veth97' )
6065 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto kernel metric [0-9]* expires' )
6067 print ( '### ip -6 route show dev veth97-peer' )
6068 output
= check_output ( 'ip -6 route show dev veth97-peer' )
6070 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto ra metric [0-9]* expires' )
6072 print ( '### ip -6 route show dev veth98' )
6073 output
= check_output ( 'ip -6 route show dev veth98' )
6075 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto kernel metric [0-9]* expires' )
6077 print ( '### ip -6 route show dev veth98-peer' )
6078 output
= check_output ( 'ip -6 route show dev veth98-peer' )
6080 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto ra metric [0-9]* expires' )
6082 # Test case for a downstream which appears later
6083 check_output ( 'ip link add dummy97 type dummy' )
6084 self
. wait_online ([ 'dummy97:routable' ])
6086 print ( '### ip -6 address show dev dummy97 scope global' )
6087 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
6089 # address in IA_PD (Token=static)
6090 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6091 # address in IA_PD (temporary)
6092 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' )
6094 print ( '### ip -6 route show dev dummy97' )
6095 output
= check_output ( 'ip -6 route show dev dummy97' )
6097 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]01::/64 proto kernel metric [0-9]* expires' )
6099 # Test case for reconfigure
6100 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
6101 self
. wait_online ([ 'dummy98:routable' , 'dummy99:degraded' ])
6103 print ( '### ip -6 address show dev dummy98 scope global' )
6104 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
6106 # address in IA_PD (Token=static)
6107 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6108 # address in IA_PD (temporary)
6109 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' )
6111 print ( '### ip -6 address show dev dummy99 scope global' )
6112 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
6115 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
6117 print ( '### ip -6 route show dev dummy98' )
6118 output
= check_output ( 'ip -6 route show dev dummy98' )
6120 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
6122 print ( '### ip -6 route show dev dummy99' )
6123 output
= check_output ( 'ip -6 route show dev dummy99' )
6125 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
6127 self
. check_netlabel ( 'dummy98' , '3ffe:501:ffff:[2-9a-f]00::/64' )
6129 self
. check_nftset ( 'addr6' , '3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d' )
6130 self
. check_nftset ( 'addr6' , '3ffe:501:ffff:[2-9a-f]00:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*' )
6131 self
. check_nftset ( 'network6' , '3ffe:501:ffff:[2-9a-f]00::/64' )
6132 self
. check_nftset ( 'ifindex' , 'dummy98' )
6134 self
. teardown_nftset ( 'addr6' , 'network6' , 'ifindex' )
6136 def verify_dhcp4_6rd ( self
, tunnel_name
):
6137 print ( '### ip -4 address show dev veth-peer scope global' )
6138 output
= check_output ( 'ip -4 address show dev veth-peer scope global' )
6140 self
. assertIn ( 'inet 10.0.0.1/8 brd 10.255.255.255 scope global veth-peer' , output
)
6144 # dummy97: 0x01 (The link will appear later)
6146 # dummy99: auto -> 0x0[23] (No address assignment)
6147 # 6rd-XXX: auto -> 0x0[23]
6152 print ( '### ip -4 address show dev veth99 scope global' )
6153 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
6155 self
. assertRegex ( output
, 'inet 10.100.100.[0-9]*/8 (metric 1024 |)brd 10.255.255.255 scope global dynamic veth99' )
6157 print ( '### ip -6 address show dev veth99 scope global' )
6158 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
6160 # address in IA_PD (Token=static)
6161 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6162 # address in IA_PD (Token=eui64)
6163 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6164 # address in IA_PD (temporary)
6165 # Note that the temporary addresses may appear after the link enters configured state
6166 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' )
6168 print ( '### ip -6 address show dev test1 scope global' )
6169 output
= check_output ( 'ip -6 address show dev test1 scope global' )
6171 # address in IA_PD (Token=static)
6172 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6173 # address in IA_PD (temporary)
6174 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' )
6176 print ( '### ip -6 address show dev dummy98 scope global' )
6177 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
6179 # address in IA_PD (Token=static)
6180 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6181 # address in IA_PD (temporary)
6182 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' )
6184 print ( '### ip -6 address show dev dummy99 scope global' )
6185 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
6188 self
. assertNotRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+0[23]' )
6190 print ( '### ip -6 address show dev veth97 scope global' )
6191 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
6193 # address in IA_PD (Token=static)
6194 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6195 # address in IA_PD (Token=eui64)
6196 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6197 # address in IA_PD (temporary)
6198 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' )
6200 print ( '### ip -6 address show dev veth97-peer scope global' )
6201 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
6203 # NDisc address (Token=static)
6204 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6205 # NDisc address (Token=eui64)
6206 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6207 # NDisc address (temporary)
6208 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' )
6210 print ( '### ip -6 address show dev veth98 scope global' )
6211 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
6213 # address in IA_PD (Token=static)
6214 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6215 # address in IA_PD (Token=eui64)
6216 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6217 # address in IA_PD (temporary)
6218 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' )
6220 print ( '### ip -6 address show dev veth98-peer scope global' )
6221 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
6223 # NDisc address (Token=static)
6224 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6225 # NDisc address (Token=eui64)
6226 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6227 # NDisc address (temporary)
6228 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' )
6230 print ( '### ip -6 route show type unreachable' )
6231 output
= check_output ( 'ip -6 route show type unreachable' )
6233 self
. assertRegex ( output
, 'unreachable 2001:db8:6464:[0-9a-f]+00::/56 dev lo proto dhcp' )
6235 print ( '### ip -6 route show dev veth99' )
6236 output
= check_output ( 'ip -6 route show dev veth99' )
6238 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+10::/64 proto kernel metric [0-9]* expires' )
6240 print ( '### ip -6 route show dev test1' )
6241 output
= check_output ( 'ip -6 route show dev test1' )
6243 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
6245 print ( '### ip -6 route show dev dummy98' )
6246 output
= check_output ( 'ip -6 route show dev dummy98' )
6248 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
6250 print ( '### ip -6 route show dev dummy99' )
6251 output
= check_output ( 'ip -6 route show dev dummy99' )
6253 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto dhcp metric [0-9]* expires' )
6255 print ( '### ip -6 route show dev veth97' )
6256 output
= check_output ( 'ip -6 route show dev veth97' )
6258 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto kernel metric [0-9]* expires' )
6260 print ( '### ip -6 route show dev veth97-peer' )
6261 output
= check_output ( 'ip -6 route show dev veth97-peer' )
6263 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto ra metric [0-9]* expires' )
6265 print ( '### ip -6 route show dev veth98' )
6266 output
= check_output ( 'ip -6 route show dev veth98' )
6268 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto kernel metric [0-9]* expires' )
6270 print ( '### ip -6 route show dev veth98-peer' )
6271 output
= check_output ( 'ip -6 route show dev veth98-peer' )
6273 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto ra metric [0-9]* expires' )
6275 print ( '### ip -6 address show dev dummy97 scope global' )
6276 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
6278 # address in IA_PD (Token=static)
6279 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6280 # address in IA_PD (temporary)
6281 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' )
6283 print ( '### ip -6 route show dev dummy97' )
6284 output
= check_output ( 'ip -6 route show dev dummy97' )
6286 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+01::/64 proto kernel metric [0-9]* expires' )
6288 print ( f
'### ip -d link show dev {tunnel_name} ' )
6289 output
= check_output ( f
'ip -d link show dev {tunnel_name} ' )
6291 self
. assertIn ( 'link/sit 10.100.100.' , output
)
6292 self
. assertIn ( 'local 10.100.100.' , output
)
6293 self
. assertIn ( 'ttl 64' , output
)
6294 self
. assertIn ( '6rd-prefix 2001:db8::/32' , output
)
6295 self
. assertIn ( '6rd-relay_prefix 10.0.0.0/8' , output
)
6297 print ( f
'### ip -6 address show dev {tunnel_name} ' )
6298 output
= check_output ( f
'ip -6 address show dev {tunnel_name} ' )
6300 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' )
6301 self
. assertRegex ( output
, 'inet6 ::10.100.100.[0-9]+/96 scope global' )
6303 print ( f
'### ip -6 route show dev {tunnel_name} ' )
6304 output
= check_output ( f
'ip -6 route show dev {tunnel_name} ' )
6306 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto kernel metric [0-9]* expires' )
6307 self
. assertRegex ( output
, '::/96 proto kernel metric [0-9]*' )
6309 print ( '### ip -6 route show default' )
6310 output
= check_output ( 'ip -6 route show default' )
6312 self
. assertIn ( 'default' , output
)
6313 self
. assertIn ( f
'via ::10.0.0.1 dev {tunnel_name} ' , output
)
6315 def test_dhcp4_6rd ( self
):
6316 def get_dhcp_6rd_prefix ( link
):
6317 description
= get_link_description ( link
)
6319 self
. assertIn ( 'DHCPv4Client' , description
. keys ())
6320 self
. assertIn ( '6rdPrefix' , description
[ 'DHCPv4Client' ]. keys ())
6322 prefixInfo
= description
[ 'DHCPv4Client' ][ '6rdPrefix' ]
6323 self
. assertIn ( 'Prefix' , prefixInfo
. keys ())
6324 self
. assertIn ( 'PrefixLength' , prefixInfo
. keys ())
6325 self
. assertIn ( 'IPv4MaskLength' , prefixInfo
. keys ())
6326 self
. assertIn ( 'BorderRouters' , prefixInfo
. keys ())
6330 copy_network_unit ( '25-veth.netdev' , '25-dhcp4-6rd-server.network' , '25-dhcp4-6rd-upstream.network' ,
6331 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
6332 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
6333 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
6334 '25-dhcp-pd-downstream-dummy97.network' ,
6335 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
6336 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' ,
6337 '80-6rd-tunnel.network' )
6340 self
. wait_online ([ 'veth-peer:routable' ])
6343 # 6rd-prefix: 2001:db8::/32
6344 # br-addresss: 10.0.0.1
6346 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' ,
6347 ipv4_range
= '10.100.100.100,10.100.100.200' ,
6348 ipv4_router
= '10.0.0.1' )
6349 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
6350 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
6352 # Check the DBus interface for assigned prefix information
6353 prefixInfo
= get_dhcp_6rd_prefix ( 'veth99' )
6355 self
. assertEqual ( prefixInfo
[ 'Prefix' ], [ 32 , 1 , 13 , 184 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ]) # 2001:db8::
6356 self
. assertEqual ( prefixInfo
[ 'PrefixLength' ], 32 )
6357 self
. assertEqual ( prefixInfo
[ 'IPv4MaskLength' ], 8 )
6358 self
. assertEqual ( prefixInfo
[ 'BorderRouters' ], [[ 10 , 0 , 0 , 1 ]])
6360 # Test case for a downstream which appears later
6361 check_output ( 'ip link add dummy97 type dummy' )
6362 self
. wait_online ([ 'dummy97:routable' ])
6366 for name
in os
. listdir ( '/sys/class/net/' ):
6367 if name
. startswith ( '6rd-' ):
6371 self
. wait_online ([ f
' {tunnel_name} :routable' ])
6373 self
. verify_dhcp4_6rd ( tunnel_name
)
6375 # Test case for reconfigure
6376 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
6377 self
. wait_online ([ 'dummy98:routable' , 'dummy99:degraded' ])
6379 self
. verify_dhcp4_6rd ( tunnel_name
)
6381 print ( 'Wait for the DHCP lease to be renewed/rebind' )
6384 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy97:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
6385 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
6387 self
. verify_dhcp4_6rd ( tunnel_name
)
6389 class NetworkdIPv6PrefixTests ( unittest
. TestCase
, Utilities
):
6397 def test_ipv6_route_prefix ( self
):
6398 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client.network' , '25-ipv6ra-prefix.network' ,
6399 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
6402 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
6404 output
= check_output ( 'ip address show dev veth-peer' )
6406 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
6407 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
6408 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
6410 output
= check_output ( 'ip -6 route show dev veth-peer' )
6412 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
6413 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
6414 self
. assertNotIn ( '2001:db8:0:3::/64 proto ra' , output
)
6415 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
6416 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
6417 self
. assertNotIn ( '2001:db2:fff::/64 via ' , output
)
6419 output
= check_output ( 'ip address show dev veth99' )
6421 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
6422 self
. assertIn ( 'inet6 2001:db8:0:2:1a:2b:3c:4d' , output
)
6423 self
. assertIn ( 'inet6 2001:db8:0:2:fa:de:ca:fe' , output
)
6424 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
6426 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth-peer' , env
= env
)
6428 self
. assertRegex ( output
, '2001:db8:1:1::2' )
6430 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth-peer' , env
= env
)
6432 self
. assertIn ( 'example.com' , output
)
6434 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
6437 output
= check_output (* networkctl_cmd
, '--json=short' , 'status' , 'veth-peer' , env
= env
)
6441 pref64
= json
. loads ( output
)[ 'NDisc' ][ 'PREF64' ][ 0 ]
6443 prefix
= socket
. inet_ntop ( socket
. AF_INET6
, bytearray ( pref64
[ 'Prefix' ]))
6444 self
. assertEqual ( prefix
, '64:ff9b::' )
6446 prefix_length
= pref64
[ 'PrefixLength' ]
6447 self
. assertEqual ( prefix_length
, 96 )
6449 def test_ipv6_route_prefix_deny_list ( self
):
6450 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client-deny-list.network' , '25-ipv6ra-prefix.network' ,
6451 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
6454 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
6456 output
= check_output ( 'ip address show dev veth-peer' )
6458 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
6459 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
6461 output
= check_output ( 'ip -6 route show dev veth-peer' )
6463 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
6464 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
6465 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
6466 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
6468 output
= check_output ( 'ip address show dev veth99' )
6470 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
6471 self
. assertIn ( 'inet6 2001:db8:0:2:' , output
)
6473 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth-peer' , env
= env
)
6475 self
. assertRegex ( output
, '2001:db8:1:1::2' )
6477 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth-peer' , env
= env
)
6479 self
. assertIn ( 'example.com' , output
)
6481 class NetworkdMTUTests ( unittest
. TestCase
, Utilities
):
6489 def check_mtu ( self
, mtu
, ipv6_mtu
= None , reset
= True ):
6495 self
. wait_online ([ 'dummy98:routable' ])
6496 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
6497 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
6499 # test normal restart
6501 self
. wait_online ([ 'dummy98:routable' ])
6502 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
6503 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
6506 self
. reset_check_mtu ( mtu
, ipv6_mtu
)
6508 def reset_check_mtu ( self
, mtu
, ipv6_mtu
= None ):
6509 ''' test setting mtu/ipv6_mtu with interface already up '''
6512 # note - changing the device mtu resets the ipv6 mtu
6513 check_output ( 'ip link set up mtu 1501 dev dummy98' )
6514 check_output ( 'ip link set up mtu 1500 dev dummy98' )
6515 self
. check_link_attr ( 'dummy98' , 'mtu' , '1500' )
6516 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , '1500' )
6518 self
. check_mtu ( mtu
, ipv6_mtu
, reset
= False )
6520 def test_mtu_network ( self
):
6521 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' )
6522 self
. check_mtu ( '1600' )
6524 def test_mtu_netdev ( self
):
6525 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network' , copy_dropins
= False )
6526 # note - MTU set by .netdev happens ONLY at device creation!
6527 self
. check_mtu ( '1600' , reset
= False )
6529 def test_mtu_link ( self
):
6530 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network' , copy_dropins
= False )
6531 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
6532 self
. check_mtu ( '1600' , reset
= False )
6534 def test_ipv6_mtu ( self
):
6535 ''' set ipv6 mtu without setting device mtu '''
6536 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1400.conf' )
6537 self
. check_mtu ( '1500' , '1400' )
6539 def test_ipv6_mtu_toolarge ( self
):
6540 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
6541 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
6542 self
. check_mtu ( '1500' , '1500' )
6544 def test_mtu_network_ipv6_mtu ( self
):
6545 ''' set ipv6 mtu and set device mtu via network file '''
6546 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
6547 self
. check_mtu ( '1600' , '1550' )
6549 def test_mtu_netdev_ipv6_mtu ( self
):
6550 ''' set ipv6 mtu and set device mtu via netdev file '''
6551 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
6552 self
. check_mtu ( '1600' , '1550' , reset
= False )
6554 def test_mtu_link_ipv6_mtu ( self
):
6555 ''' set ipv6 mtu and set device mtu via link file '''
6556 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
6557 self
. check_mtu ( '1600' , '1550' , reset
= False )
6560 if __name__
== '__main__' :
6561 parser
= argparse
. ArgumentParser ()
6562 parser
. add_argument ( '--build-dir' , help = 'Path to build dir' , dest
= 'build_dir' )
6563 parser
. add_argument ( '--networkd' , help = 'Path to systemd-networkd' , dest
= 'networkd_bin' )
6564 parser
. add_argument ( '--resolved' , help = 'Path to systemd-resolved' , dest
= 'resolved_bin' )
6565 parser
. add_argument ( '--timesyncd' , help = 'Path to systemd-timesyncd' , dest
= 'timesyncd_bin' )
6566 parser
. add_argument ( '--udevd' , help = 'Path to systemd-udevd' , dest
= 'udevd_bin' )
6567 parser
. add_argument ( '--wait-online' , help = 'Path to systemd-networkd-wait-online' , dest
= 'wait_online_bin' )
6568 parser
. add_argument ( '--networkctl' , help = 'Path to networkctl' , dest
= 'networkctl_bin' )
6569 parser
. add_argument ( '--resolvectl' , help = 'Path to resolvectl' , dest
= 'resolvectl_bin' )
6570 parser
. add_argument ( '--timedatectl' , help = 'Path to timedatectl' , dest
= 'timedatectl_bin' )
6571 parser
. add_argument ( '--udevadm' , help = 'Path to udevadm' , dest
= 'udevadm_bin' )
6572 parser
. add_argument ( '--valgrind' , help = 'Enable valgrind' , dest
= 'use_valgrind' , type = bool , nargs
= '?' , const
= True , default
= use_valgrind
)
6573 parser
. add_argument ( '--debug' , help = 'Generate debugging logs' , dest
= 'enable_debug' , type = bool , nargs
= '?' , const
= True , default
= enable_debug
)
6574 parser
. add_argument ( '--asan-options' , help = 'ASAN options' , dest
= 'asan_options' )
6575 parser
. add_argument ( '--lsan-options' , help = 'LSAN options' , dest
= 'lsan_options' )
6576 parser
. add_argument ( '--ubsan-options' , help = 'UBSAN options' , dest
= 'ubsan_options' )
6577 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
)
6578 ns
, unknown_args
= parser
. parse_known_args ( namespace
= unittest
)
6581 if ns
. networkd_bin
or ns
. resolved_bin
or ns
. timesyncd_bin
or ns
. udevd_bin
or \
6582 ns
. wait_online_bin
or ns
. networkctl_bin
or ns
. resolvectl_bin
or ns
. timedatectl_bin
or ns
. udevadm_bin
:
6583 print ( 'WARNING: --networkd, --resolved, --timesyncd, --udevd, --wait-online, --networkctl, --resolvectl, --timedatectl, or --udevadm options are ignored when --build-dir is specified.' )
6584 networkd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd' )
6585 resolved_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-resolved' )
6586 timesyncd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-timesyncd' )
6587 udevd_bin
= os
. path
. join ( ns
. build_dir
, 'udevadm' )
6588 wait_online_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd-wait-online' )
6589 networkctl_bin
= os
. path
. join ( ns
. build_dir
, 'networkctl' )
6590 resolvectl_bin
= os
. path
. join ( ns
. build_dir
, 'resolvectl' )
6591 timedatectl_bin
= os
. path
. join ( ns
. build_dir
, 'timedatectl' )
6592 udevadm_bin
= os
. path
. join ( ns
. build_dir
, 'udevadm' )
6595 networkd_bin
= ns
. networkd_bin
6597 resolved_bin
= ns
. resolved_bin
6598 if ns
. timesyncd_bin
:
6599 timesyncd_bin
= ns
. timesyncd_bin
6601 udevd_bin
= ns
. udevd_bin
6602 if ns
. wait_online_bin
:
6603 wait_online_bin
= ns
. wait_online_bin
6604 if ns
. networkctl_bin
:
6605 networkctl_bin
= ns
. networkctl_bin
6606 if ns
. resolvectl_bin
:
6607 resolvectl_bin
= ns
. resolvectl_bin
6608 if ns
. timedatectl_bin
:
6609 timedatectl_bin
= ns
. timedatectl_bin
6611 udevadm_bin
= ns
. udevadm_bin
6613 use_valgrind
= ns
. use_valgrind
6614 enable_debug
= ns
. enable_debug
6615 asan_options
= ns
. asan_options
6616 lsan_options
= ns
. lsan_options
6617 ubsan_options
= ns
. ubsan_options
6618 with_coverage
= ns
. with_coverage
6621 # Do not forget the trailing space.
6622 valgrind_cmd
= 'valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all '
6624 networkctl_cmd
= valgrind_cmd
. split () + [ networkctl_bin
]
6625 resolvectl_cmd
= valgrind_cmd
. split () + [ resolvectl_bin
]
6626 timedatectl_cmd
= valgrind_cmd
. split () + [ timedatectl_bin
]
6627 udevadm_cmd
= valgrind_cmd
. split () + [ udevadm_bin
]
6628 wait_online_cmd
= valgrind_cmd
. split () + [ wait_online_bin
]
6631 env
. update ({ 'ASAN_OPTIONS' : asan_options
})
6633 env
. update ({ 'LSAN_OPTIONS' : lsan_options
})
6635 env
. update ({ 'UBSAN_OPTIONS' : ubsan_options
})
6637 env
. update ({ 'SYSTEMD_MEMPOOL' : '0' })
6639 wait_online_env
= env
. copy ()
6641 wait_online_env
. update ({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
6643 sys
. argv
[ 1 :] = unknown_args
6644 unittest
. main ( verbosity
= 3 )