]>
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_all_unmanaged ( self
):
1162 self
. wait_online ([])
1164 def test_wait_online_any ( self
):
1165 copy_network_unit ( '25-bridge.netdev' , '25-bridge.network' , '11-dummy.netdev' , '11-dummy.network' )
1168 self
. wait_online ([ 'bridge99' , 'test1:degraded' ], bool_any
= True )
1170 self
. wait_operstate ( 'bridge99' , '(off|no-carrier)' , setup_state
= 'configuring' )
1171 self
. wait_operstate ( 'test1' , 'degraded' )
1173 class NetworkdNetDevTests ( unittest
. TestCase
, Utilities
):
1181 def test_dropin_and_name_conflict ( self
):
1182 copy_network_unit ( '10-dropin-test.netdev' , '15-name-conflict-test.netdev' )
1185 self
. wait_online ([ 'dropin-test:off' ], setup_state
= 'unmanaged' )
1187 output
= check_output ( 'ip link show dropin-test' )
1189 self
. assertRegex ( output
, '00:50:56:c0:00:28' )
1191 @expectedFailureIfModuleIsNotAvailable ( 'bareudp' )
1192 def test_bareudp ( self
):
1193 copy_network_unit ( '25-bareudp.netdev' , '26-netdev-link-local-addressing-yes.network' )
1196 self
. wait_online ([ 'bareudp99:degraded' ])
1198 output
= check_output ( 'ip -d link show bareudp99' )
1200 self
. assertRegex ( output
, 'dstport 1000 ' )
1201 self
. assertRegex ( output
, 'ethertype ip ' )
1203 @expectedFailureIfModuleIsNotAvailable ( 'batman-adv' )
1204 def test_batadv ( self
):
1205 copy_network_unit ( '25-batadv.netdev' , '26-netdev-link-local-addressing-yes.network' )
1208 self
. wait_online ([ 'batadv99:degraded' ])
1210 output
= check_output ( 'ip -d link show batadv99' )
1212 self
. assertRegex ( output
, 'batadv' )
1214 def test_bridge ( self
):
1215 copy_network_unit ( '25-bridge.netdev' , '25-bridge-configure-without-carrier.network' )
1218 self
. wait_online ([ 'bridge99:no-carrier' ])
1220 tick
= os
. sysconf ( 'SC_CLK_TCK' )
1221 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'hello_time' )) / tick
))
1222 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'max_age' )) / tick
))
1223 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'forward_delay' )) / tick
))
1224 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'ageing_time' )) / tick
))
1225 self
. assertEqual ( 9 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'priority' )))
1226 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_querier' )))
1227 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_snooping' )))
1228 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'stp_state' )))
1229 self
. assertEqual ( 3 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_igmp_version' )))
1231 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bridge99' , env
= env
)
1233 self
. assertRegex ( output
, 'Priority: 9' )
1234 self
. assertRegex ( output
, 'STP: yes' )
1235 self
. assertRegex ( output
, 'Multicast IGMP Version: 3' )
1237 output
= check_output ( 'ip -d link show bridge99' )
1239 self
. assertIn ( 'vlan_filtering 1 ' , output
)
1240 self
. assertIn ( 'vlan_protocol 802.1ad ' , output
)
1241 self
. assertIn ( 'vlan_default_pvid 9 ' , output
)
1243 def test_bond ( self
):
1244 copy_network_unit ( '25-bond.netdev' , '25-bond-balanced-tlb.netdev' )
1247 self
. wait_online ([ 'bond99:off' , 'bond98:off' ], setup_state
= 'unmanaged' )
1249 self
. check_link_attr ( 'bond99' , 'bonding' , 'mode' , '802.3ad 4' )
1250 self
. check_link_attr ( 'bond99' , 'bonding' , 'xmit_hash_policy' , 'layer3+4 1' )
1251 self
. check_link_attr ( 'bond99' , 'bonding' , 'miimon' , '1000' )
1252 self
. check_link_attr ( 'bond99' , 'bonding' , 'lacp_rate' , 'fast 1' )
1253 self
. check_link_attr ( 'bond99' , 'bonding' , 'updelay' , '2000' )
1254 self
. check_link_attr ( 'bond99' , 'bonding' , 'downdelay' , '2000' )
1255 self
. check_link_attr ( 'bond99' , 'bonding' , 'resend_igmp' , '4' )
1256 self
. check_link_attr ( 'bond99' , 'bonding' , 'min_links' , '1' )
1257 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_actor_sys_prio' , '1218' )
1258 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_user_port_key' , '811' )
1259 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_actor_system' , '00:11:22:33:44:55' )
1261 self
. check_link_attr ( 'bond98' , 'bonding' , 'mode' , 'balance-tlb 5' )
1262 self
. check_link_attr ( 'bond98' , 'bonding' , 'tlb_dynamic_lb' , '1' )
1264 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bond99' , env
= env
)
1266 self
. assertIn ( 'Mode: 802.3ad' , output
)
1267 self
. assertIn ( 'Miimon: 1s' , output
)
1268 self
. assertIn ( 'Updelay: 2s' , output
)
1269 self
. assertIn ( 'Downdelay: 2s' , output
)
1271 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bond98' , env
= env
)
1273 self
. assertIn ( 'Mode: balance-tlb' , output
)
1275 def test_vlan ( self
):
1276 copy_network_unit ( '21-vlan.netdev' , '11-dummy.netdev' ,
1277 '21-vlan.network' , '21-vlan-test1.network' )
1280 self
. wait_online ([ 'test1:degraded' , 'vlan99:routable' ])
1282 output
= check_output ( 'ip -d link show test1' )
1284 self
. assertRegex ( output
, ' mtu 2000 ' )
1286 output
= check_output ( 'ip -d link show vlan99' )
1288 self
. assertIn ( ' mtu 2000 ' , output
)
1289 self
. assertIn ( 'REORDER_HDR' , output
)
1290 self
. assertIn ( 'LOOSE_BINDING' , output
)
1291 self
. assertIn ( 'GVRP' , output
)
1292 self
. assertIn ( 'MVRP' , output
)
1293 self
. assertIn ( ' id 99 ' , output
)
1294 self
. assertIn ( 'ingress-qos-map { 4:100 7:13 }' , output
)
1295 self
. assertIn ( 'egress-qos-map { 0:1 1:3 6:6 7:7 10:3 }' , output
)
1297 output
= check_output ( 'ip -4 address show dev test1' )
1299 self
. assertRegex ( output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1' )
1300 self
. assertRegex ( output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1' )
1302 output
= check_output ( 'ip -4 address show dev vlan99' )
1304 self
. assertRegex ( output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99' )
1306 def test_vlan_on_bond ( self
):
1307 # For issue #24377 (https://github.com/systemd/systemd/issues/24377),
1308 # which is fixed by b05e52000b4eee764b383cc3031da0a3739e996e (PR#24020).
1310 copy_network_unit ( '21-bond-802.3ad.netdev' , '21-bond-802.3ad.network' ,
1311 '21-vlan-on-bond.netdev' , '21-vlan-on-bond.network' )
1313 self
. wait_online ([ 'bond99:off' ])
1314 self
. wait_operstate ( 'vlan99' , operstate
= 'off' , setup_state
= 'configuring' , setup_timeout
= 10 )
1316 # The commit b05e52000b4eee764b383cc3031da0a3739e996e adds ", ignoring". To make it easily confirmed
1317 # that the issue is fixed by the commit, let's allow to match both string.
1318 log_re
= re
. compile ( 'vlan99: Could not bring up interface(, ignoring|): Network is down$' , re
. MULTILINE
)
1322 if log_re
. search ( read_networkd_log ()):
1327 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '21-dummy-bond-slave.network' )
1329 self
. wait_online ([ 'test1:enslaved' , 'dummy98:enslaved' , 'bond99:carrier' , 'vlan99:routable' ])
1331 def test_macvtap ( self
):
1333 for mode
in [ 'private' , 'vepa' , 'bridge' , 'passthru' ]:
1339 print ( f
'### test_macvtap(mode= {mode} )' )
1340 with self
. subTest ( mode
= mode
):
1341 copy_network_unit ( '21-macvtap.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1342 '11-dummy.netdev' , '25-macvtap.network' )
1343 with
open ( os
. path
. join ( network_unit_dir
, '21-macvtap.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1344 f
. write ( '[MACVTAP] \n Mode=' + mode
)
1347 self
. wait_online ([ 'macvtap99:degraded' ,
1348 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1350 output
= check_output ( 'ip -d link show macvtap99' )
1352 self
. assertRegex ( output
, 'macvtap mode ' + mode
+ ' ' )
1354 def test_macvlan ( self
):
1356 for mode
in [ 'private' , 'vepa' , 'bridge' , 'passthru' ]:
1362 print ( f
'### test_macvlan(mode= {mode} )' )
1363 with self
. subTest ( mode
= mode
):
1364 copy_network_unit ( '21-macvlan.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1365 '11-dummy.netdev' , '25-macvlan.network' )
1366 with
open ( os
. path
. join ( network_unit_dir
, '21-macvlan.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1367 f
. write ( '[MACVLAN] \n Mode=' + mode
)
1370 self
. wait_online ([ 'macvlan99:degraded' ,
1371 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1373 output
= check_output ( 'ip -d link show test1' )
1375 self
. assertRegex ( output
, ' mtu 2000 ' )
1377 output
= check_output ( 'ip -d link show macvlan99' )
1379 self
. assertRegex ( output
, ' mtu 2000 ' )
1380 self
. assertRegex ( output
, 'macvlan mode ' + mode
+ ' ' )
1382 remove_link ( 'test1' )
1385 check_output ( "ip link add test1 type dummy" )
1386 self
. wait_online ([ 'macvlan99:degraded' ,
1387 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1389 output
= check_output ( 'ip -d link show test1' )
1391 self
. assertRegex ( output
, ' mtu 2000 ' )
1393 output
= check_output ( 'ip -d link show macvlan99' )
1395 self
. assertRegex ( output
, ' mtu 2000 ' )
1396 self
. assertRegex ( output
, 'macvlan mode ' + mode
+ ' ' )
1398 @expectedFailureIfModuleIsNotAvailable ( 'ipvlan' )
1399 def test_ipvlan ( self
):
1401 for mode
, flag
in [[ 'L2' , 'private' ], [ 'L3' , 'vepa' ], [ 'L3S' , 'bridge' ]]:
1407 print ( f
'### test_ipvlan(mode= {mode} , flag= {flag} )' )
1408 with self
. subTest ( mode
= mode
, flag
= flag
):
1409 copy_network_unit ( '25-ipvlan.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1410 '11-dummy.netdev' , '25-ipvlan.network' )
1411 with
open ( os
. path
. join ( network_unit_dir
, '25-ipvlan.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1412 f
. write ( '[IPVLAN] \n Mode=' + mode
+ ' \n Flags=' + flag
)
1415 self
. wait_online ([ 'ipvlan99:degraded' , 'test1:degraded' ])
1417 output
= check_output ( 'ip -d link show ipvlan99' )
1419 self
. assertRegex ( output
, 'ipvlan *mode ' + mode
. lower () + ' ' + flag
)
1421 @expectedFailureIfModuleIsNotAvailable ( 'ipvtap' )
1422 def test_ipvtap ( self
):
1424 for mode
, flag
in [[ 'L2' , 'private' ], [ 'L3' , 'vepa' ], [ 'L3S' , 'bridge' ]]:
1430 print ( f
'### test_ipvtap(mode= {mode} , flag= {flag} )' )
1431 with self
. subTest ( mode
= mode
, flag
= flag
):
1432 copy_network_unit ( '25-ipvtap.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1433 '11-dummy.netdev' , '25-ipvtap.network' )
1434 with
open ( os
. path
. join ( network_unit_dir
, '25-ipvtap.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1435 f
. write ( '[IPVTAP] \n Mode=' + mode
+ ' \n Flags=' + flag
)
1438 self
. wait_online ([ 'ipvtap99:degraded' , 'test1:degraded' ])
1440 output
= check_output ( 'ip -d link show ipvtap99' )
1442 self
. assertRegex ( output
, 'ipvtap *mode ' + mode
. lower () + ' ' + flag
)
1444 def test_veth ( self
):
1445 copy_network_unit ( '25-veth.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1446 '25-veth-mtu.netdev' )
1449 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:degraded' , 'veth-mtu:degraded' , 'veth-mtu-peer:degraded' ])
1451 output
= check_output ( 'ip -d link show veth99' )
1453 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bc' )
1454 output
= check_output ( 'ip -d link show veth-peer' )
1456 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bd' )
1458 output
= check_output ( 'ip -d link show veth-mtu' )
1460 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:be' )
1461 self
. assertRegex ( output
, 'mtu 1800' )
1462 output
= check_output ( 'ip -d link show veth-mtu-peer' )
1464 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bf' )
1465 self
. assertRegex ( output
, 'mtu 1800' )
1467 def test_tuntap ( self
):
1468 copy_network_unit ( '25-tun.netdev' , '25-tap.netdev' , '26-netdev-link-local-addressing-yes.network' )
1471 self
. wait_online ([ 'testtun99:degraded' , 'testtap99:degraded' ])
1473 pid
= networkd_pid ()
1474 name
= psutil
. Process ( pid
). name ()[: 15 ]
1476 output
= check_output ( 'ip -d tuntap show' )
1478 self
. assertRegex ( output
, fr
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1479 self
. assertRegex ( output
, fr
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1481 output
= check_output ( 'ip -d link show testtun99' )
1483 # Old ip command does not support IFF_ flags
1484 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1485 self
. assertIn ( 'UP,LOWER_UP' , output
)
1487 output
= check_output ( 'ip -d link show testtap99' )
1489 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1490 self
. assertIn ( 'UP,LOWER_UP' , output
)
1492 remove_network_unit ( '26-netdev-link-local-addressing-yes.network' )
1495 self
. wait_online ([ 'testtun99:degraded' , 'testtap99:degraded' ], setup_state
= 'unmanaged' )
1497 pid
= networkd_pid ()
1498 name
= psutil
. Process ( pid
). name ()[: 15 ]
1500 output
= check_output ( 'ip -d tuntap show' )
1502 self
. assertRegex ( output
, fr
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1503 self
. assertRegex ( output
, fr
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1505 output
= check_output ( 'ip -d link show testtun99' )
1507 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1508 self
. assertIn ( 'UP,LOWER_UP' , output
)
1510 output
= check_output ( 'ip -d link show testtap99' )
1512 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1513 self
. assertIn ( 'UP,LOWER_UP' , output
)
1515 clear_network_units ()
1517 self
. wait_online ([ 'testtun99:off' , 'testtap99:off' ], setup_state
= 'unmanaged' )
1519 output
= check_output ( 'ip -d tuntap show' )
1521 self
. assertRegex ( output
, r
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$' )
1522 self
. assertRegex ( output
, r
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$' )
1527 output
= check_output ( 'ip -d link show testtun99' )
1529 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1530 if 'NO-CARRIER' in output
:
1538 output
= check_output ( 'ip -d link show testtap99' )
1540 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1541 if 'NO-CARRIER' in output
:
1546 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
1548 copy_network_unit ( '25-vrf.netdev' , '26-netdev-link-local-addressing-yes.network' )
1551 self
. wait_online ([ 'vrf99:carrier' ])
1553 @expectedFailureIfModuleIsNotAvailable ( 'vcan' )
1554 def test_vcan ( self
):
1555 copy_network_unit ( '25-vcan.netdev' , '26-netdev-link-local-addressing-yes.network' )
1558 self
. wait_online ([ 'vcan99:carrier' ])
1560 @expectedFailureIfModuleIsNotAvailable ( 'vxcan' )
1561 def test_vxcan ( self
):
1562 copy_network_unit ( '25-vxcan.netdev' , '26-netdev-link-local-addressing-yes.network' )
1565 self
. wait_online ([ 'vxcan99:carrier' , 'vxcan-peer:carrier' ])
1567 @expectedFailureIfModuleIsNotAvailable ( 'wireguard' )
1568 def test_wireguard ( self
):
1569 copy_network_unit ( '25-wireguard.netdev' , '25-wireguard.network' ,
1570 '25-wireguard-23-peers.netdev' , '25-wireguard-23-peers.network' ,
1571 '25-wireguard-preshared-key.txt' , '25-wireguard-private-key.txt' ,
1572 '25-wireguard-no-peer.netdev' , '25-wireguard-no-peer.network' )
1574 self
. wait_online ([ 'wg99:routable' , 'wg98:routable' , 'wg97:carrier' ])
1576 output
= check_output ( 'ip -4 address show dev wg99' )
1578 self
. assertIn ( 'inet 192.168.124.1/24 scope global wg99' , output
)
1580 output
= check_output ( 'ip -4 address show dev wg99' )
1582 self
. assertIn ( 'inet 169.254.11.1/24 scope link wg99' , output
)
1584 output
= check_output ( 'ip -6 address show dev wg99' )
1586 self
. assertIn ( 'inet6 fe80::1/64 scope link' , output
)
1588 output
= check_output ( 'ip -4 address show dev wg98' )
1590 self
. assertIn ( 'inet 192.168.123.123/24 scope global wg98' , output
)
1592 output
= check_output ( 'ip -6 address show dev wg98' )
1594 self
. assertIn ( 'inet6 fd8d:4d6d:3ccb:500::1/64 scope global' , output
)
1596 output
= check_output ( 'ip -4 route show dev wg99 table 1234' )
1598 self
. assertIn ( '192.168.26.0/24 proto static metric 123' , output
)
1600 output
= check_output ( 'ip -6 route show dev wg99 table 1234' )
1602 self
. assertIn ( 'fd31:bf08:57cb::/48 proto static metric 123 pref medium' , output
)
1604 output
= check_output ( 'ip -6 route show dev wg98 table 1234' )
1606 self
. assertIn ( 'fd8d:4d6d:3ccb:500:c79:2339:edce:ece1 proto static metric 123 pref medium' , output
)
1607 self
. assertIn ( 'fd8d:4d6d:3ccb:500:1dbf:ca8a:32d3:dd81 proto static metric 123 pref medium' , output
)
1608 self
. assertIn ( 'fd8d:4d6d:3ccb:500:1e54:1415:35d0:a47c proto static metric 123 pref medium' , output
)
1609 self
. assertIn ( 'fd8d:4d6d:3ccb:500:270d:b5dd:4a3f:8909 proto static metric 123 pref medium' , output
)
1610 self
. assertIn ( 'fd8d:4d6d:3ccb:500:5660:679d:3532:94d8 proto static metric 123 pref medium' , output
)
1611 self
. assertIn ( 'fd8d:4d6d:3ccb:500:6825:573f:30f3:9472 proto static metric 123 pref medium' , output
)
1612 self
. assertIn ( 'fd8d:4d6d:3ccb:500:6f2e:6888:c6fd:dfb9 proto static metric 123 pref medium' , output
)
1613 self
. assertIn ( 'fd8d:4d6d:3ccb:500:8d4d:bab:7280:a09a proto static metric 123 pref medium' , output
)
1614 self
. assertIn ( 'fd8d:4d6d:3ccb:500:900c:d437:ec27:8822 proto static metric 123 pref medium' , output
)
1615 self
. assertIn ( 'fd8d:4d6d:3ccb:500:9742:9931:5217:18d5 proto static metric 123 pref medium' , output
)
1616 self
. assertIn ( 'fd8d:4d6d:3ccb:500:9c11:d820:2e96:9be0 proto static metric 123 pref medium' , output
)
1617 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a072:80da:de4f:add1 proto static metric 123 pref medium' , output
)
1618 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a3f3:df38:19b0:721 proto static metric 123 pref medium' , output
)
1619 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a94b:cd6a:a32d:90e6 proto static metric 123 pref medium' , output
)
1620 self
. assertIn ( 'fd8d:4d6d:3ccb:500:b39c:9cdc:755a:ead3 proto static metric 123 pref medium' , output
)
1621 self
. assertIn ( 'fd8d:4d6d:3ccb:500:b684:4f81:2e3e:132e proto static metric 123 pref medium' , output
)
1622 self
. assertIn ( 'fd8d:4d6d:3ccb:500:bad5:495d:8e9c:3427 proto static metric 123 pref medium' , output
)
1623 self
. assertIn ( 'fd8d:4d6d:3ccb:500:bfe5:c3c3:5d77:fcb proto static metric 123 pref medium' , output
)
1624 self
. assertIn ( 'fd8d:4d6d:3ccb:500:c624:6bf7:4c09:3b59 proto static metric 123 pref medium' , output
)
1625 self
. assertIn ( 'fd8d:4d6d:3ccb:500:d4f9:5dc:9296:a1a proto static metric 123 pref medium' , output
)
1626 self
. assertIn ( 'fd8d:4d6d:3ccb:500:dcdd:d33b:90c9:6088 proto static metric 123 pref medium' , output
)
1627 self
. assertIn ( 'fd8d:4d6d:3ccb:500:e2e1:ae15:103f:f376 proto static metric 123 pref medium' , output
)
1628 self
. assertIn ( 'fd8d:4d6d:3ccb:500:f349:c4f0:10c1:6b4 proto static metric 123 pref medium' , output
)
1629 self
. assertIn ( 'fd8d:4d6d:3ccb:c79:2339:edce::/96 proto static metric 123 pref medium' , output
)
1630 self
. assertIn ( 'fd8d:4d6d:3ccb:1dbf:ca8a:32d3::/96 proto static metric 123 pref medium' , output
)
1631 self
. assertIn ( 'fd8d:4d6d:3ccb:1e54:1415:35d0::/96 proto static metric 123 pref medium' , output
)
1632 self
. assertIn ( 'fd8d:4d6d:3ccb:270d:b5dd:4a3f::/96 proto static metric 123 pref medium' , output
)
1633 self
. assertIn ( 'fd8d:4d6d:3ccb:5660:679d:3532::/96 proto static metric 123 pref medium' , output
)
1634 self
. assertIn ( 'fd8d:4d6d:3ccb:6825:573f:30f3::/96 proto static metric 123 pref medium' , output
)
1635 self
. assertIn ( 'fd8d:4d6d:3ccb:6f2e:6888:c6fd::/96 proto static metric 123 pref medium' , output
)
1636 self
. assertIn ( 'fd8d:4d6d:3ccb:8d4d:bab:7280::/96 proto static metric 123 pref medium' , output
)
1637 self
. assertIn ( 'fd8d:4d6d:3ccb:900c:d437:ec27::/96 proto static metric 123 pref medium' , output
)
1638 self
. assertIn ( 'fd8d:4d6d:3ccb:9742:9931:5217::/96 proto static metric 123 pref medium' , output
)
1639 self
. assertIn ( 'fd8d:4d6d:3ccb:9c11:d820:2e96::/96 proto static metric 123 pref medium' , output
)
1640 self
. assertIn ( 'fd8d:4d6d:3ccb:a072:80da:de4f::/96 proto static metric 123 pref medium' , output
)
1641 self
. assertIn ( 'fd8d:4d6d:3ccb:a3f3:df38:19b0::/96 proto static metric 123 pref medium' , output
)
1642 self
. assertIn ( 'fd8d:4d6d:3ccb:a94b:cd6a:a32d::/96 proto static metric 123 pref medium' , output
)
1643 self
. assertIn ( 'fd8d:4d6d:3ccb:b39c:9cdc:755a::/96 proto static metric 123 pref medium' , output
)
1644 self
. assertIn ( 'fd8d:4d6d:3ccb:b684:4f81:2e3e::/96 proto static metric 123 pref medium' , output
)
1645 self
. assertIn ( 'fd8d:4d6d:3ccb:bad5:495d:8e9c::/96 proto static metric 123 pref medium' , output
)
1646 self
. assertIn ( 'fd8d:4d6d:3ccb:bfe5:c3c3:5d77::/96 proto static metric 123 pref medium' , output
)
1647 self
. assertIn ( 'fd8d:4d6d:3ccb:c624:6bf7:4c09::/96 proto static metric 123 pref medium' , output
)
1648 self
. assertIn ( 'fd8d:4d6d:3ccb:d4f9:5dc:9296::/96 proto static metric 123 pref medium' , output
)
1649 self
. assertIn ( 'fd8d:4d6d:3ccb:dcdd:d33b:90c9::/96 proto static metric 123 pref medium' , output
)
1650 self
. assertIn ( 'fd8d:4d6d:3ccb:e2e1:ae15:103f::/96 proto static metric 123 pref medium' , output
)
1651 self
. assertIn ( 'fd8d:4d6d:3ccb:f349:c4f0:10c1::/96 proto static metric 123 pref medium' , output
)
1653 if shutil
. which ( 'wg' ):
1656 output
= check_output ( 'wg show wg99 listen-port' )
1657 self
. assertEqual ( output
, '51820' )
1658 output
= check_output ( 'wg show wg99 fwmark' )
1659 self
. assertEqual ( output
, '0x4d2' )
1660 output
= check_output ( 'wg show wg99 private-key' )
1661 self
. assertEqual ( output
, 'EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=' )
1662 output
= check_output ( 'wg show wg99 allowed-ips' )
1663 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t 192.168.124.3/32' , output
)
1664 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t 192.168.124.2/32' , output
)
1665 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t fdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128' , output
)
1666 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 192.168.26.0/24 fd31:bf08:57cb::/48' , output
)
1667 output
= check_output ( 'wg show wg99 persistent-keepalive' )
1668 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t off' , output
)
1669 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t off' , output
)
1670 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t off' , output
)
1671 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 20' , output
)
1672 output
= check_output ( 'wg show wg99 endpoints' )
1673 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t (none)' , output
)
1674 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t (none)' , output
)
1675 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t (none)' , output
)
1676 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 192.168.27.3:51820' , output
)
1677 output
= check_output ( 'wg show wg99 preshared-keys' )
1678 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t 6Fsg8XN0DE6aPQgAX4r2oazEYJOGqyHUz3QRH/jCB+I=' , output
)
1679 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t it7nd33chCT/tKT2ZZWfYyp43Zs+6oif72hexnSNMqA=' , output
)
1680 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=' , output
)
1681 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=' , output
)
1683 output
= check_output ( 'wg show wg98 private-key' )
1684 self
. assertEqual ( output
, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr+WHtZLZ90FU=' )
1686 output
= check_output ( 'wg show wg97 listen-port' )
1687 self
. assertEqual ( output
, '51821' )
1688 output
= check_output ( 'wg show wg97 fwmark' )
1689 self
. assertEqual ( output
, '0x4d3' )
1691 def test_geneve ( self
):
1692 copy_network_unit ( '25-geneve.netdev' , '26-netdev-link-local-addressing-yes.network' )
1695 self
. wait_online ([ 'geneve99:degraded' ])
1697 output
= check_output ( 'ip -d link show geneve99' )
1699 self
. assertRegex ( output
, '192.168.22.1' )
1700 self
. assertRegex ( output
, '6082' )
1701 self
. assertRegex ( output
, 'udpcsum' )
1702 self
. assertRegex ( output
, 'udp6zerocsumrx' )
1704 def test_ipip_tunnel ( self
):
1705 copy_network_unit ( '12-dummy.netdev' , '25-ipip.network' ,
1706 '25-ipip-tunnel.netdev' , '25-tunnel.network' ,
1707 '25-ipip-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1708 '25-ipip-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1709 '25-ipip-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1711 self
. wait_online ([ 'ipiptun99:routable' , 'ipiptun98:routable' , 'ipiptun97:routable' , 'ipiptun96:routable' , 'dummy98:degraded' ])
1713 output
= check_output ( 'ip -d link show ipiptun99' )
1715 self
. assertRegex ( output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98' )
1716 output
= check_output ( 'ip -d link show ipiptun98' )
1718 self
. assertRegex ( output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98' )
1719 output
= check_output ( 'ip -d link show ipiptun97' )
1721 self
. assertRegex ( output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98' )
1722 output
= check_output ( 'ip -d link show ipiptun96' )
1724 self
. assertRegex ( output
, 'ipip (ipip )?remote any local any dev dummy98' )
1726 def test_gre_tunnel ( self
):
1727 copy_network_unit ( '12-dummy.netdev' , '25-gretun.network' ,
1728 '25-gre-tunnel.netdev' , '25-tunnel.network' ,
1729 '25-gre-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1730 '25-gre-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1731 '25-gre-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1733 self
. wait_online ([ 'gretun99:routable' , 'gretun98:routable' , 'gretun97:routable' , 'gretun96:routable' , 'dummy98:degraded' ])
1735 output
= check_output ( 'ip -d link show gretun99' )
1737 self
. assertRegex ( output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1738 self
. assertRegex ( output
, 'ikey 1.2.3.103' )
1739 self
. assertRegex ( output
, 'okey 1.2.4.103' )
1740 self
. assertRegex ( output
, 'iseq' )
1741 self
. assertRegex ( output
, 'oseq' )
1742 output
= check_output ( 'ip -d link show gretun98' )
1744 self
. assertRegex ( output
, 'gre remote 10.65.223.239 local any dev dummy98' )
1745 self
. assertRegex ( output
, 'ikey 0.0.0.104' )
1746 self
. assertRegex ( output
, 'okey 0.0.0.104' )
1747 self
. assertNotRegex ( output
, 'iseq' )
1748 self
. assertNotRegex ( output
, 'oseq' )
1749 output
= check_output ( 'ip -d link show gretun97' )
1751 self
. assertRegex ( output
, 'gre remote any local 10.65.223.238 dev dummy98' )
1752 self
. assertRegex ( output
, 'ikey 0.0.0.105' )
1753 self
. assertRegex ( output
, 'okey 0.0.0.105' )
1754 self
. assertNotRegex ( output
, 'iseq' )
1755 self
. assertNotRegex ( output
, 'oseq' )
1756 output
= check_output ( 'ip -d link show gretun96' )
1758 self
. assertRegex ( output
, 'gre remote any local any dev dummy98' )
1759 self
. assertRegex ( output
, 'ikey 0.0.0.106' )
1760 self
. assertRegex ( output
, 'okey 0.0.0.106' )
1761 self
. assertNotRegex ( output
, 'iseq' )
1762 self
. assertNotRegex ( output
, 'oseq' )
1764 def test_ip6gre_tunnel ( self
):
1765 copy_network_unit ( '12-dummy.netdev' , '25-ip6gretun.network' ,
1766 '25-ip6gre-tunnel.netdev' , '25-tunnel.network' ,
1767 '25-ip6gre-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1768 '25-ip6gre-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1769 '25-ip6gre-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1772 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1774 self
. wait_links ( 'dummy98' , 'ip6gretun99' , 'ip6gretun98' , 'ip6gretun97' , 'ip6gretun96' )
1776 output
= check_output ( 'ip -d link show ip6gretun99' )
1778 self
. assertRegex ( output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1779 output
= check_output ( 'ip -d link show ip6gretun98' )
1781 self
. assertRegex ( output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98' )
1782 output
= check_output ( 'ip -d link show ip6gretun97' )
1784 self
. assertRegex ( output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98' )
1785 output
= check_output ( 'ip -d link show ip6gretun96' )
1787 self
. assertRegex ( output
, 'ip6gre remote any local any dev dummy98' )
1789 def test_gretap_tunnel ( self
):
1790 copy_network_unit ( '12-dummy.netdev' , '25-gretap.network' ,
1791 '25-gretap-tunnel.netdev' , '25-tunnel.network' ,
1792 '25-gretap-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1794 self
. wait_online ([ 'gretap99:routable' , 'gretap98:routable' , 'dummy98:degraded' ])
1796 output
= check_output ( 'ip -d link show gretap99' )
1798 self
. assertRegex ( output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1799 self
. assertRegex ( output
, 'ikey 0.0.0.106' )
1800 self
. assertRegex ( output
, 'okey 0.0.0.106' )
1801 self
. assertRegex ( output
, 'iseq' )
1802 self
. assertRegex ( output
, 'oseq' )
1803 output
= check_output ( 'ip -d link show gretap98' )
1805 self
. assertRegex ( output
, 'gretap remote 10.65.223.239 local any dev dummy98' )
1806 self
. assertRegex ( output
, 'ikey 0.0.0.107' )
1807 self
. assertRegex ( output
, 'okey 0.0.0.107' )
1808 self
. assertRegex ( output
, 'iseq' )
1809 self
. assertRegex ( output
, 'oseq' )
1811 def test_ip6gretap_tunnel ( self
):
1812 copy_network_unit ( '12-dummy.netdev' , '25-ip6gretap.network' ,
1813 '25-ip6gretap-tunnel.netdev' , '25-tunnel.network' ,
1814 '25-ip6gretap-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1816 self
. wait_online ([ 'ip6gretap99:routable' , 'ip6gretap98:routable' , 'dummy98:degraded' ])
1818 output
= check_output ( 'ip -d link show ip6gretap99' )
1820 self
. assertRegex ( output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1821 output
= check_output ( 'ip -d link show ip6gretap98' )
1823 self
. assertRegex ( output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98' )
1825 def test_vti_tunnel ( self
):
1826 copy_network_unit ( '12-dummy.netdev' , '25-vti.network' ,
1827 '25-vti-tunnel.netdev' , '25-tunnel.network' ,
1828 '25-vti-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1829 '25-vti-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1830 '25-vti-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1832 self
. wait_online ([ 'vtitun99:routable' , 'vtitun98:routable' , 'vtitun97:routable' , 'vtitun96:routable' , 'dummy98:degraded' ])
1834 output
= check_output ( 'ip -d link show vtitun99' )
1836 self
. assertRegex ( output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1837 output
= check_output ( 'ip -d link show vtitun98' )
1839 self
. assertRegex ( output
, 'vti remote 10.65.223.239 local any dev dummy98' )
1840 output
= check_output ( 'ip -d link show vtitun97' )
1842 self
. assertRegex ( output
, 'vti remote any local 10.65.223.238 dev dummy98' )
1843 output
= check_output ( 'ip -d link show vtitun96' )
1845 self
. assertRegex ( output
, 'vti remote any local any dev dummy98' )
1847 def test_vti6_tunnel ( self
):
1848 copy_network_unit ( '12-dummy.netdev' , '25-vti6.network' ,
1849 '25-vti6-tunnel.netdev' , '25-tunnel.network' ,
1850 '25-vti6-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1851 '25-vti6-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' )
1853 self
. wait_online ([ 'vti6tun99:routable' , 'vti6tun98:routable' , 'vti6tun97:routable' , 'dummy98:degraded' ])
1855 output
= check_output ( 'ip -d link show vti6tun99' )
1857 self
. assertRegex ( output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1858 output
= check_output ( 'ip -d link show vti6tun98' )
1860 self
. assertRegex ( output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98' )
1861 output
= check_output ( 'ip -d link show vti6tun97' )
1863 self
. assertRegex ( output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98' )
1865 def test_ip6tnl_tunnel ( self
):
1866 copy_network_unit ( '12-dummy.netdev' , '25-ip6tnl.network' ,
1867 '25-ip6tnl-tunnel.netdev' , '25-tunnel.network' ,
1868 '25-ip6tnl-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1869 '25-ip6tnl-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1870 '25-veth.netdev' , '25-ip6tnl-slaac.network' , '25-ipv6-prefix.network' ,
1871 '25-ip6tnl-tunnel-local-slaac.netdev' , '25-ip6tnl-tunnel-local-slaac.network' ,
1872 '25-ip6tnl-tunnel-external.netdev' , '26-netdev-link-local-addressing-yes.network' )
1874 self
. wait_online ([ 'ip6tnl99:routable' , 'ip6tnl98:routable' , 'ip6tnl97:routable' ,
1875 'ip6tnl-slaac:degraded' , 'ip6tnl-external:degraded' ,
1876 'dummy98:degraded' , 'veth99:routable' , 'veth-peer:degraded' ])
1878 output
= check_output ( 'ip -d link show ip6tnl99' )
1880 self
. assertIn ( 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' , output
)
1881 output
= check_output ( 'ip -d link show ip6tnl98' )
1883 self
. assertRegex ( output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98' )
1884 output
= check_output ( 'ip -d link show ip6tnl97' )
1886 self
. assertRegex ( output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98' )
1887 output
= check_output ( 'ip -d link show ip6tnl-external' )
1889 self
. assertIn ( 'ip6tnl-external@NONE:' , output
)
1890 self
. assertIn ( 'ip6tnl external ' , output
)
1891 output
= check_output ( 'ip -d link show ip6tnl-slaac' )
1893 self
. assertIn ( 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99' , output
)
1895 output
= check_output ( 'ip -6 address show veth99' )
1897 self
. assertIn ( 'inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic' , output
)
1899 output
= check_output ( 'ip -4 route show default' )
1901 self
. assertIn ( 'default dev ip6tnl-slaac proto static' , output
)
1903 def test_sit_tunnel ( self
):
1904 copy_network_unit ( '12-dummy.netdev' , '25-sit.network' ,
1905 '25-sit-tunnel.netdev' , '25-tunnel.network' ,
1906 '25-sit-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1907 '25-sit-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1908 '25-sit-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1910 self
. wait_online ([ 'sittun99:routable' , 'sittun98:routable' , 'sittun97:routable' , 'sittun96:routable' , 'dummy98:degraded' ])
1912 output
= check_output ( 'ip -d link show sittun99' )
1914 self
. assertRegex ( output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98" )
1915 output
= check_output ( 'ip -d link show sittun98' )
1917 self
. assertRegex ( output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98" )
1918 output
= check_output ( 'ip -d link show sittun97' )
1920 self
. assertRegex ( output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98" )
1921 output
= check_output ( 'ip -d link show sittun96' )
1923 self
. assertRegex ( output
, "sit (ip6ip )?remote any local any dev dummy98" )
1925 def test_isatap_tunnel ( self
):
1926 copy_network_unit ( '12-dummy.netdev' , '25-isatap.network' ,
1927 '25-isatap-tunnel.netdev' , '25-tunnel.network' )
1929 self
. wait_online ([ 'isataptun99:routable' , 'dummy98:degraded' ])
1931 output
= check_output ( 'ip -d link show isataptun99' )
1933 self
. assertRegex ( output
, "isatap " )
1935 def test_6rd_tunnel ( self
):
1936 copy_network_unit ( '12-dummy.netdev' , '25-6rd.network' ,
1937 '25-6rd-tunnel.netdev' , '25-tunnel.network' )
1939 self
. wait_online ([ 'sittun99:routable' , 'dummy98:degraded' ])
1941 output
= check_output ( 'ip -d link show sittun99' )
1943 self
. assertRegex ( output
, '6rd-prefix 2602::/24' )
1945 @expectedFailureIfERSPANv0IsNotSupported ()
1946 def test_erspan_tunnel_v0 ( self
):
1947 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
1948 '25-erspan0-tunnel.netdev' , '25-tunnel.network' ,
1949 '25-erspan0-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1951 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
1953 output
= check_output ( 'ip -d link show erspan99' )
1955 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
1956 self
. assertIn ( 'erspan_ver 0' , output
)
1957 self
. assertNotIn ( 'erspan_index 123' , output
)
1958 self
. assertNotIn ( 'erspan_dir ingress' , output
)
1959 self
. assertNotIn ( 'erspan_hwid 1f' , output
)
1960 self
. assertIn ( 'ikey 0.0.0.101' , output
)
1961 self
. assertIn ( 'iseq' , output
)
1962 output
= check_output ( 'ip -d link show erspan98' )
1964 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
1965 self
. assertIn ( 'erspan_ver 0' , output
)
1966 self
. assertNotIn ( 'erspan_index 124' , output
)
1967 self
. assertNotIn ( 'erspan_dir egress' , output
)
1968 self
. assertNotIn ( 'erspan_hwid 2f' , output
)
1969 self
. assertIn ( 'ikey 0.0.0.102' , output
)
1970 self
. assertIn ( 'iseq' , output
)
1972 def test_erspan_tunnel_v1 ( self
):
1973 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
1974 '25-erspan1-tunnel.netdev' , '25-tunnel.network' ,
1975 '25-erspan1-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1977 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
1979 output
= check_output ( 'ip -d link show erspan99' )
1981 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
1982 self
. assertIn ( 'erspan_ver 1' , output
)
1983 self
. assertIn ( 'erspan_index 123' , output
)
1984 self
. assertNotIn ( 'erspan_dir ingress' , output
)
1985 self
. assertNotIn ( 'erspan_hwid 1f' , output
)
1986 self
. assertIn ( 'ikey 0.0.0.101' , output
)
1987 self
. assertIn ( 'okey 0.0.0.101' , output
)
1988 self
. assertIn ( 'iseq' , output
)
1989 self
. assertIn ( 'oseq' , output
)
1990 output
= check_output ( 'ip -d link show erspan98' )
1992 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
1993 self
. assertIn ( 'erspan_ver 1' , output
)
1994 self
. assertIn ( 'erspan_index 124' , output
)
1995 self
. assertNotIn ( 'erspan_dir egress' , output
)
1996 self
. assertNotIn ( 'erspan_hwid 2f' , output
)
1997 self
. assertIn ( 'ikey 0.0.0.102' , output
)
1998 self
. assertIn ( 'okey 0.0.0.102' , output
)
1999 self
. assertIn ( 'iseq' , output
)
2000 self
. assertIn ( 'oseq' , output
)
2002 @expectedFailureIfERSPANv2IsNotSupported ()
2003 def test_erspan_tunnel_v2 ( self
):
2004 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
2005 '25-erspan2-tunnel.netdev' , '25-tunnel.network' ,
2006 '25-erspan2-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
2008 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
2010 output
= check_output ( 'ip -d link show erspan99' )
2012 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
2013 self
. assertIn ( 'erspan_ver 2' , output
)
2014 self
. assertNotIn ( 'erspan_index 123' , output
)
2015 self
. assertIn ( 'erspan_dir ingress' , output
)
2016 self
. assertIn ( 'erspan_hwid 0x1f' , output
)
2017 self
. assertIn ( 'ikey 0.0.0.101' , output
)
2018 self
. assertIn ( 'okey 0.0.0.101' , output
)
2019 self
. assertIn ( 'iseq' , output
)
2020 self
. assertIn ( 'oseq' , output
)
2021 output
= check_output ( 'ip -d link show erspan98' )
2023 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
2024 self
. assertIn ( 'erspan_ver 2' , output
)
2025 self
. assertNotIn ( 'erspan_index 124' , output
)
2026 self
. assertIn ( 'erspan_dir egress' , output
)
2027 self
. assertIn ( 'erspan_hwid 0x2f' , output
)
2028 self
. assertIn ( 'ikey 0.0.0.102' , output
)
2029 self
. assertIn ( 'okey 0.0.0.102' , output
)
2030 self
. assertIn ( 'iseq' , output
)
2031 self
. assertIn ( 'oseq' , output
)
2033 def test_tunnel_independent ( self
):
2034 copy_network_unit ( '25-ipip-tunnel-independent.netdev' , '26-netdev-link-local-addressing-yes.network' )
2037 self
. wait_online ([ 'ipiptun99:carrier' ])
2039 def test_tunnel_independent_loopback ( self
):
2040 copy_network_unit ( '25-ipip-tunnel-independent-loopback.netdev' , '26-netdev-link-local-addressing-yes.network' )
2043 self
. wait_online ([ 'ipiptun99:carrier' ])
2045 @expectedFailureIfModuleIsNotAvailable ( 'xfrm_interface' )
2046 def test_xfrm ( self
):
2047 copy_network_unit ( '12-dummy.netdev' , '25-xfrm.network' ,
2048 '25-xfrm.netdev' , '25-xfrm-independent.netdev' ,
2049 '26-netdev-link-local-addressing-yes.network' )
2052 self
. wait_online ([ 'dummy98:degraded' , 'xfrm98:degraded' , 'xfrm99:degraded' ])
2054 output
= check_output ( 'ip -d link show dev xfrm98' )
2056 self
. assertIn ( 'xfrm98@dummy98:' , output
)
2057 self
. assertIn ( 'xfrm if_id 0x98 ' , output
)
2059 output
= check_output ( 'ip -d link show dev xfrm99' )
2061 self
. assertIn ( 'xfrm99@lo:' , output
)
2062 self
. assertIn ( 'xfrm if_id 0x99 ' , output
)
2064 @expectedFailureIfModuleIsNotAvailable ( 'fou' )
2066 # The following redundant check is necessary for CentOS CI.
2067 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
2068 self
. assertTrue ( is_module_available ( 'fou' ))
2070 copy_network_unit ( '25-fou-ipproto-ipip.netdev' , '25-fou-ipproto-gre.netdev' ,
2071 '25-fou-ipip.netdev' , '25-fou-sit.netdev' ,
2072 '25-fou-gre.netdev' , '25-fou-gretap.netdev' )
2075 self
. wait_online ([ 'ipiptun96:off' , 'sittun96:off' , 'gretun96:off' , 'gretap96:off' ], setup_state
= 'unmanaged' )
2077 output
= check_output ( 'ip fou show' )
2079 self
. assertRegex ( output
, 'port 55555 ipproto 4' )
2080 self
. assertRegex ( output
, 'port 55556 ipproto 47' )
2082 output
= check_output ( 'ip -d link show ipiptun96' )
2084 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55555' )
2085 output
= check_output ( 'ip -d link show sittun96' )
2087 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55555' )
2088 output
= check_output ( 'ip -d link show gretun96' )
2090 self
. assertRegex ( output
, 'encap fou encap-sport 1001 encap-dport 55556' )
2091 output
= check_output ( 'ip -d link show gretap96' )
2093 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55556' )
2095 def test_vxlan ( self
):
2096 copy_network_unit ( '11-dummy.netdev' , '25-vxlan-test1.network' ,
2097 '25-vxlan.netdev' , '25-vxlan.network' ,
2098 '25-vxlan-ipv6.netdev' , '25-vxlan-ipv6.network' ,
2099 '25-vxlan-independent.netdev' , '26-netdev-link-local-addressing-yes.network' ,
2100 '25-veth.netdev' , '25-vxlan-veth99.network' , '25-ipv6-prefix.network' ,
2101 '25-vxlan-local-slaac.netdev' , '25-vxlan-local-slaac.network' )
2104 self
. wait_online ([ 'test1:degraded' , 'veth99:routable' , 'veth-peer:degraded' ,
2105 'vxlan99:degraded' , 'vxlan98:degraded' , 'vxlan97:degraded' , 'vxlan-slaac:degraded' ])
2107 output
= check_output ( 'ip -d link show vxlan99' )
2109 self
. assertIn ( '999' , output
)
2110 self
. assertIn ( '5555' , output
)
2111 self
. assertIn ( 'l2miss' , output
)
2112 self
. assertIn ( 'l3miss' , output
)
2113 self
. assertIn ( 'udpcsum' , output
)
2114 self
. assertIn ( 'udp6zerocsumtx' , output
)
2115 self
. assertIn ( 'udp6zerocsumrx' , output
)
2116 self
. assertIn ( 'remcsumtx' , output
)
2117 self
. assertIn ( 'remcsumrx' , output
)
2118 self
. assertIn ( 'gbp' , output
)
2120 output
= check_output ( 'bridge fdb show dev vxlan99' )
2122 self
. assertIn ( '00:11:22:33:44:55 dst 10.0.0.5 self permanent' , output
)
2123 self
. assertIn ( '00:11:22:33:44:66 dst 10.0.0.6 self permanent' , output
)
2124 self
. assertIn ( '00:11:22:33:44:77 dst 10.0.0.7 via test1 self permanent' , output
)
2126 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'vxlan99' , env
= env
)
2128 self
. assertIn ( 'VNI: 999' , output
)
2129 self
. assertIn ( 'Destination Port: 5555' , output
)
2130 self
. assertIn ( 'Underlying Device: test1' , output
)
2132 output
= check_output ( 'bridge fdb show dev vxlan97' )
2134 self
. assertIn ( '00:00:00:00:00:00 dst fe80::23b:d2ff:fe95:967f via test1 self permanent' , output
)
2135 self
. assertIn ( '00:00:00:00:00:00 dst fe80::27c:16ff:fec0:6c74 via test1 self permanent' , output
)
2136 self
. assertIn ( '00:00:00:00:00:00 dst fe80::2a2:e4ff:fef9:2269 via test1 self permanent' , output
)
2138 output
= check_output ( 'ip -d link show vxlan-slaac' )
2140 self
. assertIn ( 'vxlan id 4831584 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99' , output
)
2142 output
= check_output ( 'ip -6 address show veth99' )
2144 self
. assertIn ( 'inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic' , output
)
2146 @unittest . skipUnless ( compare_kernel_version ( "6" ), reason
= "Causes kernel panic on unpatched kernels: https://bugzilla.kernel.org/show_bug.cgi?id=208315" )
2147 def test_macsec ( self
):
2148 copy_network_unit ( '25-macsec.netdev' , '25-macsec.network' , '25-macsec.key' ,
2149 '26-macsec.network' , '12-dummy.netdev' )
2152 self
. wait_online ([ 'dummy98:degraded' , 'macsec99:routable' ])
2154 output
= check_output ( 'ip -d link show macsec99' )
2156 self
. assertRegex ( output
, 'macsec99@dummy98' )
2157 self
. assertRegex ( output
, 'macsec sci [0-9a-f]*000b' )
2158 self
. assertRegex ( output
, 'encrypt on' )
2160 output
= check_output ( 'ip macsec show macsec99' )
2162 self
. assertRegex ( output
, 'encrypt on' )
2163 self
. assertRegex ( output
, 'TXSC: [0-9a-f]*000b on SA 1' )
2164 self
. assertRegex ( output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000' )
2165 self
. assertRegex ( output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000' )
2166 self
. assertRegex ( output
, 'RXSC: c619528fe6a00100, state on' )
2167 self
. assertRegex ( output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000' )
2168 self
. assertRegex ( output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000' )
2169 self
. assertRegex ( output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000' )
2170 self
. assertRegex ( output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000' )
2171 self
. assertNotRegex ( output
, 'key 02030405067080900000000000000000' )
2172 self
. assertRegex ( output
, 'RXSC: 8c16456c83a90002, state on' )
2173 self
. assertRegex ( output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000' )
2175 def test_nlmon ( self
):
2176 copy_network_unit ( '25-nlmon.netdev' , '26-netdev-link-local-addressing-yes.network' )
2179 self
. wait_online ([ 'nlmon99:carrier' ])
2181 @expectedFailureIfModuleIsNotAvailable ( 'ifb' )
2183 copy_network_unit ( '25-ifb.netdev' , '26-netdev-link-local-addressing-yes.network' )
2186 self
. wait_online ([ 'ifb99:degraded' ])
2188 class NetworkdL2TPTests ( unittest
. TestCase
, Utilities
):
2196 @expectedFailureIfModuleIsNotAvailable ( 'l2tp_eth' , 'l2tp_netlink' )
2197 def test_l2tp_udp ( self
):
2198 copy_network_unit ( '11-dummy.netdev' , '25-l2tp-dummy.network' ,
2199 '25-l2tp-udp.netdev' , '25-l2tp.network' )
2202 self
. wait_online ([ 'test1:routable' , 'l2tp-ses1:degraded' , 'l2tp-ses2:degraded' ])
2204 output
= check_output ( 'ip l2tp show tunnel tunnel_id 10' )
2206 self
. assertRegex ( output
, "Tunnel 10, encap UDP" )
2207 self
. assertRegex ( output
, "From 192.168.30.100 to 192.168.30.101" )
2208 self
. assertRegex ( output
, "Peer tunnel 11" )
2209 self
. assertRegex ( output
, "UDP source / dest ports: 3000/4000" )
2210 self
. assertRegex ( output
, "UDP checksum: enabled" )
2212 output
= check_output ( 'ip l2tp show session tid 10 session_id 15' )
2214 self
. assertRegex ( output
, "Session 15 in tunnel 10" )
2215 self
. assertRegex ( output
, "Peer session 16, tunnel 11" )
2216 self
. assertRegex ( output
, "interface name: l2tp-ses1" )
2218 output
= check_output ( 'ip l2tp show session tid 10 session_id 17' )
2220 self
. assertRegex ( output
, "Session 17 in tunnel 10" )
2221 self
. assertRegex ( output
, "Peer session 18, tunnel 11" )
2222 self
. assertRegex ( output
, "interface name: l2tp-ses2" )
2224 @expectedFailureIfModuleIsNotAvailable ( 'l2tp_eth' , 'l2tp_ip' , 'l2tp_netlink' )
2225 def test_l2tp_ip ( self
):
2226 copy_network_unit ( '11-dummy.netdev' , '25-l2tp-dummy.network' ,
2227 '25-l2tp-ip.netdev' , '25-l2tp.network' )
2230 self
. wait_online ([ 'test1:routable' , 'l2tp-ses3:degraded' , 'l2tp-ses4:degraded' ])
2232 output
= check_output ( 'ip l2tp show tunnel tunnel_id 10' )
2234 self
. assertRegex ( output
, "Tunnel 10, encap IP" )
2235 self
. assertRegex ( output
, "From 192.168.30.100 to 192.168.30.101" )
2236 self
. assertRegex ( output
, "Peer tunnel 12" )
2238 output
= check_output ( 'ip l2tp show session tid 10 session_id 25' )
2240 self
. assertRegex ( output
, "Session 25 in tunnel 10" )
2241 self
. assertRegex ( output
, "Peer session 26, tunnel 12" )
2242 self
. assertRegex ( output
, "interface name: l2tp-ses3" )
2244 output
= check_output ( 'ip l2tp show session tid 10 session_id 27' )
2246 self
. assertRegex ( output
, "Session 27 in tunnel 10" )
2247 self
. assertRegex ( output
, "Peer session 28, tunnel 12" )
2248 self
. assertRegex ( output
, "interface name: l2tp-ses4" )
2250 class NetworkdNetworkTests ( unittest
. TestCase
, Utilities
):
2258 def test_address_static ( self
):
2259 # test for #22515. The address will be removed and replaced with /64 prefix.
2260 check_output ( 'ip link add dummy98 type dummy' )
2261 check_output ( 'ip link set dev dummy98 up' )
2262 check_output ( 'ip -6 address add 2001:db8:0:f101::15/128 dev dummy98' )
2263 self
. wait_address ( 'dummy98' , '2001:db8:0:f101::15/128' , ipv
= '-6' )
2264 check_output ( 'ip -4 address add 10.3.2.3/16 brd 10.3.255.250 scope global label dummy98:hoge dev dummy98' )
2265 self
. wait_address ( 'dummy98' , '10.3.2.3/16 brd 10.3.255.250' , ipv
= '-4' )
2267 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' )
2270 self
. wait_online ([ 'dummy98:routable' ])
2272 output
= check_output ( 'ip -4 address show dev dummy98' )
2274 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
2275 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
2276 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
2277 self
. assertIn ( 'inet 10.7.8.9/16 brd 10.7.255.255 scope link deprecated dummy98' , output
)
2278 self
. assertIn ( 'inet 10.8.8.1/16 scope global dummy98' , output
)
2279 self
. assertIn ( 'inet 10.8.8.2/16 brd 10.8.8.128 scope global secondary dummy98' , output
)
2280 self
. assertRegex ( output
, 'inet 10.9.0.1/16 (metric 128 |)brd 10.9.255.255 scope global dummy98' )
2282 # test for ENOBUFS issue #17012
2283 for i
in range ( 1 , 254 ):
2284 self
. assertIn ( f
'inet 10.3.3. {i} /16 brd 10.3.255.255' , output
)
2287 self
. assertNotIn ( '10.10.0.1/16' , output
)
2288 self
. assertNotIn ( '10.10.0.2/16' , output
)
2290 output
= check_output ( 'ip -4 address show dev dummy98 label 32' )
2291 self
. assertIn ( 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32' , output
)
2293 output
= check_output ( 'ip -4 address show dev dummy98 label 33' )
2294 self
. assertIn ( 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33' , output
)
2296 output
= check_output ( 'ip -4 address show dev dummy98 label 34' )
2297 self
. assertRegex ( output
, r
'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34' )
2299 output
= check_output ( 'ip -4 address show dev dummy98 label 35' )
2300 self
. assertRegex ( output
, r
'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35' )
2302 output
= check_output ( 'ip -4 route show dev dummy98' )
2304 self
. assertIn ( '10.9.0.0/16 proto kernel scope link src 10.9.0.1 metric 128' , output
)
2306 output
= check_output ( 'ip -6 address show dev dummy98' )
2308 self
. assertIn ( 'inet6 2001:db8:0:f101::15/64 scope global' , output
)
2309 self
. assertIn ( 'inet6 2001:db8:0:f101::16/64 scope global' , output
)
2310 self
. assertIn ( 'inet6 2001:db8:0:f102::15/64 scope global' , output
)
2311 self
. assertIn ( 'inet6 2001:db8:0:f102::16/64 scope global' , output
)
2312 self
. assertIn ( 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global' , output
)
2313 self
. assertIn ( 'inet6 2001:db8:1:f101::1/64 scope global deprecated' , output
)
2314 self
. assertRegex ( output
, r
'inet6 fd[0-9a-f:]*1/64 scope global' )
2316 self
. check_netlabel ( 'dummy98' , r
'10\.4\.3\.0/24' )
2319 # 1. set preferred lifetime forever to drop the deprecated flag for testing #20891.
2320 check_output ( 'ip address change 10.7.8.9/16 dev dummy98 preferred_lft forever' )
2321 check_output ( 'ip address change 2001:db8:1:f101::1/64 dev dummy98 preferred_lft forever' )
2322 output
= check_output ( 'ip -4 address show dev dummy98' )
2324 self
. assertNotIn ( 'deprecated' , output
)
2325 output
= check_output ( 'ip -6 address show dev dummy98' )
2327 self
. assertNotIn ( 'deprecated' , output
)
2329 # 2. reconfigure the interface.
2330 networkctl_reconfigure ( 'dummy98' )
2331 self
. wait_online ([ 'dummy98:routable' ])
2333 # 3. check the deprecated flag is set for the address configured with PreferredLifetime=0
2334 output
= check_output ( 'ip -4 address show dev dummy98' )
2336 self
. assertIn ( 'inet 10.7.8.9/16 brd 10.7.255.255 scope link deprecated dummy98' , output
)
2337 output
= check_output ( 'ip -6 address show dev dummy98' )
2339 self
. assertIn ( 'inet6 2001:db8:1:f101::1/64 scope global deprecated' , output
)
2341 # test for ENOBUFS issue #17012
2342 output
= check_output ( 'ip -4 address show dev dummy98' )
2343 for i
in range ( 1 , 254 ):
2344 self
. assertIn ( f
'inet 10.3.3. {i} /16 brd 10.3.255.255' , output
)
2346 # TODO: check json string
2347 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2349 def test_address_ipv4acd ( self
):
2350 check_output ( 'ip netns add ns99' )
2351 check_output ( 'ip link add veth99 type veth peer veth-peer' )
2352 check_output ( 'ip link set veth-peer netns ns99' )
2353 check_output ( 'ip link set veth99 up' )
2354 check_output ( 'ip netns exec ns99 ip link set veth-peer up' )
2355 check_output ( 'ip netns exec ns99 ip address add 192.168.100.10/24 dev veth-peer' )
2357 copy_network_unit ( '25-address-ipv4acd-veth99.network' , copy_dropins
= False )
2359 self
. wait_online ([ 'veth99:routable' ])
2361 output
= check_output ( 'ip -4 address show dev veth99' )
2363 self
. assertNotIn ( '192.168.100.10/24' , output
)
2364 self
. assertIn ( '192.168.100.11/24' , output
)
2366 copy_network_unit ( '25-address-ipv4acd-veth99.network.d/conflict-address.conf' )
2368 self
. wait_operstate ( 'veth99' , operstate
= 'routable' , setup_state
= 'configuring' , setup_timeout
= 10 )
2370 output
= check_output ( 'ip -4 address show dev veth99' )
2372 self
. assertNotIn ( '192.168.100.10/24' , output
)
2373 self
. assertIn ( '192.168.100.11/24' , output
)
2375 def test_address_peer_ipv4 ( self
):
2376 # test for issue #17304
2377 copy_network_unit ( '25-address-peer-ipv4.network' , '12-dummy.netdev' )
2379 for trial
in range ( 2 ):
2385 self
. wait_online ([ 'dummy98:routable' ])
2387 output
= check_output ( 'ip -4 address show dev dummy98' )
2388 self
. assertIn ( 'inet 100.64.0.1 peer 100.64.0.2/32 scope global' , output
)
2390 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
2391 def test_prefix_route ( self
):
2392 copy_network_unit ( '25-prefix-route-with-vrf.network' , '12-dummy.netdev' ,
2393 '25-prefix-route-without-vrf.network' , '11-dummy.netdev' ,
2394 '25-vrf.netdev' , '25-vrf.network' )
2395 for trial
in range ( 2 ):
2401 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' , 'vrf99:carrier' ])
2403 output
= check_output ( 'ip route show table 42 dev dummy98' )
2404 print ( '### ip route show table 42 dev dummy98' )
2406 self
. assertRegex ( output
, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1' )
2407 self
. assertRegex ( output
, '10.20.33.0/24 proto kernel scope link src 10.20.33.1' )
2408 self
. assertRegex ( output
, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1' )
2409 self
. assertRegex ( output
, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1' )
2410 self
. assertRegex ( output
, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1' )
2411 self
. assertRegex ( output
, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1' )
2412 self
. assertRegex ( output
, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1' )
2413 output
= check_output ( 'ip -6 route show table 42 dev dummy98' )
2414 print ( '### ip -6 route show table 42 dev dummy98' )
2418 self
. assertRegex ( output
, 'local fdde:11:22::1 proto kernel metric 0 pref medium' )
2419 #self.assertRegex(output, 'fdde:11:22::1 proto kernel metric 256 pref medium')
2420 self
. assertRegex ( output
, 'local fdde:11:33::1 proto kernel metric 0 pref medium' )
2421 self
. assertRegex ( output
, 'fdde:11:33::/64 proto kernel metric 256 pref medium' )
2422 self
. assertRegex ( output
, 'local fdde:11:44::1 proto kernel metric 0 pref medium' )
2423 self
. assertRegex ( output
, 'local fdde:11:55::1 proto kernel metric 0 pref medium' )
2424 self
. assertRegex ( output
, 'fe80::/64 proto kernel metric 256 pref medium' )
2425 self
. assertRegex ( output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium' )
2429 output
= check_output ( 'ip route show dev test1' )
2430 print ( '### ip route show dev test1' )
2432 self
. assertRegex ( output
, '10.21.33.0/24 proto kernel scope link src 10.21.33.1' )
2433 output
= check_output ( 'ip route show table local dev test1' )
2434 print ( '### ip route show table local dev test1' )
2436 self
. assertRegex ( output
, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1' )
2437 self
. assertRegex ( output
, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1' )
2438 self
. assertRegex ( output
, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1' )
2439 self
. assertRegex ( output
, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1' )
2440 self
. assertRegex ( output
, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1' )
2441 self
. assertRegex ( output
, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1' )
2442 output
= check_output ( 'ip -6 route show dev test1' )
2443 print ( '### ip -6 route show dev test1' )
2445 self
. assertRegex ( output
, 'fdde:12:22::1 proto kernel metric 256 pref medium' )
2446 self
. assertRegex ( output
, 'fdde:12:33::/64 proto kernel metric 256 pref medium' )
2447 self
. assertRegex ( output
, 'fe80::/64 proto kernel metric 256 pref medium' )
2448 output
= check_output ( 'ip -6 route show table local dev test1' )
2449 print ( '### ip -6 route show table local dev test1' )
2451 self
. assertRegex ( output
, 'local fdde:12:22::1 proto kernel metric 0 pref medium' )
2452 self
. assertRegex ( output
, 'local fdde:12:33::1 proto kernel metric 0 pref medium' )
2453 self
. assertRegex ( output
, 'local fdde:12:44::1 proto kernel metric 0 pref medium' )
2454 self
. assertRegex ( output
, 'local fdde:12:55::1 proto kernel metric 0 pref medium' )
2455 self
. assertRegex ( output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium' )
2457 def test_configure_without_carrier ( self
):
2458 copy_network_unit ( '11-dummy.netdev' )
2460 self
. wait_operstate ( 'test1' , 'off' , '' )
2461 check_output ( 'ip link set dev test1 up carrier off' )
2463 copy_network_unit ( '25-test1.network.d/configure-without-carrier.conf' , copy_dropins
= False )
2465 self
. wait_online ([ 'test1:no-carrier' ])
2467 carrier_map
= { 'on' : '1' , 'off' : '0' }
2468 routable_map
= { 'on' : 'routable' , 'off' : 'no-carrier' }
2469 for carrier
in [ 'off' , 'on' , 'off' ]:
2470 with self
. subTest ( carrier
= carrier
):
2471 if carrier_map
[ carrier
] != read_link_attr ( 'test1' , 'carrier' ):
2472 check_output ( f
'ip link set dev test1 carrier {carrier} ' )
2473 self
. wait_online ([ f
'test1:{routable_map[carrier]}:{routable_map[carrier]}' ])
2475 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
2477 self
. assertRegex ( output
, '192.168.0.15' )
2478 self
. assertRegex ( output
, '192.168.0.1' )
2479 self
. assertRegex ( output
, routable_map
[ carrier
])
2481 def test_configure_without_carrier_yes_ignore_carrier_loss_no ( self
):
2482 copy_network_unit ( '11-dummy.netdev' )
2484 self
. wait_operstate ( 'test1' , 'off' , '' )
2485 check_output ( 'ip link set dev test1 up carrier off' )
2487 copy_network_unit ( '25-test1.network' )
2489 self
. wait_online ([ 'test1:no-carrier' ])
2491 carrier_map
= { 'on' : '1' , 'off' : '0' }
2492 routable_map
= { 'on' : 'routable' , 'off' : 'no-carrier' }
2493 for ( carrier
, have_config
) in [( 'off' , True ), ( 'on' , True ), ( 'off' , False )]:
2494 with self
. subTest ( carrier
= carrier
, have_config
= have_config
):
2495 if carrier_map
[ carrier
] != read_link_attr ( 'test1' , 'carrier' ):
2496 check_output ( f
'ip link set dev test1 carrier {carrier} ' )
2497 self
. wait_online ([ f
'test1:{routable_map[carrier]}:{routable_map[carrier]}' ])
2499 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
2502 self
. assertRegex ( output
, '192.168.0.15' )
2503 self
. assertRegex ( output
, '192.168.0.1' )
2505 self
. assertNotRegex ( output
, '192.168.0.15' )
2506 self
. assertNotRegex ( output
, '192.168.0.1' )
2507 self
. assertRegex ( output
, routable_map
[ carrier
])
2509 def test_routing_policy_rule ( self
):
2510 copy_network_unit ( '25-routing-policy-rule-test1.network' , '11-dummy.netdev' )
2512 self
. wait_online ([ 'test1:degraded' ])
2514 output
= check_output ( 'ip rule list iif test1 priority 111' )
2516 self
. assertRegex ( output
, '111:' )
2517 self
. assertRegex ( output
, 'from 192.168.100.18' )
2518 self
. assertRegex ( output
, r
'tos (0x08|throughput)\s' )
2519 self
. assertRegex ( output
, 'iif test1' )
2520 self
. assertRegex ( output
, 'oif test1' )
2521 self
. assertRegex ( output
, 'lookup 7' )
2523 output
= check_output ( 'ip rule list iif test1 priority 101' )
2525 self
. assertRegex ( output
, '101:' )
2526 self
. assertRegex ( output
, 'from all' )
2527 self
. assertRegex ( output
, 'iif test1' )
2528 self
. assertRegex ( output
, 'lookup 9' )
2530 output
= check_output ( 'ip -6 rule list iif test1 priority 100' )
2532 self
. assertRegex ( output
, '100:' )
2533 self
. assertRegex ( output
, 'from all' )
2534 self
. assertRegex ( output
, 'iif test1' )
2535 self
. assertRegex ( output
, 'lookup 8' )
2537 output
= check_output ( 'ip rule list iif test1 priority 102' )
2539 self
. assertRegex ( output
, '102:' )
2540 self
. assertRegex ( output
, 'from 0.0.0.0/8' )
2541 self
. assertRegex ( output
, 'iif test1' )
2542 self
. assertRegex ( output
, 'lookup 10' )
2544 # TODO: check json string
2545 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2547 def test_routing_policy_rule_issue_11280 ( self
):
2548 copy_network_unit ( '25-routing-policy-rule-test1.network' , '11-dummy.netdev' ,
2549 '25-routing-policy-rule-dummy98.network' , '12-dummy.netdev' )
2551 for trial
in range ( 3 ):
2552 restart_networkd ( show_logs
=( trial
> 0 ))
2553 self
. wait_online ([ 'test1:degraded' , 'dummy98:degraded' ])
2555 output
= check_output ( 'ip rule list table 7' )
2557 self
. assertRegex ( output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7' )
2559 output
= check_output ( 'ip rule list table 8' )
2561 self
. assertRegex ( output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8' )
2563 def test_routing_policy_rule_reconfigure ( self
):
2564 copy_network_unit ( '25-routing-policy-rule-reconfigure2.network' , '11-dummy.netdev' )
2566 self
. wait_online ([ 'test1:degraded' ])
2568 output
= check_output ( 'ip rule list table 1011' )
2570 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2571 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2572 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2573 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2575 output
= check_output ( 'ip -6 rule list table 1011' )
2577 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2579 copy_network_unit ( '25-routing-policy-rule-reconfigure1.network' , '11-dummy.netdev' )
2581 self
. wait_online ([ 'test1:degraded' ])
2583 output
= check_output ( 'ip rule list table 1011' )
2585 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2586 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2587 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2588 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2590 output
= check_output ( 'ip -6 rule list table 1011' )
2592 self
. assertNotIn ( '10112: from all oif test1 lookup 1011' , output
)
2593 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2595 call ( 'ip rule delete priority 10111' )
2596 call ( 'ip rule delete priority 10112' )
2597 call ( 'ip rule delete priority 10113' )
2598 call ( 'ip rule delete priority 10114' )
2599 call ( 'ip -6 rule delete priority 10113' )
2601 output
= check_output ( 'ip rule list table 1011' )
2603 self
. assertEqual ( output
, '' )
2605 output
= check_output ( 'ip -6 rule list table 1011' )
2607 self
. assertEqual ( output
, '' )
2609 networkctl_reconfigure ( 'test1' )
2610 self
. wait_online ([ 'test1:degraded' ])
2612 output
= check_output ( 'ip rule list table 1011' )
2614 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2615 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2616 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2617 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2619 output
= check_output ( 'ip -6 rule list table 1011' )
2621 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2623 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable ()
2624 def test_routing_policy_rule_port_range ( self
):
2625 copy_network_unit ( '25-fibrule-port-range.network' , '11-dummy.netdev' )
2627 self
. wait_online ([ 'test1:degraded' ])
2629 output
= check_output ( 'ip rule' )
2631 self
. assertRegex ( output
, '111' )
2632 self
. assertRegex ( output
, 'from 192.168.100.18' )
2633 self
. assertRegex ( output
, '1123-1150' )
2634 self
. assertRegex ( output
, '3224-3290' )
2635 self
. assertRegex ( output
, 'tcp' )
2636 self
. assertRegex ( output
, 'lookup 7' )
2638 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable ()
2639 def test_routing_policy_rule_invert ( self
):
2640 copy_network_unit ( '25-fibrule-invert.network' , '11-dummy.netdev' )
2642 self
. wait_online ([ 'test1:degraded' ])
2644 output
= check_output ( 'ip rule' )
2646 self
. assertRegex ( output
, '111' )
2647 self
. assertRegex ( output
, 'not.*?from.*?192.168.100.18' )
2648 self
. assertRegex ( output
, 'tcp' )
2649 self
. assertRegex ( output
, 'lookup 7' )
2651 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable ()
2652 def test_routing_policy_rule_uidrange ( self
):
2653 copy_network_unit ( '25-fibrule-uidrange.network' , '11-dummy.netdev' )
2655 self
. wait_online ([ 'test1:degraded' ])
2657 output
= check_output ( 'ip rule' )
2659 self
. assertRegex ( output
, '111' )
2660 self
. assertRegex ( output
, 'from 192.168.100.18' )
2661 self
. assertRegex ( output
, 'lookup 7' )
2662 self
. assertRegex ( output
, 'uidrange 100-200' )
2664 def _test_route_static ( self
, manage_foreign_routes
):
2665 if not manage_foreign_routes
:
2666 copy_networkd_conf_dropin ( 'networkd-manage-foreign-routes-no.conf' )
2668 copy_network_unit ( '25-route-static.network' , '12-dummy.netdev' )
2670 self
. wait_online ([ 'dummy98:routable' ])
2672 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
2675 print ( '### ip -6 route show dev dummy98' )
2676 output
= check_output ( 'ip -6 route show dev dummy98' )
2678 self
. assertIn ( '2001:1234:5:8fff:ff:ff:ff:ff proto static' , output
)
2679 self
. assertIn ( '2001:1234:5:8f63::1 proto kernel' , output
)
2680 self
. assertIn ( '2001:1234:5:afff:ff:ff:ff:ff via fe80:0:222:4dff:ff:ff:ff:ff proto static' , output
)
2682 print ( '### ip -6 route show default' )
2683 output
= check_output ( 'ip -6 route show default' )
2685 self
. assertIn ( 'default' , output
)
2686 self
. assertIn ( 'via 2001:1234:5:8fff:ff:ff:ff:ff' , output
)
2688 print ( '### ip -4 route show dev dummy98' )
2689 output
= check_output ( 'ip -4 route show dev dummy98' )
2691 self
. assertIn ( '149.10.124.48/28 proto kernel scope link src 149.10.124.58' , output
)
2692 self
. assertIn ( '149.10.124.64 proto static scope link' , output
)
2693 self
. assertIn ( '169.254.0.0/16 proto static scope link metric 2048' , output
)
2694 self
. assertIn ( '192.168.1.1 proto static scope link initcwnd 20' , output
)
2695 self
. assertIn ( '192.168.1.2 proto static scope link initrwnd 30' , output
)
2696 self
. assertIn ( '192.168.1.3 proto static scope link advmss 30' , output
)
2697 self
. assertIn ( 'multicast 149.10.123.4 proto static' , output
)
2699 print ( '### ip -4 route show dev dummy98 default' )
2700 output
= check_output ( 'ip -4 route show dev dummy98 default' )
2702 self
. assertIn ( 'default via 149.10.125.65 proto static onlink' , output
)
2703 self
. assertIn ( 'default via 149.10.124.64 proto static' , output
)
2704 self
. assertIn ( 'default proto static' , output
)
2706 print ( '### ip -4 route show table local dev dummy98' )
2707 output
= check_output ( 'ip -4 route show table local dev dummy98' )
2709 self
. assertIn ( 'local 149.10.123.1 proto static scope host' , output
)
2710 self
. assertIn ( 'anycast 149.10.123.2 proto static scope link' , output
)
2711 self
. assertIn ( 'broadcast 149.10.123.3 proto static scope link' , output
)
2713 print ( '### ip -4 route show type blackhole' )
2714 output
= check_output ( 'ip -4 route show type blackhole' )
2716 self
. assertIn ( 'blackhole 202.54.1.2 proto static' , output
)
2718 print ( '### ip -4 route show type unreachable' )
2719 output
= check_output ( 'ip -4 route show type unreachable' )
2721 self
. assertIn ( 'unreachable 202.54.1.3 proto static' , output
)
2723 print ( '### ip -4 route show type prohibit' )
2724 output
= check_output ( 'ip -4 route show type prohibit' )
2726 self
. assertIn ( 'prohibit 202.54.1.4 proto static' , output
)
2728 print ( '### ip -6 route show type blackhole' )
2729 output
= check_output ( 'ip -6 route show type blackhole' )
2731 self
. assertIn ( 'blackhole 2001:1234:5678::2 dev lo proto static' , output
)
2733 print ( '### ip -6 route show type unreachable' )
2734 output
= check_output ( 'ip -6 route show type unreachable' )
2736 self
. assertIn ( 'unreachable 2001:1234:5678::3 dev lo proto static' , output
)
2738 print ( '### ip -6 route show type prohibit' )
2739 output
= check_output ( 'ip -6 route show type prohibit' )
2741 self
. assertIn ( 'prohibit 2001:1234:5678::4 dev lo proto static' , output
)
2743 print ( '### ip route show 192.168.10.1' )
2744 output
= check_output ( 'ip route show 192.168.10.1' )
2746 self
. assertIn ( '192.168.10.1 proto static' , output
)
2747 self
. assertIn ( 'nexthop via 149.10.124.59 dev dummy98 weight 10' , output
)
2748 self
. assertIn ( 'nexthop via 149.10.124.60 dev dummy98 weight 5' , output
)
2750 print ( '### ip route show 192.168.10.2' )
2751 output
= check_output ( 'ip route show 192.168.10.2' )
2753 # old ip command does not show IPv6 gateways...
2754 self
. assertIn ( '192.168.10.2 proto static' , output
)
2755 self
. assertIn ( 'nexthop' , output
)
2756 self
. assertIn ( 'dev dummy98 weight 10' , output
)
2757 self
. assertIn ( 'dev dummy98 weight 5' , output
)
2759 print ( '### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff' )
2760 output
= check_output ( 'ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff' )
2762 # old ip command does not show 'nexthop' keyword and weight...
2763 self
. assertIn ( '2001:1234:5:7fff:ff:ff:ff:ff' , output
)
2764 self
. assertIn ( 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98' , output
)
2765 self
. assertIn ( 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98' , output
)
2767 # TODO: check json string
2768 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2770 copy_network_unit ( '25-address-static.network' )
2772 self
. wait_online ([ 'dummy98:routable' ])
2774 # check all routes managed by Manager are removed
2775 print ( '### ip -4 route show type blackhole' )
2776 output
= check_output ( 'ip -4 route show type blackhole' )
2778 self
. assertEqual ( output
, '' )
2780 print ( '### ip -4 route show type unreachable' )
2781 output
= check_output ( 'ip -4 route show type unreachable' )
2783 self
. assertEqual ( output
, '' )
2785 print ( '### ip -4 route show type prohibit' )
2786 output
= check_output ( 'ip -4 route show type prohibit' )
2788 self
. assertEqual ( output
, '' )
2790 print ( '### ip -6 route show type blackhole' )
2791 output
= check_output ( 'ip -6 route show type blackhole' )
2793 self
. assertEqual ( output
, '' )
2795 print ( '### ip -6 route show type unreachable' )
2796 output
= check_output ( 'ip -6 route show type unreachable' )
2798 self
. assertEqual ( output
, '' )
2800 print ( '### ip -6 route show type prohibit' )
2801 output
= check_output ( 'ip -6 route show type prohibit' )
2803 self
. assertEqual ( output
, '' )
2805 remove_network_unit ( '25-address-static.network' )
2807 self
. wait_online ([ 'dummy98:routable' ])
2809 # check all routes managed by Manager are reconfigured
2810 print ( '### ip -4 route show type blackhole' )
2811 output
= check_output ( 'ip -4 route show type blackhole' )
2813 self
. assertIn ( 'blackhole 202.54.1.2 proto static' , output
)
2815 print ( '### ip -4 route show type unreachable' )
2816 output
= check_output ( 'ip -4 route show type unreachable' )
2818 self
. assertIn ( 'unreachable 202.54.1.3 proto static' , output
)
2820 print ( '### ip -4 route show type prohibit' )
2821 output
= check_output ( 'ip -4 route show type prohibit' )
2823 self
. assertIn ( 'prohibit 202.54.1.4 proto static' , output
)
2825 print ( '### ip -6 route show type blackhole' )
2826 output
= check_output ( 'ip -6 route show type blackhole' )
2828 self
. assertIn ( 'blackhole 2001:1234:5678::2 dev lo proto static' , output
)
2830 print ( '### ip -6 route show type unreachable' )
2831 output
= check_output ( 'ip -6 route show type unreachable' )
2833 self
. assertIn ( 'unreachable 2001:1234:5678::3 dev lo proto static' , output
)
2835 print ( '### ip -6 route show type prohibit' )
2836 output
= check_output ( 'ip -6 route show type prohibit' )
2838 self
. assertIn ( 'prohibit 2001:1234:5678::4 dev lo proto static' , output
)
2840 remove_link ( 'dummy98' )
2843 # check all routes managed by Manager are removed
2844 print ( '### ip -4 route show type blackhole' )
2845 output
= check_output ( 'ip -4 route show type blackhole' )
2847 self
. assertEqual ( output
, '' )
2849 print ( '### ip -4 route show type unreachable' )
2850 output
= check_output ( 'ip -4 route show type unreachable' )
2852 self
. assertEqual ( output
, '' )
2854 print ( '### ip -4 route show type prohibit' )
2855 output
= check_output ( 'ip -4 route show type prohibit' )
2857 self
. assertEqual ( output
, '' )
2859 print ( '### ip -6 route show type blackhole' )
2860 output
= check_output ( 'ip -6 route show type blackhole' )
2862 self
. assertEqual ( output
, '' )
2864 print ( '### ip -6 route show type unreachable' )
2865 output
= check_output ( 'ip -6 route show type unreachable' )
2867 self
. assertEqual ( output
, '' )
2869 print ( '### ip -6 route show type prohibit' )
2870 output
= check_output ( 'ip -6 route show type prohibit' )
2872 self
. assertEqual ( output
, '' )
2876 def test_route_static ( self
):
2878 for manage_foreign_routes
in [ True , False ]:
2884 print ( f
'### test_route_static(manage_foreign_routes= {manage_foreign_routes} )' )
2885 with self
. subTest ( manage_foreign_routes
= manage_foreign_routes
):
2886 self
._ test
_ route
_ static
( manage_foreign_routes
)
2888 @expectedFailureIfRTA_VIAIsNotSupported ()
2889 def test_route_via_ipv6 ( self
):
2890 copy_network_unit ( '25-route-via-ipv6.network' , '12-dummy.netdev' )
2892 self
. wait_online ([ 'dummy98:routable' ])
2894 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
2897 print ( '### ip -6 route show dev dummy98' )
2898 output
= check_output ( 'ip -6 route show dev dummy98' )
2900 self
. assertRegex ( output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static' )
2901 self
. assertRegex ( output
, '2001:1234:5:8f63::1 proto kernel' )
2903 print ( '### ip -4 route show dev dummy98' )
2904 output
= check_output ( 'ip -4 route show dev dummy98' )
2906 self
. assertRegex ( output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58' )
2907 self
. assertRegex ( output
, '149.10.124.66 via inet6 2001:1234:5:8fff:ff:ff:ff:ff proto static' )
2909 @expectedFailureIfModuleIsNotAvailable ( 'tcp_dctcp' )
2910 def test_route_congctl ( self
):
2911 copy_network_unit ( '25-route-congctl.network' , '12-dummy.netdev' )
2913 self
. wait_online ([ 'dummy98:routable' ])
2915 print ( '### ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff' )
2916 output
= check_output ( 'ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff' )
2918 self
. assertIn ( '2001:1234:5:8fff:ff:ff:ff:ff proto static' , output
)
2919 self
. assertIn ( 'congctl dctcp' , output
)
2921 print ( '### ip -4 route show dev dummy98 149.10.124.66' )
2922 output
= check_output ( 'ip -4 route show dev dummy98 149.10.124.66' )
2924 self
. assertIn ( '149.10.124.66 proto static' , output
)
2925 self
. assertIn ( 'congctl dctcp' , output
)
2927 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
2928 def test_route_vrf ( self
):
2929 copy_network_unit ( '25-route-vrf.network' , '12-dummy.netdev' ,
2930 '25-vrf.netdev' , '25-vrf.network' )
2932 self
. wait_online ([ 'dummy98:routable' , 'vrf99:carrier' ])
2934 output
= check_output ( 'ip route show vrf vrf99' )
2936 self
. assertRegex ( output
, 'default via 192.168.100.1' )
2938 output
= check_output ( 'ip route show' )
2940 self
. assertNotRegex ( output
, 'default via 192.168.100.1' )
2942 def test_gateway_reconfigure ( self
):
2943 copy_network_unit ( '25-gateway-static.network' , '12-dummy.netdev' )
2945 self
. wait_online ([ 'dummy98:routable' ])
2946 print ( '### ip -4 route show dev dummy98 default' )
2947 output
= check_output ( 'ip -4 route show dev dummy98 default' )
2949 self
. assertIn ( 'default via 149.10.124.59 proto static' , output
)
2950 self
. assertNotIn ( '149.10.124.60' , output
)
2952 remove_network_unit ( '25-gateway-static.network' )
2953 copy_network_unit ( '25-gateway-next-static.network' )
2955 self
. wait_online ([ 'dummy98:routable' ])
2956 print ( '### ip -4 route show dev dummy98 default' )
2957 output
= check_output ( 'ip -4 route show dev dummy98 default' )
2959 self
. assertNotIn ( '149.10.124.59' , output
)
2960 self
. assertIn ( 'default via 149.10.124.60 proto static' , output
)
2962 def test_ip_route_ipv6_src_route ( self
):
2963 # a dummy device does not make the addresses go through tentative state, so we
2964 # reuse a bond from an earlier test, which does make the addresses go through
2965 # tentative state, and do our test on that
2966 copy_network_unit ( '23-active-slave.network' , '25-route-ipv6-src.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
2968 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:routable' ])
2970 output
= check_output ( 'ip -6 route list dev bond199' )
2972 self
. assertRegex ( output
, 'abcd::/16' )
2973 self
. assertRegex ( output
, 'src' )
2974 self
. assertRegex ( output
, '2001:1234:56:8f63::2' )
2976 def test_ip_link_mac_address ( self
):
2977 copy_network_unit ( '25-address-link-section.network' , '12-dummy.netdev' )
2979 self
. wait_online ([ 'dummy98:degraded' ])
2981 output
= check_output ( 'ip link show dummy98' )
2983 self
. assertRegex ( output
, '00:01:02:aa:bb:cc' )
2985 def test_ip_link_unmanaged ( self
):
2986 copy_network_unit ( '25-link-section-unmanaged.network' , '12-dummy.netdev' )
2989 self
. wait_operstate ( 'dummy98' , 'off' , setup_state
= 'unmanaged' )
2991 def test_ipv6_address_label ( self
):
2992 copy_network_unit ( '25-ipv6-address-label-section.network' , '12-dummy.netdev' )
2994 self
. wait_online ([ 'dummy98:degraded' ])
2996 output
= check_output ( 'ip addrlabel list' )
2998 self
. assertRegex ( output
, '2004:da8:1::/64' )
3000 def test_ipv6_proxy_ndp ( self
):
3001 copy_network_unit ( '25-ipv6-proxy-ndp.network' , '12-dummy.netdev' )
3004 self
. wait_online ([ 'dummy98:routable' ])
3006 output
= check_output ( 'ip neighbor show proxy dev dummy98' )
3008 for i
in range ( 1 , 5 ):
3009 self
. assertRegex ( output
, f
'2607:5300:203:5215: {i} ::1 *proxy' )
3011 def test_neighbor_section ( self
):
3012 copy_network_unit ( '25-neighbor-section.network' , '12-dummy.netdev' )
3014 self
. wait_online ([ 'dummy98:degraded' ], timeout
= '40s' )
3016 print ( '### ip neigh list dev dummy98' )
3017 output
= check_output ( 'ip neigh list dev dummy98' )
3019 self
. assertRegex ( output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT' )
3020 self
. assertRegex ( output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT' )
3022 # TODO: check json string
3023 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3025 def test_neighbor_reconfigure ( self
):
3026 copy_network_unit ( '25-neighbor-section.network' , '12-dummy.netdev' )
3028 self
. wait_online ([ 'dummy98:degraded' ], timeout
= '40s' )
3030 print ( '### ip neigh list dev dummy98' )
3031 output
= check_output ( 'ip neigh list dev dummy98' )
3033 self
. assertRegex ( output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT' )
3034 self
. assertRegex ( output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT' )
3036 remove_network_unit ( '25-neighbor-section.network' )
3037 copy_network_unit ( '25-neighbor-next.network' )
3039 self
. wait_online ([ 'dummy98:degraded' ], timeout
= '40s' )
3040 print ( '### ip neigh list dev dummy98' )
3041 output
= check_output ( 'ip neigh list dev dummy98' )
3043 self
. assertNotRegex ( output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT' )
3044 self
. assertRegex ( output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT' )
3045 self
. assertNotRegex ( output
, '2004:da8:1::1.*PERMANENT' )
3047 def test_neighbor_gre ( self
):
3048 copy_network_unit ( '25-neighbor-ip.network' , '25-neighbor-ipv6.network' , '25-neighbor-ip-dummy.network' ,
3049 '12-dummy.netdev' , '25-gre-tunnel-remote-any.netdev' , '25-ip6gre-tunnel-remote-any.netdev' )
3051 self
. wait_online ([ 'dummy98:degraded' , 'gretun97:routable' , 'ip6gretun97:routable' ], timeout
= '40s' )
3053 output
= check_output ( 'ip neigh list dev gretun97' )
3055 self
. assertRegex ( output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT' )
3057 output
= check_output ( 'ip neigh list dev ip6gretun97' )
3059 self
. assertRegex ( output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT' )
3061 # TODO: check json string
3062 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3064 def test_link_local_addressing ( self
):
3065 copy_network_unit ( '25-link-local-addressing-yes.network' , '11-dummy.netdev' ,
3066 '25-link-local-addressing-no.network' , '12-dummy.netdev' )
3068 self
. wait_online ([ 'test1:degraded' , 'dummy98:carrier' ])
3070 output
= check_output ( 'ip address show dev test1' )
3072 self
. assertRegex ( output
, 'inet .* scope link' )
3073 self
. assertRegex ( output
, 'inet6 .* scope link' )
3075 output
= check_output ( 'ip address show dev dummy98' )
3077 self
. assertNotRegex ( output
, 'inet6* .* scope link' )
3079 # Documentation/networking/ip-sysctl.txt
3081 # addr_gen_mode - INTEGER
3082 # Defines how link-local and autoconf addresses are generated.
3084 # 0: generate address based on EUI64 (default)
3085 # 1: do no generate a link-local address, use EUI64 for addresses generated
3087 # 2: generate stable privacy addresses, using the secret from
3088 # stable_secret (RFC7217)
3089 # 3: generate stable privacy addresses, using a random secret if unset
3091 self
. check_ipv6_sysctl_attr ( 'test1' , 'stable_secret' , '0123:4567:89ab:cdef:0123:4567:89ab:cdef' )
3092 self
. check_ipv6_sysctl_attr ( 'test1' , 'addr_gen_mode' , '2' )
3093 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'addr_gen_mode' , '1' )
3095 def test_link_local_addressing_ipv6ll ( self
):
3096 copy_network_unit ( '26-link-local-addressing-ipv6.network' , '12-dummy.netdev' )
3098 self
. wait_online ([ 'dummy98:degraded' ])
3100 # An IPv6LL address exists by default.
3101 output
= check_output ( 'ip address show dev dummy98' )
3103 self
. assertRegex ( output
, 'inet6 .* scope link' )
3105 copy_network_unit ( '25-link-local-addressing-no.network' )
3107 self
. wait_online ([ 'dummy98:carrier' ])
3109 # Check if the IPv6LL address is removed.
3110 output
= check_output ( 'ip address show dev dummy98' )
3112 self
. assertNotRegex ( output
, 'inet6 .* scope link' )
3114 remove_network_unit ( '25-link-local-addressing-no.network' )
3116 self
. wait_online ([ 'dummy98:degraded' ])
3118 # Check if a new IPv6LL address is assigned.
3119 output
= check_output ( 'ip address show dev dummy98' )
3121 self
. assertRegex ( output
, 'inet6 .* scope link' )
3123 def test_sysctl ( self
):
3124 copy_network_unit ( '25-sysctl.network' , '12-dummy.netdev' )
3126 self
. wait_online ([ 'dummy98:degraded' ])
3128 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
3129 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'use_tempaddr' , '2' )
3130 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'dad_transmits' , '3' )
3131 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'hop_limit' , '5' )
3132 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'proxy_ndp' , '1' )
3133 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
3134 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'proxy_arp' , '1' )
3135 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'accept_local' , '1' )
3137 def test_sysctl_disable_ipv6 ( self
):
3138 copy_network_unit ( '25-sysctl-disable-ipv6.network' , '12-dummy.netdev' )
3140 print ( '## Disable ipv6' )
3141 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=1' )
3142 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=1' )
3145 self
. wait_online ([ 'dummy98:routable' ])
3147 output
= check_output ( 'ip -4 address show dummy98' )
3149 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3150 output
= check_output ( 'ip -6 address show dummy98' )
3152 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3153 self
. assertRegex ( output
, 'inet6 .* scope link' )
3154 output
= check_output ( 'ip -4 route show dev dummy98' )
3156 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3157 output
= check_output ( 'ip -6 route show default' )
3159 self
. assertRegex ( output
, 'default' )
3160 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3162 remove_link ( 'dummy98' )
3164 print ( '## Enable ipv6' )
3165 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=0' )
3166 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=0' )
3169 self
. wait_online ([ 'dummy98:routable' ])
3171 output
= check_output ( 'ip -4 address show dummy98' )
3173 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3174 output
= check_output ( 'ip -6 address show dummy98' )
3176 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3177 self
. assertRegex ( output
, 'inet6 .* scope link' )
3178 output
= check_output ( 'ip -4 route show dev dummy98' )
3180 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3181 output
= check_output ( 'ip -6 route show default' )
3183 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3185 def test_bind_carrier ( self
):
3186 copy_network_unit ( '25-bind-carrier.network' , '11-dummy.netdev' )
3189 # no bound interface.
3190 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
3191 output
= check_output ( 'ip address show test1' )
3193 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3194 self
. assertIn ( 'DOWN' , output
)
3195 self
. assertNotIn ( '192.168.10' , output
)
3197 # add one bound interface. The interface will be up.
3198 check_output ( 'ip link add dummy98 type dummy' )
3199 check_output ( 'ip link set dummy98 up' )
3200 self
. wait_online ([ 'test1:routable' ])
3201 output
= check_output ( 'ip address show test1' )
3203 self
. assertIn ( 'UP,LOWER_UP' , output
)
3204 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3206 # add another bound interface. The interface is still up.
3207 check_output ( 'ip link add dummy99 type dummy' )
3208 check_output ( 'ip link set dummy99 up' )
3209 self
. wait_operstate ( 'dummy99' , 'degraded' , setup_state
= 'unmanaged' )
3210 output
= check_output ( 'ip address show test1' )
3212 self
. assertIn ( 'UP,LOWER_UP' , output
)
3213 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3215 # remove one of the bound interfaces. The interface is still up
3216 remove_link ( 'dummy98' )
3217 output
= check_output ( 'ip address show test1' )
3219 self
. assertIn ( 'UP,LOWER_UP' , output
)
3220 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3222 # bring down the remaining bound interface. The interface will be down.
3223 check_output ( 'ip link set dummy99 down' )
3224 self
. wait_operstate ( 'test1' , 'off' )
3225 self
. wait_address_dropped ( 'test1' , r
'192.168.10' , ipv
= '-4' , timeout_sec
= 10 )
3226 output
= check_output ( 'ip address show test1' )
3228 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3229 self
. assertIn ( 'DOWN' , output
)
3230 self
. assertNotIn ( '192.168.10' , output
)
3232 # bring up the bound interface. The interface will be up.
3233 check_output ( 'ip link set dummy99 up' )
3234 self
. wait_online ([ 'test1:routable' ])
3235 output
= check_output ( 'ip address show test1' )
3237 self
. assertIn ( 'UP,LOWER_UP' , output
)
3238 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3240 # remove the remaining bound interface. The interface will be down.
3241 remove_link ( 'dummy99' )
3242 self
. wait_operstate ( 'test1' , 'off' )
3243 self
. wait_address_dropped ( 'test1' , r
'192.168.10' , ipv
= '-4' , timeout_sec
= 10 )
3244 output
= check_output ( 'ip address show test1' )
3246 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3247 self
. assertIn ( 'DOWN' , output
)
3248 self
. assertNotIn ( '192.168.10' , output
)
3250 # re-add one bound interface. The interface will be up.
3251 check_output ( 'ip link add dummy98 type dummy' )
3252 check_output ( 'ip link set dummy98 up' )
3253 self
. wait_online ([ 'test1:routable' ])
3254 output
= check_output ( 'ip address show test1' )
3256 self
. assertIn ( 'UP,LOWER_UP' , output
)
3257 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3259 def _test_activation_policy ( self
, interface
, test
):
3260 conffile
= '25-activation-policy.network'
3262 conffile
= f
' {conffile} .d/ {test} .conf'
3263 if interface
== 'vlan99' :
3264 copy_network_unit ( '21-vlan.netdev' , '21-vlan-test1.network' )
3265 copy_network_unit ( '11-dummy.netdev' , conffile
, copy_dropins
= False )
3268 always
= test
. startswith ( 'always' )
3269 initial_up
= test
!= 'manual' and not test
. endswith ( 'down' ) # note: default is up
3270 expect_up
= initial_up
3271 next_up
= not expect_up
3273 if test
. endswith ( 'down' ):
3274 self
. wait_activated ( interface
)
3276 for iteration
in range ( 4 ):
3277 with self
. subTest ( iteration
= iteration
, expect_up
= expect_up
):
3278 operstate
= 'routable' if expect_up
else 'off'
3279 setup_state
= 'configured' if expect_up
else ( 'configuring' if iteration
== 0 else None )
3280 self
. wait_operstate ( interface
, operstate
, setup_state
= setup_state
, setup_timeout
= 20 )
3283 self
. assertIn ( 'UP' , check_output ( f
'ip link show {interface} ' ))
3284 self
. assertIn ( '192.168.10.30/24' , check_output ( f
'ip address show {interface} ' ))
3285 self
. assertIn ( 'default via 192.168.10.1' , check_output ( f
'ip route show dev {interface} ' ))
3287 self
. assertIn ( 'DOWN' , check_output ( f
'ip link show {interface} ' ))
3290 check_output ( f
'ip link set dev {interface} up' )
3292 check_output ( f
'ip link set dev {interface} down' )
3293 expect_up
= initial_up
if always
else next_up
3294 next_up
= not next_up
3298 def test_activation_policy ( self
):
3300 for interface
in [ 'test1' , 'vlan99' ]:
3301 for test
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , '' ]:
3307 print ( f
'### test_activation_policy(interface= {interface} , test= {test} )' )
3308 with self
. subTest ( interface
= interface
, test
= test
):
3309 self
._ test
_ activation
_ policy
( interface
, test
)
3311 def _test_activation_policy_required_for_online ( self
, policy
, required
):
3312 conffile
= '25-activation-policy.network'
3313 units
= [ '11-dummy.netdev' , '12-dummy.netdev' , '12-dummy.network' , conffile
]
3315 units
+= [ f
' {conffile} .d/ {policy} .conf' ]
3317 units
+= [ f
' {conffile} .d/required- {required} .conf' ]
3318 copy_network_unit (* units
, copy_dropins
= False )
3321 if policy
. endswith ( 'down' ):
3322 self
. wait_activated ( 'test1' )
3324 if policy
. endswith ( 'down' ) or policy
== 'manual' :
3325 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
3327 self
. wait_online ([ 'test1' ])
3329 if policy
== 'always-down' :
3330 # if always-down, required for online is forced to no
3333 # otherwise if required for online is specified, it should match that
3334 expected
= required
== 'yes'
3336 # otherwise if only policy specified, required for online defaults to
3337 # true if policy is up, always-up, or bound
3338 expected
= policy
. endswith ( 'up' ) or policy
== 'bound'
3340 # default is true, if neither are specified
3343 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
3346 yesno
= 'yes' if expected
else 'no'
3347 self
. assertRegex ( output
, f
'Required For Online: {yesno} ' )
3349 def test_activation_policy_required_for_online ( self
):
3351 for policy
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , 'bound' , '' ]:
3352 for required
in [ 'yes' , 'no' , '' ]:
3358 print ( f
'### test_activation_policy_required_for_online(policy= {policy} , required= {required} )' )
3359 with self
. subTest ( policy
= policy
, required
= required
):
3360 self
._ test
_ activation
_ policy
_ required
_ for
_ online
( policy
, required
)
3362 def test_domain ( self
):
3363 copy_network_unit ( '12-dummy.netdev' , '24-search-domain.network' )
3365 self
. wait_online ([ 'dummy98:routable' ])
3367 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
3369 self
. assertRegex ( output
, 'Address: 192.168.42.100' )
3370 self
. assertRegex ( output
, 'DNS: 192.168.42.1' )
3371 self
. assertRegex ( output
, 'Search Domains: one' )
3373 def test_keep_configuration_static ( self
):
3374 check_output ( 'ip link add name dummy98 type dummy' )
3375 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
3376 check_output ( 'ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500' )
3377 output
= check_output ( 'ip address show dummy98' )
3379 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
3380 self
. assertRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
3381 output
= check_output ( 'ip route show dev dummy98' )
3384 copy_network_unit ( '24-keep-configuration-static.network' )
3386 self
. wait_online ([ 'dummy98:routable' ])
3388 output
= check_output ( 'ip address show dummy98' )
3390 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
3391 self
. assertNotRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
3393 @expectedFailureIfNexthopIsNotAvailable ()
3394 def test_nexthop ( self
):
3395 def check_nexthop ( self
):
3396 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
3398 output
= check_output ( 'ip nexthop list dev veth99' )
3400 self
. assertIn ( 'id 1 via 192.168.5.1 dev veth99' , output
)
3401 self
. assertIn ( 'id 2 via 2001:1234:5:8f63::2 dev veth99' , output
)
3402 self
. assertIn ( 'id 3 dev veth99' , output
)
3403 self
. assertIn ( 'id 4 dev veth99' , output
)
3404 self
. assertRegex ( output
, 'id 5 via 192.168.10.1 dev veth99 .*onlink' )
3405 self
. assertIn ( 'id 8 via fe80:0:222:4dff:ff:ff:ff:ff dev veth99' , output
)
3406 self
. assertRegex ( output
, r
'id [0-9]* via 192.168.5.2 dev veth99' )
3408 output
= check_output ( 'ip nexthop list dev dummy98' )
3410 self
. assertIn ( 'id 20 via 192.168.20.1 dev dummy98' , output
)
3412 # kernel manages blackhole nexthops on lo
3413 output
= check_output ( 'ip nexthop list dev lo' )
3415 self
. assertIn ( 'id 6 blackhole' , output
)
3416 self
. assertIn ( 'id 7 blackhole' , output
)
3418 # group nexthops are shown with -0 option
3419 output
= check_output ( 'ip -0 nexthop list id 21' )
3421 self
. assertRegex ( output
, r
'id 21 group (1,3/20|20/1,3)' )
3423 output
= check_output ( 'ip route show dev veth99 10.10.10.10' )
3425 self
. assertEqual ( '10.10.10.10 nhid 1 via 192.168.5.1 proto static' , output
)
3427 output
= check_output ( 'ip route show dev veth99 10.10.10.11' )
3429 self
. assertEqual ( '10.10.10.11 nhid 2 via inet6 2001:1234:5:8f63::2 proto static' , output
)
3431 output
= check_output ( 'ip route show dev veth99 10.10.10.12' )
3433 self
. assertEqual ( '10.10.10.12 nhid 5 via 192.168.10.1 proto static onlink' , output
)
3435 output
= check_output ( 'ip -6 route show dev veth99 2001:1234:5:8f62::1' )
3437 self
. assertEqual ( '2001:1234:5:8f62::1 nhid 2 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium' , output
)
3439 output
= check_output ( 'ip route show 10.10.10.13' )
3441 self
. assertEqual ( 'blackhole 10.10.10.13 nhid 6 dev lo proto static' , output
)
3443 output
= check_output ( 'ip -6 route show 2001:1234:5:8f62::2' )
3445 self
. assertEqual ( 'blackhole 2001:1234:5:8f62::2 nhid 7 dev lo proto static metric 1024 pref medium' , output
)
3447 output
= check_output ( 'ip route show 10.10.10.14' )
3449 self
. assertIn ( '10.10.10.14 nhid 21 proto static' , output
)
3450 self
. assertIn ( 'nexthop via 192.168.20.1 dev dummy98 weight 1' , output
)
3451 self
. assertIn ( 'nexthop via 192.168.5.1 dev veth99 weight 3' , output
)
3453 # TODO: check json string
3454 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3456 copy_network_unit ( '25-nexthop.network' , '25-veth.netdev' , '25-veth-peer.network' ,
3457 '12-dummy.netdev' , '25-nexthop-dummy.network' )
3462 remove_network_unit ( '25-nexthop.network' )
3463 copy_network_unit ( '25-nexthop-nothing.network' )
3465 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
3467 output
= check_output ( 'ip nexthop list dev veth99' )
3469 self
. assertEqual ( output
, '' )
3470 output
= check_output ( 'ip nexthop list dev lo' )
3472 self
. assertEqual ( output
, '' )
3474 remove_network_unit ( '25-nexthop-nothing.network' )
3475 copy_network_unit ( '25-nexthop.network' )
3476 networkctl_reconfigure ( 'dummy98' )
3481 remove_link ( 'veth99' )
3484 output
= check_output ( 'ip nexthop list dev lo' )
3486 self
. assertEqual ( output
, '' )
3488 class NetworkdTCTests ( unittest
. TestCase
, Utilities
):
3496 @expectedFailureIfModuleIsNotAvailable ( 'sch_cake' )
3497 def test_qdisc_cake ( self
):
3498 copy_network_unit ( '25-qdisc-cake.network' , '12-dummy.netdev' )
3500 self
. wait_online ([ 'dummy98:routable' ])
3502 output
= check_output ( 'tc qdisc show dev dummy98' )
3504 self
. assertIn ( 'qdisc cake 3a: root' , output
)
3505 self
. assertIn ( 'bandwidth 500Mbit' , output
)
3506 self
. assertIn ( 'autorate-ingress' , output
)
3507 self
. assertIn ( 'diffserv8' , output
)
3508 self
. assertIn ( 'dual-dsthost' , output
)
3509 self
. assertIn ( ' nat' , output
)
3510 self
. assertIn ( ' wash' , output
)
3511 self
. assertIn ( ' split-gso' , output
)
3512 self
. assertIn ( ' raw' , output
)
3513 self
. assertIn ( ' atm' , output
)
3514 self
. assertIn ( 'overhead 128' , output
)
3515 self
. assertIn ( 'mpu 20' , output
)
3516 self
. assertIn ( 'fwmark 0xff00' , output
)
3517 self
. assertIn ( 'rtt 1s' , output
)
3518 self
. assertIn ( 'ack-filter-aggressive' , output
)
3520 @expectedFailureIfModuleIsNotAvailable ( 'sch_codel' )
3521 def test_qdisc_codel ( self
):
3522 copy_network_unit ( '25-qdisc-codel.network' , '12-dummy.netdev' )
3524 self
. wait_online ([ 'dummy98:routable' ])
3526 output
= check_output ( 'tc qdisc show dev dummy98' )
3528 self
. assertRegex ( output
, 'qdisc codel 33: root' )
3529 self
. assertRegex ( output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn' )
3531 @expectedFailureIfModuleIsNotAvailable ( 'sch_drr' )
3532 def test_qdisc_drr ( self
):
3533 copy_network_unit ( '25-qdisc-drr.network' , '12-dummy.netdev' )
3535 self
. wait_online ([ 'dummy98:routable' ])
3537 output
= check_output ( 'tc qdisc show dev dummy98' )
3539 self
. assertRegex ( output
, 'qdisc drr 2: root' )
3540 output
= check_output ( 'tc class show dev dummy98' )
3542 self
. assertRegex ( output
, 'class drr 2:30 root quantum 2000b' )
3544 @expectedFailureIfModuleIsNotAvailable ( 'sch_ets' )
3545 def test_qdisc_ets ( self
):
3546 copy_network_unit ( '25-qdisc-ets.network' , '12-dummy.netdev' )
3548 self
. wait_online ([ 'dummy98:routable' ])
3550 output
= check_output ( 'tc qdisc show dev dummy98' )
3553 self
. assertRegex ( output
, 'qdisc ets 3a: root' )
3554 self
. assertRegex ( output
, 'bands 10 strict 3' )
3555 self
. assertRegex ( output
, 'quanta 1 2 3 4 5' )
3556 self
. assertRegex ( output
, 'priomap 3 4 5 6 7' )
3558 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq' )
3559 def test_qdisc_fq ( self
):
3560 copy_network_unit ( '25-qdisc-fq.network' , '12-dummy.netdev' )
3562 self
. wait_online ([ 'dummy98:routable' ])
3564 output
= check_output ( 'tc qdisc show dev dummy98' )
3566 self
. assertRegex ( output
, 'qdisc fq 32: root' )
3567 self
. assertRegex ( output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511' )
3568 self
. assertRegex ( output
, 'quantum 1500' )
3569 self
. assertRegex ( output
, 'initial_quantum 13000' )
3570 self
. assertRegex ( output
, 'maxrate 1Mbit' )
3572 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_codel' )
3573 def test_qdisc_fq_codel ( self
):
3574 copy_network_unit ( '25-qdisc-fq_codel.network' , '12-dummy.netdev' )
3576 self
. wait_online ([ 'dummy98:routable' ])
3578 output
= check_output ( 'tc qdisc show dev dummy98' )
3580 self
. assertRegex ( output
, 'qdisc fq_codel 34: root' )
3581 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' )
3583 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_pie' )
3584 def test_qdisc_fq_pie ( self
):
3585 copy_network_unit ( '25-qdisc-fq_pie.network' , '12-dummy.netdev' )
3587 self
. wait_online ([ 'dummy98:routable' ])
3589 output
= check_output ( 'tc qdisc show dev dummy98' )
3592 self
. assertRegex ( output
, 'qdisc fq_pie 3a: root' )
3593 self
. assertRegex ( output
, 'limit 200000p' )
3595 @expectedFailureIfModuleIsNotAvailable ( 'sch_gred' )
3596 def test_qdisc_gred ( self
):
3597 copy_network_unit ( '25-qdisc-gred.network' , '12-dummy.netdev' )
3599 self
. wait_online ([ 'dummy98:routable' ])
3601 output
= check_output ( 'tc qdisc show dev dummy98' )
3603 self
. assertRegex ( output
, 'qdisc gred 38: root' )
3604 self
. assertRegex ( output
, 'vqs 12 default 10 grio' )
3606 @expectedFailureIfModuleIsNotAvailable ( 'sch_hhf' )
3607 def test_qdisc_hhf ( self
):
3608 copy_network_unit ( '25-qdisc-hhf.network' , '12-dummy.netdev' )
3610 self
. wait_online ([ 'dummy98:routable' ])
3612 output
= check_output ( 'tc qdisc show dev dummy98' )
3614 self
. assertRegex ( output
, 'qdisc hhf 3a: root' )
3615 self
. assertRegex ( output
, 'limit 1022p' )
3617 @expectedFailureIfModuleIsNotAvailable ( 'sch_htb' )
3618 def test_qdisc_htb_fifo ( self
):
3619 copy_network_unit ( '25-qdisc-htb-fifo.network' , '12-dummy.netdev' )
3621 self
. wait_online ([ 'dummy98:routable' ])
3623 output
= check_output ( 'tc qdisc show dev dummy98' )
3625 self
. assertRegex ( output
, 'qdisc htb 2: root' )
3626 self
. assertRegex ( output
, r
'default (0x30|30)' )
3628 self
. assertRegex ( output
, 'qdisc pfifo 37: parent 2:37' )
3629 self
. assertRegex ( output
, 'limit 100000p' )
3631 self
. assertRegex ( output
, 'qdisc bfifo 3a: parent 2:3a' )
3632 self
. assertRegex ( output
, 'limit 1000000' )
3634 self
. assertRegex ( output
, 'qdisc pfifo_head_drop 3b: parent 2:3b' )
3635 self
. assertRegex ( output
, 'limit 1023p' )
3637 self
. assertRegex ( output
, 'qdisc pfifo_fast 3c: parent 2:3c' )
3639 output
= check_output ( 'tc -d class show dev dummy98' )
3641 # Here (:|prio) is a workaround for a bug in iproute2 v6.2.0 caused by
3642 # https://github.com/shemminger/iproute2/commit/010a8388aea11e767ba3a2506728b9ad9760df0e
3643 # which is fixed in v6.3.0 by
3644 # https://github.com/shemminger/iproute2/commit/4e0e56e0ef05387f7f5d8ab41fe6ec6a1897b26d
3645 self
. assertRegex ( output
, 'class htb 2:37 root leaf 37(:|prio) ' )
3646 self
. assertRegex ( output
, 'class htb 2:3a root leaf 3a(:|prio) ' )
3647 self
. assertRegex ( output
, 'class htb 2:3b root leaf 3b(:|prio) ' )
3648 self
. assertRegex ( output
, 'class htb 2:3c root leaf 3c(:|prio) ' )
3649 self
. assertRegex ( output
, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit' )
3650 self
. assertRegex ( output
, 'burst 123456' )
3651 self
. assertRegex ( output
, 'cburst 123457' )
3653 @expectedFailureIfModuleIsNotAvailable ( 'sch_ingress' )
3654 def test_qdisc_ingress ( self
):
3655 copy_network_unit ( '25-qdisc-clsact.network' , '12-dummy.netdev' ,
3656 '25-qdisc-ingress.network' , '11-dummy.netdev' )
3658 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' ])
3660 output
= check_output ( 'tc qdisc show dev dummy98' )
3662 self
. assertRegex ( output
, 'qdisc clsact' )
3664 output
= check_output ( 'tc qdisc show dev test1' )
3666 self
. assertRegex ( output
, 'qdisc ingress' )
3668 @expectedFailureIfModuleIsNotAvailable ( 'sch_netem' )
3669 def test_qdisc_netem ( self
):
3670 copy_network_unit ( '25-qdisc-netem.network' , '12-dummy.netdev' ,
3671 '25-qdisc-netem-compat.network' , '11-dummy.netdev' )
3673 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' ])
3675 output
= check_output ( 'tc qdisc show dev dummy98' )
3677 self
. assertRegex ( output
, 'qdisc netem 30: root' )
3678 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
3680 output
= check_output ( 'tc qdisc show dev test1' )
3682 self
. assertRegex ( output
, 'qdisc netem [0-9a-f]*: root' )
3683 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
3685 @expectedFailureIfModuleIsNotAvailable ( 'sch_pie' )
3686 def test_qdisc_pie ( self
):
3687 copy_network_unit ( '25-qdisc-pie.network' , '12-dummy.netdev' )
3689 self
. wait_online ([ 'dummy98:routable' ])
3691 output
= check_output ( 'tc qdisc show dev dummy98' )
3693 self
. assertRegex ( output
, 'qdisc pie 3a: root' )
3694 self
. assertRegex ( output
, 'limit 200000' )
3696 @expectedFailureIfModuleIsNotAvailable ( 'sch_qfq' )
3697 def test_qdisc_qfq ( self
):
3698 copy_network_unit ( '25-qdisc-qfq.network' , '12-dummy.netdev' )
3700 self
. wait_online ([ 'dummy98:routable' ])
3702 output
= check_output ( 'tc qdisc show dev dummy98' )
3704 self
. assertRegex ( output
, 'qdisc qfq 2: root' )
3705 output
= check_output ( 'tc class show dev dummy98' )
3707 self
. assertRegex ( output
, 'class qfq 2:30 root weight 2 maxpkt 16000' )
3708 self
. assertRegex ( output
, 'class qfq 2:31 root weight 10 maxpkt 8000' )
3710 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfb' )
3711 def test_qdisc_sfb ( self
):
3712 copy_network_unit ( '25-qdisc-sfb.network' , '12-dummy.netdev' )
3714 self
. wait_online ([ 'dummy98:routable' ])
3716 output
= check_output ( 'tc qdisc show dev dummy98' )
3718 self
. assertRegex ( output
, 'qdisc sfb 39: root' )
3719 self
. assertRegex ( output
, 'limit 200000' )
3721 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfq' )
3722 def test_qdisc_sfq ( self
):
3723 copy_network_unit ( '25-qdisc-sfq.network' , '12-dummy.netdev' )
3725 self
. wait_online ([ 'dummy98:routable' ])
3727 output
= check_output ( 'tc qdisc show dev dummy98' )
3729 self
. assertRegex ( output
, 'qdisc sfq 36: root' )
3730 self
. assertRegex ( output
, 'perturb 5sec' )
3732 @expectedFailureIfModuleIsNotAvailable ( 'sch_tbf' )
3733 def test_qdisc_tbf ( self
):
3734 copy_network_unit ( '25-qdisc-tbf.network' , '12-dummy.netdev' )
3736 self
. wait_online ([ 'dummy98:routable' ])
3738 output
= check_output ( 'tc qdisc show dev dummy98' )
3740 self
. assertRegex ( output
, 'qdisc tbf 35: root' )
3741 self
. assertRegex ( output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms' )
3743 @expectedFailureIfModuleIsNotAvailable ( 'sch_teql' )
3744 def test_qdisc_teql ( self
):
3745 call_quiet ( 'rmmod sch_teql' )
3747 copy_network_unit ( '25-qdisc-teql.network' , '12-dummy.netdev' )
3749 self
. wait_links ( 'dummy98' )
3750 check_output ( 'modprobe sch_teql max_equalizers=2' )
3751 self
. wait_online ([ 'dummy98:routable' ])
3753 output
= check_output ( 'tc qdisc show dev dummy98' )
3755 self
. assertRegex ( output
, 'qdisc teql1 31: root' )
3757 class NetworkdStateFileTests ( unittest
. TestCase
, Utilities
):
3765 def test_state_file ( self
):
3766 copy_network_unit ( '12-dummy.netdev' , '25-state-file-tests.network' )
3768 self
. wait_online ([ 'dummy98:routable' ])
3770 # make link state file updated
3771 check_output (* resolvectl_cmd
, 'revert' , 'dummy98' , env
= env
)
3773 # TODO: check json string
3774 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3776 output
= read_link_state_file ( 'dummy98' )
3778 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
3779 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
3780 self
. assertIn ( 'ADMIN_STATE=configured' , output
)
3781 self
. assertIn ( 'OPER_STATE=routable' , output
)
3782 self
. assertIn ( 'REQUIRED_FOR_ONLINE=yes' , output
)
3783 self
. assertIn ( 'REQUIRED_OPER_STATE_FOR_ONLINE=routable' , output
)
3784 self
. assertIn ( 'REQUIRED_FAMILY_FOR_ONLINE=both' , output
)
3785 self
. assertIn ( 'ACTIVATION_POLICY=up' , output
)
3786 self
. assertIn ( 'NETWORK_FILE=/run/systemd/network/25-state-file-tests.network' , output
)
3787 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
3788 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
3789 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
3790 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
3791 self
. assertIn ( 'LLMNR=no' , output
)
3792 self
. assertIn ( 'MDNS=yes' , output
)
3793 self
. assertIn ( 'DNSSEC=no' , output
)
3795 check_output (* resolvectl_cmd
, 'dns' , 'dummy98' , '10.10.10.12#ccc.com' , '10.10.10.13' , '1111:2222::3333' , env
= env
)
3796 check_output (* resolvectl_cmd
, 'domain' , 'dummy98' , 'hogehogehoge' , '~foofoofoo' , env
= env
)
3797 check_output (* resolvectl_cmd
, 'llmnr' , 'dummy98' , 'yes' , env
= env
)
3798 check_output (* resolvectl_cmd
, 'mdns' , 'dummy98' , 'no' , env
= env
)
3799 check_output (* resolvectl_cmd
, 'dnssec' , 'dummy98' , 'yes' , env
= env
)
3800 check_output (* timedatectl_cmd
, 'ntp-servers' , 'dummy98' , '2.fedora.pool.ntp.org' , '3.fedora.pool.ntp.org' , env
= env
)
3802 # TODO: check json string
3803 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3805 output
= read_link_state_file ( 'dummy98' )
3807 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
3808 self
. assertIn ( 'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org' , output
)
3809 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
3810 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
3811 self
. assertIn ( 'LLMNR=yes' , output
)
3812 self
. assertIn ( 'MDNS=no' , output
)
3813 self
. assertIn ( 'DNSSEC=yes' , output
)
3815 check_output (* timedatectl_cmd
, 'revert' , 'dummy98' , env
= env
)
3817 # TODO: check json string
3818 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3820 output
= read_link_state_file ( 'dummy98' )
3822 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
3823 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
3824 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
3825 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
3826 self
. assertIn ( 'LLMNR=yes' , output
)
3827 self
. assertIn ( 'MDNS=no' , output
)
3828 self
. assertIn ( 'DNSSEC=yes' , output
)
3830 check_output (* resolvectl_cmd
, 'revert' , 'dummy98' , env
= env
)
3832 # TODO: check json string
3833 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3835 output
= read_link_state_file ( 'dummy98' )
3837 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
3838 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
3839 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
3840 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
3841 self
. assertIn ( 'LLMNR=no' , output
)
3842 self
. assertIn ( 'MDNS=yes' , output
)
3843 self
. assertIn ( 'DNSSEC=no' , output
)
3845 def test_address_state ( self
):
3846 copy_network_unit ( '12-dummy.netdev' , '12-dummy-no-address.network' )
3849 self
. wait_online ([ 'dummy98:degraded' ])
3851 output
= read_link_state_file ( 'dummy98' )
3852 self
. assertIn ( 'IPV4_ADDRESS_STATE=off' , output
)
3853 self
. assertIn ( 'IPV6_ADDRESS_STATE=degraded' , output
)
3855 # with a routable IPv4 address
3856 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
3857 self
. wait_online ([ 'dummy98:routable' ], ipv4
= True )
3858 self
. wait_online ([ 'dummy98:routable' ])
3860 output
= read_link_state_file ( 'dummy98' )
3861 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
3862 self
. assertIn ( 'IPV6_ADDRESS_STATE=degraded' , output
)
3864 check_output ( 'ip address del 10.1.2.3/16 dev dummy98' )
3866 # with a routable IPv6 address
3867 check_output ( 'ip address add 2002:da8:1:0:1034:56ff:fe78:9abc/64 dev dummy98' )
3868 self
. wait_online ([ 'dummy98:routable' ], ipv6
= True )
3869 self
. wait_online ([ 'dummy98:routable' ])
3871 output
= read_link_state_file ( 'dummy98' )
3872 self
. assertIn ( 'IPV4_ADDRESS_STATE=off' , output
)
3873 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
3875 class NetworkdBondTests ( unittest
. TestCase
, Utilities
):
3883 def test_bond_keep_master ( self
):
3884 check_output ( 'ip link add bond199 type bond mode active-backup' )
3885 check_output ( 'ip link add dummy98 type dummy' )
3886 check_output ( 'ip link set dummy98 master bond199' )
3888 copy_network_unit ( '23-keep-master.network' )
3890 self
. wait_online ([ 'dummy98:enslaved' ])
3892 output
= check_output ( 'ip -d link show bond199' )
3894 self
. assertRegex ( output
, 'active_slave dummy98' )
3896 output
= check_output ( 'ip -d link show dummy98' )
3898 self
. assertRegex ( output
, 'master bond199' )
3900 def test_bond_active_slave ( self
):
3901 copy_network_unit ( '23-active-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
3903 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
3905 output
= check_output ( 'ip -d link show bond199' )
3907 self
. assertIn ( 'active_slave dummy98' , output
)
3909 def test_bond_primary_slave ( self
):
3910 copy_network_unit ( '23-primary-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
3912 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
3914 output
= check_output ( 'ip -d link show bond199' )
3916 self
. assertIn ( 'primary dummy98' , output
)
3919 mkdir_p ( os
. path
. join ( network_unit_dir
, '23-bond199.network.d' ))
3920 for mac
in [ '00:11:22:33:44:55' , '00:11:22:33:44:56' ]:
3921 with
open ( os
. path
. join ( network_unit_dir
, '23-bond199.network.d/mac.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
3922 f
. write ( f
'[Link] \n MACAddress= {mac} \n ' )
3925 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
3927 output
= check_output ( 'ip -d link show bond199' )
3929 self
. assertIn ( f
'link/ether {mac} ' , output
)
3931 def test_bond_operstate ( self
):
3932 copy_network_unit ( '25-bond.netdev' , '11-dummy.netdev' , '12-dummy.netdev' ,
3933 '25-bond99.network' , '25-bond-slave.network' )
3935 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bond99:routable' ])
3937 output
= check_output ( 'ip -d link show dummy98' )
3939 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
3941 output
= check_output ( 'ip -d link show test1' )
3943 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
3945 output
= check_output ( 'ip -d link show bond99' )
3947 self
. assertRegex ( output
, 'MASTER,UP,LOWER_UP' )
3949 self
. wait_operstate ( 'dummy98' , 'enslaved' )
3950 self
. wait_operstate ( 'test1' , 'enslaved' )
3951 self
. wait_operstate ( 'bond99' , 'routable' )
3953 check_output ( 'ip link set dummy98 down' )
3955 self
. wait_operstate ( 'dummy98' , 'off' )
3956 self
. wait_operstate ( 'test1' , 'enslaved' )
3957 self
. wait_operstate ( 'bond99' , 'degraded-carrier' )
3959 check_output ( 'ip link set dummy98 up' )
3961 self
. wait_operstate ( 'dummy98' , 'enslaved' )
3962 self
. wait_operstate ( 'test1' , 'enslaved' )
3963 self
. wait_operstate ( 'bond99' , 'routable' )
3965 check_output ( 'ip link set dummy98 down' )
3966 check_output ( 'ip link set test1 down' )
3968 self
. wait_operstate ( 'dummy98' , 'off' )
3969 self
. wait_operstate ( 'test1' , 'off' )
3971 if not self
. wait_operstate ( 'bond99' , 'no-carrier' , setup_timeout
= 30 , fail_assert
= False ):
3972 # Huh? Kernel does not recognize that all slave interfaces are down?
3973 # Let's confirm that networkd's operstate is consistent with ip's result.
3974 self
. assertNotRegex ( output
, 'NO-CARRIER' )
3976 class NetworkdBridgeTests ( unittest
. TestCase
, Utilities
):
3984 def test_bridge_vlan ( self
):
3985 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave.network' ,
3986 '26-bridge.netdev' , '26-bridge-vlan-master.network' )
3988 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' ])
3990 output
= check_output ( 'bridge vlan show dev test1' )
3992 self
. assertNotRegex ( output
, '4063' )
3993 for i
in range ( 4064 , 4095 ):
3994 self
. assertRegex ( output
, f
' {i} ' )
3995 self
. assertNotRegex ( output
, '4095' )
3997 output
= check_output ( 'bridge vlan show dev bridge99' )
3999 self
. assertNotRegex ( output
, '4059' )
4000 for i
in range ( 4060 , 4095 ):
4001 self
. assertRegex ( output
, f
' {i} ' )
4002 self
. assertNotRegex ( output
, '4095' )
4004 def test_bridge_vlan_issue_20373 ( self
):
4005 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave-issue-20373.network' ,
4006 '26-bridge-issue-20373.netdev' , '26-bridge-vlan-master-issue-20373.network' ,
4007 '21-vlan.netdev' , '21-vlan.network' )
4009 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' , 'vlan99:routable' ])
4011 output
= check_output ( 'bridge vlan show dev test1' )
4013 self
. assertIn ( '100 PVID Egress Untagged' , output
)
4014 self
. assertIn ( '560' , output
)
4015 self
. assertIn ( '600' , output
)
4017 output
= check_output ( 'bridge vlan show dev bridge99' )
4019 self
. assertIn ( '1 PVID Egress Untagged' , output
)
4020 self
. assertIn ( '100' , output
)
4021 self
. assertIn ( '600' , output
)
4023 def test_bridge_mdb ( self
):
4024 copy_network_unit ( '11-dummy.netdev' , '26-bridge-mdb-slave.network' ,
4025 '26-bridge.netdev' , '26-bridge-mdb-master.network' )
4027 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' ])
4029 output
= check_output ( 'bridge mdb show dev bridge99' )
4031 self
. assertRegex ( output
, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064' )
4032 self
. assertRegex ( output
, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065' )
4034 # Old kernel may not support bridge MDB entries on bridge master
4035 if call_quiet ( 'bridge mdb add dev bridge99 port bridge99 grp 224.0.1.3 temp vid 4068' ) == 0 :
4036 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp ff02:aaaa:fee5::1:4 temp *vid 4066' )
4037 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp 224.0.1.2 temp *vid 4067' )
4039 def test_bridge_keep_master ( self
):
4040 check_output ( 'ip link add bridge99 type bridge' )
4041 check_output ( 'ip link set bridge99 up' )
4042 check_output ( 'ip link add dummy98 type dummy' )
4043 check_output ( 'ip link set dummy98 master bridge99' )
4045 copy_network_unit ( '23-keep-master.network' )
4047 self
. wait_online ([ 'dummy98:enslaved' ])
4049 output
= check_output ( 'ip -d link show dummy98' )
4051 self
. assertRegex ( output
, 'master bridge99' )
4052 self
. assertRegex ( output
, 'bridge' )
4054 output
= check_output ( 'bridge -d link show dummy98' )
4056 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
4057 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
4058 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
4059 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
4060 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
4061 # CONFIG_BRIDGE_IGMP_SNOOPING=y
4062 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
4063 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
4064 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
4065 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
4066 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
4067 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
4069 def test_bridge_property ( self
):
4070 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
4071 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
4072 '25-bridge99.network' )
4074 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' ])
4076 output
= check_output ( 'ip -d link show bridge99' )
4078 self
. assertIn ( 'mtu 9000 ' , output
)
4080 output
= check_output ( 'ip -d link show test1' )
4082 self
. assertIn ( 'master bridge99 ' , output
)
4083 self
. assertIn ( 'bridge_slave' , output
)
4084 self
. assertIn ( 'mtu 9000 ' , output
)
4086 output
= check_output ( 'ip -d link show dummy98' )
4088 self
. assertIn ( 'master bridge99 ' , output
)
4089 self
. assertIn ( 'bridge_slave' , output
)
4090 self
. assertIn ( 'mtu 9000 ' , output
)
4092 output
= check_output ( 'ip addr show bridge99' )
4094 self
. assertIn ( '192.168.0.15/24' , output
)
4096 output
= check_output ( 'bridge -d link show dummy98' )
4098 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
4099 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
4100 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'isolated' , '1' )
4101 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
4102 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
4103 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
4104 # CONFIG_BRIDGE_IGMP_SNOOPING=y
4105 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
4106 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
4107 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
4108 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
4109 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
4110 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
4112 output
= check_output ( 'bridge -d link show test1' )
4114 self
. check_bridge_port_attr ( 'bridge99' , 'test1' , 'priority' , '0' )
4116 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
4117 output
= check_output ( 'ip addr show bridge99' )
4119 self
. assertIn ( '192.168.0.16/24' , output
)
4122 print ( '### ip -6 route list table all dev bridge99' )
4123 output
= check_output ( 'ip -6 route list table all dev bridge99' )
4125 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
4127 remove_link ( 'test1' )
4128 self
. wait_operstate ( 'bridge99' , 'degraded-carrier' )
4130 output
= check_output ( 'ip -d link show bridge99' )
4132 self
. assertIn ( 'mtu 9000 ' , output
)
4134 output
= check_output ( 'ip -d link show dummy98' )
4136 self
. assertIn ( 'master bridge99 ' , output
)
4137 self
. assertIn ( 'bridge_slave' , output
)
4138 self
. assertIn ( 'mtu 9000 ' , output
)
4140 remove_link ( 'dummy98' )
4141 self
. wait_operstate ( 'bridge99' , 'no-carrier' )
4143 output
= check_output ( 'ip -d link show bridge99' )
4145 # When no carrier, the kernel may reset the MTU
4146 self
. assertIn ( 'NO-CARRIER' , output
)
4148 output
= check_output ( 'ip address show bridge99' )
4150 self
. assertNotIn ( '192.168.0.15/24' , output
)
4151 self
. assertIn ( '192.168.0.16/24' , output
) # foreign address is kept
4153 print ( '### ip -6 route list table all dev bridge99' )
4154 output
= check_output ( 'ip -6 route list table all dev bridge99' )
4156 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
4158 check_output ( 'ip link add dummy98 type dummy' )
4159 self
. wait_online ([ 'dummy98:enslaved' , 'bridge99:routable' ])
4161 output
= check_output ( 'ip -d link show bridge99' )
4163 self
. assertIn ( 'mtu 9000 ' , output
)
4165 output
= check_output ( 'ip -d link show dummy98' )
4167 self
. assertIn ( 'master bridge99 ' , output
)
4168 self
. assertIn ( 'bridge_slave' , output
)
4169 self
. assertIn ( 'mtu 9000 ' , output
)
4171 def test_bridge_configure_without_carrier ( self
):
4172 copy_network_unit ( '26-bridge.netdev' , '26-bridge-configure-without-carrier.network' ,
4176 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
4177 for test
in [ 'no-slave' , 'add-slave' , 'slave-up' , 'slave-no-carrier' , 'slave-carrier' , 'slave-down' ]:
4178 with self
. subTest ( test
= test
):
4179 if test
== 'no-slave' :
4180 # bridge has no slaves; it's up but *might* not have carrier
4181 self
. wait_operstate ( 'bridge99' , operstate
= r
'(no-carrier|routable)' , setup_state
= None , setup_timeout
= 30 )
4182 # due to a bug in the kernel, newly-created bridges are brought up
4183 # *with* carrier, unless they have had any setting changed; e.g.
4184 # their mac set, priority set, etc. Then, they will lose carrier
4185 # as soon as a (down) slave interface is added, and regain carrier
4186 # again once the slave interface is brought up.
4187 #self.check_link_attr('bridge99', 'carrier', '0')
4188 elif test
== 'add-slave' :
4189 # add slave to bridge, but leave it down; bridge is definitely no-carrier
4190 self
. check_link_attr ( 'test1' , 'operstate' , 'down' )
4191 check_output ( 'ip link set dev test1 master bridge99' )
4192 self
. wait_operstate ( 'bridge99' , operstate
= 'no-carrier' , setup_state
= None )
4193 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4194 elif test
== 'slave-up' :
4195 # bring up slave, which will have carrier; bridge gains carrier
4196 check_output ( 'ip link set dev test1 up' )
4197 self
. wait_online ([ 'bridge99:routable' ])
4198 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
4199 elif test
== 'slave-no-carrier' :
4200 # drop slave carrier; bridge loses carrier
4201 check_output ( 'ip link set dev test1 carrier off' )
4202 self
. wait_online ([ 'bridge99:no-carrier:no-carrier' ])
4203 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4204 elif test
== 'slave-carrier' :
4205 # restore slave carrier; bridge gains carrier
4206 check_output ( 'ip link set dev test1 carrier on' )
4207 self
. wait_online ([ 'bridge99:routable' ])
4208 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
4209 elif test
== 'slave-down' :
4210 # bring down slave; bridge loses carrier
4211 check_output ( 'ip link set dev test1 down' )
4212 self
. wait_online ([ 'bridge99:no-carrier:no-carrier' ])
4213 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4215 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bridge99' , env
= env
)
4216 self
. assertRegex ( output
, '10.1.2.3' )
4217 self
. assertRegex ( output
, '10.1.2.1' )
4219 def test_bridge_ignore_carrier_loss ( self
):
4220 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
4221 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
4222 '25-bridge99-ignore-carrier-loss.network' )
4224 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' ])
4226 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
4227 remove_link ( 'test1' , 'dummy98' )
4230 output
= check_output ( 'ip address show bridge99' )
4232 self
. assertRegex ( output
, 'NO-CARRIER' )
4233 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
4234 self
. assertRegex ( output
, 'inet 192.168.0.16/24 scope global secondary bridge99' )
4236 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain ( self
):
4237 copy_network_unit ( '26-bridge.netdev' , '26-bridge-slave-interface-1.network' ,
4238 '25-bridge99-ignore-carrier-loss.network' )
4240 self
. wait_online ([ 'bridge99:no-carrier' ])
4242 for trial
in range ( 4 ):
4243 check_output ( 'ip link add dummy98 type dummy' )
4244 check_output ( 'ip link set dummy98 up' )
4246 remove_link ( 'dummy98' )
4248 self
. wait_online ([ 'bridge99:routable' , 'dummy98:enslaved' ])
4250 output
= check_output ( 'ip address show bridge99' )
4252 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
4254 output
= check_output ( 'ip rule list table 100' )
4256 self
. assertIn ( 'from all to 8.8.8.8 lookup 100' , output
)
4258 class NetworkdSRIOVTests ( unittest
. TestCase
, Utilities
):
4266 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
4267 def test_sriov ( self
):
4268 copy_network_unit ( '25-default.link' , '25-sriov.network' )
4270 call ( 'modprobe netdevsim' )
4272 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4275 with
open ( '/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4279 self
. wait_online ([ 'eni99np1:routable' ])
4281 output
= check_output ( 'ip link show dev eni99np1' )
4283 self
. assertRegex ( output
,
4284 '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 *'
4285 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4286 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4289 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
4290 def test_sriov_udev ( self
):
4291 copy_network_unit ( '25-sriov.link' , '25-sriov-udev.network' )
4293 call ( 'modprobe netdevsim' )
4295 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4299 self
. wait_online ([ 'eni99np1:routable' ])
4301 # the name eni99np1 may be an alternative name.
4302 ifname
= link_resolve ( 'eni99np1' )
4304 output
= check_output ( 'ip link show dev eni99np1' )
4306 self
. assertRegex ( output
,
4307 '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 *'
4308 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4309 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4311 self
. assertNotIn ( 'vf 3' , output
)
4312 self
. assertNotIn ( 'vf 4' , output
)
4314 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4315 f
. write ( '[Link] \n SR-IOVVirtualFunctions=4 \n ' )
4318 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4320 output
= check_output ( 'ip link show dev eni99np1' )
4322 self
. assertRegex ( output
,
4323 '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 *'
4324 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4325 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
4328 self
. assertNotIn ( 'vf 4' , output
)
4330 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4331 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
4334 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4336 output
= check_output ( 'ip link show dev eni99np1' )
4338 self
. assertRegex ( output
,
4339 '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 *'
4340 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4341 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
4344 self
. assertNotIn ( 'vf 4' , output
)
4346 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4347 f
. write ( '[Link] \n SR-IOVVirtualFunctions=2 \n ' )
4350 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4352 output
= check_output ( 'ip link show dev eni99np1' )
4354 self
. assertRegex ( output
,
4355 '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 *'
4356 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off'
4358 self
. assertNotIn ( 'vf 2' , output
)
4359 self
. assertNotIn ( 'vf 3' , output
)
4360 self
. assertNotIn ( 'vf 4' , output
)
4362 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4363 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
4366 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4368 output
= check_output ( 'ip link show dev eni99np1' )
4370 self
. assertRegex ( output
,
4371 '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 *'
4372 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4373 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4375 self
. assertNotIn ( 'vf 3' , output
)
4376 self
. assertNotIn ( 'vf 4' , output
)
4378 class NetworkdLLDPTests ( unittest
. TestCase
, Utilities
):
4386 def test_lldp ( self
):
4387 copy_network_unit ( '23-emit-lldp.network' , '24-lldp.network' , '25-veth.netdev' )
4389 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:degraded' ])
4391 for trial
in range ( 10 ):
4395 output
= check_output (* networkctl_cmd
, 'lldp' , env
= env
)
4397 if re
. search ( r
'veth99 .* veth-peer' , output
):
4402 class NetworkdRATests ( unittest
. TestCase
, Utilities
):
4410 def test_ipv6_prefix_delegation ( self
):
4411 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth.network' )
4413 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4415 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth99' , env
= env
)
4417 self
. assertRegex ( output
, 'fe80::' )
4418 self
. assertRegex ( output
, '2002:da8:1::1' )
4420 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth99' , env
= env
)
4422 self
. assertIn ( 'hogehoge.test' , output
)
4424 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4426 self
. assertRegex ( output
, '2002:da8:1:0' )
4428 self
. check_netlabel ( 'veth99' , '2002:da8:1::/64' )
4429 self
. check_netlabel ( 'veth99' , '2002:da8:2::/64' )
4431 def test_ipv6_token_static ( self
):
4432 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-static.network' )
4434 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4436 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4438 self
. assertRegex ( output
, '2002:da8:1:0:1a:2b:3c:4d' )
4439 self
. assertRegex ( output
, '2002:da8:1:0:fa:de:ca:fe' )
4440 self
. assertRegex ( output
, '2002:da8:2:0:1a:2b:3c:4d' )
4441 self
. assertRegex ( output
, '2002:da8:2:0:fa:de:ca:fe' )
4443 def test_ipv6_token_prefixstable ( self
):
4444 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable.network' )
4446 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4448 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4450 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
4451 self
. assertIn ( '2002:da8:2:0:1034:56ff:fe78:9abc' , output
) # EUI64
4453 def test_ipv6_token_prefixstable_without_address ( self
):
4454 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable-without-address.network' )
4456 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4458 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4460 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
4461 self
. assertIn ( '2002:da8:2:0:f689:561a:8eda:7443' , output
)
4463 def test_router_preference ( self
):
4464 copy_network_unit ( '25-veth-client.netdev' ,
4465 '25-veth-router-high.netdev' ,
4466 '25-veth-router-low.netdev' ,
4468 '25-veth-bridge.network' ,
4469 '25-veth-client.network' ,
4470 '25-veth-router-high.network' ,
4471 '25-veth-router-low.network' ,
4472 '25-bridge99.network' )
4474 self
. wait_online ([ 'client-p:enslaved' ,
4475 'router-high:degraded' , 'router-high-p:enslaved' ,
4476 'router-low:degraded' , 'router-low-p:enslaved' ,
4477 'bridge99:routable' ])
4479 networkctl_reconfigure ( 'client' )
4480 self
. wait_online ([ 'client:routable' ])
4482 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4483 self
. wait_address ( 'client' , '2002:da8:1:98:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4484 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 512' , ipv
= '-6' , timeout_sec
= 10 )
4485 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 2048' , ipv
= '-6' , timeout_sec
= 10 )
4487 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
4489 self
. assertIn ( 'pref high' , output
)
4490 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
4492 self
. assertIn ( 'pref low' , output
)
4494 with
open ( os
. path
. join ( network_unit_dir
, '25-veth-client.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4495 f
. write ( ' \n [Link] \n MACAddress=12:34:56:78:9a:01 \n [IPv6AcceptRA] \n RouteMetric=100:200:300 \n ' )
4498 self
. wait_online ([ 'client:routable' ])
4500 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a01/64' , ipv
= '-6' , timeout_sec
= 10 )
4501 self
. wait_address ( 'client' , '2002:da8:1:98:1034:56ff:fe78:9a01/64' , ipv
= '-6' , timeout_sec
= 10 )
4502 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 100' , ipv
= '-6' , timeout_sec
= 10 )
4503 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 300' , ipv
= '-6' , timeout_sec
= 10 )
4505 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
4507 self
. assertIn ( 'pref high' , output
)
4508 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
4510 self
. assertIn ( 'pref low' , output
)
4512 class NetworkdDHCPServerTests ( unittest
. TestCase
, Utilities
):
4520 def test_dhcp_server ( self
):
4521 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server.network' )
4523 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4525 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4527 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4528 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
4529 self
. assertRegex ( output
, 'DNS: 192.168.5.1 \n *192.168.5.10' )
4530 self
. assertRegex ( output
, 'NTP: 192.168.5.1 \n *192.168.5.11' )
4532 def test_dhcp_server_with_uplink ( self
):
4533 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-downstream.network' ,
4534 '12-dummy.netdev' , '25-dhcp-server-uplink.network' )
4536 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4538 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4540 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4541 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
4542 self
. assertIn ( 'DNS: 192.168.5.1' , output
)
4543 self
. assertIn ( 'NTP: 192.168.5.1' , output
)
4545 def test_emit_router_timezone ( self
):
4546 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-timezone-router.network' , '25-dhcp-server-timezone-router.network' )
4548 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4550 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4552 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4553 self
. assertIn ( 'Gateway: 192.168.5.1' , output
)
4554 self
. assertIn ( 'Time Zone: Europe/Berlin' , output
)
4556 def test_dhcp_server_static_lease ( self
):
4557 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-static-lease.network' , '25-dhcp-server-static-lease.network' )
4559 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4561 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4563 self
. assertIn ( 'Address: 10.1.1.200 (DHCP4 via 10.1.1.1)' , output
)
4564 self
. assertIn ( 'DHCP4 Client ID: 12:34:56:78:9a:bc' , output
)
4566 def test_dhcp_server_static_lease_default_client_id ( self
):
4567 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-static-lease.network' )
4569 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4571 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4573 self
. assertIn ( 'Address: 10.1.1.200 (DHCP4 via 10.1.1.1)' , output
)
4574 self
. assertRegex ( output
, 'DHCP4 Client ID: IAID:[0-9a-z]*/DUID' )
4576 class NetworkdDHCPServerRelayAgentTests ( unittest
. TestCase
, Utilities
):
4584 def test_relay_agent ( self
):
4585 copy_network_unit ( '25-agent-veth-client.netdev' ,
4586 '25-agent-veth-server.netdev' ,
4587 '25-agent-client.network' ,
4588 '25-agent-server.network' ,
4589 '25-agent-client-peer.network' ,
4590 '25-agent-server-peer.network' )
4593 self
. wait_online ([ 'client:routable' ])
4595 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'client' , env
= env
)
4597 self
. assertRegex ( output
, r
'Address: 192.168.5.150 \(DHCP4 via 192.168.5.1\)' )
4599 class NetworkdDHCPClientTests ( unittest
. TestCase
, Utilities
):
4607 def test_dhcp_client_ipv6_only ( self
):
4608 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv6-only.network' )
4611 self
. wait_online ([ 'veth-peer:carrier' ])
4613 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4616 output
= check_output ( 'ip address show dev veth99 scope global' )
4618 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
4619 self
. assertNotIn ( '192.168.5' , output
)
4621 # checking semi-static route
4622 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
4624 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
4626 # Confirm that ipv6 token is not set in the kernel
4627 output
= check_output ( 'ip token show dev veth99' )
4629 self
. assertRegex ( output
, 'token :: dev veth99' )
4631 print ( '## dnsmasq log' )
4632 output
= read_dnsmasq_log_file ()
4634 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
4635 self
. assertNotIn ( 'DHCPADVERTISE(veth-peer)' , output
)
4636 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
4637 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
4638 self
. assertIn ( 'sent size: 0 option: 14 rapid-commit' , output
)
4640 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-ipv6-only.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4641 f
. write ( ' \n [DHCPv6] \n RapidCommit=no \n ' )
4647 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4650 output
= check_output ( 'ip address show dev veth99 scope global' )
4652 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
4653 self
. assertNotIn ( '192.168.5' , output
)
4655 # checking semi-static route
4656 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
4658 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
4660 print ( '## dnsmasq log' )
4661 output
= read_dnsmasq_log_file ()
4663 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
4664 self
. assertIn ( 'DHCPADVERTISE(veth-peer)' , output
)
4665 self
. assertIn ( 'DHCPREQUEST(veth-peer)' , output
)
4666 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
4667 self
. assertNotIn ( 'rapid-commit' , output
)
4669 def test_dhcp_client_ipv4_only ( self
):
4670 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv4-only.network' )
4673 self
. wait_online ([ 'veth-peer:carrier' ])
4674 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7' ,
4675 '--dhcp-option=option:domain-search,example.com' ,
4676 '--dhcp-alternate-port=67,5555' ,
4677 ipv4_range
= '192.168.5.110,192.168.5.119' )
4678 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4679 self
. wait_address ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' )
4681 print ( '## ip address show dev veth99 scope global' )
4682 output
= check_output ( 'ip address show dev veth99 scope global' )
4684 self
. assertIn ( 'mtu 1492' , output
)
4685 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
4686 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' )
4687 self
. assertNotIn ( '2600::' , output
)
4689 print ( '## ip route show table main dev veth99' )
4690 output
= check_output ( 'ip route show table main dev veth99' )
4692 # no DHCP routes assigned to the main table
4693 self
. assertNotIn ( 'proto dhcp' , output
)
4695 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
4696 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
4697 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
4698 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
4700 print ( '## ip route show table 211 dev veth99' )
4701 output
= check_output ( 'ip route show table 211 dev veth99' )
4703 self
. assertRegex ( output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.11[0-9] metric 24' )
4704 self
. assertRegex ( output
, '192.168.5.0/24 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4705 self
. assertRegex ( output
, '192.168.5.1 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4706 self
. assertRegex ( output
, '192.168.5.6 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4707 self
. assertRegex ( output
, '192.168.5.7 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4708 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
4710 print ( '## link state file' )
4711 output
= read_link_state_file ( 'veth99' )
4713 # checking DNS server and Domains
4714 self
. assertIn ( 'DNS=192.168.5.6 192.168.5.7' , output
)
4715 self
. assertIn ( 'DOMAINS=example.com' , output
)
4717 print ( '## dnsmasq log' )
4718 output
= read_dnsmasq_log_file ()
4720 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
4721 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc' , output
)
4722 self
. assertIn ( 'client provides name: test-hostname' , output
)
4723 self
. assertIn ( '26:mtu' , output
)
4725 # change address range, DNS servers, and Domains
4727 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8' ,
4728 '--dhcp-option=option:domain-search,foo.example.com' ,
4729 '--dhcp-alternate-port=67,5555' ,
4730 ipv4_range
= '192.168.5.120,192.168.5.129' ,)
4732 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4733 print ( 'Wait for the DHCP lease to be expired' )
4734 self
. wait_address_dropped ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' , timeout_sec
= 120 )
4735 self
. wait_address ( 'veth99' , r
'inet 192.168.5.12[0-9]*/24' , ipv
= '-4' )
4737 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4739 print ( '## ip address show dev veth99 scope global' )
4740 output
= check_output ( 'ip address show dev veth99 scope global' )
4742 self
. assertIn ( 'mtu 1492' , output
)
4743 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
4744 self
. assertNotIn ( '192.168.5.11' , output
)
4745 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' )
4746 self
. assertNotIn ( '2600::' , output
)
4748 print ( '## ip route show table main dev veth99' )
4749 output
= check_output ( 'ip route show table main dev veth99' )
4751 # no DHCP routes assigned to the main table
4752 self
. assertNotIn ( 'proto dhcp' , output
)
4754 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
4755 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
4756 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
4757 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
4759 print ( '## ip route show table 211 dev veth99' )
4760 output
= check_output ( 'ip route show table 211 dev veth99' )
4762 self
. assertRegex ( output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.12[0-9] metric 24' )
4763 self
. assertRegex ( output
, '192.168.5.0/24 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4764 self
. assertRegex ( output
, '192.168.5.1 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4765 self
. assertNotIn ( '192.168.5.6' , output
)
4766 self
. assertRegex ( output
, '192.168.5.7 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4767 self
. assertRegex ( output
, '192.168.5.8 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4768 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
4770 print ( '## link state file' )
4771 output
= read_link_state_file ( 'veth99' )
4773 # checking DNS server and Domains
4774 self
. assertIn ( 'DNS=192.168.5.1 192.168.5.7 192.168.5.8' , output
)
4775 self
. assertIn ( 'DOMAINS=foo.example.com' , output
)
4777 print ( '## dnsmasq log' )
4778 output
= read_dnsmasq_log_file ()
4780 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
4781 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 192.168.5.11' , output
)
4782 self
. assertIn ( 'client provides name: test-hostname' , output
)
4783 self
. assertIn ( '26:mtu' , output
)
4785 self
. check_netlabel ( 'veth99' , r
'192\.168\.5\.0/24' )
4787 def test_dhcp_client_ipv4_use_routes_gateway ( self
):
4789 for ( routes
, gateway
, dns_and_ntp_routes
, classless
) in itertools
. product ([ True , False ], repeat
= 4 ):
4795 print ( f
'### test_dhcp_client_ipv4_use_routes_gateway(routes= {routes} , gateway= {gateway} , dns_and_ntp_routes= {dns_and_ntp_routes} , classless= {classless} )' )
4796 with self
. subTest ( routes
= routes
, gateway
= gateway
, dns_and_ntp_routes
= dns_and_ntp_routes
, classless
= classless
):
4797 self
._ test
_ dhcp
_ client
_ ipv
4_u se
_ routes
_ gateway
( routes
, gateway
, dns_and_ntp_routes
, classless
)
4799 def _test_dhcp_client_ipv4_use_routes_gateway ( self
, use_routes
, use_gateway
, dns_and_ntp_routes
, classless
):
4800 testunit
= '25-dhcp-client-ipv4-use-routes-use-gateway.network'
4801 testunits
= [ '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , testunit
]
4802 testunits
. append ( f
' {testunit} .d/use-routes- {use_routes} .conf' )
4803 testunits
. append ( f
' {testunit} .d/use-gateway- {use_gateway} .conf' )
4804 testunits
. append ( f
' {testunit} .d/use-dns-and-ntp-routes- {dns_and_ntp_routes} .conf' )
4805 copy_network_unit (* testunits
, copy_dropins
= False )
4808 self
. wait_online ([ 'veth-peer:carrier' ])
4809 additional_options
= [
4810 '--dhcp-option=option:dns-server,192.168.5.10,8.8.8.8' ,
4811 '--dhcp-option=option:ntp-server,192.168.5.11,9.9.9.9' ,
4812 '--dhcp-option=option:static-route,192.168.5.100,192.168.5.2,8.8.8.8,192.168.5.3'
4815 additional_options
+= [
4816 '--dhcp-option=option:classless-static-route,0.0.0.0/0,192.168.5.4,8.0.0.0/8,192.168.5.5'
4818 start_dnsmasq (* additional_options
)
4819 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4821 output
= check_output ( 'ip -4 route show dev veth99' )
4827 self
. assertRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4828 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4829 self
. assertRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4830 self
. assertRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4832 self
. assertRegex ( output
, r
'192.168.5.0/24 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4833 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4834 self
. assertRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4836 self
. assertNotRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4837 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4838 self
. assertNotRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4839 self
. assertNotRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4840 self
. assertNotRegex ( output
, r
'192.168.5.0/24 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4841 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4842 self
. assertNotRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4845 if use_gateway
and ( not classless
or not use_routes
):
4846 self
. assertRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4848 self
. assertNotRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4850 # Check route to gateway
4851 if ( use_gateway
or dns_and_ntp_routes
) and ( not classless
or not use_routes
):
4852 self
. assertRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4854 self
. assertNotRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4856 # Check RoutesToDNS= and RoutesToNTP=
4857 if dns_and_ntp_routes
:
4858 self
. assertRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4859 self
. assertRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4860 if classless
and use_routes
:
4861 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4862 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4864 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4865 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4867 self
. assertNotRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4868 self
. assertNotRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4869 self
. assertNotRegex ( output
, r
'8.8.8.8 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
4870 self
. assertNotRegex ( output
, r
'9.9.9.9 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
4872 # TODO: check json string
4873 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
4875 def test_dhcp_client_settings_anonymize ( self
):
4876 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-anonymize.network' )
4878 self
. wait_online ([ 'veth-peer:carrier' ])
4880 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4882 print ( '## dnsmasq log' )
4883 output
= read_dnsmasq_log_file ()
4885 self
. assertNotIn ( 'VendorClassIdentifier=SusantVendorTest' , output
)
4886 self
. assertNotIn ( 'test-hostname' , output
)
4887 self
. assertNotIn ( '26:mtu' , output
)
4889 def test_dhcp_keep_configuration_dhcp ( self
):
4890 copy_network_unit ( '25-veth.netdev' ,
4891 '25-dhcp-server-veth-peer.network' ,
4892 '25-dhcp-client-keep-configuration-dhcp.network' )
4894 self
. wait_online ([ 'veth-peer:carrier' ])
4896 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4898 output
= check_output ( 'ip address show dev veth99 scope global' )
4900 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4901 'valid_lft forever preferred_lft forever' )
4903 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
4906 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4907 print ( 'Wait for the DHCP lease to be expired' )
4910 # The lease address should be kept after the lease expired
4911 output
= check_output ( 'ip address show dev veth99 scope global' )
4913 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4914 'valid_lft forever preferred_lft forever' )
4918 # The lease address should be kept after networkd stopped
4919 output
= check_output ( 'ip address show dev veth99 scope global' )
4921 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4922 'valid_lft forever preferred_lft forever' )
4924 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-keep-configuration-dhcp.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4925 f
. write ( '[Network] \n DHCP=no \n ' )
4928 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4930 # Still the lease address should be kept after networkd restarted
4931 output
= check_output ( 'ip address show dev veth99 scope global' )
4933 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4934 'valid_lft forever preferred_lft forever' )
4936 def test_dhcp_keep_configuration_dhcp_on_stop ( self
):
4937 copy_network_unit ( '25-veth.netdev' ,
4938 '25-dhcp-server-veth-peer.network' ,
4939 '25-dhcp-client-keep-configuration-dhcp-on-stop.network' )
4941 self
. wait_online ([ 'veth-peer:carrier' ])
4943 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4945 output
= check_output ( 'ip address show dev veth99 scope global' )
4947 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
4952 output
= check_output ( 'ip address show dev veth99 scope global' )
4954 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
4957 self
. wait_online ([ 'veth-peer:routable' ])
4959 output
= check_output ( 'ip address show dev veth99 scope global' )
4961 self
. assertNotIn ( '192.168.5.' , output
)
4963 def test_dhcp_client_reuse_address_as_static ( self
):
4964 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' )
4966 self
. wait_online ([ 'veth-peer:carrier' ])
4968 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4970 # link become 'routable' when at least one protocol provide an valid address.
4971 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
4972 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
4974 output
= check_output ( 'ip address show dev veth99 scope global' )
4975 ipv4_address
= re
. search ( r
'192.168.5.[0-9]*/24' , output
). group ()
4976 ipv6_address
= re
. search ( r
'2600::[0-9a-f:]*/128' , output
). group ()
4977 static_network
= ' \n ' . join ([ '[Match]' , 'Name=veth99' , '[Network]' , 'IPv6AcceptRA=no' , 'Address=' + ipv4_address
, 'Address=' + ipv6_address
])
4978 print ( static_network
)
4980 remove_network_unit ( '25-dhcp-client.network' )
4982 with
open ( os
. path
. join ( network_unit_dir
, '25-static.network' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
4983 f
. write ( static_network
)
4986 self
. wait_online ([ 'veth99:routable' ])
4988 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
4990 self
. assertRegex ( output
, f
'inet {ipv4_address} brd 192.168.5.255 scope global veth99 \n *'
4991 'valid_lft forever preferred_lft forever' )
4993 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
4995 self
. assertRegex ( output
, f
'inet6 {ipv6_address} scope global * \n *'
4996 'valid_lft forever preferred_lft forever' )
4998 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
4999 def test_dhcp_client_vrf ( self
):
5000 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-vrf.network' ,
5001 '25-vrf.netdev' , '25-vrf.network' )
5003 self
. wait_online ([ 'veth-peer:carrier' ])
5005 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'vrf99:carrier' ])
5007 # link become 'routable' when at least one protocol provide an valid address.
5008 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5009 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5011 print ( '## ip -d link show dev vrf99' )
5012 output
= check_output ( 'ip -d link show dev vrf99' )
5014 self
. assertRegex ( output
, 'vrf table 42' )
5016 print ( '## ip address show vrf vrf99' )
5017 output
= check_output ( 'ip address show vrf vrf99' )
5019 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5020 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5021 self
. assertRegex ( output
, 'inet6 .* scope link' )
5023 print ( '## ip address show dev veth99' )
5024 output
= check_output ( 'ip address show dev veth99' )
5026 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5027 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5028 self
. assertRegex ( output
, 'inet6 .* scope link' )
5030 print ( '## ip route show vrf vrf99' )
5031 output
= check_output ( 'ip route show vrf vrf99' )
5033 self
. assertRegex ( output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.' )
5034 self
. assertRegex ( output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5' )
5035 self
. assertRegex ( output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5' )
5037 print ( '## ip route show table main dev veth99' )
5038 output
= check_output ( 'ip route show table main dev veth99' )
5040 self
. assertEqual ( output
, '' )
5042 def test_dhcp_client_gateway_onlink_implicit ( self
):
5043 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
5044 '25-dhcp-client-gateway-onlink-implicit.network' )
5046 self
. wait_online ([ 'veth-peer:carrier' ])
5048 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5050 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
5052 self
. assertRegex ( output
, '192.168.5' )
5054 output
= check_output ( 'ip route list dev veth99 10.0.0.0/8' )
5056 self
. assertRegex ( output
, 'onlink' )
5057 output
= check_output ( 'ip route list dev veth99 192.168.100.0/24' )
5059 self
. assertRegex ( output
, 'onlink' )
5061 def test_dhcp_client_with_ipv4ll ( self
):
5062 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
5063 '25-dhcp-client-with-ipv4ll.network' )
5065 # we need to increase timeout above default, as this will need to wait for
5066 # systemd-networkd to get the dhcpv4 transient failure event
5067 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:routable' ], timeout
= '60s' )
5069 output
= check_output ( 'ip -4 address show dev veth99' )
5071 self
. assertNotIn ( '192.168.5.' , output
)
5072 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
5075 print ( 'Wait for a DHCP lease to be acquired and the IPv4LL address to be dropped' )
5076 self
. wait_address ( 'veth99' , r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic' , ipv
= '-4' )
5077 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' )
5078 self
. wait_online ([ 'veth99:routable' ])
5080 output
= check_output ( 'ip -4 address show dev veth99' )
5082 self
. assertRegex ( output
, r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99' )
5083 self
. assertNotIn ( '169.254.' , output
)
5084 self
. assertNotIn ( 'scope link' , output
)
5087 print ( 'Wait for the DHCP lease to be expired and an IPv4LL address to be acquired' )
5088 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 )
5089 self
. wait_address ( 'veth99' , r
'inet 169\.254\.133\.11/16 metric 2048 brd 169\.254\.255\.255 scope link' , scope
= 'link' , ipv
= '-4' )
5091 output
= check_output ( 'ip -4 address show dev veth99' )
5093 self
. assertNotIn ( '192.168.5.' , output
)
5094 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
5096 def test_dhcp_client_use_dns ( self
):
5097 def check ( self
, ipv4
, ipv6
):
5098 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5099 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5100 f
. write ( '[DHCPv4] \n UseDNS=' )
5101 f
. write ( 'yes' if ipv4
else 'no' )
5102 f
. write ( ' \n [DHCPv6] \n UseDNS=' )
5103 f
. write ( 'yes' if ipv6
else 'no' )
5104 f
. write ( ' \n [IPv6AcceptRA] \n UseDNS=no' )
5107 self
. wait_online ([ 'veth99:routable' ])
5109 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5110 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5111 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5113 # make resolved re-read the link state file
5114 check_output (* resolvectl_cmd
, 'revert' , 'veth99' , env
= env
)
5116 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth99' , env
= env
)
5119 self
. assertIn ( '192.168.5.1' , output
)
5121 self
. assertNotIn ( '192.168.5.1' , output
)
5123 self
. assertIn ( '2600::1' , output
)
5125 self
. assertNotIn ( '2600::1' , output
)
5127 # TODO: check json string
5128 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5130 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5133 self
. wait_online ([ 'veth-peer:carrier' ])
5134 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1' ,
5135 '--dhcp-option=option6:dns-server,[2600::1]' )
5137 check ( self
, True , True )
5138 check ( self
, True , False )
5139 check ( self
, False , True )
5140 check ( self
, False , False )
5142 class NetworkdDHCPPDTests ( unittest
. TestCase
, Utilities
):
5150 def test_dhcp6pd ( self
):
5151 copy_network_unit ( '25-veth.netdev' , '25-dhcp6pd-server.network' , '25-dhcp6pd-upstream.network' ,
5152 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
5153 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
5154 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
5155 '25-dhcp-pd-downstream-dummy97.network' ,
5156 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
5157 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' )
5160 self
. wait_online ([ 'veth-peer:routable' ])
5161 start_isc_dhcpd ( conf_file
= 'isc-dhcpd-dhcp6pd.conf' , ipv
= '-6' )
5162 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5163 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5165 print ( '### ip -6 address show dev veth-peer scope global' )
5166 output
= check_output ( 'ip -6 address show dev veth-peer scope global' )
5168 self
. assertIn ( 'inet6 3ffe:501:ffff:100::1/64 scope global' , output
)
5172 # dummy97: 0x01 (The link will appear later)
5174 # dummy99: auto -> 0x02 (No address assignment)
5179 print ( '### ip -6 address show dev veth99 scope global' )
5180 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5183 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:100::[0-9]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5184 # address in IA_PD (Token=static)
5185 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic' )
5186 # address in IA_PD (Token=eui64)
5187 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic' )
5188 # address in IA_PD (temporary)
5189 # Note that the temporary addresses may appear after the link enters configured state
5190 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' )
5192 print ( '### ip -6 address show dev test1 scope global' )
5193 output
= check_output ( 'ip -6 address show dev test1 scope global' )
5195 # address in IA_PD (Token=static)
5196 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5197 # address in IA_PD (temporary)
5198 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' )
5200 print ( '### ip -6 address show dev dummy98 scope global' )
5201 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5203 # address in IA_PD (Token=static)
5204 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5205 # address in IA_PD (temporary)
5206 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' )
5208 print ( '### ip -6 address show dev dummy99 scope global' )
5209 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5212 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
5214 print ( '### ip -6 address show dev veth97 scope global' )
5215 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
5217 # address in IA_PD (Token=static)
5218 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5219 # address in IA_PD (Token=eui64)
5220 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5221 # address in IA_PD (temporary)
5222 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' )
5224 print ( '### ip -6 address show dev veth97-peer scope global' )
5225 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
5227 # NDisc address (Token=static)
5228 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5229 # NDisc address (Token=eui64)
5230 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5231 # NDisc address (temporary)
5232 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' )
5234 print ( '### ip -6 address show dev veth98 scope global' )
5235 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
5237 # address in IA_PD (Token=static)
5238 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5239 # address in IA_PD (Token=eui64)
5240 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5241 # address in IA_PD (temporary)
5242 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' )
5244 print ( '### ip -6 address show dev veth98-peer scope global' )
5245 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
5247 # NDisc address (Token=static)
5248 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5249 # NDisc address (Token=eui64)
5250 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5251 # NDisc address (temporary)
5252 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' )
5254 print ( '### ip -6 route show type unreachable' )
5255 output
= check_output ( 'ip -6 route show type unreachable' )
5257 self
. assertRegex ( output
, 'unreachable 3ffe:501:ffff:[2-9a-f]00::/56 dev lo proto dhcp' )
5259 print ( '### ip -6 route show dev veth99' )
5260 output
= check_output ( 'ip -6 route show dev veth99' )
5262 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]10::/64 proto kernel metric [0-9]* expires' )
5264 print ( '### ip -6 route show dev test1' )
5265 output
= check_output ( 'ip -6 route show dev test1' )
5267 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5269 print ( '### ip -6 route show dev dummy98' )
5270 output
= check_output ( 'ip -6 route show dev dummy98' )
5272 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5274 print ( '### ip -6 route show dev dummy99' )
5275 output
= check_output ( 'ip -6 route show dev dummy99' )
5277 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
5279 print ( '### ip -6 route show dev veth97' )
5280 output
= check_output ( 'ip -6 route show dev veth97' )
5282 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto kernel metric [0-9]* expires' )
5284 print ( '### ip -6 route show dev veth97-peer' )
5285 output
= check_output ( 'ip -6 route show dev veth97-peer' )
5287 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto ra metric [0-9]* expires' )
5289 print ( '### ip -6 route show dev veth98' )
5290 output
= check_output ( 'ip -6 route show dev veth98' )
5292 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto kernel metric [0-9]* expires' )
5294 print ( '### ip -6 route show dev veth98-peer' )
5295 output
= check_output ( 'ip -6 route show dev veth98-peer' )
5297 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto ra metric [0-9]* expires' )
5299 # Test case for a downstream which appears later
5300 check_output ( 'ip link add dummy97 type dummy' )
5301 self
. wait_online ([ 'dummy97:routable' ])
5303 print ( '### ip -6 address show dev dummy97 scope global' )
5304 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
5306 # address in IA_PD (Token=static)
5307 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5308 # address in IA_PD (temporary)
5309 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' )
5311 print ( '### ip -6 route show dev dummy97' )
5312 output
= check_output ( 'ip -6 route show dev dummy97' )
5314 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]01::/64 proto kernel metric [0-9]* expires' )
5316 # Test case for reconfigure
5317 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
5318 self
. wait_online ([ 'dummy98:routable' , 'dummy99:degraded' ])
5320 print ( '### ip -6 address show dev dummy98 scope global' )
5321 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5323 # address in IA_PD (Token=static)
5324 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5325 # address in IA_PD (temporary)
5326 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' )
5328 print ( '### ip -6 address show dev dummy99 scope global' )
5329 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5332 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
5334 print ( '### ip -6 route show dev dummy98' )
5335 output
= check_output ( 'ip -6 route show dev dummy98' )
5337 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5339 print ( '### ip -6 route show dev dummy99' )
5340 output
= check_output ( 'ip -6 route show dev dummy99' )
5342 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
5344 self
. check_netlabel ( 'dummy98' , '3ffe:501:ffff:[2-9a-f]00::/64' )
5346 def verify_dhcp4_6rd ( self
, tunnel_name
):
5347 print ( '### ip -4 address show dev veth-peer scope global' )
5348 output
= check_output ( 'ip -4 address show dev veth-peer scope global' )
5350 self
. assertIn ( 'inet 10.0.0.1/8 brd 10.255.255.255 scope global veth-peer' , output
)
5354 # dummy97: 0x01 (The link will appear later)
5356 # dummy99: auto -> 0x0[23] (No address assignment)
5357 # 6rd-XXX: auto -> 0x0[23]
5362 print ( '### ip -4 address show dev veth99 scope global' )
5363 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
5365 self
. assertRegex ( output
, 'inet 10.100.100.[0-9]*/8 (metric 1024 |)brd 10.255.255.255 scope global dynamic veth99' )
5367 print ( '### ip -6 address show dev veth99 scope global' )
5368 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5370 # address in IA_PD (Token=static)
5371 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5372 # address in IA_PD (Token=eui64)
5373 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5374 # address in IA_PD (temporary)
5375 # Note that the temporary addresses may appear after the link enters configured state
5376 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' )
5378 print ( '### ip -6 address show dev test1 scope global' )
5379 output
= check_output ( 'ip -6 address show dev test1 scope global' )
5381 # address in IA_PD (Token=static)
5382 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5383 # address in IA_PD (temporary)
5384 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' )
5386 print ( '### ip -6 address show dev dummy98 scope global' )
5387 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5389 # address in IA_PD (Token=static)
5390 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5391 # address in IA_PD (temporary)
5392 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' )
5394 print ( '### ip -6 address show dev dummy99 scope global' )
5395 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5398 self
. assertNotRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+0[23]' )
5400 print ( '### ip -6 address show dev veth97 scope global' )
5401 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
5403 # address in IA_PD (Token=static)
5404 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5405 # address in IA_PD (Token=eui64)
5406 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5407 # address in IA_PD (temporary)
5408 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' )
5410 print ( '### ip -6 address show dev veth97-peer scope global' )
5411 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
5413 # NDisc address (Token=static)
5414 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5415 # NDisc address (Token=eui64)
5416 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5417 # NDisc address (temporary)
5418 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' )
5420 print ( '### ip -6 address show dev veth98 scope global' )
5421 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
5423 # address in IA_PD (Token=static)
5424 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5425 # address in IA_PD (Token=eui64)
5426 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5427 # address in IA_PD (temporary)
5428 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' )
5430 print ( '### ip -6 address show dev veth98-peer scope global' )
5431 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
5433 # NDisc address (Token=static)
5434 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5435 # NDisc address (Token=eui64)
5436 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5437 # NDisc address (temporary)
5438 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' )
5440 print ( '### ip -6 route show type unreachable' )
5441 output
= check_output ( 'ip -6 route show type unreachable' )
5443 self
. assertRegex ( output
, 'unreachable 2001:db8:6464:[0-9a-f]+00::/56 dev lo proto dhcp' )
5445 print ( '### ip -6 route show dev veth99' )
5446 output
= check_output ( 'ip -6 route show dev veth99' )
5448 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+10::/64 proto kernel metric [0-9]* expires' )
5450 print ( '### ip -6 route show dev test1' )
5451 output
= check_output ( 'ip -6 route show dev test1' )
5453 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
5455 print ( '### ip -6 route show dev dummy98' )
5456 output
= check_output ( 'ip -6 route show dev dummy98' )
5458 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
5460 print ( '### ip -6 route show dev dummy99' )
5461 output
= check_output ( 'ip -6 route show dev dummy99' )
5463 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto dhcp metric [0-9]* expires' )
5465 print ( '### ip -6 route show dev veth97' )
5466 output
= check_output ( 'ip -6 route show dev veth97' )
5468 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto kernel metric [0-9]* expires' )
5470 print ( '### ip -6 route show dev veth97-peer' )
5471 output
= check_output ( 'ip -6 route show dev veth97-peer' )
5473 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto ra metric [0-9]* expires' )
5475 print ( '### ip -6 route show dev veth98' )
5476 output
= check_output ( 'ip -6 route show dev veth98' )
5478 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto kernel metric [0-9]* expires' )
5480 print ( '### ip -6 route show dev veth98-peer' )
5481 output
= check_output ( 'ip -6 route show dev veth98-peer' )
5483 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto ra metric [0-9]* expires' )
5485 print ( '### ip -6 address show dev dummy97 scope global' )
5486 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
5488 # address in IA_PD (Token=static)
5489 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5490 # address in IA_PD (temporary)
5491 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' )
5493 print ( '### ip -6 route show dev dummy97' )
5494 output
= check_output ( 'ip -6 route show dev dummy97' )
5496 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+01::/64 proto kernel metric [0-9]* expires' )
5498 print ( f
'### ip -d link show dev {tunnel_name} ' )
5499 output
= check_output ( f
'ip -d link show dev {tunnel_name} ' )
5501 self
. assertIn ( 'link/sit 10.100.100.' , output
)
5502 self
. assertIn ( 'local 10.100.100.' , output
)
5503 self
. assertIn ( 'ttl 64' , output
)
5504 self
. assertIn ( '6rd-prefix 2001:db8::/32' , output
)
5505 self
. assertIn ( '6rd-relay_prefix 10.0.0.0/8' , output
)
5507 print ( f
'### ip -6 address show dev {tunnel_name} ' )
5508 output
= check_output ( f
'ip -6 address show dev {tunnel_name} ' )
5510 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' )
5511 self
. assertRegex ( output
, 'inet6 ::10.100.100.[0-9]+/96 scope global' )
5513 print ( f
'### ip -6 route show dev {tunnel_name} ' )
5514 output
= check_output ( f
'ip -6 route show dev {tunnel_name} ' )
5516 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto kernel metric [0-9]* expires' )
5517 self
. assertRegex ( output
, '::/96 proto kernel metric [0-9]*' )
5519 print ( '### ip -6 route show default' )
5520 output
= check_output ( 'ip -6 route show default' )
5522 self
. assertIn ( 'default' , output
)
5523 self
. assertIn ( f
'via ::10.0.0.1 dev {tunnel_name} ' , output
)
5525 def test_dhcp4_6rd ( self
):
5526 copy_network_unit ( '25-veth.netdev' , '25-dhcp4-6rd-server.network' , '25-dhcp4-6rd-upstream.network' ,
5527 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
5528 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
5529 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
5530 '25-dhcp-pd-downstream-dummy97.network' ,
5531 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
5532 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' ,
5533 '80-6rd-tunnel.network' )
5536 self
. wait_online ([ 'veth-peer:routable' ])
5539 # 6rd-prefix: 2001:db8::/32
5540 # br-addresss: 10.0.0.1
5542 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' ,
5543 ipv4_range
= '10.100.100.100,10.100.100.200' ,
5544 ipv4_router
= '10.0.0.1' )
5545 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5546 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5548 # Test case for a downstream which appears later
5549 check_output ( 'ip link add dummy97 type dummy' )
5550 self
. wait_online ([ 'dummy97:routable' ])
5554 for name
in os
. listdir ( '/sys/class/net/' ):
5555 if name
. startswith ( '6rd-' ):
5559 self
. wait_online ([ f
' {tunnel_name} :routable' ])
5561 self
. verify_dhcp4_6rd ( tunnel_name
)
5563 # Test case for reconfigure
5564 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
5565 self
. wait_online ([ 'dummy98:routable' , 'dummy99:degraded' ])
5567 self
. verify_dhcp4_6rd ( tunnel_name
)
5569 print ( 'Wait for the DHCP lease to be renewed/rebind' )
5572 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy97:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5573 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5575 self
. verify_dhcp4_6rd ( tunnel_name
)
5577 class NetworkdIPv6PrefixTests ( unittest
. TestCase
, Utilities
):
5585 def test_ipv6_route_prefix ( self
):
5586 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client.network' , '25-ipv6ra-prefix.network' ,
5587 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
5590 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
5592 output
= check_output ( 'ip address show dev veth-peer' )
5594 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
5595 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
5596 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
5598 output
= check_output ( 'ip -6 route show dev veth-peer' )
5600 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
5601 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
5602 self
. assertNotIn ( '2001:db8:0:3::/64 proto ra' , output
)
5603 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
5604 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
5605 self
. assertNotIn ( '2001:db2:fff::/64 via ' , output
)
5607 output
= check_output ( 'ip address show dev veth99' )
5609 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
5610 self
. assertIn ( 'inet6 2001:db8:0:2:1a:2b:3c:4d' , output
)
5611 self
. assertIn ( 'inet6 2001:db8:0:2:fa:de:ca:fe' , output
)
5612 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
5614 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth-peer' , env
= env
)
5616 self
. assertRegex ( output
, '2001:db8:1:1::2' )
5618 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth-peer' , env
= env
)
5620 self
. assertIn ( 'example.com' , output
)
5622 # TODO: check json string
5623 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5625 def test_ipv6_route_prefix_deny_list ( self
):
5626 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client-deny-list.network' , '25-ipv6ra-prefix.network' ,
5627 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
5630 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
5632 output
= check_output ( 'ip address show dev veth-peer' )
5634 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
5635 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
5637 output
= check_output ( 'ip -6 route show dev veth-peer' )
5639 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
5640 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
5641 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
5642 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
5644 output
= check_output ( 'ip address show dev veth99' )
5646 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
5647 self
. assertIn ( 'inet6 2001:db8:0:2:' , output
)
5649 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth-peer' , env
= env
)
5651 self
. assertRegex ( output
, '2001:db8:1:1::2' )
5653 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth-peer' , env
= env
)
5655 self
. assertIn ( 'example.com' , output
)
5657 class NetworkdMTUTests ( unittest
. TestCase
, Utilities
):
5665 def check_mtu ( self
, mtu
, ipv6_mtu
= None , reset
= True ):
5671 self
. wait_online ([ 'dummy98:routable' ])
5672 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
5673 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
5675 # test normal restart
5677 self
. wait_online ([ 'dummy98:routable' ])
5678 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
5679 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
5682 self
. reset_check_mtu ( mtu
, ipv6_mtu
)
5684 def reset_check_mtu ( self
, mtu
, ipv6_mtu
= None ):
5685 ''' test setting mtu/ipv6_mtu with interface already up '''
5688 # note - changing the device mtu resets the ipv6 mtu
5689 check_output ( 'ip link set up mtu 1501 dev dummy98' )
5690 check_output ( 'ip link set up mtu 1500 dev dummy98' )
5691 self
. check_link_attr ( 'dummy98' , 'mtu' , '1500' )
5692 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , '1500' )
5694 self
. check_mtu ( mtu
, ipv6_mtu
, reset
= False )
5696 def test_mtu_network ( self
):
5697 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' )
5698 self
. check_mtu ( '1600' )
5700 def test_mtu_netdev ( self
):
5701 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network' , copy_dropins
= False )
5702 # note - MTU set by .netdev happens ONLY at device creation!
5703 self
. check_mtu ( '1600' , reset
= False )
5705 def test_mtu_link ( self
):
5706 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network' , copy_dropins
= False )
5707 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
5708 self
. check_mtu ( '1600' , reset
= False )
5710 def test_ipv6_mtu ( self
):
5711 ''' set ipv6 mtu without setting device mtu '''
5712 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1400.conf' )
5713 self
. check_mtu ( '1500' , '1400' )
5715 def test_ipv6_mtu_toolarge ( self
):
5716 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
5717 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5718 self
. check_mtu ( '1500' , '1500' )
5720 def test_mtu_network_ipv6_mtu ( self
):
5721 ''' set ipv6 mtu and set device mtu via network file '''
5722 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5723 self
. check_mtu ( '1600' , '1550' )
5725 def test_mtu_netdev_ipv6_mtu ( self
):
5726 ''' set ipv6 mtu and set device mtu via netdev file '''
5727 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5728 self
. check_mtu ( '1600' , '1550' , reset
= False )
5730 def test_mtu_link_ipv6_mtu ( self
):
5731 ''' set ipv6 mtu and set device mtu via link file '''
5732 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5733 self
. check_mtu ( '1600' , '1550' , reset
= False )
5736 if __name__
== '__main__' :
5737 parser
= argparse
. ArgumentParser ()
5738 parser
. add_argument ( '--build-dir' , help = 'Path to build dir' , dest
= 'build_dir' )
5739 parser
. add_argument ( '--networkd' , help = 'Path to systemd-networkd' , dest
= 'networkd_bin' )
5740 parser
. add_argument ( '--resolved' , help = 'Path to systemd-resolved' , dest
= 'resolved_bin' )
5741 parser
. add_argument ( '--timesyncd' , help = 'Path to systemd-timesyncd' , dest
= 'timesyncd_bin' )
5742 parser
. add_argument ( '--udevd' , help = 'Path to systemd-udevd' , dest
= 'udevd_bin' )
5743 parser
. add_argument ( '--wait-online' , help = 'Path to systemd-networkd-wait-online' , dest
= 'wait_online_bin' )
5744 parser
. add_argument ( '--networkctl' , help = 'Path to networkctl' , dest
= 'networkctl_bin' )
5745 parser
. add_argument ( '--resolvectl' , help = 'Path to resolvectl' , dest
= 'resolvectl_bin' )
5746 parser
. add_argument ( '--timedatectl' , help = 'Path to timedatectl' , dest
= 'timedatectl_bin' )
5747 parser
. add_argument ( '--udevadm' , help = 'Path to udevadm' , dest
= 'udevadm_bin' )
5748 parser
. add_argument ( '--valgrind' , help = 'Enable valgrind' , dest
= 'use_valgrind' , type = bool , nargs
= '?' , const
= True , default
= use_valgrind
)
5749 parser
. add_argument ( '--debug' , help = 'Generate debugging logs' , dest
= 'enable_debug' , type = bool , nargs
= '?' , const
= True , default
= enable_debug
)
5750 parser
. add_argument ( '--asan-options' , help = 'ASAN options' , dest
= 'asan_options' )
5751 parser
. add_argument ( '--lsan-options' , help = 'LSAN options' , dest
= 'lsan_options' )
5752 parser
. add_argument ( '--ubsan-options' , help = 'UBSAN options' , dest
= 'ubsan_options' )
5753 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
)
5754 ns
, unknown_args
= parser
. parse_known_args ( namespace
= unittest
)
5757 if ns
. networkd_bin
or ns
. resolved_bin
or ns
. timesyncd_bin
or ns
. udevd_bin
or \
5758 ns
. wait_online_bin
or ns
. networkctl_bin
or ns
. resolvectl_bin
or ns
. timedatectl_bin
or ns
. udevadm_bin
:
5759 print ( 'WARNING: --networkd, --resolved, --timesyncd, --udevd, --wait-online, --networkctl, --resolvectl, --timedatectl, or --udevadm options are ignored when --build-dir is specified.' )
5760 networkd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd' )
5761 resolved_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-resolved' )
5762 timesyncd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-timesyncd' )
5763 udevd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-udevd' )
5764 wait_online_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd-wait-online' )
5765 networkctl_bin
= os
. path
. join ( ns
. build_dir
, 'networkctl' )
5766 resolvectl_bin
= os
. path
. join ( ns
. build_dir
, 'resolvectl' )
5767 timedatectl_bin
= os
. path
. join ( ns
. build_dir
, 'timedatectl' )
5768 udevadm_bin
= os
. path
. join ( ns
. build_dir
, 'udevadm' )
5771 networkd_bin
= ns
. networkd_bin
5773 resolved_bin
= ns
. resolved_bin
5774 if ns
. timesyncd_bin
:
5775 timesyncd_bin
= ns
. timesyncd_bin
5777 udevd_bin
= ns
. udevd_bin
5778 if ns
. wait_online_bin
:
5779 wait_online_bin
= ns
. wait_online_bin
5780 if ns
. networkctl_bin
:
5781 networkctl_bin
= ns
. networkctl_bin
5782 if ns
. resolvectl_bin
:
5783 resolvectl_bin
= ns
. resolvectl_bin
5784 if ns
. timedatectl_bin
:
5785 timedatectl_bin
= ns
. timedatectl_bin
5787 udevadm_bin
= ns
. udevadm_bin
5789 use_valgrind
= ns
. use_valgrind
5790 enable_debug
= ns
. enable_debug
5791 asan_options
= ns
. asan_options
5792 lsan_options
= ns
. lsan_options
5793 ubsan_options
= ns
. ubsan_options
5794 with_coverage
= ns
. with_coverage
5797 # Do not forget the trailing space.
5798 valgrind_cmd
= 'valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all '
5800 networkctl_cmd
= valgrind_cmd
. split () + [ networkctl_bin
]
5801 resolvectl_cmd
= valgrind_cmd
. split () + [ resolvectl_bin
]
5802 timedatectl_cmd
= valgrind_cmd
. split () + [ timedatectl_bin
]
5803 udevadm_cmd
= valgrind_cmd
. split () + [ udevadm_bin
]
5804 wait_online_cmd
= valgrind_cmd
. split () + [ wait_online_bin
]
5807 env
. update ({ 'ASAN_OPTIONS' : asan_options
})
5809 env
. update ({ 'LSAN_OPTIONS' : lsan_options
})
5811 env
. update ({ 'UBSAN_OPTIONS' : ubsan_options
})
5813 env
. update ({ 'SYSTEMD_MEMPOOL' : '0' })
5815 wait_online_env
= env
. copy ()
5817 wait_online_env
. update ({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
5819 sys
. argv
[ 1 :] = unknown_args
5820 unittest
. main ( verbosity
= 3 )