]>
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 /root/src/test/test-network/systemd-networkd-tests.py.
24 network_unit_dir
= '/run/systemd/network'
25 networkd_conf_dropin_dir
= '/run/systemd/networkd.conf.d'
26 networkd_ci_temp_dir
= '/run/networkd-ci'
27 udev_rules_dir
= '/run/udev/rules.d'
29 dnsmasq_pid_file
= '/run/networkd-ci/test-dnsmasq.pid'
30 dnsmasq_log_file
= '/run/networkd-ci/test-dnsmasq.log'
31 dnsmasq_lease_file
= '/run/networkd-ci/test-dnsmasq.lease'
33 isc_dhcpd_pid_file
= '/run/networkd-ci/test-isc-dhcpd.pid'
34 isc_dhcpd_lease_file
= '/run/networkd-ci/test-isc-dhcpd.lease'
36 systemd_lib_paths
= [ '/usr/lib/systemd' , '/lib/systemd' ]
37 which_paths
= ':' . join ( systemd_lib_paths
+ os
. getenv ( 'PATH' , os
. defpath
). lstrip ( ':' ). split ( ':' ))
39 networkd_bin
= shutil
. which ( 'systemd-networkd' , path
= which_paths
)
40 resolved_bin
= shutil
. which ( 'systemd-resolved' , path
= which_paths
)
41 timesyncd_bin
= shutil
. which ( 'systemd-timesyncd' , path
= which_paths
)
42 udevd_bin
= shutil
. which ( 'systemd-udevd' , path
= which_paths
)
43 wait_online_bin
= shutil
. which ( 'systemd-networkd-wait-online' , path
= which_paths
)
44 networkctl_bin
= shutil
. which ( 'networkctl' , path
= which_paths
)
45 resolvectl_bin
= shutil
. which ( 'resolvectl' , path
= which_paths
)
46 timedatectl_bin
= shutil
. which ( 'timedatectl' , path
= which_paths
)
47 udevadm_bin
= shutil
. which ( 'udevadm' , path
= which_paths
)
75 saved_ipv4_rules
= None
76 saved_ipv6_rules
= None
80 if os
. path
. exists ( path
):
84 shutil
. rmtree ( path
, ignore_errors
= True )
90 shutil
. copytree ( src
, dst
, copy_function
= shutil
. copy
)
93 os
. makedirs ( path
, exist_ok
= True )
96 pathlib
. Path ( path
). touch ()
98 def check_output (* command
, ** kwargs
):
99 # This checks the result and returns stdout (and stderr) on success.
100 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
101 ret
= subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. PIPE
, stderr
= subprocess
. STDOUT
, ** kwargs
)
102 if ret
. returncode
== 0 :
103 return ret
. stdout
. rstrip ()
104 # When returncode != 0, print stdout and stderr, then trigger CalledProcessError.
106 ret
. check_returncode ()
108 def call (* command
, ** kwargs
):
109 # This returns returncode. stdout and stderr are merged and shown in console
110 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
111 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stderr
= subprocess
. STDOUT
, ** kwargs
). returncode
113 def call_quiet (* command
, ** kwargs
):
114 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
115 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. DEVNULL
, stderr
= subprocess
. DEVNULL
, ** kwargs
). returncode
117 def run (* command
, ** kwargs
):
118 # This returns CompletedProcess instance.
119 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
120 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. PIPE
, stderr
= subprocess
. PIPE
, ** kwargs
)
122 def is_module_available ( module_name
):
123 lsmod_output
= check_output ( 'lsmod' )
124 module_re
= re
. compile ( rf
'^{re.escape(module_name)} \b ' , re
. MULTILINE
)
125 return module_re
. search ( lsmod_output
) or call_quiet ( 'modprobe' , module_name
) == 0
127 def expectedFailureIfModuleIsNotAvailable ( module_name
):
129 return func
if is_module_available ( module_name
) else unittest
. expectedFailure ( func
)
133 def expectedFailureIfERSPANv0IsNotSupported ():
134 # erspan version 0 is supported since f989d546a2d5a9f001f6f8be49d98c10ab9b1897 (v5.8)
136 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' )
137 remove_link ( 'erspan99' )
138 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
142 def expectedFailureIfERSPANv2IsNotSupported ():
143 # erspan version 2 is supported since f551c91de262ba36b20c3ac19538afb4f4507441 (v4.16)
145 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' )
146 remove_link ( 'erspan99' )
147 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
151 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable ():
153 rc
= call_quiet ( 'ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7' )
154 call_quiet ( 'ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7' )
155 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
159 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable ():
161 rc
= call_quiet ( 'ip rule add not from 192.168.100.19 ipproto tcp table 7' )
162 call_quiet ( 'ip rule del not from 192.168.100.19 ipproto tcp table 7' )
163 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
167 def expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable ():
170 if call_quiet ( 'ip rule add from 192.168.100.19 table 7 uidrange 200-300' ) == 0 :
171 ret
= run ( 'ip rule list from 192.168.100.19 table 7' )
172 supported
= ret
. returncode
== 0 and 'uidrange 200-300' in ret
. stdout
173 call_quiet ( 'ip rule del from 192.168.100.19 table 7 uidrange 200-300' )
174 return func
if supported
else unittest
. expectedFailure ( func
)
178 def expectedFailureIfLinkFileFieldIsNotSet ():
180 call_quiet ( 'ip link add name dummy99 type dummy' )
181 ret
= run ( 'udevadm info -w10s /sys/class/net/dummy99' )
182 supported
= ret
. returncode
== 0 and 'E: ID_NET_LINK_FILE=' in ret
. stdout
183 remove_link ( 'dummy99' )
184 return func
if supported
else unittest
. expectedFailure ( func
)
188 def expectedFailureIfNexthopIsNotAvailable ():
190 rc
= call_quiet ( 'ip nexthop list' )
191 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
195 def expectedFailureIfRTA_VIAIsNotSupported ():
197 call_quiet ( 'ip link add dummy98 type dummy' )
198 call_quiet ( 'ip link set up dev dummy98' )
199 call_quiet ( 'ip route add 2001:1234:5:8fff:ff:ff:ff:fe/128 dev dummy98' )
200 rc
= call_quiet ( 'ip route add 10.10.10.10 via inet6 2001:1234:5:8fff:ff:ff:ff:fe dev dummy98' )
201 remove_link ( 'dummy98' )
202 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
206 def expectedFailureIfAlternativeNameIsNotAvailable ():
208 call_quiet ( 'ip link add dummy98 type dummy' )
210 call_quiet ( 'ip link prop add dev dummy98 altname hogehogehogehogehoge' ) == 0 and \
211 call_quiet ( 'ip link show dev hogehogehogehogehoge' ) == 0
212 remove_link ( 'dummy98' )
213 return func
if supported
else unittest
. expectedFailure ( func
)
217 def expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ():
219 def finalize ( func
, supported
):
220 call_quiet ( 'rmmod netdevsim' )
221 return func
if supported
else unittest
. expectedFailure ( func
)
223 call_quiet ( 'rmmod netdevsim' )
224 if call_quiet ( 'modprobe netdevsim' ) != 0 :
225 return finalize ( func
, False )
228 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
231 return finalize ( func
, False )
233 if not os
. path
. exists ( '/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs' ):
234 return finalize ( func
, False )
236 # Also checks if udevd supports .link files, as it seems disabled on CentOS CI (Arch).
237 rc
= call_quiet ( 'udevadm info -w10s /sys/class/net/eni99np1' )
238 return finalize ( func
, rc
== 0 )
243 check_output (* udevadm_cmd
, 'control' , '--reload' )
245 def copy_network_unit (* units
, copy_dropins
= True ):
247 Copy networkd unit files into the testbed.
249 Any networkd unit file type can be specified, as well as drop-in files.
251 By default, all drop-ins for a specified unit file are copied in;
252 to avoid that specify dropins=False.
254 When a drop-in file is specified, its unit file is also copied in automatically.
257 mkdir_p ( network_unit_dir
)
259 if copy_dropins
and os
. path
. exists ( os
. path
. join ( networkd_ci_temp_dir
, unit
+ '.d' )):
260 cp_r ( os
. path
. join ( networkd_ci_temp_dir
, unit
+ '.d' ), os
. path
. join ( network_unit_dir
, unit
+ '.d' ))
262 if unit
. endswith ( '.conf' ):
264 unit
= os
. path
. dirname ( dropin
). rstrip ( '.d' )
265 dropindir
= os
. path
. join ( network_unit_dir
, unit
+ '.d' )
267 cp ( os
. path
. join ( networkd_ci_temp_dir
, dropin
), dropindir
)
269 cp ( os
. path
. join ( networkd_ci_temp_dir
, unit
), network_unit_dir
)
271 if unit
. endswith ( '.link' ):
277 def remove_network_unit (* units
):
279 Remove previously copied unit files from the testbed.
281 Drop-ins will be removed automatically.
285 rm_f ( os
. path
. join ( network_unit_dir
, unit
))
286 rm_rf ( os
. path
. join ( network_unit_dir
, unit
+ '.d' ))
288 if unit
. endswith ( '.link' ) or unit
. endswith ( '.link.d' ):
294 def clear_network_units ():
296 if os
. path
. exists ( network_unit_dir
):
297 units
= os
. listdir ( network_unit_dir
)
299 if unit
. endswith ( '.link' ) or unit
. endswith ( '.link.d' ):
302 rm_rf ( network_unit_dir
)
307 def copy_networkd_conf_dropin (* dropins
):
308 """Copy networkd.conf dropin files into the testbed."""
309 mkdir_p ( networkd_conf_dropin_dir
)
310 for dropin
in dropins
:
311 cp ( os
. path
. join ( networkd_ci_temp_dir
, dropin
), networkd_conf_dropin_dir
)
313 def remove_networkd_conf_dropin (* dropins
):
314 """Remove previously copied networkd.conf dropin files from the testbed."""
315 for dropin
in dropins
:
316 rm_f ( os
. path
. join ( networkd_conf_dropin_dir
, dropin
))
318 def clear_networkd_conf_dropins ():
319 rm_rf ( networkd_conf_dropin_dir
)
321 def copy_udev_rule (* rules
):
322 """Copy udev rules"""
323 mkdir_p ( udev_rules_dir
)
325 cp ( os
. path
. join ( networkd_ci_temp_dir
, rule
), udev_rules_dir
)
327 def remove_udev_rule (* rules
):
328 """Remove previously copied udev rules"""
330 rm_f ( os
. path
. join ( udev_rules_dir
, rule
))
332 def clear_udev_rules ():
333 rm_rf ( udev_rules_dir
)
335 def save_active_units ():
336 for u
in [ 'systemd-networkd.socket' , 'systemd-networkd.service' ,
337 'systemd-resolved.service' , 'systemd-timesyncd.service' ,
338 'firewalld.service' ]:
339 if call ( f
'systemctl is-active --quiet {u} ' ) == 0 :
340 call ( f
'systemctl stop {u} ' )
341 active_units
. append ( u
)
343 def restore_active_units ():
344 if 'systemd-networkd.socket' in active_units
:
345 call ( 'systemctl stop systemd-networkd.socket systemd-networkd.service' )
346 for u
in active_units
:
347 call ( f
'systemctl restart {u} ' )
349 def create_service_dropin ( service
, command
, reload_command
= None , additional_settings
= None ):
353 f
'ExecStart=!! {valgrind_cmd}{command} ' ,
358 f
'ExecReload= {valgrind_cmd}{reload_command} ' ,
361 drop_in
+= [ 'Environment=SYSTEMD_LOG_LEVEL=debug' ]
363 drop_in
+= [ f
'Environment=ASAN_OPTIONS=" {asan_options} "' ]
365 drop_in
+= [ f
'Environment=LSAN_OPTIONS=" {lsan_options} "' ]
367 drop_in
+= [ f
'Environment=UBSAN_OPTIONS=" {ubsan_options} "' ]
368 if asan_options
or lsan_options
or ubsan_options
:
369 drop_in
+= [ 'SystemCallFilter=' ]
370 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
371 drop_in
+= [ 'MemoryDenyWriteExecute=no' ]
374 'Environment=SYSTEMD_MEMPOOL=0' ,
382 if additional_settings
:
383 drop_in
+= additional_settings
385 mkdir_p ( f
'/run/systemd/system/ {service} .service.d' )
386 with
open ( f
'/run/systemd/system/ {service} .service.d/00-override.conf' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
387 f
. write ( ' \n ' . join ( drop_in
))
389 def link_exists ( link
):
390 return os
. path
. exists ( os
. path
. join ( '/sys/class/net' , link
, 'ifindex' ))
392 def remove_link (* links
, protect
= False ):
394 if protect
and link
in protected_links
:
396 if link_exists ( link
):
397 call ( f
'ip link del dev {link} ' )
399 def save_existing_links ():
400 links
= os
. listdir ( '/sys/class/net' )
402 if link_exists ( link
):
403 protected_links
. add ( link
)
405 print ( '### The following links will be protected:' )
406 print ( ', ' . join ( sorted ( list ( protected_links
))))
409 links
= os
. listdir ( '/sys/class/net' )
410 remove_link (* links
, protect
= True )
412 def flush_nexthops ():
413 # Currently, the 'ip nexthop' command does not have 'save' and 'restore'.
414 # Hence, we cannot restore nexthops in a simple way.
415 # Let's assume there is no nexthop used in the system
416 call_quiet ( 'ip nexthop flush' )
419 # pylint: disable=global-statement
421 saved_routes
= check_output ( 'ip route show table all' )
422 print ( '### The following routes will be protected:' )
427 output
= check_output ( 'ip route show table all' )
428 for line
in output
. splitlines ():
429 if line
in saved_routes
:
431 if 'proto kernel' in line
:
433 if ' dev ' in line
and not ' dev lo ' in line
:
437 print ( '### Removing routes that did not exist when the test started.' )
439 call ( f
'ip route del {line} ' )
441 def save_routing_policy_rules ():
442 # pylint: disable=global-statement
443 global saved_ipv4_rules
, saved_ipv6_rules
445 output
= check_output ( f
'ip - {ipv} rule show' )
446 print ( f
'### The following IPv {ipv} routing policy rules will be protected:' )
450 saved_ipv4_rules
= save ( 4 )
451 saved_ipv6_rules
= save ( 6 )
453 def flush_routing_policy_rules ():
454 def flush ( ipv
, saved_rules
):
456 output
= check_output ( f
'ip - {ipv} rule show' )
457 for line
in output
. splitlines ():
458 if line
in saved_rules
:
462 print ( f
'### Removing IPv {ipv} routing policy rules that did not exist when the test started.' )
464 words
= line
. replace ( 'lookup [l3mdev-table]' , 'l3mdev' ). split ()
465 priority
= words
[ 0 ]. rstrip ( ':' )
466 call ( f
'ip - {ipv} rule del priority {priority} ' + ' ' . join ( words
[ 1 :]))
468 flush ( 4 , saved_ipv4_rules
)
469 flush ( 6 , saved_ipv6_rules
)
471 def flush_fou_ports ():
472 ret
= run ( 'ip fou show' )
473 if ret
. returncode
!= 0 :
474 return # fou may not be supported
475 for line
in ret
. stdout
. splitlines ():
476 port
= line
. split ()[ 1 ]
477 call ( f
'ip fou del port {port} ' )
479 def flush_l2tp_tunnels ():
481 ret
= run ( 'ip l2tp show tunnel' )
482 if ret
. returncode
!= 0 :
483 return # l2tp may not be supported
484 for line
in ret
. stdout
. splitlines ():
486 if words
[ 0 ] == 'Tunnel' :
487 tid
= words
[ 1 ]. rstrip ( ',' )
488 call ( f
'ip l2tp del tunnel tunnel_id {tid} ' )
491 # Removing L2TP tunnel is asynchronous and slightly takes a time.
494 r
= run ( f
'ip l2tp show tunnel tunnel_id {tid} ' )
495 if r
. returncode
!= 0 or len ( r
. stdout
. rstrip ()) == 0 :
499 print ( f
'Cannot remove L2TP tunnel {tid} , ignoring.' )
502 global saved_timezone
503 r
= run (* timedatectl_cmd
, 'show' , '--value' , '--property' , 'Timezone' , env
= env
)
504 if r
. returncode
== 0 :
505 saved_timezone
= r
. stdout
. rstrip ()
506 print ( f
'### Saved timezone: {saved_timezone} ' )
508 def restore_timezone ():
510 call (* timedatectl_cmd
, 'set-timezone' , f
' {saved_timezone} ' , env
= env
)
512 def read_link_attr (* args
):
513 with
open ( os
. path
. join ( '/sys/class/net' , * args
), encoding
= 'utf-8' ) as f
:
514 return f
. readline (). strip ()
516 def read_link_state_file ( link
):
517 ifindex
= read_link_attr ( link
, 'ifindex' )
518 path
= os
. path
. join ( '/run/systemd/netif/links' , ifindex
)
519 with
open ( path
, encoding
= 'utf-8' ) as f
:
522 def read_ip_sysctl_attr ( link
, attribute
, ipv
):
523 with
open ( os
. path
. join ( '/proc/sys/net' , ipv
, 'conf' , link
, attribute
), encoding
= 'utf-8' ) as f
:
524 return f
. readline (). strip ()
526 def read_ipv6_sysctl_attr ( link
, attribute
):
527 return read_ip_sysctl_attr ( link
, attribute
, 'ipv6' )
529 def read_ipv4_sysctl_attr ( link
, attribute
):
530 return read_ip_sysctl_attr ( link
, attribute
, 'ipv4' )
532 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' ):
535 f
'--log-facility= {dnsmasq_log_file} ' ,
536 '--log-queries=extra' ,
538 f
'--pid-file= {dnsmasq_pid_file} ' ,
539 '--conf-file=/dev/null' ,
541 f
'--interface= {interface} ' ,
542 f
'--dhcp-leasefile= {dnsmasq_lease_file} ' ,
544 f
'--dhcp-range= {ipv6_range} , {lease_time} ' ,
545 f
'--dhcp-range= {ipv4_range} , {lease_time} ' ,
546 '--dhcp-option=option:mtu,1492' ,
547 f
'--dhcp-option=option:router, {ipv4_router} ' ,
550 ) + additional_options
551 check_output (* command
)
553 def stop_by_pid_file ( pid_file
):
554 if not os
. path
. exists ( pid_file
):
556 with
open ( pid_file
, 'r' , encoding
= 'utf-8' ) as f
:
557 pid
= f
. read (). rstrip ( ' \t\r\n \0' )
558 os
. kill ( int ( pid
), signal
. SIGTERM
)
562 print ( f
"PID {pid} is still alive, waiting..." )
565 if e
. errno
== errno
. ESRCH
:
567 print ( f
"Unexpected exception when waiting for {pid} to die: {e.errno}" )
571 stop_by_pid_file ( dnsmasq_pid_file
)
572 rm_f ( dnsmasq_lease_file
)
573 rm_f ( dnsmasq_log_file
)
575 def read_dnsmasq_log_file ():
576 with
open ( dnsmasq_log_file
, encoding
= 'utf-8' ) as f
:
579 def start_isc_dhcpd ( conf_file
, ipv
, interface
= 'veth-peer' ):
580 conf_file_path
= os
. path
. join ( networkd_ci_temp_dir
, conf_file
)
581 isc_dhcpd_command
= f
'dhcpd {ipv} -cf {conf_file_path} -lf {isc_dhcpd_lease_file} -pf {isc_dhcpd_pid_file} {interface} '
582 touch ( isc_dhcpd_lease_file
)
583 check_output ( isc_dhcpd_command
)
585 def stop_isc_dhcpd ():
586 stop_by_pid_file ( isc_dhcpd_pid_file
)
587 rm_f ( isc_dhcpd_lease_file
)
589 def stop_networkd ( show_logs
= True ):
591 invocation_id
= check_output ( 'systemctl show systemd-networkd.service -p InvocationID --value' )
592 check_output ( 'systemctl stop systemd-networkd.socket' )
593 check_output ( 'systemctl stop systemd-networkd.service' )
595 print ( check_output ( 'journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
))
597 def start_networkd ():
598 check_output ( 'systemctl start systemd-networkd' )
600 def restart_networkd ( show_logs
= True ):
601 stop_networkd ( show_logs
)
604 def networkctl_reconfigure (* links
):
605 check_output (* networkctl_cmd
, 'reconfigure' , * links
, env
= env
)
607 def networkctl_reload ( sleep_time
= 1 ):
608 check_output (* networkctl_cmd
, 'reload' , env
= env
)
609 # 'networkctl reload' asynchronously reconfigure links.
610 # Hence, we need to wait for a short time for link to be in configuring state.
612 time
. sleep ( sleep_time
)
617 def tear_down_common ():
618 # 1. stop DHCP servers
623 call_quiet ( 'rmmod netdevsim' )
624 call_quiet ( 'rmmod sch_teql' )
626 # 3. remove network namespace
627 call_quiet ( 'ip netns del ns99' )
637 clear_network_units ()
638 clear_networkd_conf_dropins ()
643 flush_routing_policy_rules ()
647 rm_rf ( networkd_ci_temp_dir
)
648 cp_r ( os
. path
. join ( os
. path
. dirname ( os
. path
. abspath ( __file__
)), 'conf' ), networkd_ci_temp_dir
)
650 clear_network_units ()
651 clear_networkd_conf_dropins ()
654 copy_udev_rule ( '00-debug-net.rules' )
658 save_existing_links ()
660 save_routing_policy_rules ()
663 create_service_dropin ( 'systemd-networkd' , networkd_bin
,
664 f
' {networkctl_bin} reload' ,
665 [ '[Service]' , 'Restart=no' , '[Unit]' , 'StartLimitIntervalSec=0' ])
666 create_service_dropin ( 'systemd-resolved' , resolved_bin
)
667 create_service_dropin ( 'systemd-timesyncd' , timesyncd_bin
)
669 # TODO: also run udevd with sanitizers, valgrind, or coverage
670 #create_service_dropin('systemd-udevd', udevd_bin,
671 # f'{udevadm_bin} control --reload --timeout 0')
675 f
'ExecStart=!! {udevd_bin} ' ,
677 f
'ExecReload= {udevadm_bin} control --reload --timeout 0' ,
680 mkdir_p ( '/run/systemd/system/systemd-udevd.service.d' )
681 with
open ( '/run/systemd/system/systemd-udevd.service.d/00-override.conf' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
682 f
. write ( ' \n ' . join ( drop_in
))
684 check_output ( 'systemctl daemon-reload' )
685 print ( check_output ( 'systemctl cat systemd-networkd.service' ))
686 print ( check_output ( 'systemctl cat systemd-resolved.service' ))
687 print ( check_output ( 'systemctl cat systemd-timesyncd.service' ))
688 print ( check_output ( 'systemctl cat systemd-udevd.service' ))
689 check_output ( 'systemctl restart systemd-resolved.service' )
690 check_output ( 'systemctl restart systemd-timesyncd.service' )
691 check_output ( 'systemctl restart systemd-udevd.service' )
693 def tearDownModule ():
694 rm_rf ( networkd_ci_temp_dir
)
696 clear_network_units ()
697 clear_networkd_conf_dropins ()
701 rm_rf ( '/run/systemd/system/systemd-networkd.service.d' )
702 rm_rf ( '/run/systemd/system/systemd-resolved.service.d' )
703 rm_rf ( '/run/systemd/system/systemd-timesyncd.service.d' )
704 rm_rf ( '/run/systemd/system/systemd-udevd.service.d' )
705 check_output ( 'systemctl daemon-reload' )
706 check_output ( 'systemctl restart systemd-udevd.service' )
707 restore_active_units ()
710 # pylint: disable=no-member
712 def check_link_exists ( self
, link
, expected
= True ):
714 self
. assertTrue ( link_exists ( link
))
716 self
. assertFalse ( link_exists ( link
))
718 def check_link_attr ( self
, * args
):
719 self
. assertEqual ( read_link_attr (* args
[:- 1 ]), args
[- 1 ])
721 def check_bridge_port_attr ( self
, master
, port
, attribute
, expected
, allow_enoent
= False ):
722 path
= os
. path
. join ( '/sys/devices/virtual/net' , master
, 'lower_' + port
, 'brport' , attribute
)
723 if allow_enoent
and not os
. path
. exists ( path
):
725 with
open ( path
, encoding
= 'utf-8' ) as f
:
726 self
. assertEqual ( f
. readline (). strip (), expected
)
728 def check_ipv4_sysctl_attr ( self
, link
, attribute
, expected
):
729 self
. assertEqual ( read_ipv4_sysctl_attr ( link
, attribute
), expected
)
731 def check_ipv6_sysctl_attr ( self
, link
, attribute
, expected
):
732 self
. assertEqual ( read_ipv6_sysctl_attr ( link
, attribute
), expected
)
734 def wait_links ( self
, * links
, timeout
= 20 , fail_assert
= True ):
735 def links_exist (* links
):
737 if not link_exists ( link
):
741 for iteration
in range ( timeout
+ 1 ):
745 if links_exist (* links
):
748 self
. fail ( 'Timed out waiting for all links to be created: ' + ', ' . join ( list ( links
)))
751 def wait_activated ( self
, link
, state
= 'down' , timeout
= 20 , fail_assert
= True ):
752 # wait for the interface is activated.
753 invocation_id
= check_output ( 'systemctl show systemd-networkd -p InvocationID --value' )
754 needle
= f
' {link} : Bringing link {state} '
756 for iteration
in range ( timeout
+ 1 ):
759 if not link_exists ( link
):
761 output
= check_output ( 'journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
)
762 if needle
in output
and flag
in check_output ( f
'ip link show {link} ' ):
765 self
. fail ( f
'Timed out waiting for {link} activated.' )
768 def wait_operstate ( self
, link
, operstate
= 'degraded' , setup_state
= 'configured' , setup_timeout
= 5 , fail_assert
= True ):
769 """Wait for the link to reach the specified operstate and/or setup state.
771 Specify None or '' for either operstate or setup_state to ignore that state.
772 This will recheck until the state conditions are met or the timeout expires.
774 If the link successfully matches the requested state, this returns True.
775 If this times out waiting for the link to match, the behavior depends on the
776 'fail_assert' parameter; if True, this causes a test assertion failure,
777 otherwise this returns False. The default is to cause assertion failure.
779 Note that this function matches on *exactly* the given operstate and setup_state.
780 To wait for a link to reach *or exceed* a given operstate, use wait_online().
787 for secs
in range ( setup_timeout
+ 1 ):
790 if not link_exists ( link
):
792 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , link
, env
= env
)
793 if re
. search ( rf
'(?m)^\s*State:\s+ {operstate} \s+\( {setup_state} \)\s*$' , output
):
798 self
. fail ( f
'Timed out waiting for {link} to reach state {operstate} / {setup_state} ' )
801 def wait_online ( self
, links_with_operstate
, timeout
= '20s' , bool_any
= False , ipv4
= False , ipv6
= False , setup_state
= 'configured' , setup_timeout
= 5 ):
802 """Wait for the link(s) to reach the specified operstate and/or setup state.
804 This is similar to wait_operstate() but can be used for multiple links,
805 and it also calls systemd-networkd-wait-online to wait for the given operstate.
806 The operstate should be specified in the link name, like 'eth0:degraded'.
807 If just a link name is provided, wait-online's default operstate to wait for is degraded.
809 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
810 'setup_timeout' controls the per-link timeout waiting for the setup_state.
812 Set 'bool_any' to True to wait for any (instead of all) of the given links.
813 If this is set, no setup_state checks are done.
815 Set 'ipv4' or 'ipv6' to True to wait for IPv4 address or IPv6 address, respectively, of each of the given links.
816 This is applied only for the operational state 'degraded' or above.
818 Note that this function waits for the link(s) to reach *or exceed* the given operstate.
819 However, the setup_state, if specified, must be matched *exactly*.
821 This returns if the link(s) reached the requested operstate/setup_state; otherwise it
822 raises CalledProcessError or fails test assertion.
824 args
= wait_online_cmd
+ [ f
'--timeout= {timeout} ' ] + [ f
'--interface= {link} ' for link
in links_with_operstate
]
832 check_output (* args
, env
= wait_online_env
)
833 except subprocess
. CalledProcessError
as e
:
834 # show detailed status on failure
835 for link
in links_with_operstate
:
836 name
= link
. split ( ':' )[ 0 ]
837 if link_exists ( name
):
838 call (* networkctl_cmd
, '-n' , '0' , 'status' , name
, env
= env
)
840 if not bool_any
and setup_state
:
841 for link
in links_with_operstate
:
842 self
. wait_operstate ( link
. split ( ':' )[ 0 ], None , setup_state
, setup_timeout
)
844 def wait_address ( self
, link
, address_regex
, scope
= 'global' , ipv
= '' , timeout_sec
= 100 ):
845 for i
in range ( timeout_sec
):
848 output
= check_output ( f
'ip {ipv} address show dev {link} scope {scope} ' )
849 if re
. search ( address_regex
, output
) and 'tentative' not in output
:
852 self
. assertRegex ( output
, address_regex
)
854 def wait_address_dropped ( self
, link
, address_regex
, scope
= 'global' , ipv
= '' , timeout_sec
= 100 ):
855 for i
in range ( timeout_sec
):
858 output
= check_output ( f
'ip {ipv} address show dev {link} scope {scope} ' )
859 if not re
. search ( address_regex
, output
):
862 self
. assertNotRegex ( output
, address_regex
)
864 class NetworkctlTests ( unittest
. TestCase
, Utilities
):
872 @expectedFailureIfAlternativeNameIsNotAvailable ()
873 def test_altname ( self
):
874 copy_network_unit ( '26-netdev-link-local-addressing-yes.network' , '12-dummy.netdev' , '12-dummy.link' )
876 self
. wait_online ([ 'dummy98:degraded' ])
878 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
879 self
. assertRegex ( output
, 'hogehogehogehogehogehoge' )
881 def test_reconfigure ( self
):
882 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' )
884 self
. wait_online ([ 'dummy98:routable' ])
886 output
= check_output ( 'ip -4 address show dev dummy98' )
888 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
889 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
890 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
892 check_output ( 'ip address del 10.1.2.3/16 dev dummy98' )
893 check_output ( 'ip address del 10.1.2.4/16 dev dummy98' )
894 check_output ( 'ip address del 10.2.2.4/16 dev dummy98' )
896 networkctl_reconfigure ( 'dummy98' )
897 self
. wait_online ([ 'dummy98:routable' ])
899 output
= check_output ( 'ip -4 address show dev dummy98' )
901 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
902 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
903 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
905 remove_network_unit ( '25-address-static.network' )
908 self
. wait_operstate ( 'dummy98' , 'degraded' , setup_state
= 'unmanaged' )
910 output
= check_output ( 'ip -4 address show dev dummy98' )
912 self
. assertNotIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
913 self
. assertNotIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
914 self
. assertNotIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
916 copy_network_unit ( '25-address-static.network' )
918 self
. wait_online ([ 'dummy98:routable' ])
920 output
= check_output ( 'ip -4 address show dev dummy98' )
922 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
923 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
924 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
926 def test_reload ( self
):
929 copy_network_unit ( '11-dummy.netdev' )
931 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'unmanaged' )
933 copy_network_unit ( '11-dummy.network' )
935 self
. wait_online ([ 'test1:degraded' ])
937 remove_network_unit ( '11-dummy.network' )
939 self
. wait_operstate ( 'test1' , 'degraded' , setup_state
= 'unmanaged' )
941 remove_network_unit ( '11-dummy.netdev' )
943 self
. wait_operstate ( 'test1' , 'degraded' , setup_state
= 'unmanaged' )
945 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
947 self
. wait_operstate ( 'test1' , 'degraded' )
950 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
953 self
. wait_online ([ 'test1:degraded' ])
955 output
= check_output (* networkctl_cmd
, 'list' , env
= env
)
956 self
. assertRegex ( output
, '1 lo ' )
957 self
. assertRegex ( output
, 'test1' )
959 output
= check_output (* networkctl_cmd
, 'list' , 'test1' , env
= env
)
960 self
. assertNotRegex ( output
, '1 lo ' )
961 self
. assertRegex ( output
, 'test1' )
963 output
= check_output (* networkctl_cmd
, 'list' , 'te*' , env
= env
)
964 self
. assertNotRegex ( output
, '1 lo ' )
965 self
. assertRegex ( output
, 'test1' )
967 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'te*' , env
= env
)
968 self
. assertNotRegex ( output
, '1: lo ' )
969 self
. assertRegex ( output
, 'test1' )
971 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'tes[a-z][0-9]' , env
= env
)
972 self
. assertNotRegex ( output
, '1: lo ' )
973 self
. assertRegex ( output
, 'test1' )
976 copy_network_unit ( '11-dummy-mtu.netdev' , '11-dummy.network' )
979 self
. wait_online ([ 'test1:degraded' ])
981 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
982 self
. assertRegex ( output
, 'MTU: 1600' )
985 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
987 self
. wait_online ([ 'test1:degraded' ])
989 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
991 self
. assertRegex ( output
, 'Type: ether' )
993 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'lo' , env
= env
)
995 self
. assertRegex ( output
, 'Type: loopback' )
997 @expectedFailureIfLinkFileFieldIsNotSet ()
998 def test_udev_link_file ( self
):
999 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1001 self
. wait_online ([ 'test1:degraded' ])
1003 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
1005 self
. assertRegex ( output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link' )
1006 self
. assertRegex ( output
, r
'Network File: /run/systemd/network/11-dummy.network' )
1008 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'lo' , env
= env
)
1010 self
. assertRegex ( output
, r
'Link File: n/a' )
1011 self
. assertRegex ( output
, r
'Network File: n/a' )
1013 def test_delete_links ( self
):
1014 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' ,
1015 '25-veth.netdev' , '26-netdev-link-local-addressing-yes.network' )
1018 self
. wait_online ([ 'test1:degraded' , 'veth99:degraded' , 'veth-peer:degraded' ])
1020 check_output (* networkctl_cmd
, 'delete' , 'test1' , 'veth99' , env
= env
)
1021 self
. check_link_exists ( 'test1' , expected
= False )
1022 self
. check_link_exists ( 'veth99' , expected
= False )
1023 self
. check_link_exists ( 'veth-peer' , expected
= False )
1025 class NetworkdNetDevTests ( unittest
. TestCase
, Utilities
):
1033 def test_dropin_and_name_conflict ( self
):
1034 copy_network_unit ( '10-dropin-test.netdev' , '15-name-conflict-test.netdev' )
1037 self
. wait_online ([ 'dropin-test:off' ], setup_state
= 'unmanaged' )
1039 output
= check_output ( 'ip link show dropin-test' )
1041 self
. assertRegex ( output
, '00:50:56:c0:00:28' )
1043 def test_match_udev_property ( self
):
1044 copy_network_unit ( '12-dummy.netdev' , '13-not-match-udev-property.network' , '14-match-udev-property.network' )
1046 self
. wait_online ([ 'dummy98:routable' ])
1048 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
1050 self
. assertRegex ( output
, 'Network File: /run/systemd/network/14-match-udev-property' )
1052 def test_wait_online_any ( self
):
1053 copy_network_unit ( '25-bridge.netdev' , '25-bridge.network' , '11-dummy.netdev' , '11-dummy.network' )
1056 self
. wait_online ([ 'bridge99' , 'test1:degraded' ], bool_any
= True )
1058 self
. wait_operstate ( 'bridge99' , '(off|no-carrier)' , setup_state
= 'configuring' )
1059 self
. wait_operstate ( 'test1' , 'degraded' )
1061 @expectedFailureIfModuleIsNotAvailable ( 'bareudp' )
1062 def test_bareudp ( self
):
1063 copy_network_unit ( '25-bareudp.netdev' , '26-netdev-link-local-addressing-yes.network' )
1066 self
. wait_online ([ 'bareudp99:degraded' ])
1068 output
= check_output ( 'ip -d link show bareudp99' )
1070 self
. assertRegex ( output
, 'dstport 1000 ' )
1071 self
. assertRegex ( output
, 'ethertype ip ' )
1073 @expectedFailureIfModuleIsNotAvailable ( 'batman-adv' )
1074 def test_batadv ( self
):
1075 copy_network_unit ( '25-batadv.netdev' , '26-netdev-link-local-addressing-yes.network' )
1078 self
. wait_online ([ 'batadv99:degraded' ])
1080 output
= check_output ( 'ip -d link show batadv99' )
1082 self
. assertRegex ( output
, 'batadv' )
1084 def test_bridge ( self
):
1085 copy_network_unit ( '25-bridge.netdev' , '25-bridge-configure-without-carrier.network' )
1088 self
. wait_online ([ 'bridge99:no-carrier' ])
1090 tick
= os
. sysconf ( 'SC_CLK_TCK' )
1091 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'hello_time' )) / tick
))
1092 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'max_age' )) / tick
))
1093 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'forward_delay' )) / tick
))
1094 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'ageing_time' )) / tick
))
1095 self
. assertEqual ( 9 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'priority' )))
1096 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_querier' )))
1097 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_snooping' )))
1098 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'stp_state' )))
1099 self
. assertEqual ( 3 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_igmp_version' )))
1101 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bridge99' , env
= env
)
1103 self
. assertRegex ( output
, 'Priority: 9' )
1104 self
. assertRegex ( output
, 'STP: yes' )
1105 self
. assertRegex ( output
, 'Multicast IGMP Version: 3' )
1107 output
= check_output ( 'ip -d link show bridge99' )
1109 self
. assertIn ( 'vlan_filtering 1 ' , output
)
1110 self
. assertIn ( 'vlan_protocol 802.1ad ' , output
)
1111 self
. assertIn ( 'vlan_default_pvid 9 ' , output
)
1113 def test_bond ( self
):
1114 copy_network_unit ( '25-bond.netdev' , '25-bond-balanced-tlb.netdev' )
1117 self
. wait_online ([ 'bond99:off' , 'bond98:off' ], setup_state
= 'unmanaged' )
1119 self
. check_link_attr ( 'bond99' , 'bonding' , 'mode' , '802.3ad 4' )
1120 self
. check_link_attr ( 'bond99' , 'bonding' , 'xmit_hash_policy' , 'layer3+4 1' )
1121 self
. check_link_attr ( 'bond99' , 'bonding' , 'miimon' , '1000' )
1122 self
. check_link_attr ( 'bond99' , 'bonding' , 'lacp_rate' , 'fast 1' )
1123 self
. check_link_attr ( 'bond99' , 'bonding' , 'updelay' , '2000' )
1124 self
. check_link_attr ( 'bond99' , 'bonding' , 'downdelay' , '2000' )
1125 self
. check_link_attr ( 'bond99' , 'bonding' , 'resend_igmp' , '4' )
1126 self
. check_link_attr ( 'bond99' , 'bonding' , 'min_links' , '1' )
1127 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_actor_sys_prio' , '1218' )
1128 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_user_port_key' , '811' )
1129 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_actor_system' , '00:11:22:33:44:55' )
1131 self
. check_link_attr ( 'bond98' , 'bonding' , 'mode' , 'balance-tlb 5' )
1132 self
. check_link_attr ( 'bond98' , 'bonding' , 'tlb_dynamic_lb' , '1' )
1134 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bond99' , env
= env
)
1136 self
. assertIn ( 'Mode: 802.3ad' , output
)
1137 self
. assertIn ( 'Miimon: 1s' , output
)
1138 self
. assertIn ( 'Updelay: 2s' , output
)
1139 self
. assertIn ( 'Downdelay: 2s' , output
)
1141 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bond98' , env
= env
)
1143 self
. assertIn ( 'Mode: balance-tlb' , output
)
1145 def test_vlan ( self
):
1146 copy_network_unit ( '21-vlan.netdev' , '11-dummy.netdev' ,
1147 '21-vlan.network' , '21-vlan-test1.network' )
1150 self
. wait_online ([ 'test1:degraded' , 'vlan99:routable' ])
1152 output
= check_output ( 'ip -d link show test1' )
1154 self
. assertRegex ( output
, ' mtu 2000 ' )
1156 output
= check_output ( 'ip -d link show vlan99' )
1158 self
. assertRegex ( output
, ' mtu 2000 ' )
1159 self
. assertRegex ( output
, 'REORDER_HDR' )
1160 self
. assertRegex ( output
, 'LOOSE_BINDING' )
1161 self
. assertRegex ( output
, 'GVRP' )
1162 self
. assertRegex ( output
, 'MVRP' )
1163 self
. assertRegex ( output
, ' id 99 ' )
1165 output
= check_output ( 'ip -4 address show dev test1' )
1167 self
. assertRegex ( output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1' )
1168 self
. assertRegex ( output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1' )
1170 output
= check_output ( 'ip -4 address show dev vlan99' )
1172 self
. assertRegex ( output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99' )
1174 def test_macvtap ( self
):
1176 for mode
in [ 'private' , 'vepa' , 'bridge' , 'passthru' ]:
1182 print ( f
'### test_macvtap(mode= {mode} )' )
1183 with self
. subTest ( mode
= mode
):
1184 copy_network_unit ( '21-macvtap.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1185 '11-dummy.netdev' , '25-macvtap.network' )
1186 with
open ( os
. path
. join ( network_unit_dir
, '21-macvtap.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1187 f
. write ( '[MACVTAP] \n Mode=' + mode
)
1190 self
. wait_online ([ 'macvtap99:degraded' ,
1191 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1193 output
= check_output ( 'ip -d link show macvtap99' )
1195 self
. assertRegex ( output
, 'macvtap mode ' + mode
+ ' ' )
1197 def test_macvlan ( self
):
1199 for mode
in [ 'private' , 'vepa' , 'bridge' , 'passthru' ]:
1205 print ( f
'### test_macvlan(mode= {mode} )' )
1206 with self
. subTest ( mode
= mode
):
1207 copy_network_unit ( '21-macvlan.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1208 '11-dummy.netdev' , '25-macvlan.network' )
1209 with
open ( os
. path
. join ( network_unit_dir
, '21-macvlan.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1210 f
. write ( '[MACVLAN] \n Mode=' + mode
)
1213 self
. wait_online ([ 'macvlan99:degraded' ,
1214 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1216 output
= check_output ( 'ip -d link show test1' )
1218 self
. assertRegex ( output
, ' mtu 2000 ' )
1220 output
= check_output ( 'ip -d link show macvlan99' )
1222 self
. assertRegex ( output
, ' mtu 2000 ' )
1223 self
. assertRegex ( output
, 'macvlan mode ' + mode
+ ' ' )
1225 remove_link ( 'test1' )
1228 check_output ( "ip link add test1 type dummy" )
1229 self
. wait_online ([ 'macvlan99:degraded' ,
1230 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1232 output
= check_output ( 'ip -d link show test1' )
1234 self
. assertRegex ( output
, ' mtu 2000 ' )
1236 output
= check_output ( 'ip -d link show macvlan99' )
1238 self
. assertRegex ( output
, ' mtu 2000 ' )
1239 self
. assertRegex ( output
, 'macvlan mode ' + mode
+ ' ' )
1241 @expectedFailureIfModuleIsNotAvailable ( 'ipvlan' )
1242 def test_ipvlan ( self
):
1244 for mode
, flag
in [[ 'L2' , 'private' ], [ 'L3' , 'vepa' ], [ 'L3S' , 'bridge' ]]:
1250 print ( f
'### test_ipvlan(mode= {mode} , flag= {flag} )' )
1251 with self
. subTest ( mode
= mode
, flag
= flag
):
1252 copy_network_unit ( '25-ipvlan.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1253 '11-dummy.netdev' , '25-ipvlan.network' )
1254 with
open ( os
. path
. join ( network_unit_dir
, '25-ipvlan.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1255 f
. write ( '[IPVLAN] \n Mode=' + mode
+ ' \n Flags=' + flag
)
1258 self
. wait_online ([ 'ipvlan99:degraded' , 'test1:degraded' ])
1260 output
= check_output ( 'ip -d link show ipvlan99' )
1262 self
. assertRegex ( output
, 'ipvlan *mode ' + mode
. lower () + ' ' + flag
)
1264 @expectedFailureIfModuleIsNotAvailable ( 'ipvtap' )
1265 def test_ipvtap ( self
):
1267 for mode
, flag
in [[ 'L2' , 'private' ], [ 'L3' , 'vepa' ], [ 'L3S' , 'bridge' ]]:
1273 print ( f
'### test_ipvtap(mode= {mode} , flag= {flag} )' )
1274 with self
. subTest ( mode
= mode
, flag
= flag
):
1275 copy_network_unit ( '25-ipvtap.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1276 '11-dummy.netdev' , '25-ipvtap.network' )
1277 with
open ( os
. path
. join ( network_unit_dir
, '25-ipvtap.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1278 f
. write ( '[IPVTAP] \n Mode=' + mode
+ ' \n Flags=' + flag
)
1281 self
. wait_online ([ 'ipvtap99:degraded' , 'test1:degraded' ])
1283 output
= check_output ( 'ip -d link show ipvtap99' )
1285 self
. assertRegex ( output
, 'ipvtap *mode ' + mode
. lower () + ' ' + flag
)
1287 def test_veth ( self
):
1288 copy_network_unit ( '25-veth.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1289 '25-veth-mtu.netdev' )
1292 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:degraded' , 'veth-mtu:degraded' , 'veth-mtu-peer:degraded' ])
1294 output
= check_output ( 'ip -d link show veth99' )
1296 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bc' )
1297 output
= check_output ( 'ip -d link show veth-peer' )
1299 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bd' )
1301 output
= check_output ( 'ip -d link show veth-mtu' )
1303 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:be' )
1304 self
. assertRegex ( output
, 'mtu 1800' )
1305 output
= check_output ( 'ip -d link show veth-mtu-peer' )
1307 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bf' )
1308 self
. assertRegex ( output
, 'mtu 1800' )
1310 def test_tuntap ( self
):
1311 copy_network_unit ( '25-tun.netdev' , '25-tap.netdev' )
1314 self
. wait_online ([ 'testtun99:off' , 'testtap99:off' ], setup_state
= 'unmanaged' )
1316 output
= check_output ( 'ip -d link show testtun99' )
1318 # Old ip command does not support IFF_ flags
1319 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1321 output
= check_output ( 'ip -d link show testtap99' )
1323 # Old ip command does not support IFF_ flags
1324 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1326 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
1328 copy_network_unit ( '25-vrf.netdev' , '26-netdev-link-local-addressing-yes.network' )
1331 self
. wait_online ([ 'vrf99:carrier' ])
1333 @expectedFailureIfModuleIsNotAvailable ( 'vcan' )
1334 def test_vcan ( self
):
1335 copy_network_unit ( '25-vcan.netdev' , '26-netdev-link-local-addressing-yes.network' )
1338 self
. wait_online ([ 'vcan99:carrier' ])
1340 @expectedFailureIfModuleIsNotAvailable ( 'vxcan' )
1341 def test_vxcan ( self
):
1342 copy_network_unit ( '25-vxcan.netdev' , '26-netdev-link-local-addressing-yes.network' )
1345 self
. wait_online ([ 'vxcan99:carrier' , 'vxcan-peer:carrier' ])
1347 @expectedFailureIfModuleIsNotAvailable ( 'wireguard' )
1348 def test_wireguard ( self
):
1349 copy_network_unit ( '25-wireguard.netdev' , '25-wireguard.network' ,
1350 '25-wireguard-23-peers.netdev' , '25-wireguard-23-peers.network' ,
1351 '25-wireguard-preshared-key.txt' , '25-wireguard-private-key.txt' ,
1352 '25-wireguard-no-peer.netdev' , '25-wireguard-no-peer.network' )
1354 self
. wait_online ([ 'wg99:routable' , 'wg98:routable' , 'wg97:carrier' ])
1356 output
= check_output ( 'ip -4 address show dev wg99' )
1358 self
. assertIn ( 'inet 192.168.124.1/24 scope global wg99' , output
)
1360 output
= check_output ( 'ip -4 address show dev wg99' )
1362 self
. assertIn ( 'inet 169.254.11.1/24 scope link wg99' , output
)
1364 output
= check_output ( 'ip -6 address show dev wg99' )
1366 self
. assertIn ( 'inet6 fe80::1/64 scope link' , output
)
1368 output
= check_output ( 'ip -4 address show dev wg98' )
1370 self
. assertIn ( 'inet 192.168.123.123/24 scope global wg98' , output
)
1372 output
= check_output ( 'ip -6 address show dev wg98' )
1374 self
. assertIn ( 'inet6 fd8d:4d6d:3ccb:500::1/64 scope global' , output
)
1376 output
= check_output ( 'ip -4 route show dev wg99 table 1234' )
1378 self
. assertIn ( '192.168.26.0/24 proto static metric 123' , output
)
1380 output
= check_output ( 'ip -6 route show dev wg99 table 1234' )
1382 self
. assertIn ( 'fd31:bf08:57cb::/48 proto static metric 123 pref medium' , output
)
1384 output
= check_output ( 'ip -6 route show dev wg98 table 1234' )
1386 self
. assertIn ( 'fd8d:4d6d:3ccb:500:c79:2339:edce:ece1 proto static metric 123 pref medium' , output
)
1387 self
. assertIn ( 'fd8d:4d6d:3ccb:500:1dbf:ca8a:32d3:dd81 proto static metric 123 pref medium' , output
)
1388 self
. assertIn ( 'fd8d:4d6d:3ccb:500:1e54:1415:35d0:a47c proto static metric 123 pref medium' , output
)
1389 self
. assertIn ( 'fd8d:4d6d:3ccb:500:270d:b5dd:4a3f:8909 proto static metric 123 pref medium' , output
)
1390 self
. assertIn ( 'fd8d:4d6d:3ccb:500:5660:679d:3532:94d8 proto static metric 123 pref medium' , output
)
1391 self
. assertIn ( 'fd8d:4d6d:3ccb:500:6825:573f:30f3:9472 proto static metric 123 pref medium' , output
)
1392 self
. assertIn ( 'fd8d:4d6d:3ccb:500:6f2e:6888:c6fd:dfb9 proto static metric 123 pref medium' , output
)
1393 self
. assertIn ( 'fd8d:4d6d:3ccb:500:8d4d:bab:7280:a09a proto static metric 123 pref medium' , output
)
1394 self
. assertIn ( 'fd8d:4d6d:3ccb:500:900c:d437:ec27:8822 proto static metric 123 pref medium' , output
)
1395 self
. assertIn ( 'fd8d:4d6d:3ccb:500:9742:9931:5217:18d5 proto static metric 123 pref medium' , output
)
1396 self
. assertIn ( 'fd8d:4d6d:3ccb:500:9c11:d820:2e96:9be0 proto static metric 123 pref medium' , output
)
1397 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a072:80da:de4f:add1 proto static metric 123 pref medium' , output
)
1398 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a3f3:df38:19b0:721 proto static metric 123 pref medium' , output
)
1399 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a94b:cd6a:a32d:90e6 proto static metric 123 pref medium' , output
)
1400 self
. assertIn ( 'fd8d:4d6d:3ccb:500:b39c:9cdc:755a:ead3 proto static metric 123 pref medium' , output
)
1401 self
. assertIn ( 'fd8d:4d6d:3ccb:500:b684:4f81:2e3e:132e proto static metric 123 pref medium' , output
)
1402 self
. assertIn ( 'fd8d:4d6d:3ccb:500:bad5:495d:8e9c:3427 proto static metric 123 pref medium' , output
)
1403 self
. assertIn ( 'fd8d:4d6d:3ccb:500:bfe5:c3c3:5d77:fcb proto static metric 123 pref medium' , output
)
1404 self
. assertIn ( 'fd8d:4d6d:3ccb:500:c624:6bf7:4c09:3b59 proto static metric 123 pref medium' , output
)
1405 self
. assertIn ( 'fd8d:4d6d:3ccb:500:d4f9:5dc:9296:a1a proto static metric 123 pref medium' , output
)
1406 self
. assertIn ( 'fd8d:4d6d:3ccb:500:dcdd:d33b:90c9:6088 proto static metric 123 pref medium' , output
)
1407 self
. assertIn ( 'fd8d:4d6d:3ccb:500:e2e1:ae15:103f:f376 proto static metric 123 pref medium' , output
)
1408 self
. assertIn ( 'fd8d:4d6d:3ccb:500:f349:c4f0:10c1:6b4 proto static metric 123 pref medium' , output
)
1409 self
. assertIn ( 'fd8d:4d6d:3ccb:c79:2339:edce::/96 proto static metric 123 pref medium' , output
)
1410 self
. assertIn ( 'fd8d:4d6d:3ccb:1dbf:ca8a:32d3::/96 proto static metric 123 pref medium' , output
)
1411 self
. assertIn ( 'fd8d:4d6d:3ccb:1e54:1415:35d0::/96 proto static metric 123 pref medium' , output
)
1412 self
. assertIn ( 'fd8d:4d6d:3ccb:270d:b5dd:4a3f::/96 proto static metric 123 pref medium' , output
)
1413 self
. assertIn ( 'fd8d:4d6d:3ccb:5660:679d:3532::/96 proto static metric 123 pref medium' , output
)
1414 self
. assertIn ( 'fd8d:4d6d:3ccb:6825:573f:30f3::/96 proto static metric 123 pref medium' , output
)
1415 self
. assertIn ( 'fd8d:4d6d:3ccb:6f2e:6888:c6fd::/96 proto static metric 123 pref medium' , output
)
1416 self
. assertIn ( 'fd8d:4d6d:3ccb:8d4d:bab:7280::/96 proto static metric 123 pref medium' , output
)
1417 self
. assertIn ( 'fd8d:4d6d:3ccb:900c:d437:ec27::/96 proto static metric 123 pref medium' , output
)
1418 self
. assertIn ( 'fd8d:4d6d:3ccb:9742:9931:5217::/96 proto static metric 123 pref medium' , output
)
1419 self
. assertIn ( 'fd8d:4d6d:3ccb:9c11:d820:2e96::/96 proto static metric 123 pref medium' , output
)
1420 self
. assertIn ( 'fd8d:4d6d:3ccb:a072:80da:de4f::/96 proto static metric 123 pref medium' , output
)
1421 self
. assertIn ( 'fd8d:4d6d:3ccb:a3f3:df38:19b0::/96 proto static metric 123 pref medium' , output
)
1422 self
. assertIn ( 'fd8d:4d6d:3ccb:a94b:cd6a:a32d::/96 proto static metric 123 pref medium' , output
)
1423 self
. assertIn ( 'fd8d:4d6d:3ccb:b39c:9cdc:755a::/96 proto static metric 123 pref medium' , output
)
1424 self
. assertIn ( 'fd8d:4d6d:3ccb:b684:4f81:2e3e::/96 proto static metric 123 pref medium' , output
)
1425 self
. assertIn ( 'fd8d:4d6d:3ccb:bad5:495d:8e9c::/96 proto static metric 123 pref medium' , output
)
1426 self
. assertIn ( 'fd8d:4d6d:3ccb:bfe5:c3c3:5d77::/96 proto static metric 123 pref medium' , output
)
1427 self
. assertIn ( 'fd8d:4d6d:3ccb:c624:6bf7:4c09::/96 proto static metric 123 pref medium' , output
)
1428 self
. assertIn ( 'fd8d:4d6d:3ccb:d4f9:5dc:9296::/96 proto static metric 123 pref medium' , output
)
1429 self
. assertIn ( 'fd8d:4d6d:3ccb:dcdd:d33b:90c9::/96 proto static metric 123 pref medium' , output
)
1430 self
. assertIn ( 'fd8d:4d6d:3ccb:e2e1:ae15:103f::/96 proto static metric 123 pref medium' , output
)
1431 self
. assertIn ( 'fd8d:4d6d:3ccb:f349:c4f0:10c1::/96 proto static metric 123 pref medium' , output
)
1433 if shutil
. which ( 'wg' ):
1436 output
= check_output ( 'wg show wg99 listen-port' )
1437 self
. assertEqual ( output
, '51820' )
1438 output
= check_output ( 'wg show wg99 fwmark' )
1439 self
. assertEqual ( output
, '0x4d2' )
1440 output
= check_output ( 'wg show wg99 private-key' )
1441 self
. assertEqual ( output
, 'EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=' )
1442 output
= check_output ( 'wg show wg99 allowed-ips' )
1443 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t 192.168.124.3/32' , output
)
1444 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t 192.168.124.2/32' , output
)
1445 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t fdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128' , output
)
1446 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 192.168.26.0/24 fd31:bf08:57cb::/48' , output
)
1447 output
= check_output ( 'wg show wg99 persistent-keepalive' )
1448 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t off' , output
)
1449 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t off' , output
)
1450 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t off' , output
)
1451 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 20' , output
)
1452 output
= check_output ( 'wg show wg99 endpoints' )
1453 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t (none)' , output
)
1454 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t (none)' , output
)
1455 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t (none)' , output
)
1456 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 192.168.27.3:51820' , output
)
1457 output
= check_output ( 'wg show wg99 preshared-keys' )
1458 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t 6Fsg8XN0DE6aPQgAX4r2oazEYJOGqyHUz3QRH/jCB+I=' , output
)
1459 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t it7nd33chCT/tKT2ZZWfYyp43Zs+6oif72hexnSNMqA=' , output
)
1460 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=' , output
)
1461 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=' , output
)
1463 output
= check_output ( 'wg show wg98 private-key' )
1464 self
. assertEqual ( output
, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr+WHtZLZ90FU=' )
1466 output
= check_output ( 'wg show wg97 listen-port' )
1467 self
. assertEqual ( output
, '51821' )
1468 output
= check_output ( 'wg show wg97 fwmark' )
1469 self
. assertEqual ( output
, '0x4d3' )
1471 def test_geneve ( self
):
1472 copy_network_unit ( '25-geneve.netdev' , '26-netdev-link-local-addressing-yes.network' )
1475 self
. wait_online ([ 'geneve99:degraded' ])
1477 output
= check_output ( 'ip -d link show geneve99' )
1479 self
. assertRegex ( output
, '192.168.22.1' )
1480 self
. assertRegex ( output
, '6082' )
1481 self
. assertRegex ( output
, 'udpcsum' )
1482 self
. assertRegex ( output
, 'udp6zerocsumrx' )
1484 def test_ipip_tunnel ( self
):
1485 copy_network_unit ( '12-dummy.netdev' , '25-ipip.network' ,
1486 '25-ipip-tunnel.netdev' , '25-tunnel.network' ,
1487 '25-ipip-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1488 '25-ipip-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1489 '25-ipip-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1491 self
. wait_online ([ 'ipiptun99:routable' , 'ipiptun98:routable' , 'ipiptun97:routable' , 'ipiptun96:routable' , 'dummy98:degraded' ])
1493 output
= check_output ( 'ip -d link show ipiptun99' )
1495 self
. assertRegex ( output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98' )
1496 output
= check_output ( 'ip -d link show ipiptun98' )
1498 self
. assertRegex ( output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98' )
1499 output
= check_output ( 'ip -d link show ipiptun97' )
1501 self
. assertRegex ( output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98' )
1502 output
= check_output ( 'ip -d link show ipiptun96' )
1504 self
. assertRegex ( output
, 'ipip (ipip )?remote any local any dev dummy98' )
1506 def test_gre_tunnel ( self
):
1507 copy_network_unit ( '12-dummy.netdev' , '25-gretun.network' ,
1508 '25-gre-tunnel.netdev' , '25-tunnel.network' ,
1509 '25-gre-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1510 '25-gre-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1511 '25-gre-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1513 self
. wait_online ([ 'gretun99:routable' , 'gretun98:routable' , 'gretun97:routable' , 'gretun96:routable' , 'dummy98:degraded' ])
1515 output
= check_output ( 'ip -d link show gretun99' )
1517 self
. assertRegex ( output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1518 self
. assertRegex ( output
, 'ikey 1.2.3.103' )
1519 self
. assertRegex ( output
, 'okey 1.2.4.103' )
1520 self
. assertRegex ( output
, 'iseq' )
1521 self
. assertRegex ( output
, 'oseq' )
1522 output
= check_output ( 'ip -d link show gretun98' )
1524 self
. assertRegex ( output
, 'gre remote 10.65.223.239 local any dev dummy98' )
1525 self
. assertRegex ( output
, 'ikey 0.0.0.104' )
1526 self
. assertRegex ( output
, 'okey 0.0.0.104' )
1527 self
. assertNotRegex ( output
, 'iseq' )
1528 self
. assertNotRegex ( output
, 'oseq' )
1529 output
= check_output ( 'ip -d link show gretun97' )
1531 self
. assertRegex ( output
, 'gre remote any local 10.65.223.238 dev dummy98' )
1532 self
. assertRegex ( output
, 'ikey 0.0.0.105' )
1533 self
. assertRegex ( output
, 'okey 0.0.0.105' )
1534 self
. assertNotRegex ( output
, 'iseq' )
1535 self
. assertNotRegex ( output
, 'oseq' )
1536 output
= check_output ( 'ip -d link show gretun96' )
1538 self
. assertRegex ( output
, 'gre remote any local any dev dummy98' )
1539 self
. assertRegex ( output
, 'ikey 0.0.0.106' )
1540 self
. assertRegex ( output
, 'okey 0.0.0.106' )
1541 self
. assertNotRegex ( output
, 'iseq' )
1542 self
. assertNotRegex ( output
, 'oseq' )
1544 def test_ip6gre_tunnel ( self
):
1545 copy_network_unit ( '12-dummy.netdev' , '25-ip6gretun.network' ,
1546 '25-ip6gre-tunnel.netdev' , '25-tunnel.network' ,
1547 '25-ip6gre-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1548 '25-ip6gre-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1549 '25-ip6gre-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1552 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1554 self
. wait_links ( 'dummy98' , 'ip6gretun99' , 'ip6gretun98' , 'ip6gretun97' , 'ip6gretun96' )
1556 output
= check_output ( 'ip -d link show ip6gretun99' )
1558 self
. assertRegex ( output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1559 output
= check_output ( 'ip -d link show ip6gretun98' )
1561 self
. assertRegex ( output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98' )
1562 output
= check_output ( 'ip -d link show ip6gretun97' )
1564 self
. assertRegex ( output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98' )
1565 output
= check_output ( 'ip -d link show ip6gretun96' )
1567 self
. assertRegex ( output
, 'ip6gre remote any local any dev dummy98' )
1569 def test_gretap_tunnel ( self
):
1570 copy_network_unit ( '12-dummy.netdev' , '25-gretap.network' ,
1571 '25-gretap-tunnel.netdev' , '25-tunnel.network' ,
1572 '25-gretap-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1574 self
. wait_online ([ 'gretap99:routable' , 'gretap98:routable' , 'dummy98:degraded' ])
1576 output
= check_output ( 'ip -d link show gretap99' )
1578 self
. assertRegex ( output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1579 self
. assertRegex ( output
, 'ikey 0.0.0.106' )
1580 self
. assertRegex ( output
, 'okey 0.0.0.106' )
1581 self
. assertRegex ( output
, 'iseq' )
1582 self
. assertRegex ( output
, 'oseq' )
1583 output
= check_output ( 'ip -d link show gretap98' )
1585 self
. assertRegex ( output
, 'gretap remote 10.65.223.239 local any dev dummy98' )
1586 self
. assertRegex ( output
, 'ikey 0.0.0.107' )
1587 self
. assertRegex ( output
, 'okey 0.0.0.107' )
1588 self
. assertRegex ( output
, 'iseq' )
1589 self
. assertRegex ( output
, 'oseq' )
1591 def test_ip6gretap_tunnel ( self
):
1592 copy_network_unit ( '12-dummy.netdev' , '25-ip6gretap.network' ,
1593 '25-ip6gretap-tunnel.netdev' , '25-tunnel.network' ,
1594 '25-ip6gretap-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1596 self
. wait_online ([ 'ip6gretap99:routable' , 'ip6gretap98:routable' , 'dummy98:degraded' ])
1598 output
= check_output ( 'ip -d link show ip6gretap99' )
1600 self
. assertRegex ( output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1601 output
= check_output ( 'ip -d link show ip6gretap98' )
1603 self
. assertRegex ( output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98' )
1605 def test_vti_tunnel ( self
):
1606 copy_network_unit ( '12-dummy.netdev' , '25-vti.network' ,
1607 '25-vti-tunnel.netdev' , '25-tunnel.network' ,
1608 '25-vti-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1609 '25-vti-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1610 '25-vti-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1612 self
. wait_online ([ 'vtitun99:routable' , 'vtitun98:routable' , 'vtitun97:routable' , 'vtitun96:routable' , 'dummy98:degraded' ])
1614 output
= check_output ( 'ip -d link show vtitun99' )
1616 self
. assertRegex ( output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1617 output
= check_output ( 'ip -d link show vtitun98' )
1619 self
. assertRegex ( output
, 'vti remote 10.65.223.239 local any dev dummy98' )
1620 output
= check_output ( 'ip -d link show vtitun97' )
1622 self
. assertRegex ( output
, 'vti remote any local 10.65.223.238 dev dummy98' )
1623 output
= check_output ( 'ip -d link show vtitun96' )
1625 self
. assertRegex ( output
, 'vti remote any local any dev dummy98' )
1627 def test_vti6_tunnel ( self
):
1628 copy_network_unit ( '12-dummy.netdev' , '25-vti6.network' ,
1629 '25-vti6-tunnel.netdev' , '25-tunnel.network' ,
1630 '25-vti6-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1631 '25-vti6-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' )
1633 self
. wait_online ([ 'vti6tun99:routable' , 'vti6tun98:routable' , 'vti6tun97:routable' , 'dummy98:degraded' ])
1635 output
= check_output ( 'ip -d link show vti6tun99' )
1637 self
. assertRegex ( output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1638 output
= check_output ( 'ip -d link show vti6tun98' )
1640 self
. assertRegex ( output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98' )
1641 output
= check_output ( 'ip -d link show vti6tun97' )
1643 self
. assertRegex ( output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98' )
1645 def test_ip6tnl_tunnel ( self
):
1646 copy_network_unit ( '12-dummy.netdev' , '25-ip6tnl.network' ,
1647 '25-ip6tnl-tunnel.netdev' , '25-tunnel.network' ,
1648 '25-ip6tnl-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1649 '25-ip6tnl-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1650 '25-veth.netdev' , '25-ip6tnl-slaac.network' , '25-ipv6-prefix.network' ,
1651 '25-ip6tnl-tunnel-local-slaac.netdev' , '25-ip6tnl-tunnel-local-slaac.network' ,
1652 '25-ip6tnl-tunnel-external.netdev' , '26-netdev-link-local-addressing-yes.network' )
1654 self
. wait_online ([ 'ip6tnl99:routable' , 'ip6tnl98:routable' , 'ip6tnl97:routable' ,
1655 'ip6tnl-slaac:degraded' , 'ip6tnl-external:degraded' ,
1656 'dummy98:degraded' , 'veth99:routable' , 'veth-peer:degraded' ])
1658 output
= check_output ( 'ip -d link show ip6tnl99' )
1660 self
. assertIn ( 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' , output
)
1661 output
= check_output ( 'ip -d link show ip6tnl98' )
1663 self
. assertRegex ( output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98' )
1664 output
= check_output ( 'ip -d link show ip6tnl97' )
1666 self
. assertRegex ( output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98' )
1667 output
= check_output ( 'ip -d link show ip6tnl-external' )
1669 self
. assertIn ( 'ip6tnl-external@NONE:' , output
)
1670 self
. assertIn ( 'ip6tnl external ' , output
)
1671 output
= check_output ( 'ip -d link show ip6tnl-slaac' )
1673 self
. assertIn ( 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99' , output
)
1675 output
= check_output ( 'ip -6 address show veth99' )
1677 self
. assertIn ( 'inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic' , output
)
1679 output
= check_output ( 'ip -4 route show default' )
1681 self
. assertIn ( 'default dev ip6tnl-slaac proto static' , output
)
1683 def test_sit_tunnel ( self
):
1684 copy_network_unit ( '12-dummy.netdev' , '25-sit.network' ,
1685 '25-sit-tunnel.netdev' , '25-tunnel.network' ,
1686 '25-sit-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1687 '25-sit-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1688 '25-sit-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1690 self
. wait_online ([ 'sittun99:routable' , 'sittun98:routable' , 'sittun97:routable' , 'sittun96:routable' , 'dummy98:degraded' ])
1692 output
= check_output ( 'ip -d link show sittun99' )
1694 self
. assertRegex ( output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98" )
1695 output
= check_output ( 'ip -d link show sittun98' )
1697 self
. assertRegex ( output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98" )
1698 output
= check_output ( 'ip -d link show sittun97' )
1700 self
. assertRegex ( output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98" )
1701 output
= check_output ( 'ip -d link show sittun96' )
1703 self
. assertRegex ( output
, "sit (ip6ip )?remote any local any dev dummy98" )
1705 def test_isatap_tunnel ( self
):
1706 copy_network_unit ( '12-dummy.netdev' , '25-isatap.network' ,
1707 '25-isatap-tunnel.netdev' , '25-tunnel.network' )
1709 self
. wait_online ([ 'isataptun99:routable' , 'dummy98:degraded' ])
1711 output
= check_output ( 'ip -d link show isataptun99' )
1713 self
. assertRegex ( output
, "isatap " )
1715 def test_6rd_tunnel ( self
):
1716 copy_network_unit ( '12-dummy.netdev' , '25-6rd.network' ,
1717 '25-6rd-tunnel.netdev' , '25-tunnel.network' )
1719 self
. wait_online ([ 'sittun99:routable' , 'dummy98:degraded' ])
1721 output
= check_output ( 'ip -d link show sittun99' )
1723 self
. assertRegex ( output
, '6rd-prefix 2602::/24' )
1725 @expectedFailureIfERSPANv0IsNotSupported ()
1726 def test_erspan_tunnel_v0 ( self
):
1727 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
1728 '25-erspan0-tunnel.netdev' , '25-tunnel.network' ,
1729 '25-erspan0-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1731 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
1733 output
= check_output ( 'ip -d link show erspan99' )
1735 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
1736 self
. assertIn ( 'erspan_ver 0' , output
)
1737 self
. assertNotIn ( 'erspan_index 123' , output
)
1738 self
. assertNotIn ( 'erspan_dir ingress' , output
)
1739 self
. assertNotIn ( 'erspan_hwid 1f' , output
)
1740 self
. assertIn ( 'ikey 0.0.0.101' , output
)
1741 self
. assertIn ( 'iseq' , output
)
1742 output
= check_output ( 'ip -d link show erspan98' )
1744 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
1745 self
. assertIn ( 'erspan_ver 0' , output
)
1746 self
. assertNotIn ( 'erspan_index 124' , output
)
1747 self
. assertNotIn ( 'erspan_dir egress' , output
)
1748 self
. assertNotIn ( 'erspan_hwid 2f' , output
)
1749 self
. assertIn ( 'ikey 0.0.0.102' , output
)
1750 self
. assertIn ( 'iseq' , output
)
1752 def test_erspan_tunnel_v1 ( self
):
1753 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
1754 '25-erspan1-tunnel.netdev' , '25-tunnel.network' ,
1755 '25-erspan1-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1757 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
1759 output
= check_output ( 'ip -d link show erspan99' )
1761 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
1762 self
. assertIn ( 'erspan_ver 1' , output
)
1763 self
. assertIn ( 'erspan_index 123' , output
)
1764 self
. assertNotIn ( 'erspan_dir ingress' , output
)
1765 self
. assertNotIn ( 'erspan_hwid 1f' , output
)
1766 self
. assertIn ( 'ikey 0.0.0.101' , output
)
1767 self
. assertIn ( 'okey 0.0.0.101' , output
)
1768 self
. assertIn ( 'iseq' , output
)
1769 self
. assertIn ( 'oseq' , output
)
1770 output
= check_output ( 'ip -d link show erspan98' )
1772 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
1773 self
. assertIn ( 'erspan_ver 1' , output
)
1774 self
. assertIn ( 'erspan_index 124' , output
)
1775 self
. assertNotIn ( 'erspan_dir egress' , output
)
1776 self
. assertNotIn ( 'erspan_hwid 2f' , output
)
1777 self
. assertIn ( 'ikey 0.0.0.102' , output
)
1778 self
. assertIn ( 'okey 0.0.0.102' , output
)
1779 self
. assertIn ( 'iseq' , output
)
1780 self
. assertIn ( 'oseq' , output
)
1782 @expectedFailureIfERSPANv2IsNotSupported ()
1783 def test_erspan_tunnel_v2 ( self
):
1784 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
1785 '25-erspan2-tunnel.netdev' , '25-tunnel.network' ,
1786 '25-erspan2-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1788 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
1790 output
= check_output ( 'ip -d link show erspan99' )
1792 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
1793 self
. assertIn ( 'erspan_ver 2' , output
)
1794 self
. assertNotIn ( 'erspan_index 123' , output
)
1795 self
. assertIn ( 'erspan_dir ingress' , output
)
1796 self
. assertIn ( 'erspan_hwid 0x1f' , output
)
1797 self
. assertIn ( 'ikey 0.0.0.101' , output
)
1798 self
. assertIn ( 'okey 0.0.0.101' , output
)
1799 self
. assertIn ( 'iseq' , output
)
1800 self
. assertIn ( 'oseq' , output
)
1801 output
= check_output ( 'ip -d link show erspan98' )
1803 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
1804 self
. assertIn ( 'erspan_ver 2' , output
)
1805 self
. assertNotIn ( 'erspan_index 124' , output
)
1806 self
. assertIn ( 'erspan_dir egress' , output
)
1807 self
. assertIn ( 'erspan_hwid 0x2f' , output
)
1808 self
. assertIn ( 'ikey 0.0.0.102' , output
)
1809 self
. assertIn ( 'okey 0.0.0.102' , output
)
1810 self
. assertIn ( 'iseq' , output
)
1811 self
. assertIn ( 'oseq' , output
)
1813 def test_tunnel_independent ( self
):
1814 copy_network_unit ( '25-ipip-tunnel-independent.netdev' , '26-netdev-link-local-addressing-yes.network' )
1817 self
. wait_online ([ 'ipiptun99:carrier' ])
1819 def test_tunnel_independent_loopback ( self
):
1820 copy_network_unit ( '25-ipip-tunnel-independent-loopback.netdev' , '26-netdev-link-local-addressing-yes.network' )
1823 self
. wait_online ([ 'ipiptun99:carrier' ])
1825 @expectedFailureIfModuleIsNotAvailable ( 'xfrm_interface' )
1826 def test_xfrm ( self
):
1827 copy_network_unit ( '12-dummy.netdev' , '25-xfrm.network' ,
1828 '25-xfrm.netdev' , '25-xfrm-independent.netdev' ,
1829 '26-netdev-link-local-addressing-yes.network' )
1832 self
. wait_online ([ 'dummy98:degraded' , 'xfrm98:degraded' , 'xfrm99:degraded' ])
1834 output
= check_output ( 'ip -d link show dev xfrm98' )
1836 self
. assertIn ( 'xfrm98@dummy98:' , output
)
1837 self
. assertIn ( 'xfrm if_id 0x98 ' , output
)
1839 output
= check_output ( 'ip -d link show dev xfrm99' )
1841 self
. assertIn ( 'xfrm99@lo:' , output
)
1842 self
. assertIn ( 'xfrm if_id 0x99 ' , output
)
1844 @expectedFailureIfModuleIsNotAvailable ( 'fou' )
1846 # The following redundant check is necessary for CentOS CI.
1847 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1848 self
. assertTrue ( is_module_available ( 'fou' ))
1850 copy_network_unit ( '25-fou-ipproto-ipip.netdev' , '25-fou-ipproto-gre.netdev' ,
1851 '25-fou-ipip.netdev' , '25-fou-sit.netdev' ,
1852 '25-fou-gre.netdev' , '25-fou-gretap.netdev' )
1855 self
. wait_online ([ 'ipiptun96:off' , 'sittun96:off' , 'gretun96:off' , 'gretap96:off' ], setup_state
= 'unmanaged' )
1857 output
= check_output ( 'ip fou show' )
1859 self
. assertRegex ( output
, 'port 55555 ipproto 4' )
1860 self
. assertRegex ( output
, 'port 55556 ipproto 47' )
1862 output
= check_output ( 'ip -d link show ipiptun96' )
1864 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55555' )
1865 output
= check_output ( 'ip -d link show sittun96' )
1867 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55555' )
1868 output
= check_output ( 'ip -d link show gretun96' )
1870 self
. assertRegex ( output
, 'encap fou encap-sport 1001 encap-dport 55556' )
1871 output
= check_output ( 'ip -d link show gretap96' )
1873 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55556' )
1875 def test_vxlan ( self
):
1876 copy_network_unit ( '11-dummy.netdev' , '25-vxlan-test1.network' ,
1877 '25-vxlan.netdev' , '25-vxlan.network' ,
1878 '25-vxlan-ipv6.netdev' , '25-vxlan-ipv6.network' ,
1879 '25-vxlan-independent.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1880 '25-veth.netdev' , '25-vxlan-veth99.network' , '25-ipv6-prefix.network' ,
1881 '25-vxlan-local-slaac.netdev' , '25-vxlan-local-slaac.network' )
1884 self
. wait_online ([ 'test1:degraded' , 'veth99:routable' , 'veth-peer:degraded' ,
1885 'vxlan99:degraded' , 'vxlan98:degraded' , 'vxlan97:degraded' , 'vxlan-slaac:degraded' ])
1887 output
= check_output ( 'ip -d link show vxlan99' )
1889 self
. assertIn ( '999' , output
)
1890 self
. assertIn ( '5555' , output
)
1891 self
. assertIn ( 'l2miss' , output
)
1892 self
. assertIn ( 'l3miss' , output
)
1893 self
. assertIn ( 'udpcsum' , output
)
1894 self
. assertIn ( 'udp6zerocsumtx' , output
)
1895 self
. assertIn ( 'udp6zerocsumrx' , output
)
1896 self
. assertIn ( 'remcsumtx' , output
)
1897 self
. assertIn ( 'remcsumrx' , output
)
1898 self
. assertIn ( 'gbp' , output
)
1900 output
= check_output ( 'bridge fdb show dev vxlan99' )
1902 self
. assertIn ( '00:11:22:33:44:55 dst 10.0.0.5 self permanent' , output
)
1903 self
. assertIn ( '00:11:22:33:44:66 dst 10.0.0.6 self permanent' , output
)
1904 self
. assertIn ( '00:11:22:33:44:77 dst 10.0.0.7 via test1 self permanent' , output
)
1906 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'vxlan99' , env
= env
)
1908 self
. assertIn ( 'VNI: 999' , output
)
1909 self
. assertIn ( 'Destination Port: 5555' , output
)
1910 self
. assertIn ( 'Underlying Device: test1' , output
)
1912 output
= check_output ( 'bridge fdb show dev vxlan97' )
1914 self
. assertIn ( '00:00:00:00:00:00 dst fe80::23b:d2ff:fe95:967f via test1 self permanent' , output
)
1915 self
. assertIn ( '00:00:00:00:00:00 dst fe80::27c:16ff:fec0:6c74 via test1 self permanent' , output
)
1916 self
. assertIn ( '00:00:00:00:00:00 dst fe80::2a2:e4ff:fef9:2269 via test1 self permanent' , output
)
1918 output
= check_output ( 'ip -d link show vxlan-slaac' )
1920 self
. assertIn ( 'vxlan id 4831584 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99' , output
)
1922 output
= check_output ( 'ip -6 address show veth99' )
1924 self
. assertIn ( 'inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic' , output
)
1926 @unittest . skip ( reason
= "Causes kernel panic on recent kernels: https://bugzilla.kernel.org/show_bug.cgi?id=208315" )
1927 def test_macsec ( self
):
1928 copy_network_unit ( '25-macsec.netdev' , '25-macsec.network' , '25-macsec.key' ,
1929 '26-macsec.network' , '12-dummy.netdev' )
1932 self
. wait_online ([ 'dummy98:degraded' , 'macsec99:routable' ])
1934 output
= check_output ( 'ip -d link show macsec99' )
1936 self
. assertRegex ( output
, 'macsec99@dummy98' )
1937 self
. assertRegex ( output
, 'macsec sci [0-9a-f]*000b' )
1938 self
. assertRegex ( output
, 'encrypt on' )
1940 output
= check_output ( 'ip macsec show macsec99' )
1942 self
. assertRegex ( output
, 'encrypt on' )
1943 self
. assertRegex ( output
, 'TXSC: [0-9a-f]*000b on SA 1' )
1944 self
. assertRegex ( output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000' )
1945 self
. assertRegex ( output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000' )
1946 self
. assertRegex ( output
, 'RXSC: c619528fe6a00100, state on' )
1947 self
. assertRegex ( output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000' )
1948 self
. assertRegex ( output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000' )
1949 self
. assertRegex ( output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000' )
1950 self
. assertRegex ( output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000' )
1951 self
. assertNotRegex ( output
, 'key 02030405067080900000000000000000' )
1952 self
. assertRegex ( output
, 'RXSC: 8c16456c83a90002, state on' )
1953 self
. assertRegex ( output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000' )
1955 def test_nlmon ( self
):
1956 copy_network_unit ( '25-nlmon.netdev' , '26-netdev-link-local-addressing-yes.network' )
1959 self
. wait_online ([ 'nlmon99:carrier' ])
1961 @expectedFailureIfModuleIsNotAvailable ( 'ifb' )
1963 copy_network_unit ( '25-ifb.netdev' , '26-netdev-link-local-addressing-yes.network' )
1966 self
. wait_online ([ 'ifb99:degraded' ])
1968 class NetworkdL2TPTests ( unittest
. TestCase
, Utilities
):
1976 @expectedFailureIfModuleIsNotAvailable ( 'l2tp_eth' )
1977 def test_l2tp_udp ( self
):
1978 copy_network_unit ( '11-dummy.netdev' , '25-l2tp-dummy.network' ,
1979 '25-l2tp-udp.netdev' , '25-l2tp.network' )
1982 self
. wait_online ([ 'test1:routable' , 'l2tp-ses1:degraded' , 'l2tp-ses2:degraded' ])
1984 output
= check_output ( 'ip l2tp show tunnel tunnel_id 10' )
1986 self
. assertRegex ( output
, "Tunnel 10, encap UDP" )
1987 self
. assertRegex ( output
, "From 192.168.30.100 to 192.168.30.101" )
1988 self
. assertRegex ( output
, "Peer tunnel 11" )
1989 self
. assertRegex ( output
, "UDP source / dest ports: 3000/4000" )
1990 self
. assertRegex ( output
, "UDP checksum: enabled" )
1992 output
= check_output ( 'ip l2tp show session tid 10 session_id 15' )
1994 self
. assertRegex ( output
, "Session 15 in tunnel 10" )
1995 self
. assertRegex ( output
, "Peer session 16, tunnel 11" )
1996 self
. assertRegex ( output
, "interface name: l2tp-ses1" )
1998 output
= check_output ( 'ip l2tp show session tid 10 session_id 17' )
2000 self
. assertRegex ( output
, "Session 17 in tunnel 10" )
2001 self
. assertRegex ( output
, "Peer session 18, tunnel 11" )
2002 self
. assertRegex ( output
, "interface name: l2tp-ses2" )
2004 @expectedFailureIfModuleIsNotAvailable ( 'l2tp_ip' )
2005 def test_l2tp_ip ( self
):
2006 copy_network_unit ( '11-dummy.netdev' , '25-l2tp-dummy.network' ,
2007 '25-l2tp-ip.netdev' , '25-l2tp.network' )
2010 self
. wait_online ([ 'test1:routable' , 'l2tp-ses3:degraded' , 'l2tp-ses4:degraded' ])
2012 output
= check_output ( 'ip l2tp show tunnel tunnel_id 10' )
2014 self
. assertRegex ( output
, "Tunnel 10, encap IP" )
2015 self
. assertRegex ( output
, "From 192.168.30.100 to 192.168.30.101" )
2016 self
. assertRegex ( output
, "Peer tunnel 12" )
2018 output
= check_output ( 'ip l2tp show session tid 10 session_id 25' )
2020 self
. assertRegex ( output
, "Session 25 in tunnel 10" )
2021 self
. assertRegex ( output
, "Peer session 26, tunnel 12" )
2022 self
. assertRegex ( output
, "interface name: l2tp-ses3" )
2024 output
= check_output ( 'ip l2tp show session tid 10 session_id 27' )
2026 self
. assertRegex ( output
, "Session 27 in tunnel 10" )
2027 self
. assertRegex ( output
, "Peer session 28, tunnel 12" )
2028 self
. assertRegex ( output
, "interface name: l2tp-ses4" )
2030 class NetworkdNetworkTests ( unittest
. TestCase
, Utilities
):
2038 def test_address_static ( self
):
2039 # test for #22515. The address will be removed and replaced with /64 prefix.
2040 check_output ( 'ip link add dummy98 type dummy' )
2041 check_output ( 'ip link set dev dummy98 up' )
2042 check_output ( 'ip -6 address add 2001:db8:0:f101::15/128 dev dummy98' )
2043 self
. wait_address ( 'dummy98' , '2001:db8:0:f101::15/128' , ipv
= '-6' )
2044 check_output ( 'ip -4 address add 10.3.2.3/16 brd 10.3.255.250 scope global label dummy98:hoge dev dummy98' )
2045 self
. wait_address ( 'dummy98' , '10.3.2.3/16 brd 10.3.255.250' , ipv
= '-4' )
2047 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' )
2050 self
. wait_online ([ 'dummy98:routable' ])
2052 output
= check_output ( 'ip -4 address show dev dummy98' )
2054 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
2055 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
2056 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
2057 self
. assertIn ( 'inet 10.7.8.9/16 brd 10.7.255.255 scope link deprecated dummy98' , output
)
2058 self
. assertIn ( 'inet 10.8.8.1/16 scope global dummy98' , output
)
2059 self
. assertIn ( 'inet 10.8.8.2/16 brd 10.8.8.128 scope global secondary dummy98' , output
)
2060 self
. assertRegex ( output
, 'inet 10.9.0.1/16 (metric 128 |)brd 10.9.255.255 scope global dummy98' )
2062 # test for ENOBUFS issue #17012
2063 for i
in range ( 1 , 254 ):
2064 self
. assertIn ( f
'inet 10.3.3. {i} /16 brd 10.3.255.255' , output
)
2067 self
. assertNotIn ( '10.10.0.1/16' , output
)
2068 self
. assertNotIn ( '10.10.0.2/16' , output
)
2070 output
= check_output ( 'ip -4 address show dev dummy98 label 32' )
2071 self
. assertIn ( 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32' , output
)
2073 output
= check_output ( 'ip -4 address show dev dummy98 label 33' )
2074 self
. assertIn ( 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33' , output
)
2076 output
= check_output ( 'ip -4 address show dev dummy98 label 34' )
2077 self
. assertRegex ( output
, r
'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34' )
2079 output
= check_output ( 'ip -4 address show dev dummy98 label 35' )
2080 self
. assertRegex ( output
, r
'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35' )
2082 output
= check_output ( 'ip -4 route show dev dummy98' )
2084 self
. assertIn ( '10.9.0.0/16 proto kernel scope link src 10.9.0.1 metric 128' , output
)
2086 output
= check_output ( 'ip -6 address show dev dummy98' )
2088 self
. assertIn ( 'inet6 2001:db8:0:f101::15/64 scope global' , output
)
2089 self
. assertIn ( 'inet6 2001:db8:0:f101::16/64 scope global' , output
)
2090 self
. assertIn ( 'inet6 2001:db8:0:f102::15/64 scope global' , output
)
2091 self
. assertIn ( 'inet6 2001:db8:0:f102::16/64 scope global' , output
)
2092 self
. assertIn ( 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global' , output
)
2093 self
. assertIn ( 'inet6 2001:db8:1:f101::1/64 scope global deprecated' , output
)
2094 self
. assertRegex ( output
, r
'inet6 fd[0-9a-f:]*1/64 scope global' )
2097 # 1. set preferred lifetime forever to drop the deprecated flag for testing #20891.
2098 check_output ( 'ip address change 10.7.8.9/16 dev dummy98 preferred_lft forever' )
2099 check_output ( 'ip address change 2001:db8:1:f101::1/64 dev dummy98 preferred_lft forever' )
2100 output
= check_output ( 'ip -4 address show dev dummy98' )
2102 self
. assertNotIn ( 'deprecated' , output
)
2103 output
= check_output ( 'ip -6 address show dev dummy98' )
2105 self
. assertNotIn ( 'deprecated' , output
)
2107 # 2. reconfigure the interface.
2108 networkctl_reconfigure ( 'dummy98' )
2109 self
. wait_online ([ 'dummy98:routable' ])
2111 # 3. check the deprecated flag is set for the address configured with PreferredLifetime=0
2112 output
= check_output ( 'ip -4 address show dev dummy98' )
2114 self
. assertIn ( 'inet 10.7.8.9/16 brd 10.7.255.255 scope link deprecated dummy98' , output
)
2115 output
= check_output ( 'ip -6 address show dev dummy98' )
2117 self
. assertIn ( 'inet6 2001:db8:1:f101::1/64 scope global deprecated' , output
)
2119 # test for ENOBUFS issue #17012
2120 output
= check_output ( 'ip -4 address show dev dummy98' )
2121 for i
in range ( 1 , 254 ):
2122 self
. assertIn ( f
'inet 10.3.3. {i} /16 brd 10.3.255.255' , output
)
2124 # TODO: check json string
2125 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2127 def test_address_ipv4acd ( self
):
2128 check_output ( 'ip netns add ns99' )
2129 check_output ( 'ip link add veth99 type veth peer veth-peer' )
2130 check_output ( 'ip link set veth-peer netns ns99' )
2131 check_output ( 'ip link set veth99 up' )
2132 check_output ( 'ip netns exec ns99 ip link set veth-peer up' )
2133 check_output ( 'ip netns exec ns99 ip address add 192.168.100.10/24 dev veth-peer' )
2135 copy_network_unit ( '25-address-ipv4acd-veth99.network' , copy_dropins
= False )
2137 self
. wait_online ([ 'veth99:routable' ])
2139 output
= check_output ( 'ip -4 address show dev veth99' )
2141 self
. assertNotIn ( '192.168.100.10/24' , output
)
2142 self
. assertIn ( '192.168.100.11/24' , output
)
2144 copy_network_unit ( '25-address-ipv4acd-veth99.network.d/conflict-address.conf' )
2146 self
. wait_operstate ( 'veth99' , operstate
= 'routable' , setup_state
= 'configuring' , setup_timeout
= 10 )
2148 output
= check_output ( 'ip -4 address show dev veth99' )
2150 self
. assertNotIn ( '192.168.100.10/24' , output
)
2151 self
. assertIn ( '192.168.100.11/24' , output
)
2153 def test_address_peer_ipv4 ( self
):
2154 # test for issue #17304
2155 copy_network_unit ( '25-address-peer-ipv4.network' , '12-dummy.netdev' )
2157 for trial
in range ( 2 ):
2163 self
. wait_online ([ 'dummy98:routable' ])
2165 output
= check_output ( 'ip -4 address show dev dummy98' )
2166 self
. assertIn ( 'inet 100.64.0.1 peer 100.64.0.2/32 scope global' , output
)
2168 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
2169 def test_prefix_route ( self
):
2170 copy_network_unit ( '25-prefix-route-with-vrf.network' , '12-dummy.netdev' ,
2171 '25-prefix-route-without-vrf.network' , '11-dummy.netdev' ,
2172 '25-vrf.netdev' , '25-vrf.network' )
2173 for trial
in range ( 2 ):
2179 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' , 'vrf99:carrier' ])
2181 output
= check_output ( 'ip route show table 42 dev dummy98' )
2182 print ( '### ip route show table 42 dev dummy98' )
2184 self
. assertRegex ( output
, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1' )
2185 self
. assertRegex ( output
, '10.20.33.0/24 proto kernel scope link src 10.20.33.1' )
2186 self
. assertRegex ( output
, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1' )
2187 self
. assertRegex ( output
, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1' )
2188 self
. assertRegex ( output
, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1' )
2189 self
. assertRegex ( output
, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1' )
2190 self
. assertRegex ( output
, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1' )
2191 output
= check_output ( 'ip -6 route show table 42 dev dummy98' )
2192 print ( '### ip -6 route show table 42 dev dummy98' )
2196 self
. assertRegex ( output
, 'local fdde:11:22::1 proto kernel metric 0 pref medium' )
2197 #self.assertRegex(output, 'fdde:11:22::1 proto kernel metric 256 pref medium')
2198 self
. assertRegex ( output
, 'local fdde:11:33::1 proto kernel metric 0 pref medium' )
2199 self
. assertRegex ( output
, 'fdde:11:33::/64 proto kernel metric 256 pref medium' )
2200 self
. assertRegex ( output
, 'local fdde:11:44::1 proto kernel metric 0 pref medium' )
2201 self
. assertRegex ( output
, 'local fdde:11:55::1 proto kernel metric 0 pref medium' )
2202 self
. assertRegex ( output
, 'fe80::/64 proto kernel metric 256 pref medium' )
2203 self
. assertRegex ( output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium' )
2207 output
= check_output ( 'ip route show dev test1' )
2208 print ( '### ip route show dev test1' )
2210 self
. assertRegex ( output
, '10.21.33.0/24 proto kernel scope link src 10.21.33.1' )
2211 output
= check_output ( 'ip route show table local dev test1' )
2212 print ( '### ip route show table local dev test1' )
2214 self
. assertRegex ( output
, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1' )
2215 self
. assertRegex ( output
, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1' )
2216 self
. assertRegex ( output
, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1' )
2217 self
. assertRegex ( output
, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1' )
2218 self
. assertRegex ( output
, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1' )
2219 self
. assertRegex ( output
, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1' )
2220 output
= check_output ( 'ip -6 route show dev test1' )
2221 print ( '### ip -6 route show dev test1' )
2223 self
. assertRegex ( output
, 'fdde:12:22::1 proto kernel metric 256 pref medium' )
2224 self
. assertRegex ( output
, 'fdde:12:33::/64 proto kernel metric 256 pref medium' )
2225 self
. assertRegex ( output
, 'fe80::/64 proto kernel metric 256 pref medium' )
2226 output
= check_output ( 'ip -6 route show table local dev test1' )
2227 print ( '### ip -6 route show table local dev test1' )
2229 self
. assertRegex ( output
, 'local fdde:12:22::1 proto kernel metric 0 pref medium' )
2230 self
. assertRegex ( output
, 'local fdde:12:33::1 proto kernel metric 0 pref medium' )
2231 self
. assertRegex ( output
, 'local fdde:12:44::1 proto kernel metric 0 pref medium' )
2232 self
. assertRegex ( output
, 'local fdde:12:55::1 proto kernel metric 0 pref medium' )
2233 self
. assertRegex ( output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium' )
2235 def test_configure_without_carrier ( self
):
2236 copy_network_unit ( '11-dummy.netdev' )
2238 self
. wait_operstate ( 'test1' , 'off' , '' )
2239 check_output ( 'ip link set dev test1 up carrier off' )
2241 copy_network_unit ( '25-test1.network.d/configure-without-carrier.conf' , copy_dropins
= False )
2243 self
. wait_online ([ 'test1:no-carrier' ])
2245 carrier_map
= { 'on' : '1' , 'off' : '0' }
2246 routable_map
= { 'on' : 'routable' , 'off' : 'no-carrier' }
2247 for carrier
in [ 'off' , 'on' , 'off' ]:
2248 with self
. subTest ( carrier
= carrier
):
2249 if carrier_map
[ carrier
] != read_link_attr ( 'test1' , 'carrier' ):
2250 check_output ( f
'ip link set dev test1 carrier {carrier} ' )
2251 self
. wait_online ([ f
'test1:{routable_map[carrier]}:{routable_map[carrier]}' ])
2253 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
2255 self
. assertRegex ( output
, '192.168.0.15' )
2256 self
. assertRegex ( output
, '192.168.0.1' )
2257 self
. assertRegex ( output
, routable_map
[ carrier
])
2259 def test_configure_without_carrier_yes_ignore_carrier_loss_no ( self
):
2260 copy_network_unit ( '11-dummy.netdev' )
2262 self
. wait_operstate ( 'test1' , 'off' , '' )
2263 check_output ( 'ip link set dev test1 up carrier off' )
2265 copy_network_unit ( '25-test1.network' )
2267 self
. wait_online ([ 'test1:no-carrier' ])
2269 carrier_map
= { 'on' : '1' , 'off' : '0' }
2270 routable_map
= { 'on' : 'routable' , 'off' : 'no-carrier' }
2271 for ( carrier
, have_config
) in [( 'off' , True ), ( 'on' , True ), ( 'off' , False )]:
2272 with self
. subTest ( carrier
= carrier
, have_config
= have_config
):
2273 if carrier_map
[ carrier
] != read_link_attr ( 'test1' , 'carrier' ):
2274 check_output ( f
'ip link set dev test1 carrier {carrier} ' )
2275 self
. wait_online ([ f
'test1:{routable_map[carrier]}:{routable_map[carrier]}' ])
2277 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
2280 self
. assertRegex ( output
, '192.168.0.15' )
2281 self
. assertRegex ( output
, '192.168.0.1' )
2283 self
. assertNotRegex ( output
, '192.168.0.15' )
2284 self
. assertNotRegex ( output
, '192.168.0.1' )
2285 self
. assertRegex ( output
, routable_map
[ carrier
])
2287 def test_routing_policy_rule ( self
):
2288 copy_network_unit ( '25-routing-policy-rule-test1.network' , '11-dummy.netdev' )
2290 self
. wait_online ([ 'test1:degraded' ])
2292 output
= check_output ( 'ip rule list iif test1 priority 111' )
2294 self
. assertRegex ( output
, '111:' )
2295 self
. assertRegex ( output
, 'from 192.168.100.18' )
2296 self
. assertRegex ( output
, r
'tos (0x08|throughput)\s' )
2297 self
. assertRegex ( output
, 'iif test1' )
2298 self
. assertRegex ( output
, 'oif test1' )
2299 self
. assertRegex ( output
, 'lookup 7' )
2301 output
= check_output ( 'ip rule list iif test1 priority 101' )
2303 self
. assertRegex ( output
, '101:' )
2304 self
. assertRegex ( output
, 'from all' )
2305 self
. assertRegex ( output
, 'iif test1' )
2306 self
. assertRegex ( output
, 'lookup 9' )
2308 output
= check_output ( 'ip -6 rule list iif test1 priority 100' )
2310 self
. assertRegex ( output
, '100:' )
2311 self
. assertRegex ( output
, 'from all' )
2312 self
. assertRegex ( output
, 'iif test1' )
2313 self
. assertRegex ( output
, 'lookup 8' )
2315 output
= check_output ( 'ip rule list iif test1 priority 102' )
2317 self
. assertRegex ( output
, '102:' )
2318 self
. assertRegex ( output
, 'from 0.0.0.0/8' )
2319 self
. assertRegex ( output
, 'iif test1' )
2320 self
. assertRegex ( output
, 'lookup 10' )
2322 # TODO: check json string
2323 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2325 def test_routing_policy_rule_issue_11280 ( self
):
2326 copy_network_unit ( '25-routing-policy-rule-test1.network' , '11-dummy.netdev' ,
2327 '25-routing-policy-rule-dummy98.network' , '12-dummy.netdev' )
2329 for trial
in range ( 3 ):
2330 restart_networkd ( show_logs
=( trial
> 0 ))
2331 self
. wait_online ([ 'test1:degraded' , 'dummy98:degraded' ])
2333 output
= check_output ( 'ip rule list table 7' )
2335 self
. assertRegex ( output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7' )
2337 output
= check_output ( 'ip rule list table 8' )
2339 self
. assertRegex ( output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8' )
2341 def test_routing_policy_rule_reconfigure ( self
):
2342 copy_network_unit ( '25-routing-policy-rule-reconfigure2.network' , '11-dummy.netdev' )
2344 self
. wait_online ([ 'test1:degraded' ])
2346 output
= check_output ( 'ip rule list table 1011' )
2348 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2349 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2350 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2351 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2353 output
= check_output ( 'ip -6 rule list table 1011' )
2355 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2357 copy_network_unit ( '25-routing-policy-rule-reconfigure1.network' , '11-dummy.netdev' )
2359 self
. wait_online ([ 'test1:degraded' ])
2361 output
= check_output ( 'ip rule list table 1011' )
2363 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2364 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2365 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2366 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2368 output
= check_output ( 'ip -6 rule list table 1011' )
2370 self
. assertNotIn ( '10112: from all oif test1 lookup 1011' , output
)
2371 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2373 call ( 'ip rule delete priority 10111' )
2374 call ( 'ip rule delete priority 10112' )
2375 call ( 'ip rule delete priority 10113' )
2376 call ( 'ip rule delete priority 10114' )
2377 call ( 'ip -6 rule delete priority 10113' )
2379 output
= check_output ( 'ip rule list table 1011' )
2381 self
. assertEqual ( output
, '' )
2383 output
= check_output ( 'ip -6 rule list table 1011' )
2385 self
. assertEqual ( output
, '' )
2387 networkctl_reconfigure ( 'test1' )
2388 self
. wait_online ([ 'test1:degraded' ])
2390 output
= check_output ( 'ip rule list table 1011' )
2392 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2393 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2394 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2395 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2397 output
= check_output ( 'ip -6 rule list table 1011' )
2399 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2401 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable ()
2402 def test_routing_policy_rule_port_range ( self
):
2403 copy_network_unit ( '25-fibrule-port-range.network' , '11-dummy.netdev' )
2405 self
. wait_online ([ 'test1:degraded' ])
2407 output
= check_output ( 'ip rule' )
2409 self
. assertRegex ( output
, '111' )
2410 self
. assertRegex ( output
, 'from 192.168.100.18' )
2411 self
. assertRegex ( output
, '1123-1150' )
2412 self
. assertRegex ( output
, '3224-3290' )
2413 self
. assertRegex ( output
, 'tcp' )
2414 self
. assertRegex ( output
, 'lookup 7' )
2416 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable ()
2417 def test_routing_policy_rule_invert ( self
):
2418 copy_network_unit ( '25-fibrule-invert.network' , '11-dummy.netdev' )
2420 self
. wait_online ([ 'test1:degraded' ])
2422 output
= check_output ( 'ip rule' )
2424 self
. assertRegex ( output
, '111' )
2425 self
. assertRegex ( output
, 'not.*?from.*?192.168.100.18' )
2426 self
. assertRegex ( output
, 'tcp' )
2427 self
. assertRegex ( output
, 'lookup 7' )
2429 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable ()
2430 def test_routing_policy_rule_uidrange ( self
):
2431 copy_network_unit ( '25-fibrule-uidrange.network' , '11-dummy.netdev' )
2433 self
. wait_online ([ 'test1:degraded' ])
2435 output
= check_output ( 'ip rule' )
2437 self
. assertRegex ( output
, '111' )
2438 self
. assertRegex ( output
, 'from 192.168.100.18' )
2439 self
. assertRegex ( output
, 'lookup 7' )
2440 self
. assertRegex ( output
, 'uidrange 100-200' )
2442 def _test_route_static ( self
, manage_foreign_routes
):
2443 if not manage_foreign_routes
:
2444 copy_networkd_conf_dropin ( 'networkd-manage-foreign-routes-no.conf' )
2446 copy_network_unit ( '25-route-static.network' , '12-dummy.netdev' )
2448 self
. wait_online ([ 'dummy98:routable' ])
2450 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
2453 print ( '### ip -6 route show dev dummy98' )
2454 output
= check_output ( 'ip -6 route show dev dummy98' )
2456 self
. assertIn ( '2001:1234:5:8fff:ff:ff:ff:ff proto static' , output
)
2457 self
. assertIn ( '2001:1234:5:8f63::1 proto kernel' , output
)
2458 self
. assertIn ( '2001:1234:5:afff:ff:ff:ff:ff via fe80:0:222:4dff:ff:ff:ff:ff proto static' , output
)
2460 print ( '### ip -6 route show default' )
2461 output
= check_output ( 'ip -6 route show default' )
2463 self
. assertIn ( 'default' , output
)
2464 self
. assertIn ( 'via 2001:1234:5:8fff:ff:ff:ff:ff' , output
)
2466 print ( '### ip -4 route show dev dummy98' )
2467 output
= check_output ( 'ip -4 route show dev dummy98' )
2469 self
. assertIn ( '149.10.124.48/28 proto kernel scope link src 149.10.124.58' , output
)
2470 self
. assertIn ( '149.10.124.64 proto static scope link' , output
)
2471 self
. assertIn ( '169.254.0.0/16 proto static scope link metric 2048' , output
)
2472 self
. assertIn ( '192.168.1.1 proto static scope link initcwnd 20' , output
)
2473 self
. assertIn ( '192.168.1.2 proto static scope link initrwnd 30' , output
)
2474 self
. assertIn ( '192.168.1.3 proto static scope link advmss 30' , output
)
2475 self
. assertIn ( 'multicast 149.10.123.4 proto static' , output
)
2477 print ( '### ip -4 route show dev dummy98 default' )
2478 output
= check_output ( 'ip -4 route show dev dummy98 default' )
2480 self
. assertIn ( 'default via 149.10.125.65 proto static onlink' , output
)
2481 self
. assertIn ( 'default via 149.10.124.64 proto static' , output
)
2482 self
. assertIn ( 'default proto static' , output
)
2484 print ( '### ip -4 route show table local dev dummy98' )
2485 output
= check_output ( 'ip -4 route show table local dev dummy98' )
2487 self
. assertIn ( 'local 149.10.123.1 proto static scope host' , output
)
2488 self
. assertIn ( 'anycast 149.10.123.2 proto static scope link' , output
)
2489 self
. assertIn ( 'broadcast 149.10.123.3 proto static scope link' , output
)
2491 print ( '### ip route show type blackhole' )
2492 output
= check_output ( 'ip route show type blackhole' )
2494 self
. assertIn ( 'blackhole 202.54.1.2 proto static' , output
)
2496 print ( '### ip route show type unreachable' )
2497 output
= check_output ( 'ip route show type unreachable' )
2499 self
. assertIn ( 'unreachable 202.54.1.3 proto static' , output
)
2501 print ( '### ip route show type prohibit' )
2502 output
= check_output ( 'ip route show type prohibit' )
2504 self
. assertIn ( 'prohibit 202.54.1.4 proto static' , output
)
2506 print ( '### ip -6 route show type blackhole' )
2507 output
= check_output ( 'ip -6 route show type blackhole' )
2509 self
. assertIn ( 'blackhole 2001:1234:5678::2 dev lo proto static' , output
)
2511 print ( '### ip -6 route show type unreachable' )
2512 output
= check_output ( 'ip -6 route show type unreachable' )
2514 self
. assertIn ( 'unreachable 2001:1234:5678::3 dev lo proto static' , output
)
2516 print ( '### ip -6 route show type prohibit' )
2517 output
= check_output ( 'ip -6 route show type prohibit' )
2519 self
. assertIn ( 'prohibit 2001:1234:5678::4 dev lo proto static' , output
)
2521 print ( '### ip route show 192.168.10.1' )
2522 output
= check_output ( 'ip route show 192.168.10.1' )
2524 self
. assertIn ( '192.168.10.1 proto static' , output
)
2525 self
. assertIn ( 'nexthop via 149.10.124.59 dev dummy98 weight 10' , output
)
2526 self
. assertIn ( 'nexthop via 149.10.124.60 dev dummy98 weight 5' , output
)
2528 print ( '### ip route show 192.168.10.2' )
2529 output
= check_output ( 'ip route show 192.168.10.2' )
2531 # old ip command does not show IPv6 gateways...
2532 self
. assertIn ( '192.168.10.2 proto static' , output
)
2533 self
. assertIn ( 'nexthop' , output
)
2534 self
. assertIn ( 'dev dummy98 weight 10' , output
)
2535 self
. assertIn ( 'dev dummy98 weight 5' , output
)
2537 print ( '### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff' )
2538 output
= check_output ( 'ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff' )
2540 # old ip command does not show 'nexthop' keyword and weight...
2541 self
. assertIn ( '2001:1234:5:7fff:ff:ff:ff:ff' , output
)
2542 self
. assertIn ( 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98' , output
)
2543 self
. assertIn ( 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98' , output
)
2545 # TODO: check json string
2546 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2548 copy_network_unit ( '25-address-static.network' )
2550 self
. wait_online ([ 'dummy98:routable' ])
2552 # check all routes managed by Manager are removed
2553 print ( '### ip route show type blackhole' )
2554 output
= check_output ( 'ip route show type blackhole' )
2556 self
. assertEqual ( output
, '' )
2558 print ( '### ip route show type unreachable' )
2559 output
= check_output ( 'ip route show type unreachable' )
2561 self
. assertEqual ( output
, '' )
2563 print ( '### ip route show type prohibit' )
2564 output
= check_output ( 'ip route show type prohibit' )
2566 self
. assertEqual ( output
, '' )
2568 print ( '### ip -6 route show type blackhole' )
2569 output
= check_output ( 'ip -6 route show type blackhole' )
2571 self
. assertEqual ( output
, '' )
2573 print ( '### ip -6 route show type unreachable' )
2574 output
= check_output ( 'ip -6 route show type unreachable' )
2576 self
. assertEqual ( output
, '' )
2578 print ( '### ip -6 route show type prohibit' )
2579 output
= check_output ( 'ip -6 route show type prohibit' )
2581 self
. assertEqual ( output
, '' )
2583 remove_network_unit ( '25-address-static.network' )
2585 self
. wait_online ([ 'dummy98:routable' ])
2587 # check all routes managed by Manager are reconfigured
2588 print ( '### ip route show type blackhole' )
2589 output
= check_output ( 'ip route show type blackhole' )
2591 self
. assertIn ( 'blackhole 202.54.1.2 proto static' , output
)
2593 print ( '### ip route show type unreachable' )
2594 output
= check_output ( 'ip route show type unreachable' )
2596 self
. assertIn ( 'unreachable 202.54.1.3 proto static' , output
)
2598 print ( '### ip route show type prohibit' )
2599 output
= check_output ( 'ip route show type prohibit' )
2601 self
. assertIn ( 'prohibit 202.54.1.4 proto static' , output
)
2603 print ( '### ip -6 route show type blackhole' )
2604 output
= check_output ( 'ip -6 route show type blackhole' )
2606 self
. assertIn ( 'blackhole 2001:1234:5678::2 dev lo proto static' , output
)
2608 print ( '### ip -6 route show type unreachable' )
2609 output
= check_output ( 'ip -6 route show type unreachable' )
2611 self
. assertIn ( 'unreachable 2001:1234:5678::3 dev lo proto static' , output
)
2613 print ( '### ip -6 route show type prohibit' )
2614 output
= check_output ( 'ip -6 route show type prohibit' )
2616 self
. assertIn ( 'prohibit 2001:1234:5678::4 dev lo proto static' , output
)
2618 remove_link ( 'dummy98' )
2621 # check all routes managed by Manager are removed
2622 print ( '### ip route show type blackhole' )
2623 output
= check_output ( 'ip route show type blackhole' )
2625 self
. assertEqual ( output
, '' )
2627 print ( '### ip route show type unreachable' )
2628 output
= check_output ( 'ip route show type unreachable' )
2630 self
. assertEqual ( output
, '' )
2632 print ( '### ip route show type prohibit' )
2633 output
= check_output ( 'ip route show type prohibit' )
2635 self
. assertEqual ( output
, '' )
2637 print ( '### ip -6 route show type blackhole' )
2638 output
= check_output ( 'ip -6 route show type blackhole' )
2640 self
. assertEqual ( output
, '' )
2642 print ( '### ip -6 route show type unreachable' )
2643 output
= check_output ( 'ip -6 route show type unreachable' )
2645 self
. assertEqual ( output
, '' )
2647 print ( '### ip -6 route show type prohibit' )
2648 output
= check_output ( 'ip -6 route show type prohibit' )
2650 self
. assertEqual ( output
, '' )
2654 def test_route_static ( self
):
2656 for manage_foreign_routes
in [ True , False ]:
2662 print ( f
'### test_route_static(manage_foreign_routes= {manage_foreign_routes} )' )
2663 with self
. subTest ( manage_foreign_routes
= manage_foreign_routes
):
2664 self
._ test
_ route
_ static
( manage_foreign_routes
)
2666 @expectedFailureIfRTA_VIAIsNotSupported ()
2667 def test_route_via_ipv6 ( self
):
2668 copy_network_unit ( '25-route-via-ipv6.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
. assertRegex ( output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static' )
2679 self
. assertRegex ( output
, '2001:1234:5:8f63::1 proto kernel' )
2681 print ( '### ip -4 route show dev dummy98' )
2682 output
= check_output ( 'ip -4 route show dev dummy98' )
2684 self
. assertRegex ( output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58' )
2685 self
. assertRegex ( output
, '149.10.124.66 via inet6 2001:1234:5:8fff:ff:ff:ff:ff proto static' )
2687 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
2688 def test_route_vrf ( self
):
2689 copy_network_unit ( '25-route-vrf.network' , '12-dummy.netdev' ,
2690 '25-vrf.netdev' , '25-vrf.network' )
2692 self
. wait_online ([ 'dummy98:routable' , 'vrf99:carrier' ])
2694 output
= check_output ( 'ip route show vrf vrf99' )
2696 self
. assertRegex ( output
, 'default via 192.168.100.1' )
2698 output
= check_output ( 'ip route show' )
2700 self
. assertNotRegex ( output
, 'default via 192.168.100.1' )
2702 def test_gateway_reconfigure ( self
):
2703 copy_network_unit ( '25-gateway-static.network' , '12-dummy.netdev' )
2705 self
. wait_online ([ 'dummy98:routable' ])
2706 print ( '### ip -4 route show dev dummy98 default' )
2707 output
= check_output ( 'ip -4 route show dev dummy98 default' )
2709 self
. assertIn ( 'default via 149.10.124.59 proto static' , output
)
2710 self
. assertNotIn ( '149.10.124.60' , output
)
2712 remove_network_unit ( '25-gateway-static.network' )
2713 copy_network_unit ( '25-gateway-next-static.network' )
2715 self
. wait_online ([ 'dummy98:routable' ])
2716 print ( '### ip -4 route show dev dummy98 default' )
2717 output
= check_output ( 'ip -4 route show dev dummy98 default' )
2719 self
. assertNotIn ( '149.10.124.59' , output
)
2720 self
. assertIn ( 'default via 149.10.124.60 proto static' , output
)
2722 def test_ip_route_ipv6_src_route ( self
):
2723 # a dummy device does not make the addresses go through tentative state, so we
2724 # reuse a bond from an earlier test, which does make the addresses go through
2725 # tentative state, and do our test on that
2726 copy_network_unit ( '23-active-slave.network' , '25-route-ipv6-src.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
2728 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:routable' ])
2730 output
= check_output ( 'ip -6 route list dev bond199' )
2732 self
. assertRegex ( output
, 'abcd::/16' )
2733 self
. assertRegex ( output
, 'src' )
2734 self
. assertRegex ( output
, '2001:1234:56:8f63::2' )
2736 def test_ip_link_mac_address ( self
):
2737 copy_network_unit ( '25-address-link-section.network' , '12-dummy.netdev' )
2739 self
. wait_online ([ 'dummy98:degraded' ])
2741 output
= check_output ( 'ip link show dummy98' )
2743 self
. assertRegex ( output
, '00:01:02:aa:bb:cc' )
2745 def test_ip_link_unmanaged ( self
):
2746 copy_network_unit ( '25-link-section-unmanaged.network' , '12-dummy.netdev' )
2749 self
. wait_operstate ( 'dummy98' , 'off' , setup_state
= 'unmanaged' )
2751 def test_ipv6_address_label ( self
):
2752 copy_network_unit ( '25-ipv6-address-label-section.network' , '12-dummy.netdev' )
2754 self
. wait_online ([ 'dummy98:degraded' ])
2756 output
= check_output ( 'ip addrlabel list' )
2758 self
. assertRegex ( output
, '2004:da8:1::/64' )
2760 def test_ipv6_proxy_ndp ( self
):
2761 copy_network_unit ( '25-ipv6-proxy-ndp.network' , '12-dummy.netdev' )
2764 self
. wait_online ([ 'dummy98:routable' ])
2766 output
= check_output ( 'ip neighbor show proxy dev dummy98' )
2768 for i
in range ( 1 , 5 ):
2769 self
. assertRegex ( output
, f
'2607:5300:203:5215: {i} ::1 *proxy' )
2771 def test_neighbor_section ( self
):
2772 copy_network_unit ( '25-neighbor-section.network' , '12-dummy.netdev' )
2774 self
. wait_online ([ 'dummy98:degraded' ], timeout
= '40s' )
2776 print ( '### ip neigh list dev dummy98' )
2777 output
= check_output ( 'ip neigh list dev dummy98' )
2779 self
. assertRegex ( output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT' )
2780 self
. assertRegex ( output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT' )
2782 # TODO: check json string
2783 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2785 def test_neighbor_reconfigure ( self
):
2786 copy_network_unit ( '25-neighbor-section.network' , '12-dummy.netdev' )
2788 self
. wait_online ([ 'dummy98:degraded' ], timeout
= '40s' )
2790 print ( '### ip neigh list dev dummy98' )
2791 output
= check_output ( 'ip neigh list dev dummy98' )
2793 self
. assertRegex ( output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT' )
2794 self
. assertRegex ( output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT' )
2796 remove_network_unit ( '25-neighbor-section.network' )
2797 copy_network_unit ( '25-neighbor-next.network' )
2799 self
. wait_online ([ 'dummy98:degraded' ], timeout
= '40s' )
2800 print ( '### ip neigh list dev dummy98' )
2801 output
= check_output ( 'ip neigh list dev dummy98' )
2803 self
. assertNotRegex ( output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT' )
2804 self
. assertRegex ( output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT' )
2805 self
. assertNotRegex ( output
, '2004:da8:1::1.*PERMANENT' )
2807 def test_neighbor_gre ( self
):
2808 copy_network_unit ( '25-neighbor-ip.network' , '25-neighbor-ipv6.network' , '25-neighbor-ip-dummy.network' ,
2809 '12-dummy.netdev' , '25-gre-tunnel-remote-any.netdev' , '25-ip6gre-tunnel-remote-any.netdev' )
2811 self
. wait_online ([ 'dummy98:degraded' , 'gretun97:routable' , 'ip6gretun97:routable' ], timeout
= '40s' )
2813 output
= check_output ( 'ip neigh list dev gretun97' )
2815 self
. assertRegex ( output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT' )
2817 output
= check_output ( 'ip neigh list dev ip6gretun97' )
2819 self
. assertRegex ( output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT' )
2821 # TODO: check json string
2822 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2824 def test_link_local_addressing ( self
):
2825 copy_network_unit ( '25-link-local-addressing-yes.network' , '11-dummy.netdev' ,
2826 '25-link-local-addressing-no.network' , '12-dummy.netdev' )
2828 self
. wait_online ([ 'test1:degraded' , 'dummy98:carrier' ])
2830 output
= check_output ( 'ip address show dev test1' )
2832 self
. assertRegex ( output
, 'inet .* scope link' )
2833 self
. assertRegex ( output
, 'inet6 .* scope link' )
2835 output
= check_output ( 'ip address show dev dummy98' )
2837 self
. assertNotRegex ( output
, 'inet6* .* scope link' )
2839 # Documentation/networking/ip-sysctl.txt
2841 # addr_gen_mode - INTEGER
2842 # Defines how link-local and autoconf addresses are generated.
2844 # 0: generate address based on EUI64 (default)
2845 # 1: do no generate a link-local address, use EUI64 for addresses generated
2847 # 2: generate stable privacy addresses, using the secret from
2848 # stable_secret (RFC7217)
2849 # 3: generate stable privacy addresses, using a random secret if unset
2851 self
. check_ipv6_sysctl_attr ( 'test1' , 'stable_secret' , '0123:4567:89ab:cdef:0123:4567:89ab:cdef' )
2852 self
. check_ipv6_sysctl_attr ( 'test1' , 'addr_gen_mode' , '2' )
2853 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'addr_gen_mode' , '1' )
2855 def test_link_local_addressing_ipv6ll ( self
):
2856 copy_network_unit ( '26-link-local-addressing-ipv6.network' , '12-dummy.netdev' )
2858 self
. wait_online ([ 'dummy98:degraded' ])
2860 # An IPv6LL address exists by default.
2861 output
= check_output ( 'ip address show dev dummy98' )
2863 self
. assertRegex ( output
, 'inet6 .* scope link' )
2865 copy_network_unit ( '25-link-local-addressing-no.network' )
2867 self
. wait_online ([ 'dummy98:carrier' ])
2869 # Check if the IPv6LL address is removed.
2870 output
= check_output ( 'ip address show dev dummy98' )
2872 self
. assertNotRegex ( output
, 'inet6 .* scope link' )
2874 remove_network_unit ( '25-link-local-addressing-no.network' )
2876 self
. wait_online ([ 'dummy98:degraded' ])
2878 # Check if a new IPv6LL address is assigned.
2879 output
= check_output ( 'ip address show dev dummy98' )
2881 self
. assertRegex ( output
, 'inet6 .* scope link' )
2883 def test_sysctl ( self
):
2884 copy_network_unit ( '25-sysctl.network' , '12-dummy.netdev' )
2886 self
. wait_online ([ 'dummy98:degraded' ])
2888 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
2889 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'use_tempaddr' , '2' )
2890 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'dad_transmits' , '3' )
2891 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'hop_limit' , '5' )
2892 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'proxy_ndp' , '1' )
2893 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
2894 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'proxy_arp' , '1' )
2895 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'accept_local' , '1' )
2897 def test_sysctl_disable_ipv6 ( self
):
2898 copy_network_unit ( '25-sysctl-disable-ipv6.network' , '12-dummy.netdev' )
2900 print ( '## Disable ipv6' )
2901 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=1' )
2902 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=1' )
2905 self
. wait_online ([ 'dummy98:routable' ])
2907 output
= check_output ( 'ip -4 address show dummy98' )
2909 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
2910 output
= check_output ( 'ip -6 address show dummy98' )
2912 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
2913 self
. assertRegex ( output
, 'inet6 .* scope link' )
2914 output
= check_output ( 'ip -4 route show dev dummy98' )
2916 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
2917 output
= check_output ( 'ip -6 route show default' )
2919 self
. assertRegex ( output
, 'default' )
2920 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
2922 remove_link ( 'dummy98' )
2924 print ( '## Enable ipv6' )
2925 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=0' )
2926 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=0' )
2929 self
. wait_online ([ 'dummy98:routable' ])
2931 output
= check_output ( 'ip -4 address show dummy98' )
2933 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
2934 output
= check_output ( 'ip -6 address show dummy98' )
2936 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
2937 self
. assertRegex ( output
, 'inet6 .* scope link' )
2938 output
= check_output ( 'ip -4 route show dev dummy98' )
2940 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
2941 output
= check_output ( 'ip -6 route show default' )
2943 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
2945 def test_bind_carrier ( self
):
2946 check_output ( 'ip link add dummy98 type dummy' )
2947 check_output ( 'ip link set dummy98 up' )
2950 copy_network_unit ( '25-bind-carrier.network' , '11-dummy.netdev' )
2952 self
. wait_online ([ 'test1:routable' ])
2954 output
= check_output ( 'ip address show test1' )
2956 self
. assertRegex ( output
, 'UP,LOWER_UP' )
2957 self
. assertRegex ( output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' )
2958 self
. wait_operstate ( 'test1' , 'routable' )
2960 check_output ( 'ip link add dummy99 type dummy' )
2961 check_output ( 'ip link set dummy99 up' )
2963 output
= check_output ( 'ip address show test1' )
2965 self
. assertRegex ( output
, 'UP,LOWER_UP' )
2966 self
. assertRegex ( output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' )
2967 self
. wait_operstate ( 'test1' , 'routable' )
2969 remove_link ( 'dummy98' )
2971 output
= check_output ( 'ip address show test1' )
2973 self
. assertRegex ( output
, 'UP,LOWER_UP' )
2974 self
. assertRegex ( output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' )
2975 self
. wait_operstate ( 'test1' , 'routable' )
2977 check_output ( 'ip link set dummy99 down' )
2979 output
= check_output ( 'ip address show test1' )
2981 self
. assertNotRegex ( output
, 'UP,LOWER_UP' )
2982 self
. assertRegex ( output
, 'DOWN' )
2983 self
. assertNotRegex ( output
, '192.168.10' )
2984 self
. wait_operstate ( 'test1' , 'off' )
2986 check_output ( 'ip link set dummy99 up' )
2988 output
= check_output ( 'ip address show test1' )
2990 self
. assertRegex ( output
, 'UP,LOWER_UP' )
2991 self
. assertRegex ( output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' )
2992 self
. wait_operstate ( 'test1' , 'routable' )
2994 def _test_activation_policy ( self
, interface
, test
):
2995 conffile
= '25-activation-policy.network'
2997 conffile
= f
' {conffile} .d/ {test} .conf'
2998 if interface
== 'vlan99' :
2999 copy_network_unit ( '21-vlan.netdev' , '21-vlan-test1.network' )
3000 copy_network_unit ( '11-dummy.netdev' , conffile
, copy_dropins
= False )
3003 always
= test
. startswith ( 'always' )
3004 initial_up
= test
!= 'manual' and not test
. endswith ( 'down' ) # note: default is up
3005 expect_up
= initial_up
3006 next_up
= not expect_up
3008 if test
. endswith ( 'down' ):
3009 self
. wait_activated ( interface
)
3011 for iteration
in range ( 4 ):
3012 with self
. subTest ( iteration
= iteration
, expect_up
= expect_up
):
3013 operstate
= 'routable' if expect_up
else 'off'
3014 setup_state
= 'configured' if expect_up
else ( 'configuring' if iteration
== 0 else None )
3015 self
. wait_operstate ( interface
, operstate
, setup_state
= setup_state
, setup_timeout
= 20 )
3018 self
. assertIn ( 'UP' , check_output ( f
'ip link show {interface} ' ))
3019 self
. assertIn ( '192.168.10.30/24' , check_output ( f
'ip address show {interface} ' ))
3020 self
. assertIn ( 'default via 192.168.10.1' , check_output ( f
'ip route show dev {interface} ' ))
3022 self
. assertIn ( 'DOWN' , check_output ( f
'ip link show {interface} ' ))
3025 check_output ( f
'ip link set dev {interface} up' )
3027 check_output ( f
'ip link set dev {interface} down' )
3028 expect_up
= initial_up
if always
else next_up
3029 next_up
= not next_up
3033 def test_activation_policy ( self
):
3035 for interface
in [ 'test1' , 'vlan99' ]:
3036 for test
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , '' ]:
3042 print ( f
'### test_activation_policy(interface= {interface} , test= {test} )' )
3043 with self
. subTest ( interface
= interface
, test
= test
):
3044 self
._ test
_ activation
_ policy
( interface
, test
)
3046 def _test_activation_policy_required_for_online ( self
, policy
, required
):
3047 conffile
= '25-activation-policy.network'
3048 units
= [ '11-dummy.netdev' , '12-dummy.netdev' , '12-dummy.network' , conffile
]
3050 units
+= [ f
' {conffile} .d/ {policy} .conf' ]
3052 units
+= [ f
' {conffile} .d/required- {required} .conf' ]
3053 copy_network_unit (* units
, copy_dropins
= False )
3056 if policy
. endswith ( 'down' ):
3057 self
. wait_activated ( 'test1' )
3059 if policy
. endswith ( 'down' ) or policy
== 'manual' :
3060 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
3062 self
. wait_online ([ 'test1' ])
3064 if policy
== 'always-down' :
3065 # if always-down, required for online is forced to no
3068 # otherwise if required for online is specified, it should match that
3069 expected
= required
== 'yes'
3071 # otherwise if only policy specified, required for online defaults to
3072 # true if policy is up, always-up, or bound
3073 expected
= policy
. endswith ( 'up' ) or policy
== 'bound'
3075 # default is true, if neither are specified
3078 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
3081 yesno
= 'yes' if expected
else 'no'
3082 self
. assertRegex ( output
, f
'Required For Online: {yesno} ' )
3084 def test_activation_policy_required_for_online ( self
):
3086 for policy
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , 'bound' , '' ]:
3087 for required
in [ 'yes' , 'no' , '' ]:
3093 print ( f
'### test_activation_policy_required_for_online(policy= {policy} , required= {required} )' )
3094 with self
. subTest ( policy
= policy
, required
= required
):
3095 self
._ test
_ activation
_ policy
_ required
_ for
_ online
( policy
, required
)
3097 def test_domain ( self
):
3098 copy_network_unit ( '12-dummy.netdev' , '24-search-domain.network' )
3100 self
. wait_online ([ 'dummy98:routable' ])
3102 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
3104 self
. assertRegex ( output
, 'Address: 192.168.42.100' )
3105 self
. assertRegex ( output
, 'DNS: 192.168.42.1' )
3106 self
. assertRegex ( output
, 'Search Domains: one' )
3108 def test_keep_configuration_static ( self
):
3109 check_output ( 'ip link add name dummy98 type dummy' )
3110 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
3111 check_output ( 'ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500' )
3112 output
= check_output ( 'ip address show dummy98' )
3114 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
3115 self
. assertRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
3116 output
= check_output ( 'ip route show dev dummy98' )
3119 copy_network_unit ( '24-keep-configuration-static.network' )
3121 self
. wait_online ([ 'dummy98:routable' ])
3123 output
= check_output ( 'ip address show dummy98' )
3125 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
3126 self
. assertNotRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
3128 @expectedFailureIfNexthopIsNotAvailable ()
3129 def test_nexthop ( self
):
3130 def check_nexthop ( self
):
3131 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
3133 output
= check_output ( 'ip nexthop list dev veth99' )
3135 self
. assertIn ( 'id 1 via 192.168.5.1 dev veth99' , output
)
3136 self
. assertIn ( 'id 2 via 2001:1234:5:8f63::2 dev veth99' , output
)
3137 self
. assertIn ( 'id 3 dev veth99' , output
)
3138 self
. assertIn ( 'id 4 dev veth99' , output
)
3139 self
. assertRegex ( output
, 'id 5 via 192.168.10.1 dev veth99 .*onlink' )
3140 self
. assertIn ( 'id 8 via fe80:0:222:4dff:ff:ff:ff:ff dev veth99' , output
)
3141 self
. assertRegex ( output
, r
'id [0-9]* via 192.168.5.2 dev veth99' )
3143 output
= check_output ( 'ip nexthop list dev dummy98' )
3145 self
. assertIn ( 'id 20 via 192.168.20.1 dev dummy98' , output
)
3147 # kernel manages blackhole nexthops on lo
3148 output
= check_output ( 'ip nexthop list dev lo' )
3150 self
. assertIn ( 'id 6 blackhole' , output
)
3151 self
. assertIn ( 'id 7 blackhole' , output
)
3153 # group nexthops are shown with -0 option
3154 output
= check_output ( 'ip -0 nexthop list id 21' )
3156 self
. assertRegex ( output
, r
'id 21 group (1,3/20|20/1,3)' )
3158 output
= check_output ( 'ip route show dev veth99 10.10.10.10' )
3160 self
. assertEqual ( '10.10.10.10 nhid 1 via 192.168.5.1 proto static' , output
)
3162 output
= check_output ( 'ip route show dev veth99 10.10.10.11' )
3164 self
. assertEqual ( '10.10.10.11 nhid 2 via inet6 2001:1234:5:8f63::2 proto static' , output
)
3166 output
= check_output ( 'ip route show dev veth99 10.10.10.12' )
3168 self
. assertEqual ( '10.10.10.12 nhid 5 via 192.168.10.1 proto static onlink' , output
)
3170 output
= check_output ( 'ip -6 route show dev veth99 2001:1234:5:8f62::1' )
3172 self
. assertEqual ( '2001:1234:5:8f62::1 nhid 2 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium' , output
)
3174 output
= check_output ( 'ip route show 10.10.10.13' )
3176 self
. assertEqual ( 'blackhole 10.10.10.13 nhid 6 dev lo proto static' , output
)
3178 output
= check_output ( 'ip -6 route show 2001:1234:5:8f62::2' )
3180 self
. assertEqual ( 'blackhole 2001:1234:5:8f62::2 nhid 7 dev lo proto static metric 1024 pref medium' , output
)
3182 output
= check_output ( 'ip route show 10.10.10.14' )
3184 self
. assertIn ( '10.10.10.14 nhid 21 proto static' , output
)
3185 self
. assertIn ( 'nexthop via 192.168.20.1 dev dummy98 weight 1' , output
)
3186 self
. assertIn ( 'nexthop via 192.168.5.1 dev veth99 weight 3' , output
)
3188 # TODO: check json string
3189 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3191 copy_network_unit ( '25-nexthop.network' , '25-veth.netdev' , '25-veth-peer.network' ,
3192 '12-dummy.netdev' , '25-nexthop-dummy.network' )
3197 remove_network_unit ( '25-nexthop.network' )
3198 copy_network_unit ( '25-nexthop-nothing.network' )
3200 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
3202 output
= check_output ( 'ip nexthop list dev veth99' )
3204 self
. assertEqual ( output
, '' )
3205 output
= check_output ( 'ip nexthop list dev lo' )
3207 self
. assertEqual ( output
, '' )
3209 remove_network_unit ( '25-nexthop-nothing.network' )
3210 copy_network_unit ( '25-nexthop.network' )
3211 networkctl_reconfigure ( 'dummy98' )
3216 remove_link ( 'veth99' )
3219 output
= check_output ( 'ip nexthop list dev lo' )
3221 self
. assertEqual ( output
, '' )
3223 class NetworkdTCTests ( unittest
. TestCase
, Utilities
):
3231 @expectedFailureIfModuleIsNotAvailable ( 'sch_cake' )
3232 def test_qdisc_cake ( self
):
3233 copy_network_unit ( '25-qdisc-cake.network' , '12-dummy.netdev' )
3235 self
. wait_online ([ 'dummy98:routable' ])
3237 output
= check_output ( 'tc qdisc show dev dummy98' )
3239 self
. assertIn ( 'qdisc cake 3a: root' , output
)
3240 self
. assertIn ( 'bandwidth 500Mbit' , output
)
3241 self
. assertIn ( 'autorate-ingress' , output
)
3242 self
. assertIn ( 'diffserv8' , output
)
3243 self
. assertIn ( 'dual-dsthost' , output
)
3244 self
. assertIn ( ' nat' , output
)
3245 self
. assertIn ( ' wash' , output
)
3246 self
. assertIn ( ' split-gso' , output
)
3247 self
. assertIn ( ' raw' , output
)
3248 self
. assertIn ( ' atm' , output
)
3249 self
. assertIn ( 'overhead 128' , output
)
3250 self
. assertIn ( 'mpu 20' , output
)
3251 self
. assertIn ( 'fwmark 0xff00' , output
)
3253 @expectedFailureIfModuleIsNotAvailable ( 'sch_codel' )
3254 def test_qdisc_codel ( self
):
3255 copy_network_unit ( '25-qdisc-codel.network' , '12-dummy.netdev' )
3257 self
. wait_online ([ 'dummy98:routable' ])
3259 output
= check_output ( 'tc qdisc show dev dummy98' )
3261 self
. assertRegex ( output
, 'qdisc codel 33: root' )
3262 self
. assertRegex ( output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn' )
3264 @expectedFailureIfModuleIsNotAvailable ( 'sch_drr' )
3265 def test_qdisc_drr ( self
):
3266 copy_network_unit ( '25-qdisc-drr.network' , '12-dummy.netdev' )
3268 self
. wait_online ([ 'dummy98:routable' ])
3270 output
= check_output ( 'tc qdisc show dev dummy98' )
3272 self
. assertRegex ( output
, 'qdisc drr 2: root' )
3273 output
= check_output ( 'tc class show dev dummy98' )
3275 self
. assertRegex ( output
, 'class drr 2:30 root quantum 2000b' )
3277 @expectedFailureIfModuleIsNotAvailable ( 'sch_ets' )
3278 def test_qdisc_ets ( self
):
3279 copy_network_unit ( '25-qdisc-ets.network' , '12-dummy.netdev' )
3281 self
. wait_online ([ 'dummy98:routable' ])
3283 output
= check_output ( 'tc qdisc show dev dummy98' )
3286 self
. assertRegex ( output
, 'qdisc ets 3a: root' )
3287 self
. assertRegex ( output
, 'bands 10 strict 3' )
3288 self
. assertRegex ( output
, 'quanta 1 2 3 4 5' )
3289 self
. assertRegex ( output
, 'priomap 3 4 5 6 7' )
3291 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq' )
3292 def test_qdisc_fq ( self
):
3293 copy_network_unit ( '25-qdisc-fq.network' , '12-dummy.netdev' )
3295 self
. wait_online ([ 'dummy98:routable' ])
3297 output
= check_output ( 'tc qdisc show dev dummy98' )
3299 self
. assertRegex ( output
, 'qdisc fq 32: root' )
3300 self
. assertRegex ( output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511' )
3301 self
. assertRegex ( output
, 'quantum 1500' )
3302 self
. assertRegex ( output
, 'initial_quantum 13000' )
3303 self
. assertRegex ( output
, 'maxrate 1Mbit' )
3305 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_codel' )
3306 def test_qdisc_fq_codel ( self
):
3307 copy_network_unit ( '25-qdisc-fq_codel.network' , '12-dummy.netdev' )
3309 self
. wait_online ([ 'dummy98:routable' ])
3311 output
= check_output ( 'tc qdisc show dev dummy98' )
3313 self
. assertRegex ( output
, 'qdisc fq_codel 34: root' )
3314 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' )
3316 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_pie' )
3317 def test_qdisc_fq_pie ( self
):
3318 copy_network_unit ( '25-qdisc-fq_pie.network' , '12-dummy.netdev' )
3320 self
. wait_online ([ 'dummy98:routable' ])
3322 output
= check_output ( 'tc qdisc show dev dummy98' )
3325 self
. assertRegex ( output
, 'qdisc fq_pie 3a: root' )
3326 self
. assertRegex ( output
, 'limit 200000p' )
3328 @expectedFailureIfModuleIsNotAvailable ( 'sch_gred' )
3329 def test_qdisc_gred ( self
):
3330 copy_network_unit ( '25-qdisc-gred.network' , '12-dummy.netdev' )
3332 self
. wait_online ([ 'dummy98:routable' ])
3334 output
= check_output ( 'tc qdisc show dev dummy98' )
3336 self
. assertRegex ( output
, 'qdisc gred 38: root' )
3337 self
. assertRegex ( output
, 'vqs 12 default 10 grio' )
3339 @expectedFailureIfModuleIsNotAvailable ( 'sch_hhf' )
3340 def test_qdisc_hhf ( self
):
3341 copy_network_unit ( '25-qdisc-hhf.network' , '12-dummy.netdev' )
3343 self
. wait_online ([ 'dummy98:routable' ])
3345 output
= check_output ( 'tc qdisc show dev dummy98' )
3347 self
. assertRegex ( output
, 'qdisc hhf 3a: root' )
3348 self
. assertRegex ( output
, 'limit 1022p' )
3350 @expectedFailureIfModuleIsNotAvailable ( 'sch_htb' )
3351 def test_qdisc_htb_fifo ( self
):
3352 copy_network_unit ( '25-qdisc-htb-fifo.network' , '12-dummy.netdev' )
3354 self
. wait_online ([ 'dummy98:routable' ])
3356 output
= check_output ( 'tc qdisc show dev dummy98' )
3358 self
. assertRegex ( output
, 'qdisc htb 2: root' )
3359 self
. assertRegex ( output
, r
'default (0x30|30)' )
3361 self
. assertRegex ( output
, 'qdisc pfifo 37: parent 2:37' )
3362 self
. assertRegex ( output
, 'limit 100000p' )
3364 self
. assertRegex ( output
, 'qdisc bfifo 3a: parent 2:3a' )
3365 self
. assertRegex ( output
, 'limit 1000000' )
3367 self
. assertRegex ( output
, 'qdisc pfifo_head_drop 3b: parent 2:3b' )
3368 self
. assertRegex ( output
, 'limit 1023p' )
3370 self
. assertRegex ( output
, 'qdisc pfifo_fast 3c: parent 2:3c' )
3372 output
= check_output ( 'tc -d class show dev dummy98' )
3374 self
. assertRegex ( output
, 'class htb 2:37 root leaf 37:' )
3375 self
. assertRegex ( output
, 'class htb 2:3a root leaf 3a:' )
3376 self
. assertRegex ( output
, 'class htb 2:3b root leaf 3b:' )
3377 self
. assertRegex ( output
, 'class htb 2:3c root leaf 3c:' )
3378 self
. assertRegex ( output
, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit' )
3379 self
. assertRegex ( output
, 'burst 123456' )
3380 self
. assertRegex ( output
, 'cburst 123457' )
3382 @expectedFailureIfModuleIsNotAvailable ( 'sch_ingress' )
3383 def test_qdisc_ingress ( self
):
3384 copy_network_unit ( '25-qdisc-clsact.network' , '12-dummy.netdev' ,
3385 '25-qdisc-ingress.network' , '11-dummy.netdev' )
3387 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' ])
3389 output
= check_output ( 'tc qdisc show dev dummy98' )
3391 self
. assertRegex ( output
, 'qdisc clsact' )
3393 output
= check_output ( 'tc qdisc show dev test1' )
3395 self
. assertRegex ( output
, 'qdisc ingress' )
3397 @expectedFailureIfModuleIsNotAvailable ( 'sch_netem' )
3398 def test_qdisc_netem ( self
):
3399 copy_network_unit ( '25-qdisc-netem.network' , '12-dummy.netdev' ,
3400 '25-qdisc-netem-compat.network' , '11-dummy.netdev' )
3402 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' ])
3404 output
= check_output ( 'tc qdisc show dev dummy98' )
3406 self
. assertRegex ( output
, 'qdisc netem 30: root' )
3407 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
3409 output
= check_output ( 'tc qdisc show dev test1' )
3411 self
. assertRegex ( output
, 'qdisc netem [0-9a-f]*: root' )
3412 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
3414 @expectedFailureIfModuleIsNotAvailable ( 'sch_pie' )
3415 def test_qdisc_pie ( self
):
3416 copy_network_unit ( '25-qdisc-pie.network' , '12-dummy.netdev' )
3418 self
. wait_online ([ 'dummy98:routable' ])
3420 output
= check_output ( 'tc qdisc show dev dummy98' )
3422 self
. assertRegex ( output
, 'qdisc pie 3a: root' )
3423 self
. assertRegex ( output
, 'limit 200000' )
3425 @expectedFailureIfModuleIsNotAvailable ( 'sch_qfq' )
3426 def test_qdisc_qfq ( self
):
3427 copy_network_unit ( '25-qdisc-qfq.network' , '12-dummy.netdev' )
3429 self
. wait_online ([ 'dummy98:routable' ])
3431 output
= check_output ( 'tc qdisc show dev dummy98' )
3433 self
. assertRegex ( output
, 'qdisc qfq 2: root' )
3434 output
= check_output ( 'tc class show dev dummy98' )
3436 self
. assertRegex ( output
, 'class qfq 2:30 root weight 2 maxpkt 16000' )
3437 self
. assertRegex ( output
, 'class qfq 2:31 root weight 10 maxpkt 8000' )
3439 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfb' )
3440 def test_qdisc_sfb ( self
):
3441 copy_network_unit ( '25-qdisc-sfb.network' , '12-dummy.netdev' )
3443 self
. wait_online ([ 'dummy98:routable' ])
3445 output
= check_output ( 'tc qdisc show dev dummy98' )
3447 self
. assertRegex ( output
, 'qdisc sfb 39: root' )
3448 self
. assertRegex ( output
, 'limit 200000' )
3450 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfq' )
3451 def test_qdisc_sfq ( self
):
3452 copy_network_unit ( '25-qdisc-sfq.network' , '12-dummy.netdev' )
3454 self
. wait_online ([ 'dummy98:routable' ])
3456 output
= check_output ( 'tc qdisc show dev dummy98' )
3458 self
. assertRegex ( output
, 'qdisc sfq 36: root' )
3459 self
. assertRegex ( output
, 'perturb 5sec' )
3461 @expectedFailureIfModuleIsNotAvailable ( 'sch_tbf' )
3462 def test_qdisc_tbf ( self
):
3463 copy_network_unit ( '25-qdisc-tbf.network' , '12-dummy.netdev' )
3465 self
. wait_online ([ 'dummy98:routable' ])
3467 output
= check_output ( 'tc qdisc show dev dummy98' )
3469 self
. assertRegex ( output
, 'qdisc tbf 35: root' )
3470 self
. assertRegex ( output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms' )
3472 @expectedFailureIfModuleIsNotAvailable ( 'sch_teql' )
3473 def test_qdisc_teql ( self
):
3474 call_quiet ( 'rmmod sch_teql' )
3476 copy_network_unit ( '25-qdisc-teql.network' , '12-dummy.netdev' )
3478 self
. wait_links ( 'dummy98' )
3479 check_output ( 'modprobe sch_teql max_equalizers=2' )
3480 self
. wait_online ([ 'dummy98:routable' ])
3482 output
= check_output ( 'tc qdisc show dev dummy98' )
3484 self
. assertRegex ( output
, 'qdisc teql1 31: root' )
3486 class NetworkWaitOnlineTests ( unittest
. TestCase
, Utilities
):
3494 def test_wait_online_ipv4 ( self
):
3495 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-with-ipv6-prefix.network' , '25-dhcp-client-ipv4-ipv6ra-prefix-client-with-delay.network' )
3498 self
. wait_online ([ 'veth99:routable' ], ipv4
= True )
3500 self
. wait_address ( 'veth99' , r
'192.168.5.[0-9]+' , ipv
= '-4' , timeout_sec
= 1 )
3502 def test_wait_online_ipv6 ( self
):
3503 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix-with-delay.network' , '25-ipv6ra-prefix-client-with-static-ipv4-address.network' )
3506 self
. wait_online ([ 'veth99:routable' ], ipv6
= True )
3508 self
. wait_address ( 'veth99' , r
'2002:da8:1:0:1034:56ff:fe78:9abc' , ipv
= '-6' , timeout_sec
= 1 )
3510 class NetworkdStateFileTests ( unittest
. TestCase
, Utilities
):
3518 def test_state_file ( self
):
3519 copy_network_unit ( '12-dummy.netdev' , '25-state-file-tests.network' )
3521 self
. wait_online ([ 'dummy98:routable' ])
3523 # make link state file updated
3524 check_output (* resolvectl_cmd
, 'revert' , 'dummy98' , env
= env
)
3526 # TODO: check json string
3527 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3529 output
= read_link_state_file ( 'dummy98' )
3531 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
3532 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
3533 self
. assertIn ( 'ADMIN_STATE=configured' , output
)
3534 self
. assertIn ( 'OPER_STATE=routable' , output
)
3535 self
. assertIn ( 'REQUIRED_FOR_ONLINE=yes' , output
)
3536 self
. assertIn ( 'REQUIRED_OPER_STATE_FOR_ONLINE=routable' , output
)
3537 self
. assertIn ( 'REQUIRED_FAMILY_FOR_ONLINE=both' , output
)
3538 self
. assertIn ( 'ACTIVATION_POLICY=up' , output
)
3539 self
. assertIn ( 'NETWORK_FILE=/run/systemd/network/25-state-file-tests.network' , output
)
3540 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
3541 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
3542 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
3543 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
3544 self
. assertIn ( 'LLMNR=no' , output
)
3545 self
. assertIn ( 'MDNS=yes' , output
)
3546 self
. assertIn ( 'DNSSEC=no' , output
)
3548 check_output (* resolvectl_cmd
, 'dns' , 'dummy98' , '10.10.10.12#ccc.com' , '10.10.10.13' , '1111:2222::3333' , env
= env
)
3549 check_output (* resolvectl_cmd
, 'domain' , 'dummy98' , 'hogehogehoge' , '~foofoofoo' , env
= env
)
3550 check_output (* resolvectl_cmd
, 'llmnr' , 'dummy98' , 'yes' , env
= env
)
3551 check_output (* resolvectl_cmd
, 'mdns' , 'dummy98' , 'no' , env
= env
)
3552 check_output (* resolvectl_cmd
, 'dnssec' , 'dummy98' , 'yes' , env
= env
)
3553 check_output (* timedatectl_cmd
, 'ntp-servers' , 'dummy98' , '2.fedora.pool.ntp.org' , '3.fedora.pool.ntp.org' , env
= env
)
3555 # TODO: check json string
3556 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3558 output
= read_link_state_file ( 'dummy98' )
3560 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
3561 self
. assertIn ( 'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org' , output
)
3562 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
3563 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
3564 self
. assertIn ( 'LLMNR=yes' , output
)
3565 self
. assertIn ( 'MDNS=no' , output
)
3566 self
. assertIn ( 'DNSSEC=yes' , output
)
3568 check_output (* timedatectl_cmd
, 'revert' , 'dummy98' , env
= env
)
3570 # TODO: check json string
3571 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3573 output
= read_link_state_file ( 'dummy98' )
3575 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
3576 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
3577 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
3578 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
3579 self
. assertIn ( 'LLMNR=yes' , output
)
3580 self
. assertIn ( 'MDNS=no' , output
)
3581 self
. assertIn ( 'DNSSEC=yes' , output
)
3583 check_output (* resolvectl_cmd
, 'revert' , 'dummy98' , env
= env
)
3585 # TODO: check json string
3586 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3588 output
= read_link_state_file ( 'dummy98' )
3590 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
3591 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
3592 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
3593 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
3594 self
. assertIn ( 'LLMNR=no' , output
)
3595 self
. assertIn ( 'MDNS=yes' , output
)
3596 self
. assertIn ( 'DNSSEC=no' , output
)
3598 class NetworkdBondTests ( unittest
. TestCase
, Utilities
):
3606 def test_bond_keep_master ( self
):
3607 check_output ( 'ip link add bond199 type bond mode active-backup' )
3608 check_output ( 'ip link add dummy98 type dummy' )
3609 check_output ( 'ip link set dummy98 master bond199' )
3611 copy_network_unit ( '23-keep-master.network' )
3613 self
. wait_online ([ 'dummy98:enslaved' ])
3615 output
= check_output ( 'ip -d link show bond199' )
3617 self
. assertRegex ( output
, 'active_slave dummy98' )
3619 output
= check_output ( 'ip -d link show dummy98' )
3621 self
. assertRegex ( output
, 'master bond199' )
3623 def test_bond_active_slave ( self
):
3624 copy_network_unit ( '23-active-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
3626 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
3628 output
= check_output ( 'ip -d link show bond199' )
3630 self
. assertRegex ( output
, 'active_slave dummy98' )
3632 def test_bond_primary_slave ( self
):
3633 copy_network_unit ( '23-primary-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
3635 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
3637 output
= check_output ( 'ip -d link show bond199' )
3639 self
. assertRegex ( output
, 'primary dummy98' )
3641 def test_bond_operstate ( self
):
3642 copy_network_unit ( '25-bond.netdev' , '11-dummy.netdev' , '12-dummy.netdev' ,
3643 '25-bond99.network' , '25-bond-slave.network' )
3645 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bond99:routable' ])
3647 output
= check_output ( 'ip -d link show dummy98' )
3649 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
3651 output
= check_output ( 'ip -d link show test1' )
3653 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
3655 output
= check_output ( 'ip -d link show bond99' )
3657 self
. assertRegex ( output
, 'MASTER,UP,LOWER_UP' )
3659 self
. wait_operstate ( 'dummy98' , 'enslaved' )
3660 self
. wait_operstate ( 'test1' , 'enslaved' )
3661 self
. wait_operstate ( 'bond99' , 'routable' )
3663 check_output ( 'ip link set dummy98 down' )
3665 self
. wait_operstate ( 'dummy98' , 'off' )
3666 self
. wait_operstate ( 'test1' , 'enslaved' )
3667 self
. wait_operstate ( 'bond99' , 'degraded-carrier' )
3669 check_output ( 'ip link set dummy98 up' )
3671 self
. wait_operstate ( 'dummy98' , 'enslaved' )
3672 self
. wait_operstate ( 'test1' , 'enslaved' )
3673 self
. wait_operstate ( 'bond99' , 'routable' )
3675 check_output ( 'ip link set dummy98 down' )
3676 check_output ( 'ip link set test1 down' )
3678 self
. wait_operstate ( 'dummy98' , 'off' )
3679 self
. wait_operstate ( 'test1' , 'off' )
3681 if not self
. wait_operstate ( 'bond99' , 'no-carrier' , setup_timeout
= 30 , fail_assert
= False ):
3682 # Huh? Kernel does not recognize that all slave interfaces are down?
3683 # Let's confirm that networkd's operstate is consistent with ip's result.
3684 self
. assertNotRegex ( output
, 'NO-CARRIER' )
3686 class NetworkdBridgeTests ( unittest
. TestCase
, Utilities
):
3694 def test_bridge_vlan ( self
):
3695 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave.network' ,
3696 '26-bridge.netdev' , '26-bridge-vlan-master.network' )
3698 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' ])
3700 output
= check_output ( 'bridge vlan show dev test1' )
3702 self
. assertNotRegex ( output
, '4063' )
3703 for i
in range ( 4064 , 4095 ):
3704 self
. assertRegex ( output
, f
' {i} ' )
3705 self
. assertNotRegex ( output
, '4095' )
3707 output
= check_output ( 'bridge vlan show dev bridge99' )
3709 self
. assertNotRegex ( output
, '4059' )
3710 for i
in range ( 4060 , 4095 ):
3711 self
. assertRegex ( output
, f
' {i} ' )
3712 self
. assertNotRegex ( output
, '4095' )
3714 def test_bridge_vlan_issue_20373 ( self
):
3715 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave-issue-20373.network' ,
3716 '26-bridge-issue-20373.netdev' , '26-bridge-vlan-master-issue-20373.network' ,
3717 '21-vlan.netdev' , '21-vlan.network' )
3719 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' , 'vlan99:routable' ])
3721 output
= check_output ( 'bridge vlan show dev test1' )
3723 self
. assertIn ( '100 PVID Egress Untagged' , output
)
3724 self
. assertIn ( '560' , output
)
3725 self
. assertIn ( '600' , output
)
3727 output
= check_output ( 'bridge vlan show dev bridge99' )
3729 self
. assertIn ( '1 PVID Egress Untagged' , output
)
3730 self
. assertIn ( '100' , output
)
3731 self
. assertIn ( '600' , output
)
3733 def test_bridge_mdb ( self
):
3734 copy_network_unit ( '11-dummy.netdev' , '26-bridge-mdb-slave.network' ,
3735 '26-bridge.netdev' , '26-bridge-mdb-master.network' )
3737 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' ])
3739 output
= check_output ( 'bridge mdb show dev bridge99' )
3741 self
. assertRegex ( output
, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064' )
3742 self
. assertRegex ( output
, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065' )
3744 # Old kernel may not support bridge MDB entries on bridge master
3745 if call_quiet ( 'bridge mdb add dev bridge99 port bridge99 grp 224.0.1.3 temp vid 4068' ) == 0 :
3746 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp ff02:aaaa:fee5::1:4 temp *vid 4066' )
3747 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp 224.0.1.2 temp *vid 4067' )
3749 def test_bridge_keep_master ( self
):
3750 check_output ( 'ip link add bridge99 type bridge' )
3751 check_output ( 'ip link set bridge99 up' )
3752 check_output ( 'ip link add dummy98 type dummy' )
3753 check_output ( 'ip link set dummy98 master bridge99' )
3755 copy_network_unit ( '23-keep-master.network' )
3757 self
. wait_online ([ 'dummy98:enslaved' ])
3759 output
= check_output ( 'ip -d link show dummy98' )
3761 self
. assertRegex ( output
, 'master bridge99' )
3762 self
. assertRegex ( output
, 'bridge' )
3764 output
= check_output ( 'bridge -d link show dummy98' )
3766 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
3767 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
3768 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
3769 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
3770 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
3771 # CONFIG_BRIDGE_IGMP_SNOOPING=y
3772 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
3773 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
3774 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
3775 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
3776 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '1' )
3777 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '1' )
3779 def test_bridge_property ( self
):
3780 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
3781 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
3782 '25-bridge99.network' )
3784 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' ])
3786 output
= check_output ( 'ip -d link show test1' )
3788 self
. assertRegex ( output
, 'master' )
3789 self
. assertRegex ( output
, 'bridge' )
3791 output
= check_output ( 'ip -d link show dummy98' )
3793 self
. assertRegex ( output
, 'master' )
3794 self
. assertRegex ( output
, 'bridge' )
3796 output
= check_output ( 'ip addr show bridge99' )
3798 self
. assertRegex ( output
, '192.168.0.15/24' )
3800 output
= check_output ( 'bridge -d link show dummy98' )
3802 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
3803 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
3804 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'isolated' , '1' )
3805 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
3806 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
3807 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
3808 # CONFIG_BRIDGE_IGMP_SNOOPING=y
3809 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
3810 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
3811 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
3812 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
3813 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '1' )
3814 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '1' )
3816 output
= check_output ( 'bridge -d link show test1' )
3818 self
. check_bridge_port_attr ( 'bridge99' , 'test1' , 'priority' , '0' )
3820 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
3821 output
= check_output ( 'ip addr show bridge99' )
3823 self
. assertRegex ( output
, '192.168.0.16/24' )
3826 print ( '### ip -6 route list table all dev bridge99' )
3827 output
= check_output ( 'ip -6 route list table all dev bridge99' )
3829 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
3831 remove_link ( 'test1' )
3833 self
. wait_operstate ( 'bridge99' , 'degraded-carrier' )
3835 remove_link ( 'dummy98' )
3837 self
. wait_operstate ( 'bridge99' , 'no-carrier' )
3839 output
= check_output ( 'ip address show bridge99' )
3841 self
. assertRegex ( output
, 'NO-CARRIER' )
3842 self
. assertNotRegex ( output
, '192.168.0.15/24' )
3843 self
. assertRegex ( output
, '192.168.0.16/24' ) # foreign address is kept
3845 print ( '### ip -6 route list table all dev bridge99' )
3846 output
= check_output ( 'ip -6 route list table all dev bridge99' )
3848 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
3850 def test_bridge_configure_without_carrier ( self
):
3851 copy_network_unit ( '26-bridge.netdev' , '26-bridge-configure-without-carrier.network' ,
3855 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
3856 for test
in [ 'no-slave' , 'add-slave' , 'slave-up' , 'slave-no-carrier' , 'slave-carrier' , 'slave-down' ]:
3857 with self
. subTest ( test
= test
):
3858 if test
== 'no-slave' :
3859 # bridge has no slaves; it's up but *might* not have carrier
3860 self
. wait_operstate ( 'bridge99' , operstate
= r
'(no-carrier|routable)' , setup_state
= None , setup_timeout
= 30 )
3861 # due to a bug in the kernel, newly-created bridges are brought up
3862 # *with* carrier, unless they have had any setting changed; e.g.
3863 # their mac set, priority set, etc. Then, they will lose carrier
3864 # as soon as a (down) slave interface is added, and regain carrier
3865 # again once the slave interface is brought up.
3866 #self.check_link_attr('bridge99', 'carrier', '0')
3867 elif test
== 'add-slave' :
3868 # add slave to bridge, but leave it down; bridge is definitely no-carrier
3869 self
. check_link_attr ( 'test1' , 'operstate' , 'down' )
3870 check_output ( 'ip link set dev test1 master bridge99' )
3871 self
. wait_operstate ( 'bridge99' , operstate
= 'no-carrier' , setup_state
= None )
3872 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
3873 elif test
== 'slave-up' :
3874 # bring up slave, which will have carrier; bridge gains carrier
3875 check_output ( 'ip link set dev test1 up' )
3876 self
. wait_online ([ 'bridge99:routable' ])
3877 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
3878 elif test
== 'slave-no-carrier' :
3879 # drop slave carrier; bridge loses carrier
3880 check_output ( 'ip link set dev test1 carrier off' )
3881 self
. wait_online ([ 'bridge99:no-carrier:no-carrier' ])
3882 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
3883 elif test
== 'slave-carrier' :
3884 # restore slave carrier; bridge gains carrier
3885 check_output ( 'ip link set dev test1 carrier on' )
3886 self
. wait_online ([ 'bridge99:routable' ])
3887 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
3888 elif test
== 'slave-down' :
3889 # bring down slave; bridge loses carrier
3890 check_output ( 'ip link set dev test1 down' )
3891 self
. wait_online ([ 'bridge99:no-carrier:no-carrier' ])
3892 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
3894 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bridge99' , env
= env
)
3895 self
. assertRegex ( output
, '10.1.2.3' )
3896 self
. assertRegex ( output
, '10.1.2.1' )
3898 def test_bridge_ignore_carrier_loss ( self
):
3899 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
3900 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
3901 '25-bridge99-ignore-carrier-loss.network' )
3903 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' ])
3905 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
3906 remove_link ( 'test1' , 'dummy98' )
3909 output
= check_output ( 'ip address show bridge99' )
3911 self
. assertRegex ( output
, 'NO-CARRIER' )
3912 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
3913 self
. assertRegex ( output
, 'inet 192.168.0.16/24 scope global secondary bridge99' )
3915 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain ( self
):
3916 copy_network_unit ( '26-bridge.netdev' , '26-bridge-slave-interface-1.network' ,
3917 '25-bridge99-ignore-carrier-loss.network' )
3919 self
. wait_online ([ 'bridge99:no-carrier' ])
3921 for trial
in range ( 4 ):
3922 check_output ( 'ip link add dummy98 type dummy' )
3923 check_output ( 'ip link set dummy98 up' )
3925 remove_link ( 'dummy98' )
3927 self
. wait_online ([ 'bridge99:routable' , 'dummy98:enslaved' ])
3929 output
= check_output ( 'ip address show bridge99' )
3931 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
3933 output
= check_output ( 'ip rule list table 100' )
3935 self
. assertIn ( 'from all to 8.8.8.8 lookup 100' , output
)
3937 class NetworkdSRIOVTests ( unittest
. TestCase
, Utilities
):
3945 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
3946 def test_sriov ( self
):
3947 call ( 'modprobe netdevsim' )
3949 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
3952 with
open ( '/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
3955 copy_network_unit ( '25-sriov.network' )
3957 self
. wait_online ([ 'eni99np1:routable' ])
3959 output
= check_output ( 'ip link show dev eni99np1' )
3961 self
. assertRegex ( output
,
3962 '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 *'
3963 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
3964 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
3967 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
3968 def test_sriov_udev ( self
):
3969 copy_network_unit ( '25-sriov.link' , '25-sriov-udev.network' )
3971 call ( 'modprobe netdevsim' )
3973 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
3977 self
. wait_online ([ 'eni99np1:routable' ])
3979 output
= check_output ( 'ip link show dev eni99np1' )
3981 self
. assertRegex ( output
,
3982 '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 *'
3983 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
3984 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
3986 self
. assertNotIn ( 'vf 3' , output
)
3987 self
. assertNotIn ( 'vf 4' , output
)
3989 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
3990 f
. write ( '[Link] \n SR-IOVVirtualFunctions=4 \n ' )
3993 call (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , '/sys/devices/netdevsim99/net/eni99np1' )
3995 output
= check_output ( 'ip link show dev eni99np1' )
3997 self
. assertRegex ( output
,
3998 '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 *'
3999 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4000 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
4003 self
. assertNotIn ( 'vf 4' , output
)
4005 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4006 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
4009 call (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , '/sys/devices/netdevsim99/net/eni99np1' )
4011 output
= check_output ( 'ip link show dev eni99np1' )
4013 self
. assertRegex ( output
,
4014 '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 *'
4015 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4016 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
4019 self
. assertNotIn ( 'vf 4' , output
)
4021 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4022 f
. write ( '[Link] \n SR-IOVVirtualFunctions=2 \n ' )
4025 call (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , '/sys/devices/netdevsim99/net/eni99np1' )
4027 output
= check_output ( 'ip link show dev eni99np1' )
4029 self
. assertRegex ( output
,
4030 '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 *'
4031 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off'
4033 self
. assertNotIn ( 'vf 2' , output
)
4034 self
. assertNotIn ( 'vf 3' , output
)
4035 self
. assertNotIn ( 'vf 4' , output
)
4037 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4038 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
4041 call (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , '/sys/devices/netdevsim99/net/eni99np1' )
4043 output
= check_output ( 'ip link show dev eni99np1' )
4045 self
. assertRegex ( output
,
4046 '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 *'
4047 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4048 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4050 self
. assertNotIn ( 'vf 3' , output
)
4051 self
. assertNotIn ( 'vf 4' , output
)
4053 class NetworkdLLDPTests ( unittest
. TestCase
, Utilities
):
4061 def test_lldp ( self
):
4062 copy_network_unit ( '23-emit-lldp.network' , '24-lldp.network' , '25-veth.netdev' )
4064 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:degraded' ])
4066 for trial
in range ( 10 ):
4070 output
= check_output (* networkctl_cmd
, 'lldp' , env
= env
)
4072 if re
. search ( r
'veth99 .* veth-peer' , output
):
4077 class NetworkdRATests ( unittest
. TestCase
, Utilities
):
4085 def test_ipv6_prefix_delegation ( self
):
4086 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth.network' )
4088 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4090 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth99' , env
= env
)
4092 self
. assertRegex ( output
, 'fe80::' )
4093 self
. assertRegex ( output
, '2002:da8:1::1' )
4095 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth99' , env
= env
)
4097 self
. assertIn ( 'hogehoge.test' , output
)
4099 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4101 self
. assertRegex ( output
, '2002:da8:1:0' )
4103 def test_ipv6_token_static ( self
):
4104 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-static.network' )
4106 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4108 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4110 self
. assertRegex ( output
, '2002:da8:1:0:1a:2b:3c:4d' )
4111 self
. assertRegex ( output
, '2002:da8:1:0:fa:de:ca:fe' )
4112 self
. assertRegex ( output
, '2002:da8:2:0:1a:2b:3c:4d' )
4113 self
. assertRegex ( output
, '2002:da8:2:0:fa:de:ca:fe' )
4115 def test_ipv6_token_prefixstable ( self
):
4116 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable.network' )
4118 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4120 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4122 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
4123 self
. assertIn ( '2002:da8:2:0:1034:56ff:fe78:9abc' , output
) # EUI64
4125 def test_ipv6_token_prefixstable_without_address ( self
):
4126 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable-without-address.network' )
4128 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4130 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4132 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
4133 self
. assertIn ( '2002:da8:2:0:f689:561a:8eda:7443' , output
)
4135 class NetworkdDHCPServerTests ( unittest
. TestCase
, Utilities
):
4143 def test_dhcp_server ( self
):
4144 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server.network' )
4146 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4148 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4150 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4151 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
4152 self
. assertRegex ( output
, 'DNS: 192.168.5.1 \n *192.168.5.10' )
4153 self
. assertRegex ( output
, 'NTP: 192.168.5.1 \n *192.168.5.11' )
4155 def test_dhcp_server_with_uplink ( self
):
4156 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-downstream.network' ,
4157 '12-dummy.netdev' , '25-dhcp-server-uplink.network' )
4159 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4161 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4163 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4164 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
4165 self
. assertIn ( 'DNS: 192.168.5.1' , output
)
4166 self
. assertIn ( 'NTP: 192.168.5.1' , output
)
4168 def test_emit_router_timezone ( self
):
4169 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-timezone-router.network' , '25-dhcp-server-timezone-router.network' )
4171 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4173 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4175 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4176 self
. assertIn ( 'Gateway: 192.168.5.1' , output
)
4177 self
. assertIn ( 'Time Zone: Europe/Berlin' , output
)
4179 def test_dhcp_server_static_lease ( self
):
4180 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-static-lease.network' , '25-dhcp-server-static-lease.network' )
4182 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4184 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4186 self
. assertIn ( 'Address: 10.1.1.200 (DHCP4 via 10.1.1.1)' , output
)
4188 class NetworkdDHCPServerRelayAgentTests ( unittest
. TestCase
, Utilities
):
4196 def test_relay_agent ( self
):
4197 copy_network_unit ( '25-agent-veth-client.netdev' ,
4198 '25-agent-veth-server.netdev' ,
4199 '25-agent-client.network' ,
4200 '25-agent-server.network' ,
4201 '25-agent-client-peer.network' ,
4202 '25-agent-server-peer.network' )
4205 self
. wait_online ([ 'client:routable' ])
4207 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'client' , env
= env
)
4209 self
. assertRegex ( output
, r
'Address: 192.168.5.150 \(DHCP4 via 192.168.5.1\)' )
4211 class NetworkdDHCPClientTests ( unittest
. TestCase
, Utilities
):
4219 def test_dhcp_client_ipv6_only ( self
):
4220 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv6-only.network' )
4223 self
. wait_online ([ 'veth-peer:carrier' ])
4225 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4228 output
= check_output ( 'ip address show dev veth99 scope global' )
4230 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
4231 self
. assertNotIn ( '192.168.5' , output
)
4233 # checking semi-static route
4234 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
4236 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
4238 # Confirm that ipv6 token is not set in the kernel
4239 output
= check_output ( 'ip token show dev veth99' )
4241 self
. assertRegex ( output
, 'token :: dev veth99' )
4243 print ( '## dnsmasq log' )
4244 output
= read_dnsmasq_log_file ()
4246 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
4247 self
. assertNotIn ( 'DHCPADVERTISE(veth-peer)' , output
)
4248 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
4249 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
4250 self
. assertIn ( 'sent size: 0 option: 14 rapid-commit' , output
)
4252 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-ipv6-only.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4253 f
. write ( ' \n [DHCPv6] \n RapidCommit=no \n ' )
4259 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4262 output
= check_output ( 'ip address show dev veth99 scope global' )
4264 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
4265 self
. assertNotIn ( '192.168.5' , output
)
4267 # checking semi-static route
4268 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
4270 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
4272 print ( '## dnsmasq log' )
4273 output
= read_dnsmasq_log_file ()
4275 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
4276 self
. assertIn ( 'DHCPADVERTISE(veth-peer)' , output
)
4277 self
. assertIn ( 'DHCPREQUEST(veth-peer)' , output
)
4278 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
4279 self
. assertNotIn ( 'rapid-commit' , output
)
4281 def test_dhcp_client_ipv4_only ( self
):
4282 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv4-only.network' )
4285 self
. wait_online ([ 'veth-peer:carrier' ])
4286 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7' ,
4287 '--dhcp-option=option:domain-search,example.com' ,
4288 '--dhcp-alternate-port=67,5555' ,
4289 ipv4_range
= '192.168.5.110,192.168.5.119' )
4290 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4292 print ( '## ip address show dev veth99 scope global' )
4293 output
= check_output ( 'ip address show dev veth99 scope global' )
4295 self
. assertIn ( 'mtu 1492' , output
)
4296 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
4297 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' )
4298 self
. assertNotIn ( '2600::' , output
)
4300 print ( '## ip route show table main dev veth99' )
4301 output
= check_output ( 'ip route show table main dev veth99' )
4303 # no DHCP routes assigned to the main table
4304 self
. assertNotIn ( 'proto dhcp' , output
)
4306 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
4307 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
4308 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
4309 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
4311 print ( '## ip route show table 211 dev veth99' )
4312 output
= check_output ( 'ip route show table 211 dev veth99' )
4314 self
. assertRegex ( output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.11[0-9] metric 24' )
4315 self
. assertRegex ( output
, '192.168.5.0/24 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4316 self
. assertRegex ( output
, '192.168.5.1 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4317 self
. assertRegex ( output
, '192.168.5.6 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4318 self
. assertRegex ( output
, '192.168.5.7 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4319 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
4321 print ( '## link state file' )
4322 output
= read_link_state_file ( 'veth99' )
4324 # checking DNS server and Domains
4325 self
. assertIn ( 'DNS=192.168.5.6 192.168.5.7' , output
)
4326 self
. assertIn ( 'DOMAINS=example.com' , output
)
4328 print ( '## dnsmasq log' )
4329 output
= read_dnsmasq_log_file ()
4331 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
4332 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc' , output
)
4333 self
. assertIn ( 'client provides name: test-hostname' , output
)
4334 self
. assertIn ( '26:mtu' , output
)
4336 # change address range, DNS servers, and Domains
4338 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8' ,
4339 '--dhcp-option=option:domain-search,foo.example.com' ,
4340 '--dhcp-alternate-port=67,5555' ,
4341 ipv4_range
= '192.168.5.120,192.168.5.129' ,)
4343 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4344 print ( 'Wait for the DHCP lease to be expired' )
4345 self
. wait_address_dropped ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' , timeout_sec
= 120 )
4346 self
. wait_address ( 'veth99' , r
'inet 192.168.5.12[0-9]*/24' , ipv
= '-4' )
4348 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4350 print ( '## ip address show dev veth99 scope global' )
4351 output
= check_output ( 'ip address show dev veth99 scope global' )
4353 self
. assertIn ( 'mtu 1492' , output
)
4354 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
4355 self
. assertNotIn ( '192.168.5.11' , output
)
4356 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' )
4357 self
. assertNotIn ( '2600::' , output
)
4359 print ( '## ip route show table main dev veth99' )
4360 output
= check_output ( 'ip route show table main dev veth99' )
4362 # no DHCP routes assigned to the main table
4363 self
. assertNotIn ( 'proto dhcp' , output
)
4365 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
4366 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
4367 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
4368 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
4370 print ( '## ip route show table 211 dev veth99' )
4371 output
= check_output ( 'ip route show table 211 dev veth99' )
4373 self
. assertRegex ( output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.12[0-9] metric 24' )
4374 self
. assertRegex ( output
, '192.168.5.0/24 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4375 self
. assertRegex ( output
, '192.168.5.1 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4376 self
. assertNotIn ( '192.168.5.6' , output
)
4377 self
. assertRegex ( output
, '192.168.5.7 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4378 self
. assertRegex ( output
, '192.168.5.8 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4379 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
4381 print ( '## link state file' )
4382 output
= read_link_state_file ( 'veth99' )
4384 # checking DNS server and Domains
4385 self
. assertIn ( 'DNS=192.168.5.1 192.168.5.7 192.168.5.8' , output
)
4386 self
. assertIn ( 'DOMAINS=foo.example.com' , output
)
4388 print ( '## dnsmasq log' )
4389 output
= read_dnsmasq_log_file ()
4391 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
4392 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 192.168.5.11' , output
)
4393 self
. assertIn ( 'client provides name: test-hostname' , output
)
4394 self
. assertIn ( '26:mtu' , output
)
4396 def test_dhcp_client_ipv4_use_routes_gateway ( self
):
4398 for ( routes
, gateway
, dns_and_ntp_routes
, classless
) in itertools
. product ([ True , False ], repeat
= 4 ):
4404 print ( f
'### test_dhcp_client_ipv4_use_routes_gateway(routes= {routes} , gateway= {gateway} , dns_and_ntp_routes= {dns_and_ntp_routes} , classless= {classless} )' )
4405 with self
. subTest ( routes
= routes
, gateway
= gateway
, dns_and_ntp_routes
= dns_and_ntp_routes
, classless
= classless
):
4406 self
._ test
_ dhcp
_ client
_ ipv
4_u se
_ routes
_ gateway
( routes
, gateway
, dns_and_ntp_routes
, classless
)
4408 def _test_dhcp_client_ipv4_use_routes_gateway ( self
, use_routes
, use_gateway
, dns_and_ntp_routes
, classless
):
4409 testunit
= '25-dhcp-client-ipv4-use-routes-use-gateway.network'
4410 testunits
= [ '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , testunit
]
4411 testunits
. append ( f
' {testunit} .d/use-routes- {use_routes} .conf' )
4412 testunits
. append ( f
' {testunit} .d/use-gateway- {use_gateway} .conf' )
4413 testunits
. append ( f
' {testunit} .d/use-dns-and-ntp-routes- {dns_and_ntp_routes} .conf' )
4414 copy_network_unit (* testunits
, copy_dropins
= False )
4417 self
. wait_online ([ 'veth-peer:carrier' ])
4418 additional_options
= [
4419 '--dhcp-option=option:dns-server,192.168.5.10,8.8.8.8' ,
4420 '--dhcp-option=option:ntp-server,192.168.5.11,9.9.9.9' ,
4421 '--dhcp-option=option:static-route,192.168.5.100,192.168.5.2,8.8.8.8,192.168.5.3'
4424 additional_options
+= [
4425 '--dhcp-option=option:classless-static-route,0.0.0.0/0,192.168.5.4,8.0.0.0/8,192.168.5.5'
4427 start_dnsmasq (* additional_options
)
4428 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4430 output
= check_output ( 'ip -4 route show dev veth99' )
4436 self
. assertRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4437 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4438 self
. assertRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4439 self
. assertRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4441 self
. assertRegex ( output
, r
'192.168.5.0/24 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4442 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4443 self
. assertRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4445 self
. assertNotRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4446 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4447 self
. assertNotRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4448 self
. assertNotRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4449 self
. assertNotRegex ( output
, r
'192.168.5.0/24 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4450 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4451 self
. assertNotRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4454 if use_gateway
and ( not classless
or not use_routes
):
4455 self
. assertRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4457 self
. assertNotRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4459 # Check route to gateway
4460 if ( use_gateway
or dns_and_ntp_routes
) and ( not classless
or not use_routes
):
4461 self
. assertRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4463 self
. assertNotRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4465 # Check RoutesToDNS= and RoutesToNTP=
4466 if dns_and_ntp_routes
:
4467 self
. assertRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4468 self
. assertRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4469 if classless
and use_routes
:
4470 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4471 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4473 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4474 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4476 self
. assertNotRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4477 self
. assertNotRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4478 self
. assertNotRegex ( output
, r
'8.8.8.8 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
4479 self
. assertNotRegex ( output
, r
'9.9.9.9 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
4481 # TODO: check json string
4482 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
4484 def test_dhcp_client_settings_anonymize ( self
):
4485 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-anonymize.network' )
4487 self
. wait_online ([ 'veth-peer:carrier' ])
4489 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4491 print ( '## dnsmasq log' )
4492 output
= read_dnsmasq_log_file ()
4494 self
. assertNotIn ( 'VendorClassIdentifier=SusantVendorTest' , output
)
4495 self
. assertNotIn ( 'test-hostname' , output
)
4496 self
. assertNotIn ( '26:mtu' , output
)
4498 def test_dhcp_keep_configuration_dhcp ( self
):
4499 copy_network_unit ( '25-veth.netdev' ,
4500 '25-dhcp-server-veth-peer.network' ,
4501 '25-dhcp-client-keep-configuration-dhcp.network' )
4503 self
. wait_online ([ 'veth-peer:carrier' ])
4505 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4507 output
= check_output ( 'ip address show dev veth99 scope global' )
4509 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4510 'valid_lft forever preferred_lft forever' )
4512 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
4515 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4516 print ( 'Wait for the DHCP lease to be expired' )
4519 # The lease address should be kept after the lease expired
4520 output
= check_output ( 'ip address show dev veth99 scope global' )
4522 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4523 'valid_lft forever preferred_lft forever' )
4527 # The lease address should be kept after networkd stopped
4528 output
= check_output ( 'ip address show dev veth99 scope global' )
4530 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4531 'valid_lft forever preferred_lft forever' )
4533 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-keep-configuration-dhcp.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4534 f
. write ( '[Network] \n DHCP=no \n ' )
4537 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4539 # Still the lease address should be kept after networkd restarted
4540 output
= check_output ( 'ip address show dev veth99 scope global' )
4542 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4543 'valid_lft forever preferred_lft forever' )
4545 def test_dhcp_keep_configuration_dhcp_on_stop ( self
):
4546 copy_network_unit ( '25-veth.netdev' ,
4547 '25-dhcp-server-veth-peer.network' ,
4548 '25-dhcp-client-keep-configuration-dhcp-on-stop.network' )
4550 self
. wait_online ([ 'veth-peer:carrier' ])
4552 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4554 output
= check_output ( 'ip address show dev veth99 scope global' )
4556 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
4561 output
= check_output ( 'ip address show dev veth99 scope global' )
4563 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
4566 self
. wait_online ([ 'veth-peer:routable' ])
4568 output
= check_output ( 'ip address show dev veth99 scope global' )
4570 self
. assertNotIn ( '192.168.5.' , output
)
4572 def test_dhcp_client_reuse_address_as_static ( self
):
4573 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' )
4575 self
. wait_online ([ 'veth-peer:carrier' ])
4577 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4579 # link become 'routable' when at least one protocol provide an valid address.
4580 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
4581 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
4583 output
= check_output ( 'ip address show dev veth99 scope global' )
4584 ipv4_address
= re
. search ( r
'192.168.5.[0-9]*/24' , output
). group ()
4585 ipv6_address
= re
. search ( r
'2600::[0-9a-f:]*/128' , output
). group ()
4586 static_network
= ' \n ' . join ([ '[Match]' , 'Name=veth99' , '[Network]' , 'IPv6AcceptRA=no' , 'Address=' + ipv4_address
, 'Address=' + ipv6_address
])
4587 print ( static_network
)
4589 remove_network_unit ( '25-dhcp-client.network' )
4591 with
open ( os
. path
. join ( network_unit_dir
, '25-static.network' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
4592 f
. write ( static_network
)
4595 self
. wait_online ([ 'veth99:routable' ])
4597 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
4599 self
. assertRegex ( output
, f
'inet {ipv4_address} brd 192.168.5.255 scope global veth99 \n *'
4600 'valid_lft forever preferred_lft forever' )
4602 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
4604 self
. assertRegex ( output
, f
'inet6 {ipv6_address} scope global * \n *'
4605 'valid_lft forever preferred_lft forever' )
4607 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
4608 def test_dhcp_client_vrf ( self
):
4609 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-vrf.network' ,
4610 '25-vrf.netdev' , '25-vrf.network' )
4612 self
. wait_online ([ 'veth-peer:carrier' ])
4614 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'vrf99:carrier' ])
4616 # link become 'routable' when at least one protocol provide an valid address.
4617 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
4618 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
4620 print ( '## ip -d link show dev vrf99' )
4621 output
= check_output ( 'ip -d link show dev vrf99' )
4623 self
. assertRegex ( output
, 'vrf table 42' )
4625 print ( '## ip address show vrf vrf99' )
4626 output
= check_output ( 'ip address show vrf vrf99' )
4628 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
4629 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
4630 self
. assertRegex ( output
, 'inet6 .* scope link' )
4632 print ( '## ip address show dev veth99' )
4633 output
= check_output ( 'ip address show dev veth99' )
4635 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
4636 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
4637 self
. assertRegex ( output
, 'inet6 .* scope link' )
4639 print ( '## ip route show vrf vrf99' )
4640 output
= check_output ( 'ip route show vrf vrf99' )
4642 self
. assertRegex ( output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.' )
4643 self
. assertRegex ( output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5' )
4644 self
. assertRegex ( output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5' )
4646 print ( '## ip route show table main dev veth99' )
4647 output
= check_output ( 'ip route show table main dev veth99' )
4649 self
. assertEqual ( output
, '' )
4651 def test_dhcp_client_gateway_onlink_implicit ( self
):
4652 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
4653 '25-dhcp-client-gateway-onlink-implicit.network' )
4655 self
. wait_online ([ 'veth-peer:carrier' ])
4657 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4659 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4661 self
. assertRegex ( output
, '192.168.5' )
4663 output
= check_output ( 'ip route list dev veth99 10.0.0.0/8' )
4665 self
. assertRegex ( output
, 'onlink' )
4666 output
= check_output ( 'ip route list dev veth99 192.168.100.0/24' )
4668 self
. assertRegex ( output
, 'onlink' )
4670 def test_dhcp_client_with_ipv4ll ( self
):
4671 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
4672 '25-dhcp-client-with-ipv4ll.network' )
4674 # we need to increase timeout above default, as this will need to wait for
4675 # systemd-networkd to get the dhcpv4 transient failure event
4676 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:routable' ], timeout
= '60s' )
4678 output
= check_output ( 'ip -4 address show dev veth99' )
4680 self
. assertNotIn ( '192.168.5.' , output
)
4681 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
4684 print ( 'Wait for a DHCP lease to be acquired and the IPv4LL address to be dropped' )
4685 self
. wait_address ( 'veth99' , r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic' , ipv
= '-4' )
4686 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' )
4687 self
. wait_online ([ 'veth99:routable' ])
4689 output
= check_output ( 'ip -4 address show dev veth99' )
4691 self
. assertRegex ( output
, r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99' )
4692 self
. assertNotIn ( '169.254.' , output
)
4693 self
. assertNotIn ( 'scope link' , output
)
4696 print ( 'Wait for the DHCP lease to be expired and an IPv4LL address to be acquired' )
4697 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 )
4698 self
. wait_address ( 'veth99' , r
'inet 169\.254\.133\.11/16 metric 2048 brd 169\.254\.255\.255 scope link' , scope
= 'link' , ipv
= '-4' )
4700 output
= check_output ( 'ip -4 address show dev veth99' )
4702 self
. assertNotIn ( '192.168.5.' , output
)
4703 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
4705 def test_dhcp_client_use_dns ( self
):
4706 def check ( self
, ipv4
, ipv6
):
4707 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
4708 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
4709 f
. write ( '[DHCPv4] \n UseDNS=' )
4710 f
. write ( 'yes' if ipv4
else 'no' )
4711 f
. write ( ' \n [DHCPv6] \n UseDNS=' )
4712 f
. write ( 'yes' if ipv6
else 'no' )
4713 f
. write ( ' \n [IPv6AcceptRA] \n UseDNS=no' )
4716 self
. wait_online ([ 'veth99:routable' ])
4718 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
4719 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
4720 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
4722 # make resolved re-read the link state file
4723 check_output (* resolvectl_cmd
, 'revert' , 'veth99' , env
= env
)
4725 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth99' , env
= env
)
4728 self
. assertIn ( '192.168.5.1' , output
)
4730 self
. assertNotIn ( '192.168.5.1' , output
)
4732 self
. assertIn ( '2600::1' , output
)
4734 self
. assertNotIn ( '2600::1' , output
)
4736 # TODO: check json string
4737 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
4739 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
4742 self
. wait_online ([ 'veth-peer:carrier' ])
4743 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1' ,
4744 '--dhcp-option=option6:dns-server,[2600::1]' )
4746 check ( self
, True , True )
4747 check ( self
, True , False )
4748 check ( self
, False , True )
4749 check ( self
, False , False )
4751 class NetworkdDHCPPDTests ( unittest
. TestCase
, Utilities
):
4759 def test_dhcp6pd ( self
):
4760 copy_network_unit ( '25-veth.netdev' , '25-dhcp6pd-server.network' , '25-dhcp6pd-upstream.network' ,
4761 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
4762 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
4763 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
4764 '25-dhcp-pd-downstream-dummy97.network' ,
4765 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
4766 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' )
4769 self
. wait_online ([ 'veth-peer:routable' ])
4770 start_isc_dhcpd ( conf_file
= 'isc-dhcpd-dhcp6pd.conf' , ipv
= '-6' )
4771 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
4772 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
4774 print ( '### ip -6 address show dev veth-peer scope global' )
4775 output
= check_output ( 'ip -6 address show dev veth-peer scope global' )
4777 self
. assertIn ( 'inet6 3ffe:501:ffff:100::1/64 scope global' , output
)
4781 # dummy97: 0x01 (The link will appear later)
4783 # dummy99: auto -> 0x02 (No address assignment)
4788 print ( '### ip -6 address show dev veth99 scope global' )
4789 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
4792 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:100::[0-9]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
4793 # address in IA_PD (Token=static)
4794 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic' )
4795 # address in IA_PD (Token=eui64)
4796 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic' )
4797 # address in IA_PD (temporary)
4798 # Note that the temporary addresses may appear after the link enters configured state
4799 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' )
4801 print ( '### ip -6 address show dev test1 scope global' )
4802 output
= check_output ( 'ip -6 address show dev test1 scope global' )
4804 # address in IA_PD (Token=static)
4805 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
4806 # address in IA_PD (temporary)
4807 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' )
4809 print ( '### ip -6 address show dev dummy98 scope global' )
4810 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
4812 # address in IA_PD (Token=static)
4813 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
4814 # address in IA_PD (temporary)
4815 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' )
4817 print ( '### ip -6 address show dev dummy99 scope global' )
4818 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
4821 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
4823 print ( '### ip -6 address show dev veth97 scope global' )
4824 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
4826 # address in IA_PD (Token=static)
4827 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
4828 # address in IA_PD (Token=eui64)
4829 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
4830 # address in IA_PD (temporary)
4831 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' )
4833 print ( '### ip -6 address show dev veth97-peer scope global' )
4834 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
4836 # NDisc address (Token=static)
4837 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
4838 # NDisc address (Token=eui64)
4839 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
4840 # NDisc address (temporary)
4841 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' )
4843 print ( '### ip -6 address show dev veth98 scope global' )
4844 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
4846 # address in IA_PD (Token=static)
4847 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
4848 # address in IA_PD (Token=eui64)
4849 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
4850 # address in IA_PD (temporary)
4851 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' )
4853 print ( '### ip -6 address show dev veth98-peer scope global' )
4854 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
4856 # NDisc address (Token=static)
4857 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
4858 # NDisc address (Token=eui64)
4859 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
4860 # NDisc address (temporary)
4861 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' )
4863 print ( '### ip -6 route show type unreachable' )
4864 output
= check_output ( 'ip -6 route show type unreachable' )
4866 self
. assertRegex ( output
, 'unreachable 3ffe:501:ffff:[2-9a-f]00::/56 dev lo proto dhcp' )
4868 print ( '### ip -6 route show dev veth99' )
4869 output
= check_output ( 'ip -6 route show dev veth99' )
4871 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]10::/64 proto kernel metric [0-9]* expires' )
4873 print ( '### ip -6 route show dev test1' )
4874 output
= check_output ( 'ip -6 route show dev test1' )
4876 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
4878 print ( '### ip -6 route show dev dummy98' )
4879 output
= check_output ( 'ip -6 route show dev dummy98' )
4881 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
4883 print ( '### ip -6 route show dev dummy99' )
4884 output
= check_output ( 'ip -6 route show dev dummy99' )
4886 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
4888 print ( '### ip -6 route show dev veth97' )
4889 output
= check_output ( 'ip -6 route show dev veth97' )
4891 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto kernel metric [0-9]* expires' )
4893 print ( '### ip -6 route show dev veth97-peer' )
4894 output
= check_output ( 'ip -6 route show dev veth97-peer' )
4896 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto ra metric [0-9]* expires' )
4898 print ( '### ip -6 route show dev veth98' )
4899 output
= check_output ( 'ip -6 route show dev veth98' )
4901 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto kernel metric [0-9]* expires' )
4903 print ( '### ip -6 route show dev veth98-peer' )
4904 output
= check_output ( 'ip -6 route show dev veth98-peer' )
4906 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto ra metric [0-9]* expires' )
4908 # Test case for a downstream which appears later
4909 check_output ( 'ip link add dummy97 type dummy' )
4910 self
. wait_online ([ 'dummy97:routable' ])
4912 print ( '### ip -6 address show dev dummy97 scope global' )
4913 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
4915 # address in IA_PD (Token=static)
4916 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
4917 # address in IA_PD (temporary)
4918 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' )
4920 print ( '### ip -6 route show dev dummy97' )
4921 output
= check_output ( 'ip -6 route show dev dummy97' )
4923 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]01::/64 proto kernel metric [0-9]* expires' )
4925 # Test case for reconfigure
4926 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
4927 self
. wait_online ([ 'dummy98:routable' ])
4929 print ( '### ip -6 address show dev dummy98 scope global' )
4930 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
4932 # address in IA_PD (Token=static)
4933 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
4934 # address in IA_PD (temporary)
4935 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' )
4937 print ( '### ip -6 address show dev dummy99 scope global' )
4938 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
4941 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
4943 print ( '### ip -6 route show dev dummy98' )
4944 output
= check_output ( 'ip -6 route show dev dummy98' )
4946 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
4948 print ( '### ip -6 route show dev dummy99' )
4949 output
= check_output ( 'ip -6 route show dev dummy99' )
4951 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
4953 def verify_dhcp4_6rd ( self
, tunnel_name
):
4954 print ( '### ip -4 address show dev veth-peer scope global' )
4955 output
= check_output ( 'ip -4 address show dev veth-peer scope global' )
4957 self
. assertIn ( 'inet 10.0.0.1/8 brd 10.255.255.255 scope global veth-peer' , output
)
4961 # dummy97: 0x01 (The link will appear later)
4963 # dummy99: auto -> 0x0[23] (No address assignment)
4964 # 6rd-XXX: auto -> 0x0[23]
4969 print ( '### ip -4 address show dev veth99 scope global' )
4970 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
4972 self
. assertRegex ( output
, 'inet 10.100.100.[0-9]*/8 (metric 1024 |)brd 10.255.255.255 scope global dynamic veth99' )
4974 print ( '### ip -6 address show dev veth99 scope global' )
4975 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
4977 # address in IA_PD (Token=static)
4978 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
4979 # address in IA_PD (Token=eui64)
4980 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic mngtmpaddr' )
4981 # address in IA_PD (temporary)
4982 # Note that the temporary addresses may appear after the link enters configured state
4983 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' )
4985 print ( '### ip -6 address show dev test1 scope global' )
4986 output
= check_output ( 'ip -6 address show dev test1 scope global' )
4988 # address in IA_PD (Token=static)
4989 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
4990 # address in IA_PD (temporary)
4991 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' )
4993 print ( '### ip -6 address show dev dummy98 scope global' )
4994 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
4996 # address in IA_PD (Token=static)
4997 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
4998 # address in IA_PD (temporary)
4999 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' )
5001 print ( '### ip -6 address show dev dummy99 scope global' )
5002 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5005 self
. assertNotRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+0[23]' )
5007 print ( '### ip -6 address show dev veth97 scope global' )
5008 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
5010 # address in IA_PD (Token=static)
5011 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5012 # address in IA_PD (Token=eui64)
5013 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5014 # address in IA_PD (temporary)
5015 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' )
5017 print ( '### ip -6 address show dev veth97-peer scope global' )
5018 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
5020 # NDisc address (Token=static)
5021 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5022 # NDisc address (Token=eui64)
5023 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5024 # NDisc address (temporary)
5025 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' )
5027 print ( '### ip -6 address show dev veth98 scope global' )
5028 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
5030 # address in IA_PD (Token=static)
5031 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5032 # address in IA_PD (Token=eui64)
5033 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5034 # address in IA_PD (temporary)
5035 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' )
5037 print ( '### ip -6 address show dev veth98-peer scope global' )
5038 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
5040 # NDisc address (Token=static)
5041 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5042 # NDisc address (Token=eui64)
5043 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5044 # NDisc address (temporary)
5045 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' )
5047 print ( '### ip -6 route show type unreachable' )
5048 output
= check_output ( 'ip -6 route show type unreachable' )
5050 self
. assertRegex ( output
, 'unreachable 2001:db8:6464:[0-9a-f]+00::/56 dev lo proto dhcp' )
5052 print ( '### ip -6 route show dev veth99' )
5053 output
= check_output ( 'ip -6 route show dev veth99' )
5055 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+10::/64 proto kernel metric [0-9]* expires' )
5057 print ( '### ip -6 route show dev test1' )
5058 output
= check_output ( 'ip -6 route show dev test1' )
5060 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
5062 print ( '### ip -6 route show dev dummy98' )
5063 output
= check_output ( 'ip -6 route show dev dummy98' )
5065 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
5067 print ( '### ip -6 route show dev dummy99' )
5068 output
= check_output ( 'ip -6 route show dev dummy99' )
5070 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto dhcp metric [0-9]* expires' )
5072 print ( '### ip -6 route show dev veth97' )
5073 output
= check_output ( 'ip -6 route show dev veth97' )
5075 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto kernel metric [0-9]* expires' )
5077 print ( '### ip -6 route show dev veth97-peer' )
5078 output
= check_output ( 'ip -6 route show dev veth97-peer' )
5080 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto ra metric [0-9]* expires' )
5082 print ( '### ip -6 route show dev veth98' )
5083 output
= check_output ( 'ip -6 route show dev veth98' )
5085 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto kernel metric [0-9]* expires' )
5087 print ( '### ip -6 route show dev veth98-peer' )
5088 output
= check_output ( 'ip -6 route show dev veth98-peer' )
5090 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto ra metric [0-9]* expires' )
5092 print ( '### ip -6 address show dev dummy97 scope global' )
5093 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
5095 # address in IA_PD (Token=static)
5096 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5097 # address in IA_PD (temporary)
5098 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' )
5100 print ( '### ip -6 route show dev dummy97' )
5101 output
= check_output ( 'ip -6 route show dev dummy97' )
5103 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+01::/64 proto kernel metric [0-9]* expires' )
5105 print ( f
'### ip -d link show dev {tunnel_name} ' )
5106 output
= check_output ( f
'ip -d link show dev {tunnel_name} ' )
5108 self
. assertIn ( 'link/sit 10.100.100.' , output
)
5109 self
. assertIn ( 'local 10.100.100.' , output
)
5110 self
. assertIn ( 'ttl 64' , output
)
5111 self
. assertIn ( '6rd-prefix 2001:db8::/32' , output
)
5112 self
. assertIn ( '6rd-relay_prefix 10.0.0.0/8' , output
)
5114 print ( f
'### ip -6 address show dev {tunnel_name} ' )
5115 output
= check_output ( f
'ip -6 address show dev {tunnel_name} ' )
5117 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' )
5118 self
. assertRegex ( output
, 'inet6 ::10.100.100.[0-9]+/96 scope global' )
5120 print ( f
'### ip -6 route show dev {tunnel_name} ' )
5121 output
= check_output ( f
'ip -6 route show dev {tunnel_name} ' )
5123 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto kernel metric [0-9]* expires' )
5124 self
. assertRegex ( output
, '::/96 proto kernel metric [0-9]*' )
5126 print ( '### ip -6 route show default' )
5127 output
= check_output ( 'ip -6 route show default' )
5129 self
. assertIn ( 'default' , output
)
5130 self
. assertIn ( f
'via ::10.0.0.1 dev {tunnel_name} ' , output
)
5132 def test_dhcp4_6rd ( self
):
5133 copy_network_unit ( '25-veth.netdev' , '25-dhcp4-6rd-server.network' , '25-dhcp4-6rd-upstream.network' ,
5134 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
5135 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
5136 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
5137 '25-dhcp-pd-downstream-dummy97.network' ,
5138 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
5139 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' ,
5140 '80-6rd-tunnel.network' )
5143 self
. wait_online ([ 'veth-peer:routable' ])
5146 # 6rd-prefix: 2001:db8::/32
5147 # br-addresss: 10.0.0.1
5149 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' ,
5150 ipv4_range
= '10.100.100.100,10.100.100.200' ,
5151 ipv4_router
= '10.0.0.1' )
5152 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5153 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5155 # Test case for a downstream which appears later
5156 check_output ( 'ip link add dummy97 type dummy' )
5157 self
. wait_online ([ 'dummy97:routable' ])
5161 for name
in os
. listdir ( '/sys/class/net/' ):
5162 if name
. startswith ( '6rd-' ):
5166 self
. wait_online ([ f
' {tunnel_name} :routable' ])
5168 self
. verify_dhcp4_6rd ( tunnel_name
)
5170 # Test case for reconfigure
5171 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
5172 self
. wait_online ([ 'dummy98:routable' , 'dummy99:degraded' ])
5174 self
. verify_dhcp4_6rd ( tunnel_name
)
5176 print ( 'Wait for the DHCP lease to be expired' )
5179 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy97:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5180 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5182 self
. verify_dhcp4_6rd ( tunnel_name
)
5184 class NetworkdIPv6PrefixTests ( unittest
. TestCase
, Utilities
):
5192 def test_ipv6_route_prefix ( self
):
5193 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client.network' , '25-ipv6ra-prefix.network' ,
5194 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
5197 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
5199 output
= check_output ( 'ip address show dev veth-peer' )
5201 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
5202 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
5203 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
5205 output
= check_output ( 'ip -6 route show dev veth-peer' )
5207 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
5208 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
5209 self
. assertNotIn ( '2001:db8:0:3::/64 proto ra' , output
)
5210 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
5211 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
5212 self
. assertNotIn ( '2001:db2:fff::/64 via ' , output
)
5214 output
= check_output ( 'ip address show dev veth99' )
5216 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
5217 self
. assertIn ( 'inet6 2001:db8:0:2:1a:2b:3c:4d' , output
)
5218 self
. assertIn ( 'inet6 2001:db8:0:2:fa:de:ca:fe' , output
)
5219 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
5221 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth-peer' , env
= env
)
5223 self
. assertRegex ( output
, '2001:db8:1:1::2' )
5225 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth-peer' , env
= env
)
5227 self
. assertIn ( 'example.com' , output
)
5229 # TODO: check json string
5230 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5232 def test_ipv6_route_prefix_deny_list ( self
):
5233 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client-deny-list.network' , '25-ipv6ra-prefix.network' ,
5234 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
5237 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
5239 output
= check_output ( 'ip address show dev veth-peer' )
5241 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
5242 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
5244 output
= check_output ( 'ip -6 route show dev veth-peer' )
5246 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
5247 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
5248 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
5249 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
5251 output
= check_output ( 'ip address show dev veth99' )
5253 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
5254 self
. assertIn ( 'inet6 2001:db8:0:2:' , output
)
5256 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth-peer' , env
= env
)
5258 self
. assertRegex ( output
, '2001:db8:1:1::2' )
5260 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth-peer' , env
= env
)
5262 self
. assertIn ( 'example.com' , output
)
5264 class NetworkdMTUTests ( unittest
. TestCase
, Utilities
):
5272 def check_mtu ( self
, mtu
, ipv6_mtu
= None , reset
= True ):
5278 self
. wait_online ([ 'dummy98:routable' ])
5279 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
5280 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
5282 # test normal restart
5284 self
. wait_online ([ 'dummy98:routable' ])
5285 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
5286 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
5289 self
. reset_check_mtu ( mtu
, ipv6_mtu
)
5291 def reset_check_mtu ( self
, mtu
, ipv6_mtu
= None ):
5292 ''' test setting mtu/ipv6_mtu with interface already up '''
5295 # note - changing the device mtu resets the ipv6 mtu
5296 check_output ( 'ip link set up mtu 1501 dev dummy98' )
5297 check_output ( 'ip link set up mtu 1500 dev dummy98' )
5298 self
. check_link_attr ( 'dummy98' , 'mtu' , '1500' )
5299 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , '1500' )
5301 self
. check_mtu ( mtu
, ipv6_mtu
, reset
= False )
5303 def test_mtu_network ( self
):
5304 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' )
5305 self
. check_mtu ( '1600' )
5307 def test_mtu_netdev ( self
):
5308 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network' , copy_dropins
= False )
5309 # note - MTU set by .netdev happens ONLY at device creation!
5310 self
. check_mtu ( '1600' , reset
= False )
5312 def test_mtu_link ( self
):
5313 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network' , copy_dropins
= False )
5314 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
5315 self
. check_mtu ( '1600' , reset
= False )
5317 def test_ipv6_mtu ( self
):
5318 ''' set ipv6 mtu without setting device mtu '''
5319 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1400.conf' )
5320 self
. check_mtu ( '1500' , '1400' )
5322 def test_ipv6_mtu_toolarge ( self
):
5323 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
5324 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5325 self
. check_mtu ( '1500' , '1500' )
5327 def test_mtu_network_ipv6_mtu ( self
):
5328 ''' set ipv6 mtu and set device mtu via network file '''
5329 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5330 self
. check_mtu ( '1600' , '1550' )
5332 def test_mtu_netdev_ipv6_mtu ( self
):
5333 ''' set ipv6 mtu and set device mtu via netdev file '''
5334 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5335 self
. check_mtu ( '1600' , '1550' , reset
= False )
5337 def test_mtu_link_ipv6_mtu ( self
):
5338 ''' set ipv6 mtu and set device mtu via link file '''
5339 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5340 self
. check_mtu ( '1600' , '1550' , reset
= False )
5343 if __name__
== '__main__' :
5344 parser
= argparse
. ArgumentParser ()
5345 parser
. add_argument ( '--build-dir' , help = 'Path to build dir' , dest
= 'build_dir' )
5346 parser
. add_argument ( '--networkd' , help = 'Path to systemd-networkd' , dest
= 'networkd_bin' )
5347 parser
. add_argument ( '--resolved' , help = 'Path to systemd-resolved' , dest
= 'resolved_bin' )
5348 parser
. add_argument ( '--timesyncd' , help = 'Path to systemd-timesyncd' , dest
= 'timesyncd_bin' )
5349 parser
. add_argument ( '--udevd' , help = 'Path to systemd-udevd' , dest
= 'udevd_bin' )
5350 parser
. add_argument ( '--wait-online' , help = 'Path to systemd-networkd-wait-online' , dest
= 'wait_online_bin' )
5351 parser
. add_argument ( '--networkctl' , help = 'Path to networkctl' , dest
= 'networkctl_bin' )
5352 parser
. add_argument ( '--resolvectl' , help = 'Path to resolvectl' , dest
= 'resolvectl_bin' )
5353 parser
. add_argument ( '--timedatectl' , help = 'Path to timedatectl' , dest
= 'timedatectl_bin' )
5354 parser
. add_argument ( '--udevadm' , help = 'Path to udevadm' , dest
= 'udevadm_bin' )
5355 parser
. add_argument ( '--valgrind' , help = 'Enable valgrind' , dest
= 'use_valgrind' , type = bool , nargs
= '?' , const
= True , default
= use_valgrind
)
5356 parser
. add_argument ( '--debug' , help = 'Generate debugging logs' , dest
= 'enable_debug' , type = bool , nargs
= '?' , const
= True , default
= enable_debug
)
5357 parser
. add_argument ( '--asan-options' , help = 'ASAN options' , dest
= 'asan_options' )
5358 parser
. add_argument ( '--lsan-options' , help = 'LSAN options' , dest
= 'lsan_options' )
5359 parser
. add_argument ( '--ubsan-options' , help = 'UBSAN options' , dest
= 'ubsan_options' )
5360 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
)
5361 ns
, unknown_args
= parser
. parse_known_args ( namespace
= unittest
)
5364 if ns
. networkd_bin
or ns
. resolved_bin
or ns
. timesyncd_bin
or ns
. udevd_bin
or \
5365 ns
. wait_online_bin
or ns
. networkctl_bin
or ns
. resolvectl_bin
or ns
. timedatectl_bin
or ns
. udevadm_bin
:
5366 print ( 'WARNING: --networkd, --resolved, --timesyncd, --udevd, --wait-online, --networkctl, --resolvectl, --timedatectl, or --udevadm options are ignored when --build-dir is specified.' )
5367 networkd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd' )
5368 resolved_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-resolved' )
5369 timesyncd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-timesyncd' )
5370 udevd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-udevd' )
5371 wait_online_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd-wait-online' )
5372 networkctl_bin
= os
. path
. join ( ns
. build_dir
, 'networkctl' )
5373 resolvectl_bin
= os
. path
. join ( ns
. build_dir
, 'resolvectl' )
5374 timedatectl_bin
= os
. path
. join ( ns
. build_dir
, 'timedatectl' )
5375 udevadm_bin
= os
. path
. join ( ns
. build_dir
, 'udevadm' )
5378 networkd_bin
= ns
. networkd_bin
5380 resolved_bin
= ns
. resolved_bin
5381 if ns
. timesyncd_bin
:
5382 timesyncd_bin
= ns
. timesyncd_bin
5384 udevd_bin
= ns
. udevd_bin
5385 if ns
. wait_online_bin
:
5386 wait_online_bin
= ns
. wait_online_bin
5387 if ns
. networkctl_bin
:
5388 networkctl_bin
= ns
. networkctl_bin
5389 if ns
. resolvectl_bin
:
5390 resolvectl_bin
= ns
. resolvectl_bin
5391 if ns
. timedatectl_bin
:
5392 timedatectl_bin
= ns
. timedatectl_bin
5394 udevadm_bin
= ns
. udevadm_bin
5396 use_valgrind
= ns
. use_valgrind
5397 enable_debug
= ns
. enable_debug
5398 asan_options
= ns
. asan_options
5399 lsan_options
= ns
. lsan_options
5400 ubsan_options
= ns
. ubsan_options
5401 with_coverage
= ns
. with_coverage
5404 # Do not forget the trailing space.
5405 valgrind_cmd
= 'valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all '
5407 networkctl_cmd
= valgrind_cmd
. split () + [ networkctl_bin
]
5408 resolvectl_cmd
= valgrind_cmd
. split () + [ resolvectl_bin
]
5409 timedatectl_cmd
= valgrind_cmd
. split () + [ timedatectl_bin
]
5410 udevadm_cmd
= valgrind_cmd
. split () + [ udevadm_bin
]
5411 wait_online_cmd
= valgrind_cmd
. split () + [ wait_online_bin
]
5414 env
. update ({ 'ASAN_OPTIONS' : asan_options
})
5416 env
. update ({ 'LSAN_OPTIONS' : lsan_options
})
5418 env
. update ({ 'UBSAN_OPTIONS' : ubsan_options
})
5420 env
. update ({ 'SYSTEMD_MEMPOOL' : '0' })
5422 wait_online_env
= env
. copy ()
5424 wait_online_env
. update ({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
5426 sys
. argv
[ 1 :] = unknown_args
5427 unittest
. main ( verbosity
= 3 )