]>
git.ipfire.org Git - thirdparty/systemd.git/blob - test/test-network/systemd-networkd-tests.py
2 # SPDX-License-Identifier: LGPL-2.1-or-later
3 # pylint: disable=line-too-long,too-many-lines,too-many-branches,too-many-statements,too-many-arguments
4 # pylint: disable=too-many-public-methods,too-many-boolean-expressions,invalid-name
5 # pylint: disable=missing-function-docstring,missing-class-docstring,missing-module-docstring
6 # systemd-networkd tests
8 # These tests can be executed in the systemd mkosi image when booted in QEMU. After booting the QEMU VM,
9 # simply run this file which can be found in the VM at /usr/lib/systemd/tests/testdata/test-network/systemd-networkd-tests.py.
26 network_unit_dir
= '/run/systemd/network'
27 networkd_conf_dropin_dir
= '/run/systemd/networkd.conf.d'
28 networkd_ci_temp_dir
= '/run/networkd-ci'
29 udev_rules_dir
= '/run/udev/rules.d'
31 dnsmasq_pid_file
= '/run/networkd-ci/test-dnsmasq.pid'
32 dnsmasq_log_file
= '/run/networkd-ci/test-dnsmasq.log'
33 dnsmasq_lease_file
= '/run/networkd-ci/test-dnsmasq.lease'
35 isc_dhcpd_pid_file
= '/run/networkd-ci/test-isc-dhcpd.pid'
36 isc_dhcpd_lease_file
= '/run/networkd-ci/test-isc-dhcpd.lease'
38 systemd_lib_paths
= [ '/usr/lib/systemd' , '/lib/systemd' ]
39 which_paths
= ':' . join ( systemd_lib_paths
+ os
. getenv ( 'PATH' , os
. defpath
). lstrip ( ':' ). split ( ':' ))
41 networkd_bin
= shutil
. which ( 'systemd-networkd' , path
= which_paths
)
42 resolved_bin
= shutil
. which ( 'systemd-resolved' , path
= which_paths
)
43 timesyncd_bin
= shutil
. which ( 'systemd-timesyncd' , path
= which_paths
)
44 udevd_bin
= shutil
. which ( 'systemd-udevd' , path
= which_paths
)
45 wait_online_bin
= shutil
. which ( 'systemd-networkd-wait-online' , path
= which_paths
)
46 networkctl_bin
= shutil
. which ( 'networkctl' , path
= which_paths
)
47 resolvectl_bin
= shutil
. which ( 'resolvectl' , path
= which_paths
)
48 timedatectl_bin
= shutil
. which ( 'timedatectl' , path
= which_paths
)
49 udevadm_bin
= shutil
. which ( 'udevadm' , path
= which_paths
)
77 saved_ipv4_rules
= None
78 saved_ipv6_rules
= None
82 if os
. path
. exists ( path
):
86 shutil
. rmtree ( path
, ignore_errors
= True )
92 shutil
. copytree ( src
, dst
, copy_function
= shutil
. copy
)
95 os
. makedirs ( path
, exist_ok
= True )
98 pathlib
. Path ( path
). touch ()
100 # pylint: disable=R1710
101 def check_output (* command
, ** kwargs
):
102 # This checks the result and returns stdout (and stderr) on success.
103 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
104 ret
= subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. PIPE
, stderr
= subprocess
. STDOUT
, ** kwargs
)
105 if ret
. returncode
== 0 :
106 return ret
. stdout
. rstrip ()
107 # When returncode != 0, print stdout and stderr, then trigger CalledProcessError.
109 ret
. check_returncode ()
111 def call (* command
, ** kwargs
):
112 # This returns returncode. stdout and stderr are merged and shown in console
113 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
114 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stderr
= subprocess
. STDOUT
, ** kwargs
). returncode
116 def call_quiet (* command
, ** kwargs
):
117 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
118 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. DEVNULL
, stderr
= subprocess
. DEVNULL
, ** kwargs
). returncode
120 def run (* command
, ** kwargs
):
121 # This returns CompletedProcess instance.
122 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
123 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. PIPE
, stderr
= subprocess
. PIPE
, ** kwargs
)
125 def is_module_available (* module_names
):
126 for module_name
in module_names
:
127 lsmod_output
= check_output ( 'lsmod' )
128 module_re
= re
. compile ( rf
'^{re.escape(module_name)} \b ' , re
. MULTILINE
)
129 if not module_re
. search ( lsmod_output
) and call_quiet ( 'modprobe' , module_name
) != 0 :
133 def expectedFailureIfModuleIsNotAvailable (* module_names
):
135 return func
if is_module_available (* module_names
) else unittest
. expectedFailure ( func
)
139 def expectedFailureIfERSPANv0IsNotSupported ():
140 # erspan version 0 is supported since f989d546a2d5a9f001f6f8be49d98c10ab9b1897 (v5.8)
142 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' )
143 remove_link ( 'erspan99' )
144 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
148 def expectedFailureIfERSPANv2IsNotSupported ():
149 # erspan version 2 is supported since f551c91de262ba36b20c3ac19538afb4f4507441 (v4.16)
151 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' )
152 remove_link ( 'erspan99' )
153 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
157 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable ():
159 rc
= call_quiet ( 'ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7' )
160 call_quiet ( 'ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7' )
161 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
165 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable ():
167 rc
= call_quiet ( 'ip rule add not from 192.168.100.19 ipproto tcp table 7' )
168 call_quiet ( 'ip rule del not from 192.168.100.19 ipproto tcp table 7' )
169 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
173 def expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable ():
176 if call_quiet ( 'ip rule add from 192.168.100.19 table 7 uidrange 200-300' ) == 0 :
177 ret
= run ( 'ip rule list from 192.168.100.19 table 7' )
178 supported
= ret
. returncode
== 0 and 'uidrange 200-300' in ret
. stdout
179 call_quiet ( 'ip rule del from 192.168.100.19 table 7 uidrange 200-300' )
180 return func
if supported
else unittest
. expectedFailure ( func
)
184 def expectedFailureIfNexthopIsNotAvailable ():
186 rc
= call_quiet ( 'ip nexthop list' )
187 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
191 def expectedFailureIfRTA_VIAIsNotSupported ():
193 call_quiet ( 'ip link add dummy98 type dummy' )
194 call_quiet ( 'ip link set up dev dummy98' )
195 call_quiet ( 'ip route add 2001:1234:5:8fff:ff:ff:ff:fe/128 dev dummy98' )
196 rc
= call_quiet ( 'ip route add 10.10.10.10 via inet6 2001:1234:5:8fff:ff:ff:ff:fe dev dummy98' )
197 remove_link ( 'dummy98' )
198 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
202 def expectedFailureIfAlternativeNameIsNotAvailable ():
204 call_quiet ( 'ip link add dummy98 type dummy' )
206 call_quiet ( 'ip link prop add dev dummy98 altname hogehogehogehogehoge' ) == 0 and \
207 call_quiet ( 'ip link show dev hogehogehogehogehoge' ) == 0
208 remove_link ( 'dummy98' )
209 return func
if supported
else unittest
. expectedFailure ( func
)
213 def expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ():
215 def finalize ( func
, supported
):
216 call_quiet ( 'rmmod netdevsim' )
217 return func
if supported
else unittest
. expectedFailure ( func
)
219 call_quiet ( 'rmmod netdevsim' )
220 if call_quiet ( 'modprobe netdevsim' ) != 0 :
221 return finalize ( func
, False )
224 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
227 return finalize ( func
, False )
229 return finalize ( func
, os
. path
. exists ( '/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs' ))
233 # pylint: disable=C0415
234 def compare_kernel_version ( min_kernel_version
):
237 from packaging
import version
239 print ( 'Failed to import either platform or packaging module, assuming the comparison failed' )
242 # Get only the actual kernel version without any build/distro/arch stuff
243 # e.g. '5.18.5-200.fc36.x86_64' -> '5.18.5'
244 kver
= platform
. release (). split ( '-' )[ 0 ]
246 return version
. parse ( kver
) >= version
. parse ( min_kernel_version
)
249 check_output (* udevadm_cmd
, 'control' , '--reload' )
251 def copy_network_unit (* units
, copy_dropins
= True ):
253 Copy networkd unit files into the testbed.
255 Any networkd unit file type can be specified, as well as drop-in files.
257 By default, all drop-ins for a specified unit file are copied in;
258 to avoid that specify dropins=False.
260 When a drop-in file is specified, its unit file is also copied in automatically.
263 mkdir_p ( network_unit_dir
)
265 if copy_dropins
and os
. path
. exists ( os
. path
. join ( networkd_ci_temp_dir
, unit
+ '.d' )):
266 cp_r ( os
. path
. join ( networkd_ci_temp_dir
, unit
+ '.d' ), os
. path
. join ( network_unit_dir
, unit
+ '.d' ))
268 if unit
. endswith ( '.conf' ):
270 unit
= os
. path
. dirname ( dropin
). rstrip ( '.d' )
271 dropindir
= os
. path
. join ( network_unit_dir
, unit
+ '.d' )
273 cp ( os
. path
. join ( networkd_ci_temp_dir
, dropin
), dropindir
)
275 cp ( os
. path
. join ( networkd_ci_temp_dir
, unit
), network_unit_dir
)
277 if unit
. endswith ( '.link' ):
283 def remove_network_unit (* units
):
285 Remove previously copied unit files from the testbed.
287 Drop-ins will be removed automatically.
291 rm_f ( os
. path
. join ( network_unit_dir
, unit
))
292 rm_rf ( os
. path
. join ( network_unit_dir
, unit
+ '.d' ))
294 if unit
. endswith ( '.link' ) or unit
. endswith ( '.link.d' ):
300 def clear_network_units ():
302 if os
. path
. exists ( network_unit_dir
):
303 units
= os
. listdir ( network_unit_dir
)
305 if unit
. endswith ( '.link' ) or unit
. endswith ( '.link.d' ):
308 rm_rf ( network_unit_dir
)
313 def copy_networkd_conf_dropin (* dropins
):
314 """Copy networkd.conf dropin files into the testbed."""
315 mkdir_p ( networkd_conf_dropin_dir
)
316 for dropin
in dropins
:
317 cp ( os
. path
. join ( networkd_ci_temp_dir
, dropin
), networkd_conf_dropin_dir
)
319 def remove_networkd_conf_dropin (* dropins
):
320 """Remove previously copied networkd.conf dropin files from the testbed."""
321 for dropin
in dropins
:
322 rm_f ( os
. path
. join ( networkd_conf_dropin_dir
, dropin
))
324 def clear_networkd_conf_dropins ():
325 rm_rf ( networkd_conf_dropin_dir
)
327 def copy_udev_rule (* rules
):
328 """Copy udev rules"""
329 mkdir_p ( udev_rules_dir
)
331 cp ( os
. path
. join ( networkd_ci_temp_dir
, rule
), udev_rules_dir
)
333 def remove_udev_rule (* rules
):
334 """Remove previously copied udev rules"""
336 rm_f ( os
. path
. join ( udev_rules_dir
, rule
))
338 def clear_udev_rules ():
339 rm_rf ( udev_rules_dir
)
341 def save_active_units ():
342 for u
in [ 'systemd-networkd.socket' , 'systemd-networkd.service' ,
343 'systemd-resolved.service' , 'systemd-timesyncd.service' ,
344 'firewalld.service' ]:
345 if call ( f
'systemctl is-active --quiet {u} ' ) == 0 :
346 call ( f
'systemctl stop {u} ' )
347 active_units
. append ( u
)
349 def restore_active_units ():
350 if 'systemd-networkd.socket' in active_units
:
351 call ( 'systemctl stop systemd-networkd.socket systemd-networkd.service' )
352 for u
in active_units
:
353 call ( f
'systemctl restart {u} ' )
355 def create_unit_dropin ( unit
, contents
):
356 mkdir_p ( f
'/run/systemd/system/ {unit} .d' )
357 with
open ( f
'/run/systemd/system/ {unit} .d/00-override.conf' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
358 f
. write ( ' \n ' . join ( contents
))
360 def create_service_dropin ( service
, command
, reload_command
= None , additional_settings
= None ):
364 f
'ExecStart=!! {valgrind_cmd}{command} ' ,
369 f
'ExecReload= {valgrind_cmd}{reload_command} ' ,
372 drop_in
+= [ 'Environment=SYSTEMD_LOG_LEVEL=debug' ]
374 drop_in
+= [ f
'Environment=ASAN_OPTIONS=" {asan_options} "' ]
376 drop_in
+= [ f
'Environment=LSAN_OPTIONS=" {lsan_options} "' ]
378 drop_in
+= [ f
'Environment=UBSAN_OPTIONS=" {ubsan_options} "' ]
379 if asan_options
or lsan_options
or ubsan_options
:
380 drop_in
+= [ 'SystemCallFilter=' ]
381 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
382 drop_in
+= [ 'MemoryDenyWriteExecute=no' ]
385 'Environment=SYSTEMD_MEMPOOL=0' ,
393 if additional_settings
:
394 drop_in
+= additional_settings
396 create_unit_dropin ( f
' {service} .service' , drop_in
)
398 def link_exists ( link
):
399 return call_quiet ( f
'ip link show {link} ' ) == 0
401 def link_resolve ( link
):
402 return check_output ( f
'ip link show {link} ' ). split ( ':' )[ 1 ]. strip ()
404 def remove_link (* links
, protect
= False ):
406 if protect
and link
in protected_links
:
408 if link_exists ( link
):
409 call ( f
'ip link del dev {link} ' )
411 def save_existing_links ():
412 links
= os
. listdir ( '/sys/class/net' )
414 if link_exists ( link
):
415 protected_links
. add ( link
)
417 print ( '### The following links will be protected:' )
418 print ( ', ' . join ( sorted ( list ( protected_links
))))
421 links
= os
. listdir ( '/sys/class/net' )
422 remove_link (* links
, protect
= True )
424 def flush_nexthops ():
425 # Currently, the 'ip nexthop' command does not have 'save' and 'restore'.
426 # Hence, we cannot restore nexthops in a simple way.
427 # Let's assume there is no nexthop used in the system
428 call_quiet ( 'ip nexthop flush' )
431 # pylint: disable=global-statement
433 saved_routes
= check_output ( 'ip route show table all' )
434 print ( '### The following routes will be protected:' )
439 output
= check_output ( 'ip route show table all' )
440 for line
in output
. splitlines ():
441 if line
in saved_routes
:
443 if 'proto kernel' in line
:
445 if ' dev ' in line
and not ' dev lo ' in line
:
449 print ( '### Removing routes that did not exist when the test started.' )
451 call ( f
'ip route del {line} ' )
453 def save_routing_policy_rules ():
454 # pylint: disable=global-statement
455 global saved_ipv4_rules
, saved_ipv6_rules
457 output
= check_output ( f
'ip - {ipv} rule show' )
458 print ( f
'### The following IPv {ipv} routing policy rules will be protected:' )
462 saved_ipv4_rules
= save ( 4 )
463 saved_ipv6_rules
= save ( 6 )
465 def flush_routing_policy_rules ():
466 def flush ( ipv
, saved_rules
):
468 output
= check_output ( f
'ip - {ipv} rule show' )
469 for line
in output
. splitlines ():
470 if line
in saved_rules
:
474 print ( f
'### Removing IPv {ipv} routing policy rules that did not exist when the test started.' )
476 words
= line
. replace ( 'lookup [l3mdev-table]' , 'l3mdev' ). split ()
477 priority
= words
[ 0 ]. rstrip ( ':' )
478 call ( f
'ip - {ipv} rule del priority {priority} ' + ' ' . join ( words
[ 1 :]))
480 flush ( 4 , saved_ipv4_rules
)
481 flush ( 6 , saved_ipv6_rules
)
483 def flush_fou_ports ():
484 ret
= run ( 'ip fou show' )
485 if ret
. returncode
!= 0 :
486 return # fou may not be supported
487 for line
in ret
. stdout
. splitlines ():
488 port
= line
. split ()[ 1 ]
489 call ( f
'ip fou del port {port} ' )
491 def flush_l2tp_tunnels ():
493 ret
= run ( 'ip l2tp show tunnel' )
494 if ret
. returncode
!= 0 :
495 return # l2tp may not be supported
496 for line
in ret
. stdout
. splitlines ():
498 if words
[ 0 ] == 'Tunnel' :
499 tid
= words
[ 1 ]. rstrip ( ',' )
500 call ( f
'ip l2tp del tunnel tunnel_id {tid} ' )
503 # Removing L2TP tunnel is asynchronous and slightly takes a time.
506 r
= run ( f
'ip l2tp show tunnel tunnel_id {tid} ' )
507 if r
. returncode
!= 0 or len ( r
. stdout
. rstrip ()) == 0 :
511 print ( f
'Cannot remove L2TP tunnel {tid} , ignoring.' )
514 # pylint: disable=global-statement
515 global saved_timezone
516 r
= run (* timedatectl_cmd
, 'show' , '--value' , '--property' , 'Timezone' , env
= env
)
517 if r
. returncode
== 0 :
518 saved_timezone
= r
. stdout
. rstrip ()
519 print ( f
'### Saved timezone: {saved_timezone} ' )
521 def restore_timezone ():
523 call (* timedatectl_cmd
, 'set-timezone' , f
' {saved_timezone} ' , env
= env
)
525 def read_link_attr (* args
):
526 with
open ( os
. path
. join ( '/sys/class/net' , * args
), encoding
= 'utf-8' ) as f
:
527 return f
. readline (). strip ()
529 def read_link_state_file ( link
):
530 ifindex
= read_link_attr ( link
, 'ifindex' )
531 path
= os
. path
. join ( '/run/systemd/netif/links' , ifindex
)
532 with
open ( path
, encoding
= 'utf-8' ) as f
:
535 def read_ip_sysctl_attr ( link
, attribute
, ipv
):
536 with
open ( os
. path
. join ( '/proc/sys/net' , ipv
, 'conf' , link
, attribute
), encoding
= 'utf-8' ) as f
:
537 return f
. readline (). strip ()
539 def read_ipv6_sysctl_attr ( link
, attribute
):
540 return read_ip_sysctl_attr ( link
, attribute
, 'ipv6' )
542 def read_ipv4_sysctl_attr ( link
, attribute
):
543 return read_ip_sysctl_attr ( link
, attribute
, 'ipv4' )
545 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' ):
548 f
'--log-facility= {dnsmasq_log_file} ' ,
549 '--log-queries=extra' ,
551 f
'--pid-file= {dnsmasq_pid_file} ' ,
552 '--conf-file=/dev/null' ,
554 f
'--interface= {interface} ' ,
555 f
'--dhcp-leasefile= {dnsmasq_lease_file} ' ,
557 f
'--dhcp-range= {ipv6_range} , {lease_time} ' ,
558 f
'--dhcp-range= {ipv4_range} , {lease_time} ' ,
559 '--dhcp-option=option:mtu,1492' ,
560 f
'--dhcp-option=option:router, {ipv4_router} ' ,
563 ) + additional_options
564 check_output (* command
)
566 def stop_by_pid_file ( pid_file
):
567 if not os
. path
. exists ( pid_file
):
569 with
open ( pid_file
, 'r' , encoding
= 'utf-8' ) as f
:
570 pid
= f
. read (). rstrip ( ' \t\r\n \0' )
571 os
. kill ( int ( pid
), signal
. SIGTERM
)
575 print ( f
"PID {pid} is still alive, waiting..." )
578 if e
. errno
== errno
. ESRCH
:
580 print ( f
"Unexpected exception when waiting for {pid} to die: {e.errno}" )
584 stop_by_pid_file ( dnsmasq_pid_file
)
585 rm_f ( dnsmasq_lease_file
)
586 rm_f ( dnsmasq_log_file
)
588 def read_dnsmasq_log_file ():
589 with
open ( dnsmasq_log_file
, encoding
= 'utf-8' ) as f
:
592 def start_isc_dhcpd ( conf_file
, ipv
, interface
= 'veth-peer' ):
593 conf_file_path
= os
. path
. join ( networkd_ci_temp_dir
, conf_file
)
594 isc_dhcpd_command
= f
'dhcpd {ipv} -cf {conf_file_path} -lf {isc_dhcpd_lease_file} -pf {isc_dhcpd_pid_file} {interface} '
595 touch ( isc_dhcpd_lease_file
)
596 check_output ( isc_dhcpd_command
)
598 def stop_isc_dhcpd ():
599 stop_by_pid_file ( isc_dhcpd_pid_file
)
600 rm_f ( isc_dhcpd_lease_file
)
602 def networkd_invocation_id ():
603 return check_output ( 'systemctl show --value -p InvocationID systemd-networkd.service' )
605 def read_networkd_log ( invocation_id
= None ):
606 if not invocation_id
:
607 invocation_id
= networkd_invocation_id ()
608 return check_output ( 'journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
)
610 def stop_networkd ( show_logs
= True ):
612 invocation_id
= networkd_invocation_id ()
613 check_output ( 'systemctl stop systemd-networkd.socket' )
614 check_output ( 'systemctl stop systemd-networkd.service' )
616 print ( read_networkd_log ( invocation_id
))
618 def start_networkd ():
619 check_output ( 'systemctl start systemd-networkd' )
621 def restart_networkd ( show_logs
= True ):
623 invocation_id
= networkd_invocation_id ()
624 check_output ( 'systemctl restart systemd-networkd.service' )
626 print ( read_networkd_log ( invocation_id
))
629 return int ( check_output ( 'systemctl show --value -p MainPID systemd-networkd.service' ))
631 def networkctl_reconfigure (* links
):
632 check_output (* networkctl_cmd
, 'reconfigure' , * links
, env
= env
)
634 def networkctl_reload ( sleep_time
= 1 ):
635 check_output (* networkctl_cmd
, 'reload' , env
= env
)
636 # 'networkctl reload' asynchronously reconfigure links.
637 # Hence, we need to wait for a short time for link to be in configuring state.
639 time
. sleep ( sleep_time
)
644 def tear_down_common ():
645 # 1. stop DHCP servers
650 call_quiet ( 'rmmod netdevsim' )
651 call_quiet ( 'rmmod sch_teql' )
653 # 3. remove network namespace
654 call_quiet ( 'ip netns del ns99' )
664 clear_network_units ()
665 clear_networkd_conf_dropins ()
670 flush_routing_policy_rules ()
674 rm_rf ( networkd_ci_temp_dir
)
675 cp_r ( os
. path
. join ( os
. path
. dirname ( os
. path
. abspath ( __file__
)), 'conf' ), networkd_ci_temp_dir
)
677 clear_network_units ()
678 clear_networkd_conf_dropins ()
681 copy_udev_rule ( '00-debug-net.rules' )
685 save_existing_links ()
687 save_routing_policy_rules ()
690 create_service_dropin ( 'systemd-networkd' , networkd_bin
,
691 f
' {networkctl_bin} reload' ,
692 [ '[Service]' , 'Restart=no' , '[Unit]' , 'StartLimitIntervalSec=0' ])
693 create_service_dropin ( 'systemd-resolved' , resolved_bin
)
694 create_service_dropin ( 'systemd-timesyncd' , timesyncd_bin
)
696 # TODO: also run udevd with sanitizers, valgrind, or coverage
697 #create_service_dropin('systemd-udevd', udevd_bin,
698 # f'{udevadm_bin} control --reload --timeout 0')
700 'systemd-udevd.service' ,
704 f
'ExecStart=!! {udevd_bin} ' ,
706 f
'ExecReload= {udevadm_bin} control --reload --timeout 0' ,
710 'systemd-networkd.socket' ,
713 'StartLimitIntervalSec=0' ,
717 check_output ( 'systemctl daemon-reload' )
718 print ( check_output ( 'systemctl cat systemd-networkd.service' ))
719 print ( check_output ( 'systemctl cat systemd-resolved.service' ))
720 print ( check_output ( 'systemctl cat systemd-timesyncd.service' ))
721 print ( check_output ( 'systemctl cat systemd-udevd.service' ))
722 check_output ( 'systemctl restart systemd-resolved.service' )
723 check_output ( 'systemctl restart systemd-timesyncd.service' )
724 check_output ( 'systemctl restart systemd-udevd.service' )
726 def tearDownModule ():
727 rm_rf ( networkd_ci_temp_dir
)
729 clear_network_units ()
730 clear_networkd_conf_dropins ()
734 rm_rf ( '/run/systemd/system/systemd-networkd.service.d' )
735 rm_rf ( '/run/systemd/system/systemd-networkd.socket.d' )
736 rm_rf ( '/run/systemd/system/systemd-resolved.service.d' )
737 rm_rf ( '/run/systemd/system/systemd-timesyncd.service.d' )
738 rm_rf ( '/run/systemd/system/systemd-udevd.service.d' )
739 check_output ( 'systemctl daemon-reload' )
740 check_output ( 'systemctl restart systemd-udevd.service' )
741 restore_active_units ()
744 # pylint: disable=no-member
746 def check_link_exists ( self
, link
, expected
= True ):
748 self
. assertTrue ( link_exists ( link
))
750 self
. assertFalse ( link_exists ( link
))
752 def check_link_attr ( self
, * args
):
753 self
. assertEqual ( read_link_attr (* args
[:- 1 ]), args
[- 1 ])
755 def check_bridge_port_attr ( self
, master
, port
, attribute
, expected
, allow_enoent
= False ):
756 path
= os
. path
. join ( '/sys/devices/virtual/net' , master
, 'lower_' + port
, 'brport' , attribute
)
757 if allow_enoent
and not os
. path
. exists ( path
):
759 with
open ( path
, encoding
= 'utf-8' ) as f
:
760 self
. assertEqual ( f
. readline (). strip (), expected
)
762 def check_ipv4_sysctl_attr ( self
, link
, attribute
, expected
):
763 self
. assertEqual ( read_ipv4_sysctl_attr ( link
, attribute
), expected
)
765 def check_ipv6_sysctl_attr ( self
, link
, attribute
, expected
):
766 self
. assertEqual ( read_ipv6_sysctl_attr ( link
, attribute
), expected
)
768 def wait_links ( self
, * links
, timeout
= 20 , fail_assert
= True ):
769 def links_exist (* links
):
771 if not link_exists ( link
):
775 for iteration
in range ( timeout
+ 1 ):
779 if links_exist (* links
):
782 self
. fail ( 'Timed out waiting for all links to be created: ' + ', ' . join ( list ( links
)))
785 def wait_activated ( self
, link
, state
= 'down' , timeout
= 20 , fail_assert
= True ):
786 # wait for the interface is activated.
787 invocation_id
= check_output ( 'systemctl show systemd-networkd -p InvocationID --value' )
788 needle
= f
' {link} : Bringing link {state} '
790 for iteration
in range ( timeout
+ 1 ):
793 if not link_exists ( link
):
795 output
= check_output ( 'journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
)
796 if needle
in output
and flag
in check_output ( f
'ip link show {link} ' ):
799 self
. fail ( f
'Timed out waiting for {link} activated.' )
802 def wait_operstate ( self
, link
, operstate
= 'degraded' , setup_state
= 'configured' , setup_timeout
= 5 , fail_assert
= True ):
803 """Wait for the link to reach the specified operstate and/or setup state.
805 Specify None or '' for either operstate or setup_state to ignore that state.
806 This will recheck until the state conditions are met or the timeout expires.
808 If the link successfully matches the requested state, this returns True.
809 If this times out waiting for the link to match, the behavior depends on the
810 'fail_assert' parameter; if True, this causes a test assertion failure,
811 otherwise this returns False. The default is to cause assertion failure.
813 Note that this function matches on *exactly* the given operstate and setup_state.
814 To wait for a link to reach *or exceed* a given operstate, use wait_online().
821 for secs
in range ( setup_timeout
+ 1 ):
824 if not link_exists ( link
):
826 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , link
, env
= env
)
827 if re
. search ( rf
'(?m)^\s*State:\s+ {operstate} \s+\( {setup_state} \)\s*$' , output
):
831 self
. fail ( f
'Timed out waiting for {link} to reach state {operstate} / {setup_state} ' )
834 def wait_online ( self
, links_with_operstate
, timeout
= '20s' , bool_any
= False , ipv4
= False , ipv6
= False , setup_state
= 'configured' , setup_timeout
= 5 ):
835 """Wait for the links to reach the specified operstate and/or setup state.
837 This is similar to wait_operstate() but can be used for multiple links,
838 and it also calls systemd-networkd-wait-online to wait for the given operstate.
839 The operstate should be specified in the link name, like 'eth0:degraded'.
840 If just a link name is provided, wait-online's default operstate to wait for is degraded.
842 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
843 'setup_timeout' controls the per-link timeout waiting for the setup_state.
845 Set 'bool_any' to True to wait for any (instead of all) of the given links.
846 If this is set, no setup_state checks are done.
848 Set 'ipv4' or 'ipv6' to True to wait for IPv4 address or IPv6 address, respectively, of each of the given links.
849 This is applied only for the operational state 'degraded' or above.
851 Note that this function waits for the links to reach *or exceed* the given operstate.
852 However, the setup_state, if specified, must be matched *exactly*.
854 This returns if the links reached the requested operstate/setup_state; otherwise it
855 raises CalledProcessError or fails test assertion.
857 args
= wait_online_cmd
+ [ f
'--timeout= {timeout} ' ] + [ f
'--interface= {link} ' for link
in links_with_operstate
] + [ f
'--ignore= {link} ' for link
in protected_links
]
865 check_output (* args
, env
= wait_online_env
)
866 except subprocess
. CalledProcessError
:
867 # show detailed status on failure
868 for link
in links_with_operstate
:
869 name
= link
. split ( ':' )[ 0 ]
870 if link_exists ( name
):
871 call (* networkctl_cmd
, '-n' , '0' , 'status' , name
, env
= env
)
873 if not bool_any
and setup_state
:
874 for link
in links_with_operstate
:
875 self
. wait_operstate ( link
. split ( ':' )[ 0 ], None , setup_state
, setup_timeout
)
877 def wait_address ( self
, link
, address_regex
, scope
= 'global' , ipv
= '' , timeout_sec
= 100 ):
878 for i
in range ( timeout_sec
):
881 output
= check_output ( f
'ip {ipv} address show dev {link} scope {scope} ' )
882 if re
. search ( address_regex
, output
) and 'tentative' not in output
:
885 self
. assertRegex ( output
, address_regex
)
887 def wait_address_dropped ( self
, link
, address_regex
, scope
= 'global' , ipv
= '' , timeout_sec
= 100 ):
888 for i
in range ( timeout_sec
):
891 output
= check_output ( f
'ip {ipv} address show dev {link} scope {scope} ' )
892 if not re
. search ( address_regex
, output
):
895 self
. assertNotRegex ( output
, address_regex
)
897 def wait_route ( self
, link
, route_regex
, table
= 'main' , ipv
= '' , timeout_sec
= 100 ):
898 for i
in range ( timeout_sec
):
901 output
= check_output ( f
'ip {ipv} route show dev {link} table {table} ' )
902 if re
. search ( route_regex
, output
):
905 self
. assertRegex ( output
, route_regex
)
907 def check_netlabel ( self
, interface
, address
, label
= 'system_u:object_r:root_t:s0' ):
908 if not shutil
. which ( 'selinuxenabled' ):
909 print ( '## Checking NetLabel skipped: selinuxenabled command not found.' )
910 elif call_quiet ( 'selinuxenabled' ) != 0 :
911 print ( '## Checking NetLabel skipped: SELinux disabled.' )
912 elif not shutil
. which ( 'netlabelctl' ): # not packaged by all distros
913 print ( '## Checking NetLabel skipped: netlabelctl command not found.' )
915 output
= check_output ( 'netlabelctl unlbl list' )
917 self
. assertRegex ( output
, f
'interface: {interface} ,address: {address} ,label:" {label} "' )
919 class NetworkctlTests ( unittest
. TestCase
, Utilities
):
927 @expectedFailureIfAlternativeNameIsNotAvailable ()
928 def test_altname ( self
):
929 copy_network_unit ( '26-netdev-link-local-addressing-yes.network' , '12-dummy.netdev' , '12-dummy.link' )
931 self
. wait_online ([ 'dummy98:degraded' ])
933 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
934 self
. assertRegex ( output
, 'hogehogehogehogehogehoge' )
936 @expectedFailureIfAlternativeNameIsNotAvailable ()
937 def test_rename_to_altname ( self
):
938 copy_network_unit ( '26-netdev-link-local-addressing-yes.network' ,
939 '12-dummy.netdev' , '12-dummy-rename-to-altname.link' )
941 self
. wait_online ([ 'dummyalt:degraded' ])
943 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummyalt' , env
= env
)
944 self
. assertIn ( 'hogehogehogehogehogehoge' , output
)
945 self
. assertNotIn ( 'dummy98' , output
)
947 def test_reconfigure ( self
):
948 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' )
950 self
. wait_online ([ 'dummy98:routable' ])
952 output
= check_output ( 'ip -4 address show dev dummy98' )
954 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
955 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
956 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
958 check_output ( 'ip address del 10.1.2.3/16 dev dummy98' )
959 check_output ( 'ip address del 10.1.2.4/16 dev dummy98' )
960 check_output ( 'ip address del 10.2.2.4/16 dev dummy98' )
962 networkctl_reconfigure ( 'dummy98' )
963 self
. wait_online ([ 'dummy98:routable' ])
965 output
= check_output ( 'ip -4 address show dev dummy98' )
967 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
968 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
969 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
971 remove_network_unit ( '25-address-static.network' )
974 self
. wait_operstate ( 'dummy98' , 'degraded' , setup_state
= 'unmanaged' )
976 output
= check_output ( 'ip -4 address show dev dummy98' )
978 self
. assertNotIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
979 self
. assertNotIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
980 self
. assertNotIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
982 copy_network_unit ( '25-address-static.network' )
984 self
. wait_online ([ 'dummy98:routable' ])
986 output
= check_output ( 'ip -4 address show dev dummy98' )
988 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
989 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
990 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
992 def test_reload ( self
):
995 copy_network_unit ( '11-dummy.netdev' )
997 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'unmanaged' )
999 copy_network_unit ( '11-dummy.network' )
1001 self
. wait_online ([ 'test1:degraded' ])
1003 remove_network_unit ( '11-dummy.network' )
1005 self
. wait_operstate ( 'test1' , 'degraded' , setup_state
= 'unmanaged' )
1007 remove_network_unit ( '11-dummy.netdev' )
1009 self
. wait_operstate ( 'test1' , 'degraded' , setup_state
= 'unmanaged' )
1011 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1013 self
. wait_operstate ( 'test1' , 'degraded' )
1015 def test_glob ( self
):
1016 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1019 self
. wait_online ([ 'test1:degraded' ])
1021 output
= check_output (* networkctl_cmd
, 'list' , env
= env
)
1022 self
. assertRegex ( output
, '1 lo ' )
1023 self
. assertRegex ( output
, 'test1' )
1025 output
= check_output (* networkctl_cmd
, 'list' , 'test1' , env
= env
)
1026 self
. assertNotRegex ( output
, '1 lo ' )
1027 self
. assertRegex ( output
, 'test1' )
1029 output
= check_output (* networkctl_cmd
, 'list' , 'te*' , env
= env
)
1030 self
. assertNotRegex ( output
, '1 lo ' )
1031 self
. assertRegex ( output
, 'test1' )
1033 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'te*' , env
= env
)
1034 self
. assertNotRegex ( output
, '1: lo ' )
1035 self
. assertRegex ( output
, 'test1' )
1037 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'tes[a-z][0-9]' , env
= env
)
1038 self
. assertNotRegex ( output
, '1: lo ' )
1039 self
. assertRegex ( output
, 'test1' )
1042 copy_network_unit ( '11-dummy-mtu.netdev' , '11-dummy.network' )
1045 self
. wait_online ([ 'test1:degraded' ])
1047 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
1048 self
. assertRegex ( output
, 'MTU: 1600' )
1050 def test_type ( self
):
1051 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1053 self
. wait_online ([ 'test1:degraded' ])
1055 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
1057 self
. assertRegex ( output
, 'Type: ether' )
1059 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'lo' , env
= env
)
1061 self
. assertRegex ( output
, 'Type: loopback' )
1063 def test_udev_link_file ( self
):
1064 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' , '25-default.link' )
1066 self
. wait_online ([ 'test1:degraded' ])
1068 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
1070 self
. assertRegex ( output
, r
'Link File: /run/systemd/network/25-default.link' )
1071 self
. assertRegex ( output
, r
'Network File: /run/systemd/network/11-dummy.network' )
1073 # This test may be run on the system that has older udevd than 70f32a260b5ebb68c19ecadf5d69b3844896ba55 (v249).
1074 # In that case, the udev DB for the loopback network interface may already have ID_NET_LINK_FILE property.
1075 # Let's reprocess the interface and drop the property.
1076 check_output (* udevadm_cmd
, 'trigger' , '--settle' , '--action=add' , '/sys/class/net/lo' )
1077 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'lo' , env
= env
)
1079 self
. assertRegex ( output
, r
'Link File: n/a' )
1080 self
. assertRegex ( output
, r
'Network File: n/a' )
1082 def test_delete_links ( self
):
1083 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' ,
1084 '25-veth.netdev' , '26-netdev-link-local-addressing-yes.network' )
1087 self
. wait_online ([ 'test1:degraded' , 'veth99:degraded' , 'veth-peer:degraded' ])
1089 check_output (* networkctl_cmd
, 'delete' , 'test1' , 'veth99' , env
= env
)
1090 self
. check_link_exists ( 'test1' , expected
= False )
1091 self
. check_link_exists ( 'veth99' , expected
= False )
1092 self
. check_link_exists ( 'veth-peer' , expected
= False )
1094 class NetworkdMatchTests ( unittest
. TestCase
, Utilities
):
1102 @expectedFailureIfAlternativeNameIsNotAvailable ()
1103 def test_match ( self
):
1104 copy_network_unit ( '12-dummy-mac.netdev' ,
1105 '12-dummy-match-mac-01.network' ,
1106 '12-dummy-match-mac-02.network' ,
1107 '12-dummy-match-renamed.network' ,
1108 '12-dummy-match-altname.network' ,
1109 '12-dummy-altname.link' )
1112 self
. wait_online ([ 'dummy98:routable' ])
1113 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
1114 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-mac-01.network' , output
)
1115 output
= check_output ( 'ip -4 address show dev dummy98' )
1116 self
. assertIn ( '10.0.0.1/16' , output
)
1118 check_output ( 'ip link set dev dummy98 down' )
1119 check_output ( 'ip link set dev dummy98 address 12:34:56:78:9a:02' )
1121 self
. wait_address ( 'dummy98' , '10.0.0.2/16' , ipv
= '-4' , timeout_sec
= 10 )
1122 self
. wait_online ([ 'dummy98:routable' ])
1123 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
1124 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-mac-02.network' , output
)
1126 check_output ( 'ip link set dev dummy98 down' )
1127 check_output ( 'ip link set dev dummy98 name dummy98-1' )
1129 self
. wait_address ( 'dummy98-1' , '10.0.1.2/16' , ipv
= '-4' , timeout_sec
= 10 )
1130 self
. wait_online ([ 'dummy98-1:routable' ])
1131 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98-1' , env
= env
)
1132 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-renamed.network' , output
)
1134 check_output ( 'ip link set dev dummy98-1 down' )
1135 check_output ( 'ip link set dev dummy98-1 name dummy98-2' )
1136 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '/sys/class/net/dummy98-2' )
1138 self
. wait_address ( 'dummy98-2' , '10.0.2.2/16' , ipv
= '-4' , timeout_sec
= 10 )
1139 self
. wait_online ([ 'dummy98-2:routable' ])
1140 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98-2' , env
= env
)
1141 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-altname.network' , output
)
1143 def test_match_udev_property ( self
):
1144 copy_network_unit ( '12-dummy.netdev' , '13-not-match-udev-property.network' , '14-match-udev-property.network' )
1146 self
. wait_online ([ 'dummy98:routable' ])
1148 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
1150 self
. assertRegex ( output
, 'Network File: /run/systemd/network/14-match-udev-property' )
1152 class WaitOnlineTests ( unittest
. TestCase
, Utilities
):
1160 def test_wait_online_any ( self
):
1161 copy_network_unit ( '25-bridge.netdev' , '25-bridge.network' , '11-dummy.netdev' , '11-dummy.network' )
1164 self
. wait_online ([ 'bridge99' , 'test1:degraded' ], bool_any
= True )
1166 self
. wait_operstate ( 'bridge99' , '(off|no-carrier)' , setup_state
= 'configuring' )
1167 self
. wait_operstate ( 'test1' , 'degraded' )
1169 class NetworkdNetDevTests ( unittest
. TestCase
, Utilities
):
1177 def test_dropin_and_name_conflict ( self
):
1178 copy_network_unit ( '10-dropin-test.netdev' , '15-name-conflict-test.netdev' )
1181 self
. wait_online ([ 'dropin-test:off' ], setup_state
= 'unmanaged' )
1183 output
= check_output ( 'ip link show dropin-test' )
1185 self
. assertRegex ( output
, '00:50:56:c0:00:28' )
1187 @expectedFailureIfModuleIsNotAvailable ( 'bareudp' )
1188 def test_bareudp ( self
):
1189 copy_network_unit ( '25-bareudp.netdev' , '26-netdev-link-local-addressing-yes.network' )
1192 self
. wait_online ([ 'bareudp99:degraded' ])
1194 output
= check_output ( 'ip -d link show bareudp99' )
1196 self
. assertRegex ( output
, 'dstport 1000 ' )
1197 self
. assertRegex ( output
, 'ethertype ip ' )
1199 @expectedFailureIfModuleIsNotAvailable ( 'batman-adv' )
1200 def test_batadv ( self
):
1201 copy_network_unit ( '25-batadv.netdev' , '26-netdev-link-local-addressing-yes.network' )
1204 self
. wait_online ([ 'batadv99:degraded' ])
1206 output
= check_output ( 'ip -d link show batadv99' )
1208 self
. assertRegex ( output
, 'batadv' )
1210 def test_bridge ( self
):
1211 copy_network_unit ( '25-bridge.netdev' , '25-bridge-configure-without-carrier.network' )
1214 self
. wait_online ([ 'bridge99:no-carrier' ])
1216 tick
= os
. sysconf ( 'SC_CLK_TCK' )
1217 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'hello_time' )) / tick
))
1218 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'max_age' )) / tick
))
1219 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'forward_delay' )) / tick
))
1220 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'ageing_time' )) / tick
))
1221 self
. assertEqual ( 9 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'priority' )))
1222 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_querier' )))
1223 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_snooping' )))
1224 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'stp_state' )))
1225 self
. assertEqual ( 3 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_igmp_version' )))
1227 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bridge99' , env
= env
)
1229 self
. assertRegex ( output
, 'Priority: 9' )
1230 self
. assertRegex ( output
, 'STP: yes' )
1231 self
. assertRegex ( output
, 'Multicast IGMP Version: 3' )
1233 output
= check_output ( 'ip -d link show bridge99' )
1235 self
. assertIn ( 'vlan_filtering 1 ' , output
)
1236 self
. assertIn ( 'vlan_protocol 802.1ad ' , output
)
1237 self
. assertIn ( 'vlan_default_pvid 9 ' , output
)
1239 def test_bond ( self
):
1240 copy_network_unit ( '25-bond.netdev' , '25-bond-balanced-tlb.netdev' )
1243 self
. wait_online ([ 'bond99:off' , 'bond98:off' ], setup_state
= 'unmanaged' )
1245 self
. check_link_attr ( 'bond99' , 'bonding' , 'mode' , '802.3ad 4' )
1246 self
. check_link_attr ( 'bond99' , 'bonding' , 'xmit_hash_policy' , 'layer3+4 1' )
1247 self
. check_link_attr ( 'bond99' , 'bonding' , 'miimon' , '1000' )
1248 self
. check_link_attr ( 'bond99' , 'bonding' , 'lacp_rate' , 'fast 1' )
1249 self
. check_link_attr ( 'bond99' , 'bonding' , 'updelay' , '2000' )
1250 self
. check_link_attr ( 'bond99' , 'bonding' , 'downdelay' , '2000' )
1251 self
. check_link_attr ( 'bond99' , 'bonding' , 'resend_igmp' , '4' )
1252 self
. check_link_attr ( 'bond99' , 'bonding' , 'min_links' , '1' )
1253 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_actor_sys_prio' , '1218' )
1254 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_user_port_key' , '811' )
1255 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_actor_system' , '00:11:22:33:44:55' )
1257 self
. check_link_attr ( 'bond98' , 'bonding' , 'mode' , 'balance-tlb 5' )
1258 self
. check_link_attr ( 'bond98' , 'bonding' , 'tlb_dynamic_lb' , '1' )
1260 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bond99' , env
= env
)
1262 self
. assertIn ( 'Mode: 802.3ad' , output
)
1263 self
. assertIn ( 'Miimon: 1s' , output
)
1264 self
. assertIn ( 'Updelay: 2s' , output
)
1265 self
. assertIn ( 'Downdelay: 2s' , output
)
1267 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bond98' , env
= env
)
1269 self
. assertIn ( 'Mode: balance-tlb' , output
)
1271 def test_vlan ( self
):
1272 copy_network_unit ( '21-vlan.netdev' , '11-dummy.netdev' ,
1273 '21-vlan.network' , '21-vlan-test1.network' )
1276 self
. wait_online ([ 'test1:degraded' , 'vlan99:routable' ])
1278 output
= check_output ( 'ip -d link show test1' )
1280 self
. assertRegex ( output
, ' mtu 2000 ' )
1282 output
= check_output ( 'ip -d link show vlan99' )
1284 self
. assertIn ( ' mtu 2000 ' , output
)
1285 self
. assertIn ( 'REORDER_HDR' , output
)
1286 self
. assertIn ( 'LOOSE_BINDING' , output
)
1287 self
. assertIn ( 'GVRP' , output
)
1288 self
. assertIn ( 'MVRP' , output
)
1289 self
. assertIn ( ' id 99 ' , output
)
1290 self
. assertIn ( 'ingress-qos-map { 4:100 7:13 }' , output
)
1291 self
. assertIn ( 'egress-qos-map { 0:1 1:3 6:6 7:7 10:3 }' , output
)
1293 output
= check_output ( 'ip -4 address show dev test1' )
1295 self
. assertRegex ( output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1' )
1296 self
. assertRegex ( output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1' )
1298 output
= check_output ( 'ip -4 address show dev vlan99' )
1300 self
. assertRegex ( output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99' )
1302 def test_vlan_on_bond ( self
):
1303 # For issue #24377 (https://github.com/systemd/systemd/issues/24377),
1304 # which is fixed by b05e52000b4eee764b383cc3031da0a3739e996e (PR#24020).
1306 copy_network_unit ( '21-bond-802.3ad.netdev' , '21-bond-802.3ad.network' ,
1307 '21-vlan-on-bond.netdev' , '21-vlan-on-bond.network' )
1309 self
. wait_online ([ 'bond99:off' ])
1310 self
. wait_operstate ( 'vlan99' , operstate
= 'off' , setup_state
= 'configuring' , setup_timeout
= 10 )
1312 # The commit b05e52000b4eee764b383cc3031da0a3739e996e adds ", ignoring". To make it easily confirmed
1313 # that the issue is fixed by the commit, let's allow to match both string.
1314 log_re
= re
. compile ( 'vlan99: Could not bring up interface(, ignoring|): Network is down$' , re
. MULTILINE
)
1318 if log_re
. search ( read_networkd_log ()):
1323 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '21-dummy-bond-slave.network' )
1325 self
. wait_online ([ 'test1:enslaved' , 'dummy98:enslaved' , 'bond99:carrier' , 'vlan99:routable' ])
1327 def test_macvtap ( self
):
1329 for mode
in [ 'private' , 'vepa' , 'bridge' , 'passthru' ]:
1335 print ( f
'### test_macvtap(mode= {mode} )' )
1336 with self
. subTest ( mode
= mode
):
1337 copy_network_unit ( '21-macvtap.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1338 '11-dummy.netdev' , '25-macvtap.network' )
1339 with
open ( os
. path
. join ( network_unit_dir
, '21-macvtap.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1340 f
. write ( '[MACVTAP] \n Mode=' + mode
)
1343 self
. wait_online ([ 'macvtap99:degraded' ,
1344 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1346 output
= check_output ( 'ip -d link show macvtap99' )
1348 self
. assertRegex ( output
, 'macvtap mode ' + mode
+ ' ' )
1350 def test_macvlan ( self
):
1352 for mode
in [ 'private' , 'vepa' , 'bridge' , 'passthru' ]:
1358 print ( f
'### test_macvlan(mode= {mode} )' )
1359 with self
. subTest ( mode
= mode
):
1360 copy_network_unit ( '21-macvlan.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1361 '11-dummy.netdev' , '25-macvlan.network' )
1362 with
open ( os
. path
. join ( network_unit_dir
, '21-macvlan.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1363 f
. write ( '[MACVLAN] \n Mode=' + mode
)
1366 self
. wait_online ([ 'macvlan99:degraded' ,
1367 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1369 output
= check_output ( 'ip -d link show test1' )
1371 self
. assertRegex ( output
, ' mtu 2000 ' )
1373 output
= check_output ( 'ip -d link show macvlan99' )
1375 self
. assertRegex ( output
, ' mtu 2000 ' )
1376 self
. assertRegex ( output
, 'macvlan mode ' + mode
+ ' ' )
1378 remove_link ( 'test1' )
1381 check_output ( "ip link add test1 type dummy" )
1382 self
. wait_online ([ 'macvlan99:degraded' ,
1383 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1385 output
= check_output ( 'ip -d link show test1' )
1387 self
. assertRegex ( output
, ' mtu 2000 ' )
1389 output
= check_output ( 'ip -d link show macvlan99' )
1391 self
. assertRegex ( output
, ' mtu 2000 ' )
1392 self
. assertRegex ( output
, 'macvlan mode ' + mode
+ ' ' )
1394 @expectedFailureIfModuleIsNotAvailable ( 'ipvlan' )
1395 def test_ipvlan ( self
):
1397 for mode
, flag
in [[ 'L2' , 'private' ], [ 'L3' , 'vepa' ], [ 'L3S' , 'bridge' ]]:
1403 print ( f
'### test_ipvlan(mode= {mode} , flag= {flag} )' )
1404 with self
. subTest ( mode
= mode
, flag
= flag
):
1405 copy_network_unit ( '25-ipvlan.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1406 '11-dummy.netdev' , '25-ipvlan.network' )
1407 with
open ( os
. path
. join ( network_unit_dir
, '25-ipvlan.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1408 f
. write ( '[IPVLAN] \n Mode=' + mode
+ ' \n Flags=' + flag
)
1411 self
. wait_online ([ 'ipvlan99:degraded' , 'test1:degraded' ])
1413 output
= check_output ( 'ip -d link show ipvlan99' )
1415 self
. assertRegex ( output
, 'ipvlan *mode ' + mode
. lower () + ' ' + flag
)
1417 @expectedFailureIfModuleIsNotAvailable ( 'ipvtap' )
1418 def test_ipvtap ( self
):
1420 for mode
, flag
in [[ 'L2' , 'private' ], [ 'L3' , 'vepa' ], [ 'L3S' , 'bridge' ]]:
1426 print ( f
'### test_ipvtap(mode= {mode} , flag= {flag} )' )
1427 with self
. subTest ( mode
= mode
, flag
= flag
):
1428 copy_network_unit ( '25-ipvtap.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1429 '11-dummy.netdev' , '25-ipvtap.network' )
1430 with
open ( os
. path
. join ( network_unit_dir
, '25-ipvtap.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1431 f
. write ( '[IPVTAP] \n Mode=' + mode
+ ' \n Flags=' + flag
)
1434 self
. wait_online ([ 'ipvtap99:degraded' , 'test1:degraded' ])
1436 output
= check_output ( 'ip -d link show ipvtap99' )
1438 self
. assertRegex ( output
, 'ipvtap *mode ' + mode
. lower () + ' ' + flag
)
1440 def test_veth ( self
):
1441 copy_network_unit ( '25-veth.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1442 '25-veth-mtu.netdev' )
1445 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:degraded' , 'veth-mtu:degraded' , 'veth-mtu-peer:degraded' ])
1447 output
= check_output ( 'ip -d link show veth99' )
1449 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bc' )
1450 output
= check_output ( 'ip -d link show veth-peer' )
1452 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bd' )
1454 output
= check_output ( 'ip -d link show veth-mtu' )
1456 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:be' )
1457 self
. assertRegex ( output
, 'mtu 1800' )
1458 output
= check_output ( 'ip -d link show veth-mtu-peer' )
1460 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bf' )
1461 self
. assertRegex ( output
, 'mtu 1800' )
1463 def test_tuntap ( self
):
1464 copy_network_unit ( '25-tun.netdev' , '25-tap.netdev' , '26-netdev-link-local-addressing-yes.network' )
1467 self
. wait_online ([ 'testtun99:degraded' , 'testtap99:degraded' ])
1469 pid
= networkd_pid ()
1470 name
= psutil
. Process ( pid
). name ()[: 15 ]
1472 output
= check_output ( 'ip -d tuntap show' )
1474 self
. assertRegex ( output
, fr
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1475 self
. assertRegex ( output
, fr
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1477 output
= check_output ( 'ip -d link show testtun99' )
1479 # Old ip command does not support IFF_ flags
1480 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1481 self
. assertIn ( 'UP,LOWER_UP' , output
)
1483 output
= check_output ( 'ip -d link show testtap99' )
1485 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1486 self
. assertIn ( 'UP,LOWER_UP' , output
)
1488 remove_network_unit ( '26-netdev-link-local-addressing-yes.network' )
1491 self
. wait_online ([ 'testtun99:degraded' , 'testtap99:degraded' ], setup_state
= 'unmanaged' )
1493 pid
= networkd_pid ()
1494 name
= psutil
. Process ( pid
). name ()[: 15 ]
1496 output
= check_output ( 'ip -d tuntap show' )
1498 self
. assertRegex ( output
, fr
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1499 self
. assertRegex ( output
, fr
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1501 output
= check_output ( 'ip -d link show testtun99' )
1503 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1504 self
. assertIn ( 'UP,LOWER_UP' , output
)
1506 output
= check_output ( 'ip -d link show testtap99' )
1508 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1509 self
. assertIn ( 'UP,LOWER_UP' , output
)
1511 clear_network_units ()
1513 self
. wait_online ([ 'testtun99:off' , 'testtap99:off' ], setup_state
= 'unmanaged' )
1515 output
= check_output ( 'ip -d tuntap show' )
1517 self
. assertRegex ( output
, r
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$' )
1518 self
. assertRegex ( output
, r
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$' )
1523 output
= check_output ( 'ip -d link show testtun99' )
1525 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1526 if 'NO-CARRIER' in output
:
1534 output
= check_output ( 'ip -d link show testtap99' )
1536 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1537 if 'NO-CARRIER' in output
:
1542 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
1544 copy_network_unit ( '25-vrf.netdev' , '26-netdev-link-local-addressing-yes.network' )
1547 self
. wait_online ([ 'vrf99:carrier' ])
1549 @expectedFailureIfModuleIsNotAvailable ( 'vcan' )
1550 def test_vcan ( self
):
1551 copy_network_unit ( '25-vcan.netdev' , '26-netdev-link-local-addressing-yes.network' )
1554 self
. wait_online ([ 'vcan99:carrier' ])
1556 @expectedFailureIfModuleIsNotAvailable ( 'vxcan' )
1557 def test_vxcan ( self
):
1558 copy_network_unit ( '25-vxcan.netdev' , '26-netdev-link-local-addressing-yes.network' )
1561 self
. wait_online ([ 'vxcan99:carrier' , 'vxcan-peer:carrier' ])
1563 @expectedFailureIfModuleIsNotAvailable ( 'wireguard' )
1564 def test_wireguard ( self
):
1565 copy_network_unit ( '25-wireguard.netdev' , '25-wireguard.network' ,
1566 '25-wireguard-23-peers.netdev' , '25-wireguard-23-peers.network' ,
1567 '25-wireguard-preshared-key.txt' , '25-wireguard-private-key.txt' ,
1568 '25-wireguard-no-peer.netdev' , '25-wireguard-no-peer.network' )
1570 self
. wait_online ([ 'wg99:routable' , 'wg98:routable' , 'wg97:carrier' ])
1572 output
= check_output ( 'ip -4 address show dev wg99' )
1574 self
. assertIn ( 'inet 192.168.124.1/24 scope global wg99' , output
)
1576 output
= check_output ( 'ip -4 address show dev wg99' )
1578 self
. assertIn ( 'inet 169.254.11.1/24 scope link wg99' , output
)
1580 output
= check_output ( 'ip -6 address show dev wg99' )
1582 self
. assertIn ( 'inet6 fe80::1/64 scope link' , output
)
1584 output
= check_output ( 'ip -4 address show dev wg98' )
1586 self
. assertIn ( 'inet 192.168.123.123/24 scope global wg98' , output
)
1588 output
= check_output ( 'ip -6 address show dev wg98' )
1590 self
. assertIn ( 'inet6 fd8d:4d6d:3ccb:500::1/64 scope global' , output
)
1592 output
= check_output ( 'ip -4 route show dev wg99 table 1234' )
1594 self
. assertIn ( '192.168.26.0/24 proto static metric 123' , output
)
1596 output
= check_output ( 'ip -6 route show dev wg99 table 1234' )
1598 self
. assertIn ( 'fd31:bf08:57cb::/48 proto static metric 123 pref medium' , output
)
1600 output
= check_output ( 'ip -6 route show dev wg98 table 1234' )
1602 self
. assertIn ( 'fd8d:4d6d:3ccb:500:c79:2339:edce:ece1 proto static metric 123 pref medium' , output
)
1603 self
. assertIn ( 'fd8d:4d6d:3ccb:500:1dbf:ca8a:32d3:dd81 proto static metric 123 pref medium' , output
)
1604 self
. assertIn ( 'fd8d:4d6d:3ccb:500:1e54:1415:35d0:a47c proto static metric 123 pref medium' , output
)
1605 self
. assertIn ( 'fd8d:4d6d:3ccb:500:270d:b5dd:4a3f:8909 proto static metric 123 pref medium' , output
)
1606 self
. assertIn ( 'fd8d:4d6d:3ccb:500:5660:679d:3532:94d8 proto static metric 123 pref medium' , output
)
1607 self
. assertIn ( 'fd8d:4d6d:3ccb:500:6825:573f:30f3:9472 proto static metric 123 pref medium' , output
)
1608 self
. assertIn ( 'fd8d:4d6d:3ccb:500:6f2e:6888:c6fd:dfb9 proto static metric 123 pref medium' , output
)
1609 self
. assertIn ( 'fd8d:4d6d:3ccb:500:8d4d:bab:7280:a09a proto static metric 123 pref medium' , output
)
1610 self
. assertIn ( 'fd8d:4d6d:3ccb:500:900c:d437:ec27:8822 proto static metric 123 pref medium' , output
)
1611 self
. assertIn ( 'fd8d:4d6d:3ccb:500:9742:9931:5217:18d5 proto static metric 123 pref medium' , output
)
1612 self
. assertIn ( 'fd8d:4d6d:3ccb:500:9c11:d820:2e96:9be0 proto static metric 123 pref medium' , output
)
1613 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a072:80da:de4f:add1 proto static metric 123 pref medium' , output
)
1614 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a3f3:df38:19b0:721 proto static metric 123 pref medium' , output
)
1615 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a94b:cd6a:a32d:90e6 proto static metric 123 pref medium' , output
)
1616 self
. assertIn ( 'fd8d:4d6d:3ccb:500:b39c:9cdc:755a:ead3 proto static metric 123 pref medium' , output
)
1617 self
. assertIn ( 'fd8d:4d6d:3ccb:500:b684:4f81:2e3e:132e proto static metric 123 pref medium' , output
)
1618 self
. assertIn ( 'fd8d:4d6d:3ccb:500:bad5:495d:8e9c:3427 proto static metric 123 pref medium' , output
)
1619 self
. assertIn ( 'fd8d:4d6d:3ccb:500:bfe5:c3c3:5d77:fcb proto static metric 123 pref medium' , output
)
1620 self
. assertIn ( 'fd8d:4d6d:3ccb:500:c624:6bf7:4c09:3b59 proto static metric 123 pref medium' , output
)
1621 self
. assertIn ( 'fd8d:4d6d:3ccb:500:d4f9:5dc:9296:a1a proto static metric 123 pref medium' , output
)
1622 self
. assertIn ( 'fd8d:4d6d:3ccb:500:dcdd:d33b:90c9:6088 proto static metric 123 pref medium' , output
)
1623 self
. assertIn ( 'fd8d:4d6d:3ccb:500:e2e1:ae15:103f:f376 proto static metric 123 pref medium' , output
)
1624 self
. assertIn ( 'fd8d:4d6d:3ccb:500:f349:c4f0:10c1:6b4 proto static metric 123 pref medium' , output
)
1625 self
. assertIn ( 'fd8d:4d6d:3ccb:c79:2339:edce::/96 proto static metric 123 pref medium' , output
)
1626 self
. assertIn ( 'fd8d:4d6d:3ccb:1dbf:ca8a:32d3::/96 proto static metric 123 pref medium' , output
)
1627 self
. assertIn ( 'fd8d:4d6d:3ccb:1e54:1415:35d0::/96 proto static metric 123 pref medium' , output
)
1628 self
. assertIn ( 'fd8d:4d6d:3ccb:270d:b5dd:4a3f::/96 proto static metric 123 pref medium' , output
)
1629 self
. assertIn ( 'fd8d:4d6d:3ccb:5660:679d:3532::/96 proto static metric 123 pref medium' , output
)
1630 self
. assertIn ( 'fd8d:4d6d:3ccb:6825:573f:30f3::/96 proto static metric 123 pref medium' , output
)
1631 self
. assertIn ( 'fd8d:4d6d:3ccb:6f2e:6888:c6fd::/96 proto static metric 123 pref medium' , output
)
1632 self
. assertIn ( 'fd8d:4d6d:3ccb:8d4d:bab:7280::/96 proto static metric 123 pref medium' , output
)
1633 self
. assertIn ( 'fd8d:4d6d:3ccb:900c:d437:ec27::/96 proto static metric 123 pref medium' , output
)
1634 self
. assertIn ( 'fd8d:4d6d:3ccb:9742:9931:5217::/96 proto static metric 123 pref medium' , output
)
1635 self
. assertIn ( 'fd8d:4d6d:3ccb:9c11:d820:2e96::/96 proto static metric 123 pref medium' , output
)
1636 self
. assertIn ( 'fd8d:4d6d:3ccb:a072:80da:de4f::/96 proto static metric 123 pref medium' , output
)
1637 self
. assertIn ( 'fd8d:4d6d:3ccb:a3f3:df38:19b0::/96 proto static metric 123 pref medium' , output
)
1638 self
. assertIn ( 'fd8d:4d6d:3ccb:a94b:cd6a:a32d::/96 proto static metric 123 pref medium' , output
)
1639 self
. assertIn ( 'fd8d:4d6d:3ccb:b39c:9cdc:755a::/96 proto static metric 123 pref medium' , output
)
1640 self
. assertIn ( 'fd8d:4d6d:3ccb:b684:4f81:2e3e::/96 proto static metric 123 pref medium' , output
)
1641 self
. assertIn ( 'fd8d:4d6d:3ccb:bad5:495d:8e9c::/96 proto static metric 123 pref medium' , output
)
1642 self
. assertIn ( 'fd8d:4d6d:3ccb:bfe5:c3c3:5d77::/96 proto static metric 123 pref medium' , output
)
1643 self
. assertIn ( 'fd8d:4d6d:3ccb:c624:6bf7:4c09::/96 proto static metric 123 pref medium' , output
)
1644 self
. assertIn ( 'fd8d:4d6d:3ccb:d4f9:5dc:9296::/96 proto static metric 123 pref medium' , output
)
1645 self
. assertIn ( 'fd8d:4d6d:3ccb:dcdd:d33b:90c9::/96 proto static metric 123 pref medium' , output
)
1646 self
. assertIn ( 'fd8d:4d6d:3ccb:e2e1:ae15:103f::/96 proto static metric 123 pref medium' , output
)
1647 self
. assertIn ( 'fd8d:4d6d:3ccb:f349:c4f0:10c1::/96 proto static metric 123 pref medium' , output
)
1649 if shutil
. which ( 'wg' ):
1652 output
= check_output ( 'wg show wg99 listen-port' )
1653 self
. assertEqual ( output
, '51820' )
1654 output
= check_output ( 'wg show wg99 fwmark' )
1655 self
. assertEqual ( output
, '0x4d2' )
1656 output
= check_output ( 'wg show wg99 private-key' )
1657 self
. assertEqual ( output
, 'EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=' )
1658 output
= check_output ( 'wg show wg99 allowed-ips' )
1659 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t 192.168.124.3/32' , output
)
1660 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t 192.168.124.2/32' , output
)
1661 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t fdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128' , output
)
1662 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 192.168.26.0/24 fd31:bf08:57cb::/48' , output
)
1663 output
= check_output ( 'wg show wg99 persistent-keepalive' )
1664 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t off' , output
)
1665 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t off' , output
)
1666 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t off' , output
)
1667 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 20' , output
)
1668 output
= check_output ( 'wg show wg99 endpoints' )
1669 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t (none)' , output
)
1670 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t (none)' , output
)
1671 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t (none)' , output
)
1672 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 192.168.27.3:51820' , output
)
1673 output
= check_output ( 'wg show wg99 preshared-keys' )
1674 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t 6Fsg8XN0DE6aPQgAX4r2oazEYJOGqyHUz3QRH/jCB+I=' , output
)
1675 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t it7nd33chCT/tKT2ZZWfYyp43Zs+6oif72hexnSNMqA=' , output
)
1676 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=' , output
)
1677 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=' , output
)
1679 output
= check_output ( 'wg show wg98 private-key' )
1680 self
. assertEqual ( output
, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr+WHtZLZ90FU=' )
1682 output
= check_output ( 'wg show wg97 listen-port' )
1683 self
. assertEqual ( output
, '51821' )
1684 output
= check_output ( 'wg show wg97 fwmark' )
1685 self
. assertEqual ( output
, '0x4d3' )
1687 def test_geneve ( self
):
1688 copy_network_unit ( '25-geneve.netdev' , '26-netdev-link-local-addressing-yes.network' )
1691 self
. wait_online ([ 'geneve99:degraded' ])
1693 output
= check_output ( 'ip -d link show geneve99' )
1695 self
. assertRegex ( output
, '192.168.22.1' )
1696 self
. assertRegex ( output
, '6082' )
1697 self
. assertRegex ( output
, 'udpcsum' )
1698 self
. assertRegex ( output
, 'udp6zerocsumrx' )
1700 def test_ipip_tunnel ( self
):
1701 copy_network_unit ( '12-dummy.netdev' , '25-ipip.network' ,
1702 '25-ipip-tunnel.netdev' , '25-tunnel.network' ,
1703 '25-ipip-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1704 '25-ipip-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1705 '25-ipip-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1707 self
. wait_online ([ 'ipiptun99:routable' , 'ipiptun98:routable' , 'ipiptun97:routable' , 'ipiptun96:routable' , 'dummy98:degraded' ])
1709 output
= check_output ( 'ip -d link show ipiptun99' )
1711 self
. assertRegex ( output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98' )
1712 output
= check_output ( 'ip -d link show ipiptun98' )
1714 self
. assertRegex ( output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98' )
1715 output
= check_output ( 'ip -d link show ipiptun97' )
1717 self
. assertRegex ( output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98' )
1718 output
= check_output ( 'ip -d link show ipiptun96' )
1720 self
. assertRegex ( output
, 'ipip (ipip )?remote any local any dev dummy98' )
1722 def test_gre_tunnel ( self
):
1723 copy_network_unit ( '12-dummy.netdev' , '25-gretun.network' ,
1724 '25-gre-tunnel.netdev' , '25-tunnel.network' ,
1725 '25-gre-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1726 '25-gre-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1727 '25-gre-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1729 self
. wait_online ([ 'gretun99:routable' , 'gretun98:routable' , 'gretun97:routable' , 'gretun96:routable' , 'dummy98:degraded' ])
1731 output
= check_output ( 'ip -d link show gretun99' )
1733 self
. assertRegex ( output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1734 self
. assertRegex ( output
, 'ikey 1.2.3.103' )
1735 self
. assertRegex ( output
, 'okey 1.2.4.103' )
1736 self
. assertRegex ( output
, 'iseq' )
1737 self
. assertRegex ( output
, 'oseq' )
1738 output
= check_output ( 'ip -d link show gretun98' )
1740 self
. assertRegex ( output
, 'gre remote 10.65.223.239 local any dev dummy98' )
1741 self
. assertRegex ( output
, 'ikey 0.0.0.104' )
1742 self
. assertRegex ( output
, 'okey 0.0.0.104' )
1743 self
. assertNotRegex ( output
, 'iseq' )
1744 self
. assertNotRegex ( output
, 'oseq' )
1745 output
= check_output ( 'ip -d link show gretun97' )
1747 self
. assertRegex ( output
, 'gre remote any local 10.65.223.238 dev dummy98' )
1748 self
. assertRegex ( output
, 'ikey 0.0.0.105' )
1749 self
. assertRegex ( output
, 'okey 0.0.0.105' )
1750 self
. assertNotRegex ( output
, 'iseq' )
1751 self
. assertNotRegex ( output
, 'oseq' )
1752 output
= check_output ( 'ip -d link show gretun96' )
1754 self
. assertRegex ( output
, 'gre remote any local any dev dummy98' )
1755 self
. assertRegex ( output
, 'ikey 0.0.0.106' )
1756 self
. assertRegex ( output
, 'okey 0.0.0.106' )
1757 self
. assertNotRegex ( output
, 'iseq' )
1758 self
. assertNotRegex ( output
, 'oseq' )
1760 def test_ip6gre_tunnel ( self
):
1761 copy_network_unit ( '12-dummy.netdev' , '25-ip6gretun.network' ,
1762 '25-ip6gre-tunnel.netdev' , '25-tunnel.network' ,
1763 '25-ip6gre-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1764 '25-ip6gre-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1765 '25-ip6gre-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1768 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1770 self
. wait_links ( 'dummy98' , 'ip6gretun99' , 'ip6gretun98' , 'ip6gretun97' , 'ip6gretun96' )
1772 output
= check_output ( 'ip -d link show ip6gretun99' )
1774 self
. assertRegex ( output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1775 output
= check_output ( 'ip -d link show ip6gretun98' )
1777 self
. assertRegex ( output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98' )
1778 output
= check_output ( 'ip -d link show ip6gretun97' )
1780 self
. assertRegex ( output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98' )
1781 output
= check_output ( 'ip -d link show ip6gretun96' )
1783 self
. assertRegex ( output
, 'ip6gre remote any local any dev dummy98' )
1785 def test_gretap_tunnel ( self
):
1786 copy_network_unit ( '12-dummy.netdev' , '25-gretap.network' ,
1787 '25-gretap-tunnel.netdev' , '25-tunnel.network' ,
1788 '25-gretap-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1790 self
. wait_online ([ 'gretap99:routable' , 'gretap98:routable' , 'dummy98:degraded' ])
1792 output
= check_output ( 'ip -d link show gretap99' )
1794 self
. assertRegex ( output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1795 self
. assertRegex ( output
, 'ikey 0.0.0.106' )
1796 self
. assertRegex ( output
, 'okey 0.0.0.106' )
1797 self
. assertRegex ( output
, 'iseq' )
1798 self
. assertRegex ( output
, 'oseq' )
1799 output
= check_output ( 'ip -d link show gretap98' )
1801 self
. assertRegex ( output
, 'gretap remote 10.65.223.239 local any dev dummy98' )
1802 self
. assertRegex ( output
, 'ikey 0.0.0.107' )
1803 self
. assertRegex ( output
, 'okey 0.0.0.107' )
1804 self
. assertRegex ( output
, 'iseq' )
1805 self
. assertRegex ( output
, 'oseq' )
1807 def test_ip6gretap_tunnel ( self
):
1808 copy_network_unit ( '12-dummy.netdev' , '25-ip6gretap.network' ,
1809 '25-ip6gretap-tunnel.netdev' , '25-tunnel.network' ,
1810 '25-ip6gretap-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1812 self
. wait_online ([ 'ip6gretap99:routable' , 'ip6gretap98:routable' , 'dummy98:degraded' ])
1814 output
= check_output ( 'ip -d link show ip6gretap99' )
1816 self
. assertRegex ( output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1817 output
= check_output ( 'ip -d link show ip6gretap98' )
1819 self
. assertRegex ( output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98' )
1821 def test_vti_tunnel ( self
):
1822 copy_network_unit ( '12-dummy.netdev' , '25-vti.network' ,
1823 '25-vti-tunnel.netdev' , '25-tunnel.network' ,
1824 '25-vti-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1825 '25-vti-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1826 '25-vti-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1828 self
. wait_online ([ 'vtitun99:routable' , 'vtitun98:routable' , 'vtitun97:routable' , 'vtitun96:routable' , 'dummy98:degraded' ])
1830 output
= check_output ( 'ip -d link show vtitun99' )
1832 self
. assertRegex ( output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1833 output
= check_output ( 'ip -d link show vtitun98' )
1835 self
. assertRegex ( output
, 'vti remote 10.65.223.239 local any dev dummy98' )
1836 output
= check_output ( 'ip -d link show vtitun97' )
1838 self
. assertRegex ( output
, 'vti remote any local 10.65.223.238 dev dummy98' )
1839 output
= check_output ( 'ip -d link show vtitun96' )
1841 self
. assertRegex ( output
, 'vti remote any local any dev dummy98' )
1843 def test_vti6_tunnel ( self
):
1844 copy_network_unit ( '12-dummy.netdev' , '25-vti6.network' ,
1845 '25-vti6-tunnel.netdev' , '25-tunnel.network' ,
1846 '25-vti6-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1847 '25-vti6-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' )
1849 self
. wait_online ([ 'vti6tun99:routable' , 'vti6tun98:routable' , 'vti6tun97:routable' , 'dummy98:degraded' ])
1851 output
= check_output ( 'ip -d link show vti6tun99' )
1853 self
. assertRegex ( output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1854 output
= check_output ( 'ip -d link show vti6tun98' )
1856 self
. assertRegex ( output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98' )
1857 output
= check_output ( 'ip -d link show vti6tun97' )
1859 self
. assertRegex ( output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98' )
1861 def test_ip6tnl_tunnel ( self
):
1862 copy_network_unit ( '12-dummy.netdev' , '25-ip6tnl.network' ,
1863 '25-ip6tnl-tunnel.netdev' , '25-tunnel.network' ,
1864 '25-ip6tnl-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1865 '25-ip6tnl-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1866 '25-veth.netdev' , '25-ip6tnl-slaac.network' , '25-ipv6-prefix.network' ,
1867 '25-ip6tnl-tunnel-local-slaac.netdev' , '25-ip6tnl-tunnel-local-slaac.network' ,
1868 '25-ip6tnl-tunnel-external.netdev' , '26-netdev-link-local-addressing-yes.network' )
1870 self
. wait_online ([ 'ip6tnl99:routable' , 'ip6tnl98:routable' , 'ip6tnl97:routable' ,
1871 'ip6tnl-slaac:degraded' , 'ip6tnl-external:degraded' ,
1872 'dummy98:degraded' , 'veth99:routable' , 'veth-peer:degraded' ])
1874 output
= check_output ( 'ip -d link show ip6tnl99' )
1876 self
. assertIn ( 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' , output
)
1877 output
= check_output ( 'ip -d link show ip6tnl98' )
1879 self
. assertRegex ( output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98' )
1880 output
= check_output ( 'ip -d link show ip6tnl97' )
1882 self
. assertRegex ( output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98' )
1883 output
= check_output ( 'ip -d link show ip6tnl-external' )
1885 self
. assertIn ( 'ip6tnl-external@NONE:' , output
)
1886 self
. assertIn ( 'ip6tnl external ' , output
)
1887 output
= check_output ( 'ip -d link show ip6tnl-slaac' )
1889 self
. assertIn ( 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99' , output
)
1891 output
= check_output ( 'ip -6 address show veth99' )
1893 self
. assertIn ( 'inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic' , output
)
1895 output
= check_output ( 'ip -4 route show default' )
1897 self
. assertIn ( 'default dev ip6tnl-slaac proto static' , output
)
1899 def test_sit_tunnel ( self
):
1900 copy_network_unit ( '12-dummy.netdev' , '25-sit.network' ,
1901 '25-sit-tunnel.netdev' , '25-tunnel.network' ,
1902 '25-sit-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1903 '25-sit-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1904 '25-sit-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1906 self
. wait_online ([ 'sittun99:routable' , 'sittun98:routable' , 'sittun97:routable' , 'sittun96:routable' , 'dummy98:degraded' ])
1908 output
= check_output ( 'ip -d link show sittun99' )
1910 self
. assertRegex ( output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98" )
1911 output
= check_output ( 'ip -d link show sittun98' )
1913 self
. assertRegex ( output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98" )
1914 output
= check_output ( 'ip -d link show sittun97' )
1916 self
. assertRegex ( output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98" )
1917 output
= check_output ( 'ip -d link show sittun96' )
1919 self
. assertRegex ( output
, "sit (ip6ip )?remote any local any dev dummy98" )
1921 def test_isatap_tunnel ( self
):
1922 copy_network_unit ( '12-dummy.netdev' , '25-isatap.network' ,
1923 '25-isatap-tunnel.netdev' , '25-tunnel.network' )
1925 self
. wait_online ([ 'isataptun99:routable' , 'dummy98:degraded' ])
1927 output
= check_output ( 'ip -d link show isataptun99' )
1929 self
. assertRegex ( output
, "isatap " )
1931 def test_6rd_tunnel ( self
):
1932 copy_network_unit ( '12-dummy.netdev' , '25-6rd.network' ,
1933 '25-6rd-tunnel.netdev' , '25-tunnel.network' )
1935 self
. wait_online ([ 'sittun99:routable' , 'dummy98:degraded' ])
1937 output
= check_output ( 'ip -d link show sittun99' )
1939 self
. assertRegex ( output
, '6rd-prefix 2602::/24' )
1941 @expectedFailureIfERSPANv0IsNotSupported ()
1942 def test_erspan_tunnel_v0 ( self
):
1943 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
1944 '25-erspan0-tunnel.netdev' , '25-tunnel.network' ,
1945 '25-erspan0-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1947 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
1949 output
= check_output ( 'ip -d link show erspan99' )
1951 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
1952 self
. assertIn ( 'erspan_ver 0' , output
)
1953 self
. assertNotIn ( 'erspan_index 123' , output
)
1954 self
. assertNotIn ( 'erspan_dir ingress' , output
)
1955 self
. assertNotIn ( 'erspan_hwid 1f' , output
)
1956 self
. assertIn ( 'ikey 0.0.0.101' , output
)
1957 self
. assertIn ( 'iseq' , output
)
1958 output
= check_output ( 'ip -d link show erspan98' )
1960 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
1961 self
. assertIn ( 'erspan_ver 0' , output
)
1962 self
. assertNotIn ( 'erspan_index 124' , output
)
1963 self
. assertNotIn ( 'erspan_dir egress' , output
)
1964 self
. assertNotIn ( 'erspan_hwid 2f' , output
)
1965 self
. assertIn ( 'ikey 0.0.0.102' , output
)
1966 self
. assertIn ( 'iseq' , output
)
1968 def test_erspan_tunnel_v1 ( self
):
1969 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
1970 '25-erspan1-tunnel.netdev' , '25-tunnel.network' ,
1971 '25-erspan1-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1973 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
1975 output
= check_output ( 'ip -d link show erspan99' )
1977 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
1978 self
. assertIn ( 'erspan_ver 1' , output
)
1979 self
. assertIn ( 'erspan_index 123' , output
)
1980 self
. assertNotIn ( 'erspan_dir ingress' , output
)
1981 self
. assertNotIn ( 'erspan_hwid 1f' , output
)
1982 self
. assertIn ( 'ikey 0.0.0.101' , output
)
1983 self
. assertIn ( 'okey 0.0.0.101' , output
)
1984 self
. assertIn ( 'iseq' , output
)
1985 self
. assertIn ( 'oseq' , output
)
1986 output
= check_output ( 'ip -d link show erspan98' )
1988 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
1989 self
. assertIn ( 'erspan_ver 1' , output
)
1990 self
. assertIn ( 'erspan_index 124' , output
)
1991 self
. assertNotIn ( 'erspan_dir egress' , output
)
1992 self
. assertNotIn ( 'erspan_hwid 2f' , output
)
1993 self
. assertIn ( 'ikey 0.0.0.102' , output
)
1994 self
. assertIn ( 'okey 0.0.0.102' , output
)
1995 self
. assertIn ( 'iseq' , output
)
1996 self
. assertIn ( 'oseq' , output
)
1998 @expectedFailureIfERSPANv2IsNotSupported ()
1999 def test_erspan_tunnel_v2 ( self
):
2000 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
2001 '25-erspan2-tunnel.netdev' , '25-tunnel.network' ,
2002 '25-erspan2-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
2004 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
2006 output
= check_output ( 'ip -d link show erspan99' )
2008 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
2009 self
. assertIn ( 'erspan_ver 2' , output
)
2010 self
. assertNotIn ( 'erspan_index 123' , output
)
2011 self
. assertIn ( 'erspan_dir ingress' , output
)
2012 self
. assertIn ( 'erspan_hwid 0x1f' , output
)
2013 self
. assertIn ( 'ikey 0.0.0.101' , output
)
2014 self
. assertIn ( 'okey 0.0.0.101' , output
)
2015 self
. assertIn ( 'iseq' , output
)
2016 self
. assertIn ( 'oseq' , output
)
2017 output
= check_output ( 'ip -d link show erspan98' )
2019 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
2020 self
. assertIn ( 'erspan_ver 2' , output
)
2021 self
. assertNotIn ( 'erspan_index 124' , output
)
2022 self
. assertIn ( 'erspan_dir egress' , output
)
2023 self
. assertIn ( 'erspan_hwid 0x2f' , output
)
2024 self
. assertIn ( 'ikey 0.0.0.102' , output
)
2025 self
. assertIn ( 'okey 0.0.0.102' , output
)
2026 self
. assertIn ( 'iseq' , output
)
2027 self
. assertIn ( 'oseq' , output
)
2029 def test_tunnel_independent ( self
):
2030 copy_network_unit ( '25-ipip-tunnel-independent.netdev' , '26-netdev-link-local-addressing-yes.network' )
2033 self
. wait_online ([ 'ipiptun99:carrier' ])
2035 def test_tunnel_independent_loopback ( self
):
2036 copy_network_unit ( '25-ipip-tunnel-independent-loopback.netdev' , '26-netdev-link-local-addressing-yes.network' )
2039 self
. wait_online ([ 'ipiptun99:carrier' ])
2041 @expectedFailureIfModuleIsNotAvailable ( 'xfrm_interface' )
2042 def test_xfrm ( self
):
2043 copy_network_unit ( '12-dummy.netdev' , '25-xfrm.network' ,
2044 '25-xfrm.netdev' , '25-xfrm-independent.netdev' ,
2045 '26-netdev-link-local-addressing-yes.network' )
2048 self
. wait_online ([ 'dummy98:degraded' , 'xfrm98:degraded' , 'xfrm99:degraded' ])
2050 output
= check_output ( 'ip -d link show dev xfrm98' )
2052 self
. assertIn ( 'xfrm98@dummy98:' , output
)
2053 self
. assertIn ( 'xfrm if_id 0x98 ' , output
)
2055 output
= check_output ( 'ip -d link show dev xfrm99' )
2057 self
. assertIn ( 'xfrm99@lo:' , output
)
2058 self
. assertIn ( 'xfrm if_id 0x99 ' , output
)
2060 @expectedFailureIfModuleIsNotAvailable ( 'fou' )
2062 # The following redundant check is necessary for CentOS CI.
2063 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
2064 self
. assertTrue ( is_module_available ( 'fou' ))
2066 copy_network_unit ( '25-fou-ipproto-ipip.netdev' , '25-fou-ipproto-gre.netdev' ,
2067 '25-fou-ipip.netdev' , '25-fou-sit.netdev' ,
2068 '25-fou-gre.netdev' , '25-fou-gretap.netdev' )
2071 self
. wait_online ([ 'ipiptun96:off' , 'sittun96:off' , 'gretun96:off' , 'gretap96:off' ], setup_state
= 'unmanaged' )
2073 output
= check_output ( 'ip fou show' )
2075 self
. assertRegex ( output
, 'port 55555 ipproto 4' )
2076 self
. assertRegex ( output
, 'port 55556 ipproto 47' )
2078 output
= check_output ( 'ip -d link show ipiptun96' )
2080 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55555' )
2081 output
= check_output ( 'ip -d link show sittun96' )
2083 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55555' )
2084 output
= check_output ( 'ip -d link show gretun96' )
2086 self
. assertRegex ( output
, 'encap fou encap-sport 1001 encap-dport 55556' )
2087 output
= check_output ( 'ip -d link show gretap96' )
2089 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55556' )
2091 def test_vxlan ( self
):
2092 copy_network_unit ( '11-dummy.netdev' , '25-vxlan-test1.network' ,
2093 '25-vxlan.netdev' , '25-vxlan.network' ,
2094 '25-vxlan-ipv6.netdev' , '25-vxlan-ipv6.network' ,
2095 '25-vxlan-independent.netdev' , '26-netdev-link-local-addressing-yes.network' ,
2096 '25-veth.netdev' , '25-vxlan-veth99.network' , '25-ipv6-prefix.network' ,
2097 '25-vxlan-local-slaac.netdev' , '25-vxlan-local-slaac.network' )
2100 self
. wait_online ([ 'test1:degraded' , 'veth99:routable' , 'veth-peer:degraded' ,
2101 'vxlan99:degraded' , 'vxlan98:degraded' , 'vxlan97:degraded' , 'vxlan-slaac:degraded' ])
2103 output
= check_output ( 'ip -d link show vxlan99' )
2105 self
. assertIn ( '999' , output
)
2106 self
. assertIn ( '5555' , output
)
2107 self
. assertIn ( 'l2miss' , output
)
2108 self
. assertIn ( 'l3miss' , output
)
2109 self
. assertIn ( 'udpcsum' , output
)
2110 self
. assertIn ( 'udp6zerocsumtx' , output
)
2111 self
. assertIn ( 'udp6zerocsumrx' , output
)
2112 self
. assertIn ( 'remcsumtx' , output
)
2113 self
. assertIn ( 'remcsumrx' , output
)
2114 self
. assertIn ( 'gbp' , output
)
2116 output
= check_output ( 'bridge fdb show dev vxlan99' )
2118 self
. assertIn ( '00:11:22:33:44:55 dst 10.0.0.5 self permanent' , output
)
2119 self
. assertIn ( '00:11:22:33:44:66 dst 10.0.0.6 self permanent' , output
)
2120 self
. assertIn ( '00:11:22:33:44:77 dst 10.0.0.7 via test1 self permanent' , output
)
2122 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'vxlan99' , env
= env
)
2124 self
. assertIn ( 'VNI: 999' , output
)
2125 self
. assertIn ( 'Destination Port: 5555' , output
)
2126 self
. assertIn ( 'Underlying Device: test1' , output
)
2128 output
= check_output ( 'bridge fdb show dev vxlan97' )
2130 self
. assertIn ( '00:00:00:00:00:00 dst fe80::23b:d2ff:fe95:967f via test1 self permanent' , output
)
2131 self
. assertIn ( '00:00:00:00:00:00 dst fe80::27c:16ff:fec0:6c74 via test1 self permanent' , output
)
2132 self
. assertIn ( '00:00:00:00:00:00 dst fe80::2a2:e4ff:fef9:2269 via test1 self permanent' , output
)
2134 output
= check_output ( 'ip -d link show vxlan-slaac' )
2136 self
. assertIn ( 'vxlan id 4831584 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99' , output
)
2138 output
= check_output ( 'ip -6 address show veth99' )
2140 self
. assertIn ( 'inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic' , output
)
2142 @unittest . skipUnless ( compare_kernel_version ( "6" ), reason
= "Causes kernel panic on unpatched kernels: https://bugzilla.kernel.org/show_bug.cgi?id=208315" )
2143 def test_macsec ( self
):
2144 copy_network_unit ( '25-macsec.netdev' , '25-macsec.network' , '25-macsec.key' ,
2145 '26-macsec.network' , '12-dummy.netdev' )
2148 self
. wait_online ([ 'dummy98:degraded' , 'macsec99:routable' ])
2150 output
= check_output ( 'ip -d link show macsec99' )
2152 self
. assertRegex ( output
, 'macsec99@dummy98' )
2153 self
. assertRegex ( output
, 'macsec sci [0-9a-f]*000b' )
2154 self
. assertRegex ( output
, 'encrypt on' )
2156 output
= check_output ( 'ip macsec show macsec99' )
2158 self
. assertRegex ( output
, 'encrypt on' )
2159 self
. assertRegex ( output
, 'TXSC: [0-9a-f]*000b on SA 1' )
2160 self
. assertRegex ( output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000' )
2161 self
. assertRegex ( output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000' )
2162 self
. assertRegex ( output
, 'RXSC: c619528fe6a00100, state on' )
2163 self
. assertRegex ( output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000' )
2164 self
. assertRegex ( output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000' )
2165 self
. assertRegex ( output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000' )
2166 self
. assertRegex ( output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000' )
2167 self
. assertNotRegex ( output
, 'key 02030405067080900000000000000000' )
2168 self
. assertRegex ( output
, 'RXSC: 8c16456c83a90002, state on' )
2169 self
. assertRegex ( output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000' )
2171 def test_nlmon ( self
):
2172 copy_network_unit ( '25-nlmon.netdev' , '26-netdev-link-local-addressing-yes.network' )
2175 self
. wait_online ([ 'nlmon99:carrier' ])
2177 @expectedFailureIfModuleIsNotAvailable ( 'ifb' )
2179 copy_network_unit ( '25-ifb.netdev' , '26-netdev-link-local-addressing-yes.network' )
2182 self
. wait_online ([ 'ifb99:degraded' ])
2184 class NetworkdL2TPTests ( unittest
. TestCase
, Utilities
):
2192 @expectedFailureIfModuleIsNotAvailable ( 'l2tp_eth' , 'l2tp_netlink' )
2193 def test_l2tp_udp ( self
):
2194 copy_network_unit ( '11-dummy.netdev' , '25-l2tp-dummy.network' ,
2195 '25-l2tp-udp.netdev' , '25-l2tp.network' )
2198 self
. wait_online ([ 'test1:routable' , 'l2tp-ses1:degraded' , 'l2tp-ses2:degraded' ])
2200 output
= check_output ( 'ip l2tp show tunnel tunnel_id 10' )
2202 self
. assertRegex ( output
, "Tunnel 10, encap UDP" )
2203 self
. assertRegex ( output
, "From 192.168.30.100 to 192.168.30.101" )
2204 self
. assertRegex ( output
, "Peer tunnel 11" )
2205 self
. assertRegex ( output
, "UDP source / dest ports: 3000/4000" )
2206 self
. assertRegex ( output
, "UDP checksum: enabled" )
2208 output
= check_output ( 'ip l2tp show session tid 10 session_id 15' )
2210 self
. assertRegex ( output
, "Session 15 in tunnel 10" )
2211 self
. assertRegex ( output
, "Peer session 16, tunnel 11" )
2212 self
. assertRegex ( output
, "interface name: l2tp-ses1" )
2214 output
= check_output ( 'ip l2tp show session tid 10 session_id 17' )
2216 self
. assertRegex ( output
, "Session 17 in tunnel 10" )
2217 self
. assertRegex ( output
, "Peer session 18, tunnel 11" )
2218 self
. assertRegex ( output
, "interface name: l2tp-ses2" )
2220 @expectedFailureIfModuleIsNotAvailable ( 'l2tp_eth' , 'l2tp_ip' , 'l2tp_netlink' )
2221 def test_l2tp_ip ( self
):
2222 copy_network_unit ( '11-dummy.netdev' , '25-l2tp-dummy.network' ,
2223 '25-l2tp-ip.netdev' , '25-l2tp.network' )
2226 self
. wait_online ([ 'test1:routable' , 'l2tp-ses3:degraded' , 'l2tp-ses4:degraded' ])
2228 output
= check_output ( 'ip l2tp show tunnel tunnel_id 10' )
2230 self
. assertRegex ( output
, "Tunnel 10, encap IP" )
2231 self
. assertRegex ( output
, "From 192.168.30.100 to 192.168.30.101" )
2232 self
. assertRegex ( output
, "Peer tunnel 12" )
2234 output
= check_output ( 'ip l2tp show session tid 10 session_id 25' )
2236 self
. assertRegex ( output
, "Session 25 in tunnel 10" )
2237 self
. assertRegex ( output
, "Peer session 26, tunnel 12" )
2238 self
. assertRegex ( output
, "interface name: l2tp-ses3" )
2240 output
= check_output ( 'ip l2tp show session tid 10 session_id 27' )
2242 self
. assertRegex ( output
, "Session 27 in tunnel 10" )
2243 self
. assertRegex ( output
, "Peer session 28, tunnel 12" )
2244 self
. assertRegex ( output
, "interface name: l2tp-ses4" )
2246 class NetworkdNetworkTests ( unittest
. TestCase
, Utilities
):
2254 def test_address_static ( self
):
2255 # test for #22515. The address will be removed and replaced with /64 prefix.
2256 check_output ( 'ip link add dummy98 type dummy' )
2257 check_output ( 'ip link set dev dummy98 up' )
2258 check_output ( 'ip -6 address add 2001:db8:0:f101::15/128 dev dummy98' )
2259 self
. wait_address ( 'dummy98' , '2001:db8:0:f101::15/128' , ipv
= '-6' )
2260 check_output ( 'ip -4 address add 10.3.2.3/16 brd 10.3.255.250 scope global label dummy98:hoge dev dummy98' )
2261 self
. wait_address ( 'dummy98' , '10.3.2.3/16 brd 10.3.255.250' , ipv
= '-4' )
2263 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' )
2266 self
. wait_online ([ 'dummy98:routable' ])
2268 output
= check_output ( 'ip -4 address show dev dummy98' )
2270 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
2271 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
2272 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
2273 self
. assertIn ( 'inet 10.7.8.9/16 brd 10.7.255.255 scope link deprecated dummy98' , output
)
2274 self
. assertIn ( 'inet 10.8.8.1/16 scope global dummy98' , output
)
2275 self
. assertIn ( 'inet 10.8.8.2/16 brd 10.8.8.128 scope global secondary dummy98' , output
)
2276 self
. assertRegex ( output
, 'inet 10.9.0.1/16 (metric 128 |)brd 10.9.255.255 scope global dummy98' )
2278 # test for ENOBUFS issue #17012
2279 for i
in range ( 1 , 254 ):
2280 self
. assertIn ( f
'inet 10.3.3. {i} /16 brd 10.3.255.255' , output
)
2283 self
. assertNotIn ( '10.10.0.1/16' , output
)
2284 self
. assertNotIn ( '10.10.0.2/16' , output
)
2286 output
= check_output ( 'ip -4 address show dev dummy98 label 32' )
2287 self
. assertIn ( 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32' , output
)
2289 output
= check_output ( 'ip -4 address show dev dummy98 label 33' )
2290 self
. assertIn ( 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33' , output
)
2292 output
= check_output ( 'ip -4 address show dev dummy98 label 34' )
2293 self
. assertRegex ( output
, r
'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34' )
2295 output
= check_output ( 'ip -4 address show dev dummy98 label 35' )
2296 self
. assertRegex ( output
, r
'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35' )
2298 output
= check_output ( 'ip -4 route show dev dummy98' )
2300 self
. assertIn ( '10.9.0.0/16 proto kernel scope link src 10.9.0.1 metric 128' , output
)
2302 output
= check_output ( 'ip -6 address show dev dummy98' )
2304 self
. assertIn ( 'inet6 2001:db8:0:f101::15/64 scope global' , output
)
2305 self
. assertIn ( 'inet6 2001:db8:0:f101::16/64 scope global' , output
)
2306 self
. assertIn ( 'inet6 2001:db8:0:f102::15/64 scope global' , output
)
2307 self
. assertIn ( 'inet6 2001:db8:0:f102::16/64 scope global' , output
)
2308 self
. assertIn ( 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global' , output
)
2309 self
. assertIn ( 'inet6 2001:db8:1:f101::1/64 scope global deprecated' , output
)
2310 self
. assertRegex ( output
, r
'inet6 fd[0-9a-f:]*1/64 scope global' )
2312 self
. check_netlabel ( 'dummy98' , r
'10\.4\.3\.0/24' )
2315 # 1. set preferred lifetime forever to drop the deprecated flag for testing #20891.
2316 check_output ( 'ip address change 10.7.8.9/16 dev dummy98 preferred_lft forever' )
2317 check_output ( 'ip address change 2001:db8:1:f101::1/64 dev dummy98 preferred_lft forever' )
2318 output
= check_output ( 'ip -4 address show dev dummy98' )
2320 self
. assertNotIn ( 'deprecated' , output
)
2321 output
= check_output ( 'ip -6 address show dev dummy98' )
2323 self
. assertNotIn ( 'deprecated' , output
)
2325 # 2. reconfigure the interface.
2326 networkctl_reconfigure ( 'dummy98' )
2327 self
. wait_online ([ 'dummy98:routable' ])
2329 # 3. check the deprecated flag is set for the address configured with PreferredLifetime=0
2330 output
= check_output ( 'ip -4 address show dev dummy98' )
2332 self
. assertIn ( 'inet 10.7.8.9/16 brd 10.7.255.255 scope link deprecated dummy98' , output
)
2333 output
= check_output ( 'ip -6 address show dev dummy98' )
2335 self
. assertIn ( 'inet6 2001:db8:1:f101::1/64 scope global deprecated' , output
)
2337 # test for ENOBUFS issue #17012
2338 output
= check_output ( 'ip -4 address show dev dummy98' )
2339 for i
in range ( 1 , 254 ):
2340 self
. assertIn ( f
'inet 10.3.3. {i} /16 brd 10.3.255.255' , output
)
2342 # TODO: check json string
2343 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2345 def test_address_ipv4acd ( self
):
2346 check_output ( 'ip netns add ns99' )
2347 check_output ( 'ip link add veth99 type veth peer veth-peer' )
2348 check_output ( 'ip link set veth-peer netns ns99' )
2349 check_output ( 'ip link set veth99 up' )
2350 check_output ( 'ip netns exec ns99 ip link set veth-peer up' )
2351 check_output ( 'ip netns exec ns99 ip address add 192.168.100.10/24 dev veth-peer' )
2353 copy_network_unit ( '25-address-ipv4acd-veth99.network' , copy_dropins
= False )
2355 self
. wait_online ([ 'veth99:routable' ])
2357 output
= check_output ( 'ip -4 address show dev veth99' )
2359 self
. assertNotIn ( '192.168.100.10/24' , output
)
2360 self
. assertIn ( '192.168.100.11/24' , output
)
2362 copy_network_unit ( '25-address-ipv4acd-veth99.network.d/conflict-address.conf' )
2364 self
. wait_operstate ( 'veth99' , operstate
= 'routable' , setup_state
= 'configuring' , setup_timeout
= 10 )
2366 output
= check_output ( 'ip -4 address show dev veth99' )
2368 self
. assertNotIn ( '192.168.100.10/24' , output
)
2369 self
. assertIn ( '192.168.100.11/24' , output
)
2371 def test_address_peer_ipv4 ( self
):
2372 # test for issue #17304
2373 copy_network_unit ( '25-address-peer-ipv4.network' , '12-dummy.netdev' )
2375 for trial
in range ( 2 ):
2381 self
. wait_online ([ 'dummy98:routable' ])
2383 output
= check_output ( 'ip -4 address show dev dummy98' )
2384 self
. assertIn ( 'inet 100.64.0.1 peer 100.64.0.2/32 scope global' , output
)
2386 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
2387 def test_prefix_route ( self
):
2388 copy_network_unit ( '25-prefix-route-with-vrf.network' , '12-dummy.netdev' ,
2389 '25-prefix-route-without-vrf.network' , '11-dummy.netdev' ,
2390 '25-vrf.netdev' , '25-vrf.network' )
2391 for trial
in range ( 2 ):
2397 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' , 'vrf99:carrier' ])
2399 output
= check_output ( 'ip route show table 42 dev dummy98' )
2400 print ( '### ip route show table 42 dev dummy98' )
2402 self
. assertRegex ( output
, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1' )
2403 self
. assertRegex ( output
, '10.20.33.0/24 proto kernel scope link src 10.20.33.1' )
2404 self
. assertRegex ( output
, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1' )
2405 self
. assertRegex ( output
, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1' )
2406 self
. assertRegex ( output
, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1' )
2407 self
. assertRegex ( output
, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1' )
2408 self
. assertRegex ( output
, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1' )
2409 output
= check_output ( 'ip -6 route show table 42 dev dummy98' )
2410 print ( '### ip -6 route show table 42 dev dummy98' )
2414 self
. assertRegex ( output
, 'local fdde:11:22::1 proto kernel metric 0 pref medium' )
2415 #self.assertRegex(output, 'fdde:11:22::1 proto kernel metric 256 pref medium')
2416 self
. assertRegex ( output
, 'local fdde:11:33::1 proto kernel metric 0 pref medium' )
2417 self
. assertRegex ( output
, 'fdde:11:33::/64 proto kernel metric 256 pref medium' )
2418 self
. assertRegex ( output
, 'local fdde:11:44::1 proto kernel metric 0 pref medium' )
2419 self
. assertRegex ( output
, 'local fdde:11:55::1 proto kernel metric 0 pref medium' )
2420 self
. assertRegex ( output
, 'fe80::/64 proto kernel metric 256 pref medium' )
2421 self
. assertRegex ( output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium' )
2425 output
= check_output ( 'ip route show dev test1' )
2426 print ( '### ip route show dev test1' )
2428 self
. assertRegex ( output
, '10.21.33.0/24 proto kernel scope link src 10.21.33.1' )
2429 output
= check_output ( 'ip route show table local dev test1' )
2430 print ( '### ip route show table local dev test1' )
2432 self
. assertRegex ( output
, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1' )
2433 self
. assertRegex ( output
, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1' )
2434 self
. assertRegex ( output
, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1' )
2435 self
. assertRegex ( output
, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1' )
2436 self
. assertRegex ( output
, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1' )
2437 self
. assertRegex ( output
, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1' )
2438 output
= check_output ( 'ip -6 route show dev test1' )
2439 print ( '### ip -6 route show dev test1' )
2441 self
. assertRegex ( output
, 'fdde:12:22::1 proto kernel metric 256 pref medium' )
2442 self
. assertRegex ( output
, 'fdde:12:33::/64 proto kernel metric 256 pref medium' )
2443 self
. assertRegex ( output
, 'fe80::/64 proto kernel metric 256 pref medium' )
2444 output
= check_output ( 'ip -6 route show table local dev test1' )
2445 print ( '### ip -6 route show table local dev test1' )
2447 self
. assertRegex ( output
, 'local fdde:12:22::1 proto kernel metric 0 pref medium' )
2448 self
. assertRegex ( output
, 'local fdde:12:33::1 proto kernel metric 0 pref medium' )
2449 self
. assertRegex ( output
, 'local fdde:12:44::1 proto kernel metric 0 pref medium' )
2450 self
. assertRegex ( output
, 'local fdde:12:55::1 proto kernel metric 0 pref medium' )
2451 self
. assertRegex ( output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium' )
2453 def test_configure_without_carrier ( self
):
2454 copy_network_unit ( '11-dummy.netdev' )
2456 self
. wait_operstate ( 'test1' , 'off' , '' )
2457 check_output ( 'ip link set dev test1 up carrier off' )
2459 copy_network_unit ( '25-test1.network.d/configure-without-carrier.conf' , copy_dropins
= False )
2461 self
. wait_online ([ 'test1:no-carrier' ])
2463 carrier_map
= { 'on' : '1' , 'off' : '0' }
2464 routable_map
= { 'on' : 'routable' , 'off' : 'no-carrier' }
2465 for carrier
in [ 'off' , 'on' , 'off' ]:
2466 with self
. subTest ( carrier
= carrier
):
2467 if carrier_map
[ carrier
] != read_link_attr ( 'test1' , 'carrier' ):
2468 check_output ( f
'ip link set dev test1 carrier {carrier} ' )
2469 self
. wait_online ([ f
'test1:{routable_map[carrier]}:{routable_map[carrier]}' ])
2471 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
2473 self
. assertRegex ( output
, '192.168.0.15' )
2474 self
. assertRegex ( output
, '192.168.0.1' )
2475 self
. assertRegex ( output
, routable_map
[ carrier
])
2477 def test_configure_without_carrier_yes_ignore_carrier_loss_no ( self
):
2478 copy_network_unit ( '11-dummy.netdev' )
2480 self
. wait_operstate ( 'test1' , 'off' , '' )
2481 check_output ( 'ip link set dev test1 up carrier off' )
2483 copy_network_unit ( '25-test1.network' )
2485 self
. wait_online ([ 'test1:no-carrier' ])
2487 carrier_map
= { 'on' : '1' , 'off' : '0' }
2488 routable_map
= { 'on' : 'routable' , 'off' : 'no-carrier' }
2489 for ( carrier
, have_config
) in [( 'off' , True ), ( 'on' , True ), ( 'off' , False )]:
2490 with self
. subTest ( carrier
= carrier
, have_config
= have_config
):
2491 if carrier_map
[ carrier
] != read_link_attr ( 'test1' , 'carrier' ):
2492 check_output ( f
'ip link set dev test1 carrier {carrier} ' )
2493 self
. wait_online ([ f
'test1:{routable_map[carrier]}:{routable_map[carrier]}' ])
2495 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
2498 self
. assertRegex ( output
, '192.168.0.15' )
2499 self
. assertRegex ( output
, '192.168.0.1' )
2501 self
. assertNotRegex ( output
, '192.168.0.15' )
2502 self
. assertNotRegex ( output
, '192.168.0.1' )
2503 self
. assertRegex ( output
, routable_map
[ carrier
])
2505 def test_routing_policy_rule ( self
):
2506 copy_network_unit ( '25-routing-policy-rule-test1.network' , '11-dummy.netdev' )
2508 self
. wait_online ([ 'test1:degraded' ])
2510 output
= check_output ( 'ip rule list iif test1 priority 111' )
2512 self
. assertRegex ( output
, '111:' )
2513 self
. assertRegex ( output
, 'from 192.168.100.18' )
2514 self
. assertRegex ( output
, r
'tos (0x08|throughput)\s' )
2515 self
. assertRegex ( output
, 'iif test1' )
2516 self
. assertRegex ( output
, 'oif test1' )
2517 self
. assertRegex ( output
, 'lookup 7' )
2519 output
= check_output ( 'ip rule list iif test1 priority 101' )
2521 self
. assertRegex ( output
, '101:' )
2522 self
. assertRegex ( output
, 'from all' )
2523 self
. assertRegex ( output
, 'iif test1' )
2524 self
. assertRegex ( output
, 'lookup 9' )
2526 output
= check_output ( 'ip -6 rule list iif test1 priority 100' )
2528 self
. assertRegex ( output
, '100:' )
2529 self
. assertRegex ( output
, 'from all' )
2530 self
. assertRegex ( output
, 'iif test1' )
2531 self
. assertRegex ( output
, 'lookup 8' )
2533 output
= check_output ( 'ip rule list iif test1 priority 102' )
2535 self
. assertRegex ( output
, '102:' )
2536 self
. assertRegex ( output
, 'from 0.0.0.0/8' )
2537 self
. assertRegex ( output
, 'iif test1' )
2538 self
. assertRegex ( output
, 'lookup 10' )
2540 # TODO: check json string
2541 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2543 def test_routing_policy_rule_issue_11280 ( self
):
2544 copy_network_unit ( '25-routing-policy-rule-test1.network' , '11-dummy.netdev' ,
2545 '25-routing-policy-rule-dummy98.network' , '12-dummy.netdev' )
2547 for trial
in range ( 3 ):
2548 restart_networkd ( show_logs
=( trial
> 0 ))
2549 self
. wait_online ([ 'test1:degraded' , 'dummy98:degraded' ])
2551 output
= check_output ( 'ip rule list table 7' )
2553 self
. assertRegex ( output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7' )
2555 output
= check_output ( 'ip rule list table 8' )
2557 self
. assertRegex ( output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8' )
2559 def test_routing_policy_rule_reconfigure ( self
):
2560 copy_network_unit ( '25-routing-policy-rule-reconfigure2.network' , '11-dummy.netdev' )
2562 self
. wait_online ([ 'test1:degraded' ])
2564 output
= check_output ( 'ip rule list table 1011' )
2566 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2567 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2568 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2569 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2571 output
= check_output ( 'ip -6 rule list table 1011' )
2573 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2575 copy_network_unit ( '25-routing-policy-rule-reconfigure1.network' , '11-dummy.netdev' )
2577 self
. wait_online ([ 'test1:degraded' ])
2579 output
= check_output ( 'ip rule list table 1011' )
2581 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2582 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2583 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2584 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2586 output
= check_output ( 'ip -6 rule list table 1011' )
2588 self
. assertNotIn ( '10112: from all oif test1 lookup 1011' , output
)
2589 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2591 call ( 'ip rule delete priority 10111' )
2592 call ( 'ip rule delete priority 10112' )
2593 call ( 'ip rule delete priority 10113' )
2594 call ( 'ip rule delete priority 10114' )
2595 call ( 'ip -6 rule delete priority 10113' )
2597 output
= check_output ( 'ip rule list table 1011' )
2599 self
. assertEqual ( output
, '' )
2601 output
= check_output ( 'ip -6 rule list table 1011' )
2603 self
. assertEqual ( output
, '' )
2605 networkctl_reconfigure ( 'test1' )
2606 self
. wait_online ([ 'test1:degraded' ])
2608 output
= check_output ( 'ip rule list table 1011' )
2610 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2611 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2612 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2613 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2615 output
= check_output ( 'ip -6 rule list table 1011' )
2617 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2619 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable ()
2620 def test_routing_policy_rule_port_range ( self
):
2621 copy_network_unit ( '25-fibrule-port-range.network' , '11-dummy.netdev' )
2623 self
. wait_online ([ 'test1:degraded' ])
2625 output
= check_output ( 'ip rule' )
2627 self
. assertRegex ( output
, '111' )
2628 self
. assertRegex ( output
, 'from 192.168.100.18' )
2629 self
. assertRegex ( output
, '1123-1150' )
2630 self
. assertRegex ( output
, '3224-3290' )
2631 self
. assertRegex ( output
, 'tcp' )
2632 self
. assertRegex ( output
, 'lookup 7' )
2634 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable ()
2635 def test_routing_policy_rule_invert ( self
):
2636 copy_network_unit ( '25-fibrule-invert.network' , '11-dummy.netdev' )
2638 self
. wait_online ([ 'test1:degraded' ])
2640 output
= check_output ( 'ip rule' )
2642 self
. assertRegex ( output
, '111' )
2643 self
. assertRegex ( output
, 'not.*?from.*?192.168.100.18' )
2644 self
. assertRegex ( output
, 'tcp' )
2645 self
. assertRegex ( output
, 'lookup 7' )
2647 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable ()
2648 def test_routing_policy_rule_uidrange ( self
):
2649 copy_network_unit ( '25-fibrule-uidrange.network' , '11-dummy.netdev' )
2651 self
. wait_online ([ 'test1:degraded' ])
2653 output
= check_output ( 'ip rule' )
2655 self
. assertRegex ( output
, '111' )
2656 self
. assertRegex ( output
, 'from 192.168.100.18' )
2657 self
. assertRegex ( output
, 'lookup 7' )
2658 self
. assertRegex ( output
, 'uidrange 100-200' )
2660 def _test_route_static ( self
, manage_foreign_routes
):
2661 if not manage_foreign_routes
:
2662 copy_networkd_conf_dropin ( 'networkd-manage-foreign-routes-no.conf' )
2664 copy_network_unit ( '25-route-static.network' , '12-dummy.netdev' )
2666 self
. wait_online ([ 'dummy98:routable' ])
2668 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
2671 print ( '### ip -6 route show dev dummy98' )
2672 output
= check_output ( 'ip -6 route show dev dummy98' )
2674 self
. assertIn ( '2001:1234:5:8fff:ff:ff:ff:ff proto static' , output
)
2675 self
. assertIn ( '2001:1234:5:8f63::1 proto kernel' , output
)
2676 self
. assertIn ( '2001:1234:5:afff:ff:ff:ff:ff via fe80:0:222:4dff:ff:ff:ff:ff proto static' , output
)
2678 print ( '### ip -6 route show default' )
2679 output
= check_output ( 'ip -6 route show default' )
2681 self
. assertIn ( 'default' , output
)
2682 self
. assertIn ( 'via 2001:1234:5:8fff:ff:ff:ff:ff' , output
)
2684 print ( '### ip -4 route show dev dummy98' )
2685 output
= check_output ( 'ip -4 route show dev dummy98' )
2687 self
. assertIn ( '149.10.124.48/28 proto kernel scope link src 149.10.124.58' , output
)
2688 self
. assertIn ( '149.10.124.64 proto static scope link' , output
)
2689 self
. assertIn ( '169.254.0.0/16 proto static scope link metric 2048' , output
)
2690 self
. assertIn ( '192.168.1.1 proto static scope link initcwnd 20' , output
)
2691 self
. assertIn ( '192.168.1.2 proto static scope link initrwnd 30' , output
)
2692 self
. assertIn ( '192.168.1.3 proto static scope link advmss 30' , output
)
2693 self
. assertIn ( 'multicast 149.10.123.4 proto static' , output
)
2695 print ( '### ip -4 route show dev dummy98 default' )
2696 output
= check_output ( 'ip -4 route show dev dummy98 default' )
2698 self
. assertIn ( 'default via 149.10.125.65 proto static onlink' , output
)
2699 self
. assertIn ( 'default via 149.10.124.64 proto static' , output
)
2700 self
. assertIn ( 'default proto static' , output
)
2702 print ( '### ip -4 route show table local dev dummy98' )
2703 output
= check_output ( 'ip -4 route show table local dev dummy98' )
2705 self
. assertIn ( 'local 149.10.123.1 proto static scope host' , output
)
2706 self
. assertIn ( 'anycast 149.10.123.2 proto static scope link' , output
)
2707 self
. assertIn ( 'broadcast 149.10.123.3 proto static scope link' , output
)
2709 print ( '### ip -4 route show type blackhole' )
2710 output
= check_output ( 'ip -4 route show type blackhole' )
2712 self
. assertIn ( 'blackhole 202.54.1.2 proto static' , output
)
2714 print ( '### ip -4 route show type unreachable' )
2715 output
= check_output ( 'ip -4 route show type unreachable' )
2717 self
. assertIn ( 'unreachable 202.54.1.3 proto static' , output
)
2719 print ( '### ip -4 route show type prohibit' )
2720 output
= check_output ( 'ip -4 route show type prohibit' )
2722 self
. assertIn ( 'prohibit 202.54.1.4 proto static' , output
)
2724 print ( '### ip -6 route show type blackhole' )
2725 output
= check_output ( 'ip -6 route show type blackhole' )
2727 self
. assertIn ( 'blackhole 2001:1234:5678::2 dev lo proto static' , output
)
2729 print ( '### ip -6 route show type unreachable' )
2730 output
= check_output ( 'ip -6 route show type unreachable' )
2732 self
. assertIn ( 'unreachable 2001:1234:5678::3 dev lo proto static' , output
)
2734 print ( '### ip -6 route show type prohibit' )
2735 output
= check_output ( 'ip -6 route show type prohibit' )
2737 self
. assertIn ( 'prohibit 2001:1234:5678::4 dev lo proto static' , output
)
2739 print ( '### ip route show 192.168.10.1' )
2740 output
= check_output ( 'ip route show 192.168.10.1' )
2742 self
. assertIn ( '192.168.10.1 proto static' , output
)
2743 self
. assertIn ( 'nexthop via 149.10.124.59 dev dummy98 weight 10' , output
)
2744 self
. assertIn ( 'nexthop via 149.10.124.60 dev dummy98 weight 5' , output
)
2746 print ( '### ip route show 192.168.10.2' )
2747 output
= check_output ( 'ip route show 192.168.10.2' )
2749 # old ip command does not show IPv6 gateways...
2750 self
. assertIn ( '192.168.10.2 proto static' , output
)
2751 self
. assertIn ( 'nexthop' , output
)
2752 self
. assertIn ( 'dev dummy98 weight 10' , output
)
2753 self
. assertIn ( 'dev dummy98 weight 5' , output
)
2755 print ( '### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff' )
2756 output
= check_output ( 'ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff' )
2758 # old ip command does not show 'nexthop' keyword and weight...
2759 self
. assertIn ( '2001:1234:5:7fff:ff:ff:ff:ff' , output
)
2760 self
. assertIn ( 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98' , output
)
2761 self
. assertIn ( 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98' , output
)
2763 # TODO: check json string
2764 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2766 copy_network_unit ( '25-address-static.network' )
2768 self
. wait_online ([ 'dummy98:routable' ])
2770 # check all routes managed by Manager are removed
2771 print ( '### ip -4 route show type blackhole' )
2772 output
= check_output ( 'ip -4 route show type blackhole' )
2774 self
. assertEqual ( output
, '' )
2776 print ( '### ip -4 route show type unreachable' )
2777 output
= check_output ( 'ip -4 route show type unreachable' )
2779 self
. assertEqual ( output
, '' )
2781 print ( '### ip -4 route show type prohibit' )
2782 output
= check_output ( 'ip -4 route show type prohibit' )
2784 self
. assertEqual ( output
, '' )
2786 print ( '### ip -6 route show type blackhole' )
2787 output
= check_output ( 'ip -6 route show type blackhole' )
2789 self
. assertEqual ( output
, '' )
2791 print ( '### ip -6 route show type unreachable' )
2792 output
= check_output ( 'ip -6 route show type unreachable' )
2794 self
. assertEqual ( output
, '' )
2796 print ( '### ip -6 route show type prohibit' )
2797 output
= check_output ( 'ip -6 route show type prohibit' )
2799 self
. assertEqual ( output
, '' )
2801 remove_network_unit ( '25-address-static.network' )
2803 self
. wait_online ([ 'dummy98:routable' ])
2805 # check all routes managed by Manager are reconfigured
2806 print ( '### ip -4 route show type blackhole' )
2807 output
= check_output ( 'ip -4 route show type blackhole' )
2809 self
. assertIn ( 'blackhole 202.54.1.2 proto static' , output
)
2811 print ( '### ip -4 route show type unreachable' )
2812 output
= check_output ( 'ip -4 route show type unreachable' )
2814 self
. assertIn ( 'unreachable 202.54.1.3 proto static' , output
)
2816 print ( '### ip -4 route show type prohibit' )
2817 output
= check_output ( 'ip -4 route show type prohibit' )
2819 self
. assertIn ( 'prohibit 202.54.1.4 proto static' , output
)
2821 print ( '### ip -6 route show type blackhole' )
2822 output
= check_output ( 'ip -6 route show type blackhole' )
2824 self
. assertIn ( 'blackhole 2001:1234:5678::2 dev lo proto static' , output
)
2826 print ( '### ip -6 route show type unreachable' )
2827 output
= check_output ( 'ip -6 route show type unreachable' )
2829 self
. assertIn ( 'unreachable 2001:1234:5678::3 dev lo proto static' , output
)
2831 print ( '### ip -6 route show type prohibit' )
2832 output
= check_output ( 'ip -6 route show type prohibit' )
2834 self
. assertIn ( 'prohibit 2001:1234:5678::4 dev lo proto static' , output
)
2836 remove_link ( 'dummy98' )
2839 # check all routes managed by Manager are removed
2840 print ( '### ip -4 route show type blackhole' )
2841 output
= check_output ( 'ip -4 route show type blackhole' )
2843 self
. assertEqual ( output
, '' )
2845 print ( '### ip -4 route show type unreachable' )
2846 output
= check_output ( 'ip -4 route show type unreachable' )
2848 self
. assertEqual ( output
, '' )
2850 print ( '### ip -4 route show type prohibit' )
2851 output
= check_output ( 'ip -4 route show type prohibit' )
2853 self
. assertEqual ( output
, '' )
2855 print ( '### ip -6 route show type blackhole' )
2856 output
= check_output ( 'ip -6 route show type blackhole' )
2858 self
. assertEqual ( output
, '' )
2860 print ( '### ip -6 route show type unreachable' )
2861 output
= check_output ( 'ip -6 route show type unreachable' )
2863 self
. assertEqual ( output
, '' )
2865 print ( '### ip -6 route show type prohibit' )
2866 output
= check_output ( 'ip -6 route show type prohibit' )
2868 self
. assertEqual ( output
, '' )
2872 def test_route_static ( self
):
2874 for manage_foreign_routes
in [ True , False ]:
2880 print ( f
'### test_route_static(manage_foreign_routes= {manage_foreign_routes} )' )
2881 with self
. subTest ( manage_foreign_routes
= manage_foreign_routes
):
2882 self
._ test
_ route
_ static
( manage_foreign_routes
)
2884 @expectedFailureIfRTA_VIAIsNotSupported ()
2885 def test_route_via_ipv6 ( self
):
2886 copy_network_unit ( '25-route-via-ipv6.network' , '12-dummy.netdev' )
2888 self
. wait_online ([ 'dummy98:routable' ])
2890 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
2893 print ( '### ip -6 route show dev dummy98' )
2894 output
= check_output ( 'ip -6 route show dev dummy98' )
2896 self
. assertRegex ( output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static' )
2897 self
. assertRegex ( output
, '2001:1234:5:8f63::1 proto kernel' )
2899 print ( '### ip -4 route show dev dummy98' )
2900 output
= check_output ( 'ip -4 route show dev dummy98' )
2902 self
. assertRegex ( output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58' )
2903 self
. assertRegex ( output
, '149.10.124.66 via inet6 2001:1234:5:8fff:ff:ff:ff:ff proto static' )
2905 @expectedFailureIfModuleIsNotAvailable ( 'tcp_dctcp' )
2906 def test_route_congctl ( self
):
2907 copy_network_unit ( '25-route-congctl.network' , '12-dummy.netdev' )
2909 self
. wait_online ([ 'dummy98:routable' ])
2911 print ( '### ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff' )
2912 output
= check_output ( 'ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff' )
2914 self
. assertIn ( '2001:1234:5:8fff:ff:ff:ff:ff proto static' , output
)
2915 self
. assertIn ( 'congctl dctcp' , output
)
2917 print ( '### ip -4 route show dev dummy98 149.10.124.66' )
2918 output
= check_output ( 'ip -4 route show dev dummy98 149.10.124.66' )
2920 self
. assertIn ( '149.10.124.66 proto static' , output
)
2921 self
. assertIn ( 'congctl dctcp' , output
)
2923 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
2924 def test_route_vrf ( self
):
2925 copy_network_unit ( '25-route-vrf.network' , '12-dummy.netdev' ,
2926 '25-vrf.netdev' , '25-vrf.network' )
2928 self
. wait_online ([ 'dummy98:routable' , 'vrf99:carrier' ])
2930 output
= check_output ( 'ip route show vrf vrf99' )
2932 self
. assertRegex ( output
, 'default via 192.168.100.1' )
2934 output
= check_output ( 'ip route show' )
2936 self
. assertNotRegex ( output
, 'default via 192.168.100.1' )
2938 def test_gateway_reconfigure ( self
):
2939 copy_network_unit ( '25-gateway-static.network' , '12-dummy.netdev' )
2941 self
. wait_online ([ 'dummy98:routable' ])
2942 print ( '### ip -4 route show dev dummy98 default' )
2943 output
= check_output ( 'ip -4 route show dev dummy98 default' )
2945 self
. assertIn ( 'default via 149.10.124.59 proto static' , output
)
2946 self
. assertNotIn ( '149.10.124.60' , output
)
2948 remove_network_unit ( '25-gateway-static.network' )
2949 copy_network_unit ( '25-gateway-next-static.network' )
2951 self
. wait_online ([ 'dummy98:routable' ])
2952 print ( '### ip -4 route show dev dummy98 default' )
2953 output
= check_output ( 'ip -4 route show dev dummy98 default' )
2955 self
. assertNotIn ( '149.10.124.59' , output
)
2956 self
. assertIn ( 'default via 149.10.124.60 proto static' , output
)
2958 def test_ip_route_ipv6_src_route ( self
):
2959 # a dummy device does not make the addresses go through tentative state, so we
2960 # reuse a bond from an earlier test, which does make the addresses go through
2961 # tentative state, and do our test on that
2962 copy_network_unit ( '23-active-slave.network' , '25-route-ipv6-src.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
2964 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:routable' ])
2966 output
= check_output ( 'ip -6 route list dev bond199' )
2968 self
. assertRegex ( output
, 'abcd::/16' )
2969 self
. assertRegex ( output
, 'src' )
2970 self
. assertRegex ( output
, '2001:1234:56:8f63::2' )
2972 def test_ip_link_mac_address ( self
):
2973 copy_network_unit ( '25-address-link-section.network' , '12-dummy.netdev' )
2975 self
. wait_online ([ 'dummy98:degraded' ])
2977 output
= check_output ( 'ip link show dummy98' )
2979 self
. assertRegex ( output
, '00:01:02:aa:bb:cc' )
2981 def test_ip_link_unmanaged ( self
):
2982 copy_network_unit ( '25-link-section-unmanaged.network' , '12-dummy.netdev' )
2985 self
. wait_operstate ( 'dummy98' , 'off' , setup_state
= 'unmanaged' )
2987 def test_ipv6_address_label ( self
):
2988 copy_network_unit ( '25-ipv6-address-label-section.network' , '12-dummy.netdev' )
2990 self
. wait_online ([ 'dummy98:degraded' ])
2992 output
= check_output ( 'ip addrlabel list' )
2994 self
. assertRegex ( output
, '2004:da8:1::/64' )
2996 def test_ipv6_proxy_ndp ( self
):
2997 copy_network_unit ( '25-ipv6-proxy-ndp.network' , '12-dummy.netdev' )
3000 self
. wait_online ([ 'dummy98:routable' ])
3002 output
= check_output ( 'ip neighbor show proxy dev dummy98' )
3004 for i
in range ( 1 , 5 ):
3005 self
. assertRegex ( output
, f
'2607:5300:203:5215: {i} ::1 *proxy' )
3007 def test_neighbor_section ( self
):
3008 copy_network_unit ( '25-neighbor-section.network' , '12-dummy.netdev' )
3010 self
. wait_online ([ 'dummy98:degraded' ], timeout
= '40s' )
3012 print ( '### ip neigh list dev dummy98' )
3013 output
= check_output ( 'ip neigh list dev dummy98' )
3015 self
. assertRegex ( output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT' )
3016 self
. assertRegex ( output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT' )
3018 # TODO: check json string
3019 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3021 def test_neighbor_reconfigure ( self
):
3022 copy_network_unit ( '25-neighbor-section.network' , '12-dummy.netdev' )
3024 self
. wait_online ([ 'dummy98:degraded' ], timeout
= '40s' )
3026 print ( '### ip neigh list dev dummy98' )
3027 output
= check_output ( 'ip neigh list dev dummy98' )
3029 self
. assertRegex ( output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT' )
3030 self
. assertRegex ( output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT' )
3032 remove_network_unit ( '25-neighbor-section.network' )
3033 copy_network_unit ( '25-neighbor-next.network' )
3035 self
. wait_online ([ 'dummy98:degraded' ], timeout
= '40s' )
3036 print ( '### ip neigh list dev dummy98' )
3037 output
= check_output ( 'ip neigh list dev dummy98' )
3039 self
. assertNotRegex ( output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT' )
3040 self
. assertRegex ( output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT' )
3041 self
. assertNotRegex ( output
, '2004:da8:1::1.*PERMANENT' )
3043 def test_neighbor_gre ( self
):
3044 copy_network_unit ( '25-neighbor-ip.network' , '25-neighbor-ipv6.network' , '25-neighbor-ip-dummy.network' ,
3045 '12-dummy.netdev' , '25-gre-tunnel-remote-any.netdev' , '25-ip6gre-tunnel-remote-any.netdev' )
3047 self
. wait_online ([ 'dummy98:degraded' , 'gretun97:routable' , 'ip6gretun97:routable' ], timeout
= '40s' )
3049 output
= check_output ( 'ip neigh list dev gretun97' )
3051 self
. assertRegex ( output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT' )
3053 output
= check_output ( 'ip neigh list dev ip6gretun97' )
3055 self
. assertRegex ( output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT' )
3057 # TODO: check json string
3058 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3060 def test_link_local_addressing ( self
):
3061 copy_network_unit ( '25-link-local-addressing-yes.network' , '11-dummy.netdev' ,
3062 '25-link-local-addressing-no.network' , '12-dummy.netdev' )
3064 self
. wait_online ([ 'test1:degraded' , 'dummy98:carrier' ])
3066 output
= check_output ( 'ip address show dev test1' )
3068 self
. assertRegex ( output
, 'inet .* scope link' )
3069 self
. assertRegex ( output
, 'inet6 .* scope link' )
3071 output
= check_output ( 'ip address show dev dummy98' )
3073 self
. assertNotRegex ( output
, 'inet6* .* scope link' )
3075 # Documentation/networking/ip-sysctl.txt
3077 # addr_gen_mode - INTEGER
3078 # Defines how link-local and autoconf addresses are generated.
3080 # 0: generate address based on EUI64 (default)
3081 # 1: do no generate a link-local address, use EUI64 for addresses generated
3083 # 2: generate stable privacy addresses, using the secret from
3084 # stable_secret (RFC7217)
3085 # 3: generate stable privacy addresses, using a random secret if unset
3087 self
. check_ipv6_sysctl_attr ( 'test1' , 'stable_secret' , '0123:4567:89ab:cdef:0123:4567:89ab:cdef' )
3088 self
. check_ipv6_sysctl_attr ( 'test1' , 'addr_gen_mode' , '2' )
3089 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'addr_gen_mode' , '1' )
3091 def test_link_local_addressing_ipv6ll ( self
):
3092 copy_network_unit ( '26-link-local-addressing-ipv6.network' , '12-dummy.netdev' )
3094 self
. wait_online ([ 'dummy98:degraded' ])
3096 # An IPv6LL address exists by default.
3097 output
= check_output ( 'ip address show dev dummy98' )
3099 self
. assertRegex ( output
, 'inet6 .* scope link' )
3101 copy_network_unit ( '25-link-local-addressing-no.network' )
3103 self
. wait_online ([ 'dummy98:carrier' ])
3105 # Check if the IPv6LL address is removed.
3106 output
= check_output ( 'ip address show dev dummy98' )
3108 self
. assertNotRegex ( output
, 'inet6 .* scope link' )
3110 remove_network_unit ( '25-link-local-addressing-no.network' )
3112 self
. wait_online ([ 'dummy98:degraded' ])
3114 # Check if a new IPv6LL address is assigned.
3115 output
= check_output ( 'ip address show dev dummy98' )
3117 self
. assertRegex ( output
, 'inet6 .* scope link' )
3119 def test_sysctl ( self
):
3120 copy_network_unit ( '25-sysctl.network' , '12-dummy.netdev' )
3122 self
. wait_online ([ 'dummy98:degraded' ])
3124 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
3125 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'use_tempaddr' , '2' )
3126 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'dad_transmits' , '3' )
3127 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'hop_limit' , '5' )
3128 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'proxy_ndp' , '1' )
3129 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
3130 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'proxy_arp' , '1' )
3131 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'accept_local' , '1' )
3133 def test_sysctl_disable_ipv6 ( self
):
3134 copy_network_unit ( '25-sysctl-disable-ipv6.network' , '12-dummy.netdev' )
3136 print ( '## Disable ipv6' )
3137 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=1' )
3138 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=1' )
3141 self
. wait_online ([ 'dummy98:routable' ])
3143 output
= check_output ( 'ip -4 address show dummy98' )
3145 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3146 output
= check_output ( 'ip -6 address show dummy98' )
3148 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3149 self
. assertRegex ( output
, 'inet6 .* scope link' )
3150 output
= check_output ( 'ip -4 route show dev dummy98' )
3152 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3153 output
= check_output ( 'ip -6 route show default' )
3155 self
. assertRegex ( output
, 'default' )
3156 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3158 remove_link ( 'dummy98' )
3160 print ( '## Enable ipv6' )
3161 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=0' )
3162 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=0' )
3165 self
. wait_online ([ 'dummy98:routable' ])
3167 output
= check_output ( 'ip -4 address show dummy98' )
3169 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3170 output
= check_output ( 'ip -6 address show dummy98' )
3172 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3173 self
. assertRegex ( output
, 'inet6 .* scope link' )
3174 output
= check_output ( 'ip -4 route show dev dummy98' )
3176 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3177 output
= check_output ( 'ip -6 route show default' )
3179 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3181 def test_bind_carrier ( self
):
3182 copy_network_unit ( '25-bind-carrier.network' , '11-dummy.netdev' )
3185 # no bound interface.
3186 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
3187 output
= check_output ( 'ip address show test1' )
3189 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3190 self
. assertIn ( 'DOWN' , output
)
3191 self
. assertNotIn ( '192.168.10' , output
)
3193 # add one bound interface. The interface will be up.
3194 check_output ( 'ip link add dummy98 type dummy' )
3195 check_output ( 'ip link set dummy98 up' )
3196 self
. wait_online ([ 'test1:routable' ])
3197 output
= check_output ( 'ip address show test1' )
3199 self
. assertIn ( 'UP,LOWER_UP' , output
)
3200 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3202 # add another bound interface. The interface is still up.
3203 check_output ( 'ip link add dummy99 type dummy' )
3204 check_output ( 'ip link set dummy99 up' )
3205 self
. wait_operstate ( 'dummy99' , 'degraded' , setup_state
= 'unmanaged' )
3206 output
= check_output ( 'ip address show test1' )
3208 self
. assertIn ( 'UP,LOWER_UP' , output
)
3209 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3211 # remove one of the bound interfaces. The interface is still up
3212 remove_link ( 'dummy98' )
3213 output
= check_output ( 'ip address show test1' )
3215 self
. assertIn ( 'UP,LOWER_UP' , output
)
3216 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3218 # bring down the remaining bound interface. The interface will be down.
3219 check_output ( 'ip link set dummy99 down' )
3220 self
. wait_operstate ( 'test1' , 'off' )
3221 self
. wait_address_dropped ( 'test1' , r
'192.168.10' , ipv
= '-4' , timeout_sec
= 10 )
3222 output
= check_output ( 'ip address show test1' )
3224 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3225 self
. assertIn ( 'DOWN' , output
)
3226 self
. assertNotIn ( '192.168.10' , output
)
3228 # bring up the bound interface. The interface will be up.
3229 check_output ( 'ip link set dummy99 up' )
3230 self
. wait_online ([ 'test1:routable' ])
3231 output
= check_output ( 'ip address show test1' )
3233 self
. assertIn ( 'UP,LOWER_UP' , output
)
3234 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3236 # remove the remaining bound interface. The interface will be down.
3237 remove_link ( 'dummy99' )
3238 self
. wait_operstate ( 'test1' , 'off' )
3239 self
. wait_address_dropped ( 'test1' , r
'192.168.10' , ipv
= '-4' , timeout_sec
= 10 )
3240 output
= check_output ( 'ip address show test1' )
3242 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3243 self
. assertIn ( 'DOWN' , output
)
3244 self
. assertNotIn ( '192.168.10' , output
)
3246 # re-add one bound interface. The interface will be up.
3247 check_output ( 'ip link add dummy98 type dummy' )
3248 check_output ( 'ip link set dummy98 up' )
3249 self
. wait_online ([ 'test1:routable' ])
3250 output
= check_output ( 'ip address show test1' )
3252 self
. assertIn ( 'UP,LOWER_UP' , output
)
3253 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3255 def _test_activation_policy ( self
, interface
, test
):
3256 conffile
= '25-activation-policy.network'
3258 conffile
= f
' {conffile} .d/ {test} .conf'
3259 if interface
== 'vlan99' :
3260 copy_network_unit ( '21-vlan.netdev' , '21-vlan-test1.network' )
3261 copy_network_unit ( '11-dummy.netdev' , conffile
, copy_dropins
= False )
3264 always
= test
. startswith ( 'always' )
3265 initial_up
= test
!= 'manual' and not test
. endswith ( 'down' ) # note: default is up
3266 expect_up
= initial_up
3267 next_up
= not expect_up
3269 if test
. endswith ( 'down' ):
3270 self
. wait_activated ( interface
)
3272 for iteration
in range ( 4 ):
3273 with self
. subTest ( iteration
= iteration
, expect_up
= expect_up
):
3274 operstate
= 'routable' if expect_up
else 'off'
3275 setup_state
= 'configured' if expect_up
else ( 'configuring' if iteration
== 0 else None )
3276 self
. wait_operstate ( interface
, operstate
, setup_state
= setup_state
, setup_timeout
= 20 )
3279 self
. assertIn ( 'UP' , check_output ( f
'ip link show {interface} ' ))
3280 self
. assertIn ( '192.168.10.30/24' , check_output ( f
'ip address show {interface} ' ))
3281 self
. assertIn ( 'default via 192.168.10.1' , check_output ( f
'ip route show dev {interface} ' ))
3283 self
. assertIn ( 'DOWN' , check_output ( f
'ip link show {interface} ' ))
3286 check_output ( f
'ip link set dev {interface} up' )
3288 check_output ( f
'ip link set dev {interface} down' )
3289 expect_up
= initial_up
if always
else next_up
3290 next_up
= not next_up
3294 def test_activation_policy ( self
):
3296 for interface
in [ 'test1' , 'vlan99' ]:
3297 for test
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , '' ]:
3303 print ( f
'### test_activation_policy(interface= {interface} , test= {test} )' )
3304 with self
. subTest ( interface
= interface
, test
= test
):
3305 self
._ test
_ activation
_ policy
( interface
, test
)
3307 def _test_activation_policy_required_for_online ( self
, policy
, required
):
3308 conffile
= '25-activation-policy.network'
3309 units
= [ '11-dummy.netdev' , '12-dummy.netdev' , '12-dummy.network' , conffile
]
3311 units
+= [ f
' {conffile} .d/ {policy} .conf' ]
3313 units
+= [ f
' {conffile} .d/required- {required} .conf' ]
3314 copy_network_unit (* units
, copy_dropins
= False )
3317 if policy
. endswith ( 'down' ):
3318 self
. wait_activated ( 'test1' )
3320 if policy
. endswith ( 'down' ) or policy
== 'manual' :
3321 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
3323 self
. wait_online ([ 'test1' ])
3325 if policy
== 'always-down' :
3326 # if always-down, required for online is forced to no
3329 # otherwise if required for online is specified, it should match that
3330 expected
= required
== 'yes'
3332 # otherwise if only policy specified, required for online defaults to
3333 # true if policy is up, always-up, or bound
3334 expected
= policy
. endswith ( 'up' ) or policy
== 'bound'
3336 # default is true, if neither are specified
3339 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
3342 yesno
= 'yes' if expected
else 'no'
3343 self
. assertRegex ( output
, f
'Required For Online: {yesno} ' )
3345 def test_activation_policy_required_for_online ( self
):
3347 for policy
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , 'bound' , '' ]:
3348 for required
in [ 'yes' , 'no' , '' ]:
3354 print ( f
'### test_activation_policy_required_for_online(policy= {policy} , required= {required} )' )
3355 with self
. subTest ( policy
= policy
, required
= required
):
3356 self
._ test
_ activation
_ policy
_ required
_ for
_ online
( policy
, required
)
3358 def test_domain ( self
):
3359 copy_network_unit ( '12-dummy.netdev' , '24-search-domain.network' )
3361 self
. wait_online ([ 'dummy98:routable' ])
3363 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
3365 self
. assertRegex ( output
, 'Address: 192.168.42.100' )
3366 self
. assertRegex ( output
, 'DNS: 192.168.42.1' )
3367 self
. assertRegex ( output
, 'Search Domains: one' )
3369 def test_keep_configuration_static ( self
):
3370 check_output ( 'ip link add name dummy98 type dummy' )
3371 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
3372 check_output ( 'ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500' )
3373 output
= check_output ( 'ip address show dummy98' )
3375 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
3376 self
. assertRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
3377 output
= check_output ( 'ip route show dev dummy98' )
3380 copy_network_unit ( '24-keep-configuration-static.network' )
3382 self
. wait_online ([ 'dummy98:routable' ])
3384 output
= check_output ( 'ip address show dummy98' )
3386 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
3387 self
. assertNotRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
3389 @expectedFailureIfNexthopIsNotAvailable ()
3390 def test_nexthop ( self
):
3391 def check_nexthop ( self
):
3392 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
3394 output
= check_output ( 'ip nexthop list dev veth99' )
3396 self
. assertIn ( 'id 1 via 192.168.5.1 dev veth99' , output
)
3397 self
. assertIn ( 'id 2 via 2001:1234:5:8f63::2 dev veth99' , output
)
3398 self
. assertIn ( 'id 3 dev veth99' , output
)
3399 self
. assertIn ( 'id 4 dev veth99' , output
)
3400 self
. assertRegex ( output
, 'id 5 via 192.168.10.1 dev veth99 .*onlink' )
3401 self
. assertIn ( 'id 8 via fe80:0:222:4dff:ff:ff:ff:ff dev veth99' , output
)
3402 self
. assertRegex ( output
, r
'id [0-9]* via 192.168.5.2 dev veth99' )
3404 output
= check_output ( 'ip nexthop list dev dummy98' )
3406 self
. assertIn ( 'id 20 via 192.168.20.1 dev dummy98' , output
)
3408 # kernel manages blackhole nexthops on lo
3409 output
= check_output ( 'ip nexthop list dev lo' )
3411 self
. assertIn ( 'id 6 blackhole' , output
)
3412 self
. assertIn ( 'id 7 blackhole' , output
)
3414 # group nexthops are shown with -0 option
3415 output
= check_output ( 'ip -0 nexthop list id 21' )
3417 self
. assertRegex ( output
, r
'id 21 group (1,3/20|20/1,3)' )
3419 output
= check_output ( 'ip route show dev veth99 10.10.10.10' )
3421 self
. assertEqual ( '10.10.10.10 nhid 1 via 192.168.5.1 proto static' , output
)
3423 output
= check_output ( 'ip route show dev veth99 10.10.10.11' )
3425 self
. assertEqual ( '10.10.10.11 nhid 2 via inet6 2001:1234:5:8f63::2 proto static' , output
)
3427 output
= check_output ( 'ip route show dev veth99 10.10.10.12' )
3429 self
. assertEqual ( '10.10.10.12 nhid 5 via 192.168.10.1 proto static onlink' , output
)
3431 output
= check_output ( 'ip -6 route show dev veth99 2001:1234:5:8f62::1' )
3433 self
. assertEqual ( '2001:1234:5:8f62::1 nhid 2 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium' , output
)
3435 output
= check_output ( 'ip route show 10.10.10.13' )
3437 self
. assertEqual ( 'blackhole 10.10.10.13 nhid 6 dev lo proto static' , output
)
3439 output
= check_output ( 'ip -6 route show 2001:1234:5:8f62::2' )
3441 self
. assertEqual ( 'blackhole 2001:1234:5:8f62::2 nhid 7 dev lo proto static metric 1024 pref medium' , output
)
3443 output
= check_output ( 'ip route show 10.10.10.14' )
3445 self
. assertIn ( '10.10.10.14 nhid 21 proto static' , output
)
3446 self
. assertIn ( 'nexthop via 192.168.20.1 dev dummy98 weight 1' , output
)
3447 self
. assertIn ( 'nexthop via 192.168.5.1 dev veth99 weight 3' , output
)
3449 # TODO: check json string
3450 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3452 copy_network_unit ( '25-nexthop.network' , '25-veth.netdev' , '25-veth-peer.network' ,
3453 '12-dummy.netdev' , '25-nexthop-dummy.network' )
3458 remove_network_unit ( '25-nexthop.network' )
3459 copy_network_unit ( '25-nexthop-nothing.network' )
3461 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
3463 output
= check_output ( 'ip nexthop list dev veth99' )
3465 self
. assertEqual ( output
, '' )
3466 output
= check_output ( 'ip nexthop list dev lo' )
3468 self
. assertEqual ( output
, '' )
3470 remove_network_unit ( '25-nexthop-nothing.network' )
3471 copy_network_unit ( '25-nexthop.network' )
3472 networkctl_reconfigure ( 'dummy98' )
3477 remove_link ( 'veth99' )
3480 output
= check_output ( 'ip nexthop list dev lo' )
3482 self
. assertEqual ( output
, '' )
3484 class NetworkdTCTests ( unittest
. TestCase
, Utilities
):
3492 @expectedFailureIfModuleIsNotAvailable ( 'sch_cake' )
3493 def test_qdisc_cake ( self
):
3494 copy_network_unit ( '25-qdisc-cake.network' , '12-dummy.netdev' )
3496 self
. wait_online ([ 'dummy98:routable' ])
3498 output
= check_output ( 'tc qdisc show dev dummy98' )
3500 self
. assertIn ( 'qdisc cake 3a: root' , output
)
3501 self
. assertIn ( 'bandwidth 500Mbit' , output
)
3502 self
. assertIn ( 'autorate-ingress' , output
)
3503 self
. assertIn ( 'diffserv8' , output
)
3504 self
. assertIn ( 'dual-dsthost' , output
)
3505 self
. assertIn ( ' nat' , output
)
3506 self
. assertIn ( ' wash' , output
)
3507 self
. assertIn ( ' split-gso' , output
)
3508 self
. assertIn ( ' raw' , output
)
3509 self
. assertIn ( ' atm' , output
)
3510 self
. assertIn ( 'overhead 128' , output
)
3511 self
. assertIn ( 'mpu 20' , output
)
3512 self
. assertIn ( 'fwmark 0xff00' , output
)
3513 self
. assertIn ( 'rtt 1s' , output
)
3514 self
. assertIn ( 'ack-filter-aggressive' , output
)
3516 @expectedFailureIfModuleIsNotAvailable ( 'sch_codel' )
3517 def test_qdisc_codel ( self
):
3518 copy_network_unit ( '25-qdisc-codel.network' , '12-dummy.netdev' )
3520 self
. wait_online ([ 'dummy98:routable' ])
3522 output
= check_output ( 'tc qdisc show dev dummy98' )
3524 self
. assertRegex ( output
, 'qdisc codel 33: root' )
3525 self
. assertRegex ( output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn' )
3527 @expectedFailureIfModuleIsNotAvailable ( 'sch_drr' )
3528 def test_qdisc_drr ( self
):
3529 copy_network_unit ( '25-qdisc-drr.network' , '12-dummy.netdev' )
3531 self
. wait_online ([ 'dummy98:routable' ])
3533 output
= check_output ( 'tc qdisc show dev dummy98' )
3535 self
. assertRegex ( output
, 'qdisc drr 2: root' )
3536 output
= check_output ( 'tc class show dev dummy98' )
3538 self
. assertRegex ( output
, 'class drr 2:30 root quantum 2000b' )
3540 @expectedFailureIfModuleIsNotAvailable ( 'sch_ets' )
3541 def test_qdisc_ets ( self
):
3542 copy_network_unit ( '25-qdisc-ets.network' , '12-dummy.netdev' )
3544 self
. wait_online ([ 'dummy98:routable' ])
3546 output
= check_output ( 'tc qdisc show dev dummy98' )
3549 self
. assertRegex ( output
, 'qdisc ets 3a: root' )
3550 self
. assertRegex ( output
, 'bands 10 strict 3' )
3551 self
. assertRegex ( output
, 'quanta 1 2 3 4 5' )
3552 self
. assertRegex ( output
, 'priomap 3 4 5 6 7' )
3554 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq' )
3555 def test_qdisc_fq ( self
):
3556 copy_network_unit ( '25-qdisc-fq.network' , '12-dummy.netdev' )
3558 self
. wait_online ([ 'dummy98:routable' ])
3560 output
= check_output ( 'tc qdisc show dev dummy98' )
3562 self
. assertRegex ( output
, 'qdisc fq 32: root' )
3563 self
. assertRegex ( output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511' )
3564 self
. assertRegex ( output
, 'quantum 1500' )
3565 self
. assertRegex ( output
, 'initial_quantum 13000' )
3566 self
. assertRegex ( output
, 'maxrate 1Mbit' )
3568 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_codel' )
3569 def test_qdisc_fq_codel ( self
):
3570 copy_network_unit ( '25-qdisc-fq_codel.network' , '12-dummy.netdev' )
3572 self
. wait_online ([ 'dummy98:routable' ])
3574 output
= check_output ( 'tc qdisc show dev dummy98' )
3576 self
. assertRegex ( output
, 'qdisc fq_codel 34: root' )
3577 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' )
3579 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_pie' )
3580 def test_qdisc_fq_pie ( self
):
3581 copy_network_unit ( '25-qdisc-fq_pie.network' , '12-dummy.netdev' )
3583 self
. wait_online ([ 'dummy98:routable' ])
3585 output
= check_output ( 'tc qdisc show dev dummy98' )
3588 self
. assertRegex ( output
, 'qdisc fq_pie 3a: root' )
3589 self
. assertRegex ( output
, 'limit 200000p' )
3591 @expectedFailureIfModuleIsNotAvailable ( 'sch_gred' )
3592 def test_qdisc_gred ( self
):
3593 copy_network_unit ( '25-qdisc-gred.network' , '12-dummy.netdev' )
3595 self
. wait_online ([ 'dummy98:routable' ])
3597 output
= check_output ( 'tc qdisc show dev dummy98' )
3599 self
. assertRegex ( output
, 'qdisc gred 38: root' )
3600 self
. assertRegex ( output
, 'vqs 12 default 10 grio' )
3602 @expectedFailureIfModuleIsNotAvailable ( 'sch_hhf' )
3603 def test_qdisc_hhf ( self
):
3604 copy_network_unit ( '25-qdisc-hhf.network' , '12-dummy.netdev' )
3606 self
. wait_online ([ 'dummy98:routable' ])
3608 output
= check_output ( 'tc qdisc show dev dummy98' )
3610 self
. assertRegex ( output
, 'qdisc hhf 3a: root' )
3611 self
. assertRegex ( output
, 'limit 1022p' )
3613 @expectedFailureIfModuleIsNotAvailable ( 'sch_htb' )
3614 def test_qdisc_htb_fifo ( self
):
3615 copy_network_unit ( '25-qdisc-htb-fifo.network' , '12-dummy.netdev' )
3617 self
. wait_online ([ 'dummy98:routable' ])
3619 output
= check_output ( 'tc qdisc show dev dummy98' )
3621 self
. assertRegex ( output
, 'qdisc htb 2: root' )
3622 self
. assertRegex ( output
, r
'default (0x30|30)' )
3624 self
. assertRegex ( output
, 'qdisc pfifo 37: parent 2:37' )
3625 self
. assertRegex ( output
, 'limit 100000p' )
3627 self
. assertRegex ( output
, 'qdisc bfifo 3a: parent 2:3a' )
3628 self
. assertRegex ( output
, 'limit 1000000' )
3630 self
. assertRegex ( output
, 'qdisc pfifo_head_drop 3b: parent 2:3b' )
3631 self
. assertRegex ( output
, 'limit 1023p' )
3633 self
. assertRegex ( output
, 'qdisc pfifo_fast 3c: parent 2:3c' )
3635 output
= check_output ( 'tc -d class show dev dummy98' )
3637 # Here (:|prio) is a workaround for a bug in iproute2 v6.2.0 caused by
3638 # https://github.com/shemminger/iproute2/commit/010a8388aea11e767ba3a2506728b9ad9760df0e
3639 # which is fixed in v6.3.0 by
3640 # https://github.com/shemminger/iproute2/commit/4e0e56e0ef05387f7f5d8ab41fe6ec6a1897b26d
3641 self
. assertRegex ( output
, 'class htb 2:37 root leaf 37(:|prio) ' )
3642 self
. assertRegex ( output
, 'class htb 2:3a root leaf 3a(:|prio) ' )
3643 self
. assertRegex ( output
, 'class htb 2:3b root leaf 3b(:|prio) ' )
3644 self
. assertRegex ( output
, 'class htb 2:3c root leaf 3c(:|prio) ' )
3645 self
. assertRegex ( output
, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit' )
3646 self
. assertRegex ( output
, 'burst 123456' )
3647 self
. assertRegex ( output
, 'cburst 123457' )
3649 @expectedFailureIfModuleIsNotAvailable ( 'sch_ingress' )
3650 def test_qdisc_ingress ( self
):
3651 copy_network_unit ( '25-qdisc-clsact.network' , '12-dummy.netdev' ,
3652 '25-qdisc-ingress.network' , '11-dummy.netdev' )
3654 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' ])
3656 output
= check_output ( 'tc qdisc show dev dummy98' )
3658 self
. assertRegex ( output
, 'qdisc clsact' )
3660 output
= check_output ( 'tc qdisc show dev test1' )
3662 self
. assertRegex ( output
, 'qdisc ingress' )
3664 @expectedFailureIfModuleIsNotAvailable ( 'sch_netem' )
3665 def test_qdisc_netem ( self
):
3666 copy_network_unit ( '25-qdisc-netem.network' , '12-dummy.netdev' ,
3667 '25-qdisc-netem-compat.network' , '11-dummy.netdev' )
3669 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' ])
3671 output
= check_output ( 'tc qdisc show dev dummy98' )
3673 self
. assertRegex ( output
, 'qdisc netem 30: root' )
3674 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
3676 output
= check_output ( 'tc qdisc show dev test1' )
3678 self
. assertRegex ( output
, 'qdisc netem [0-9a-f]*: root' )
3679 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
3681 @expectedFailureIfModuleIsNotAvailable ( 'sch_pie' )
3682 def test_qdisc_pie ( self
):
3683 copy_network_unit ( '25-qdisc-pie.network' , '12-dummy.netdev' )
3685 self
. wait_online ([ 'dummy98:routable' ])
3687 output
= check_output ( 'tc qdisc show dev dummy98' )
3689 self
. assertRegex ( output
, 'qdisc pie 3a: root' )
3690 self
. assertRegex ( output
, 'limit 200000' )
3692 @expectedFailureIfModuleIsNotAvailable ( 'sch_qfq' )
3693 def test_qdisc_qfq ( self
):
3694 copy_network_unit ( '25-qdisc-qfq.network' , '12-dummy.netdev' )
3696 self
. wait_online ([ 'dummy98:routable' ])
3698 output
= check_output ( 'tc qdisc show dev dummy98' )
3700 self
. assertRegex ( output
, 'qdisc qfq 2: root' )
3701 output
= check_output ( 'tc class show dev dummy98' )
3703 self
. assertRegex ( output
, 'class qfq 2:30 root weight 2 maxpkt 16000' )
3704 self
. assertRegex ( output
, 'class qfq 2:31 root weight 10 maxpkt 8000' )
3706 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfb' )
3707 def test_qdisc_sfb ( self
):
3708 copy_network_unit ( '25-qdisc-sfb.network' , '12-dummy.netdev' )
3710 self
. wait_online ([ 'dummy98:routable' ])
3712 output
= check_output ( 'tc qdisc show dev dummy98' )
3714 self
. assertRegex ( output
, 'qdisc sfb 39: root' )
3715 self
. assertRegex ( output
, 'limit 200000' )
3717 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfq' )
3718 def test_qdisc_sfq ( self
):
3719 copy_network_unit ( '25-qdisc-sfq.network' , '12-dummy.netdev' )
3721 self
. wait_online ([ 'dummy98:routable' ])
3723 output
= check_output ( 'tc qdisc show dev dummy98' )
3725 self
. assertRegex ( output
, 'qdisc sfq 36: root' )
3726 self
. assertRegex ( output
, 'perturb 5sec' )
3728 @expectedFailureIfModuleIsNotAvailable ( 'sch_tbf' )
3729 def test_qdisc_tbf ( self
):
3730 copy_network_unit ( '25-qdisc-tbf.network' , '12-dummy.netdev' )
3732 self
. wait_online ([ 'dummy98:routable' ])
3734 output
= check_output ( 'tc qdisc show dev dummy98' )
3736 self
. assertRegex ( output
, 'qdisc tbf 35: root' )
3737 self
. assertRegex ( output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms' )
3739 @expectedFailureIfModuleIsNotAvailable ( 'sch_teql' )
3740 def test_qdisc_teql ( self
):
3741 call_quiet ( 'rmmod sch_teql' )
3743 copy_network_unit ( '25-qdisc-teql.network' , '12-dummy.netdev' )
3745 self
. wait_links ( 'dummy98' )
3746 check_output ( 'modprobe sch_teql max_equalizers=2' )
3747 self
. wait_online ([ 'dummy98:routable' ])
3749 output
= check_output ( 'tc qdisc show dev dummy98' )
3751 self
. assertRegex ( output
, 'qdisc teql1 31: root' )
3753 class NetworkdStateFileTests ( unittest
. TestCase
, Utilities
):
3761 def test_state_file ( self
):
3762 copy_network_unit ( '12-dummy.netdev' , '25-state-file-tests.network' )
3764 self
. wait_online ([ 'dummy98:routable' ])
3766 # make link state file updated
3767 check_output (* resolvectl_cmd
, 'revert' , 'dummy98' , env
= env
)
3769 # TODO: check json string
3770 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3772 output
= read_link_state_file ( 'dummy98' )
3774 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
3775 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
3776 self
. assertIn ( 'ADMIN_STATE=configured' , output
)
3777 self
. assertIn ( 'OPER_STATE=routable' , output
)
3778 self
. assertIn ( 'REQUIRED_FOR_ONLINE=yes' , output
)
3779 self
. assertIn ( 'REQUIRED_OPER_STATE_FOR_ONLINE=routable' , output
)
3780 self
. assertIn ( 'REQUIRED_FAMILY_FOR_ONLINE=both' , output
)
3781 self
. assertIn ( 'ACTIVATION_POLICY=up' , output
)
3782 self
. assertIn ( 'NETWORK_FILE=/run/systemd/network/25-state-file-tests.network' , output
)
3783 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
3784 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
3785 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
3786 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
3787 self
. assertIn ( 'LLMNR=no' , output
)
3788 self
. assertIn ( 'MDNS=yes' , output
)
3789 self
. assertIn ( 'DNSSEC=no' , output
)
3791 check_output (* resolvectl_cmd
, 'dns' , 'dummy98' , '10.10.10.12#ccc.com' , '10.10.10.13' , '1111:2222::3333' , env
= env
)
3792 check_output (* resolvectl_cmd
, 'domain' , 'dummy98' , 'hogehogehoge' , '~foofoofoo' , env
= env
)
3793 check_output (* resolvectl_cmd
, 'llmnr' , 'dummy98' , 'yes' , env
= env
)
3794 check_output (* resolvectl_cmd
, 'mdns' , 'dummy98' , 'no' , env
= env
)
3795 check_output (* resolvectl_cmd
, 'dnssec' , 'dummy98' , 'yes' , env
= env
)
3796 check_output (* timedatectl_cmd
, 'ntp-servers' , 'dummy98' , '2.fedora.pool.ntp.org' , '3.fedora.pool.ntp.org' , env
= env
)
3798 # TODO: check json string
3799 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3801 output
= read_link_state_file ( 'dummy98' )
3803 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
3804 self
. assertIn ( 'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org' , output
)
3805 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
3806 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
3807 self
. assertIn ( 'LLMNR=yes' , output
)
3808 self
. assertIn ( 'MDNS=no' , output
)
3809 self
. assertIn ( 'DNSSEC=yes' , output
)
3811 check_output (* timedatectl_cmd
, 'revert' , 'dummy98' , env
= env
)
3813 # TODO: check json string
3814 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3816 output
= read_link_state_file ( 'dummy98' )
3818 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
3819 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
3820 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
3821 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
3822 self
. assertIn ( 'LLMNR=yes' , output
)
3823 self
. assertIn ( 'MDNS=no' , output
)
3824 self
. assertIn ( 'DNSSEC=yes' , output
)
3826 check_output (* resolvectl_cmd
, 'revert' , 'dummy98' , env
= env
)
3828 # TODO: check json string
3829 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3831 output
= read_link_state_file ( 'dummy98' )
3833 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
3834 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
3835 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
3836 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
3837 self
. assertIn ( 'LLMNR=no' , output
)
3838 self
. assertIn ( 'MDNS=yes' , output
)
3839 self
. assertIn ( 'DNSSEC=no' , output
)
3841 def test_address_state ( self
):
3842 copy_network_unit ( '12-dummy.netdev' , '12-dummy-no-address.network' )
3845 self
. wait_online ([ 'dummy98:degraded' ])
3847 output
= read_link_state_file ( 'dummy98' )
3848 self
. assertIn ( 'IPV4_ADDRESS_STATE=off' , output
)
3849 self
. assertIn ( 'IPV6_ADDRESS_STATE=degraded' , output
)
3851 # with a routable IPv4 address
3852 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
3853 self
. wait_online ([ 'dummy98:routable' ], ipv4
= True )
3854 self
. wait_online ([ 'dummy98:routable' ])
3856 output
= read_link_state_file ( 'dummy98' )
3857 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
3858 self
. assertIn ( 'IPV6_ADDRESS_STATE=degraded' , output
)
3860 check_output ( 'ip address del 10.1.2.3/16 dev dummy98' )
3862 # with a routable IPv6 address
3863 check_output ( 'ip address add 2002:da8:1:0:1034:56ff:fe78:9abc/64 dev dummy98' )
3864 self
. wait_online ([ 'dummy98:routable' ], ipv6
= True )
3865 self
. wait_online ([ 'dummy98:routable' ])
3867 output
= read_link_state_file ( 'dummy98' )
3868 self
. assertIn ( 'IPV4_ADDRESS_STATE=off' , output
)
3869 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
3871 class NetworkdBondTests ( unittest
. TestCase
, Utilities
):
3879 def test_bond_keep_master ( self
):
3880 check_output ( 'ip link add bond199 type bond mode active-backup' )
3881 check_output ( 'ip link add dummy98 type dummy' )
3882 check_output ( 'ip link set dummy98 master bond199' )
3884 copy_network_unit ( '23-keep-master.network' )
3886 self
. wait_online ([ 'dummy98:enslaved' ])
3888 output
= check_output ( 'ip -d link show bond199' )
3890 self
. assertRegex ( output
, 'active_slave dummy98' )
3892 output
= check_output ( 'ip -d link show dummy98' )
3894 self
. assertRegex ( output
, 'master bond199' )
3896 def test_bond_active_slave ( self
):
3897 copy_network_unit ( '23-active-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
3899 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
3901 output
= check_output ( 'ip -d link show bond199' )
3903 self
. assertIn ( 'active_slave dummy98' , output
)
3905 def test_bond_primary_slave ( self
):
3906 copy_network_unit ( '23-primary-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
3908 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
3910 output
= check_output ( 'ip -d link show bond199' )
3912 self
. assertIn ( 'primary dummy98' , output
)
3915 mkdir_p ( os
. path
. join ( network_unit_dir
, '23-bond199.network.d' ))
3916 for mac
in [ '00:11:22:33:44:55' , '00:11:22:33:44:56' ]:
3917 with
open ( os
. path
. join ( network_unit_dir
, '23-bond199.network.d/mac.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
3918 f
. write ( f
'[Link] \n MACAddress= {mac} \n ' )
3921 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
3923 output
= check_output ( 'ip -d link show bond199' )
3925 self
. assertIn ( f
'link/ether {mac} ' , output
)
3927 def test_bond_operstate ( self
):
3928 copy_network_unit ( '25-bond.netdev' , '11-dummy.netdev' , '12-dummy.netdev' ,
3929 '25-bond99.network' , '25-bond-slave.network' )
3931 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bond99:routable' ])
3933 output
= check_output ( 'ip -d link show dummy98' )
3935 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
3937 output
= check_output ( 'ip -d link show test1' )
3939 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
3941 output
= check_output ( 'ip -d link show bond99' )
3943 self
. assertRegex ( output
, 'MASTER,UP,LOWER_UP' )
3945 self
. wait_operstate ( 'dummy98' , 'enslaved' )
3946 self
. wait_operstate ( 'test1' , 'enslaved' )
3947 self
. wait_operstate ( 'bond99' , 'routable' )
3949 check_output ( 'ip link set dummy98 down' )
3951 self
. wait_operstate ( 'dummy98' , 'off' )
3952 self
. wait_operstate ( 'test1' , 'enslaved' )
3953 self
. wait_operstate ( 'bond99' , 'degraded-carrier' )
3955 check_output ( 'ip link set dummy98 up' )
3957 self
. wait_operstate ( 'dummy98' , 'enslaved' )
3958 self
. wait_operstate ( 'test1' , 'enslaved' )
3959 self
. wait_operstate ( 'bond99' , 'routable' )
3961 check_output ( 'ip link set dummy98 down' )
3962 check_output ( 'ip link set test1 down' )
3964 self
. wait_operstate ( 'dummy98' , 'off' )
3965 self
. wait_operstate ( 'test1' , 'off' )
3967 if not self
. wait_operstate ( 'bond99' , 'no-carrier' , setup_timeout
= 30 , fail_assert
= False ):
3968 # Huh? Kernel does not recognize that all slave interfaces are down?
3969 # Let's confirm that networkd's operstate is consistent with ip's result.
3970 self
. assertNotRegex ( output
, 'NO-CARRIER' )
3972 class NetworkdBridgeTests ( unittest
. TestCase
, Utilities
):
3980 def test_bridge_vlan ( self
):
3981 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave.network' ,
3982 '26-bridge.netdev' , '26-bridge-vlan-master.network' )
3984 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' ])
3986 output
= check_output ( 'bridge vlan show dev test1' )
3988 self
. assertNotRegex ( output
, '4063' )
3989 for i
in range ( 4064 , 4095 ):
3990 self
. assertRegex ( output
, f
' {i} ' )
3991 self
. assertNotRegex ( output
, '4095' )
3993 output
= check_output ( 'bridge vlan show dev bridge99' )
3995 self
. assertNotRegex ( output
, '4059' )
3996 for i
in range ( 4060 , 4095 ):
3997 self
. assertRegex ( output
, f
' {i} ' )
3998 self
. assertNotRegex ( output
, '4095' )
4000 def test_bridge_vlan_issue_20373 ( self
):
4001 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave-issue-20373.network' ,
4002 '26-bridge-issue-20373.netdev' , '26-bridge-vlan-master-issue-20373.network' ,
4003 '21-vlan.netdev' , '21-vlan.network' )
4005 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' , 'vlan99:routable' ])
4007 output
= check_output ( 'bridge vlan show dev test1' )
4009 self
. assertIn ( '100 PVID Egress Untagged' , output
)
4010 self
. assertIn ( '560' , output
)
4011 self
. assertIn ( '600' , output
)
4013 output
= check_output ( 'bridge vlan show dev bridge99' )
4015 self
. assertIn ( '1 PVID Egress Untagged' , output
)
4016 self
. assertIn ( '100' , output
)
4017 self
. assertIn ( '600' , output
)
4019 def test_bridge_mdb ( self
):
4020 copy_network_unit ( '11-dummy.netdev' , '26-bridge-mdb-slave.network' ,
4021 '26-bridge.netdev' , '26-bridge-mdb-master.network' )
4023 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' ])
4025 output
= check_output ( 'bridge mdb show dev bridge99' )
4027 self
. assertRegex ( output
, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064' )
4028 self
. assertRegex ( output
, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065' )
4030 # Old kernel may not support bridge MDB entries on bridge master
4031 if call_quiet ( 'bridge mdb add dev bridge99 port bridge99 grp 224.0.1.3 temp vid 4068' ) == 0 :
4032 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp ff02:aaaa:fee5::1:4 temp *vid 4066' )
4033 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp 224.0.1.2 temp *vid 4067' )
4035 def test_bridge_keep_master ( self
):
4036 check_output ( 'ip link add bridge99 type bridge' )
4037 check_output ( 'ip link set bridge99 up' )
4038 check_output ( 'ip link add dummy98 type dummy' )
4039 check_output ( 'ip link set dummy98 master bridge99' )
4041 copy_network_unit ( '23-keep-master.network' )
4043 self
. wait_online ([ 'dummy98:enslaved' ])
4045 output
= check_output ( 'ip -d link show dummy98' )
4047 self
. assertRegex ( output
, 'master bridge99' )
4048 self
. assertRegex ( output
, 'bridge' )
4050 output
= check_output ( 'bridge -d link show dummy98' )
4052 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
4053 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
4054 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
4055 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
4056 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
4057 # CONFIG_BRIDGE_IGMP_SNOOPING=y
4058 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
4059 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
4060 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
4061 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
4062 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
4063 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
4065 def test_bridge_property ( self
):
4066 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
4067 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
4068 '25-bridge99.network' )
4070 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' ])
4072 output
= check_output ( 'ip -d link show bridge99' )
4074 self
. assertIn ( 'mtu 9000 ' , output
)
4076 output
= check_output ( 'ip -d link show test1' )
4078 self
. assertIn ( 'master bridge99 ' , output
)
4079 self
. assertIn ( 'bridge_slave' , output
)
4080 self
. assertIn ( 'mtu 9000 ' , output
)
4082 output
= check_output ( 'ip -d link show dummy98' )
4084 self
. assertIn ( 'master bridge99 ' , output
)
4085 self
. assertIn ( 'bridge_slave' , output
)
4086 self
. assertIn ( 'mtu 9000 ' , output
)
4088 output
= check_output ( 'ip addr show bridge99' )
4090 self
. assertIn ( '192.168.0.15/24' , output
)
4092 output
= check_output ( 'bridge -d link show dummy98' )
4094 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
4095 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
4096 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'isolated' , '1' )
4097 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
4098 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
4099 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
4100 # CONFIG_BRIDGE_IGMP_SNOOPING=y
4101 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
4102 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
4103 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
4104 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
4105 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
4106 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
4108 output
= check_output ( 'bridge -d link show test1' )
4110 self
. check_bridge_port_attr ( 'bridge99' , 'test1' , 'priority' , '0' )
4112 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
4113 output
= check_output ( 'ip addr show bridge99' )
4115 self
. assertIn ( '192.168.0.16/24' , output
)
4118 print ( '### ip -6 route list table all dev bridge99' )
4119 output
= check_output ( 'ip -6 route list table all dev bridge99' )
4121 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
4123 remove_link ( 'test1' )
4124 self
. wait_operstate ( 'bridge99' , 'degraded-carrier' )
4126 output
= check_output ( 'ip -d link show bridge99' )
4128 self
. assertIn ( 'mtu 9000 ' , output
)
4130 output
= check_output ( 'ip -d link show dummy98' )
4132 self
. assertIn ( 'master bridge99 ' , output
)
4133 self
. assertIn ( 'bridge_slave' , output
)
4134 self
. assertIn ( 'mtu 9000 ' , output
)
4136 remove_link ( 'dummy98' )
4137 self
. wait_operstate ( 'bridge99' , 'no-carrier' )
4139 output
= check_output ( 'ip -d link show bridge99' )
4141 # When no carrier, the kernel may reset the MTU
4142 self
. assertIn ( 'NO-CARRIER' , output
)
4144 output
= check_output ( 'ip address show bridge99' )
4146 self
. assertNotIn ( '192.168.0.15/24' , output
)
4147 self
. assertIn ( '192.168.0.16/24' , output
) # foreign address is kept
4149 print ( '### ip -6 route list table all dev bridge99' )
4150 output
= check_output ( 'ip -6 route list table all dev bridge99' )
4152 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
4154 check_output ( 'ip link add dummy98 type dummy' )
4155 self
. wait_online ([ 'dummy98:enslaved' , 'bridge99:routable' ])
4157 output
= check_output ( 'ip -d link show bridge99' )
4159 self
. assertIn ( 'mtu 9000 ' , output
)
4161 output
= check_output ( 'ip -d link show dummy98' )
4163 self
. assertIn ( 'master bridge99 ' , output
)
4164 self
. assertIn ( 'bridge_slave' , output
)
4165 self
. assertIn ( 'mtu 9000 ' , output
)
4167 def test_bridge_configure_without_carrier ( self
):
4168 copy_network_unit ( '26-bridge.netdev' , '26-bridge-configure-without-carrier.network' ,
4172 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
4173 for test
in [ 'no-slave' , 'add-slave' , 'slave-up' , 'slave-no-carrier' , 'slave-carrier' , 'slave-down' ]:
4174 with self
. subTest ( test
= test
):
4175 if test
== 'no-slave' :
4176 # bridge has no slaves; it's up but *might* not have carrier
4177 self
. wait_operstate ( 'bridge99' , operstate
= r
'(no-carrier|routable)' , setup_state
= None , setup_timeout
= 30 )
4178 # due to a bug in the kernel, newly-created bridges are brought up
4179 # *with* carrier, unless they have had any setting changed; e.g.
4180 # their mac set, priority set, etc. Then, they will lose carrier
4181 # as soon as a (down) slave interface is added, and regain carrier
4182 # again once the slave interface is brought up.
4183 #self.check_link_attr('bridge99', 'carrier', '0')
4184 elif test
== 'add-slave' :
4185 # add slave to bridge, but leave it down; bridge is definitely no-carrier
4186 self
. check_link_attr ( 'test1' , 'operstate' , 'down' )
4187 check_output ( 'ip link set dev test1 master bridge99' )
4188 self
. wait_operstate ( 'bridge99' , operstate
= 'no-carrier' , setup_state
= None )
4189 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4190 elif test
== 'slave-up' :
4191 # bring up slave, which will have carrier; bridge gains carrier
4192 check_output ( 'ip link set dev test1 up' )
4193 self
. wait_online ([ 'bridge99:routable' ])
4194 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
4195 elif test
== 'slave-no-carrier' :
4196 # drop slave carrier; bridge loses carrier
4197 check_output ( 'ip link set dev test1 carrier off' )
4198 self
. wait_online ([ 'bridge99:no-carrier:no-carrier' ])
4199 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4200 elif test
== 'slave-carrier' :
4201 # restore slave carrier; bridge gains carrier
4202 check_output ( 'ip link set dev test1 carrier on' )
4203 self
. wait_online ([ 'bridge99:routable' ])
4204 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
4205 elif test
== 'slave-down' :
4206 # bring down slave; bridge loses carrier
4207 check_output ( 'ip link set dev test1 down' )
4208 self
. wait_online ([ 'bridge99:no-carrier:no-carrier' ])
4209 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4211 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bridge99' , env
= env
)
4212 self
. assertRegex ( output
, '10.1.2.3' )
4213 self
. assertRegex ( output
, '10.1.2.1' )
4215 def test_bridge_ignore_carrier_loss ( self
):
4216 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
4217 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
4218 '25-bridge99-ignore-carrier-loss.network' )
4220 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' ])
4222 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
4223 remove_link ( 'test1' , 'dummy98' )
4226 output
= check_output ( 'ip address show bridge99' )
4228 self
. assertRegex ( output
, 'NO-CARRIER' )
4229 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
4230 self
. assertRegex ( output
, 'inet 192.168.0.16/24 scope global secondary bridge99' )
4232 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain ( self
):
4233 copy_network_unit ( '26-bridge.netdev' , '26-bridge-slave-interface-1.network' ,
4234 '25-bridge99-ignore-carrier-loss.network' )
4236 self
. wait_online ([ 'bridge99:no-carrier' ])
4238 for trial
in range ( 4 ):
4239 check_output ( 'ip link add dummy98 type dummy' )
4240 check_output ( 'ip link set dummy98 up' )
4242 remove_link ( 'dummy98' )
4244 self
. wait_online ([ 'bridge99:routable' , 'dummy98:enslaved' ])
4246 output
= check_output ( 'ip address show bridge99' )
4248 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
4250 output
= check_output ( 'ip rule list table 100' )
4252 self
. assertIn ( 'from all to 8.8.8.8 lookup 100' , output
)
4254 class NetworkdSRIOVTests ( unittest
. TestCase
, Utilities
):
4262 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
4263 def test_sriov ( self
):
4264 copy_network_unit ( '25-default.link' , '25-sriov.network' )
4266 call ( 'modprobe netdevsim' )
4268 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4271 with
open ( '/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4275 self
. wait_online ([ 'eni99np1:routable' ])
4277 output
= check_output ( 'ip link show dev eni99np1' )
4279 self
. assertRegex ( output
,
4280 '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 *'
4281 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4282 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4285 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
4286 def test_sriov_udev ( self
):
4287 copy_network_unit ( '25-sriov.link' , '25-sriov-udev.network' )
4289 call ( 'modprobe netdevsim' )
4291 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4295 self
. wait_online ([ 'eni99np1:routable' ])
4297 # the name eni99np1 may be an alternative name.
4298 ifname
= link_resolve ( 'eni99np1' )
4300 output
= check_output ( 'ip link show dev eni99np1' )
4302 self
. assertRegex ( output
,
4303 '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 *'
4304 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4305 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4307 self
. assertNotIn ( 'vf 3' , output
)
4308 self
. assertNotIn ( 'vf 4' , output
)
4310 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4311 f
. write ( '[Link] \n SR-IOVVirtualFunctions=4 \n ' )
4314 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4316 output
= check_output ( 'ip link show dev eni99np1' )
4318 self
. assertRegex ( output
,
4319 '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 *'
4320 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4321 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
4324 self
. assertNotIn ( 'vf 4' , output
)
4326 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4327 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
4330 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4332 output
= check_output ( 'ip link show dev eni99np1' )
4334 self
. assertRegex ( output
,
4335 '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 *'
4336 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4337 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
4340 self
. assertNotIn ( 'vf 4' , output
)
4342 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4343 f
. write ( '[Link] \n SR-IOVVirtualFunctions=2 \n ' )
4346 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4348 output
= check_output ( 'ip link show dev eni99np1' )
4350 self
. assertRegex ( output
,
4351 '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 *'
4352 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off'
4354 self
. assertNotIn ( 'vf 2' , output
)
4355 self
. assertNotIn ( 'vf 3' , output
)
4356 self
. assertNotIn ( 'vf 4' , output
)
4358 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4359 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
4362 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4364 output
= check_output ( 'ip link show dev eni99np1' )
4366 self
. assertRegex ( output
,
4367 '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 *'
4368 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4369 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4371 self
. assertNotIn ( 'vf 3' , output
)
4372 self
. assertNotIn ( 'vf 4' , output
)
4374 class NetworkdLLDPTests ( unittest
. TestCase
, Utilities
):
4382 def test_lldp ( self
):
4383 copy_network_unit ( '23-emit-lldp.network' , '24-lldp.network' , '25-veth.netdev' )
4385 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:degraded' ])
4387 for trial
in range ( 10 ):
4391 output
= check_output (* networkctl_cmd
, 'lldp' , env
= env
)
4393 if re
. search ( r
'veth99 .* veth-peer' , output
):
4398 class NetworkdRATests ( unittest
. TestCase
, Utilities
):
4406 def test_ipv6_prefix_delegation ( self
):
4407 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth.network' )
4409 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4411 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth99' , env
= env
)
4413 self
. assertRegex ( output
, 'fe80::' )
4414 self
. assertRegex ( output
, '2002:da8:1::1' )
4416 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth99' , env
= env
)
4418 self
. assertIn ( 'hogehoge.test' , output
)
4420 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4422 self
. assertRegex ( output
, '2002:da8:1:0' )
4424 self
. check_netlabel ( 'veth99' , '2002:da8:1::/64' )
4425 self
. check_netlabel ( 'veth99' , '2002:da8:2::/64' )
4427 def test_ipv6_token_static ( self
):
4428 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-static.network' )
4430 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4432 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4434 self
. assertRegex ( output
, '2002:da8:1:0:1a:2b:3c:4d' )
4435 self
. assertRegex ( output
, '2002:da8:1:0:fa:de:ca:fe' )
4436 self
. assertRegex ( output
, '2002:da8:2:0:1a:2b:3c:4d' )
4437 self
. assertRegex ( output
, '2002:da8:2:0:fa:de:ca:fe' )
4439 def test_ipv6_token_prefixstable ( self
):
4440 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable.network' )
4442 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4444 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4446 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
4447 self
. assertIn ( '2002:da8:2:0:1034:56ff:fe78:9abc' , output
) # EUI64
4449 def test_ipv6_token_prefixstable_without_address ( self
):
4450 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable-without-address.network' )
4452 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4454 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4456 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
4457 self
. assertIn ( '2002:da8:2:0:f689:561a:8eda:7443' , output
)
4459 def test_router_preference ( self
):
4460 copy_network_unit ( '25-veth-client.netdev' ,
4461 '25-veth-router-high.netdev' ,
4462 '25-veth-router-low.netdev' ,
4464 '25-veth-bridge.network' ,
4465 '25-veth-client.network' ,
4466 '25-veth-router-high.network' ,
4467 '25-veth-router-low.network' ,
4468 '25-bridge99.network' )
4470 self
. wait_online ([ 'client-p:enslaved' ,
4471 'router-high:degraded' , 'router-high-p:enslaved' ,
4472 'router-low:degraded' , 'router-low-p:enslaved' ,
4473 'bridge99:routable' ])
4475 networkctl_reconfigure ( 'client' )
4476 self
. wait_online ([ 'client:routable' ])
4478 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4479 self
. wait_address ( 'client' , '2002:da8:1:98:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4480 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 512' , ipv
= '-6' , timeout_sec
= 10 )
4481 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 2048' , ipv
= '-6' , timeout_sec
= 10 )
4483 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
4485 self
. assertIn ( 'pref high' , output
)
4486 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
4488 self
. assertIn ( 'pref low' , output
)
4490 with
open ( os
. path
. join ( network_unit_dir
, '25-veth-client.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4491 f
. write ( ' \n [Link] \n MACAddress=12:34:56:78:9a:01 \n [IPv6AcceptRA] \n RouteMetric=100:200:300 \n ' )
4494 self
. wait_online ([ 'client:routable' ])
4496 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a01/64' , ipv
= '-6' , timeout_sec
= 10 )
4497 self
. wait_address ( 'client' , '2002:da8:1:98:1034:56ff:fe78:9a01/64' , ipv
= '-6' , timeout_sec
= 10 )
4498 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 100' , ipv
= '-6' , timeout_sec
= 10 )
4499 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 300' , ipv
= '-6' , timeout_sec
= 10 )
4501 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
4503 self
. assertIn ( 'pref high' , output
)
4504 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
4506 self
. assertIn ( 'pref low' , output
)
4508 class NetworkdDHCPServerTests ( unittest
. TestCase
, Utilities
):
4516 def test_dhcp_server ( self
):
4517 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server.network' )
4519 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4521 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4523 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4524 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
4525 self
. assertRegex ( output
, 'DNS: 192.168.5.1 \n *192.168.5.10' )
4526 self
. assertRegex ( output
, 'NTP: 192.168.5.1 \n *192.168.5.11' )
4528 def test_dhcp_server_with_uplink ( self
):
4529 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-downstream.network' ,
4530 '12-dummy.netdev' , '25-dhcp-server-uplink.network' )
4532 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4534 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4536 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4537 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
4538 self
. assertIn ( 'DNS: 192.168.5.1' , output
)
4539 self
. assertIn ( 'NTP: 192.168.5.1' , output
)
4541 def test_emit_router_timezone ( self
):
4542 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-timezone-router.network' , '25-dhcp-server-timezone-router.network' )
4544 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4546 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4548 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4549 self
. assertIn ( 'Gateway: 192.168.5.1' , output
)
4550 self
. assertIn ( 'Time Zone: Europe/Berlin' , output
)
4552 def test_dhcp_server_static_lease ( self
):
4553 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-static-lease.network' , '25-dhcp-server-static-lease.network' )
4555 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4557 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4559 self
. assertIn ( 'Address: 10.1.1.200 (DHCP4 via 10.1.1.1)' , output
)
4560 self
. assertIn ( 'DHCP4 Client ID: 12:34:56:78:9a:bc' , output
)
4562 def test_dhcp_server_static_lease_default_client_id ( self
):
4563 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-static-lease.network' )
4565 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4567 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4569 self
. assertIn ( 'Address: 10.1.1.200 (DHCP4 via 10.1.1.1)' , output
)
4570 self
. assertRegex ( output
, 'DHCP4 Client ID: IAID:[0-9a-z]*/DUID' )
4572 class NetworkdDHCPServerRelayAgentTests ( unittest
. TestCase
, Utilities
):
4580 def test_relay_agent ( self
):
4581 copy_network_unit ( '25-agent-veth-client.netdev' ,
4582 '25-agent-veth-server.netdev' ,
4583 '25-agent-client.network' ,
4584 '25-agent-server.network' ,
4585 '25-agent-client-peer.network' ,
4586 '25-agent-server-peer.network' )
4589 self
. wait_online ([ 'client:routable' ])
4591 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'client' , env
= env
)
4593 self
. assertRegex ( output
, r
'Address: 192.168.5.150 \(DHCP4 via 192.168.5.1\)' )
4595 class NetworkdDHCPClientTests ( unittest
. TestCase
, Utilities
):
4603 def test_dhcp_client_ipv6_only ( self
):
4604 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv6-only.network' )
4607 self
. wait_online ([ 'veth-peer:carrier' ])
4609 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4612 output
= check_output ( 'ip address show dev veth99 scope global' )
4614 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
4615 self
. assertNotIn ( '192.168.5' , output
)
4617 # checking semi-static route
4618 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
4620 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
4622 # Confirm that ipv6 token is not set in the kernel
4623 output
= check_output ( 'ip token show dev veth99' )
4625 self
. assertRegex ( output
, 'token :: dev veth99' )
4627 print ( '## dnsmasq log' )
4628 output
= read_dnsmasq_log_file ()
4630 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
4631 self
. assertNotIn ( 'DHCPADVERTISE(veth-peer)' , output
)
4632 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
4633 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
4634 self
. assertIn ( 'sent size: 0 option: 14 rapid-commit' , output
)
4636 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-ipv6-only.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4637 f
. write ( ' \n [DHCPv6] \n RapidCommit=no \n ' )
4643 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4646 output
= check_output ( 'ip address show dev veth99 scope global' )
4648 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
4649 self
. assertNotIn ( '192.168.5' , output
)
4651 # checking semi-static route
4652 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
4654 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
4656 print ( '## dnsmasq log' )
4657 output
= read_dnsmasq_log_file ()
4659 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
4660 self
. assertIn ( 'DHCPADVERTISE(veth-peer)' , output
)
4661 self
. assertIn ( 'DHCPREQUEST(veth-peer)' , output
)
4662 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
4663 self
. assertNotIn ( 'rapid-commit' , output
)
4665 def test_dhcp_client_ipv4_only ( self
):
4666 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv4-only.network' )
4669 self
. wait_online ([ 'veth-peer:carrier' ])
4670 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7' ,
4671 '--dhcp-option=option:domain-search,example.com' ,
4672 '--dhcp-alternate-port=67,5555' ,
4673 ipv4_range
= '192.168.5.110,192.168.5.119' )
4674 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4675 self
. wait_address ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' )
4677 print ( '## ip address show dev veth99 scope global' )
4678 output
= check_output ( 'ip address show dev veth99 scope global' )
4680 self
. assertIn ( 'mtu 1492' , output
)
4681 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
4682 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' )
4683 self
. assertNotIn ( '2600::' , output
)
4685 print ( '## ip route show table main dev veth99' )
4686 output
= check_output ( 'ip route show table main dev veth99' )
4688 # no DHCP routes assigned to the main table
4689 self
. assertNotIn ( 'proto dhcp' , output
)
4691 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
4692 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
4693 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
4694 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
4696 print ( '## ip route show table 211 dev veth99' )
4697 output
= check_output ( 'ip route show table 211 dev veth99' )
4699 self
. assertRegex ( output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.11[0-9] metric 24' )
4700 self
. assertRegex ( output
, '192.168.5.0/24 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4701 self
. assertRegex ( output
, '192.168.5.1 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4702 self
. assertRegex ( output
, '192.168.5.6 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4703 self
. assertRegex ( output
, '192.168.5.7 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4704 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
4706 print ( '## link state file' )
4707 output
= read_link_state_file ( 'veth99' )
4709 # checking DNS server and Domains
4710 self
. assertIn ( 'DNS=192.168.5.6 192.168.5.7' , output
)
4711 self
. assertIn ( 'DOMAINS=example.com' , output
)
4713 print ( '## dnsmasq log' )
4714 output
= read_dnsmasq_log_file ()
4716 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
4717 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc' , output
)
4718 self
. assertIn ( 'client provides name: test-hostname' , output
)
4719 self
. assertIn ( '26:mtu' , output
)
4721 # change address range, DNS servers, and Domains
4723 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8' ,
4724 '--dhcp-option=option:domain-search,foo.example.com' ,
4725 '--dhcp-alternate-port=67,5555' ,
4726 ipv4_range
= '192.168.5.120,192.168.5.129' ,)
4728 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4729 print ( 'Wait for the DHCP lease to be expired' )
4730 self
. wait_address_dropped ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' , timeout_sec
= 120 )
4731 self
. wait_address ( 'veth99' , r
'inet 192.168.5.12[0-9]*/24' , ipv
= '-4' )
4733 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4735 print ( '## ip address show dev veth99 scope global' )
4736 output
= check_output ( 'ip address show dev veth99 scope global' )
4738 self
. assertIn ( 'mtu 1492' , output
)
4739 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
4740 self
. assertNotIn ( '192.168.5.11' , output
)
4741 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' )
4742 self
. assertNotIn ( '2600::' , output
)
4744 print ( '## ip route show table main dev veth99' )
4745 output
= check_output ( 'ip route show table main dev veth99' )
4747 # no DHCP routes assigned to the main table
4748 self
. assertNotIn ( 'proto dhcp' , output
)
4750 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
4751 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
4752 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
4753 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
4755 print ( '## ip route show table 211 dev veth99' )
4756 output
= check_output ( 'ip route show table 211 dev veth99' )
4758 self
. assertRegex ( output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.12[0-9] metric 24' )
4759 self
. assertRegex ( output
, '192.168.5.0/24 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4760 self
. assertRegex ( output
, '192.168.5.1 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4761 self
. assertNotIn ( '192.168.5.6' , output
)
4762 self
. assertRegex ( output
, '192.168.5.7 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4763 self
. assertRegex ( output
, '192.168.5.8 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4764 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
4766 print ( '## link state file' )
4767 output
= read_link_state_file ( 'veth99' )
4769 # checking DNS server and Domains
4770 self
. assertIn ( 'DNS=192.168.5.1 192.168.5.7 192.168.5.8' , output
)
4771 self
. assertIn ( 'DOMAINS=foo.example.com' , output
)
4773 print ( '## dnsmasq log' )
4774 output
= read_dnsmasq_log_file ()
4776 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
4777 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 192.168.5.11' , output
)
4778 self
. assertIn ( 'client provides name: test-hostname' , output
)
4779 self
. assertIn ( '26:mtu' , output
)
4781 self
. check_netlabel ( 'veth99' , r
'192\.168\.5\.0/24' )
4783 def test_dhcp_client_ipv4_use_routes_gateway ( self
):
4785 for ( routes
, gateway
, dns_and_ntp_routes
, classless
) in itertools
. product ([ True , False ], repeat
= 4 ):
4791 print ( f
'### test_dhcp_client_ipv4_use_routes_gateway(routes= {routes} , gateway= {gateway} , dns_and_ntp_routes= {dns_and_ntp_routes} , classless= {classless} )' )
4792 with self
. subTest ( routes
= routes
, gateway
= gateway
, dns_and_ntp_routes
= dns_and_ntp_routes
, classless
= classless
):
4793 self
._ test
_ dhcp
_ client
_ ipv
4_u se
_ routes
_ gateway
( routes
, gateway
, dns_and_ntp_routes
, classless
)
4795 def _test_dhcp_client_ipv4_use_routes_gateway ( self
, use_routes
, use_gateway
, dns_and_ntp_routes
, classless
):
4796 testunit
= '25-dhcp-client-ipv4-use-routes-use-gateway.network'
4797 testunits
= [ '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , testunit
]
4798 testunits
. append ( f
' {testunit} .d/use-routes- {use_routes} .conf' )
4799 testunits
. append ( f
' {testunit} .d/use-gateway- {use_gateway} .conf' )
4800 testunits
. append ( f
' {testunit} .d/use-dns-and-ntp-routes- {dns_and_ntp_routes} .conf' )
4801 copy_network_unit (* testunits
, copy_dropins
= False )
4804 self
. wait_online ([ 'veth-peer:carrier' ])
4805 additional_options
= [
4806 '--dhcp-option=option:dns-server,192.168.5.10,8.8.8.8' ,
4807 '--dhcp-option=option:ntp-server,192.168.5.11,9.9.9.9' ,
4808 '--dhcp-option=option:static-route,192.168.5.100,192.168.5.2,8.8.8.8,192.168.5.3'
4811 additional_options
+= [
4812 '--dhcp-option=option:classless-static-route,0.0.0.0/0,192.168.5.4,8.0.0.0/8,192.168.5.5'
4814 start_dnsmasq (* additional_options
)
4815 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4817 output
= check_output ( 'ip -4 route show dev veth99' )
4823 self
. assertRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4824 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4825 self
. assertRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4826 self
. assertRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4828 self
. assertRegex ( output
, r
'192.168.5.0/24 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4829 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4830 self
. assertRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4832 self
. assertNotRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4833 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4834 self
. assertNotRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4835 self
. assertNotRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4836 self
. assertNotRegex ( output
, r
'192.168.5.0/24 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4837 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4838 self
. assertNotRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4841 if use_gateway
and ( not classless
or not use_routes
):
4842 self
. assertRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4844 self
. assertNotRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4846 # Check route to gateway
4847 if ( use_gateway
or dns_and_ntp_routes
) and ( not classless
or not use_routes
):
4848 self
. assertRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4850 self
. assertNotRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4852 # Check RoutesToDNS= and RoutesToNTP=
4853 if dns_and_ntp_routes
:
4854 self
. assertRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4855 self
. assertRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4856 if classless
and use_routes
:
4857 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4858 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4860 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4861 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4863 self
. assertNotRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4864 self
. assertNotRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4865 self
. assertNotRegex ( output
, r
'8.8.8.8 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
4866 self
. assertNotRegex ( output
, r
'9.9.9.9 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
4868 # TODO: check json string
4869 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
4871 def test_dhcp_client_settings_anonymize ( self
):
4872 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-anonymize.network' )
4874 self
. wait_online ([ 'veth-peer:carrier' ])
4876 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4878 print ( '## dnsmasq log' )
4879 output
= read_dnsmasq_log_file ()
4881 self
. assertNotIn ( 'VendorClassIdentifier=SusantVendorTest' , output
)
4882 self
. assertNotIn ( 'test-hostname' , output
)
4883 self
. assertNotIn ( '26:mtu' , output
)
4885 def test_dhcp_keep_configuration_dhcp ( self
):
4886 copy_network_unit ( '25-veth.netdev' ,
4887 '25-dhcp-server-veth-peer.network' ,
4888 '25-dhcp-client-keep-configuration-dhcp.network' )
4890 self
. wait_online ([ 'veth-peer:carrier' ])
4892 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4894 output
= check_output ( 'ip address show dev veth99 scope global' )
4896 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4897 'valid_lft forever preferred_lft forever' )
4899 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
4902 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4903 print ( 'Wait for the DHCP lease to be expired' )
4906 # The lease address should be kept after the lease expired
4907 output
= check_output ( 'ip address show dev veth99 scope global' )
4909 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4910 'valid_lft forever preferred_lft forever' )
4914 # The lease address should be kept after networkd stopped
4915 output
= check_output ( 'ip address show dev veth99 scope global' )
4917 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4918 'valid_lft forever preferred_lft forever' )
4920 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-keep-configuration-dhcp.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4921 f
. write ( '[Network] \n DHCP=no \n ' )
4924 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4926 # Still the lease address should be kept after networkd restarted
4927 output
= check_output ( 'ip address show dev veth99 scope global' )
4929 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4930 'valid_lft forever preferred_lft forever' )
4932 def test_dhcp_keep_configuration_dhcp_on_stop ( self
):
4933 copy_network_unit ( '25-veth.netdev' ,
4934 '25-dhcp-server-veth-peer.network' ,
4935 '25-dhcp-client-keep-configuration-dhcp-on-stop.network' )
4937 self
. wait_online ([ 'veth-peer:carrier' ])
4939 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4941 output
= check_output ( 'ip address show dev veth99 scope global' )
4943 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
4948 output
= check_output ( 'ip address show dev veth99 scope global' )
4950 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
4953 self
. wait_online ([ 'veth-peer:routable' ])
4955 output
= check_output ( 'ip address show dev veth99 scope global' )
4957 self
. assertNotIn ( '192.168.5.' , output
)
4959 def test_dhcp_client_reuse_address_as_static ( self
):
4960 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' )
4962 self
. wait_online ([ 'veth-peer:carrier' ])
4964 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4966 # link become 'routable' when at least one protocol provide an valid address.
4967 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
4968 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
4970 output
= check_output ( 'ip address show dev veth99 scope global' )
4971 ipv4_address
= re
. search ( r
'192.168.5.[0-9]*/24' , output
). group ()
4972 ipv6_address
= re
. search ( r
'2600::[0-9a-f:]*/128' , output
). group ()
4973 static_network
= ' \n ' . join ([ '[Match]' , 'Name=veth99' , '[Network]' , 'IPv6AcceptRA=no' , 'Address=' + ipv4_address
, 'Address=' + ipv6_address
])
4974 print ( static_network
)
4976 remove_network_unit ( '25-dhcp-client.network' )
4978 with
open ( os
. path
. join ( network_unit_dir
, '25-static.network' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
4979 f
. write ( static_network
)
4982 self
. wait_online ([ 'veth99:routable' ])
4984 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
4986 self
. assertRegex ( output
, f
'inet {ipv4_address} brd 192.168.5.255 scope global veth99 \n *'
4987 'valid_lft forever preferred_lft forever' )
4989 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
4991 self
. assertRegex ( output
, f
'inet6 {ipv6_address} scope global * \n *'
4992 'valid_lft forever preferred_lft forever' )
4994 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
4995 def test_dhcp_client_vrf ( self
):
4996 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-vrf.network' ,
4997 '25-vrf.netdev' , '25-vrf.network' )
4999 self
. wait_online ([ 'veth-peer:carrier' ])
5001 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'vrf99:carrier' ])
5003 # link become 'routable' when at least one protocol provide an valid address.
5004 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5005 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5007 print ( '## ip -d link show dev vrf99' )
5008 output
= check_output ( 'ip -d link show dev vrf99' )
5010 self
. assertRegex ( output
, 'vrf table 42' )
5012 print ( '## ip address show vrf vrf99' )
5013 output
= check_output ( 'ip address show vrf vrf99' )
5015 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5016 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5017 self
. assertRegex ( output
, 'inet6 .* scope link' )
5019 print ( '## ip address show dev veth99' )
5020 output
= check_output ( 'ip address show dev veth99' )
5022 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5023 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5024 self
. assertRegex ( output
, 'inet6 .* scope link' )
5026 print ( '## ip route show vrf vrf99' )
5027 output
= check_output ( 'ip route show vrf vrf99' )
5029 self
. assertRegex ( output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.' )
5030 self
. assertRegex ( output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5' )
5031 self
. assertRegex ( output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5' )
5033 print ( '## ip route show table main dev veth99' )
5034 output
= check_output ( 'ip route show table main dev veth99' )
5036 self
. assertEqual ( output
, '' )
5038 def test_dhcp_client_gateway_onlink_implicit ( self
):
5039 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
5040 '25-dhcp-client-gateway-onlink-implicit.network' )
5042 self
. wait_online ([ 'veth-peer:carrier' ])
5044 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5046 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
5048 self
. assertRegex ( output
, '192.168.5' )
5050 output
= check_output ( 'ip route list dev veth99 10.0.0.0/8' )
5052 self
. assertRegex ( output
, 'onlink' )
5053 output
= check_output ( 'ip route list dev veth99 192.168.100.0/24' )
5055 self
. assertRegex ( output
, 'onlink' )
5057 def test_dhcp_client_with_ipv4ll ( self
):
5058 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
5059 '25-dhcp-client-with-ipv4ll.network' )
5061 # we need to increase timeout above default, as this will need to wait for
5062 # systemd-networkd to get the dhcpv4 transient failure event
5063 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:routable' ], timeout
= '60s' )
5065 output
= check_output ( 'ip -4 address show dev veth99' )
5067 self
. assertNotIn ( '192.168.5.' , output
)
5068 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
5071 print ( 'Wait for a DHCP lease to be acquired and the IPv4LL address to be dropped' )
5072 self
. wait_address ( 'veth99' , r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic' , ipv
= '-4' )
5073 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' )
5074 self
. wait_online ([ 'veth99:routable' ])
5076 output
= check_output ( 'ip -4 address show dev veth99' )
5078 self
. assertRegex ( output
, r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99' )
5079 self
. assertNotIn ( '169.254.' , output
)
5080 self
. assertNotIn ( 'scope link' , output
)
5083 print ( 'Wait for the DHCP lease to be expired and an IPv4LL address to be acquired' )
5084 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 )
5085 self
. wait_address ( 'veth99' , r
'inet 169\.254\.133\.11/16 metric 2048 brd 169\.254\.255\.255 scope link' , scope
= 'link' , ipv
= '-4' )
5087 output
= check_output ( 'ip -4 address show dev veth99' )
5089 self
. assertNotIn ( '192.168.5.' , output
)
5090 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
5092 def test_dhcp_client_use_dns ( self
):
5093 def check ( self
, ipv4
, ipv6
):
5094 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5095 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5096 f
. write ( '[DHCPv4] \n UseDNS=' )
5097 f
. write ( 'yes' if ipv4
else 'no' )
5098 f
. write ( ' \n [DHCPv6] \n UseDNS=' )
5099 f
. write ( 'yes' if ipv6
else 'no' )
5100 f
. write ( ' \n [IPv6AcceptRA] \n UseDNS=no' )
5103 self
. wait_online ([ 'veth99:routable' ])
5105 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5106 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5107 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5109 # make resolved re-read the link state file
5110 check_output (* resolvectl_cmd
, 'revert' , 'veth99' , env
= env
)
5112 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth99' , env
= env
)
5115 self
. assertIn ( '192.168.5.1' , output
)
5117 self
. assertNotIn ( '192.168.5.1' , output
)
5119 self
. assertIn ( '2600::1' , output
)
5121 self
. assertNotIn ( '2600::1' , output
)
5123 # TODO: check json string
5124 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5126 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5129 self
. wait_online ([ 'veth-peer:carrier' ])
5130 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1' ,
5131 '--dhcp-option=option6:dns-server,[2600::1]' )
5133 check ( self
, True , True )
5134 check ( self
, True , False )
5135 check ( self
, False , True )
5136 check ( self
, False , False )
5138 class NetworkdDHCPPDTests ( unittest
. TestCase
, Utilities
):
5146 def test_dhcp6pd ( self
):
5147 copy_network_unit ( '25-veth.netdev' , '25-dhcp6pd-server.network' , '25-dhcp6pd-upstream.network' ,
5148 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
5149 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
5150 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
5151 '25-dhcp-pd-downstream-dummy97.network' ,
5152 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
5153 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' )
5156 self
. wait_online ([ 'veth-peer:routable' ])
5157 start_isc_dhcpd ( conf_file
= 'isc-dhcpd-dhcp6pd.conf' , ipv
= '-6' )
5158 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5159 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5161 print ( '### ip -6 address show dev veth-peer scope global' )
5162 output
= check_output ( 'ip -6 address show dev veth-peer scope global' )
5164 self
. assertIn ( 'inet6 3ffe:501:ffff:100::1/64 scope global' , output
)
5168 # dummy97: 0x01 (The link will appear later)
5170 # dummy99: auto -> 0x02 (No address assignment)
5175 print ( '### ip -6 address show dev veth99 scope global' )
5176 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5179 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:100::[0-9]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5180 # address in IA_PD (Token=static)
5181 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic' )
5182 # address in IA_PD (Token=eui64)
5183 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic' )
5184 # address in IA_PD (temporary)
5185 # Note that the temporary addresses may appear after the link enters configured state
5186 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' )
5188 print ( '### ip -6 address show dev test1 scope global' )
5189 output
= check_output ( 'ip -6 address show dev test1 scope global' )
5191 # address in IA_PD (Token=static)
5192 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5193 # address in IA_PD (temporary)
5194 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' )
5196 print ( '### ip -6 address show dev dummy98 scope global' )
5197 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5199 # address in IA_PD (Token=static)
5200 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5201 # address in IA_PD (temporary)
5202 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' )
5204 print ( '### ip -6 address show dev dummy99 scope global' )
5205 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5208 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
5210 print ( '### ip -6 address show dev veth97 scope global' )
5211 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
5213 # address in IA_PD (Token=static)
5214 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5215 # address in IA_PD (Token=eui64)
5216 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5217 # address in IA_PD (temporary)
5218 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' )
5220 print ( '### ip -6 address show dev veth97-peer scope global' )
5221 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
5223 # NDisc address (Token=static)
5224 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5225 # NDisc address (Token=eui64)
5226 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5227 # NDisc address (temporary)
5228 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' )
5230 print ( '### ip -6 address show dev veth98 scope global' )
5231 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
5233 # address in IA_PD (Token=static)
5234 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5235 # address in IA_PD (Token=eui64)
5236 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5237 # address in IA_PD (temporary)
5238 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' )
5240 print ( '### ip -6 address show dev veth98-peer scope global' )
5241 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
5243 # NDisc address (Token=static)
5244 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5245 # NDisc address (Token=eui64)
5246 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5247 # NDisc address (temporary)
5248 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' )
5250 print ( '### ip -6 route show type unreachable' )
5251 output
= check_output ( 'ip -6 route show type unreachable' )
5253 self
. assertRegex ( output
, 'unreachable 3ffe:501:ffff:[2-9a-f]00::/56 dev lo proto dhcp' )
5255 print ( '### ip -6 route show dev veth99' )
5256 output
= check_output ( 'ip -6 route show dev veth99' )
5258 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]10::/64 proto kernel metric [0-9]* expires' )
5260 print ( '### ip -6 route show dev test1' )
5261 output
= check_output ( 'ip -6 route show dev test1' )
5263 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5265 print ( '### ip -6 route show dev dummy98' )
5266 output
= check_output ( 'ip -6 route show dev dummy98' )
5268 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5270 print ( '### ip -6 route show dev dummy99' )
5271 output
= check_output ( 'ip -6 route show dev dummy99' )
5273 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
5275 print ( '### ip -6 route show dev veth97' )
5276 output
= check_output ( 'ip -6 route show dev veth97' )
5278 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto kernel metric [0-9]* expires' )
5280 print ( '### ip -6 route show dev veth97-peer' )
5281 output
= check_output ( 'ip -6 route show dev veth97-peer' )
5283 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto ra metric [0-9]* expires' )
5285 print ( '### ip -6 route show dev veth98' )
5286 output
= check_output ( 'ip -6 route show dev veth98' )
5288 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto kernel metric [0-9]* expires' )
5290 print ( '### ip -6 route show dev veth98-peer' )
5291 output
= check_output ( 'ip -6 route show dev veth98-peer' )
5293 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto ra metric [0-9]* expires' )
5295 # Test case for a downstream which appears later
5296 check_output ( 'ip link add dummy97 type dummy' )
5297 self
. wait_online ([ 'dummy97:routable' ])
5299 print ( '### ip -6 address show dev dummy97 scope global' )
5300 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
5302 # address in IA_PD (Token=static)
5303 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5304 # address in IA_PD (temporary)
5305 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' )
5307 print ( '### ip -6 route show dev dummy97' )
5308 output
= check_output ( 'ip -6 route show dev dummy97' )
5310 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]01::/64 proto kernel metric [0-9]* expires' )
5312 # Test case for reconfigure
5313 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
5314 self
. wait_online ([ 'dummy98:routable' , 'dummy99:degraded' ])
5316 print ( '### ip -6 address show dev dummy98 scope global' )
5317 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5319 # address in IA_PD (Token=static)
5320 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5321 # address in IA_PD (temporary)
5322 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' )
5324 print ( '### ip -6 address show dev dummy99 scope global' )
5325 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5328 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
5330 print ( '### ip -6 route show dev dummy98' )
5331 output
= check_output ( 'ip -6 route show dev dummy98' )
5333 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5335 print ( '### ip -6 route show dev dummy99' )
5336 output
= check_output ( 'ip -6 route show dev dummy99' )
5338 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
5340 self
. check_netlabel ( 'dummy98' , '3ffe:501:ffff:[2-9a-f]00::/64' )
5342 def verify_dhcp4_6rd ( self
, tunnel_name
):
5343 print ( '### ip -4 address show dev veth-peer scope global' )
5344 output
= check_output ( 'ip -4 address show dev veth-peer scope global' )
5346 self
. assertIn ( 'inet 10.0.0.1/8 brd 10.255.255.255 scope global veth-peer' , output
)
5350 # dummy97: 0x01 (The link will appear later)
5352 # dummy99: auto -> 0x0[23] (No address assignment)
5353 # 6rd-XXX: auto -> 0x0[23]
5358 print ( '### ip -4 address show dev veth99 scope global' )
5359 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
5361 self
. assertRegex ( output
, 'inet 10.100.100.[0-9]*/8 (metric 1024 |)brd 10.255.255.255 scope global dynamic veth99' )
5363 print ( '### ip -6 address show dev veth99 scope global' )
5364 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5366 # address in IA_PD (Token=static)
5367 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5368 # address in IA_PD (Token=eui64)
5369 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5370 # address in IA_PD (temporary)
5371 # Note that the temporary addresses may appear after the link enters configured state
5372 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' )
5374 print ( '### ip -6 address show dev test1 scope global' )
5375 output
= check_output ( 'ip -6 address show dev test1 scope global' )
5377 # address in IA_PD (Token=static)
5378 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5379 # address in IA_PD (temporary)
5380 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' )
5382 print ( '### ip -6 address show dev dummy98 scope global' )
5383 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5385 # address in IA_PD (Token=static)
5386 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5387 # address in IA_PD (temporary)
5388 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' )
5390 print ( '### ip -6 address show dev dummy99 scope global' )
5391 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5394 self
. assertNotRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+0[23]' )
5396 print ( '### ip -6 address show dev veth97 scope global' )
5397 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
5399 # address in IA_PD (Token=static)
5400 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5401 # address in IA_PD (Token=eui64)
5402 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5403 # address in IA_PD (temporary)
5404 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' )
5406 print ( '### ip -6 address show dev veth97-peer scope global' )
5407 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
5409 # NDisc address (Token=static)
5410 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5411 # NDisc address (Token=eui64)
5412 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5413 # NDisc address (temporary)
5414 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' )
5416 print ( '### ip -6 address show dev veth98 scope global' )
5417 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
5419 # address in IA_PD (Token=static)
5420 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5421 # address in IA_PD (Token=eui64)
5422 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5423 # address in IA_PD (temporary)
5424 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' )
5426 print ( '### ip -6 address show dev veth98-peer scope global' )
5427 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
5429 # NDisc address (Token=static)
5430 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5431 # NDisc address (Token=eui64)
5432 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5433 # NDisc address (temporary)
5434 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' )
5436 print ( '### ip -6 route show type unreachable' )
5437 output
= check_output ( 'ip -6 route show type unreachable' )
5439 self
. assertRegex ( output
, 'unreachable 2001:db8:6464:[0-9a-f]+00::/56 dev lo proto dhcp' )
5441 print ( '### ip -6 route show dev veth99' )
5442 output
= check_output ( 'ip -6 route show dev veth99' )
5444 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+10::/64 proto kernel metric [0-9]* expires' )
5446 print ( '### ip -6 route show dev test1' )
5447 output
= check_output ( 'ip -6 route show dev test1' )
5449 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
5451 print ( '### ip -6 route show dev dummy98' )
5452 output
= check_output ( 'ip -6 route show dev dummy98' )
5454 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
5456 print ( '### ip -6 route show dev dummy99' )
5457 output
= check_output ( 'ip -6 route show dev dummy99' )
5459 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto dhcp metric [0-9]* expires' )
5461 print ( '### ip -6 route show dev veth97' )
5462 output
= check_output ( 'ip -6 route show dev veth97' )
5464 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto kernel metric [0-9]* expires' )
5466 print ( '### ip -6 route show dev veth97-peer' )
5467 output
= check_output ( 'ip -6 route show dev veth97-peer' )
5469 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto ra metric [0-9]* expires' )
5471 print ( '### ip -6 route show dev veth98' )
5472 output
= check_output ( 'ip -6 route show dev veth98' )
5474 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto kernel metric [0-9]* expires' )
5476 print ( '### ip -6 route show dev veth98-peer' )
5477 output
= check_output ( 'ip -6 route show dev veth98-peer' )
5479 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto ra metric [0-9]* expires' )
5481 print ( '### ip -6 address show dev dummy97 scope global' )
5482 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
5484 # address in IA_PD (Token=static)
5485 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5486 # address in IA_PD (temporary)
5487 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' )
5489 print ( '### ip -6 route show dev dummy97' )
5490 output
= check_output ( 'ip -6 route show dev dummy97' )
5492 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+01::/64 proto kernel metric [0-9]* expires' )
5494 print ( f
'### ip -d link show dev {tunnel_name} ' )
5495 output
= check_output ( f
'ip -d link show dev {tunnel_name} ' )
5497 self
. assertIn ( 'link/sit 10.100.100.' , output
)
5498 self
. assertIn ( 'local 10.100.100.' , output
)
5499 self
. assertIn ( 'ttl 64' , output
)
5500 self
. assertIn ( '6rd-prefix 2001:db8::/32' , output
)
5501 self
. assertIn ( '6rd-relay_prefix 10.0.0.0/8' , output
)
5503 print ( f
'### ip -6 address show dev {tunnel_name} ' )
5504 output
= check_output ( f
'ip -6 address show dev {tunnel_name} ' )
5506 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' )
5507 self
. assertRegex ( output
, 'inet6 ::10.100.100.[0-9]+/96 scope global' )
5509 print ( f
'### ip -6 route show dev {tunnel_name} ' )
5510 output
= check_output ( f
'ip -6 route show dev {tunnel_name} ' )
5512 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto kernel metric [0-9]* expires' )
5513 self
. assertRegex ( output
, '::/96 proto kernel metric [0-9]*' )
5515 print ( '### ip -6 route show default' )
5516 output
= check_output ( 'ip -6 route show default' )
5518 self
. assertIn ( 'default' , output
)
5519 self
. assertIn ( f
'via ::10.0.0.1 dev {tunnel_name} ' , output
)
5521 def test_dhcp4_6rd ( self
):
5522 copy_network_unit ( '25-veth.netdev' , '25-dhcp4-6rd-server.network' , '25-dhcp4-6rd-upstream.network' ,
5523 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
5524 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
5525 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
5526 '25-dhcp-pd-downstream-dummy97.network' ,
5527 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
5528 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' ,
5529 '80-6rd-tunnel.network' )
5532 self
. wait_online ([ 'veth-peer:routable' ])
5535 # 6rd-prefix: 2001:db8::/32
5536 # br-addresss: 10.0.0.1
5538 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' ,
5539 ipv4_range
= '10.100.100.100,10.100.100.200' ,
5540 ipv4_router
= '10.0.0.1' )
5541 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5542 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5544 # Test case for a downstream which appears later
5545 check_output ( 'ip link add dummy97 type dummy' )
5546 self
. wait_online ([ 'dummy97:routable' ])
5550 for name
in os
. listdir ( '/sys/class/net/' ):
5551 if name
. startswith ( '6rd-' ):
5555 self
. wait_online ([ f
' {tunnel_name} :routable' ])
5557 self
. verify_dhcp4_6rd ( tunnel_name
)
5559 # Test case for reconfigure
5560 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
5561 self
. wait_online ([ 'dummy98:routable' , 'dummy99:degraded' ])
5563 self
. verify_dhcp4_6rd ( tunnel_name
)
5565 print ( 'Wait for the DHCP lease to be renewed/rebind' )
5568 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy97:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5569 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5571 self
. verify_dhcp4_6rd ( tunnel_name
)
5573 class NetworkdIPv6PrefixTests ( unittest
. TestCase
, Utilities
):
5581 def test_ipv6_route_prefix ( self
):
5582 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client.network' , '25-ipv6ra-prefix.network' ,
5583 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
5586 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
5588 output
= check_output ( 'ip address show dev veth-peer' )
5590 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
5591 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
5592 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
5594 output
= check_output ( 'ip -6 route show dev veth-peer' )
5596 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
5597 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
5598 self
. assertNotIn ( '2001:db8:0:3::/64 proto ra' , output
)
5599 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
5600 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
5601 self
. assertNotIn ( '2001:db2:fff::/64 via ' , output
)
5603 output
= check_output ( 'ip address show dev veth99' )
5605 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
5606 self
. assertIn ( 'inet6 2001:db8:0:2:1a:2b:3c:4d' , output
)
5607 self
. assertIn ( 'inet6 2001:db8:0:2:fa:de:ca:fe' , output
)
5608 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
5610 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth-peer' , env
= env
)
5612 self
. assertRegex ( output
, '2001:db8:1:1::2' )
5614 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth-peer' , env
= env
)
5616 self
. assertIn ( 'example.com' , output
)
5618 # TODO: check json string
5619 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5621 def test_ipv6_route_prefix_deny_list ( self
):
5622 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client-deny-list.network' , '25-ipv6ra-prefix.network' ,
5623 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
5626 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
5628 output
= check_output ( 'ip address show dev veth-peer' )
5630 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
5631 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
5633 output
= check_output ( 'ip -6 route show dev veth-peer' )
5635 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
5636 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
5637 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
5638 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
5640 output
= check_output ( 'ip address show dev veth99' )
5642 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
5643 self
. assertIn ( 'inet6 2001:db8:0:2:' , output
)
5645 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth-peer' , env
= env
)
5647 self
. assertRegex ( output
, '2001:db8:1:1::2' )
5649 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth-peer' , env
= env
)
5651 self
. assertIn ( 'example.com' , output
)
5653 class NetworkdMTUTests ( unittest
. TestCase
, Utilities
):
5661 def check_mtu ( self
, mtu
, ipv6_mtu
= None , reset
= True ):
5667 self
. wait_online ([ 'dummy98:routable' ])
5668 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
5669 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
5671 # test normal restart
5673 self
. wait_online ([ 'dummy98:routable' ])
5674 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
5675 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
5678 self
. reset_check_mtu ( mtu
, ipv6_mtu
)
5680 def reset_check_mtu ( self
, mtu
, ipv6_mtu
= None ):
5681 ''' test setting mtu/ipv6_mtu with interface already up '''
5684 # note - changing the device mtu resets the ipv6 mtu
5685 check_output ( 'ip link set up mtu 1501 dev dummy98' )
5686 check_output ( 'ip link set up mtu 1500 dev dummy98' )
5687 self
. check_link_attr ( 'dummy98' , 'mtu' , '1500' )
5688 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , '1500' )
5690 self
. check_mtu ( mtu
, ipv6_mtu
, reset
= False )
5692 def test_mtu_network ( self
):
5693 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' )
5694 self
. check_mtu ( '1600' )
5696 def test_mtu_netdev ( self
):
5697 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network' , copy_dropins
= False )
5698 # note - MTU set by .netdev happens ONLY at device creation!
5699 self
. check_mtu ( '1600' , reset
= False )
5701 def test_mtu_link ( self
):
5702 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network' , copy_dropins
= False )
5703 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
5704 self
. check_mtu ( '1600' , reset
= False )
5706 def test_ipv6_mtu ( self
):
5707 ''' set ipv6 mtu without setting device mtu '''
5708 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1400.conf' )
5709 self
. check_mtu ( '1500' , '1400' )
5711 def test_ipv6_mtu_toolarge ( self
):
5712 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
5713 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5714 self
. check_mtu ( '1500' , '1500' )
5716 def test_mtu_network_ipv6_mtu ( self
):
5717 ''' set ipv6 mtu and set device mtu via network file '''
5718 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5719 self
. check_mtu ( '1600' , '1550' )
5721 def test_mtu_netdev_ipv6_mtu ( self
):
5722 ''' set ipv6 mtu and set device mtu via netdev file '''
5723 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5724 self
. check_mtu ( '1600' , '1550' , reset
= False )
5726 def test_mtu_link_ipv6_mtu ( self
):
5727 ''' set ipv6 mtu and set device mtu via link file '''
5728 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5729 self
. check_mtu ( '1600' , '1550' , reset
= False )
5732 if __name__
== '__main__' :
5733 parser
= argparse
. ArgumentParser ()
5734 parser
. add_argument ( '--build-dir' , help = 'Path to build dir' , dest
= 'build_dir' )
5735 parser
. add_argument ( '--networkd' , help = 'Path to systemd-networkd' , dest
= 'networkd_bin' )
5736 parser
. add_argument ( '--resolved' , help = 'Path to systemd-resolved' , dest
= 'resolved_bin' )
5737 parser
. add_argument ( '--timesyncd' , help = 'Path to systemd-timesyncd' , dest
= 'timesyncd_bin' )
5738 parser
. add_argument ( '--udevd' , help = 'Path to systemd-udevd' , dest
= 'udevd_bin' )
5739 parser
. add_argument ( '--wait-online' , help = 'Path to systemd-networkd-wait-online' , dest
= 'wait_online_bin' )
5740 parser
. add_argument ( '--networkctl' , help = 'Path to networkctl' , dest
= 'networkctl_bin' )
5741 parser
. add_argument ( '--resolvectl' , help = 'Path to resolvectl' , dest
= 'resolvectl_bin' )
5742 parser
. add_argument ( '--timedatectl' , help = 'Path to timedatectl' , dest
= 'timedatectl_bin' )
5743 parser
. add_argument ( '--udevadm' , help = 'Path to udevadm' , dest
= 'udevadm_bin' )
5744 parser
. add_argument ( '--valgrind' , help = 'Enable valgrind' , dest
= 'use_valgrind' , type = bool , nargs
= '?' , const
= True , default
= use_valgrind
)
5745 parser
. add_argument ( '--debug' , help = 'Generate debugging logs' , dest
= 'enable_debug' , type = bool , nargs
= '?' , const
= True , default
= enable_debug
)
5746 parser
. add_argument ( '--asan-options' , help = 'ASAN options' , dest
= 'asan_options' )
5747 parser
. add_argument ( '--lsan-options' , help = 'LSAN options' , dest
= 'lsan_options' )
5748 parser
. add_argument ( '--ubsan-options' , help = 'UBSAN options' , dest
= 'ubsan_options' )
5749 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
)
5750 ns
, unknown_args
= parser
. parse_known_args ( namespace
= unittest
)
5753 if ns
. networkd_bin
or ns
. resolved_bin
or ns
. timesyncd_bin
or ns
. udevd_bin
or \
5754 ns
. wait_online_bin
or ns
. networkctl_bin
or ns
. resolvectl_bin
or ns
. timedatectl_bin
or ns
. udevadm_bin
:
5755 print ( 'WARNING: --networkd, --resolved, --timesyncd, --udevd, --wait-online, --networkctl, --resolvectl, --timedatectl, or --udevadm options are ignored when --build-dir is specified.' )
5756 networkd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd' )
5757 resolved_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-resolved' )
5758 timesyncd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-timesyncd' )
5759 udevd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-udevd' )
5760 wait_online_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd-wait-online' )
5761 networkctl_bin
= os
. path
. join ( ns
. build_dir
, 'networkctl' )
5762 resolvectl_bin
= os
. path
. join ( ns
. build_dir
, 'resolvectl' )
5763 timedatectl_bin
= os
. path
. join ( ns
. build_dir
, 'timedatectl' )
5764 udevadm_bin
= os
. path
. join ( ns
. build_dir
, 'udevadm' )
5767 networkd_bin
= ns
. networkd_bin
5769 resolved_bin
= ns
. resolved_bin
5770 if ns
. timesyncd_bin
:
5771 timesyncd_bin
= ns
. timesyncd_bin
5773 udevd_bin
= ns
. udevd_bin
5774 if ns
. wait_online_bin
:
5775 wait_online_bin
= ns
. wait_online_bin
5776 if ns
. networkctl_bin
:
5777 networkctl_bin
= ns
. networkctl_bin
5778 if ns
. resolvectl_bin
:
5779 resolvectl_bin
= ns
. resolvectl_bin
5780 if ns
. timedatectl_bin
:
5781 timedatectl_bin
= ns
. timedatectl_bin
5783 udevadm_bin
= ns
. udevadm_bin
5785 use_valgrind
= ns
. use_valgrind
5786 enable_debug
= ns
. enable_debug
5787 asan_options
= ns
. asan_options
5788 lsan_options
= ns
. lsan_options
5789 ubsan_options
= ns
. ubsan_options
5790 with_coverage
= ns
. with_coverage
5793 # Do not forget the trailing space.
5794 valgrind_cmd
= 'valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all '
5796 networkctl_cmd
= valgrind_cmd
. split () + [ networkctl_bin
]
5797 resolvectl_cmd
= valgrind_cmd
. split () + [ resolvectl_bin
]
5798 timedatectl_cmd
= valgrind_cmd
. split () + [ timedatectl_bin
]
5799 udevadm_cmd
= valgrind_cmd
. split () + [ udevadm_bin
]
5800 wait_online_cmd
= valgrind_cmd
. split () + [ wait_online_bin
]
5803 env
. update ({ 'ASAN_OPTIONS' : asan_options
})
5805 env
. update ({ 'LSAN_OPTIONS' : lsan_options
})
5807 env
. update ({ 'UBSAN_OPTIONS' : ubsan_options
})
5809 env
. update ({ 'SYSTEMD_MEMPOOL' : '0' })
5811 wait_online_env
= env
. copy ()
5813 wait_online_env
. update ({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
5815 sys
. argv
[ 1 :] = unknown_args
5816 unittest
. main ( verbosity
= 3 )