]>
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.
25 network_unit_dir
= '/run/systemd/network'
26 networkd_conf_dropin_dir
= '/run/systemd/networkd.conf.d'
27 networkd_ci_temp_dir
= '/run/networkd-ci'
28 udev_rules_dir
= '/run/udev/rules.d'
30 dnsmasq_pid_file
= '/run/networkd-ci/test-dnsmasq.pid'
31 dnsmasq_log_file
= '/run/networkd-ci/test-dnsmasq.log'
32 dnsmasq_lease_file
= '/run/networkd-ci/test-dnsmasq.lease'
34 isc_dhcpd_pid_file
= '/run/networkd-ci/test-isc-dhcpd.pid'
35 isc_dhcpd_lease_file
= '/run/networkd-ci/test-isc-dhcpd.lease'
37 systemd_lib_paths
= [ '/usr/lib/systemd' , '/lib/systemd' ]
38 which_paths
= ':' . join ( systemd_lib_paths
+ os
. getenv ( 'PATH' , os
. defpath
). lstrip ( ':' ). split ( ':' ))
40 networkd_bin
= shutil
. which ( 'systemd-networkd' , path
= which_paths
)
41 resolved_bin
= shutil
. which ( 'systemd-resolved' , path
= which_paths
)
42 timesyncd_bin
= shutil
. which ( 'systemd-timesyncd' , path
= which_paths
)
43 udevd_bin
= shutil
. which ( 'systemd-udevd' , path
= which_paths
)
44 wait_online_bin
= shutil
. which ( 'systemd-networkd-wait-online' , path
= which_paths
)
45 networkctl_bin
= shutil
. which ( 'networkctl' , path
= which_paths
)
46 resolvectl_bin
= shutil
. which ( 'resolvectl' , path
= which_paths
)
47 timedatectl_bin
= shutil
. which ( 'timedatectl' , path
= which_paths
)
48 udevadm_bin
= shutil
. which ( 'udevadm' , path
= which_paths
)
76 saved_ipv4_rules
= None
77 saved_ipv6_rules
= None
81 if os
. path
. exists ( path
):
85 shutil
. rmtree ( path
, ignore_errors
= True )
91 shutil
. copytree ( src
, dst
, copy_function
= shutil
. copy
)
94 os
. makedirs ( path
, exist_ok
= True )
97 pathlib
. Path ( path
). touch ()
99 def check_output (* command
, ** kwargs
):
100 # This checks the result and returns stdout (and stderr) on success.
101 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
102 ret
= subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. PIPE
, stderr
= subprocess
. STDOUT
, ** kwargs
)
103 if ret
. returncode
== 0 :
104 return ret
. stdout
. rstrip ()
105 # When returncode != 0, print stdout and stderr, then trigger CalledProcessError.
107 ret
. check_returncode ()
109 def call (* command
, ** kwargs
):
110 # This returns returncode. stdout and stderr are merged and shown in console
111 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
112 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stderr
= subprocess
. STDOUT
, ** kwargs
). returncode
114 def call_quiet (* command
, ** kwargs
):
115 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
116 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. DEVNULL
, stderr
= subprocess
. DEVNULL
, ** kwargs
). returncode
118 def run (* command
, ** kwargs
):
119 # This returns CompletedProcess instance.
120 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
121 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. PIPE
, stderr
= subprocess
. PIPE
, ** kwargs
)
123 def is_module_available (* module_names
):
124 for module_name
in module_names
:
125 lsmod_output
= check_output ( 'lsmod' )
126 module_re
= re
. compile ( rf
'^{re.escape(module_name)} \b ' , re
. MULTILINE
)
127 if not module_re
. search ( lsmod_output
) and call_quiet ( 'modprobe' , module_name
) != 0 :
131 def expectedFailureIfModuleIsNotAvailable (* module_names
):
133 return func
if is_module_available (* module_names
) else unittest
. expectedFailure ( func
)
137 def expectedFailureIfERSPANv0IsNotSupported ():
138 # erspan version 0 is supported since f989d546a2d5a9f001f6f8be49d98c10ab9b1897 (v5.8)
140 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' )
141 remove_link ( 'erspan99' )
142 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
146 def expectedFailureIfERSPANv2IsNotSupported ():
147 # erspan version 2 is supported since f551c91de262ba36b20c3ac19538afb4f4507441 (v4.16)
149 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' )
150 remove_link ( 'erspan99' )
151 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
155 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable ():
157 rc
= call_quiet ( 'ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7' )
158 call_quiet ( 'ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7' )
159 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
163 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable ():
165 rc
= call_quiet ( 'ip rule add not from 192.168.100.19 ipproto tcp table 7' )
166 call_quiet ( 'ip rule del not from 192.168.100.19 ipproto tcp table 7' )
167 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
171 def expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable ():
174 if call_quiet ( 'ip rule add from 192.168.100.19 table 7 uidrange 200-300' ) == 0 :
175 ret
= run ( 'ip rule list from 192.168.100.19 table 7' )
176 supported
= ret
. returncode
== 0 and 'uidrange 200-300' in ret
. stdout
177 call_quiet ( 'ip rule del from 192.168.100.19 table 7 uidrange 200-300' )
178 return func
if supported
else unittest
. expectedFailure ( func
)
182 def expectedFailureIfLinkFileFieldIsNotSet ():
184 call_quiet ( 'ip link add name dummy99 type dummy' )
185 ret
= run ( 'udevadm info -w10s /sys/class/net/dummy99' )
186 supported
= ret
. returncode
== 0 and 'E: ID_NET_LINK_FILE=' in ret
. stdout
187 remove_link ( 'dummy99' )
188 return func
if supported
else unittest
. expectedFailure ( func
)
192 def expectedFailureIfNexthopIsNotAvailable ():
194 rc
= call_quiet ( 'ip nexthop list' )
195 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
199 def expectedFailureIfRTA_VIAIsNotSupported ():
201 call_quiet ( 'ip link add dummy98 type dummy' )
202 call_quiet ( 'ip link set up dev dummy98' )
203 call_quiet ( 'ip route add 2001:1234:5:8fff:ff:ff:ff:fe/128 dev dummy98' )
204 rc
= call_quiet ( 'ip route add 10.10.10.10 via inet6 2001:1234:5:8fff:ff:ff:ff:fe dev dummy98' )
205 remove_link ( 'dummy98' )
206 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
210 def expectedFailureIfAlternativeNameIsNotAvailable ():
212 call_quiet ( 'ip link add dummy98 type dummy' )
214 call_quiet ( 'ip link prop add dev dummy98 altname hogehogehogehogehoge' ) == 0 and \
215 call_quiet ( 'ip link show dev hogehogehogehogehoge' ) == 0
216 remove_link ( 'dummy98' )
217 return func
if supported
else unittest
. expectedFailure ( func
)
221 def expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ():
223 def finalize ( func
, supported
):
224 call_quiet ( 'rmmod netdevsim' )
225 return func
if supported
else unittest
. expectedFailure ( func
)
227 call_quiet ( 'rmmod netdevsim' )
228 if call_quiet ( 'modprobe netdevsim' ) != 0 :
229 return finalize ( func
, False )
232 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
235 return finalize ( func
, False )
237 if not os
. path
. exists ( '/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs' ):
238 return finalize ( func
, False )
240 # Also checks if udevd supports .link files, as it seems disabled on CentOS CI (Arch).
241 rc
= call_quiet ( 'udevadm info -w10s /sys/class/net/eni99np1' )
242 return finalize ( func
, rc
== 0 )
247 check_output (* udevadm_cmd
, 'control' , '--reload' )
249 def copy_network_unit (* units
, copy_dropins
= True ):
251 Copy networkd unit files into the testbed.
253 Any networkd unit file type can be specified, as well as drop-in files.
255 By default, all drop-ins for a specified unit file are copied in;
256 to avoid that specify dropins=False.
258 When a drop-in file is specified, its unit file is also copied in automatically.
261 mkdir_p ( network_unit_dir
)
263 if copy_dropins
and os
. path
. exists ( os
. path
. join ( networkd_ci_temp_dir
, unit
+ '.d' )):
264 cp_r ( os
. path
. join ( networkd_ci_temp_dir
, unit
+ '.d' ), os
. path
. join ( network_unit_dir
, unit
+ '.d' ))
266 if unit
. endswith ( '.conf' ):
268 unit
= os
. path
. dirname ( dropin
). rstrip ( '.d' )
269 dropindir
= os
. path
. join ( network_unit_dir
, unit
+ '.d' )
271 cp ( os
. path
. join ( networkd_ci_temp_dir
, dropin
), dropindir
)
273 cp ( os
. path
. join ( networkd_ci_temp_dir
, unit
), network_unit_dir
)
275 if unit
. endswith ( '.link' ):
281 def remove_network_unit (* units
):
283 Remove previously copied unit files from the testbed.
285 Drop-ins will be removed automatically.
289 rm_f ( os
. path
. join ( network_unit_dir
, unit
))
290 rm_rf ( os
. path
. join ( network_unit_dir
, unit
+ '.d' ))
292 if unit
. endswith ( '.link' ) or unit
. endswith ( '.link.d' ):
298 def clear_network_units ():
300 if os
. path
. exists ( network_unit_dir
):
301 units
= os
. listdir ( network_unit_dir
)
303 if unit
. endswith ( '.link' ) or unit
. endswith ( '.link.d' ):
306 rm_rf ( network_unit_dir
)
311 def copy_networkd_conf_dropin (* dropins
):
312 """Copy networkd.conf dropin files into the testbed."""
313 mkdir_p ( networkd_conf_dropin_dir
)
314 for dropin
in dropins
:
315 cp ( os
. path
. join ( networkd_ci_temp_dir
, dropin
), networkd_conf_dropin_dir
)
317 def remove_networkd_conf_dropin (* dropins
):
318 """Remove previously copied networkd.conf dropin files from the testbed."""
319 for dropin
in dropins
:
320 rm_f ( os
. path
. join ( networkd_conf_dropin_dir
, dropin
))
322 def clear_networkd_conf_dropins ():
323 rm_rf ( networkd_conf_dropin_dir
)
325 def copy_udev_rule (* rules
):
326 """Copy udev rules"""
327 mkdir_p ( udev_rules_dir
)
329 cp ( os
. path
. join ( networkd_ci_temp_dir
, rule
), udev_rules_dir
)
331 def remove_udev_rule (* rules
):
332 """Remove previously copied udev rules"""
334 rm_f ( os
. path
. join ( udev_rules_dir
, rule
))
336 def clear_udev_rules ():
337 rm_rf ( udev_rules_dir
)
339 def save_active_units ():
340 for u
in [ 'systemd-networkd.socket' , 'systemd-networkd.service' ,
341 'systemd-resolved.service' , 'systemd-timesyncd.service' ,
342 'firewalld.service' ]:
343 if call ( f
'systemctl is-active --quiet {u} ' ) == 0 :
344 call ( f
'systemctl stop {u} ' )
345 active_units
. append ( u
)
347 def restore_active_units ():
348 if 'systemd-networkd.socket' in active_units
:
349 call ( 'systemctl stop systemd-networkd.socket systemd-networkd.service' )
350 for u
in active_units
:
351 call ( f
'systemctl restart {u} ' )
353 def create_unit_dropin ( unit
, contents
):
354 mkdir_p ( f
'/run/systemd/system/ {unit} .d' )
355 with
open ( f
'/run/systemd/system/ {unit} .d/00-override.conf' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
356 f
. write ( ' \n ' . join ( contents
))
358 def create_service_dropin ( service
, command
, reload_command
= None , additional_settings
= None ):
362 f
'ExecStart=!! {valgrind_cmd}{command} ' ,
367 f
'ExecReload= {valgrind_cmd}{reload_command} ' ,
370 drop_in
+= [ 'Environment=SYSTEMD_LOG_LEVEL=debug' ]
372 drop_in
+= [ f
'Environment=ASAN_OPTIONS=" {asan_options} "' ]
374 drop_in
+= [ f
'Environment=LSAN_OPTIONS=" {lsan_options} "' ]
376 drop_in
+= [ f
'Environment=UBSAN_OPTIONS=" {ubsan_options} "' ]
377 if asan_options
or lsan_options
or ubsan_options
:
378 drop_in
+= [ 'SystemCallFilter=' ]
379 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
380 drop_in
+= [ 'MemoryDenyWriteExecute=no' ]
383 'Environment=SYSTEMD_MEMPOOL=0' ,
391 if additional_settings
:
392 drop_in
+= additional_settings
394 create_unit_dropin ( f
' {service} .service' , drop_in
)
396 def link_exists ( link
):
397 return os
. path
. exists ( os
. path
. join ( '/sys/class/net' , link
, 'ifindex' ))
399 def remove_link (* links
, protect
= False ):
401 if protect
and link
in protected_links
:
403 if link_exists ( link
):
404 call ( f
'ip link del dev {link} ' )
406 def save_existing_links ():
407 links
= os
. listdir ( '/sys/class/net' )
409 if link_exists ( link
):
410 protected_links
. add ( link
)
412 print ( '### The following links will be protected:' )
413 print ( ', ' . join ( sorted ( list ( protected_links
))))
416 links
= os
. listdir ( '/sys/class/net' )
417 remove_link (* links
, protect
= True )
419 def flush_nexthops ():
420 # Currently, the 'ip nexthop' command does not have 'save' and 'restore'.
421 # Hence, we cannot restore nexthops in a simple way.
422 # Let's assume there is no nexthop used in the system
423 call_quiet ( 'ip nexthop flush' )
426 # pylint: disable=global-statement
428 saved_routes
= check_output ( 'ip route show table all' )
429 print ( '### The following routes will be protected:' )
434 output
= check_output ( 'ip route show table all' )
435 for line
in output
. splitlines ():
436 if line
in saved_routes
:
438 if 'proto kernel' in line
:
440 if ' dev ' in line
and not ' dev lo ' in line
:
444 print ( '### Removing routes that did not exist when the test started.' )
446 call ( f
'ip route del {line} ' )
448 def save_routing_policy_rules ():
449 # pylint: disable=global-statement
450 global saved_ipv4_rules
, saved_ipv6_rules
452 output
= check_output ( f
'ip - {ipv} rule show' )
453 print ( f
'### The following IPv {ipv} routing policy rules will be protected:' )
457 saved_ipv4_rules
= save ( 4 )
458 saved_ipv6_rules
= save ( 6 )
460 def flush_routing_policy_rules ():
461 def flush ( ipv
, saved_rules
):
463 output
= check_output ( f
'ip - {ipv} rule show' )
464 for line
in output
. splitlines ():
465 if line
in saved_rules
:
469 print ( f
'### Removing IPv {ipv} routing policy rules that did not exist when the test started.' )
471 words
= line
. replace ( 'lookup [l3mdev-table]' , 'l3mdev' ). split ()
472 priority
= words
[ 0 ]. rstrip ( ':' )
473 call ( f
'ip - {ipv} rule del priority {priority} ' + ' ' . join ( words
[ 1 :]))
475 flush ( 4 , saved_ipv4_rules
)
476 flush ( 6 , saved_ipv6_rules
)
478 def flush_fou_ports ():
479 ret
= run ( 'ip fou show' )
480 if ret
. returncode
!= 0 :
481 return # fou may not be supported
482 for line
in ret
. stdout
. splitlines ():
483 port
= line
. split ()[ 1 ]
484 call ( f
'ip fou del port {port} ' )
486 def flush_l2tp_tunnels ():
488 ret
= run ( 'ip l2tp show tunnel' )
489 if ret
. returncode
!= 0 :
490 return # l2tp may not be supported
491 for line
in ret
. stdout
. splitlines ():
493 if words
[ 0 ] == 'Tunnel' :
494 tid
= words
[ 1 ]. rstrip ( ',' )
495 call ( f
'ip l2tp del tunnel tunnel_id {tid} ' )
498 # Removing L2TP tunnel is asynchronous and slightly takes a time.
501 r
= run ( f
'ip l2tp show tunnel tunnel_id {tid} ' )
502 if r
. returncode
!= 0 or len ( r
. stdout
. rstrip ()) == 0 :
506 print ( f
'Cannot remove L2TP tunnel {tid} , ignoring.' )
509 global saved_timezone
510 r
= run (* timedatectl_cmd
, 'show' , '--value' , '--property' , 'Timezone' , env
= env
)
511 if r
. returncode
== 0 :
512 saved_timezone
= r
. stdout
. rstrip ()
513 print ( f
'### Saved timezone: {saved_timezone} ' )
515 def restore_timezone ():
517 call (* timedatectl_cmd
, 'set-timezone' , f
' {saved_timezone} ' , env
= env
)
519 def read_link_attr (* args
):
520 with
open ( os
. path
. join ( '/sys/class/net' , * args
), encoding
= 'utf-8' ) as f
:
521 return f
. readline (). strip ()
523 def read_link_state_file ( link
):
524 ifindex
= read_link_attr ( link
, 'ifindex' )
525 path
= os
. path
. join ( '/run/systemd/netif/links' , ifindex
)
526 with
open ( path
, encoding
= 'utf-8' ) as f
:
529 def read_ip_sysctl_attr ( link
, attribute
, ipv
):
530 with
open ( os
. path
. join ( '/proc/sys/net' , ipv
, 'conf' , link
, attribute
), encoding
= 'utf-8' ) as f
:
531 return f
. readline (). strip ()
533 def read_ipv6_sysctl_attr ( link
, attribute
):
534 return read_ip_sysctl_attr ( link
, attribute
, 'ipv6' )
536 def read_ipv4_sysctl_attr ( link
, attribute
):
537 return read_ip_sysctl_attr ( link
, attribute
, 'ipv4' )
539 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' ):
542 f
'--log-facility= {dnsmasq_log_file} ' ,
543 '--log-queries=extra' ,
545 f
'--pid-file= {dnsmasq_pid_file} ' ,
546 '--conf-file=/dev/null' ,
548 f
'--interface= {interface} ' ,
549 f
'--dhcp-leasefile= {dnsmasq_lease_file} ' ,
551 f
'--dhcp-range= {ipv6_range} , {lease_time} ' ,
552 f
'--dhcp-range= {ipv4_range} , {lease_time} ' ,
553 '--dhcp-option=option:mtu,1492' ,
554 f
'--dhcp-option=option:router, {ipv4_router} ' ,
557 ) + additional_options
558 check_output (* command
)
560 def stop_by_pid_file ( pid_file
):
561 if not os
. path
. exists ( pid_file
):
563 with
open ( pid_file
, 'r' , encoding
= 'utf-8' ) as f
:
564 pid
= f
. read (). rstrip ( ' \t\r\n \0' )
565 os
. kill ( int ( pid
), signal
. SIGTERM
)
569 print ( f
"PID {pid} is still alive, waiting..." )
572 if e
. errno
== errno
. ESRCH
:
574 print ( f
"Unexpected exception when waiting for {pid} to die: {e.errno}" )
578 stop_by_pid_file ( dnsmasq_pid_file
)
579 rm_f ( dnsmasq_lease_file
)
580 rm_f ( dnsmasq_log_file
)
582 def read_dnsmasq_log_file ():
583 with
open ( dnsmasq_log_file
, encoding
= 'utf-8' ) as f
:
586 def start_isc_dhcpd ( conf_file
, ipv
, interface
= 'veth-peer' ):
587 conf_file_path
= os
. path
. join ( networkd_ci_temp_dir
, conf_file
)
588 isc_dhcpd_command
= f
'dhcpd {ipv} -cf {conf_file_path} -lf {isc_dhcpd_lease_file} -pf {isc_dhcpd_pid_file} {interface} '
589 touch ( isc_dhcpd_lease_file
)
590 check_output ( isc_dhcpd_command
)
592 def stop_isc_dhcpd ():
593 stop_by_pid_file ( isc_dhcpd_pid_file
)
594 rm_f ( isc_dhcpd_lease_file
)
596 def networkd_invocation_id ():
597 return check_output ( 'systemctl show --value -p InvocationID systemd-networkd.service' )
599 def read_networkd_log ( invocation_id
= None ):
600 if not invocation_id
:
601 invocation_id
= networkd_invocation_id ()
602 return check_output ( 'journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
)
604 def stop_networkd ( show_logs
= True ):
606 invocation_id
= networkd_invocation_id ()
607 check_output ( 'systemctl stop systemd-networkd.socket' )
608 check_output ( 'systemctl stop systemd-networkd.service' )
610 print ( read_networkd_log ( invocation_id
))
612 def start_networkd ():
613 check_output ( 'systemctl start systemd-networkd' )
615 def restart_networkd ( show_logs
= True ):
617 invocation_id
= networkd_invocation_id ()
618 check_output ( 'systemctl restart systemd-networkd.service' )
620 print ( read_networkd_log ( invocation_id
))
623 return int ( check_output ( 'systemctl show --value -p MainPID systemd-networkd.service' ))
625 def networkctl_reconfigure (* links
):
626 check_output (* networkctl_cmd
, 'reconfigure' , * links
, env
= env
)
628 def networkctl_reload ( sleep_time
= 1 ):
629 check_output (* networkctl_cmd
, 'reload' , env
= env
)
630 # 'networkctl reload' asynchronously reconfigure links.
631 # Hence, we need to wait for a short time for link to be in configuring state.
633 time
. sleep ( sleep_time
)
638 def tear_down_common ():
639 # 1. stop DHCP servers
644 call_quiet ( 'rmmod netdevsim' )
645 call_quiet ( 'rmmod sch_teql' )
647 # 3. remove network namespace
648 call_quiet ( 'ip netns del ns99' )
658 clear_network_units ()
659 clear_networkd_conf_dropins ()
664 flush_routing_policy_rules ()
668 rm_rf ( networkd_ci_temp_dir
)
669 cp_r ( os
. path
. join ( os
. path
. dirname ( os
. path
. abspath ( __file__
)), 'conf' ), networkd_ci_temp_dir
)
671 clear_network_units ()
672 clear_networkd_conf_dropins ()
675 copy_udev_rule ( '00-debug-net.rules' )
679 save_existing_links ()
681 save_routing_policy_rules ()
684 create_service_dropin ( 'systemd-networkd' , networkd_bin
,
685 f
' {networkctl_bin} reload' ,
686 [ '[Service]' , 'Restart=no' , '[Unit]' , 'StartLimitIntervalSec=0' ])
687 create_service_dropin ( 'systemd-resolved' , resolved_bin
)
688 create_service_dropin ( 'systemd-timesyncd' , timesyncd_bin
)
690 # TODO: also run udevd with sanitizers, valgrind, or coverage
691 #create_service_dropin('systemd-udevd', udevd_bin,
692 # f'{udevadm_bin} control --reload --timeout 0')
694 'systemd-udevd.service' ,
698 f
'ExecStart=!! {udevd_bin} ' ,
700 f
'ExecReload= {udevadm_bin} control --reload --timeout 0' ,
704 'systemd-networkd.socket' ,
707 'StartLimitIntervalSec=0' ,
711 check_output ( 'systemctl daemon-reload' )
712 print ( check_output ( 'systemctl cat systemd-networkd.service' ))
713 print ( check_output ( 'systemctl cat systemd-resolved.service' ))
714 print ( check_output ( 'systemctl cat systemd-timesyncd.service' ))
715 print ( check_output ( 'systemctl cat systemd-udevd.service' ))
716 check_output ( 'systemctl restart systemd-resolved.service' )
717 check_output ( 'systemctl restart systemd-timesyncd.service' )
718 check_output ( 'systemctl restart systemd-udevd.service' )
720 def tearDownModule ():
721 rm_rf ( networkd_ci_temp_dir
)
723 clear_network_units ()
724 clear_networkd_conf_dropins ()
728 rm_rf ( '/run/systemd/system/systemd-networkd.service.d' )
729 rm_rf ( '/run/systemd/system/systemd-networkd.socket.d' )
730 rm_rf ( '/run/systemd/system/systemd-resolved.service.d' )
731 rm_rf ( '/run/systemd/system/systemd-timesyncd.service.d' )
732 rm_rf ( '/run/systemd/system/systemd-udevd.service.d' )
733 check_output ( 'systemctl daemon-reload' )
734 check_output ( 'systemctl restart systemd-udevd.service' )
735 restore_active_units ()
738 # pylint: disable=no-member
740 def check_link_exists ( self
, link
, expected
= True ):
742 self
. assertTrue ( link_exists ( link
))
744 self
. assertFalse ( link_exists ( link
))
746 def check_link_attr ( self
, * args
):
747 self
. assertEqual ( read_link_attr (* args
[:- 1 ]), args
[- 1 ])
749 def check_bridge_port_attr ( self
, master
, port
, attribute
, expected
, allow_enoent
= False ):
750 path
= os
. path
. join ( '/sys/devices/virtual/net' , master
, 'lower_' + port
, 'brport' , attribute
)
751 if allow_enoent
and not os
. path
. exists ( path
):
753 with
open ( path
, encoding
= 'utf-8' ) as f
:
754 self
. assertEqual ( f
. readline (). strip (), expected
)
756 def check_ipv4_sysctl_attr ( self
, link
, attribute
, expected
):
757 self
. assertEqual ( read_ipv4_sysctl_attr ( link
, attribute
), expected
)
759 def check_ipv6_sysctl_attr ( self
, link
, attribute
, expected
):
760 self
. assertEqual ( read_ipv6_sysctl_attr ( link
, attribute
), expected
)
762 def wait_links ( self
, * links
, timeout
= 20 , fail_assert
= True ):
763 def links_exist (* links
):
765 if not link_exists ( link
):
769 for iteration
in range ( timeout
+ 1 ):
773 if links_exist (* links
):
776 self
. fail ( 'Timed out waiting for all links to be created: ' + ', ' . join ( list ( links
)))
779 def wait_activated ( self
, link
, state
= 'down' , timeout
= 20 , fail_assert
= True ):
780 # wait for the interface is activated.
781 invocation_id
= check_output ( 'systemctl show systemd-networkd -p InvocationID --value' )
782 needle
= f
' {link} : Bringing link {state} '
784 for iteration
in range ( timeout
+ 1 ):
787 if not link_exists ( link
):
789 output
= check_output ( 'journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
)
790 if needle
in output
and flag
in check_output ( f
'ip link show {link} ' ):
793 self
. fail ( f
'Timed out waiting for {link} activated.' )
796 def wait_operstate ( self
, link
, operstate
= 'degraded' , setup_state
= 'configured' , setup_timeout
= 5 , fail_assert
= True ):
797 """Wait for the link to reach the specified operstate and/or setup state.
799 Specify None or '' for either operstate or setup_state to ignore that state.
800 This will recheck until the state conditions are met or the timeout expires.
802 If the link successfully matches the requested state, this returns True.
803 If this times out waiting for the link to match, the behavior depends on the
804 'fail_assert' parameter; if True, this causes a test assertion failure,
805 otherwise this returns False. The default is to cause assertion failure.
807 Note that this function matches on *exactly* the given operstate and setup_state.
808 To wait for a link to reach *or exceed* a given operstate, use wait_online().
815 for secs
in range ( setup_timeout
+ 1 ):
818 if not link_exists ( link
):
820 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , link
, env
= env
)
821 if re
. search ( rf
'(?m)^\s*State:\s+ {operstate} \s+\( {setup_state} \)\s*$' , output
):
826 self
. fail ( f
'Timed out waiting for {link} to reach state {operstate} / {setup_state} ' )
829 def wait_online ( self
, links_with_operstate
, timeout
= '20s' , bool_any
= False , ipv4
= False , ipv6
= False , setup_state
= 'configured' , setup_timeout
= 5 ):
830 """Wait for the link(s) to reach the specified operstate and/or setup state.
832 This is similar to wait_operstate() but can be used for multiple links,
833 and it also calls systemd-networkd-wait-online to wait for the given operstate.
834 The operstate should be specified in the link name, like 'eth0:degraded'.
835 If just a link name is provided, wait-online's default operstate to wait for is degraded.
837 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
838 'setup_timeout' controls the per-link timeout waiting for the setup_state.
840 Set 'bool_any' to True to wait for any (instead of all) of the given links.
841 If this is set, no setup_state checks are done.
843 Set 'ipv4' or 'ipv6' to True to wait for IPv4 address or IPv6 address, respectively, of each of the given links.
844 This is applied only for the operational state 'degraded' or above.
846 Note that this function waits for the link(s) to reach *or exceed* the given operstate.
847 However, the setup_state, if specified, must be matched *exactly*.
849 This returns if the link(s) reached the requested operstate/setup_state; otherwise it
850 raises CalledProcessError or fails test assertion.
852 args
= wait_online_cmd
+ [ f
'--timeout= {timeout} ' ] + [ f
'--interface= {link} ' for link
in links_with_operstate
]
860 check_output (* args
, env
= wait_online_env
)
861 except subprocess
. CalledProcessError
as e
:
862 # show detailed status on failure
863 for link
in links_with_operstate
:
864 name
= link
. split ( ':' )[ 0 ]
865 if link_exists ( name
):
866 call (* networkctl_cmd
, '-n' , '0' , 'status' , name
, env
= env
)
868 if not bool_any
and setup_state
:
869 for link
in links_with_operstate
:
870 self
. wait_operstate ( link
. split ( ':' )[ 0 ], None , setup_state
, setup_timeout
)
872 def wait_address ( self
, link
, address_regex
, scope
= 'global' , ipv
= '' , timeout_sec
= 100 ):
873 for i
in range ( timeout_sec
):
876 output
= check_output ( f
'ip {ipv} address show dev {link} scope {scope} ' )
877 if re
. search ( address_regex
, output
) and 'tentative' not in output
:
880 self
. assertRegex ( output
, address_regex
)
882 def wait_address_dropped ( self
, link
, address_regex
, scope
= 'global' , ipv
= '' , timeout_sec
= 100 ):
883 for i
in range ( timeout_sec
):
886 output
= check_output ( f
'ip {ipv} address show dev {link} scope {scope} ' )
887 if not re
. search ( address_regex
, output
):
890 self
. assertNotRegex ( output
, address_regex
)
892 class NetworkctlTests ( unittest
. TestCase
, Utilities
):
900 @expectedFailureIfAlternativeNameIsNotAvailable ()
901 def test_altname ( self
):
902 copy_network_unit ( '26-netdev-link-local-addressing-yes.network' , '12-dummy.netdev' , '12-dummy.link' )
904 self
. wait_online ([ 'dummy98:degraded' ])
906 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
907 self
. assertRegex ( output
, 'hogehogehogehogehogehoge' )
909 def test_reconfigure ( self
):
910 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' )
912 self
. wait_online ([ 'dummy98:routable' ])
914 output
= check_output ( 'ip -4 address show dev dummy98' )
916 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
917 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
918 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
920 check_output ( 'ip address del 10.1.2.3/16 dev dummy98' )
921 check_output ( 'ip address del 10.1.2.4/16 dev dummy98' )
922 check_output ( 'ip address del 10.2.2.4/16 dev dummy98' )
924 networkctl_reconfigure ( 'dummy98' )
925 self
. wait_online ([ 'dummy98:routable' ])
927 output
= check_output ( 'ip -4 address show dev dummy98' )
929 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
930 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
931 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
933 remove_network_unit ( '25-address-static.network' )
936 self
. wait_operstate ( 'dummy98' , 'degraded' , setup_state
= 'unmanaged' )
938 output
= check_output ( 'ip -4 address show dev dummy98' )
940 self
. assertNotIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
941 self
. assertNotIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
942 self
. assertNotIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
944 copy_network_unit ( '25-address-static.network' )
946 self
. wait_online ([ 'dummy98:routable' ])
948 output
= check_output ( 'ip -4 address show dev dummy98' )
950 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
951 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
952 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
954 def test_reload ( self
):
957 copy_network_unit ( '11-dummy.netdev' )
959 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'unmanaged' )
961 copy_network_unit ( '11-dummy.network' )
963 self
. wait_online ([ 'test1:degraded' ])
965 remove_network_unit ( '11-dummy.network' )
967 self
. wait_operstate ( 'test1' , 'degraded' , setup_state
= 'unmanaged' )
969 remove_network_unit ( '11-dummy.netdev' )
971 self
. wait_operstate ( 'test1' , 'degraded' , setup_state
= 'unmanaged' )
973 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
975 self
. wait_operstate ( 'test1' , 'degraded' )
978 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
981 self
. wait_online ([ 'test1:degraded' ])
983 output
= check_output (* networkctl_cmd
, 'list' , env
= env
)
984 self
. assertRegex ( output
, '1 lo ' )
985 self
. assertRegex ( output
, 'test1' )
987 output
= check_output (* networkctl_cmd
, 'list' , 'test1' , env
= env
)
988 self
. assertNotRegex ( output
, '1 lo ' )
989 self
. assertRegex ( output
, 'test1' )
991 output
= check_output (* networkctl_cmd
, 'list' , 'te*' , env
= env
)
992 self
. assertNotRegex ( output
, '1 lo ' )
993 self
. assertRegex ( output
, 'test1' )
995 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'te*' , env
= env
)
996 self
. assertNotRegex ( output
, '1: lo ' )
997 self
. assertRegex ( output
, 'test1' )
999 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'tes[a-z][0-9]' , env
= env
)
1000 self
. assertNotRegex ( output
, '1: lo ' )
1001 self
. assertRegex ( output
, 'test1' )
1004 copy_network_unit ( '11-dummy-mtu.netdev' , '11-dummy.network' )
1007 self
. wait_online ([ 'test1:degraded' ])
1009 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
1010 self
. assertRegex ( output
, 'MTU: 1600' )
1012 def test_type ( self
):
1013 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1015 self
. wait_online ([ 'test1:degraded' ])
1017 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
1019 self
. assertRegex ( output
, 'Type: ether' )
1021 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'lo' , env
= env
)
1023 self
. assertRegex ( output
, 'Type: loopback' )
1025 @expectedFailureIfLinkFileFieldIsNotSet ()
1026 def test_udev_link_file ( self
):
1027 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1029 self
. wait_online ([ 'test1:degraded' ])
1031 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
1033 self
. assertRegex ( output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link' )
1034 self
. assertRegex ( output
, r
'Network File: /run/systemd/network/11-dummy.network' )
1036 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'lo' , env
= env
)
1038 self
. assertRegex ( output
, r
'Link File: n/a' )
1039 self
. assertRegex ( output
, r
'Network File: n/a' )
1041 def test_delete_links ( self
):
1042 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' ,
1043 '25-veth.netdev' , '26-netdev-link-local-addressing-yes.network' )
1046 self
. wait_online ([ 'test1:degraded' , 'veth99:degraded' , 'veth-peer:degraded' ])
1048 check_output (* networkctl_cmd
, 'delete' , 'test1' , 'veth99' , env
= env
)
1049 self
. check_link_exists ( 'test1' , expected
= False )
1050 self
. check_link_exists ( 'veth99' , expected
= False )
1051 self
. check_link_exists ( 'veth-peer' , expected
= False )
1053 class NetworkdNetDevTests ( unittest
. TestCase
, Utilities
):
1061 def test_dropin_and_name_conflict ( self
):
1062 copy_network_unit ( '10-dropin-test.netdev' , '15-name-conflict-test.netdev' )
1065 self
. wait_online ([ 'dropin-test:off' ], setup_state
= 'unmanaged' )
1067 output
= check_output ( 'ip link show dropin-test' )
1069 self
. assertRegex ( output
, '00:50:56:c0:00:28' )
1071 def test_match_udev_property ( self
):
1072 copy_network_unit ( '12-dummy.netdev' , '13-not-match-udev-property.network' , '14-match-udev-property.network' )
1074 self
. wait_online ([ 'dummy98:routable' ])
1076 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
1078 self
. assertRegex ( output
, 'Network File: /run/systemd/network/14-match-udev-property' )
1080 def test_wait_online_any ( self
):
1081 copy_network_unit ( '25-bridge.netdev' , '25-bridge.network' , '11-dummy.netdev' , '11-dummy.network' )
1084 self
. wait_online ([ 'bridge99' , 'test1:degraded' ], bool_any
= True )
1086 self
. wait_operstate ( 'bridge99' , '(off|no-carrier)' , setup_state
= 'configuring' )
1087 self
. wait_operstate ( 'test1' , 'degraded' )
1089 @expectedFailureIfModuleIsNotAvailable ( 'bareudp' )
1090 def test_bareudp ( self
):
1091 copy_network_unit ( '25-bareudp.netdev' , '26-netdev-link-local-addressing-yes.network' )
1094 self
. wait_online ([ 'bareudp99:degraded' ])
1096 output
= check_output ( 'ip -d link show bareudp99' )
1098 self
. assertRegex ( output
, 'dstport 1000 ' )
1099 self
. assertRegex ( output
, 'ethertype ip ' )
1101 @expectedFailureIfModuleIsNotAvailable ( 'batman-adv' )
1102 def test_batadv ( self
):
1103 copy_network_unit ( '25-batadv.netdev' , '26-netdev-link-local-addressing-yes.network' )
1106 self
. wait_online ([ 'batadv99:degraded' ])
1108 output
= check_output ( 'ip -d link show batadv99' )
1110 self
. assertRegex ( output
, 'batadv' )
1112 def test_bridge ( self
):
1113 copy_network_unit ( '25-bridge.netdev' , '25-bridge-configure-without-carrier.network' )
1116 self
. wait_online ([ 'bridge99:no-carrier' ])
1118 tick
= os
. sysconf ( 'SC_CLK_TCK' )
1119 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'hello_time' )) / tick
))
1120 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'max_age' )) / tick
))
1121 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'forward_delay' )) / tick
))
1122 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'ageing_time' )) / tick
))
1123 self
. assertEqual ( 9 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'priority' )))
1124 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_querier' )))
1125 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_snooping' )))
1126 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'stp_state' )))
1127 self
. assertEqual ( 3 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_igmp_version' )))
1129 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bridge99' , env
= env
)
1131 self
. assertRegex ( output
, 'Priority: 9' )
1132 self
. assertRegex ( output
, 'STP: yes' )
1133 self
. assertRegex ( output
, 'Multicast IGMP Version: 3' )
1135 output
= check_output ( 'ip -d link show bridge99' )
1137 self
. assertIn ( 'vlan_filtering 1 ' , output
)
1138 self
. assertIn ( 'vlan_protocol 802.1ad ' , output
)
1139 self
. assertIn ( 'vlan_default_pvid 9 ' , output
)
1141 def test_bond ( self
):
1142 copy_network_unit ( '25-bond.netdev' , '25-bond-balanced-tlb.netdev' )
1145 self
. wait_online ([ 'bond99:off' , 'bond98:off' ], setup_state
= 'unmanaged' )
1147 self
. check_link_attr ( 'bond99' , 'bonding' , 'mode' , '802.3ad 4' )
1148 self
. check_link_attr ( 'bond99' , 'bonding' , 'xmit_hash_policy' , 'layer3+4 1' )
1149 self
. check_link_attr ( 'bond99' , 'bonding' , 'miimon' , '1000' )
1150 self
. check_link_attr ( 'bond99' , 'bonding' , 'lacp_rate' , 'fast 1' )
1151 self
. check_link_attr ( 'bond99' , 'bonding' , 'updelay' , '2000' )
1152 self
. check_link_attr ( 'bond99' , 'bonding' , 'downdelay' , '2000' )
1153 self
. check_link_attr ( 'bond99' , 'bonding' , 'resend_igmp' , '4' )
1154 self
. check_link_attr ( 'bond99' , 'bonding' , 'min_links' , '1' )
1155 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_actor_sys_prio' , '1218' )
1156 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_user_port_key' , '811' )
1157 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_actor_system' , '00:11:22:33:44:55' )
1159 self
. check_link_attr ( 'bond98' , 'bonding' , 'mode' , 'balance-tlb 5' )
1160 self
. check_link_attr ( 'bond98' , 'bonding' , 'tlb_dynamic_lb' , '1' )
1162 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bond99' , env
= env
)
1164 self
. assertIn ( 'Mode: 802.3ad' , output
)
1165 self
. assertIn ( 'Miimon: 1s' , output
)
1166 self
. assertIn ( 'Updelay: 2s' , output
)
1167 self
. assertIn ( 'Downdelay: 2s' , output
)
1169 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bond98' , env
= env
)
1171 self
. assertIn ( 'Mode: balance-tlb' , output
)
1173 def test_vlan ( self
):
1174 copy_network_unit ( '21-vlan.netdev' , '11-dummy.netdev' ,
1175 '21-vlan.network' , '21-vlan-test1.network' )
1178 self
. wait_online ([ 'test1:degraded' , 'vlan99:routable' ])
1180 output
= check_output ( 'ip -d link show test1' )
1182 self
. assertRegex ( output
, ' mtu 2000 ' )
1184 output
= check_output ( 'ip -d link show vlan99' )
1186 self
. assertRegex ( output
, ' mtu 2000 ' )
1187 self
. assertRegex ( output
, 'REORDER_HDR' )
1188 self
. assertRegex ( output
, 'LOOSE_BINDING' )
1189 self
. assertRegex ( output
, 'GVRP' )
1190 self
. assertRegex ( output
, 'MVRP' )
1191 self
. assertRegex ( output
, ' id 99 ' )
1193 output
= check_output ( 'ip -4 address show dev test1' )
1195 self
. assertRegex ( output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1' )
1196 self
. assertRegex ( output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1' )
1198 output
= check_output ( 'ip -4 address show dev vlan99' )
1200 self
. assertRegex ( output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99' )
1202 def test_vlan_on_bond ( self
):
1203 # For issue #24377 (https://github.com/systemd/systemd/issues/24377),
1204 # which is fixed by b05e52000b4eee764b383cc3031da0a3739e996e (PR#24020).
1206 copy_network_unit ( '21-bond-802.3ad.netdev' , '21-bond-802.3ad.network' ,
1207 '21-vlan-on-bond.netdev' , '21-vlan-on-bond.network' )
1209 self
. wait_online ([ 'bond99:off' ])
1210 self
. wait_operstate ( 'vlan99' , operstate
= 'off' , setup_state
= 'configuring' , setup_timeout
= 10 )
1212 # The commit b05e52000b4eee764b383cc3031da0a3739e996e adds ", ignoring". To make it easily confirmed
1213 # that the issue is fixed by the commit, let's allow to match both string.
1214 log_re
= re
. compile ( 'vlan99: Could not bring up interface(, ignoring|): Network is down$' , re
. MULTILINE
)
1218 if log_re
. search ( read_networkd_log ()):
1223 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '21-dummy-bond-slave.network' )
1225 self
. wait_online ([ 'test1:enslaved' , 'dummy98:enslaved' , 'bond99:carrier' , 'vlan99:routable' ])
1227 def test_macvtap ( self
):
1229 for mode
in [ 'private' , 'vepa' , 'bridge' , 'passthru' ]:
1235 print ( f
'### test_macvtap(mode= {mode} )' )
1236 with self
. subTest ( mode
= mode
):
1237 copy_network_unit ( '21-macvtap.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1238 '11-dummy.netdev' , '25-macvtap.network' )
1239 with
open ( os
. path
. join ( network_unit_dir
, '21-macvtap.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1240 f
. write ( '[MACVTAP] \n Mode=' + mode
)
1243 self
. wait_online ([ 'macvtap99:degraded' ,
1244 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1246 output
= check_output ( 'ip -d link show macvtap99' )
1248 self
. assertRegex ( output
, 'macvtap mode ' + mode
+ ' ' )
1250 def test_macvlan ( self
):
1252 for mode
in [ 'private' , 'vepa' , 'bridge' , 'passthru' ]:
1258 print ( f
'### test_macvlan(mode= {mode} )' )
1259 with self
. subTest ( mode
= mode
):
1260 copy_network_unit ( '21-macvlan.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1261 '11-dummy.netdev' , '25-macvlan.network' )
1262 with
open ( os
. path
. join ( network_unit_dir
, '21-macvlan.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1263 f
. write ( '[MACVLAN] \n Mode=' + mode
)
1266 self
. wait_online ([ 'macvlan99:degraded' ,
1267 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1269 output
= check_output ( 'ip -d link show test1' )
1271 self
. assertRegex ( output
, ' mtu 2000 ' )
1273 output
= check_output ( 'ip -d link show macvlan99' )
1275 self
. assertRegex ( output
, ' mtu 2000 ' )
1276 self
. assertRegex ( output
, 'macvlan mode ' + mode
+ ' ' )
1278 remove_link ( 'test1' )
1281 check_output ( "ip link add test1 type dummy" )
1282 self
. wait_online ([ 'macvlan99:degraded' ,
1283 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1285 output
= check_output ( 'ip -d link show test1' )
1287 self
. assertRegex ( output
, ' mtu 2000 ' )
1289 output
= check_output ( 'ip -d link show macvlan99' )
1291 self
. assertRegex ( output
, ' mtu 2000 ' )
1292 self
. assertRegex ( output
, 'macvlan mode ' + mode
+ ' ' )
1294 @expectedFailureIfModuleIsNotAvailable ( 'ipvlan' )
1295 def test_ipvlan ( self
):
1297 for mode
, flag
in [[ 'L2' , 'private' ], [ 'L3' , 'vepa' ], [ 'L3S' , 'bridge' ]]:
1303 print ( f
'### test_ipvlan(mode= {mode} , flag= {flag} )' )
1304 with self
. subTest ( mode
= mode
, flag
= flag
):
1305 copy_network_unit ( '25-ipvlan.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1306 '11-dummy.netdev' , '25-ipvlan.network' )
1307 with
open ( os
. path
. join ( network_unit_dir
, '25-ipvlan.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1308 f
. write ( '[IPVLAN] \n Mode=' + mode
+ ' \n Flags=' + flag
)
1311 self
. wait_online ([ 'ipvlan99:degraded' , 'test1:degraded' ])
1313 output
= check_output ( 'ip -d link show ipvlan99' )
1315 self
. assertRegex ( output
, 'ipvlan *mode ' + mode
. lower () + ' ' + flag
)
1317 @expectedFailureIfModuleIsNotAvailable ( 'ipvtap' )
1318 def test_ipvtap ( self
):
1320 for mode
, flag
in [[ 'L2' , 'private' ], [ 'L3' , 'vepa' ], [ 'L3S' , 'bridge' ]]:
1326 print ( f
'### test_ipvtap(mode= {mode} , flag= {flag} )' )
1327 with self
. subTest ( mode
= mode
, flag
= flag
):
1328 copy_network_unit ( '25-ipvtap.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1329 '11-dummy.netdev' , '25-ipvtap.network' )
1330 with
open ( os
. path
. join ( network_unit_dir
, '25-ipvtap.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1331 f
. write ( '[IPVTAP] \n Mode=' + mode
+ ' \n Flags=' + flag
)
1334 self
. wait_online ([ 'ipvtap99:degraded' , 'test1:degraded' ])
1336 output
= check_output ( 'ip -d link show ipvtap99' )
1338 self
. assertRegex ( output
, 'ipvtap *mode ' + mode
. lower () + ' ' + flag
)
1340 def test_veth ( self
):
1341 copy_network_unit ( '25-veth.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1342 '25-veth-mtu.netdev' )
1345 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:degraded' , 'veth-mtu:degraded' , 'veth-mtu-peer:degraded' ])
1347 output
= check_output ( 'ip -d link show veth99' )
1349 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bc' )
1350 output
= check_output ( 'ip -d link show veth-peer' )
1352 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bd' )
1354 output
= check_output ( 'ip -d link show veth-mtu' )
1356 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:be' )
1357 self
. assertRegex ( output
, 'mtu 1800' )
1358 output
= check_output ( 'ip -d link show veth-mtu-peer' )
1360 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bf' )
1361 self
. assertRegex ( output
, 'mtu 1800' )
1363 def test_tuntap ( self
):
1364 copy_network_unit ( '25-tun.netdev' , '25-tap.netdev' , '26-netdev-link-local-addressing-yes.network' )
1367 self
. wait_online ([ 'testtun99:degraded' , 'testtap99:degraded' ])
1369 pid
= networkd_pid ()
1370 name
= psutil
. Process ( pid
). name ()[: 15 ]
1372 output
= check_output ( 'ip -d tuntap show' )
1374 self
. assertRegex ( output
, f
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|) \n\t Attached to processes: {name} \( {pid} \)systemd\(1\)$' )
1375 self
. assertRegex ( output
, f
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|) \n\t Attached to processes: {name} \( {pid} \)systemd\(1\)$' )
1377 output
= check_output ( 'ip -d link show testtun99' )
1379 # Old ip command does not support IFF_ flags
1380 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1381 self
. assertIn ( 'UP,LOWER_UP' , output
)
1383 output
= check_output ( 'ip -d link show testtap99' )
1385 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1386 self
. assertIn ( 'UP,LOWER_UP' , output
)
1388 remove_network_unit ( '26-netdev-link-local-addressing-yes.network' )
1391 self
. wait_online ([ 'testtun99:degraded' , 'testtap99:degraded' ], setup_state
= 'unmanaged' )
1393 pid
= networkd_pid ()
1394 name
= psutil
. Process ( pid
). name ()[: 15 ]
1396 output
= check_output ( 'ip -d tuntap show' )
1398 self
. assertRegex ( output
, f
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|) \n\t Attached to processes: {name} \( {pid} \)systemd\(1\)$' )
1399 self
. assertRegex ( output
, f
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|) \n\t Attached to processes: {name} \( {pid} \)systemd\(1\)$' )
1401 output
= check_output ( 'ip -d link show testtun99' )
1403 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1404 self
. assertIn ( 'UP,LOWER_UP' , output
)
1406 output
= check_output ( 'ip -d link show testtap99' )
1408 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1409 self
. assertIn ( 'UP,LOWER_UP' , output
)
1411 clear_network_units ()
1413 self
. wait_online ([ 'testtun99:off' , 'testtap99:off' ], setup_state
= 'unmanaged' )
1415 output
= check_output ( 'ip -d tuntap show' )
1417 self
. assertRegex ( output
, f
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|) \n\t Attached to processes:$' )
1418 self
. assertRegex ( output
, f
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|) \n\t Attached to processes:$' )
1423 output
= check_output ( 'ip -d link show testtun99' )
1425 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1426 if 'NO-CARRIER' in output
:
1434 output
= check_output ( 'ip -d link show testtap99' )
1436 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1437 if 'NO-CARRIER' in output
:
1442 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
1444 copy_network_unit ( '25-vrf.netdev' , '26-netdev-link-local-addressing-yes.network' )
1447 self
. wait_online ([ 'vrf99:carrier' ])
1449 @expectedFailureIfModuleIsNotAvailable ( 'vcan' )
1450 def test_vcan ( self
):
1451 copy_network_unit ( '25-vcan.netdev' , '26-netdev-link-local-addressing-yes.network' )
1454 self
. wait_online ([ 'vcan99:carrier' ])
1456 @expectedFailureIfModuleIsNotAvailable ( 'vxcan' )
1457 def test_vxcan ( self
):
1458 copy_network_unit ( '25-vxcan.netdev' , '26-netdev-link-local-addressing-yes.network' )
1461 self
. wait_online ([ 'vxcan99:carrier' , 'vxcan-peer:carrier' ])
1463 @expectedFailureIfModuleIsNotAvailable ( 'wireguard' )
1464 def test_wireguard ( self
):
1465 copy_network_unit ( '25-wireguard.netdev' , '25-wireguard.network' ,
1466 '25-wireguard-23-peers.netdev' , '25-wireguard-23-peers.network' ,
1467 '25-wireguard-preshared-key.txt' , '25-wireguard-private-key.txt' ,
1468 '25-wireguard-no-peer.netdev' , '25-wireguard-no-peer.network' )
1470 self
. wait_online ([ 'wg99:routable' , 'wg98:routable' , 'wg97:carrier' ])
1472 output
= check_output ( 'ip -4 address show dev wg99' )
1474 self
. assertIn ( 'inet 192.168.124.1/24 scope global wg99' , output
)
1476 output
= check_output ( 'ip -4 address show dev wg99' )
1478 self
. assertIn ( 'inet 169.254.11.1/24 scope link wg99' , output
)
1480 output
= check_output ( 'ip -6 address show dev wg99' )
1482 self
. assertIn ( 'inet6 fe80::1/64 scope link' , output
)
1484 output
= check_output ( 'ip -4 address show dev wg98' )
1486 self
. assertIn ( 'inet 192.168.123.123/24 scope global wg98' , output
)
1488 output
= check_output ( 'ip -6 address show dev wg98' )
1490 self
. assertIn ( 'inet6 fd8d:4d6d:3ccb:500::1/64 scope global' , output
)
1492 output
= check_output ( 'ip -4 route show dev wg99 table 1234' )
1494 self
. assertIn ( '192.168.26.0/24 proto static metric 123' , output
)
1496 output
= check_output ( 'ip -6 route show dev wg99 table 1234' )
1498 self
. assertIn ( 'fd31:bf08:57cb::/48 proto static metric 123 pref medium' , output
)
1500 output
= check_output ( 'ip -6 route show dev wg98 table 1234' )
1502 self
. assertIn ( 'fd8d:4d6d:3ccb:500:c79:2339:edce:ece1 proto static metric 123 pref medium' , output
)
1503 self
. assertIn ( 'fd8d:4d6d:3ccb:500:1dbf:ca8a:32d3:dd81 proto static metric 123 pref medium' , output
)
1504 self
. assertIn ( 'fd8d:4d6d:3ccb:500:1e54:1415:35d0:a47c proto static metric 123 pref medium' , output
)
1505 self
. assertIn ( 'fd8d:4d6d:3ccb:500:270d:b5dd:4a3f:8909 proto static metric 123 pref medium' , output
)
1506 self
. assertIn ( 'fd8d:4d6d:3ccb:500:5660:679d:3532:94d8 proto static metric 123 pref medium' , output
)
1507 self
. assertIn ( 'fd8d:4d6d:3ccb:500:6825:573f:30f3:9472 proto static metric 123 pref medium' , output
)
1508 self
. assertIn ( 'fd8d:4d6d:3ccb:500:6f2e:6888:c6fd:dfb9 proto static metric 123 pref medium' , output
)
1509 self
. assertIn ( 'fd8d:4d6d:3ccb:500:8d4d:bab:7280:a09a proto static metric 123 pref medium' , output
)
1510 self
. assertIn ( 'fd8d:4d6d:3ccb:500:900c:d437:ec27:8822 proto static metric 123 pref medium' , output
)
1511 self
. assertIn ( 'fd8d:4d6d:3ccb:500:9742:9931:5217:18d5 proto static metric 123 pref medium' , output
)
1512 self
. assertIn ( 'fd8d:4d6d:3ccb:500:9c11:d820:2e96:9be0 proto static metric 123 pref medium' , output
)
1513 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a072:80da:de4f:add1 proto static metric 123 pref medium' , output
)
1514 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a3f3:df38:19b0:721 proto static metric 123 pref medium' , output
)
1515 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a94b:cd6a:a32d:90e6 proto static metric 123 pref medium' , output
)
1516 self
. assertIn ( 'fd8d:4d6d:3ccb:500:b39c:9cdc:755a:ead3 proto static metric 123 pref medium' , output
)
1517 self
. assertIn ( 'fd8d:4d6d:3ccb:500:b684:4f81:2e3e:132e proto static metric 123 pref medium' , output
)
1518 self
. assertIn ( 'fd8d:4d6d:3ccb:500:bad5:495d:8e9c:3427 proto static metric 123 pref medium' , output
)
1519 self
. assertIn ( 'fd8d:4d6d:3ccb:500:bfe5:c3c3:5d77:fcb proto static metric 123 pref medium' , output
)
1520 self
. assertIn ( 'fd8d:4d6d:3ccb:500:c624:6bf7:4c09:3b59 proto static metric 123 pref medium' , output
)
1521 self
. assertIn ( 'fd8d:4d6d:3ccb:500:d4f9:5dc:9296:a1a proto static metric 123 pref medium' , output
)
1522 self
. assertIn ( 'fd8d:4d6d:3ccb:500:dcdd:d33b:90c9:6088 proto static metric 123 pref medium' , output
)
1523 self
. assertIn ( 'fd8d:4d6d:3ccb:500:e2e1:ae15:103f:f376 proto static metric 123 pref medium' , output
)
1524 self
. assertIn ( 'fd8d:4d6d:3ccb:500:f349:c4f0:10c1:6b4 proto static metric 123 pref medium' , output
)
1525 self
. assertIn ( 'fd8d:4d6d:3ccb:c79:2339:edce::/96 proto static metric 123 pref medium' , output
)
1526 self
. assertIn ( 'fd8d:4d6d:3ccb:1dbf:ca8a:32d3::/96 proto static metric 123 pref medium' , output
)
1527 self
. assertIn ( 'fd8d:4d6d:3ccb:1e54:1415:35d0::/96 proto static metric 123 pref medium' , output
)
1528 self
. assertIn ( 'fd8d:4d6d:3ccb:270d:b5dd:4a3f::/96 proto static metric 123 pref medium' , output
)
1529 self
. assertIn ( 'fd8d:4d6d:3ccb:5660:679d:3532::/96 proto static metric 123 pref medium' , output
)
1530 self
. assertIn ( 'fd8d:4d6d:3ccb:6825:573f:30f3::/96 proto static metric 123 pref medium' , output
)
1531 self
. assertIn ( 'fd8d:4d6d:3ccb:6f2e:6888:c6fd::/96 proto static metric 123 pref medium' , output
)
1532 self
. assertIn ( 'fd8d:4d6d:3ccb:8d4d:bab:7280::/96 proto static metric 123 pref medium' , output
)
1533 self
. assertIn ( 'fd8d:4d6d:3ccb:900c:d437:ec27::/96 proto static metric 123 pref medium' , output
)
1534 self
. assertIn ( 'fd8d:4d6d:3ccb:9742:9931:5217::/96 proto static metric 123 pref medium' , output
)
1535 self
. assertIn ( 'fd8d:4d6d:3ccb:9c11:d820:2e96::/96 proto static metric 123 pref medium' , output
)
1536 self
. assertIn ( 'fd8d:4d6d:3ccb:a072:80da:de4f::/96 proto static metric 123 pref medium' , output
)
1537 self
. assertIn ( 'fd8d:4d6d:3ccb:a3f3:df38:19b0::/96 proto static metric 123 pref medium' , output
)
1538 self
. assertIn ( 'fd8d:4d6d:3ccb:a94b:cd6a:a32d::/96 proto static metric 123 pref medium' , output
)
1539 self
. assertIn ( 'fd8d:4d6d:3ccb:b39c:9cdc:755a::/96 proto static metric 123 pref medium' , output
)
1540 self
. assertIn ( 'fd8d:4d6d:3ccb:b684:4f81:2e3e::/96 proto static metric 123 pref medium' , output
)
1541 self
. assertIn ( 'fd8d:4d6d:3ccb:bad5:495d:8e9c::/96 proto static metric 123 pref medium' , output
)
1542 self
. assertIn ( 'fd8d:4d6d:3ccb:bfe5:c3c3:5d77::/96 proto static metric 123 pref medium' , output
)
1543 self
. assertIn ( 'fd8d:4d6d:3ccb:c624:6bf7:4c09::/96 proto static metric 123 pref medium' , output
)
1544 self
. assertIn ( 'fd8d:4d6d:3ccb:d4f9:5dc:9296::/96 proto static metric 123 pref medium' , output
)
1545 self
. assertIn ( 'fd8d:4d6d:3ccb:dcdd:d33b:90c9::/96 proto static metric 123 pref medium' , output
)
1546 self
. assertIn ( 'fd8d:4d6d:3ccb:e2e1:ae15:103f::/96 proto static metric 123 pref medium' , output
)
1547 self
. assertIn ( 'fd8d:4d6d:3ccb:f349:c4f0:10c1::/96 proto static metric 123 pref medium' , output
)
1549 if shutil
. which ( 'wg' ):
1552 output
= check_output ( 'wg show wg99 listen-port' )
1553 self
. assertEqual ( output
, '51820' )
1554 output
= check_output ( 'wg show wg99 fwmark' )
1555 self
. assertEqual ( output
, '0x4d2' )
1556 output
= check_output ( 'wg show wg99 private-key' )
1557 self
. assertEqual ( output
, 'EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=' )
1558 output
= check_output ( 'wg show wg99 allowed-ips' )
1559 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t 192.168.124.3/32' , output
)
1560 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t 192.168.124.2/32' , output
)
1561 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t fdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128' , output
)
1562 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 192.168.26.0/24 fd31:bf08:57cb::/48' , output
)
1563 output
= check_output ( 'wg show wg99 persistent-keepalive' )
1564 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t off' , output
)
1565 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t off' , output
)
1566 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t off' , output
)
1567 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 20' , output
)
1568 output
= check_output ( 'wg show wg99 endpoints' )
1569 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t (none)' , output
)
1570 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t (none)' , output
)
1571 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t (none)' , output
)
1572 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 192.168.27.3:51820' , output
)
1573 output
= check_output ( 'wg show wg99 preshared-keys' )
1574 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t 6Fsg8XN0DE6aPQgAX4r2oazEYJOGqyHUz3QRH/jCB+I=' , output
)
1575 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t it7nd33chCT/tKT2ZZWfYyp43Zs+6oif72hexnSNMqA=' , output
)
1576 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=' , output
)
1577 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=' , output
)
1579 output
= check_output ( 'wg show wg98 private-key' )
1580 self
. assertEqual ( output
, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr+WHtZLZ90FU=' )
1582 output
= check_output ( 'wg show wg97 listen-port' )
1583 self
. assertEqual ( output
, '51821' )
1584 output
= check_output ( 'wg show wg97 fwmark' )
1585 self
. assertEqual ( output
, '0x4d3' )
1587 def test_geneve ( self
):
1588 copy_network_unit ( '25-geneve.netdev' , '26-netdev-link-local-addressing-yes.network' )
1591 self
. wait_online ([ 'geneve99:degraded' ])
1593 output
= check_output ( 'ip -d link show geneve99' )
1595 self
. assertRegex ( output
, '192.168.22.1' )
1596 self
. assertRegex ( output
, '6082' )
1597 self
. assertRegex ( output
, 'udpcsum' )
1598 self
. assertRegex ( output
, 'udp6zerocsumrx' )
1600 def test_ipip_tunnel ( self
):
1601 copy_network_unit ( '12-dummy.netdev' , '25-ipip.network' ,
1602 '25-ipip-tunnel.netdev' , '25-tunnel.network' ,
1603 '25-ipip-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1604 '25-ipip-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1605 '25-ipip-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1607 self
. wait_online ([ 'ipiptun99:routable' , 'ipiptun98:routable' , 'ipiptun97:routable' , 'ipiptun96:routable' , 'dummy98:degraded' ])
1609 output
= check_output ( 'ip -d link show ipiptun99' )
1611 self
. assertRegex ( output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98' )
1612 output
= check_output ( 'ip -d link show ipiptun98' )
1614 self
. assertRegex ( output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98' )
1615 output
= check_output ( 'ip -d link show ipiptun97' )
1617 self
. assertRegex ( output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98' )
1618 output
= check_output ( 'ip -d link show ipiptun96' )
1620 self
. assertRegex ( output
, 'ipip (ipip )?remote any local any dev dummy98' )
1622 def test_gre_tunnel ( self
):
1623 copy_network_unit ( '12-dummy.netdev' , '25-gretun.network' ,
1624 '25-gre-tunnel.netdev' , '25-tunnel.network' ,
1625 '25-gre-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1626 '25-gre-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1627 '25-gre-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1629 self
. wait_online ([ 'gretun99:routable' , 'gretun98:routable' , 'gretun97:routable' , 'gretun96:routable' , 'dummy98:degraded' ])
1631 output
= check_output ( 'ip -d link show gretun99' )
1633 self
. assertRegex ( output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1634 self
. assertRegex ( output
, 'ikey 1.2.3.103' )
1635 self
. assertRegex ( output
, 'okey 1.2.4.103' )
1636 self
. assertRegex ( output
, 'iseq' )
1637 self
. assertRegex ( output
, 'oseq' )
1638 output
= check_output ( 'ip -d link show gretun98' )
1640 self
. assertRegex ( output
, 'gre remote 10.65.223.239 local any dev dummy98' )
1641 self
. assertRegex ( output
, 'ikey 0.0.0.104' )
1642 self
. assertRegex ( output
, 'okey 0.0.0.104' )
1643 self
. assertNotRegex ( output
, 'iseq' )
1644 self
. assertNotRegex ( output
, 'oseq' )
1645 output
= check_output ( 'ip -d link show gretun97' )
1647 self
. assertRegex ( output
, 'gre remote any local 10.65.223.238 dev dummy98' )
1648 self
. assertRegex ( output
, 'ikey 0.0.0.105' )
1649 self
. assertRegex ( output
, 'okey 0.0.0.105' )
1650 self
. assertNotRegex ( output
, 'iseq' )
1651 self
. assertNotRegex ( output
, 'oseq' )
1652 output
= check_output ( 'ip -d link show gretun96' )
1654 self
. assertRegex ( output
, 'gre remote any local any dev dummy98' )
1655 self
. assertRegex ( output
, 'ikey 0.0.0.106' )
1656 self
. assertRegex ( output
, 'okey 0.0.0.106' )
1657 self
. assertNotRegex ( output
, 'iseq' )
1658 self
. assertNotRegex ( output
, 'oseq' )
1660 def test_ip6gre_tunnel ( self
):
1661 copy_network_unit ( '12-dummy.netdev' , '25-ip6gretun.network' ,
1662 '25-ip6gre-tunnel.netdev' , '25-tunnel.network' ,
1663 '25-ip6gre-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1664 '25-ip6gre-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1665 '25-ip6gre-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1668 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1670 self
. wait_links ( 'dummy98' , 'ip6gretun99' , 'ip6gretun98' , 'ip6gretun97' , 'ip6gretun96' )
1672 output
= check_output ( 'ip -d link show ip6gretun99' )
1674 self
. assertRegex ( output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1675 output
= check_output ( 'ip -d link show ip6gretun98' )
1677 self
. assertRegex ( output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98' )
1678 output
= check_output ( 'ip -d link show ip6gretun97' )
1680 self
. assertRegex ( output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98' )
1681 output
= check_output ( 'ip -d link show ip6gretun96' )
1683 self
. assertRegex ( output
, 'ip6gre remote any local any dev dummy98' )
1685 def test_gretap_tunnel ( self
):
1686 copy_network_unit ( '12-dummy.netdev' , '25-gretap.network' ,
1687 '25-gretap-tunnel.netdev' , '25-tunnel.network' ,
1688 '25-gretap-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1690 self
. wait_online ([ 'gretap99:routable' , 'gretap98:routable' , 'dummy98:degraded' ])
1692 output
= check_output ( 'ip -d link show gretap99' )
1694 self
. assertRegex ( output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1695 self
. assertRegex ( output
, 'ikey 0.0.0.106' )
1696 self
. assertRegex ( output
, 'okey 0.0.0.106' )
1697 self
. assertRegex ( output
, 'iseq' )
1698 self
. assertRegex ( output
, 'oseq' )
1699 output
= check_output ( 'ip -d link show gretap98' )
1701 self
. assertRegex ( output
, 'gretap remote 10.65.223.239 local any dev dummy98' )
1702 self
. assertRegex ( output
, 'ikey 0.0.0.107' )
1703 self
. assertRegex ( output
, 'okey 0.0.0.107' )
1704 self
. assertRegex ( output
, 'iseq' )
1705 self
. assertRegex ( output
, 'oseq' )
1707 def test_ip6gretap_tunnel ( self
):
1708 copy_network_unit ( '12-dummy.netdev' , '25-ip6gretap.network' ,
1709 '25-ip6gretap-tunnel.netdev' , '25-tunnel.network' ,
1710 '25-ip6gretap-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1712 self
. wait_online ([ 'ip6gretap99:routable' , 'ip6gretap98:routable' , 'dummy98:degraded' ])
1714 output
= check_output ( 'ip -d link show ip6gretap99' )
1716 self
. assertRegex ( output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1717 output
= check_output ( 'ip -d link show ip6gretap98' )
1719 self
. assertRegex ( output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98' )
1721 def test_vti_tunnel ( self
):
1722 copy_network_unit ( '12-dummy.netdev' , '25-vti.network' ,
1723 '25-vti-tunnel.netdev' , '25-tunnel.network' ,
1724 '25-vti-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1725 '25-vti-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1726 '25-vti-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1728 self
. wait_online ([ 'vtitun99:routable' , 'vtitun98:routable' , 'vtitun97:routable' , 'vtitun96:routable' , 'dummy98:degraded' ])
1730 output
= check_output ( 'ip -d link show vtitun99' )
1732 self
. assertRegex ( output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1733 output
= check_output ( 'ip -d link show vtitun98' )
1735 self
. assertRegex ( output
, 'vti remote 10.65.223.239 local any dev dummy98' )
1736 output
= check_output ( 'ip -d link show vtitun97' )
1738 self
. assertRegex ( output
, 'vti remote any local 10.65.223.238 dev dummy98' )
1739 output
= check_output ( 'ip -d link show vtitun96' )
1741 self
. assertRegex ( output
, 'vti remote any local any dev dummy98' )
1743 def test_vti6_tunnel ( self
):
1744 copy_network_unit ( '12-dummy.netdev' , '25-vti6.network' ,
1745 '25-vti6-tunnel.netdev' , '25-tunnel.network' ,
1746 '25-vti6-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1747 '25-vti6-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' )
1749 self
. wait_online ([ 'vti6tun99:routable' , 'vti6tun98:routable' , 'vti6tun97:routable' , 'dummy98:degraded' ])
1751 output
= check_output ( 'ip -d link show vti6tun99' )
1753 self
. assertRegex ( output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1754 output
= check_output ( 'ip -d link show vti6tun98' )
1756 self
. assertRegex ( output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98' )
1757 output
= check_output ( 'ip -d link show vti6tun97' )
1759 self
. assertRegex ( output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98' )
1761 def test_ip6tnl_tunnel ( self
):
1762 copy_network_unit ( '12-dummy.netdev' , '25-ip6tnl.network' ,
1763 '25-ip6tnl-tunnel.netdev' , '25-tunnel.network' ,
1764 '25-ip6tnl-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1765 '25-ip6tnl-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1766 '25-veth.netdev' , '25-ip6tnl-slaac.network' , '25-ipv6-prefix.network' ,
1767 '25-ip6tnl-tunnel-local-slaac.netdev' , '25-ip6tnl-tunnel-local-slaac.network' ,
1768 '25-ip6tnl-tunnel-external.netdev' , '26-netdev-link-local-addressing-yes.network' )
1770 self
. wait_online ([ 'ip6tnl99:routable' , 'ip6tnl98:routable' , 'ip6tnl97:routable' ,
1771 'ip6tnl-slaac:degraded' , 'ip6tnl-external:degraded' ,
1772 'dummy98:degraded' , 'veth99:routable' , 'veth-peer:degraded' ])
1774 output
= check_output ( 'ip -d link show ip6tnl99' )
1776 self
. assertIn ( 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' , output
)
1777 output
= check_output ( 'ip -d link show ip6tnl98' )
1779 self
. assertRegex ( output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98' )
1780 output
= check_output ( 'ip -d link show ip6tnl97' )
1782 self
. assertRegex ( output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98' )
1783 output
= check_output ( 'ip -d link show ip6tnl-external' )
1785 self
. assertIn ( 'ip6tnl-external@NONE:' , output
)
1786 self
. assertIn ( 'ip6tnl external ' , output
)
1787 output
= check_output ( 'ip -d link show ip6tnl-slaac' )
1789 self
. assertIn ( 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99' , output
)
1791 output
= check_output ( 'ip -6 address show veth99' )
1793 self
. assertIn ( 'inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic' , output
)
1795 output
= check_output ( 'ip -4 route show default' )
1797 self
. assertIn ( 'default dev ip6tnl-slaac proto static' , output
)
1799 def test_sit_tunnel ( self
):
1800 copy_network_unit ( '12-dummy.netdev' , '25-sit.network' ,
1801 '25-sit-tunnel.netdev' , '25-tunnel.network' ,
1802 '25-sit-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1803 '25-sit-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1804 '25-sit-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1806 self
. wait_online ([ 'sittun99:routable' , 'sittun98:routable' , 'sittun97:routable' , 'sittun96:routable' , 'dummy98:degraded' ])
1808 output
= check_output ( 'ip -d link show sittun99' )
1810 self
. assertRegex ( output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98" )
1811 output
= check_output ( 'ip -d link show sittun98' )
1813 self
. assertRegex ( output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98" )
1814 output
= check_output ( 'ip -d link show sittun97' )
1816 self
. assertRegex ( output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98" )
1817 output
= check_output ( 'ip -d link show sittun96' )
1819 self
. assertRegex ( output
, "sit (ip6ip )?remote any local any dev dummy98" )
1821 def test_isatap_tunnel ( self
):
1822 copy_network_unit ( '12-dummy.netdev' , '25-isatap.network' ,
1823 '25-isatap-tunnel.netdev' , '25-tunnel.network' )
1825 self
. wait_online ([ 'isataptun99:routable' , 'dummy98:degraded' ])
1827 output
= check_output ( 'ip -d link show isataptun99' )
1829 self
. assertRegex ( output
, "isatap " )
1831 def test_6rd_tunnel ( self
):
1832 copy_network_unit ( '12-dummy.netdev' , '25-6rd.network' ,
1833 '25-6rd-tunnel.netdev' , '25-tunnel.network' )
1835 self
. wait_online ([ 'sittun99:routable' , 'dummy98:degraded' ])
1837 output
= check_output ( 'ip -d link show sittun99' )
1839 self
. assertRegex ( output
, '6rd-prefix 2602::/24' )
1841 @expectedFailureIfERSPANv0IsNotSupported ()
1842 def test_erspan_tunnel_v0 ( self
):
1843 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
1844 '25-erspan0-tunnel.netdev' , '25-tunnel.network' ,
1845 '25-erspan0-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1847 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
1849 output
= check_output ( 'ip -d link show erspan99' )
1851 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
1852 self
. assertIn ( 'erspan_ver 0' , output
)
1853 self
. assertNotIn ( 'erspan_index 123' , output
)
1854 self
. assertNotIn ( 'erspan_dir ingress' , output
)
1855 self
. assertNotIn ( 'erspan_hwid 1f' , output
)
1856 self
. assertIn ( 'ikey 0.0.0.101' , output
)
1857 self
. assertIn ( 'iseq' , output
)
1858 output
= check_output ( 'ip -d link show erspan98' )
1860 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
1861 self
. assertIn ( 'erspan_ver 0' , output
)
1862 self
. assertNotIn ( 'erspan_index 124' , output
)
1863 self
. assertNotIn ( 'erspan_dir egress' , output
)
1864 self
. assertNotIn ( 'erspan_hwid 2f' , output
)
1865 self
. assertIn ( 'ikey 0.0.0.102' , output
)
1866 self
. assertIn ( 'iseq' , output
)
1868 def test_erspan_tunnel_v1 ( self
):
1869 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
1870 '25-erspan1-tunnel.netdev' , '25-tunnel.network' ,
1871 '25-erspan1-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1873 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
1875 output
= check_output ( 'ip -d link show erspan99' )
1877 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
1878 self
. assertIn ( 'erspan_ver 1' , output
)
1879 self
. assertIn ( 'erspan_index 123' , output
)
1880 self
. assertNotIn ( 'erspan_dir ingress' , output
)
1881 self
. assertNotIn ( 'erspan_hwid 1f' , output
)
1882 self
. assertIn ( 'ikey 0.0.0.101' , output
)
1883 self
. assertIn ( 'okey 0.0.0.101' , output
)
1884 self
. assertIn ( 'iseq' , output
)
1885 self
. assertIn ( 'oseq' , output
)
1886 output
= check_output ( 'ip -d link show erspan98' )
1888 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
1889 self
. assertIn ( 'erspan_ver 1' , output
)
1890 self
. assertIn ( 'erspan_index 124' , output
)
1891 self
. assertNotIn ( 'erspan_dir egress' , output
)
1892 self
. assertNotIn ( 'erspan_hwid 2f' , output
)
1893 self
. assertIn ( 'ikey 0.0.0.102' , output
)
1894 self
. assertIn ( 'okey 0.0.0.102' , output
)
1895 self
. assertIn ( 'iseq' , output
)
1896 self
. assertIn ( 'oseq' , output
)
1898 @expectedFailureIfERSPANv2IsNotSupported ()
1899 def test_erspan_tunnel_v2 ( self
):
1900 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
1901 '25-erspan2-tunnel.netdev' , '25-tunnel.network' ,
1902 '25-erspan2-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1904 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
1906 output
= check_output ( 'ip -d link show erspan99' )
1908 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
1909 self
. assertIn ( 'erspan_ver 2' , output
)
1910 self
. assertNotIn ( 'erspan_index 123' , output
)
1911 self
. assertIn ( 'erspan_dir ingress' , output
)
1912 self
. assertIn ( 'erspan_hwid 0x1f' , output
)
1913 self
. assertIn ( 'ikey 0.0.0.101' , output
)
1914 self
. assertIn ( 'okey 0.0.0.101' , output
)
1915 self
. assertIn ( 'iseq' , output
)
1916 self
. assertIn ( 'oseq' , output
)
1917 output
= check_output ( 'ip -d link show erspan98' )
1919 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
1920 self
. assertIn ( 'erspan_ver 2' , output
)
1921 self
. assertNotIn ( 'erspan_index 124' , output
)
1922 self
. assertIn ( 'erspan_dir egress' , output
)
1923 self
. assertIn ( 'erspan_hwid 0x2f' , output
)
1924 self
. assertIn ( 'ikey 0.0.0.102' , output
)
1925 self
. assertIn ( 'okey 0.0.0.102' , output
)
1926 self
. assertIn ( 'iseq' , output
)
1927 self
. assertIn ( 'oseq' , output
)
1929 def test_tunnel_independent ( self
):
1930 copy_network_unit ( '25-ipip-tunnel-independent.netdev' , '26-netdev-link-local-addressing-yes.network' )
1933 self
. wait_online ([ 'ipiptun99:carrier' ])
1935 def test_tunnel_independent_loopback ( self
):
1936 copy_network_unit ( '25-ipip-tunnel-independent-loopback.netdev' , '26-netdev-link-local-addressing-yes.network' )
1939 self
. wait_online ([ 'ipiptun99:carrier' ])
1941 @expectedFailureIfModuleIsNotAvailable ( 'xfrm_interface' )
1942 def test_xfrm ( self
):
1943 copy_network_unit ( '12-dummy.netdev' , '25-xfrm.network' ,
1944 '25-xfrm.netdev' , '25-xfrm-independent.netdev' ,
1945 '26-netdev-link-local-addressing-yes.network' )
1948 self
. wait_online ([ 'dummy98:degraded' , 'xfrm98:degraded' , 'xfrm99:degraded' ])
1950 output
= check_output ( 'ip -d link show dev xfrm98' )
1952 self
. assertIn ( 'xfrm98@dummy98:' , output
)
1953 self
. assertIn ( 'xfrm if_id 0x98 ' , output
)
1955 output
= check_output ( 'ip -d link show dev xfrm99' )
1957 self
. assertIn ( 'xfrm99@lo:' , output
)
1958 self
. assertIn ( 'xfrm if_id 0x99 ' , output
)
1960 @expectedFailureIfModuleIsNotAvailable ( 'fou' )
1962 # The following redundant check is necessary for CentOS CI.
1963 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1964 self
. assertTrue ( is_module_available ( 'fou' ))
1966 copy_network_unit ( '25-fou-ipproto-ipip.netdev' , '25-fou-ipproto-gre.netdev' ,
1967 '25-fou-ipip.netdev' , '25-fou-sit.netdev' ,
1968 '25-fou-gre.netdev' , '25-fou-gretap.netdev' )
1971 self
. wait_online ([ 'ipiptun96:off' , 'sittun96:off' , 'gretun96:off' , 'gretap96:off' ], setup_state
= 'unmanaged' )
1973 output
= check_output ( 'ip fou show' )
1975 self
. assertRegex ( output
, 'port 55555 ipproto 4' )
1976 self
. assertRegex ( output
, 'port 55556 ipproto 47' )
1978 output
= check_output ( 'ip -d link show ipiptun96' )
1980 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55555' )
1981 output
= check_output ( 'ip -d link show sittun96' )
1983 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55555' )
1984 output
= check_output ( 'ip -d link show gretun96' )
1986 self
. assertRegex ( output
, 'encap fou encap-sport 1001 encap-dport 55556' )
1987 output
= check_output ( 'ip -d link show gretap96' )
1989 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55556' )
1991 def test_vxlan ( self
):
1992 copy_network_unit ( '11-dummy.netdev' , '25-vxlan-test1.network' ,
1993 '25-vxlan.netdev' , '25-vxlan.network' ,
1994 '25-vxlan-ipv6.netdev' , '25-vxlan-ipv6.network' ,
1995 '25-vxlan-independent.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1996 '25-veth.netdev' , '25-vxlan-veth99.network' , '25-ipv6-prefix.network' ,
1997 '25-vxlan-local-slaac.netdev' , '25-vxlan-local-slaac.network' )
2000 self
. wait_online ([ 'test1:degraded' , 'veth99:routable' , 'veth-peer:degraded' ,
2001 'vxlan99:degraded' , 'vxlan98:degraded' , 'vxlan97:degraded' , 'vxlan-slaac:degraded' ])
2003 output
= check_output ( 'ip -d link show vxlan99' )
2005 self
. assertIn ( '999' , output
)
2006 self
. assertIn ( '5555' , output
)
2007 self
. assertIn ( 'l2miss' , output
)
2008 self
. assertIn ( 'l3miss' , output
)
2009 self
. assertIn ( 'udpcsum' , output
)
2010 self
. assertIn ( 'udp6zerocsumtx' , output
)
2011 self
. assertIn ( 'udp6zerocsumrx' , output
)
2012 self
. assertIn ( 'remcsumtx' , output
)
2013 self
. assertIn ( 'remcsumrx' , output
)
2014 self
. assertIn ( 'gbp' , output
)
2016 output
= check_output ( 'bridge fdb show dev vxlan99' )
2018 self
. assertIn ( '00:11:22:33:44:55 dst 10.0.0.5 self permanent' , output
)
2019 self
. assertIn ( '00:11:22:33:44:66 dst 10.0.0.6 self permanent' , output
)
2020 self
. assertIn ( '00:11:22:33:44:77 dst 10.0.0.7 via test1 self permanent' , output
)
2022 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'vxlan99' , env
= env
)
2024 self
. assertIn ( 'VNI: 999' , output
)
2025 self
. assertIn ( 'Destination Port: 5555' , output
)
2026 self
. assertIn ( 'Underlying Device: test1' , output
)
2028 output
= check_output ( 'bridge fdb show dev vxlan97' )
2030 self
. assertIn ( '00:00:00:00:00:00 dst fe80::23b:d2ff:fe95:967f via test1 self permanent' , output
)
2031 self
. assertIn ( '00:00:00:00:00:00 dst fe80::27c:16ff:fec0:6c74 via test1 self permanent' , output
)
2032 self
. assertIn ( '00:00:00:00:00:00 dst fe80::2a2:e4ff:fef9:2269 via test1 self permanent' , output
)
2034 output
= check_output ( 'ip -d link show vxlan-slaac' )
2036 self
. assertIn ( 'vxlan id 4831584 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99' , output
)
2038 output
= check_output ( 'ip -6 address show veth99' )
2040 self
. assertIn ( 'inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic' , output
)
2042 @unittest . skip ( reason
= "Causes kernel panic on recent kernels: https://bugzilla.kernel.org/show_bug.cgi?id=208315" )
2043 def test_macsec ( self
):
2044 copy_network_unit ( '25-macsec.netdev' , '25-macsec.network' , '25-macsec.key' ,
2045 '26-macsec.network' , '12-dummy.netdev' )
2048 self
. wait_online ([ 'dummy98:degraded' , 'macsec99:routable' ])
2050 output
= check_output ( 'ip -d link show macsec99' )
2052 self
. assertRegex ( output
, 'macsec99@dummy98' )
2053 self
. assertRegex ( output
, 'macsec sci [0-9a-f]*000b' )
2054 self
. assertRegex ( output
, 'encrypt on' )
2056 output
= check_output ( 'ip macsec show macsec99' )
2058 self
. assertRegex ( output
, 'encrypt on' )
2059 self
. assertRegex ( output
, 'TXSC: [0-9a-f]*000b on SA 1' )
2060 self
. assertRegex ( output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000' )
2061 self
. assertRegex ( output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000' )
2062 self
. assertRegex ( output
, 'RXSC: c619528fe6a00100, state on' )
2063 self
. assertRegex ( output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000' )
2064 self
. assertRegex ( output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000' )
2065 self
. assertRegex ( output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000' )
2066 self
. assertRegex ( output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000' )
2067 self
. assertNotRegex ( output
, 'key 02030405067080900000000000000000' )
2068 self
. assertRegex ( output
, 'RXSC: 8c16456c83a90002, state on' )
2069 self
. assertRegex ( output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000' )
2071 def test_nlmon ( self
):
2072 copy_network_unit ( '25-nlmon.netdev' , '26-netdev-link-local-addressing-yes.network' )
2075 self
. wait_online ([ 'nlmon99:carrier' ])
2077 @expectedFailureIfModuleIsNotAvailable ( 'ifb' )
2079 copy_network_unit ( '25-ifb.netdev' , '26-netdev-link-local-addressing-yes.network' )
2082 self
. wait_online ([ 'ifb99:degraded' ])
2084 class NetworkdL2TPTests ( unittest
. TestCase
, Utilities
):
2092 @expectedFailureIfModuleIsNotAvailable ( 'l2tp_eth' , 'l2tp_netlink' )
2093 def test_l2tp_udp ( self
):
2094 copy_network_unit ( '11-dummy.netdev' , '25-l2tp-dummy.network' ,
2095 '25-l2tp-udp.netdev' , '25-l2tp.network' )
2098 self
. wait_online ([ 'test1:routable' , 'l2tp-ses1:degraded' , 'l2tp-ses2:degraded' ])
2100 output
= check_output ( 'ip l2tp show tunnel tunnel_id 10' )
2102 self
. assertRegex ( output
, "Tunnel 10, encap UDP" )
2103 self
. assertRegex ( output
, "From 192.168.30.100 to 192.168.30.101" )
2104 self
. assertRegex ( output
, "Peer tunnel 11" )
2105 self
. assertRegex ( output
, "UDP source / dest ports: 3000/4000" )
2106 self
. assertRegex ( output
, "UDP checksum: enabled" )
2108 output
= check_output ( 'ip l2tp show session tid 10 session_id 15' )
2110 self
. assertRegex ( output
, "Session 15 in tunnel 10" )
2111 self
. assertRegex ( output
, "Peer session 16, tunnel 11" )
2112 self
. assertRegex ( output
, "interface name: l2tp-ses1" )
2114 output
= check_output ( 'ip l2tp show session tid 10 session_id 17' )
2116 self
. assertRegex ( output
, "Session 17 in tunnel 10" )
2117 self
. assertRegex ( output
, "Peer session 18, tunnel 11" )
2118 self
. assertRegex ( output
, "interface name: l2tp-ses2" )
2120 @expectedFailureIfModuleIsNotAvailable ( 'l2tp_eth' , 'l2tp_ip' , 'l2tp_netlink' )
2121 def test_l2tp_ip ( self
):
2122 copy_network_unit ( '11-dummy.netdev' , '25-l2tp-dummy.network' ,
2123 '25-l2tp-ip.netdev' , '25-l2tp.network' )
2126 self
. wait_online ([ 'test1:routable' , 'l2tp-ses3:degraded' , 'l2tp-ses4:degraded' ])
2128 output
= check_output ( 'ip l2tp show tunnel tunnel_id 10' )
2130 self
. assertRegex ( output
, "Tunnel 10, encap IP" )
2131 self
. assertRegex ( output
, "From 192.168.30.100 to 192.168.30.101" )
2132 self
. assertRegex ( output
, "Peer tunnel 12" )
2134 output
= check_output ( 'ip l2tp show session tid 10 session_id 25' )
2136 self
. assertRegex ( output
, "Session 25 in tunnel 10" )
2137 self
. assertRegex ( output
, "Peer session 26, tunnel 12" )
2138 self
. assertRegex ( output
, "interface name: l2tp-ses3" )
2140 output
= check_output ( 'ip l2tp show session tid 10 session_id 27' )
2142 self
. assertRegex ( output
, "Session 27 in tunnel 10" )
2143 self
. assertRegex ( output
, "Peer session 28, tunnel 12" )
2144 self
. assertRegex ( output
, "interface name: l2tp-ses4" )
2146 class NetworkdNetworkTests ( unittest
. TestCase
, Utilities
):
2154 def test_address_static ( self
):
2155 # test for #22515. The address will be removed and replaced with /64 prefix.
2156 check_output ( 'ip link add dummy98 type dummy' )
2157 check_output ( 'ip link set dev dummy98 up' )
2158 check_output ( 'ip -6 address add 2001:db8:0:f101::15/128 dev dummy98' )
2159 self
. wait_address ( 'dummy98' , '2001:db8:0:f101::15/128' , ipv
= '-6' )
2160 check_output ( 'ip -4 address add 10.3.2.3/16 brd 10.3.255.250 scope global label dummy98:hoge dev dummy98' )
2161 self
. wait_address ( 'dummy98' , '10.3.2.3/16 brd 10.3.255.250' , ipv
= '-4' )
2163 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' )
2166 self
. wait_online ([ 'dummy98:routable' ])
2168 output
= check_output ( 'ip -4 address show dev dummy98' )
2170 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
2171 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
2172 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
2173 self
. assertIn ( 'inet 10.7.8.9/16 brd 10.7.255.255 scope link deprecated dummy98' , output
)
2174 self
. assertIn ( 'inet 10.8.8.1/16 scope global dummy98' , output
)
2175 self
. assertIn ( 'inet 10.8.8.2/16 brd 10.8.8.128 scope global secondary dummy98' , output
)
2176 self
. assertRegex ( output
, 'inet 10.9.0.1/16 (metric 128 |)brd 10.9.255.255 scope global dummy98' )
2178 # test for ENOBUFS issue #17012
2179 for i
in range ( 1 , 254 ):
2180 self
. assertIn ( f
'inet 10.3.3. {i} /16 brd 10.3.255.255' , output
)
2183 self
. assertNotIn ( '10.10.0.1/16' , output
)
2184 self
. assertNotIn ( '10.10.0.2/16' , output
)
2186 output
= check_output ( 'ip -4 address show dev dummy98 label 32' )
2187 self
. assertIn ( 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32' , output
)
2189 output
= check_output ( 'ip -4 address show dev dummy98 label 33' )
2190 self
. assertIn ( 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33' , output
)
2192 output
= check_output ( 'ip -4 address show dev dummy98 label 34' )
2193 self
. assertRegex ( output
, r
'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34' )
2195 output
= check_output ( 'ip -4 address show dev dummy98 label 35' )
2196 self
. assertRegex ( output
, r
'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35' )
2198 output
= check_output ( 'ip -4 route show dev dummy98' )
2200 self
. assertIn ( '10.9.0.0/16 proto kernel scope link src 10.9.0.1 metric 128' , output
)
2202 output
= check_output ( 'ip -6 address show dev dummy98' )
2204 self
. assertIn ( 'inet6 2001:db8:0:f101::15/64 scope global' , output
)
2205 self
. assertIn ( 'inet6 2001:db8:0:f101::16/64 scope global' , output
)
2206 self
. assertIn ( 'inet6 2001:db8:0:f102::15/64 scope global' , output
)
2207 self
. assertIn ( 'inet6 2001:db8:0:f102::16/64 scope global' , output
)
2208 self
. assertIn ( 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global' , output
)
2209 self
. assertIn ( 'inet6 2001:db8:1:f101::1/64 scope global deprecated' , output
)
2210 self
. assertRegex ( output
, r
'inet6 fd[0-9a-f:]*1/64 scope global' )
2213 # 1. set preferred lifetime forever to drop the deprecated flag for testing #20891.
2214 check_output ( 'ip address change 10.7.8.9/16 dev dummy98 preferred_lft forever' )
2215 check_output ( 'ip address change 2001:db8:1:f101::1/64 dev dummy98 preferred_lft forever' )
2216 output
= check_output ( 'ip -4 address show dev dummy98' )
2218 self
. assertNotIn ( 'deprecated' , output
)
2219 output
= check_output ( 'ip -6 address show dev dummy98' )
2221 self
. assertNotIn ( 'deprecated' , output
)
2223 # 2. reconfigure the interface.
2224 networkctl_reconfigure ( 'dummy98' )
2225 self
. wait_online ([ 'dummy98:routable' ])
2227 # 3. check the deprecated flag is set for the address configured with PreferredLifetime=0
2228 output
= check_output ( 'ip -4 address show dev dummy98' )
2230 self
. assertIn ( 'inet 10.7.8.9/16 brd 10.7.255.255 scope link deprecated dummy98' , output
)
2231 output
= check_output ( 'ip -6 address show dev dummy98' )
2233 self
. assertIn ( 'inet6 2001:db8:1:f101::1/64 scope global deprecated' , output
)
2235 # test for ENOBUFS issue #17012
2236 output
= check_output ( 'ip -4 address show dev dummy98' )
2237 for i
in range ( 1 , 254 ):
2238 self
. assertIn ( f
'inet 10.3.3. {i} /16 brd 10.3.255.255' , output
)
2240 # TODO: check json string
2241 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2243 def test_address_ipv4acd ( self
):
2244 check_output ( 'ip netns add ns99' )
2245 check_output ( 'ip link add veth99 type veth peer veth-peer' )
2246 check_output ( 'ip link set veth-peer netns ns99' )
2247 check_output ( 'ip link set veth99 up' )
2248 check_output ( 'ip netns exec ns99 ip link set veth-peer up' )
2249 check_output ( 'ip netns exec ns99 ip address add 192.168.100.10/24 dev veth-peer' )
2251 copy_network_unit ( '25-address-ipv4acd-veth99.network' , copy_dropins
= False )
2253 self
. wait_online ([ 'veth99:routable' ])
2255 output
= check_output ( 'ip -4 address show dev veth99' )
2257 self
. assertNotIn ( '192.168.100.10/24' , output
)
2258 self
. assertIn ( '192.168.100.11/24' , output
)
2260 copy_network_unit ( '25-address-ipv4acd-veth99.network.d/conflict-address.conf' )
2262 self
. wait_operstate ( 'veth99' , operstate
= 'routable' , setup_state
= 'configuring' , setup_timeout
= 10 )
2264 output
= check_output ( 'ip -4 address show dev veth99' )
2266 self
. assertNotIn ( '192.168.100.10/24' , output
)
2267 self
. assertIn ( '192.168.100.11/24' , output
)
2269 def test_address_peer_ipv4 ( self
):
2270 # test for issue #17304
2271 copy_network_unit ( '25-address-peer-ipv4.network' , '12-dummy.netdev' )
2273 for trial
in range ( 2 ):
2279 self
. wait_online ([ 'dummy98:routable' ])
2281 output
= check_output ( 'ip -4 address show dev dummy98' )
2282 self
. assertIn ( 'inet 100.64.0.1 peer 100.64.0.2/32 scope global' , output
)
2284 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
2285 def test_prefix_route ( self
):
2286 copy_network_unit ( '25-prefix-route-with-vrf.network' , '12-dummy.netdev' ,
2287 '25-prefix-route-without-vrf.network' , '11-dummy.netdev' ,
2288 '25-vrf.netdev' , '25-vrf.network' )
2289 for trial
in range ( 2 ):
2295 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' , 'vrf99:carrier' ])
2297 output
= check_output ( 'ip route show table 42 dev dummy98' )
2298 print ( '### ip route show table 42 dev dummy98' )
2300 self
. assertRegex ( output
, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1' )
2301 self
. assertRegex ( output
, '10.20.33.0/24 proto kernel scope link src 10.20.33.1' )
2302 self
. assertRegex ( output
, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1' )
2303 self
. assertRegex ( output
, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1' )
2304 self
. assertRegex ( output
, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1' )
2305 self
. assertRegex ( output
, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1' )
2306 self
. assertRegex ( output
, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1' )
2307 output
= check_output ( 'ip -6 route show table 42 dev dummy98' )
2308 print ( '### ip -6 route show table 42 dev dummy98' )
2312 self
. assertRegex ( output
, 'local fdde:11:22::1 proto kernel metric 0 pref medium' )
2313 #self.assertRegex(output, 'fdde:11:22::1 proto kernel metric 256 pref medium')
2314 self
. assertRegex ( output
, 'local fdde:11:33::1 proto kernel metric 0 pref medium' )
2315 self
. assertRegex ( output
, 'fdde:11:33::/64 proto kernel metric 256 pref medium' )
2316 self
. assertRegex ( output
, 'local fdde:11:44::1 proto kernel metric 0 pref medium' )
2317 self
. assertRegex ( output
, 'local fdde:11:55::1 proto kernel metric 0 pref medium' )
2318 self
. assertRegex ( output
, 'fe80::/64 proto kernel metric 256 pref medium' )
2319 self
. assertRegex ( output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium' )
2323 output
= check_output ( 'ip route show dev test1' )
2324 print ( '### ip route show dev test1' )
2326 self
. assertRegex ( output
, '10.21.33.0/24 proto kernel scope link src 10.21.33.1' )
2327 output
= check_output ( 'ip route show table local dev test1' )
2328 print ( '### ip route show table local dev test1' )
2330 self
. assertRegex ( output
, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1' )
2331 self
. assertRegex ( output
, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1' )
2332 self
. assertRegex ( output
, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1' )
2333 self
. assertRegex ( output
, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1' )
2334 self
. assertRegex ( output
, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1' )
2335 self
. assertRegex ( output
, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1' )
2336 output
= check_output ( 'ip -6 route show dev test1' )
2337 print ( '### ip -6 route show dev test1' )
2339 self
. assertRegex ( output
, 'fdde:12:22::1 proto kernel metric 256 pref medium' )
2340 self
. assertRegex ( output
, 'fdde:12:33::/64 proto kernel metric 256 pref medium' )
2341 self
. assertRegex ( output
, 'fe80::/64 proto kernel metric 256 pref medium' )
2342 output
= check_output ( 'ip -6 route show table local dev test1' )
2343 print ( '### ip -6 route show table local dev test1' )
2345 self
. assertRegex ( output
, 'local fdde:12:22::1 proto kernel metric 0 pref medium' )
2346 self
. assertRegex ( output
, 'local fdde:12:33::1 proto kernel metric 0 pref medium' )
2347 self
. assertRegex ( output
, 'local fdde:12:44::1 proto kernel metric 0 pref medium' )
2348 self
. assertRegex ( output
, 'local fdde:12:55::1 proto kernel metric 0 pref medium' )
2349 self
. assertRegex ( output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium' )
2351 def test_configure_without_carrier ( self
):
2352 copy_network_unit ( '11-dummy.netdev' )
2354 self
. wait_operstate ( 'test1' , 'off' , '' )
2355 check_output ( 'ip link set dev test1 up carrier off' )
2357 copy_network_unit ( '25-test1.network.d/configure-without-carrier.conf' , copy_dropins
= False )
2359 self
. wait_online ([ 'test1:no-carrier' ])
2361 carrier_map
= { 'on' : '1' , 'off' : '0' }
2362 routable_map
= { 'on' : 'routable' , 'off' : 'no-carrier' }
2363 for carrier
in [ 'off' , 'on' , 'off' ]:
2364 with self
. subTest ( carrier
= carrier
):
2365 if carrier_map
[ carrier
] != read_link_attr ( 'test1' , 'carrier' ):
2366 check_output ( f
'ip link set dev test1 carrier {carrier} ' )
2367 self
. wait_online ([ f
'test1:{routable_map[carrier]}:{routable_map[carrier]}' ])
2369 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
2371 self
. assertRegex ( output
, '192.168.0.15' )
2372 self
. assertRegex ( output
, '192.168.0.1' )
2373 self
. assertRegex ( output
, routable_map
[ carrier
])
2375 def test_configure_without_carrier_yes_ignore_carrier_loss_no ( self
):
2376 copy_network_unit ( '11-dummy.netdev' )
2378 self
. wait_operstate ( 'test1' , 'off' , '' )
2379 check_output ( 'ip link set dev test1 up carrier off' )
2381 copy_network_unit ( '25-test1.network' )
2383 self
. wait_online ([ 'test1:no-carrier' ])
2385 carrier_map
= { 'on' : '1' , 'off' : '0' }
2386 routable_map
= { 'on' : 'routable' , 'off' : 'no-carrier' }
2387 for ( carrier
, have_config
) in [( 'off' , True ), ( 'on' , True ), ( 'off' , False )]:
2388 with self
. subTest ( carrier
= carrier
, have_config
= have_config
):
2389 if carrier_map
[ carrier
] != read_link_attr ( 'test1' , 'carrier' ):
2390 check_output ( f
'ip link set dev test1 carrier {carrier} ' )
2391 self
. wait_online ([ f
'test1:{routable_map[carrier]}:{routable_map[carrier]}' ])
2393 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
2396 self
. assertRegex ( output
, '192.168.0.15' )
2397 self
. assertRegex ( output
, '192.168.0.1' )
2399 self
. assertNotRegex ( output
, '192.168.0.15' )
2400 self
. assertNotRegex ( output
, '192.168.0.1' )
2401 self
. assertRegex ( output
, routable_map
[ carrier
])
2403 def test_routing_policy_rule ( self
):
2404 copy_network_unit ( '25-routing-policy-rule-test1.network' , '11-dummy.netdev' )
2406 self
. wait_online ([ 'test1:degraded' ])
2408 output
= check_output ( 'ip rule list iif test1 priority 111' )
2410 self
. assertRegex ( output
, '111:' )
2411 self
. assertRegex ( output
, 'from 192.168.100.18' )
2412 self
. assertRegex ( output
, r
'tos (0x08|throughput)\s' )
2413 self
. assertRegex ( output
, 'iif test1' )
2414 self
. assertRegex ( output
, 'oif test1' )
2415 self
. assertRegex ( output
, 'lookup 7' )
2417 output
= check_output ( 'ip rule list iif test1 priority 101' )
2419 self
. assertRegex ( output
, '101:' )
2420 self
. assertRegex ( output
, 'from all' )
2421 self
. assertRegex ( output
, 'iif test1' )
2422 self
. assertRegex ( output
, 'lookup 9' )
2424 output
= check_output ( 'ip -6 rule list iif test1 priority 100' )
2426 self
. assertRegex ( output
, '100:' )
2427 self
. assertRegex ( output
, 'from all' )
2428 self
. assertRegex ( output
, 'iif test1' )
2429 self
. assertRegex ( output
, 'lookup 8' )
2431 output
= check_output ( 'ip rule list iif test1 priority 102' )
2433 self
. assertRegex ( output
, '102:' )
2434 self
. assertRegex ( output
, 'from 0.0.0.0/8' )
2435 self
. assertRegex ( output
, 'iif test1' )
2436 self
. assertRegex ( output
, 'lookup 10' )
2438 # TODO: check json string
2439 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2441 def test_routing_policy_rule_issue_11280 ( self
):
2442 copy_network_unit ( '25-routing-policy-rule-test1.network' , '11-dummy.netdev' ,
2443 '25-routing-policy-rule-dummy98.network' , '12-dummy.netdev' )
2445 for trial
in range ( 3 ):
2446 restart_networkd ( show_logs
=( trial
> 0 ))
2447 self
. wait_online ([ 'test1:degraded' , 'dummy98:degraded' ])
2449 output
= check_output ( 'ip rule list table 7' )
2451 self
. assertRegex ( output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7' )
2453 output
= check_output ( 'ip rule list table 8' )
2455 self
. assertRegex ( output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8' )
2457 def test_routing_policy_rule_reconfigure ( self
):
2458 copy_network_unit ( '25-routing-policy-rule-reconfigure2.network' , '11-dummy.netdev' )
2460 self
. wait_online ([ 'test1:degraded' ])
2462 output
= check_output ( 'ip rule list table 1011' )
2464 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2465 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2466 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2467 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2469 output
= check_output ( 'ip -6 rule list table 1011' )
2471 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2473 copy_network_unit ( '25-routing-policy-rule-reconfigure1.network' , '11-dummy.netdev' )
2475 self
. wait_online ([ 'test1:degraded' ])
2477 output
= check_output ( 'ip rule list table 1011' )
2479 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2480 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2481 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2482 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2484 output
= check_output ( 'ip -6 rule list table 1011' )
2486 self
. assertNotIn ( '10112: from all oif test1 lookup 1011' , output
)
2487 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2489 call ( 'ip rule delete priority 10111' )
2490 call ( 'ip rule delete priority 10112' )
2491 call ( 'ip rule delete priority 10113' )
2492 call ( 'ip rule delete priority 10114' )
2493 call ( 'ip -6 rule delete priority 10113' )
2495 output
= check_output ( 'ip rule list table 1011' )
2497 self
. assertEqual ( output
, '' )
2499 output
= check_output ( 'ip -6 rule list table 1011' )
2501 self
. assertEqual ( output
, '' )
2503 networkctl_reconfigure ( 'test1' )
2504 self
. wait_online ([ 'test1:degraded' ])
2506 output
= check_output ( 'ip rule list table 1011' )
2508 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2509 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2510 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2511 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2513 output
= check_output ( 'ip -6 rule list table 1011' )
2515 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2517 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable ()
2518 def test_routing_policy_rule_port_range ( self
):
2519 copy_network_unit ( '25-fibrule-port-range.network' , '11-dummy.netdev' )
2521 self
. wait_online ([ 'test1:degraded' ])
2523 output
= check_output ( 'ip rule' )
2525 self
. assertRegex ( output
, '111' )
2526 self
. assertRegex ( output
, 'from 192.168.100.18' )
2527 self
. assertRegex ( output
, '1123-1150' )
2528 self
. assertRegex ( output
, '3224-3290' )
2529 self
. assertRegex ( output
, 'tcp' )
2530 self
. assertRegex ( output
, 'lookup 7' )
2532 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable ()
2533 def test_routing_policy_rule_invert ( self
):
2534 copy_network_unit ( '25-fibrule-invert.network' , '11-dummy.netdev' )
2536 self
. wait_online ([ 'test1:degraded' ])
2538 output
= check_output ( 'ip rule' )
2540 self
. assertRegex ( output
, '111' )
2541 self
. assertRegex ( output
, 'not.*?from.*?192.168.100.18' )
2542 self
. assertRegex ( output
, 'tcp' )
2543 self
. assertRegex ( output
, 'lookup 7' )
2545 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable ()
2546 def test_routing_policy_rule_uidrange ( self
):
2547 copy_network_unit ( '25-fibrule-uidrange.network' , '11-dummy.netdev' )
2549 self
. wait_online ([ 'test1:degraded' ])
2551 output
= check_output ( 'ip rule' )
2553 self
. assertRegex ( output
, '111' )
2554 self
. assertRegex ( output
, 'from 192.168.100.18' )
2555 self
. assertRegex ( output
, 'lookup 7' )
2556 self
. assertRegex ( output
, 'uidrange 100-200' )
2558 def _test_route_static ( self
, manage_foreign_routes
):
2559 if not manage_foreign_routes
:
2560 copy_networkd_conf_dropin ( 'networkd-manage-foreign-routes-no.conf' )
2562 copy_network_unit ( '25-route-static.network' , '12-dummy.netdev' )
2564 self
. wait_online ([ 'dummy98:routable' ])
2566 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
2569 print ( '### ip -6 route show dev dummy98' )
2570 output
= check_output ( 'ip -6 route show dev dummy98' )
2572 self
. assertIn ( '2001:1234:5:8fff:ff:ff:ff:ff proto static' , output
)
2573 self
. assertIn ( '2001:1234:5:8f63::1 proto kernel' , output
)
2574 self
. assertIn ( '2001:1234:5:afff:ff:ff:ff:ff via fe80:0:222:4dff:ff:ff:ff:ff proto static' , output
)
2576 print ( '### ip -6 route show default' )
2577 output
= check_output ( 'ip -6 route show default' )
2579 self
. assertIn ( 'default' , output
)
2580 self
. assertIn ( 'via 2001:1234:5:8fff:ff:ff:ff:ff' , output
)
2582 print ( '### ip -4 route show dev dummy98' )
2583 output
= check_output ( 'ip -4 route show dev dummy98' )
2585 self
. assertIn ( '149.10.124.48/28 proto kernel scope link src 149.10.124.58' , output
)
2586 self
. assertIn ( '149.10.124.64 proto static scope link' , output
)
2587 self
. assertIn ( '169.254.0.0/16 proto static scope link metric 2048' , output
)
2588 self
. assertIn ( '192.168.1.1 proto static scope link initcwnd 20' , output
)
2589 self
. assertIn ( '192.168.1.2 proto static scope link initrwnd 30' , output
)
2590 self
. assertIn ( '192.168.1.3 proto static scope link advmss 30' , output
)
2591 self
. assertIn ( 'multicast 149.10.123.4 proto static' , output
)
2593 print ( '### ip -4 route show dev dummy98 default' )
2594 output
= check_output ( 'ip -4 route show dev dummy98 default' )
2596 self
. assertIn ( 'default via 149.10.125.65 proto static onlink' , output
)
2597 self
. assertIn ( 'default via 149.10.124.64 proto static' , output
)
2598 self
. assertIn ( 'default proto static' , output
)
2600 print ( '### ip -4 route show table local dev dummy98' )
2601 output
= check_output ( 'ip -4 route show table local dev dummy98' )
2603 self
. assertIn ( 'local 149.10.123.1 proto static scope host' , output
)
2604 self
. assertIn ( 'anycast 149.10.123.2 proto static scope link' , output
)
2605 self
. assertIn ( 'broadcast 149.10.123.3 proto static scope link' , output
)
2607 print ( '### ip route show type blackhole' )
2608 output
= check_output ( 'ip route show type blackhole' )
2610 self
. assertIn ( 'blackhole 202.54.1.2 proto static' , output
)
2612 print ( '### ip route show type unreachable' )
2613 output
= check_output ( 'ip route show type unreachable' )
2615 self
. assertIn ( 'unreachable 202.54.1.3 proto static' , output
)
2617 print ( '### ip route show type prohibit' )
2618 output
= check_output ( 'ip route show type prohibit' )
2620 self
. assertIn ( 'prohibit 202.54.1.4 proto static' , output
)
2622 print ( '### ip -6 route show type blackhole' )
2623 output
= check_output ( 'ip -6 route show type blackhole' )
2625 self
. assertIn ( 'blackhole 2001:1234:5678::2 dev lo proto static' , output
)
2627 print ( '### ip -6 route show type unreachable' )
2628 output
= check_output ( 'ip -6 route show type unreachable' )
2630 self
. assertIn ( 'unreachable 2001:1234:5678::3 dev lo proto static' , output
)
2632 print ( '### ip -6 route show type prohibit' )
2633 output
= check_output ( 'ip -6 route show type prohibit' )
2635 self
. assertIn ( 'prohibit 2001:1234:5678::4 dev lo proto static' , output
)
2637 print ( '### ip route show 192.168.10.1' )
2638 output
= check_output ( 'ip route show 192.168.10.1' )
2640 self
. assertIn ( '192.168.10.1 proto static' , output
)
2641 self
. assertIn ( 'nexthop via 149.10.124.59 dev dummy98 weight 10' , output
)
2642 self
. assertIn ( 'nexthop via 149.10.124.60 dev dummy98 weight 5' , output
)
2644 print ( '### ip route show 192.168.10.2' )
2645 output
= check_output ( 'ip route show 192.168.10.2' )
2647 # old ip command does not show IPv6 gateways...
2648 self
. assertIn ( '192.168.10.2 proto static' , output
)
2649 self
. assertIn ( 'nexthop' , output
)
2650 self
. assertIn ( 'dev dummy98 weight 10' , output
)
2651 self
. assertIn ( 'dev dummy98 weight 5' , output
)
2653 print ( '### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff' )
2654 output
= check_output ( 'ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff' )
2656 # old ip command does not show 'nexthop' keyword and weight...
2657 self
. assertIn ( '2001:1234:5:7fff:ff:ff:ff:ff' , output
)
2658 self
. assertIn ( 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98' , output
)
2659 self
. assertIn ( 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98' , output
)
2661 # TODO: check json string
2662 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2664 copy_network_unit ( '25-address-static.network' )
2666 self
. wait_online ([ 'dummy98:routable' ])
2668 # check all routes managed by Manager are removed
2669 print ( '### ip route show type blackhole' )
2670 output
= check_output ( 'ip route show type blackhole' )
2672 self
. assertEqual ( output
, '' )
2674 print ( '### ip route show type unreachable' )
2675 output
= check_output ( 'ip route show type unreachable' )
2677 self
. assertEqual ( output
, '' )
2679 print ( '### ip route show type prohibit' )
2680 output
= check_output ( 'ip route show type prohibit' )
2682 self
. assertEqual ( output
, '' )
2684 print ( '### ip -6 route show type blackhole' )
2685 output
= check_output ( 'ip -6 route show type blackhole' )
2687 self
. assertEqual ( output
, '' )
2689 print ( '### ip -6 route show type unreachable' )
2690 output
= check_output ( 'ip -6 route show type unreachable' )
2692 self
. assertEqual ( output
, '' )
2694 print ( '### ip -6 route show type prohibit' )
2695 output
= check_output ( 'ip -6 route show type prohibit' )
2697 self
. assertEqual ( output
, '' )
2699 remove_network_unit ( '25-address-static.network' )
2701 self
. wait_online ([ 'dummy98:routable' ])
2703 # check all routes managed by Manager are reconfigured
2704 print ( '### ip route show type blackhole' )
2705 output
= check_output ( 'ip route show type blackhole' )
2707 self
. assertIn ( 'blackhole 202.54.1.2 proto static' , output
)
2709 print ( '### ip route show type unreachable' )
2710 output
= check_output ( 'ip route show type unreachable' )
2712 self
. assertIn ( 'unreachable 202.54.1.3 proto static' , output
)
2714 print ( '### ip route show type prohibit' )
2715 output
= check_output ( 'ip route show type prohibit' )
2717 self
. assertIn ( 'prohibit 202.54.1.4 proto static' , output
)
2719 print ( '### ip -6 route show type blackhole' )
2720 output
= check_output ( 'ip -6 route show type blackhole' )
2722 self
. assertIn ( 'blackhole 2001:1234:5678::2 dev lo proto static' , output
)
2724 print ( '### ip -6 route show type unreachable' )
2725 output
= check_output ( 'ip -6 route show type unreachable' )
2727 self
. assertIn ( 'unreachable 2001:1234:5678::3 dev lo proto static' , output
)
2729 print ( '### ip -6 route show type prohibit' )
2730 output
= check_output ( 'ip -6 route show type prohibit' )
2732 self
. assertIn ( 'prohibit 2001:1234:5678::4 dev lo proto static' , output
)
2734 remove_link ( 'dummy98' )
2737 # check all routes managed by Manager are removed
2738 print ( '### ip route show type blackhole' )
2739 output
= check_output ( 'ip route show type blackhole' )
2741 self
. assertEqual ( output
, '' )
2743 print ( '### ip route show type unreachable' )
2744 output
= check_output ( 'ip route show type unreachable' )
2746 self
. assertEqual ( output
, '' )
2748 print ( '### ip route show type prohibit' )
2749 output
= check_output ( 'ip route show type prohibit' )
2751 self
. assertEqual ( output
, '' )
2753 print ( '### ip -6 route show type blackhole' )
2754 output
= check_output ( 'ip -6 route show type blackhole' )
2756 self
. assertEqual ( output
, '' )
2758 print ( '### ip -6 route show type unreachable' )
2759 output
= check_output ( 'ip -6 route show type unreachable' )
2761 self
. assertEqual ( output
, '' )
2763 print ( '### ip -6 route show type prohibit' )
2764 output
= check_output ( 'ip -6 route show type prohibit' )
2766 self
. assertEqual ( output
, '' )
2770 def test_route_static ( self
):
2772 for manage_foreign_routes
in [ True , False ]:
2778 print ( f
'### test_route_static(manage_foreign_routes= {manage_foreign_routes} )' )
2779 with self
. subTest ( manage_foreign_routes
= manage_foreign_routes
):
2780 self
._ test
_ route
_ static
( manage_foreign_routes
)
2782 @expectedFailureIfRTA_VIAIsNotSupported ()
2783 def test_route_via_ipv6 ( self
):
2784 copy_network_unit ( '25-route-via-ipv6.network' , '12-dummy.netdev' )
2786 self
. wait_online ([ 'dummy98:routable' ])
2788 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
2791 print ( '### ip -6 route show dev dummy98' )
2792 output
= check_output ( 'ip -6 route show dev dummy98' )
2794 self
. assertRegex ( output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static' )
2795 self
. assertRegex ( output
, '2001:1234:5:8f63::1 proto kernel' )
2797 print ( '### ip -4 route show dev dummy98' )
2798 output
= check_output ( 'ip -4 route show dev dummy98' )
2800 self
. assertRegex ( output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58' )
2801 self
. assertRegex ( output
, '149.10.124.66 via inet6 2001:1234:5:8fff:ff:ff:ff:ff proto static' )
2803 @expectedFailureIfModuleIsNotAvailable ( 'tcp_dctcp' )
2804 def test_route_congctl ( self
):
2805 copy_network_unit ( '25-route-congctl.network' , '12-dummy.netdev' )
2807 self
. wait_online ([ 'dummy98:routable' ])
2809 print ( '### ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff' )
2810 output
= check_output ( 'ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff' )
2812 self
. assertIn ( '2001:1234:5:8fff:ff:ff:ff:ff proto static' , output
)
2813 self
. assertIn ( 'congctl dctcp' , output
)
2815 print ( '### ip -4 route show dev dummy98 149.10.124.66' )
2816 output
= check_output ( 'ip -4 route show dev dummy98 149.10.124.66' )
2818 self
. assertIn ( '149.10.124.66 proto static' , output
)
2819 self
. assertIn ( 'congctl dctcp' , output
)
2821 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
2822 def test_route_vrf ( self
):
2823 copy_network_unit ( '25-route-vrf.network' , '12-dummy.netdev' ,
2824 '25-vrf.netdev' , '25-vrf.network' )
2826 self
. wait_online ([ 'dummy98:routable' , 'vrf99:carrier' ])
2828 output
= check_output ( 'ip route show vrf vrf99' )
2830 self
. assertRegex ( output
, 'default via 192.168.100.1' )
2832 output
= check_output ( 'ip route show' )
2834 self
. assertNotRegex ( output
, 'default via 192.168.100.1' )
2836 def test_gateway_reconfigure ( self
):
2837 copy_network_unit ( '25-gateway-static.network' , '12-dummy.netdev' )
2839 self
. wait_online ([ 'dummy98:routable' ])
2840 print ( '### ip -4 route show dev dummy98 default' )
2841 output
= check_output ( 'ip -4 route show dev dummy98 default' )
2843 self
. assertIn ( 'default via 149.10.124.59 proto static' , output
)
2844 self
. assertNotIn ( '149.10.124.60' , output
)
2846 remove_network_unit ( '25-gateway-static.network' )
2847 copy_network_unit ( '25-gateway-next-static.network' )
2849 self
. wait_online ([ 'dummy98:routable' ])
2850 print ( '### ip -4 route show dev dummy98 default' )
2851 output
= check_output ( 'ip -4 route show dev dummy98 default' )
2853 self
. assertNotIn ( '149.10.124.59' , output
)
2854 self
. assertIn ( 'default via 149.10.124.60 proto static' , output
)
2856 def test_ip_route_ipv6_src_route ( self
):
2857 # a dummy device does not make the addresses go through tentative state, so we
2858 # reuse a bond from an earlier test, which does make the addresses go through
2859 # tentative state, and do our test on that
2860 copy_network_unit ( '23-active-slave.network' , '25-route-ipv6-src.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
2862 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:routable' ])
2864 output
= check_output ( 'ip -6 route list dev bond199' )
2866 self
. assertRegex ( output
, 'abcd::/16' )
2867 self
. assertRegex ( output
, 'src' )
2868 self
. assertRegex ( output
, '2001:1234:56:8f63::2' )
2870 def test_ip_link_mac_address ( self
):
2871 copy_network_unit ( '25-address-link-section.network' , '12-dummy.netdev' )
2873 self
. wait_online ([ 'dummy98:degraded' ])
2875 output
= check_output ( 'ip link show dummy98' )
2877 self
. assertRegex ( output
, '00:01:02:aa:bb:cc' )
2879 def test_ip_link_unmanaged ( self
):
2880 copy_network_unit ( '25-link-section-unmanaged.network' , '12-dummy.netdev' )
2883 self
. wait_operstate ( 'dummy98' , 'off' , setup_state
= 'unmanaged' )
2885 def test_ipv6_address_label ( self
):
2886 copy_network_unit ( '25-ipv6-address-label-section.network' , '12-dummy.netdev' )
2888 self
. wait_online ([ 'dummy98:degraded' ])
2890 output
= check_output ( 'ip addrlabel list' )
2892 self
. assertRegex ( output
, '2004:da8:1::/64' )
2894 def test_ipv6_proxy_ndp ( self
):
2895 copy_network_unit ( '25-ipv6-proxy-ndp.network' , '12-dummy.netdev' )
2898 self
. wait_online ([ 'dummy98:routable' ])
2900 output
= check_output ( 'ip neighbor show proxy dev dummy98' )
2902 for i
in range ( 1 , 5 ):
2903 self
. assertRegex ( output
, f
'2607:5300:203:5215: {i} ::1 *proxy' )
2905 def test_neighbor_section ( self
):
2906 copy_network_unit ( '25-neighbor-section.network' , '12-dummy.netdev' )
2908 self
. wait_online ([ 'dummy98:degraded' ], timeout
= '40s' )
2910 print ( '### ip neigh list dev dummy98' )
2911 output
= check_output ( 'ip neigh list dev dummy98' )
2913 self
. assertRegex ( output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT' )
2914 self
. assertRegex ( output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT' )
2916 # TODO: check json string
2917 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2919 def test_neighbor_reconfigure ( self
):
2920 copy_network_unit ( '25-neighbor-section.network' , '12-dummy.netdev' )
2922 self
. wait_online ([ 'dummy98:degraded' ], timeout
= '40s' )
2924 print ( '### ip neigh list dev dummy98' )
2925 output
= check_output ( 'ip neigh list dev dummy98' )
2927 self
. assertRegex ( output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT' )
2928 self
. assertRegex ( output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT' )
2930 remove_network_unit ( '25-neighbor-section.network' )
2931 copy_network_unit ( '25-neighbor-next.network' )
2933 self
. wait_online ([ 'dummy98:degraded' ], timeout
= '40s' )
2934 print ( '### ip neigh list dev dummy98' )
2935 output
= check_output ( 'ip neigh list dev dummy98' )
2937 self
. assertNotRegex ( output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT' )
2938 self
. assertRegex ( output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT' )
2939 self
. assertNotRegex ( output
, '2004:da8:1::1.*PERMANENT' )
2941 def test_neighbor_gre ( self
):
2942 copy_network_unit ( '25-neighbor-ip.network' , '25-neighbor-ipv6.network' , '25-neighbor-ip-dummy.network' ,
2943 '12-dummy.netdev' , '25-gre-tunnel-remote-any.netdev' , '25-ip6gre-tunnel-remote-any.netdev' )
2945 self
. wait_online ([ 'dummy98:degraded' , 'gretun97:routable' , 'ip6gretun97:routable' ], timeout
= '40s' )
2947 output
= check_output ( 'ip neigh list dev gretun97' )
2949 self
. assertRegex ( output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT' )
2951 output
= check_output ( 'ip neigh list dev ip6gretun97' )
2953 self
. assertRegex ( output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT' )
2955 # TODO: check json string
2956 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2958 def test_link_local_addressing ( self
):
2959 copy_network_unit ( '25-link-local-addressing-yes.network' , '11-dummy.netdev' ,
2960 '25-link-local-addressing-no.network' , '12-dummy.netdev' )
2962 self
. wait_online ([ 'test1:degraded' , 'dummy98:carrier' ])
2964 output
= check_output ( 'ip address show dev test1' )
2966 self
. assertRegex ( output
, 'inet .* scope link' )
2967 self
. assertRegex ( output
, 'inet6 .* scope link' )
2969 output
= check_output ( 'ip address show dev dummy98' )
2971 self
. assertNotRegex ( output
, 'inet6* .* scope link' )
2973 # Documentation/networking/ip-sysctl.txt
2975 # addr_gen_mode - INTEGER
2976 # Defines how link-local and autoconf addresses are generated.
2978 # 0: generate address based on EUI64 (default)
2979 # 1: do no generate a link-local address, use EUI64 for addresses generated
2981 # 2: generate stable privacy addresses, using the secret from
2982 # stable_secret (RFC7217)
2983 # 3: generate stable privacy addresses, using a random secret if unset
2985 self
. check_ipv6_sysctl_attr ( 'test1' , 'stable_secret' , '0123:4567:89ab:cdef:0123:4567:89ab:cdef' )
2986 self
. check_ipv6_sysctl_attr ( 'test1' , 'addr_gen_mode' , '2' )
2987 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'addr_gen_mode' , '1' )
2989 def test_link_local_addressing_ipv6ll ( self
):
2990 copy_network_unit ( '26-link-local-addressing-ipv6.network' , '12-dummy.netdev' )
2992 self
. wait_online ([ 'dummy98:degraded' ])
2994 # An IPv6LL address exists by default.
2995 output
= check_output ( 'ip address show dev dummy98' )
2997 self
. assertRegex ( output
, 'inet6 .* scope link' )
2999 copy_network_unit ( '25-link-local-addressing-no.network' )
3001 self
. wait_online ([ 'dummy98:carrier' ])
3003 # Check if the IPv6LL address is removed.
3004 output
= check_output ( 'ip address show dev dummy98' )
3006 self
. assertNotRegex ( output
, 'inet6 .* scope link' )
3008 remove_network_unit ( '25-link-local-addressing-no.network' )
3010 self
. wait_online ([ 'dummy98:degraded' ])
3012 # Check if a new IPv6LL address is assigned.
3013 output
= check_output ( 'ip address show dev dummy98' )
3015 self
. assertRegex ( output
, 'inet6 .* scope link' )
3017 def test_sysctl ( self
):
3018 copy_network_unit ( '25-sysctl.network' , '12-dummy.netdev' )
3020 self
. wait_online ([ 'dummy98:degraded' ])
3022 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
3023 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'use_tempaddr' , '2' )
3024 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'dad_transmits' , '3' )
3025 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'hop_limit' , '5' )
3026 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'proxy_ndp' , '1' )
3027 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
3028 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'proxy_arp' , '1' )
3029 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'accept_local' , '1' )
3031 def test_sysctl_disable_ipv6 ( self
):
3032 copy_network_unit ( '25-sysctl-disable-ipv6.network' , '12-dummy.netdev' )
3034 print ( '## Disable ipv6' )
3035 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=1' )
3036 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=1' )
3039 self
. wait_online ([ 'dummy98:routable' ])
3041 output
= check_output ( 'ip -4 address show dummy98' )
3043 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3044 output
= check_output ( 'ip -6 address show dummy98' )
3046 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3047 self
. assertRegex ( output
, 'inet6 .* scope link' )
3048 output
= check_output ( 'ip -4 route show dev dummy98' )
3050 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3051 output
= check_output ( 'ip -6 route show default' )
3053 self
. assertRegex ( output
, 'default' )
3054 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3056 remove_link ( 'dummy98' )
3058 print ( '## Enable ipv6' )
3059 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=0' )
3060 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=0' )
3063 self
. wait_online ([ 'dummy98:routable' ])
3065 output
= check_output ( 'ip -4 address show dummy98' )
3067 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3068 output
= check_output ( 'ip -6 address show dummy98' )
3070 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3071 self
. assertRegex ( output
, 'inet6 .* scope link' )
3072 output
= check_output ( 'ip -4 route show dev dummy98' )
3074 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3075 output
= check_output ( 'ip -6 route show default' )
3077 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3079 def test_bind_carrier ( self
):
3080 check_output ( 'ip link add dummy98 type dummy' )
3081 check_output ( 'ip link set dummy98 up' )
3084 copy_network_unit ( '25-bind-carrier.network' , '11-dummy.netdev' )
3086 self
. wait_online ([ 'test1:routable' ])
3088 output
= check_output ( 'ip address show test1' )
3090 self
. assertRegex ( output
, 'UP,LOWER_UP' )
3091 self
. assertRegex ( output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' )
3092 self
. wait_operstate ( 'test1' , 'routable' )
3094 check_output ( 'ip link add dummy99 type dummy' )
3095 check_output ( 'ip link set dummy99 up' )
3097 output
= check_output ( 'ip address show test1' )
3099 self
. assertRegex ( output
, 'UP,LOWER_UP' )
3100 self
. assertRegex ( output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' )
3101 self
. wait_operstate ( 'test1' , 'routable' )
3103 remove_link ( 'dummy98' )
3105 output
= check_output ( 'ip address show test1' )
3107 self
. assertRegex ( output
, 'UP,LOWER_UP' )
3108 self
. assertRegex ( output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' )
3109 self
. wait_operstate ( 'test1' , 'routable' )
3111 check_output ( 'ip link set dummy99 down' )
3113 output
= check_output ( 'ip address show test1' )
3115 self
. assertNotRegex ( output
, 'UP,LOWER_UP' )
3116 self
. assertRegex ( output
, 'DOWN' )
3117 self
. assertNotRegex ( output
, '192.168.10' )
3118 self
. wait_operstate ( 'test1' , 'off' )
3120 check_output ( 'ip link set dummy99 up' )
3122 output
= check_output ( 'ip address show test1' )
3124 self
. assertRegex ( output
, 'UP,LOWER_UP' )
3125 self
. assertRegex ( output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' )
3126 self
. wait_operstate ( 'test1' , 'routable' )
3128 def _test_activation_policy ( self
, interface
, test
):
3129 conffile
= '25-activation-policy.network'
3131 conffile
= f
' {conffile} .d/ {test} .conf'
3132 if interface
== 'vlan99' :
3133 copy_network_unit ( '21-vlan.netdev' , '21-vlan-test1.network' )
3134 copy_network_unit ( '11-dummy.netdev' , conffile
, copy_dropins
= False )
3137 always
= test
. startswith ( 'always' )
3138 initial_up
= test
!= 'manual' and not test
. endswith ( 'down' ) # note: default is up
3139 expect_up
= initial_up
3140 next_up
= not expect_up
3142 if test
. endswith ( 'down' ):
3143 self
. wait_activated ( interface
)
3145 for iteration
in range ( 4 ):
3146 with self
. subTest ( iteration
= iteration
, expect_up
= expect_up
):
3147 operstate
= 'routable' if expect_up
else 'off'
3148 setup_state
= 'configured' if expect_up
else ( 'configuring' if iteration
== 0 else None )
3149 self
. wait_operstate ( interface
, operstate
, setup_state
= setup_state
, setup_timeout
= 20 )
3152 self
. assertIn ( 'UP' , check_output ( f
'ip link show {interface} ' ))
3153 self
. assertIn ( '192.168.10.30/24' , check_output ( f
'ip address show {interface} ' ))
3154 self
. assertIn ( 'default via 192.168.10.1' , check_output ( f
'ip route show dev {interface} ' ))
3156 self
. assertIn ( 'DOWN' , check_output ( f
'ip link show {interface} ' ))
3159 check_output ( f
'ip link set dev {interface} up' )
3161 check_output ( f
'ip link set dev {interface} down' )
3162 expect_up
= initial_up
if always
else next_up
3163 next_up
= not next_up
3167 def test_activation_policy ( self
):
3169 for interface
in [ 'test1' , 'vlan99' ]:
3170 for test
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , '' ]:
3176 print ( f
'### test_activation_policy(interface= {interface} , test= {test} )' )
3177 with self
. subTest ( interface
= interface
, test
= test
):
3178 self
._ test
_ activation
_ policy
( interface
, test
)
3180 def _test_activation_policy_required_for_online ( self
, policy
, required
):
3181 conffile
= '25-activation-policy.network'
3182 units
= [ '11-dummy.netdev' , '12-dummy.netdev' , '12-dummy.network' , conffile
]
3184 units
+= [ f
' {conffile} .d/ {policy} .conf' ]
3186 units
+= [ f
' {conffile} .d/required- {required} .conf' ]
3187 copy_network_unit (* units
, copy_dropins
= False )
3190 if policy
. endswith ( 'down' ):
3191 self
. wait_activated ( 'test1' )
3193 if policy
. endswith ( 'down' ) or policy
== 'manual' :
3194 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
3196 self
. wait_online ([ 'test1' ])
3198 if policy
== 'always-down' :
3199 # if always-down, required for online is forced to no
3202 # otherwise if required for online is specified, it should match that
3203 expected
= required
== 'yes'
3205 # otherwise if only policy specified, required for online defaults to
3206 # true if policy is up, always-up, or bound
3207 expected
= policy
. endswith ( 'up' ) or policy
== 'bound'
3209 # default is true, if neither are specified
3212 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
3215 yesno
= 'yes' if expected
else 'no'
3216 self
. assertRegex ( output
, f
'Required For Online: {yesno} ' )
3218 def test_activation_policy_required_for_online ( self
):
3220 for policy
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , 'bound' , '' ]:
3221 for required
in [ 'yes' , 'no' , '' ]:
3227 print ( f
'### test_activation_policy_required_for_online(policy= {policy} , required= {required} )' )
3228 with self
. subTest ( policy
= policy
, required
= required
):
3229 self
._ test
_ activation
_ policy
_ required
_ for
_ online
( policy
, required
)
3231 def test_domain ( self
):
3232 copy_network_unit ( '12-dummy.netdev' , '24-search-domain.network' )
3234 self
. wait_online ([ 'dummy98:routable' ])
3236 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
3238 self
. assertRegex ( output
, 'Address: 192.168.42.100' )
3239 self
. assertRegex ( output
, 'DNS: 192.168.42.1' )
3240 self
. assertRegex ( output
, 'Search Domains: one' )
3242 def test_keep_configuration_static ( self
):
3243 check_output ( 'ip link add name dummy98 type dummy' )
3244 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
3245 check_output ( 'ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500' )
3246 output
= check_output ( 'ip address show dummy98' )
3248 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
3249 self
. assertRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
3250 output
= check_output ( 'ip route show dev dummy98' )
3253 copy_network_unit ( '24-keep-configuration-static.network' )
3255 self
. wait_online ([ 'dummy98:routable' ])
3257 output
= check_output ( 'ip address show dummy98' )
3259 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
3260 self
. assertNotRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
3262 @expectedFailureIfNexthopIsNotAvailable ()
3263 def test_nexthop ( self
):
3264 def check_nexthop ( self
):
3265 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
3267 output
= check_output ( 'ip nexthop list dev veth99' )
3269 self
. assertIn ( 'id 1 via 192.168.5.1 dev veth99' , output
)
3270 self
. assertIn ( 'id 2 via 2001:1234:5:8f63::2 dev veth99' , output
)
3271 self
. assertIn ( 'id 3 dev veth99' , output
)
3272 self
. assertIn ( 'id 4 dev veth99' , output
)
3273 self
. assertRegex ( output
, 'id 5 via 192.168.10.1 dev veth99 .*onlink' )
3274 self
. assertIn ( 'id 8 via fe80:0:222:4dff:ff:ff:ff:ff dev veth99' , output
)
3275 self
. assertRegex ( output
, r
'id [0-9]* via 192.168.5.2 dev veth99' )
3277 output
= check_output ( 'ip nexthop list dev dummy98' )
3279 self
. assertIn ( 'id 20 via 192.168.20.1 dev dummy98' , output
)
3281 # kernel manages blackhole nexthops on lo
3282 output
= check_output ( 'ip nexthop list dev lo' )
3284 self
. assertIn ( 'id 6 blackhole' , output
)
3285 self
. assertIn ( 'id 7 blackhole' , output
)
3287 # group nexthops are shown with -0 option
3288 output
= check_output ( 'ip -0 nexthop list id 21' )
3290 self
. assertRegex ( output
, r
'id 21 group (1,3/20|20/1,3)' )
3292 output
= check_output ( 'ip route show dev veth99 10.10.10.10' )
3294 self
. assertEqual ( '10.10.10.10 nhid 1 via 192.168.5.1 proto static' , output
)
3296 output
= check_output ( 'ip route show dev veth99 10.10.10.11' )
3298 self
. assertEqual ( '10.10.10.11 nhid 2 via inet6 2001:1234:5:8f63::2 proto static' , output
)
3300 output
= check_output ( 'ip route show dev veth99 10.10.10.12' )
3302 self
. assertEqual ( '10.10.10.12 nhid 5 via 192.168.10.1 proto static onlink' , output
)
3304 output
= check_output ( 'ip -6 route show dev veth99 2001:1234:5:8f62::1' )
3306 self
. assertEqual ( '2001:1234:5:8f62::1 nhid 2 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium' , output
)
3308 output
= check_output ( 'ip route show 10.10.10.13' )
3310 self
. assertEqual ( 'blackhole 10.10.10.13 nhid 6 dev lo proto static' , output
)
3312 output
= check_output ( 'ip -6 route show 2001:1234:5:8f62::2' )
3314 self
. assertEqual ( 'blackhole 2001:1234:5:8f62::2 nhid 7 dev lo proto static metric 1024 pref medium' , output
)
3316 output
= check_output ( 'ip route show 10.10.10.14' )
3318 self
. assertIn ( '10.10.10.14 nhid 21 proto static' , output
)
3319 self
. assertIn ( 'nexthop via 192.168.20.1 dev dummy98 weight 1' , output
)
3320 self
. assertIn ( 'nexthop via 192.168.5.1 dev veth99 weight 3' , output
)
3322 # TODO: check json string
3323 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3325 copy_network_unit ( '25-nexthop.network' , '25-veth.netdev' , '25-veth-peer.network' ,
3326 '12-dummy.netdev' , '25-nexthop-dummy.network' )
3331 remove_network_unit ( '25-nexthop.network' )
3332 copy_network_unit ( '25-nexthop-nothing.network' )
3334 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
3336 output
= check_output ( 'ip nexthop list dev veth99' )
3338 self
. assertEqual ( output
, '' )
3339 output
= check_output ( 'ip nexthop list dev lo' )
3341 self
. assertEqual ( output
, '' )
3343 remove_network_unit ( '25-nexthop-nothing.network' )
3344 copy_network_unit ( '25-nexthop.network' )
3345 networkctl_reconfigure ( 'dummy98' )
3350 remove_link ( 'veth99' )
3353 output
= check_output ( 'ip nexthop list dev lo' )
3355 self
. assertEqual ( output
, '' )
3357 class NetworkdTCTests ( unittest
. TestCase
, Utilities
):
3365 @expectedFailureIfModuleIsNotAvailable ( 'sch_cake' )
3366 def test_qdisc_cake ( self
):
3367 copy_network_unit ( '25-qdisc-cake.network' , '12-dummy.netdev' )
3369 self
. wait_online ([ 'dummy98:routable' ])
3371 output
= check_output ( 'tc qdisc show dev dummy98' )
3373 self
. assertIn ( 'qdisc cake 3a: root' , output
)
3374 self
. assertIn ( 'bandwidth 500Mbit' , output
)
3375 self
. assertIn ( 'autorate-ingress' , output
)
3376 self
. assertIn ( 'diffserv8' , output
)
3377 self
. assertIn ( 'dual-dsthost' , output
)
3378 self
. assertIn ( ' nat' , output
)
3379 self
. assertIn ( ' wash' , output
)
3380 self
. assertIn ( ' split-gso' , output
)
3381 self
. assertIn ( ' raw' , output
)
3382 self
. assertIn ( ' atm' , output
)
3383 self
. assertIn ( 'overhead 128' , output
)
3384 self
. assertIn ( 'mpu 20' , output
)
3385 self
. assertIn ( 'fwmark 0xff00' , output
)
3387 @expectedFailureIfModuleIsNotAvailable ( 'sch_codel' )
3388 def test_qdisc_codel ( self
):
3389 copy_network_unit ( '25-qdisc-codel.network' , '12-dummy.netdev' )
3391 self
. wait_online ([ 'dummy98:routable' ])
3393 output
= check_output ( 'tc qdisc show dev dummy98' )
3395 self
. assertRegex ( output
, 'qdisc codel 33: root' )
3396 self
. assertRegex ( output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn' )
3398 @expectedFailureIfModuleIsNotAvailable ( 'sch_drr' )
3399 def test_qdisc_drr ( self
):
3400 copy_network_unit ( '25-qdisc-drr.network' , '12-dummy.netdev' )
3402 self
. wait_online ([ 'dummy98:routable' ])
3404 output
= check_output ( 'tc qdisc show dev dummy98' )
3406 self
. assertRegex ( output
, 'qdisc drr 2: root' )
3407 output
= check_output ( 'tc class show dev dummy98' )
3409 self
. assertRegex ( output
, 'class drr 2:30 root quantum 2000b' )
3411 @expectedFailureIfModuleIsNotAvailable ( 'sch_ets' )
3412 def test_qdisc_ets ( self
):
3413 copy_network_unit ( '25-qdisc-ets.network' , '12-dummy.netdev' )
3415 self
. wait_online ([ 'dummy98:routable' ])
3417 output
= check_output ( 'tc qdisc show dev dummy98' )
3420 self
. assertRegex ( output
, 'qdisc ets 3a: root' )
3421 self
. assertRegex ( output
, 'bands 10 strict 3' )
3422 self
. assertRegex ( output
, 'quanta 1 2 3 4 5' )
3423 self
. assertRegex ( output
, 'priomap 3 4 5 6 7' )
3425 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq' )
3426 def test_qdisc_fq ( self
):
3427 copy_network_unit ( '25-qdisc-fq.network' , '12-dummy.netdev' )
3429 self
. wait_online ([ 'dummy98:routable' ])
3431 output
= check_output ( 'tc qdisc show dev dummy98' )
3433 self
. assertRegex ( output
, 'qdisc fq 32: root' )
3434 self
. assertRegex ( output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511' )
3435 self
. assertRegex ( output
, 'quantum 1500' )
3436 self
. assertRegex ( output
, 'initial_quantum 13000' )
3437 self
. assertRegex ( output
, 'maxrate 1Mbit' )
3439 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_codel' )
3440 def test_qdisc_fq_codel ( self
):
3441 copy_network_unit ( '25-qdisc-fq_codel.network' , '12-dummy.netdev' )
3443 self
. wait_online ([ 'dummy98:routable' ])
3445 output
= check_output ( 'tc qdisc show dev dummy98' )
3447 self
. assertRegex ( output
, 'qdisc fq_codel 34: root' )
3448 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' )
3450 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_pie' )
3451 def test_qdisc_fq_pie ( self
):
3452 copy_network_unit ( '25-qdisc-fq_pie.network' , '12-dummy.netdev' )
3454 self
. wait_online ([ 'dummy98:routable' ])
3456 output
= check_output ( 'tc qdisc show dev dummy98' )
3459 self
. assertRegex ( output
, 'qdisc fq_pie 3a: root' )
3460 self
. assertRegex ( output
, 'limit 200000p' )
3462 @expectedFailureIfModuleIsNotAvailable ( 'sch_gred' )
3463 def test_qdisc_gred ( self
):
3464 copy_network_unit ( '25-qdisc-gred.network' , '12-dummy.netdev' )
3466 self
. wait_online ([ 'dummy98:routable' ])
3468 output
= check_output ( 'tc qdisc show dev dummy98' )
3470 self
. assertRegex ( output
, 'qdisc gred 38: root' )
3471 self
. assertRegex ( output
, 'vqs 12 default 10 grio' )
3473 @expectedFailureIfModuleIsNotAvailable ( 'sch_hhf' )
3474 def test_qdisc_hhf ( self
):
3475 copy_network_unit ( '25-qdisc-hhf.network' , '12-dummy.netdev' )
3477 self
. wait_online ([ 'dummy98:routable' ])
3479 output
= check_output ( 'tc qdisc show dev dummy98' )
3481 self
. assertRegex ( output
, 'qdisc hhf 3a: root' )
3482 self
. assertRegex ( output
, 'limit 1022p' )
3484 @expectedFailureIfModuleIsNotAvailable ( 'sch_htb' )
3485 def test_qdisc_htb_fifo ( self
):
3486 copy_network_unit ( '25-qdisc-htb-fifo.network' , '12-dummy.netdev' )
3488 self
. wait_online ([ 'dummy98:routable' ])
3490 output
= check_output ( 'tc qdisc show dev dummy98' )
3492 self
. assertRegex ( output
, 'qdisc htb 2: root' )
3493 self
. assertRegex ( output
, r
'default (0x30|30)' )
3495 self
. assertRegex ( output
, 'qdisc pfifo 37: parent 2:37' )
3496 self
. assertRegex ( output
, 'limit 100000p' )
3498 self
. assertRegex ( output
, 'qdisc bfifo 3a: parent 2:3a' )
3499 self
. assertRegex ( output
, 'limit 1000000' )
3501 self
. assertRegex ( output
, 'qdisc pfifo_head_drop 3b: parent 2:3b' )
3502 self
. assertRegex ( output
, 'limit 1023p' )
3504 self
. assertRegex ( output
, 'qdisc pfifo_fast 3c: parent 2:3c' )
3506 output
= check_output ( 'tc -d class show dev dummy98' )
3508 self
. assertRegex ( output
, 'class htb 2:37 root leaf 37:' )
3509 self
. assertRegex ( output
, 'class htb 2:3a root leaf 3a:' )
3510 self
. assertRegex ( output
, 'class htb 2:3b root leaf 3b:' )
3511 self
. assertRegex ( output
, 'class htb 2:3c root leaf 3c:' )
3512 self
. assertRegex ( output
, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit' )
3513 self
. assertRegex ( output
, 'burst 123456' )
3514 self
. assertRegex ( output
, 'cburst 123457' )
3516 @expectedFailureIfModuleIsNotAvailable ( 'sch_ingress' )
3517 def test_qdisc_ingress ( self
):
3518 copy_network_unit ( '25-qdisc-clsact.network' , '12-dummy.netdev' ,
3519 '25-qdisc-ingress.network' , '11-dummy.netdev' )
3521 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' ])
3523 output
= check_output ( 'tc qdisc show dev dummy98' )
3525 self
. assertRegex ( output
, 'qdisc clsact' )
3527 output
= check_output ( 'tc qdisc show dev test1' )
3529 self
. assertRegex ( output
, 'qdisc ingress' )
3531 @expectedFailureIfModuleIsNotAvailable ( 'sch_netem' )
3532 def test_qdisc_netem ( self
):
3533 copy_network_unit ( '25-qdisc-netem.network' , '12-dummy.netdev' ,
3534 '25-qdisc-netem-compat.network' , '11-dummy.netdev' )
3536 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' ])
3538 output
= check_output ( 'tc qdisc show dev dummy98' )
3540 self
. assertRegex ( output
, 'qdisc netem 30: root' )
3541 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
3543 output
= check_output ( 'tc qdisc show dev test1' )
3545 self
. assertRegex ( output
, 'qdisc netem [0-9a-f]*: root' )
3546 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
3548 @expectedFailureIfModuleIsNotAvailable ( 'sch_pie' )
3549 def test_qdisc_pie ( self
):
3550 copy_network_unit ( '25-qdisc-pie.network' , '12-dummy.netdev' )
3552 self
. wait_online ([ 'dummy98:routable' ])
3554 output
= check_output ( 'tc qdisc show dev dummy98' )
3556 self
. assertRegex ( output
, 'qdisc pie 3a: root' )
3557 self
. assertRegex ( output
, 'limit 200000' )
3559 @expectedFailureIfModuleIsNotAvailable ( 'sch_qfq' )
3560 def test_qdisc_qfq ( self
):
3561 copy_network_unit ( '25-qdisc-qfq.network' , '12-dummy.netdev' )
3563 self
. wait_online ([ 'dummy98:routable' ])
3565 output
= check_output ( 'tc qdisc show dev dummy98' )
3567 self
. assertRegex ( output
, 'qdisc qfq 2: root' )
3568 output
= check_output ( 'tc class show dev dummy98' )
3570 self
. assertRegex ( output
, 'class qfq 2:30 root weight 2 maxpkt 16000' )
3571 self
. assertRegex ( output
, 'class qfq 2:31 root weight 10 maxpkt 8000' )
3573 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfb' )
3574 def test_qdisc_sfb ( self
):
3575 copy_network_unit ( '25-qdisc-sfb.network' , '12-dummy.netdev' )
3577 self
. wait_online ([ 'dummy98:routable' ])
3579 output
= check_output ( 'tc qdisc show dev dummy98' )
3581 self
. assertRegex ( output
, 'qdisc sfb 39: root' )
3582 self
. assertRegex ( output
, 'limit 200000' )
3584 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfq' )
3585 def test_qdisc_sfq ( self
):
3586 copy_network_unit ( '25-qdisc-sfq.network' , '12-dummy.netdev' )
3588 self
. wait_online ([ 'dummy98:routable' ])
3590 output
= check_output ( 'tc qdisc show dev dummy98' )
3592 self
. assertRegex ( output
, 'qdisc sfq 36: root' )
3593 self
. assertRegex ( output
, 'perturb 5sec' )
3595 @expectedFailureIfModuleIsNotAvailable ( 'sch_tbf' )
3596 def test_qdisc_tbf ( self
):
3597 copy_network_unit ( '25-qdisc-tbf.network' , '12-dummy.netdev' )
3599 self
. wait_online ([ 'dummy98:routable' ])
3601 output
= check_output ( 'tc qdisc show dev dummy98' )
3603 self
. assertRegex ( output
, 'qdisc tbf 35: root' )
3604 self
. assertRegex ( output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms' )
3606 @expectedFailureIfModuleIsNotAvailable ( 'sch_teql' )
3607 def test_qdisc_teql ( self
):
3608 call_quiet ( 'rmmod sch_teql' )
3610 copy_network_unit ( '25-qdisc-teql.network' , '12-dummy.netdev' )
3612 self
. wait_links ( 'dummy98' )
3613 check_output ( 'modprobe sch_teql max_equalizers=2' )
3614 self
. wait_online ([ 'dummy98:routable' ])
3616 output
= check_output ( 'tc qdisc show dev dummy98' )
3618 self
. assertRegex ( output
, 'qdisc teql1 31: root' )
3620 class NetworkWaitOnlineTests ( unittest
. TestCase
, Utilities
):
3628 @expectedFailureIfModuleIsNotAvailable ( 'sch_netem' )
3629 def test_wait_online_ipv4 ( self
):
3630 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-with-ipv6-prefix.network' , '25-dhcp-client-ipv4-ipv6ra-prefix-client-with-delay.network' )
3633 self
. wait_online ([ 'veth99:routable' ], ipv4
= True )
3635 self
. wait_address ( 'veth99' , r
'192.168.5.[0-9]+' , ipv
= '-4' , timeout_sec
= 1 )
3637 @expectedFailureIfModuleIsNotAvailable ( 'sch_netem' )
3638 def test_wait_online_ipv6 ( self
):
3639 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix-with-delay.network' , '25-ipv6ra-prefix-client-with-static-ipv4-address.network' )
3642 self
. wait_online ([ 'veth99:routable' ], ipv6
= True )
3644 self
. wait_address ( 'veth99' , r
'2002:da8:1:0:1034:56ff:fe78:9abc' , ipv
= '-6' , timeout_sec
= 1 )
3646 class NetworkdStateFileTests ( unittest
. TestCase
, Utilities
):
3654 def test_state_file ( self
):
3655 copy_network_unit ( '12-dummy.netdev' , '25-state-file-tests.network' )
3657 self
. wait_online ([ 'dummy98:routable' ])
3659 # make link state file updated
3660 check_output (* resolvectl_cmd
, 'revert' , 'dummy98' , env
= env
)
3662 # TODO: check json string
3663 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3665 output
= read_link_state_file ( 'dummy98' )
3667 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
3668 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
3669 self
. assertIn ( 'ADMIN_STATE=configured' , output
)
3670 self
. assertIn ( 'OPER_STATE=routable' , output
)
3671 self
. assertIn ( 'REQUIRED_FOR_ONLINE=yes' , output
)
3672 self
. assertIn ( 'REQUIRED_OPER_STATE_FOR_ONLINE=routable' , output
)
3673 self
. assertIn ( 'REQUIRED_FAMILY_FOR_ONLINE=both' , output
)
3674 self
. assertIn ( 'ACTIVATION_POLICY=up' , output
)
3675 self
. assertIn ( 'NETWORK_FILE=/run/systemd/network/25-state-file-tests.network' , output
)
3676 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
3677 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
3678 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
3679 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
3680 self
. assertIn ( 'LLMNR=no' , output
)
3681 self
. assertIn ( 'MDNS=yes' , output
)
3682 self
. assertIn ( 'DNSSEC=no' , output
)
3684 check_output (* resolvectl_cmd
, 'dns' , 'dummy98' , '10.10.10.12#ccc.com' , '10.10.10.13' , '1111:2222::3333' , env
= env
)
3685 check_output (* resolvectl_cmd
, 'domain' , 'dummy98' , 'hogehogehoge' , '~foofoofoo' , env
= env
)
3686 check_output (* resolvectl_cmd
, 'llmnr' , 'dummy98' , 'yes' , env
= env
)
3687 check_output (* resolvectl_cmd
, 'mdns' , 'dummy98' , 'no' , env
= env
)
3688 check_output (* resolvectl_cmd
, 'dnssec' , 'dummy98' , 'yes' , env
= env
)
3689 check_output (* timedatectl_cmd
, 'ntp-servers' , 'dummy98' , '2.fedora.pool.ntp.org' , '3.fedora.pool.ntp.org' , env
= env
)
3691 # TODO: check json string
3692 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3694 output
= read_link_state_file ( 'dummy98' )
3696 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
3697 self
. assertIn ( 'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org' , output
)
3698 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
3699 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
3700 self
. assertIn ( 'LLMNR=yes' , output
)
3701 self
. assertIn ( 'MDNS=no' , output
)
3702 self
. assertIn ( 'DNSSEC=yes' , output
)
3704 check_output (* timedatectl_cmd
, 'revert' , 'dummy98' , env
= env
)
3706 # TODO: check json string
3707 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3709 output
= read_link_state_file ( 'dummy98' )
3711 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
3712 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
3713 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
3714 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
3715 self
. assertIn ( 'LLMNR=yes' , output
)
3716 self
. assertIn ( 'MDNS=no' , output
)
3717 self
. assertIn ( 'DNSSEC=yes' , output
)
3719 check_output (* resolvectl_cmd
, 'revert' , 'dummy98' , env
= env
)
3721 # TODO: check json string
3722 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3724 output
= read_link_state_file ( 'dummy98' )
3726 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
3727 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
3728 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
3729 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
3730 self
. assertIn ( 'LLMNR=no' , output
)
3731 self
. assertIn ( 'MDNS=yes' , output
)
3732 self
. assertIn ( 'DNSSEC=no' , output
)
3734 class NetworkdBondTests ( unittest
. TestCase
, Utilities
):
3742 def test_bond_keep_master ( self
):
3743 check_output ( 'ip link add bond199 type bond mode active-backup' )
3744 check_output ( 'ip link add dummy98 type dummy' )
3745 check_output ( 'ip link set dummy98 master bond199' )
3747 copy_network_unit ( '23-keep-master.network' )
3749 self
. wait_online ([ 'dummy98:enslaved' ])
3751 output
= check_output ( 'ip -d link show bond199' )
3753 self
. assertRegex ( output
, 'active_slave dummy98' )
3755 output
= check_output ( 'ip -d link show dummy98' )
3757 self
. assertRegex ( output
, 'master bond199' )
3759 def test_bond_active_slave ( self
):
3760 copy_network_unit ( '23-active-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
3762 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
3764 output
= check_output ( 'ip -d link show bond199' )
3766 self
. assertRegex ( output
, 'active_slave dummy98' )
3768 def test_bond_primary_slave ( self
):
3769 copy_network_unit ( '23-primary-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
3771 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
3773 output
= check_output ( 'ip -d link show bond199' )
3775 self
. assertRegex ( output
, 'primary dummy98' )
3777 def test_bond_operstate ( self
):
3778 copy_network_unit ( '25-bond.netdev' , '11-dummy.netdev' , '12-dummy.netdev' ,
3779 '25-bond99.network' , '25-bond-slave.network' )
3781 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bond99:routable' ])
3783 output
= check_output ( 'ip -d link show dummy98' )
3785 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
3787 output
= check_output ( 'ip -d link show test1' )
3789 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
3791 output
= check_output ( 'ip -d link show bond99' )
3793 self
. assertRegex ( output
, 'MASTER,UP,LOWER_UP' )
3795 self
. wait_operstate ( 'dummy98' , 'enslaved' )
3796 self
. wait_operstate ( 'test1' , 'enslaved' )
3797 self
. wait_operstate ( 'bond99' , 'routable' )
3799 check_output ( 'ip link set dummy98 down' )
3801 self
. wait_operstate ( 'dummy98' , 'off' )
3802 self
. wait_operstate ( 'test1' , 'enslaved' )
3803 self
. wait_operstate ( 'bond99' , 'degraded-carrier' )
3805 check_output ( 'ip link set dummy98 up' )
3807 self
. wait_operstate ( 'dummy98' , 'enslaved' )
3808 self
. wait_operstate ( 'test1' , 'enslaved' )
3809 self
. wait_operstate ( 'bond99' , 'routable' )
3811 check_output ( 'ip link set dummy98 down' )
3812 check_output ( 'ip link set test1 down' )
3814 self
. wait_operstate ( 'dummy98' , 'off' )
3815 self
. wait_operstate ( 'test1' , 'off' )
3817 if not self
. wait_operstate ( 'bond99' , 'no-carrier' , setup_timeout
= 30 , fail_assert
= False ):
3818 # Huh? Kernel does not recognize that all slave interfaces are down?
3819 # Let's confirm that networkd's operstate is consistent with ip's result.
3820 self
. assertNotRegex ( output
, 'NO-CARRIER' )
3822 class NetworkdBridgeTests ( unittest
. TestCase
, Utilities
):
3830 def test_bridge_vlan ( self
):
3831 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave.network' ,
3832 '26-bridge.netdev' , '26-bridge-vlan-master.network' )
3834 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' ])
3836 output
= check_output ( 'bridge vlan show dev test1' )
3838 self
. assertNotRegex ( output
, '4063' )
3839 for i
in range ( 4064 , 4095 ):
3840 self
. assertRegex ( output
, f
' {i} ' )
3841 self
. assertNotRegex ( output
, '4095' )
3843 output
= check_output ( 'bridge vlan show dev bridge99' )
3845 self
. assertNotRegex ( output
, '4059' )
3846 for i
in range ( 4060 , 4095 ):
3847 self
. assertRegex ( output
, f
' {i} ' )
3848 self
. assertNotRegex ( output
, '4095' )
3850 def test_bridge_vlan_issue_20373 ( self
):
3851 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave-issue-20373.network' ,
3852 '26-bridge-issue-20373.netdev' , '26-bridge-vlan-master-issue-20373.network' ,
3853 '21-vlan.netdev' , '21-vlan.network' )
3855 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' , 'vlan99:routable' ])
3857 output
= check_output ( 'bridge vlan show dev test1' )
3859 self
. assertIn ( '100 PVID Egress Untagged' , output
)
3860 self
. assertIn ( '560' , output
)
3861 self
. assertIn ( '600' , output
)
3863 output
= check_output ( 'bridge vlan show dev bridge99' )
3865 self
. assertIn ( '1 PVID Egress Untagged' , output
)
3866 self
. assertIn ( '100' , output
)
3867 self
. assertIn ( '600' , output
)
3869 def test_bridge_mdb ( self
):
3870 copy_network_unit ( '11-dummy.netdev' , '26-bridge-mdb-slave.network' ,
3871 '26-bridge.netdev' , '26-bridge-mdb-master.network' )
3873 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' ])
3875 output
= check_output ( 'bridge mdb show dev bridge99' )
3877 self
. assertRegex ( output
, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064' )
3878 self
. assertRegex ( output
, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065' )
3880 # Old kernel may not support bridge MDB entries on bridge master
3881 if call_quiet ( 'bridge mdb add dev bridge99 port bridge99 grp 224.0.1.3 temp vid 4068' ) == 0 :
3882 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp ff02:aaaa:fee5::1:4 temp *vid 4066' )
3883 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp 224.0.1.2 temp *vid 4067' )
3885 def test_bridge_keep_master ( self
):
3886 check_output ( 'ip link add bridge99 type bridge' )
3887 check_output ( 'ip link set bridge99 up' )
3888 check_output ( 'ip link add dummy98 type dummy' )
3889 check_output ( 'ip link set dummy98 master bridge99' )
3891 copy_network_unit ( '23-keep-master.network' )
3893 self
. wait_online ([ 'dummy98:enslaved' ])
3895 output
= check_output ( 'ip -d link show dummy98' )
3897 self
. assertRegex ( output
, 'master bridge99' )
3898 self
. assertRegex ( output
, 'bridge' )
3900 output
= check_output ( 'bridge -d link show dummy98' )
3902 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
3903 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
3904 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
3905 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
3906 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
3907 # CONFIG_BRIDGE_IGMP_SNOOPING=y
3908 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
3909 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
3910 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
3911 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
3912 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
3913 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
3915 def test_bridge_property ( self
):
3916 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
3917 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
3918 '25-bridge99.network' )
3920 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' ])
3922 output
= check_output ( 'ip -d link show bridge99' )
3924 self
. assertIn ( 'mtu 9000 ' , output
)
3926 output
= check_output ( 'ip -d link show test1' )
3928 self
. assertIn ( 'master bridge99 ' , output
)
3929 self
. assertIn ( 'bridge_slave' , output
)
3930 self
. assertIn ( 'mtu 9000 ' , output
)
3932 output
= check_output ( 'ip -d link show dummy98' )
3934 self
. assertIn ( 'master bridge99 ' , output
)
3935 self
. assertIn ( 'bridge_slave' , output
)
3936 self
. assertIn ( 'mtu 9000 ' , output
)
3938 output
= check_output ( 'ip addr show bridge99' )
3940 self
. assertIn ( '192.168.0.15/24' , output
)
3942 output
= check_output ( 'bridge -d link show dummy98' )
3944 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
3945 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
3946 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'isolated' , '1' )
3947 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
3948 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
3949 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
3950 # CONFIG_BRIDGE_IGMP_SNOOPING=y
3951 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
3952 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
3953 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
3954 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
3955 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
3956 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
3958 output
= check_output ( 'bridge -d link show test1' )
3960 self
. check_bridge_port_attr ( 'bridge99' , 'test1' , 'priority' , '0' )
3962 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
3963 output
= check_output ( 'ip addr show bridge99' )
3965 self
. assertIn ( '192.168.0.16/24' , output
)
3968 print ( '### ip -6 route list table all dev bridge99' )
3969 output
= check_output ( 'ip -6 route list table all dev bridge99' )
3971 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
3973 remove_link ( 'test1' )
3974 self
. wait_operstate ( 'bridge99' , 'degraded-carrier' )
3976 output
= check_output ( 'ip -d link show bridge99' )
3978 self
. assertIn ( 'mtu 9000 ' , output
)
3980 output
= check_output ( 'ip -d link show dummy98' )
3982 self
. assertIn ( 'master bridge99 ' , output
)
3983 self
. assertIn ( 'bridge_slave' , output
)
3984 self
. assertIn ( 'mtu 9000 ' , output
)
3986 remove_link ( 'dummy98' )
3987 self
. wait_operstate ( 'bridge99' , 'no-carrier' )
3989 output
= check_output ( 'ip -d link show bridge99' )
3991 # When no carrier, the kernel may reset the MTU
3992 self
. assertIn ( 'NO-CARRIER' , output
)
3994 output
= check_output ( 'ip address show bridge99' )
3996 self
. assertNotIn ( '192.168.0.15/24' , output
)
3997 self
. assertIn ( '192.168.0.16/24' , output
) # foreign address is kept
3999 print ( '### ip -6 route list table all dev bridge99' )
4000 output
= check_output ( 'ip -6 route list table all dev bridge99' )
4002 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
4004 check_output ( 'ip link add dummy98 type dummy' )
4005 self
. wait_online ([ 'dummy98:enslaved' , 'bridge99:routable' ])
4007 output
= check_output ( 'ip -d link show bridge99' )
4009 self
. assertIn ( 'mtu 9000 ' , output
)
4011 output
= check_output ( 'ip -d link show dummy98' )
4013 self
. assertIn ( 'master bridge99 ' , output
)
4014 self
. assertIn ( 'bridge_slave' , output
)
4015 self
. assertIn ( 'mtu 9000 ' , output
)
4017 def test_bridge_configure_without_carrier ( self
):
4018 copy_network_unit ( '26-bridge.netdev' , '26-bridge-configure-without-carrier.network' ,
4022 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
4023 for test
in [ 'no-slave' , 'add-slave' , 'slave-up' , 'slave-no-carrier' , 'slave-carrier' , 'slave-down' ]:
4024 with self
. subTest ( test
= test
):
4025 if test
== 'no-slave' :
4026 # bridge has no slaves; it's up but *might* not have carrier
4027 self
. wait_operstate ( 'bridge99' , operstate
= r
'(no-carrier|routable)' , setup_state
= None , setup_timeout
= 30 )
4028 # due to a bug in the kernel, newly-created bridges are brought up
4029 # *with* carrier, unless they have had any setting changed; e.g.
4030 # their mac set, priority set, etc. Then, they will lose carrier
4031 # as soon as a (down) slave interface is added, and regain carrier
4032 # again once the slave interface is brought up.
4033 #self.check_link_attr('bridge99', 'carrier', '0')
4034 elif test
== 'add-slave' :
4035 # add slave to bridge, but leave it down; bridge is definitely no-carrier
4036 self
. check_link_attr ( 'test1' , 'operstate' , 'down' )
4037 check_output ( 'ip link set dev test1 master bridge99' )
4038 self
. wait_operstate ( 'bridge99' , operstate
= 'no-carrier' , setup_state
= None )
4039 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4040 elif test
== 'slave-up' :
4041 # bring up slave, which will have carrier; bridge gains carrier
4042 check_output ( 'ip link set dev test1 up' )
4043 self
. wait_online ([ 'bridge99:routable' ])
4044 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
4045 elif test
== 'slave-no-carrier' :
4046 # drop slave carrier; bridge loses carrier
4047 check_output ( 'ip link set dev test1 carrier off' )
4048 self
. wait_online ([ 'bridge99:no-carrier:no-carrier' ])
4049 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4050 elif test
== 'slave-carrier' :
4051 # restore slave carrier; bridge gains carrier
4052 check_output ( 'ip link set dev test1 carrier on' )
4053 self
. wait_online ([ 'bridge99:routable' ])
4054 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
4055 elif test
== 'slave-down' :
4056 # bring down slave; bridge loses carrier
4057 check_output ( 'ip link set dev test1 down' )
4058 self
. wait_online ([ 'bridge99:no-carrier:no-carrier' ])
4059 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4061 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bridge99' , env
= env
)
4062 self
. assertRegex ( output
, '10.1.2.3' )
4063 self
. assertRegex ( output
, '10.1.2.1' )
4065 def test_bridge_ignore_carrier_loss ( self
):
4066 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
4067 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
4068 '25-bridge99-ignore-carrier-loss.network' )
4070 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' ])
4072 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
4073 remove_link ( 'test1' , 'dummy98' )
4076 output
= check_output ( 'ip address show bridge99' )
4078 self
. assertRegex ( output
, 'NO-CARRIER' )
4079 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
4080 self
. assertRegex ( output
, 'inet 192.168.0.16/24 scope global secondary bridge99' )
4082 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain ( self
):
4083 copy_network_unit ( '26-bridge.netdev' , '26-bridge-slave-interface-1.network' ,
4084 '25-bridge99-ignore-carrier-loss.network' )
4086 self
. wait_online ([ 'bridge99:no-carrier' ])
4088 for trial
in range ( 4 ):
4089 check_output ( 'ip link add dummy98 type dummy' )
4090 check_output ( 'ip link set dummy98 up' )
4092 remove_link ( 'dummy98' )
4094 self
. wait_online ([ 'bridge99:routable' , 'dummy98:enslaved' ])
4096 output
= check_output ( 'ip address show bridge99' )
4098 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
4100 output
= check_output ( 'ip rule list table 100' )
4102 self
. assertIn ( 'from all to 8.8.8.8 lookup 100' , output
)
4104 class NetworkdSRIOVTests ( unittest
. TestCase
, Utilities
):
4112 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
4113 def test_sriov ( self
):
4114 call ( 'modprobe netdevsim' )
4116 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4119 with
open ( '/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4122 copy_network_unit ( '25-sriov.network' )
4124 self
. wait_online ([ 'eni99np1:routable' ])
4126 output
= check_output ( 'ip link show dev eni99np1' )
4128 self
. assertRegex ( output
,
4129 '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 *'
4130 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4131 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4134 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
4135 def test_sriov_udev ( self
):
4136 copy_network_unit ( '25-sriov.link' , '25-sriov-udev.network' )
4138 call ( 'modprobe netdevsim' )
4140 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4144 self
. wait_online ([ 'eni99np1:routable' ])
4146 output
= check_output ( 'ip link show dev eni99np1' )
4148 self
. assertRegex ( output
,
4149 '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 *'
4150 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4151 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4153 self
. assertNotIn ( 'vf 3' , output
)
4154 self
. assertNotIn ( 'vf 4' , output
)
4156 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4157 f
. write ( '[Link] \n SR-IOVVirtualFunctions=4 \n ' )
4160 call (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , '/sys/devices/netdevsim99/net/eni99np1' )
4162 output
= check_output ( 'ip link show dev eni99np1' )
4164 self
. assertRegex ( output
,
4165 '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 *'
4166 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4167 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
4170 self
. assertNotIn ( 'vf 4' , output
)
4172 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4173 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
4176 call (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , '/sys/devices/netdevsim99/net/eni99np1' )
4178 output
= check_output ( 'ip link show dev eni99np1' )
4180 self
. assertRegex ( output
,
4181 '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 *'
4182 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4183 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
4186 self
. assertNotIn ( 'vf 4' , output
)
4188 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4189 f
. write ( '[Link] \n SR-IOVVirtualFunctions=2 \n ' )
4192 call (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , '/sys/devices/netdevsim99/net/eni99np1' )
4194 output
= check_output ( 'ip link show dev eni99np1' )
4196 self
. assertRegex ( output
,
4197 '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 *'
4198 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off'
4200 self
. assertNotIn ( 'vf 2' , output
)
4201 self
. assertNotIn ( 'vf 3' , output
)
4202 self
. assertNotIn ( 'vf 4' , output
)
4204 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4205 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
4208 call (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , '/sys/devices/netdevsim99/net/eni99np1' )
4210 output
= check_output ( 'ip link show dev eni99np1' )
4212 self
. assertRegex ( output
,
4213 '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 *'
4214 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4215 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4217 self
. assertNotIn ( 'vf 3' , output
)
4218 self
. assertNotIn ( 'vf 4' , output
)
4220 class NetworkdLLDPTests ( unittest
. TestCase
, Utilities
):
4228 def test_lldp ( self
):
4229 copy_network_unit ( '23-emit-lldp.network' , '24-lldp.network' , '25-veth.netdev' )
4231 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:degraded' ])
4233 for trial
in range ( 10 ):
4237 output
= check_output (* networkctl_cmd
, 'lldp' , env
= env
)
4239 if re
. search ( r
'veth99 .* veth-peer' , output
):
4244 class NetworkdRATests ( unittest
. TestCase
, Utilities
):
4252 def test_ipv6_prefix_delegation ( self
):
4253 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth.network' )
4255 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4257 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth99' , env
= env
)
4259 self
. assertRegex ( output
, 'fe80::' )
4260 self
. assertRegex ( output
, '2002:da8:1::1' )
4262 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth99' , env
= env
)
4264 self
. assertIn ( 'hogehoge.test' , output
)
4266 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4268 self
. assertRegex ( output
, '2002:da8:1:0' )
4270 def test_ipv6_token_static ( self
):
4271 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-static.network' )
4273 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4275 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4277 self
. assertRegex ( output
, '2002:da8:1:0:1a:2b:3c:4d' )
4278 self
. assertRegex ( output
, '2002:da8:1:0:fa:de:ca:fe' )
4279 self
. assertRegex ( output
, '2002:da8:2:0:1a:2b:3c:4d' )
4280 self
. assertRegex ( output
, '2002:da8:2:0:fa:de:ca:fe' )
4282 def test_ipv6_token_prefixstable ( self
):
4283 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable.network' )
4285 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4287 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4289 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
4290 self
. assertIn ( '2002:da8:2:0:1034:56ff:fe78:9abc' , output
) # EUI64
4292 def test_ipv6_token_prefixstable_without_address ( self
):
4293 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable-without-address.network' )
4295 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4297 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4299 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
4300 self
. assertIn ( '2002:da8:2:0:f689:561a:8eda:7443' , output
)
4302 class NetworkdDHCPServerTests ( unittest
. TestCase
, Utilities
):
4310 def test_dhcp_server ( self
):
4311 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server.network' )
4313 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4315 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4317 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4318 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
4319 self
. assertRegex ( output
, 'DNS: 192.168.5.1 \n *192.168.5.10' )
4320 self
. assertRegex ( output
, 'NTP: 192.168.5.1 \n *192.168.5.11' )
4322 def test_dhcp_server_with_uplink ( self
):
4323 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-downstream.network' ,
4324 '12-dummy.netdev' , '25-dhcp-server-uplink.network' )
4326 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4328 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4330 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4331 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
4332 self
. assertIn ( 'DNS: 192.168.5.1' , output
)
4333 self
. assertIn ( 'NTP: 192.168.5.1' , output
)
4335 def test_emit_router_timezone ( self
):
4336 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-timezone-router.network' , '25-dhcp-server-timezone-router.network' )
4338 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4340 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4342 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4343 self
. assertIn ( 'Gateway: 192.168.5.1' , output
)
4344 self
. assertIn ( 'Time Zone: Europe/Berlin' , output
)
4346 def test_dhcp_server_static_lease ( self
):
4347 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-static-lease.network' , '25-dhcp-server-static-lease.network' )
4349 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4351 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4353 self
. assertIn ( 'Address: 10.1.1.200 (DHCP4 via 10.1.1.1)' , output
)
4355 class NetworkdDHCPServerRelayAgentTests ( unittest
. TestCase
, Utilities
):
4363 def test_relay_agent ( self
):
4364 copy_network_unit ( '25-agent-veth-client.netdev' ,
4365 '25-agent-veth-server.netdev' ,
4366 '25-agent-client.network' ,
4367 '25-agent-server.network' ,
4368 '25-agent-client-peer.network' ,
4369 '25-agent-server-peer.network' )
4372 self
. wait_online ([ 'client:routable' ])
4374 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'client' , env
= env
)
4376 self
. assertRegex ( output
, r
'Address: 192.168.5.150 \(DHCP4 via 192.168.5.1\)' )
4378 class NetworkdDHCPClientTests ( unittest
. TestCase
, Utilities
):
4386 def test_dhcp_client_ipv6_only ( self
):
4387 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv6-only.network' )
4390 self
. wait_online ([ 'veth-peer:carrier' ])
4392 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4395 output
= check_output ( 'ip address show dev veth99 scope global' )
4397 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
4398 self
. assertNotIn ( '192.168.5' , output
)
4400 # checking semi-static route
4401 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
4403 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
4405 # Confirm that ipv6 token is not set in the kernel
4406 output
= check_output ( 'ip token show dev veth99' )
4408 self
. assertRegex ( output
, 'token :: dev veth99' )
4410 print ( '## dnsmasq log' )
4411 output
= read_dnsmasq_log_file ()
4413 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
4414 self
. assertNotIn ( 'DHCPADVERTISE(veth-peer)' , output
)
4415 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
4416 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
4417 self
. assertIn ( 'sent size: 0 option: 14 rapid-commit' , output
)
4419 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-ipv6-only.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4420 f
. write ( ' \n [DHCPv6] \n RapidCommit=no \n ' )
4426 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4429 output
= check_output ( 'ip address show dev veth99 scope global' )
4431 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
4432 self
. assertNotIn ( '192.168.5' , output
)
4434 # checking semi-static route
4435 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
4437 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
4439 print ( '## dnsmasq log' )
4440 output
= read_dnsmasq_log_file ()
4442 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
4443 self
. assertIn ( 'DHCPADVERTISE(veth-peer)' , output
)
4444 self
. assertIn ( 'DHCPREQUEST(veth-peer)' , output
)
4445 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
4446 self
. assertNotIn ( 'rapid-commit' , output
)
4448 def test_dhcp_client_ipv4_only ( self
):
4449 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv4-only.network' )
4452 self
. wait_online ([ 'veth-peer:carrier' ])
4453 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7' ,
4454 '--dhcp-option=option:domain-search,example.com' ,
4455 '--dhcp-alternate-port=67,5555' ,
4456 ipv4_range
= '192.168.5.110,192.168.5.119' )
4457 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4459 print ( '## ip address show dev veth99 scope global' )
4460 output
= check_output ( 'ip address show dev veth99 scope global' )
4462 self
. assertIn ( 'mtu 1492' , output
)
4463 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
4464 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' )
4465 self
. assertNotIn ( '2600::' , output
)
4467 print ( '## ip route show table main dev veth99' )
4468 output
= check_output ( 'ip route show table main dev veth99' )
4470 # no DHCP routes assigned to the main table
4471 self
. assertNotIn ( 'proto dhcp' , output
)
4473 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
4474 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
4475 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
4476 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
4478 print ( '## ip route show table 211 dev veth99' )
4479 output
= check_output ( 'ip route show table 211 dev veth99' )
4481 self
. assertRegex ( output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.11[0-9] metric 24' )
4482 self
. assertRegex ( output
, '192.168.5.0/24 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4483 self
. assertRegex ( output
, '192.168.5.1 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4484 self
. assertRegex ( output
, '192.168.5.6 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4485 self
. assertRegex ( output
, '192.168.5.7 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4486 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
4488 print ( '## link state file' )
4489 output
= read_link_state_file ( 'veth99' )
4491 # checking DNS server and Domains
4492 self
. assertIn ( 'DNS=192.168.5.6 192.168.5.7' , output
)
4493 self
. assertIn ( 'DOMAINS=example.com' , output
)
4495 print ( '## dnsmasq log' )
4496 output
= read_dnsmasq_log_file ()
4498 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
4499 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc' , output
)
4500 self
. assertIn ( 'client provides name: test-hostname' , output
)
4501 self
. assertIn ( '26:mtu' , output
)
4503 # change address range, DNS servers, and Domains
4505 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8' ,
4506 '--dhcp-option=option:domain-search,foo.example.com' ,
4507 '--dhcp-alternate-port=67,5555' ,
4508 ipv4_range
= '192.168.5.120,192.168.5.129' ,)
4510 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4511 print ( 'Wait for the DHCP lease to be expired' )
4512 self
. wait_address_dropped ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' , timeout_sec
= 120 )
4513 self
. wait_address ( 'veth99' , r
'inet 192.168.5.12[0-9]*/24' , ipv
= '-4' )
4515 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4517 print ( '## ip address show dev veth99 scope global' )
4518 output
= check_output ( 'ip address show dev veth99 scope global' )
4520 self
. assertIn ( 'mtu 1492' , output
)
4521 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
4522 self
. assertNotIn ( '192.168.5.11' , output
)
4523 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' )
4524 self
. assertNotIn ( '2600::' , output
)
4526 print ( '## ip route show table main dev veth99' )
4527 output
= check_output ( 'ip route show table main dev veth99' )
4529 # no DHCP routes assigned to the main table
4530 self
. assertNotIn ( 'proto dhcp' , output
)
4532 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
4533 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
4534 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
4535 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
4537 print ( '## ip route show table 211 dev veth99' )
4538 output
= check_output ( 'ip route show table 211 dev veth99' )
4540 self
. assertRegex ( output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.12[0-9] metric 24' )
4541 self
. assertRegex ( output
, '192.168.5.0/24 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4542 self
. assertRegex ( output
, '192.168.5.1 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4543 self
. assertNotIn ( '192.168.5.6' , output
)
4544 self
. assertRegex ( output
, '192.168.5.7 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4545 self
. assertRegex ( output
, '192.168.5.8 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4546 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
4548 print ( '## link state file' )
4549 output
= read_link_state_file ( 'veth99' )
4551 # checking DNS server and Domains
4552 self
. assertIn ( 'DNS=192.168.5.1 192.168.5.7 192.168.5.8' , output
)
4553 self
. assertIn ( 'DOMAINS=foo.example.com' , output
)
4555 print ( '## dnsmasq log' )
4556 output
= read_dnsmasq_log_file ()
4558 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
4559 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 192.168.5.11' , output
)
4560 self
. assertIn ( 'client provides name: test-hostname' , output
)
4561 self
. assertIn ( '26:mtu' , output
)
4563 def test_dhcp_client_ipv4_use_routes_gateway ( self
):
4565 for ( routes
, gateway
, dns_and_ntp_routes
, classless
) in itertools
. product ([ True , False ], repeat
= 4 ):
4571 print ( f
'### test_dhcp_client_ipv4_use_routes_gateway(routes= {routes} , gateway= {gateway} , dns_and_ntp_routes= {dns_and_ntp_routes} , classless= {classless} )' )
4572 with self
. subTest ( routes
= routes
, gateway
= gateway
, dns_and_ntp_routes
= dns_and_ntp_routes
, classless
= classless
):
4573 self
._ test
_ dhcp
_ client
_ ipv
4_u se
_ routes
_ gateway
( routes
, gateway
, dns_and_ntp_routes
, classless
)
4575 def _test_dhcp_client_ipv4_use_routes_gateway ( self
, use_routes
, use_gateway
, dns_and_ntp_routes
, classless
):
4576 testunit
= '25-dhcp-client-ipv4-use-routes-use-gateway.network'
4577 testunits
= [ '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , testunit
]
4578 testunits
. append ( f
' {testunit} .d/use-routes- {use_routes} .conf' )
4579 testunits
. append ( f
' {testunit} .d/use-gateway- {use_gateway} .conf' )
4580 testunits
. append ( f
' {testunit} .d/use-dns-and-ntp-routes- {dns_and_ntp_routes} .conf' )
4581 copy_network_unit (* testunits
, copy_dropins
= False )
4584 self
. wait_online ([ 'veth-peer:carrier' ])
4585 additional_options
= [
4586 '--dhcp-option=option:dns-server,192.168.5.10,8.8.8.8' ,
4587 '--dhcp-option=option:ntp-server,192.168.5.11,9.9.9.9' ,
4588 '--dhcp-option=option:static-route,192.168.5.100,192.168.5.2,8.8.8.8,192.168.5.3'
4591 additional_options
+= [
4592 '--dhcp-option=option:classless-static-route,0.0.0.0/0,192.168.5.4,8.0.0.0/8,192.168.5.5'
4594 start_dnsmasq (* additional_options
)
4595 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4597 output
= check_output ( 'ip -4 route show dev veth99' )
4603 self
. assertRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4604 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4605 self
. assertRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4606 self
. assertRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4608 self
. assertRegex ( output
, r
'192.168.5.0/24 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4609 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4610 self
. assertRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4612 self
. assertNotRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4613 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4614 self
. assertNotRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4615 self
. assertNotRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4616 self
. assertNotRegex ( output
, r
'192.168.5.0/24 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4617 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4618 self
. assertNotRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4621 if use_gateway
and ( not classless
or not use_routes
):
4622 self
. assertRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4624 self
. assertNotRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4626 # Check route to gateway
4627 if ( use_gateway
or dns_and_ntp_routes
) and ( not classless
or not use_routes
):
4628 self
. assertRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4630 self
. assertNotRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4632 # Check RoutesToDNS= and RoutesToNTP=
4633 if dns_and_ntp_routes
:
4634 self
. assertRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4635 self
. assertRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4636 if classless
and use_routes
:
4637 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4638 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4640 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4641 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4643 self
. assertNotRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4644 self
. assertNotRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4645 self
. assertNotRegex ( output
, r
'8.8.8.8 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
4646 self
. assertNotRegex ( output
, r
'9.9.9.9 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
4648 # TODO: check json string
4649 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
4651 def test_dhcp_client_settings_anonymize ( self
):
4652 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-anonymize.network' )
4654 self
. wait_online ([ 'veth-peer:carrier' ])
4656 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4658 print ( '## dnsmasq log' )
4659 output
= read_dnsmasq_log_file ()
4661 self
. assertNotIn ( 'VendorClassIdentifier=SusantVendorTest' , output
)
4662 self
. assertNotIn ( 'test-hostname' , output
)
4663 self
. assertNotIn ( '26:mtu' , output
)
4665 def test_dhcp_keep_configuration_dhcp ( self
):
4666 copy_network_unit ( '25-veth.netdev' ,
4667 '25-dhcp-server-veth-peer.network' ,
4668 '25-dhcp-client-keep-configuration-dhcp.network' )
4670 self
. wait_online ([ 'veth-peer:carrier' ])
4672 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4674 output
= check_output ( 'ip address show dev veth99 scope global' )
4676 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4677 'valid_lft forever preferred_lft forever' )
4679 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
4682 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4683 print ( 'Wait for the DHCP lease to be expired' )
4686 # The lease address should be kept after the lease expired
4687 output
= check_output ( 'ip address show dev veth99 scope global' )
4689 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4690 'valid_lft forever preferred_lft forever' )
4694 # The lease address should be kept after networkd stopped
4695 output
= check_output ( 'ip address show dev veth99 scope global' )
4697 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4698 'valid_lft forever preferred_lft forever' )
4700 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-keep-configuration-dhcp.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4701 f
. write ( '[Network] \n DHCP=no \n ' )
4704 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4706 # Still the lease address should be kept after networkd restarted
4707 output
= check_output ( 'ip address show dev veth99 scope global' )
4709 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4710 'valid_lft forever preferred_lft forever' )
4712 def test_dhcp_keep_configuration_dhcp_on_stop ( self
):
4713 copy_network_unit ( '25-veth.netdev' ,
4714 '25-dhcp-server-veth-peer.network' ,
4715 '25-dhcp-client-keep-configuration-dhcp-on-stop.network' )
4717 self
. wait_online ([ 'veth-peer:carrier' ])
4719 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4721 output
= check_output ( 'ip address show dev veth99 scope global' )
4723 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
4728 output
= check_output ( 'ip address show dev veth99 scope global' )
4730 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
4733 self
. wait_online ([ 'veth-peer:routable' ])
4735 output
= check_output ( 'ip address show dev veth99 scope global' )
4737 self
. assertNotIn ( '192.168.5.' , output
)
4739 def test_dhcp_client_reuse_address_as_static ( self
):
4740 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' )
4742 self
. wait_online ([ 'veth-peer:carrier' ])
4744 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4746 # link become 'routable' when at least one protocol provide an valid address.
4747 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
4748 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
4750 output
= check_output ( 'ip address show dev veth99 scope global' )
4751 ipv4_address
= re
. search ( r
'192.168.5.[0-9]*/24' , output
). group ()
4752 ipv6_address
= re
. search ( r
'2600::[0-9a-f:]*/128' , output
). group ()
4753 static_network
= ' \n ' . join ([ '[Match]' , 'Name=veth99' , '[Network]' , 'IPv6AcceptRA=no' , 'Address=' + ipv4_address
, 'Address=' + ipv6_address
])
4754 print ( static_network
)
4756 remove_network_unit ( '25-dhcp-client.network' )
4758 with
open ( os
. path
. join ( network_unit_dir
, '25-static.network' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
4759 f
. write ( static_network
)
4762 self
. wait_online ([ 'veth99:routable' ])
4764 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
4766 self
. assertRegex ( output
, f
'inet {ipv4_address} brd 192.168.5.255 scope global veth99 \n *'
4767 'valid_lft forever preferred_lft forever' )
4769 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
4771 self
. assertRegex ( output
, f
'inet6 {ipv6_address} scope global * \n *'
4772 'valid_lft forever preferred_lft forever' )
4774 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
4775 def test_dhcp_client_vrf ( self
):
4776 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-vrf.network' ,
4777 '25-vrf.netdev' , '25-vrf.network' )
4779 self
. wait_online ([ 'veth-peer:carrier' ])
4781 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'vrf99:carrier' ])
4783 # link become 'routable' when at least one protocol provide an valid address.
4784 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
4785 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
4787 print ( '## ip -d link show dev vrf99' )
4788 output
= check_output ( 'ip -d link show dev vrf99' )
4790 self
. assertRegex ( output
, 'vrf table 42' )
4792 print ( '## ip address show vrf vrf99' )
4793 output
= check_output ( 'ip address show vrf vrf99' )
4795 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
4796 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
4797 self
. assertRegex ( output
, 'inet6 .* scope link' )
4799 print ( '## ip address show dev veth99' )
4800 output
= check_output ( 'ip address show dev veth99' )
4802 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
4803 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
4804 self
. assertRegex ( output
, 'inet6 .* scope link' )
4806 print ( '## ip route show vrf vrf99' )
4807 output
= check_output ( 'ip route show vrf vrf99' )
4809 self
. assertRegex ( output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.' )
4810 self
. assertRegex ( output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5' )
4811 self
. assertRegex ( output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5' )
4813 print ( '## ip route show table main dev veth99' )
4814 output
= check_output ( 'ip route show table main dev veth99' )
4816 self
. assertEqual ( output
, '' )
4818 def test_dhcp_client_gateway_onlink_implicit ( self
):
4819 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
4820 '25-dhcp-client-gateway-onlink-implicit.network' )
4822 self
. wait_online ([ 'veth-peer:carrier' ])
4824 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4826 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4828 self
. assertRegex ( output
, '192.168.5' )
4830 output
= check_output ( 'ip route list dev veth99 10.0.0.0/8' )
4832 self
. assertRegex ( output
, 'onlink' )
4833 output
= check_output ( 'ip route list dev veth99 192.168.100.0/24' )
4835 self
. assertRegex ( output
, 'onlink' )
4837 def test_dhcp_client_with_ipv4ll ( self
):
4838 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
4839 '25-dhcp-client-with-ipv4ll.network' )
4841 # we need to increase timeout above default, as this will need to wait for
4842 # systemd-networkd to get the dhcpv4 transient failure event
4843 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:routable' ], timeout
= '60s' )
4845 output
= check_output ( 'ip -4 address show dev veth99' )
4847 self
. assertNotIn ( '192.168.5.' , output
)
4848 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
4851 print ( 'Wait for a DHCP lease to be acquired and the IPv4LL address to be dropped' )
4852 self
. wait_address ( 'veth99' , r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic' , ipv
= '-4' )
4853 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' )
4854 self
. wait_online ([ 'veth99:routable' ])
4856 output
= check_output ( 'ip -4 address show dev veth99' )
4858 self
. assertRegex ( output
, r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99' )
4859 self
. assertNotIn ( '169.254.' , output
)
4860 self
. assertNotIn ( 'scope link' , output
)
4863 print ( 'Wait for the DHCP lease to be expired and an IPv4LL address to be acquired' )
4864 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 )
4865 self
. wait_address ( 'veth99' , r
'inet 169\.254\.133\.11/16 metric 2048 brd 169\.254\.255\.255 scope link' , scope
= 'link' , ipv
= '-4' )
4867 output
= check_output ( 'ip -4 address show dev veth99' )
4869 self
. assertNotIn ( '192.168.5.' , output
)
4870 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
4872 def test_dhcp_client_use_dns ( self
):
4873 def check ( self
, ipv4
, ipv6
):
4874 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
4875 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
4876 f
. write ( '[DHCPv4] \n UseDNS=' )
4877 f
. write ( 'yes' if ipv4
else 'no' )
4878 f
. write ( ' \n [DHCPv6] \n UseDNS=' )
4879 f
. write ( 'yes' if ipv6
else 'no' )
4880 f
. write ( ' \n [IPv6AcceptRA] \n UseDNS=no' )
4883 self
. wait_online ([ 'veth99:routable' ])
4885 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
4886 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
4887 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
4889 # make resolved re-read the link state file
4890 check_output (* resolvectl_cmd
, 'revert' , 'veth99' , env
= env
)
4892 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth99' , env
= env
)
4895 self
. assertIn ( '192.168.5.1' , output
)
4897 self
. assertNotIn ( '192.168.5.1' , output
)
4899 self
. assertIn ( '2600::1' , output
)
4901 self
. assertNotIn ( '2600::1' , output
)
4903 # TODO: check json string
4904 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
4906 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
4909 self
. wait_online ([ 'veth-peer:carrier' ])
4910 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1' ,
4911 '--dhcp-option=option6:dns-server,[2600::1]' )
4913 check ( self
, True , True )
4914 check ( self
, True , False )
4915 check ( self
, False , True )
4916 check ( self
, False , False )
4918 class NetworkdDHCPPDTests ( unittest
. TestCase
, Utilities
):
4926 def test_dhcp6pd ( self
):
4927 copy_network_unit ( '25-veth.netdev' , '25-dhcp6pd-server.network' , '25-dhcp6pd-upstream.network' ,
4928 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
4929 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
4930 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
4931 '25-dhcp-pd-downstream-dummy97.network' ,
4932 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
4933 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' )
4936 self
. wait_online ([ 'veth-peer:routable' ])
4937 start_isc_dhcpd ( conf_file
= 'isc-dhcpd-dhcp6pd.conf' , ipv
= '-6' )
4938 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
4939 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
4941 print ( '### ip -6 address show dev veth-peer scope global' )
4942 output
= check_output ( 'ip -6 address show dev veth-peer scope global' )
4944 self
. assertIn ( 'inet6 3ffe:501:ffff:100::1/64 scope global' , output
)
4948 # dummy97: 0x01 (The link will appear later)
4950 # dummy99: auto -> 0x02 (No address assignment)
4955 print ( '### ip -6 address show dev veth99 scope global' )
4956 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
4959 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:100::[0-9]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
4960 # address in IA_PD (Token=static)
4961 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic' )
4962 # address in IA_PD (Token=eui64)
4963 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic' )
4964 # address in IA_PD (temporary)
4965 # Note that the temporary addresses may appear after the link enters configured state
4966 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' )
4968 print ( '### ip -6 address show dev test1 scope global' )
4969 output
= check_output ( 'ip -6 address show dev test1 scope global' )
4971 # address in IA_PD (Token=static)
4972 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
4973 # address in IA_PD (temporary)
4974 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' )
4976 print ( '### ip -6 address show dev dummy98 scope global' )
4977 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
4979 # address in IA_PD (Token=static)
4980 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
4981 # address in IA_PD (temporary)
4982 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' )
4984 print ( '### ip -6 address show dev dummy99 scope global' )
4985 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
4988 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
4990 print ( '### ip -6 address show dev veth97 scope global' )
4991 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
4993 # address in IA_PD (Token=static)
4994 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
4995 # address in IA_PD (Token=eui64)
4996 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
4997 # address in IA_PD (temporary)
4998 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' )
5000 print ( '### ip -6 address show dev veth97-peer scope global' )
5001 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
5003 # NDisc address (Token=static)
5004 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5005 # NDisc address (Token=eui64)
5006 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5007 # NDisc address (temporary)
5008 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' )
5010 print ( '### ip -6 address show dev veth98 scope global' )
5011 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
5013 # address in IA_PD (Token=static)
5014 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5015 # address in IA_PD (Token=eui64)
5016 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5017 # address in IA_PD (temporary)
5018 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' )
5020 print ( '### ip -6 address show dev veth98-peer scope global' )
5021 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
5023 # NDisc address (Token=static)
5024 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5025 # NDisc address (Token=eui64)
5026 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5027 # NDisc address (temporary)
5028 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' )
5030 print ( '### ip -6 route show type unreachable' )
5031 output
= check_output ( 'ip -6 route show type unreachable' )
5033 self
. assertRegex ( output
, 'unreachable 3ffe:501:ffff:[2-9a-f]00::/56 dev lo proto dhcp' )
5035 print ( '### ip -6 route show dev veth99' )
5036 output
= check_output ( 'ip -6 route show dev veth99' )
5038 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]10::/64 proto kernel metric [0-9]* expires' )
5040 print ( '### ip -6 route show dev test1' )
5041 output
= check_output ( 'ip -6 route show dev test1' )
5043 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5045 print ( '### ip -6 route show dev dummy98' )
5046 output
= check_output ( 'ip -6 route show dev dummy98' )
5048 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5050 print ( '### ip -6 route show dev dummy99' )
5051 output
= check_output ( 'ip -6 route show dev dummy99' )
5053 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
5055 print ( '### ip -6 route show dev veth97' )
5056 output
= check_output ( 'ip -6 route show dev veth97' )
5058 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto kernel metric [0-9]* expires' )
5060 print ( '### ip -6 route show dev veth97-peer' )
5061 output
= check_output ( 'ip -6 route show dev veth97-peer' )
5063 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto ra metric [0-9]* expires' )
5065 print ( '### ip -6 route show dev veth98' )
5066 output
= check_output ( 'ip -6 route show dev veth98' )
5068 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto kernel metric [0-9]* expires' )
5070 print ( '### ip -6 route show dev veth98-peer' )
5071 output
= check_output ( 'ip -6 route show dev veth98-peer' )
5073 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto ra metric [0-9]* expires' )
5075 # Test case for a downstream which appears later
5076 check_output ( 'ip link add dummy97 type dummy' )
5077 self
. wait_online ([ 'dummy97:routable' ])
5079 print ( '### ip -6 address show dev dummy97 scope global' )
5080 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
5082 # address in IA_PD (Token=static)
5083 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5084 # address in IA_PD (temporary)
5085 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' )
5087 print ( '### ip -6 route show dev dummy97' )
5088 output
= check_output ( 'ip -6 route show dev dummy97' )
5090 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]01::/64 proto kernel metric [0-9]* expires' )
5092 # Test case for reconfigure
5093 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
5094 self
. wait_online ([ 'dummy98:routable' , 'dummy99:degraded' ])
5096 print ( '### ip -6 address show dev dummy98 scope global' )
5097 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5099 # address in IA_PD (Token=static)
5100 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5101 # address in IA_PD (temporary)
5102 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' )
5104 print ( '### ip -6 address show dev dummy99 scope global' )
5105 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5108 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
5110 print ( '### ip -6 route show dev dummy98' )
5111 output
= check_output ( 'ip -6 route show dev dummy98' )
5113 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5115 print ( '### ip -6 route show dev dummy99' )
5116 output
= check_output ( 'ip -6 route show dev dummy99' )
5118 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
5120 def verify_dhcp4_6rd ( self
, tunnel_name
):
5121 print ( '### ip -4 address show dev veth-peer scope global' )
5122 output
= check_output ( 'ip -4 address show dev veth-peer scope global' )
5124 self
. assertIn ( 'inet 10.0.0.1/8 brd 10.255.255.255 scope global veth-peer' , output
)
5128 # dummy97: 0x01 (The link will appear later)
5130 # dummy99: auto -> 0x0[23] (No address assignment)
5131 # 6rd-XXX: auto -> 0x0[23]
5136 print ( '### ip -4 address show dev veth99 scope global' )
5137 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
5139 self
. assertRegex ( output
, 'inet 10.100.100.[0-9]*/8 (metric 1024 |)brd 10.255.255.255 scope global dynamic veth99' )
5141 print ( '### ip -6 address show dev veth99 scope global' )
5142 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5144 # address in IA_PD (Token=static)
5145 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5146 # address in IA_PD (Token=eui64)
5147 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5148 # address in IA_PD (temporary)
5149 # Note that the temporary addresses may appear after the link enters configured state
5150 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' )
5152 print ( '### ip -6 address show dev test1 scope global' )
5153 output
= check_output ( 'ip -6 address show dev test1 scope global' )
5155 # address in IA_PD (Token=static)
5156 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5157 # address in IA_PD (temporary)
5158 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' )
5160 print ( '### ip -6 address show dev dummy98 scope global' )
5161 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5163 # address in IA_PD (Token=static)
5164 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5165 # address in IA_PD (temporary)
5166 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' )
5168 print ( '### ip -6 address show dev dummy99 scope global' )
5169 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5172 self
. assertNotRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+0[23]' )
5174 print ( '### ip -6 address show dev veth97 scope global' )
5175 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
5177 # address in IA_PD (Token=static)
5178 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5179 # address in IA_PD (Token=eui64)
5180 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5181 # address in IA_PD (temporary)
5182 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' )
5184 print ( '### ip -6 address show dev veth97-peer scope global' )
5185 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
5187 # NDisc address (Token=static)
5188 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5189 # NDisc address (Token=eui64)
5190 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5191 # NDisc address (temporary)
5192 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' )
5194 print ( '### ip -6 address show dev veth98 scope global' )
5195 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
5197 # address in IA_PD (Token=static)
5198 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5199 # address in IA_PD (Token=eui64)
5200 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5201 # address in IA_PD (temporary)
5202 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' )
5204 print ( '### ip -6 address show dev veth98-peer scope global' )
5205 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
5207 # NDisc address (Token=static)
5208 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5209 # NDisc address (Token=eui64)
5210 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5211 # NDisc address (temporary)
5212 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' )
5214 print ( '### ip -6 route show type unreachable' )
5215 output
= check_output ( 'ip -6 route show type unreachable' )
5217 self
. assertRegex ( output
, 'unreachable 2001:db8:6464:[0-9a-f]+00::/56 dev lo proto dhcp' )
5219 print ( '### ip -6 route show dev veth99' )
5220 output
= check_output ( 'ip -6 route show dev veth99' )
5222 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+10::/64 proto kernel metric [0-9]* expires' )
5224 print ( '### ip -6 route show dev test1' )
5225 output
= check_output ( 'ip -6 route show dev test1' )
5227 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
5229 print ( '### ip -6 route show dev dummy98' )
5230 output
= check_output ( 'ip -6 route show dev dummy98' )
5232 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
5234 print ( '### ip -6 route show dev dummy99' )
5235 output
= check_output ( 'ip -6 route show dev dummy99' )
5237 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto dhcp metric [0-9]* expires' )
5239 print ( '### ip -6 route show dev veth97' )
5240 output
= check_output ( 'ip -6 route show dev veth97' )
5242 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto kernel metric [0-9]* expires' )
5244 print ( '### ip -6 route show dev veth97-peer' )
5245 output
= check_output ( 'ip -6 route show dev veth97-peer' )
5247 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto ra metric [0-9]* expires' )
5249 print ( '### ip -6 route show dev veth98' )
5250 output
= check_output ( 'ip -6 route show dev veth98' )
5252 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto kernel metric [0-9]* expires' )
5254 print ( '### ip -6 route show dev veth98-peer' )
5255 output
= check_output ( 'ip -6 route show dev veth98-peer' )
5257 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto ra metric [0-9]* expires' )
5259 print ( '### ip -6 address show dev dummy97 scope global' )
5260 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
5262 # address in IA_PD (Token=static)
5263 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5264 # address in IA_PD (temporary)
5265 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' )
5267 print ( '### ip -6 route show dev dummy97' )
5268 output
= check_output ( 'ip -6 route show dev dummy97' )
5270 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+01::/64 proto kernel metric [0-9]* expires' )
5272 print ( f
'### ip -d link show dev {tunnel_name} ' )
5273 output
= check_output ( f
'ip -d link show dev {tunnel_name} ' )
5275 self
. assertIn ( 'link/sit 10.100.100.' , output
)
5276 self
. assertIn ( 'local 10.100.100.' , output
)
5277 self
. assertIn ( 'ttl 64' , output
)
5278 self
. assertIn ( '6rd-prefix 2001:db8::/32' , output
)
5279 self
. assertIn ( '6rd-relay_prefix 10.0.0.0/8' , output
)
5281 print ( f
'### ip -6 address show dev {tunnel_name} ' )
5282 output
= check_output ( f
'ip -6 address show dev {tunnel_name} ' )
5284 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' )
5285 self
. assertRegex ( output
, 'inet6 ::10.100.100.[0-9]+/96 scope global' )
5287 print ( f
'### ip -6 route show dev {tunnel_name} ' )
5288 output
= check_output ( f
'ip -6 route show dev {tunnel_name} ' )
5290 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto kernel metric [0-9]* expires' )
5291 self
. assertRegex ( output
, '::/96 proto kernel metric [0-9]*' )
5293 print ( '### ip -6 route show default' )
5294 output
= check_output ( 'ip -6 route show default' )
5296 self
. assertIn ( 'default' , output
)
5297 self
. assertIn ( f
'via ::10.0.0.1 dev {tunnel_name} ' , output
)
5299 def test_dhcp4_6rd ( self
):
5300 copy_network_unit ( '25-veth.netdev' , '25-dhcp4-6rd-server.network' , '25-dhcp4-6rd-upstream.network' ,
5301 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
5302 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
5303 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
5304 '25-dhcp-pd-downstream-dummy97.network' ,
5305 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
5306 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' ,
5307 '80-6rd-tunnel.network' )
5310 self
. wait_online ([ 'veth-peer:routable' ])
5313 # 6rd-prefix: 2001:db8::/32
5314 # br-addresss: 10.0.0.1
5316 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' ,
5317 ipv4_range
= '10.100.100.100,10.100.100.200' ,
5318 ipv4_router
= '10.0.0.1' )
5319 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5320 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5322 # Test case for a downstream which appears later
5323 check_output ( 'ip link add dummy97 type dummy' )
5324 self
. wait_online ([ 'dummy97:routable' ])
5328 for name
in os
. listdir ( '/sys/class/net/' ):
5329 if name
. startswith ( '6rd-' ):
5333 self
. wait_online ([ f
' {tunnel_name} :routable' ])
5335 self
. verify_dhcp4_6rd ( tunnel_name
)
5337 # Test case for reconfigure
5338 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
5339 self
. wait_online ([ 'dummy98:routable' , 'dummy99:degraded' ])
5341 self
. verify_dhcp4_6rd ( tunnel_name
)
5343 print ( 'Wait for the DHCP lease to be renewed/rebind' )
5346 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy97:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5347 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5349 self
. verify_dhcp4_6rd ( tunnel_name
)
5351 class NetworkdIPv6PrefixTests ( unittest
. TestCase
, Utilities
):
5359 def test_ipv6_route_prefix ( self
):
5360 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client.network' , '25-ipv6ra-prefix.network' ,
5361 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
5364 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
5366 output
= check_output ( 'ip address show dev veth-peer' )
5368 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
5369 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
5370 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
5372 output
= check_output ( 'ip -6 route show dev veth-peer' )
5374 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
5375 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
5376 self
. assertNotIn ( '2001:db8:0:3::/64 proto ra' , output
)
5377 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
5378 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
5379 self
. assertNotIn ( '2001:db2:fff::/64 via ' , output
)
5381 output
= check_output ( 'ip address show dev veth99' )
5383 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
5384 self
. assertIn ( 'inet6 2001:db8:0:2:1a:2b:3c:4d' , output
)
5385 self
. assertIn ( 'inet6 2001:db8:0:2:fa:de:ca:fe' , output
)
5386 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
5388 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth-peer' , env
= env
)
5390 self
. assertRegex ( output
, '2001:db8:1:1::2' )
5392 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth-peer' , env
= env
)
5394 self
. assertIn ( 'example.com' , output
)
5396 # TODO: check json string
5397 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5399 def test_ipv6_route_prefix_deny_list ( self
):
5400 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client-deny-list.network' , '25-ipv6ra-prefix.network' ,
5401 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
5404 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
5406 output
= check_output ( 'ip address show dev veth-peer' )
5408 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
5409 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
5411 output
= check_output ( 'ip -6 route show dev veth-peer' )
5413 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
5414 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
5415 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
5416 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
5418 output
= check_output ( 'ip address show dev veth99' )
5420 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
5421 self
. assertIn ( 'inet6 2001:db8:0:2:' , output
)
5423 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth-peer' , env
= env
)
5425 self
. assertRegex ( output
, '2001:db8:1:1::2' )
5427 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth-peer' , env
= env
)
5429 self
. assertIn ( 'example.com' , output
)
5431 class NetworkdMTUTests ( unittest
. TestCase
, Utilities
):
5439 def check_mtu ( self
, mtu
, ipv6_mtu
= None , reset
= True ):
5445 self
. wait_online ([ 'dummy98:routable' ])
5446 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
5447 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
5449 # test normal restart
5451 self
. wait_online ([ 'dummy98:routable' ])
5452 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
5453 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
5456 self
. reset_check_mtu ( mtu
, ipv6_mtu
)
5458 def reset_check_mtu ( self
, mtu
, ipv6_mtu
= None ):
5459 ''' test setting mtu/ipv6_mtu with interface already up '''
5462 # note - changing the device mtu resets the ipv6 mtu
5463 check_output ( 'ip link set up mtu 1501 dev dummy98' )
5464 check_output ( 'ip link set up mtu 1500 dev dummy98' )
5465 self
. check_link_attr ( 'dummy98' , 'mtu' , '1500' )
5466 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , '1500' )
5468 self
. check_mtu ( mtu
, ipv6_mtu
, reset
= False )
5470 def test_mtu_network ( self
):
5471 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' )
5472 self
. check_mtu ( '1600' )
5474 def test_mtu_netdev ( self
):
5475 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network' , copy_dropins
= False )
5476 # note - MTU set by .netdev happens ONLY at device creation!
5477 self
. check_mtu ( '1600' , reset
= False )
5479 def test_mtu_link ( self
):
5480 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network' , copy_dropins
= False )
5481 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
5482 self
. check_mtu ( '1600' , reset
= False )
5484 def test_ipv6_mtu ( self
):
5485 ''' set ipv6 mtu without setting device mtu '''
5486 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1400.conf' )
5487 self
. check_mtu ( '1500' , '1400' )
5489 def test_ipv6_mtu_toolarge ( self
):
5490 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
5491 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5492 self
. check_mtu ( '1500' , '1500' )
5494 def test_mtu_network_ipv6_mtu ( self
):
5495 ''' set ipv6 mtu and set device mtu via network file '''
5496 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5497 self
. check_mtu ( '1600' , '1550' )
5499 def test_mtu_netdev_ipv6_mtu ( self
):
5500 ''' set ipv6 mtu and set device mtu via netdev file '''
5501 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5502 self
. check_mtu ( '1600' , '1550' , reset
= False )
5504 def test_mtu_link_ipv6_mtu ( self
):
5505 ''' set ipv6 mtu and set device mtu via link file '''
5506 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5507 self
. check_mtu ( '1600' , '1550' , reset
= False )
5510 if __name__
== '__main__' :
5511 parser
= argparse
. ArgumentParser ()
5512 parser
. add_argument ( '--build-dir' , help = 'Path to build dir' , dest
= 'build_dir' )
5513 parser
. add_argument ( '--networkd' , help = 'Path to systemd-networkd' , dest
= 'networkd_bin' )
5514 parser
. add_argument ( '--resolved' , help = 'Path to systemd-resolved' , dest
= 'resolved_bin' )
5515 parser
. add_argument ( '--timesyncd' , help = 'Path to systemd-timesyncd' , dest
= 'timesyncd_bin' )
5516 parser
. add_argument ( '--udevd' , help = 'Path to systemd-udevd' , dest
= 'udevd_bin' )
5517 parser
. add_argument ( '--wait-online' , help = 'Path to systemd-networkd-wait-online' , dest
= 'wait_online_bin' )
5518 parser
. add_argument ( '--networkctl' , help = 'Path to networkctl' , dest
= 'networkctl_bin' )
5519 parser
. add_argument ( '--resolvectl' , help = 'Path to resolvectl' , dest
= 'resolvectl_bin' )
5520 parser
. add_argument ( '--timedatectl' , help = 'Path to timedatectl' , dest
= 'timedatectl_bin' )
5521 parser
. add_argument ( '--udevadm' , help = 'Path to udevadm' , dest
= 'udevadm_bin' )
5522 parser
. add_argument ( '--valgrind' , help = 'Enable valgrind' , dest
= 'use_valgrind' , type = bool , nargs
= '?' , const
= True , default
= use_valgrind
)
5523 parser
. add_argument ( '--debug' , help = 'Generate debugging logs' , dest
= 'enable_debug' , type = bool , nargs
= '?' , const
= True , default
= enable_debug
)
5524 parser
. add_argument ( '--asan-options' , help = 'ASAN options' , dest
= 'asan_options' )
5525 parser
. add_argument ( '--lsan-options' , help = 'LSAN options' , dest
= 'lsan_options' )
5526 parser
. add_argument ( '--ubsan-options' , help = 'UBSAN options' , dest
= 'ubsan_options' )
5527 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
)
5528 ns
, unknown_args
= parser
. parse_known_args ( namespace
= unittest
)
5531 if ns
. networkd_bin
or ns
. resolved_bin
or ns
. timesyncd_bin
or ns
. udevd_bin
or \
5532 ns
. wait_online_bin
or ns
. networkctl_bin
or ns
. resolvectl_bin
or ns
. timedatectl_bin
or ns
. udevadm_bin
:
5533 print ( 'WARNING: --networkd, --resolved, --timesyncd, --udevd, --wait-online, --networkctl, --resolvectl, --timedatectl, or --udevadm options are ignored when --build-dir is specified.' )
5534 networkd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd' )
5535 resolved_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-resolved' )
5536 timesyncd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-timesyncd' )
5537 udevd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-udevd' )
5538 wait_online_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd-wait-online' )
5539 networkctl_bin
= os
. path
. join ( ns
. build_dir
, 'networkctl' )
5540 resolvectl_bin
= os
. path
. join ( ns
. build_dir
, 'resolvectl' )
5541 timedatectl_bin
= os
. path
. join ( ns
. build_dir
, 'timedatectl' )
5542 udevadm_bin
= os
. path
. join ( ns
. build_dir
, 'udevadm' )
5545 networkd_bin
= ns
. networkd_bin
5547 resolved_bin
= ns
. resolved_bin
5548 if ns
. timesyncd_bin
:
5549 timesyncd_bin
= ns
. timesyncd_bin
5551 udevd_bin
= ns
. udevd_bin
5552 if ns
. wait_online_bin
:
5553 wait_online_bin
= ns
. wait_online_bin
5554 if ns
. networkctl_bin
:
5555 networkctl_bin
= ns
. networkctl_bin
5556 if ns
. resolvectl_bin
:
5557 resolvectl_bin
= ns
. resolvectl_bin
5558 if ns
. timedatectl_bin
:
5559 timedatectl_bin
= ns
. timedatectl_bin
5561 udevadm_bin
= ns
. udevadm_bin
5563 use_valgrind
= ns
. use_valgrind
5564 enable_debug
= ns
. enable_debug
5565 asan_options
= ns
. asan_options
5566 lsan_options
= ns
. lsan_options
5567 ubsan_options
= ns
. ubsan_options
5568 with_coverage
= ns
. with_coverage
5571 # Do not forget the trailing space.
5572 valgrind_cmd
= 'valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all '
5574 networkctl_cmd
= valgrind_cmd
. split () + [ networkctl_bin
]
5575 resolvectl_cmd
= valgrind_cmd
. split () + [ resolvectl_bin
]
5576 timedatectl_cmd
= valgrind_cmd
. split () + [ timedatectl_bin
]
5577 udevadm_cmd
= valgrind_cmd
. split () + [ udevadm_bin
]
5578 wait_online_cmd
= valgrind_cmd
. split () + [ wait_online_bin
]
5581 env
. update ({ 'ASAN_OPTIONS' : asan_options
})
5583 env
. update ({ 'LSAN_OPTIONS' : lsan_options
})
5585 env
. update ({ 'UBSAN_OPTIONS' : ubsan_options
})
5587 env
. update ({ 'SYSTEMD_MEMPOOL' : '0' })
5589 wait_online_env
= env
. copy ()
5591 wait_online_env
. update ({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
5593 sys
. argv
[ 1 :] = unknown_args
5594 unittest
. main ( verbosity
= 3 )