]>
git.ipfire.org Git - thirdparty/systemd.git/blob - test/test-network/systemd-networkd-tests.py
2 # SPDX-License-Identifier: LGPL-2.1-or-later
3 # pylint: disable=line-too-long,too-many-lines,too-many-branches,too-many-statements,too-many-arguments
4 # pylint: disable=too-many-public-methods,too-many-boolean-expressions,invalid-name
5 # pylint: disable=missing-function-docstring,missing-class-docstring,missing-module-docstring
6 # systemd-networkd tests
8 # These tests can be executed in the systemd mkosi image when booted in QEMU. After booting the QEMU VM,
9 # simply run this file which can be found in the VM at /usr/lib/systemd/tests/testdata/test-network/systemd-networkd-tests.py.
26 network_unit_dir
= '/run/systemd/network'
27 networkd_conf_dropin_dir
= '/run/systemd/networkd.conf.d'
28 networkd_ci_temp_dir
= '/run/networkd-ci'
29 udev_rules_dir
= '/run/udev/rules.d'
31 dnsmasq_pid_file
= '/run/networkd-ci/test-dnsmasq.pid'
32 dnsmasq_log_file
= '/run/networkd-ci/test-dnsmasq.log'
33 dnsmasq_lease_file
= '/run/networkd-ci/test-dnsmasq.lease'
35 isc_dhcpd_pid_file
= '/run/networkd-ci/test-isc-dhcpd.pid'
36 isc_dhcpd_lease_file
= '/run/networkd-ci/test-isc-dhcpd.lease'
38 systemd_lib_paths
= [ '/usr/lib/systemd' , '/lib/systemd' ]
39 which_paths
= ':' . join ( systemd_lib_paths
+ os
. getenv ( 'PATH' , os
. defpath
). lstrip ( ':' ). split ( ':' ))
41 networkd_bin
= shutil
. which ( 'systemd-networkd' , path
= which_paths
)
42 resolved_bin
= shutil
. which ( 'systemd-resolved' , path
= which_paths
)
43 timesyncd_bin
= shutil
. which ( 'systemd-timesyncd' , path
= which_paths
)
44 udevd_bin
= shutil
. which ( 'systemd-udevd' , path
= which_paths
)
45 wait_online_bin
= shutil
. which ( 'systemd-networkd-wait-online' , path
= which_paths
)
46 networkctl_bin
= shutil
. which ( 'networkctl' , path
= which_paths
)
47 resolvectl_bin
= shutil
. which ( 'resolvectl' , path
= which_paths
)
48 timedatectl_bin
= shutil
. which ( 'timedatectl' , path
= which_paths
)
49 udevadm_bin
= shutil
. which ( 'udevadm' , path
= which_paths
)
77 saved_ipv4_rules
= None
78 saved_ipv6_rules
= None
82 if os
. path
. exists ( path
):
86 shutil
. rmtree ( path
, ignore_errors
= True )
92 shutil
. copytree ( src
, dst
, copy_function
= shutil
. copy
)
95 os
. makedirs ( path
, exist_ok
= True )
98 pathlib
. Path ( path
). touch ()
100 # pylint: disable=R1710
101 def check_output (* command
, ** kwargs
):
102 # This checks the result and returns stdout (and stderr) on success.
103 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
104 ret
= subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. PIPE
, stderr
= subprocess
. STDOUT
, ** kwargs
)
105 if ret
. returncode
== 0 :
106 return ret
. stdout
. rstrip ()
107 # When returncode != 0, print stdout and stderr, then trigger CalledProcessError.
109 ret
. check_returncode ()
111 def call (* command
, ** kwargs
):
112 # This returns returncode. stdout and stderr are merged and shown in console
113 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
114 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stderr
= subprocess
. STDOUT
, ** kwargs
). returncode
116 def call_quiet (* command
, ** kwargs
):
117 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
118 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. DEVNULL
, stderr
= subprocess
. DEVNULL
, ** kwargs
). returncode
120 def run (* command
, ** kwargs
):
121 # This returns CompletedProcess instance.
122 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
123 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. PIPE
, stderr
= subprocess
. PIPE
, ** kwargs
)
125 def is_module_available (* module_names
):
126 for module_name
in module_names
:
127 lsmod_output
= check_output ( 'lsmod' )
128 module_re
= re
. compile ( rf
'^{re.escape(module_name)} \b ' , re
. MULTILINE
)
129 if not module_re
. search ( lsmod_output
) and call_quiet ( 'modprobe' , module_name
) != 0 :
133 def expectedFailureIfModuleIsNotAvailable (* module_names
):
135 return func
if is_module_available (* module_names
) else unittest
. expectedFailure ( func
)
139 def expectedFailureIfERSPANv0IsNotSupported ():
140 # erspan version 0 is supported since f989d546a2d5a9f001f6f8be49d98c10ab9b1897 (v5.8)
142 rc
= call_quiet ( 'ip link add dev erspan99 type erspan seq key 30 local 192.168.1.4 remote 192.168.1.1 erspan_ver 0' )
143 remove_link ( 'erspan99' )
144 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
148 def expectedFailureIfERSPANv2IsNotSupported ():
149 # erspan version 2 is supported since f551c91de262ba36b20c3ac19538afb4f4507441 (v4.16)
151 rc
= call_quiet ( 'ip link add dev erspan99 type erspan seq key 30 local 192.168.1.4 remote 192.168.1.1 erspan_ver 2' )
152 remove_link ( 'erspan99' )
153 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
157 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable ():
159 rc
= call_quiet ( 'ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7' )
160 call_quiet ( 'ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7' )
161 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
165 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable ():
167 rc
= call_quiet ( 'ip rule add not from 192.168.100.19 ipproto tcp table 7' )
168 call_quiet ( 'ip rule del not from 192.168.100.19 ipproto tcp table 7' )
169 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
173 def expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable ():
176 if call_quiet ( 'ip rule add from 192.168.100.19 table 7 uidrange 200-300' ) == 0 :
177 ret
= run ( 'ip rule list from 192.168.100.19 table 7' )
178 supported
= ret
. returncode
== 0 and 'uidrange 200-300' in ret
. stdout
179 call_quiet ( 'ip rule del from 192.168.100.19 table 7 uidrange 200-300' )
180 return func
if supported
else unittest
. expectedFailure ( func
)
184 def expectedFailureIfNexthopIsNotAvailable ():
186 rc
= call_quiet ( 'ip nexthop list' )
187 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
191 def expectedFailureIfRTA_VIAIsNotSupported ():
193 call_quiet ( 'ip link add dummy98 type dummy' )
194 call_quiet ( 'ip link set up dev dummy98' )
195 call_quiet ( 'ip route add 2001:1234:5:8fff:ff:ff:ff:fe/128 dev dummy98' )
196 rc
= call_quiet ( 'ip route add 10.10.10.10 via inet6 2001:1234:5:8fff:ff:ff:ff:fe dev dummy98' )
197 remove_link ( 'dummy98' )
198 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
202 def expectedFailureIfAlternativeNameIsNotAvailable ():
204 call_quiet ( 'ip link add dummy98 type dummy' )
206 call_quiet ( 'ip link prop add dev dummy98 altname hogehogehogehogehoge' ) == 0 and \
207 call_quiet ( 'ip link show dev hogehogehogehogehoge' ) == 0
208 remove_link ( 'dummy98' )
209 return func
if supported
else unittest
. expectedFailure ( func
)
213 def expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ():
215 def finalize ( func
, supported
):
216 call_quiet ( 'rmmod netdevsim' )
217 return func
if supported
else unittest
. expectedFailure ( func
)
219 call_quiet ( 'rmmod netdevsim' )
220 if call_quiet ( 'modprobe netdevsim' ) != 0 :
221 return finalize ( func
, False )
224 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
227 return finalize ( func
, False )
229 return finalize ( func
, os
. path
. exists ( '/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs' ))
233 # pylint: disable=C0415
234 def compare_kernel_version ( min_kernel_version
):
237 from packaging
import version
239 print ( 'Failed to import either platform or packaging module, assuming the comparison failed' )
242 # Get only the actual kernel version without any build/distro/arch stuff
243 # e.g. '5.18.5-200.fc36.x86_64' -> '5.18.5'
244 kver
= platform
. release (). split ( '-' )[ 0 ]
246 return version
. parse ( kver
) >= version
. parse ( min_kernel_version
)
249 check_output (* udevadm_cmd
, 'control' , '--reload' )
251 def copy_network_unit (* units
, copy_dropins
= True ):
253 Copy networkd unit files into the testbed.
255 Any networkd unit file type can be specified, as well as drop-in files.
257 By default, all drop-ins for a specified unit file are copied in;
258 to avoid that specify dropins=False.
260 When a drop-in file is specified, its unit file is also copied in automatically.
263 mkdir_p ( network_unit_dir
)
265 if copy_dropins
and os
. path
. exists ( os
. path
. join ( networkd_ci_temp_dir
, unit
+ '.d' )):
266 cp_r ( os
. path
. join ( networkd_ci_temp_dir
, unit
+ '.d' ), os
. path
. join ( network_unit_dir
, unit
+ '.d' ))
268 if unit
. endswith ( '.conf' ):
270 unit
= os
. path
. dirname ( dropin
). rstrip ( '.d' )
271 dropindir
= os
. path
. join ( network_unit_dir
, unit
+ '.d' )
273 cp ( os
. path
. join ( networkd_ci_temp_dir
, dropin
), dropindir
)
275 cp ( os
. path
. join ( networkd_ci_temp_dir
, unit
), network_unit_dir
)
277 if unit
. endswith ( '.link' ):
283 def remove_network_unit (* units
):
285 Remove previously copied unit files from the testbed.
287 Drop-ins will be removed automatically.
291 rm_f ( os
. path
. join ( network_unit_dir
, unit
))
292 rm_rf ( os
. path
. join ( network_unit_dir
, unit
+ '.d' ))
294 if unit
. endswith ( '.link' ) or unit
. endswith ( '.link.d' ):
300 def clear_network_units ():
302 if os
. path
. exists ( network_unit_dir
):
303 units
= os
. listdir ( network_unit_dir
)
305 if unit
. endswith ( '.link' ) or unit
. endswith ( '.link.d' ):
308 rm_rf ( network_unit_dir
)
313 def copy_networkd_conf_dropin (* dropins
):
314 """Copy networkd.conf dropin files into the testbed."""
315 mkdir_p ( networkd_conf_dropin_dir
)
316 for dropin
in dropins
:
317 cp ( os
. path
. join ( networkd_ci_temp_dir
, dropin
), networkd_conf_dropin_dir
)
319 def remove_networkd_conf_dropin (* dropins
):
320 """Remove previously copied networkd.conf dropin files from the testbed."""
321 for dropin
in dropins
:
322 rm_f ( os
. path
. join ( networkd_conf_dropin_dir
, dropin
))
324 def clear_networkd_conf_dropins ():
325 rm_rf ( networkd_conf_dropin_dir
)
327 def copy_udev_rule (* rules
):
328 """Copy udev rules"""
329 mkdir_p ( udev_rules_dir
)
331 cp ( os
. path
. join ( networkd_ci_temp_dir
, rule
), udev_rules_dir
)
333 def remove_udev_rule (* rules
):
334 """Remove previously copied udev rules"""
336 rm_f ( os
. path
. join ( udev_rules_dir
, rule
))
338 def clear_udev_rules ():
339 rm_rf ( udev_rules_dir
)
341 def save_active_units ():
342 for u
in [ 'systemd-networkd.socket' , 'systemd-networkd.service' ,
343 'systemd-resolved.service' , 'systemd-timesyncd.service' ,
344 'firewalld.service' ]:
345 if call ( f
'systemctl is-active --quiet {u} ' ) == 0 :
346 call ( f
'systemctl stop {u} ' )
347 active_units
. append ( u
)
349 def restore_active_units ():
350 if 'systemd-networkd.socket' in active_units
:
351 call ( 'systemctl stop systemd-networkd.socket systemd-networkd.service' )
352 for u
in active_units
:
353 call ( f
'systemctl restart {u} ' )
355 def create_unit_dropin ( unit
, contents
):
356 mkdir_p ( f
'/run/systemd/system/ {unit} .d' )
357 with
open ( f
'/run/systemd/system/ {unit} .d/00-override.conf' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
358 f
. write ( ' \n ' . join ( contents
))
360 def create_service_dropin ( service
, command
, additional_settings
= None ):
364 f
'ExecStart=!! {valgrind_cmd}{command} ' ,
367 drop_in
+= [ 'Environment=SYSTEMD_LOG_LEVEL=debug' ]
369 drop_in
+= [ f
'Environment=ASAN_OPTIONS=" {asan_options} "' ]
371 drop_in
+= [ f
'Environment=LSAN_OPTIONS=" {lsan_options} "' ]
373 drop_in
+= [ f
'Environment=UBSAN_OPTIONS=" {ubsan_options} "' ]
374 if asan_options
or lsan_options
or ubsan_options
:
375 drop_in
+= [ 'SystemCallFilter=' ]
376 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
377 drop_in
+= [ 'MemoryDenyWriteExecute=no' ]
380 'Environment=SYSTEMD_MEMPOOL=0' ,
388 if additional_settings
:
389 drop_in
+= additional_settings
391 create_unit_dropin ( f
' {service} .service' , drop_in
)
393 def link_exists ( link
):
394 return call_quiet ( f
'ip link show {link} ' ) == 0
396 def link_resolve ( link
):
397 return check_output ( f
'ip link show {link} ' ). split ( ':' )[ 1 ]. strip ()
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 # pylint: disable=global-statement
510 global saved_timezone
511 r
= run (* timedatectl_cmd
, 'show' , '--value' , '--property' , 'Timezone' , env
= env
)
512 if r
. returncode
== 0 :
513 saved_timezone
= r
. stdout
. rstrip ()
514 print ( f
'### Saved timezone: {saved_timezone} ' )
516 def restore_timezone ():
518 call (* timedatectl_cmd
, 'set-timezone' , f
' {saved_timezone} ' , env
= env
)
520 def read_link_attr (* args
):
521 with
open ( os
. path
. join ( '/sys/class/net' , * args
), encoding
= 'utf-8' ) as f
:
522 return f
. readline (). strip ()
524 def read_link_state_file ( link
):
525 ifindex
= read_link_attr ( link
, 'ifindex' )
526 path
= os
. path
. join ( '/run/systemd/netif/links' , ifindex
)
527 with
open ( path
, encoding
= 'utf-8' ) as f
:
530 def read_ip_sysctl_attr ( link
, attribute
, ipv
):
531 with
open ( os
. path
. join ( '/proc/sys/net' , ipv
, 'conf' , link
, attribute
), encoding
= 'utf-8' ) as f
:
532 return f
. readline (). strip ()
534 def read_ipv6_sysctl_attr ( link
, attribute
):
535 return read_ip_sysctl_attr ( link
, attribute
, 'ipv6' )
537 def read_ipv4_sysctl_attr ( link
, attribute
):
538 return read_ip_sysctl_attr ( link
, attribute
, 'ipv4' )
540 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' ):
543 f
'--log-facility= {dnsmasq_log_file} ' ,
544 '--log-queries=extra' ,
546 f
'--pid-file= {dnsmasq_pid_file} ' ,
547 '--conf-file=/dev/null' ,
549 f
'--interface= {interface} ' ,
550 f
'--dhcp-leasefile= {dnsmasq_lease_file} ' ,
552 f
'--dhcp-range= {ipv6_range} , {lease_time} ' ,
553 f
'--dhcp-range= {ipv4_range} , {lease_time} ' ,
554 '--dhcp-option=option:mtu,1492' ,
555 f
'--dhcp-option=option:router, {ipv4_router} ' ,
558 ) + additional_options
559 check_output (* command
)
561 def stop_by_pid_file ( pid_file
):
562 if not os
. path
. exists ( pid_file
):
564 with
open ( pid_file
, 'r' , encoding
= 'utf-8' ) as f
:
565 pid
= f
. read (). rstrip ( ' \t\r\n \0' )
566 os
. kill ( int ( pid
), signal
. SIGTERM
)
570 print ( f
"PID {pid} is still alive, waiting..." )
573 if e
. errno
== errno
. ESRCH
:
575 print ( f
"Unexpected exception when waiting for {pid} to die: {e.errno}" )
579 stop_by_pid_file ( dnsmasq_pid_file
)
580 rm_f ( dnsmasq_lease_file
)
581 rm_f ( dnsmasq_log_file
)
583 def read_dnsmasq_log_file ():
584 with
open ( dnsmasq_log_file
, encoding
= 'utf-8' ) as f
:
587 def start_isc_dhcpd ( conf_file
, ipv
, interface
= 'veth-peer' ):
588 conf_file_path
= os
. path
. join ( networkd_ci_temp_dir
, conf_file
)
589 isc_dhcpd_command
= f
'dhcpd {ipv} -cf {conf_file_path} -lf {isc_dhcpd_lease_file} -pf {isc_dhcpd_pid_file} {interface} '
590 touch ( isc_dhcpd_lease_file
)
591 check_output ( isc_dhcpd_command
)
593 def stop_isc_dhcpd ():
594 stop_by_pid_file ( isc_dhcpd_pid_file
)
595 rm_f ( isc_dhcpd_lease_file
)
597 def networkd_invocation_id ():
598 return check_output ( 'systemctl show --value -p InvocationID systemd-networkd.service' )
600 def read_networkd_log ( invocation_id
= None ):
601 if not invocation_id
:
602 invocation_id
= networkd_invocation_id ()
603 return check_output ( 'journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
)
605 def stop_networkd ( show_logs
= True ):
607 invocation_id
= networkd_invocation_id ()
608 check_output ( 'systemctl stop systemd-networkd.socket' )
609 check_output ( 'systemctl stop systemd-networkd.service' )
611 print ( read_networkd_log ( invocation_id
))
613 def start_networkd ():
614 check_output ( 'systemctl start systemd-networkd' )
616 def restart_networkd ( show_logs
= True ):
618 invocation_id
= networkd_invocation_id ()
619 check_output ( 'systemctl restart systemd-networkd.service' )
621 print ( read_networkd_log ( invocation_id
))
624 return int ( check_output ( 'systemctl show --value -p MainPID systemd-networkd.service' ))
626 def networkctl_reconfigure (* links
):
627 check_output (* networkctl_cmd
, 'reconfigure' , * links
, env
= env
)
629 def networkctl_reload ( sleep_time
= 1 ):
630 check_output (* networkctl_cmd
, 'reload' , env
= env
)
631 # 'networkctl reload' asynchronously reconfigure links.
632 # Hence, we need to wait for a short time for link to be in configuring state.
634 time
. sleep ( sleep_time
)
639 def tear_down_common ():
640 # 1. stop DHCP servers
645 call_quiet ( 'rmmod netdevsim' )
646 call_quiet ( 'rmmod sch_teql' )
648 # 3. remove network namespace
649 call_quiet ( 'ip netns del ns99' )
659 clear_network_units ()
660 clear_networkd_conf_dropins ()
665 flush_routing_policy_rules ()
669 rm_rf ( networkd_ci_temp_dir
)
670 cp_r ( os
. path
. join ( os
. path
. dirname ( os
. path
. abspath ( __file__
)), 'conf' ), networkd_ci_temp_dir
)
672 clear_network_units ()
673 clear_networkd_conf_dropins ()
676 copy_udev_rule ( '00-debug-net.rules' )
680 save_existing_links ()
682 save_routing_policy_rules ()
685 create_service_dropin ( 'systemd-networkd' , networkd_bin
,
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} ' ,
702 'systemd-networkd.socket' ,
705 'StartLimitIntervalSec=0' ,
709 check_output ( 'systemctl daemon-reload' )
710 print ( check_output ( 'systemctl cat systemd-networkd.service' ))
711 print ( check_output ( 'systemctl cat systemd-resolved.service' ))
712 print ( check_output ( 'systemctl cat systemd-timesyncd.service' ))
713 print ( check_output ( 'systemctl cat systemd-udevd.service' ))
714 check_output ( 'systemctl restart systemd-resolved.service' )
715 check_output ( 'systemctl restart systemd-timesyncd.service' )
716 check_output ( 'systemctl restart systemd-udevd.service' )
718 def tearDownModule ():
719 rm_rf ( networkd_ci_temp_dir
)
721 clear_network_units ()
722 clear_networkd_conf_dropins ()
726 rm_rf ( '/run/systemd/system/systemd-networkd.service.d' )
727 rm_rf ( '/run/systemd/system/systemd-networkd.socket.d' )
728 rm_rf ( '/run/systemd/system/systemd-resolved.service.d' )
729 rm_rf ( '/run/systemd/system/systemd-timesyncd.service.d' )
730 rm_rf ( '/run/systemd/system/systemd-udevd.service.d' )
731 check_output ( 'systemctl daemon-reload' )
732 check_output ( 'systemctl restart systemd-udevd.service' )
733 restore_active_units ()
736 # pylint: disable=no-member
738 def check_link_exists ( self
, link
, expected
= True ):
740 self
. assertTrue ( link_exists ( link
))
742 self
. assertFalse ( link_exists ( link
))
744 def check_link_attr ( self
, * args
):
745 self
. assertEqual ( read_link_attr (* args
[:- 1 ]), args
[- 1 ])
747 def check_bridge_port_attr ( self
, master
, port
, attribute
, expected
, allow_enoent
= False ):
748 path
= os
. path
. join ( '/sys/devices/virtual/net' , master
, 'lower_' + port
, 'brport' , attribute
)
749 if allow_enoent
and not os
. path
. exists ( path
):
751 with
open ( path
, encoding
= 'utf-8' ) as f
:
752 self
. assertEqual ( f
. readline (). strip (), expected
)
754 def check_ipv4_sysctl_attr ( self
, link
, attribute
, expected
):
755 self
. assertEqual ( read_ipv4_sysctl_attr ( link
, attribute
), expected
)
757 def check_ipv6_sysctl_attr ( self
, link
, attribute
, expected
):
758 self
. assertEqual ( read_ipv6_sysctl_attr ( link
, attribute
), expected
)
760 def wait_links ( self
, * links
, timeout
= 20 , fail_assert
= True ):
761 def links_exist (* links
):
763 if not link_exists ( link
):
767 for iteration
in range ( timeout
+ 1 ):
771 if links_exist (* links
):
774 self
. fail ( 'Timed out waiting for all links to be created: ' + ', ' . join ( list ( links
)))
777 def wait_activated ( self
, link
, state
= 'down' , timeout
= 20 , fail_assert
= True ):
778 # wait for the interface is activated.
779 invocation_id
= check_output ( 'systemctl show systemd-networkd -p InvocationID --value' )
780 needle
= f
' {link} : Bringing link {state} '
782 for iteration
in range ( timeout
+ 1 ):
785 if not link_exists ( link
):
787 output
= check_output ( 'journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
)
788 if needle
in output
and flag
in check_output ( f
'ip link show {link} ' ):
791 self
. fail ( f
'Timed out waiting for {link} activated.' )
794 def wait_operstate ( self
, link
, operstate
= 'degraded' , setup_state
= 'configured' , setup_timeout
= 5 , fail_assert
= True ):
795 """Wait for the link to reach the specified operstate and/or setup state.
797 Specify None or '' for either operstate or setup_state to ignore that state.
798 This will recheck until the state conditions are met or the timeout expires.
800 If the link successfully matches the requested state, this returns True.
801 If this times out waiting for the link to match, the behavior depends on the
802 'fail_assert' parameter; if True, this causes a test assertion failure,
803 otherwise this returns False. The default is to cause assertion failure.
805 Note that this function matches on *exactly* the given operstate and setup_state.
806 To wait for a link to reach *or exceed* a given operstate, use wait_online().
813 for secs
in range ( setup_timeout
+ 1 ):
816 if not link_exists ( link
):
818 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , link
, env
= env
)
819 if re
. search ( rf
'(?m)^\s*State:\s+ {operstate} \s+\( {setup_state} \)\s*$' , output
):
823 self
. fail ( f
'Timed out waiting for {link} to reach state {operstate} / {setup_state} ' )
826 def wait_online ( self
, links_with_operstate
, timeout
= '20s' , bool_any
= False , ipv4
= False , ipv6
= False , setup_state
= 'configured' , setup_timeout
= 5 ):
827 """Wait for the links to reach the specified operstate and/or setup state.
829 This is similar to wait_operstate() but can be used for multiple links,
830 and it also calls systemd-networkd-wait-online to wait for the given operstate.
831 The operstate should be specified in the link name, like 'eth0:degraded'.
832 If just a link name is provided, wait-online's default operstate to wait for is degraded.
834 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
835 'setup_timeout' controls the per-link timeout waiting for the setup_state.
837 Set 'bool_any' to True to wait for any (instead of all) of the given links.
838 If this is set, no setup_state checks are done.
840 Set 'ipv4' or 'ipv6' to True to wait for IPv4 address or IPv6 address, respectively, of each of the given links.
841 This is applied only for the operational state 'degraded' or above.
843 Note that this function waits for the links to reach *or exceed* the given operstate.
844 However, the setup_state, if specified, must be matched *exactly*.
846 This returns if the links reached the requested operstate/setup_state; otherwise it
847 raises CalledProcessError or fails test assertion.
849 args
= wait_online_cmd
+ [ f
'--timeout= {timeout} ' ] + [ f
'--interface= {link} ' for link
in links_with_operstate
] + [ f
'--ignore= {link} ' for link
in protected_links
]
857 check_output (* args
, env
= wait_online_env
)
858 except subprocess
. CalledProcessError
:
859 # show detailed status on failure
860 for link
in links_with_operstate
:
861 name
= link
. split ( ':' )[ 0 ]
862 if link_exists ( name
):
863 call (* networkctl_cmd
, '-n' , '0' , 'status' , name
, env
= env
)
865 if not bool_any
and setup_state
:
866 for link
in links_with_operstate
:
867 self
. wait_operstate ( link
. split ( ':' )[ 0 ], None , setup_state
, setup_timeout
)
869 def wait_address ( self
, link
, address_regex
, scope
= 'global' , ipv
= '' , timeout_sec
= 100 ):
870 for i
in range ( timeout_sec
):
873 output
= check_output ( f
'ip {ipv} address show dev {link} scope {scope} ' )
874 if re
. search ( address_regex
, output
) and 'tentative' not in output
:
877 self
. assertRegex ( output
, address_regex
)
879 def wait_address_dropped ( self
, link
, address_regex
, scope
= 'global' , ipv
= '' , timeout_sec
= 100 ):
880 for i
in range ( timeout_sec
):
883 output
= check_output ( f
'ip {ipv} address show dev {link} scope {scope} ' )
884 if not re
. search ( address_regex
, output
):
887 self
. assertNotRegex ( output
, address_regex
)
889 def wait_route ( self
, link
, route_regex
, table
= 'main' , ipv
= '' , timeout_sec
= 100 ):
890 for i
in range ( timeout_sec
):
893 output
= check_output ( f
'ip {ipv} route show dev {link} table {table} ' )
894 if re
. search ( route_regex
, output
):
897 self
. assertRegex ( output
, route_regex
)
899 def check_netlabel ( self
, interface
, address
, label
= 'system_u:object_r:root_t:s0' ):
900 if not shutil
. which ( 'selinuxenabled' ):
901 print ( '## Checking NetLabel skipped: selinuxenabled command not found.' )
902 elif call_quiet ( 'selinuxenabled' ) != 0 :
903 print ( '## Checking NetLabel skipped: SELinux disabled.' )
904 elif not shutil
. which ( 'netlabelctl' ): # not packaged by all distros
905 print ( '## Checking NetLabel skipped: netlabelctl command not found.' )
907 output
= check_output ( 'netlabelctl unlbl list' )
909 self
. assertRegex ( output
, f
'interface: {interface} ,address: {address} ,label:" {label} "' )
911 class NetworkctlTests ( unittest
. TestCase
, Utilities
):
919 @expectedFailureIfAlternativeNameIsNotAvailable ()
920 def test_altname ( self
):
921 copy_network_unit ( '26-netdev-link-local-addressing-yes.network' , '12-dummy.netdev' , '12-dummy.link' )
923 self
. wait_online ([ 'dummy98:degraded' ])
925 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
926 self
. assertRegex ( output
, 'hogehogehogehogehogehoge' )
928 @expectedFailureIfAlternativeNameIsNotAvailable ()
929 def test_rename_to_altname ( self
):
930 copy_network_unit ( '26-netdev-link-local-addressing-yes.network' ,
931 '12-dummy.netdev' , '12-dummy-rename-to-altname.link' )
933 self
. wait_online ([ 'dummyalt:degraded' ])
935 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummyalt' , env
= env
)
936 self
. assertIn ( 'hogehogehogehogehogehoge' , output
)
937 self
. assertNotIn ( 'dummy98' , output
)
939 def test_reconfigure ( self
):
940 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' )
942 self
. wait_online ([ 'dummy98:routable' ])
944 output
= check_output ( 'ip -4 address show dev dummy98' )
946 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
947 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
948 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
950 check_output ( 'ip address del 10.1.2.3/16 dev dummy98' )
951 check_output ( 'ip address del 10.1.2.4/16 dev dummy98' )
952 check_output ( 'ip address del 10.2.2.4/16 dev dummy98' )
954 networkctl_reconfigure ( 'dummy98' )
955 self
. wait_online ([ 'dummy98:routable' ])
957 output
= check_output ( 'ip -4 address show dev dummy98' )
959 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
960 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
961 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
963 remove_network_unit ( '25-address-static.network' )
966 self
. wait_operstate ( 'dummy98' , 'degraded' , setup_state
= 'unmanaged' )
968 output
= check_output ( 'ip -4 address show dev dummy98' )
970 self
. assertNotIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
971 self
. assertNotIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
972 self
. assertNotIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
974 copy_network_unit ( '25-address-static.network' )
976 self
. wait_online ([ 'dummy98:routable' ])
978 output
= check_output ( 'ip -4 address show dev dummy98' )
980 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
981 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
982 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
984 def test_reload ( self
):
987 copy_network_unit ( '11-dummy.netdev' )
989 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'unmanaged' )
991 copy_network_unit ( '11-dummy.network' )
993 self
. wait_online ([ 'test1:degraded' ])
995 remove_network_unit ( '11-dummy.network' )
997 self
. wait_operstate ( 'test1' , 'degraded' , setup_state
= 'unmanaged' )
999 remove_network_unit ( '11-dummy.netdev' )
1001 self
. wait_operstate ( 'test1' , 'degraded' , setup_state
= 'unmanaged' )
1003 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1005 self
. wait_operstate ( 'test1' , 'degraded' )
1007 def test_glob ( self
):
1008 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1011 self
. wait_online ([ 'test1:degraded' ])
1013 output
= check_output (* networkctl_cmd
, 'list' , env
= env
)
1014 self
. assertRegex ( output
, '1 lo ' )
1015 self
. assertRegex ( output
, 'test1' )
1017 output
= check_output (* networkctl_cmd
, 'list' , 'test1' , env
= env
)
1018 self
. assertNotRegex ( output
, '1 lo ' )
1019 self
. assertRegex ( output
, 'test1' )
1021 output
= check_output (* networkctl_cmd
, 'list' , 'te*' , env
= env
)
1022 self
. assertNotRegex ( output
, '1 lo ' )
1023 self
. assertRegex ( output
, 'test1' )
1025 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'te*' , env
= env
)
1026 self
. assertNotRegex ( output
, '1: lo ' )
1027 self
. assertRegex ( output
, 'test1' )
1029 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'tes[a-z][0-9]' , env
= env
)
1030 self
. assertNotRegex ( output
, '1: lo ' )
1031 self
. assertRegex ( output
, 'test1' )
1034 copy_network_unit ( '11-dummy-mtu.netdev' , '11-dummy.network' )
1037 self
. wait_online ([ 'test1:degraded' ])
1039 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
1040 self
. assertRegex ( output
, 'MTU: 1600' )
1042 def test_type ( self
):
1043 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1045 self
. wait_online ([ 'test1:degraded' ])
1047 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
1049 self
. assertRegex ( output
, 'Type: ether' )
1051 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'lo' , env
= env
)
1053 self
. assertRegex ( output
, 'Type: loopback' )
1055 def test_udev_link_file ( self
):
1056 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' , '25-default.link' )
1058 self
. wait_online ([ 'test1:degraded' ])
1060 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
1062 self
. assertRegex ( output
, r
'Link File: /run/systemd/network/25-default.link' )
1063 self
. assertRegex ( output
, r
'Network File: /run/systemd/network/11-dummy.network' )
1065 # This test may be run on the system that has older udevd than 70f32a260b5ebb68c19ecadf5d69b3844896ba55 (v249).
1066 # In that case, the udev DB for the loopback network interface may already have ID_NET_LINK_FILE property.
1067 # Let's reprocess the interface and drop the property.
1068 check_output (* udevadm_cmd
, 'trigger' , '--settle' , '--action=add' , '/sys/class/net/lo' )
1069 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'lo' , env
= env
)
1071 self
. assertRegex ( output
, r
'Link File: n/a' )
1072 self
. assertRegex ( output
, r
'Network File: n/a' )
1074 def test_delete_links ( self
):
1075 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' ,
1076 '25-veth.netdev' , '26-netdev-link-local-addressing-yes.network' )
1079 self
. wait_online ([ 'test1:degraded' , 'veth99:degraded' , 'veth-peer:degraded' ])
1081 check_output (* networkctl_cmd
, 'delete' , 'test1' , 'veth99' , env
= env
)
1082 self
. check_link_exists ( 'test1' , expected
= False )
1083 self
. check_link_exists ( 'veth99' , expected
= False )
1084 self
. check_link_exists ( 'veth-peer' , expected
= False )
1086 class NetworkdMatchTests ( unittest
. TestCase
, Utilities
):
1094 @expectedFailureIfAlternativeNameIsNotAvailable ()
1095 def test_match ( self
):
1096 copy_network_unit ( '12-dummy-mac.netdev' ,
1097 '12-dummy-match-mac-01.network' ,
1098 '12-dummy-match-mac-02.network' ,
1099 '12-dummy-match-renamed.network' ,
1100 '12-dummy-match-altname.network' ,
1101 '12-dummy-altname.link' )
1104 self
. wait_online ([ 'dummy98:routable' ])
1105 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
1106 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-mac-01.network' , output
)
1107 output
= check_output ( 'ip -4 address show dev dummy98' )
1108 self
. assertIn ( '10.0.0.1/16' , output
)
1110 check_output ( 'ip link set dev dummy98 down' )
1111 check_output ( 'ip link set dev dummy98 address 12:34:56:78:9a:02' )
1113 self
. wait_address ( 'dummy98' , '10.0.0.2/16' , ipv
= '-4' , timeout_sec
= 10 )
1114 self
. wait_online ([ 'dummy98:routable' ])
1115 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
1116 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-mac-02.network' , output
)
1118 check_output ( 'ip link set dev dummy98 down' )
1119 check_output ( 'ip link set dev dummy98 name dummy98-1' )
1121 self
. wait_address ( 'dummy98-1' , '10.0.1.2/16' , ipv
= '-4' , timeout_sec
= 10 )
1122 self
. wait_online ([ 'dummy98-1:routable' ])
1123 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98-1' , env
= env
)
1124 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-renamed.network' , output
)
1126 check_output ( 'ip link set dev dummy98-1 down' )
1127 check_output ( 'ip link set dev dummy98-1 name dummy98-2' )
1128 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '/sys/class/net/dummy98-2' )
1130 self
. wait_address ( 'dummy98-2' , '10.0.2.2/16' , ipv
= '-4' , timeout_sec
= 10 )
1131 self
. wait_online ([ 'dummy98-2:routable' ])
1132 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98-2' , env
= env
)
1133 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-altname.network' , output
)
1135 def test_match_udev_property ( self
):
1136 copy_network_unit ( '12-dummy.netdev' , '13-not-match-udev-property.network' , '14-match-udev-property.network' )
1138 self
. wait_online ([ 'dummy98:routable' ])
1140 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
1142 self
. assertRegex ( output
, 'Network File: /run/systemd/network/14-match-udev-property' )
1144 class WaitOnlineTests ( unittest
. TestCase
, Utilities
):
1152 def test_wait_online_any ( self
):
1153 copy_network_unit ( '25-bridge.netdev' , '25-bridge.network' , '11-dummy.netdev' , '11-dummy.network' )
1156 self
. wait_online ([ 'bridge99' , 'test1:degraded' ], bool_any
= True )
1158 self
. wait_operstate ( 'bridge99' , '(off|no-carrier)' , setup_state
= 'configuring' )
1159 self
. wait_operstate ( 'test1' , 'degraded' )
1161 class NetworkdNetDevTests ( unittest
. TestCase
, Utilities
):
1169 def test_dropin_and_name_conflict ( self
):
1170 copy_network_unit ( '10-dropin-test.netdev' , '15-name-conflict-test.netdev' )
1173 self
. wait_online ([ 'dropin-test:off' ], setup_state
= 'unmanaged' )
1175 output
= check_output ( 'ip link show dropin-test' )
1177 self
. assertRegex ( output
, '00:50:56:c0:00:28' )
1179 @expectedFailureIfModuleIsNotAvailable ( 'bareudp' )
1180 def test_bareudp ( self
):
1181 copy_network_unit ( '25-bareudp.netdev' , '26-netdev-link-local-addressing-yes.network' )
1184 self
. wait_online ([ 'bareudp99:degraded' ])
1186 output
= check_output ( 'ip -d link show bareudp99' )
1188 self
. assertRegex ( output
, 'dstport 1000 ' )
1189 self
. assertRegex ( output
, 'ethertype ip ' )
1191 @expectedFailureIfModuleIsNotAvailable ( 'batman-adv' )
1192 def test_batadv ( self
):
1193 copy_network_unit ( '25-batadv.netdev' , '26-netdev-link-local-addressing-yes.network' )
1196 self
. wait_online ([ 'batadv99:degraded' ])
1198 output
= check_output ( 'ip -d link show batadv99' )
1200 self
. assertRegex ( output
, 'batadv' )
1202 def test_bridge ( self
):
1203 copy_network_unit ( '25-bridge.netdev' , '25-bridge-configure-without-carrier.network' )
1206 self
. wait_online ([ 'bridge99:no-carrier' ])
1208 tick
= os
. sysconf ( 'SC_CLK_TCK' )
1209 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'hello_time' )) / tick
))
1210 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'max_age' )) / tick
))
1211 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'forward_delay' )) / tick
))
1212 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'ageing_time' )) / tick
))
1213 self
. assertEqual ( 9 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'priority' )))
1214 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_querier' )))
1215 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_snooping' )))
1216 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'stp_state' )))
1217 self
. assertEqual ( 3 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_igmp_version' )))
1219 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bridge99' , env
= env
)
1221 self
. assertRegex ( output
, 'Priority: 9' )
1222 self
. assertRegex ( output
, 'STP: yes' )
1223 self
. assertRegex ( output
, 'Multicast IGMP Version: 3' )
1225 output
= check_output ( 'ip -d link show bridge99' )
1227 self
. assertIn ( 'vlan_filtering 1 ' , output
)
1228 self
. assertIn ( 'vlan_protocol 802.1ad ' , output
)
1229 self
. assertIn ( 'vlan_default_pvid 9 ' , output
)
1231 def test_bond ( self
):
1232 copy_network_unit ( '25-bond.netdev' , '25-bond-balanced-tlb.netdev' )
1235 self
. wait_online ([ 'bond99:off' , 'bond98:off' ], setup_state
= 'unmanaged' )
1237 self
. check_link_attr ( 'bond99' , 'bonding' , 'mode' , '802.3ad 4' )
1238 self
. check_link_attr ( 'bond99' , 'bonding' , 'xmit_hash_policy' , 'layer3+4 1' )
1239 self
. check_link_attr ( 'bond99' , 'bonding' , 'miimon' , '1000' )
1240 self
. check_link_attr ( 'bond99' , 'bonding' , 'lacp_rate' , 'fast 1' )
1241 self
. check_link_attr ( 'bond99' , 'bonding' , 'updelay' , '2000' )
1242 self
. check_link_attr ( 'bond99' , 'bonding' , 'downdelay' , '2000' )
1243 self
. check_link_attr ( 'bond99' , 'bonding' , 'resend_igmp' , '4' )
1244 self
. check_link_attr ( 'bond99' , 'bonding' , 'min_links' , '1' )
1245 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_actor_sys_prio' , '1218' )
1246 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_user_port_key' , '811' )
1247 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_actor_system' , '00:11:22:33:44:55' )
1249 self
. check_link_attr ( 'bond98' , 'bonding' , 'mode' , 'balance-tlb 5' )
1250 self
. check_link_attr ( 'bond98' , 'bonding' , 'tlb_dynamic_lb' , '1' )
1252 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bond99' , env
= env
)
1254 self
. assertIn ( 'Mode: 802.3ad' , output
)
1255 self
. assertIn ( 'Miimon: 1s' , output
)
1256 self
. assertIn ( 'Updelay: 2s' , output
)
1257 self
. assertIn ( 'Downdelay: 2s' , output
)
1259 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bond98' , env
= env
)
1261 self
. assertIn ( 'Mode: balance-tlb' , output
)
1263 def test_vlan ( self
):
1264 copy_network_unit ( '21-vlan.netdev' , '11-dummy.netdev' ,
1265 '21-vlan.network' , '21-vlan-test1.network' )
1268 self
. wait_online ([ 'test1:degraded' , 'vlan99:routable' ])
1270 output
= check_output ( 'ip -d link show test1' )
1272 self
. assertRegex ( output
, ' mtu 2000 ' )
1274 output
= check_output ( 'ip -d link show vlan99' )
1276 self
. assertIn ( ' mtu 2000 ' , output
)
1277 self
. assertIn ( 'REORDER_HDR' , output
)
1278 self
. assertIn ( 'LOOSE_BINDING' , output
)
1279 self
. assertIn ( 'GVRP' , output
)
1280 self
. assertIn ( 'MVRP' , output
)
1281 self
. assertIn ( ' id 99 ' , output
)
1282 self
. assertIn ( 'ingress-qos-map { 4:100 7:13 }' , output
)
1283 self
. assertIn ( 'egress-qos-map { 0:1 1:3 6:6 7:7 10:3 }' , output
)
1285 output
= check_output ( 'ip -4 address show dev test1' )
1287 self
. assertRegex ( output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1' )
1288 self
. assertRegex ( output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1' )
1290 output
= check_output ( 'ip -4 address show dev vlan99' )
1292 self
. assertRegex ( output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99' )
1294 def test_vlan_on_bond ( self
):
1295 # For issue #24377 (https://github.com/systemd/systemd/issues/24377),
1296 # which is fixed by b05e52000b4eee764b383cc3031da0a3739e996e (PR#24020).
1298 copy_network_unit ( '21-bond-802.3ad.netdev' , '21-bond-802.3ad.network' ,
1299 '21-vlan-on-bond.netdev' , '21-vlan-on-bond.network' )
1301 self
. wait_online ([ 'bond99:off' ])
1302 self
. wait_operstate ( 'vlan99' , operstate
= 'off' , setup_state
= 'configuring' , setup_timeout
= 10 )
1304 # The commit b05e52000b4eee764b383cc3031da0a3739e996e adds ", ignoring". To make it easily confirmed
1305 # that the issue is fixed by the commit, let's allow to match both string.
1306 log_re
= re
. compile ( 'vlan99: Could not bring up interface(, ignoring|): Network is down$' , re
. MULTILINE
)
1310 if log_re
. search ( read_networkd_log ()):
1315 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '21-dummy-bond-slave.network' )
1317 self
. wait_online ([ 'test1:enslaved' , 'dummy98:enslaved' , 'bond99:carrier' , 'vlan99:routable' ])
1319 def test_macvtap ( self
):
1321 for mode
in [ 'private' , 'vepa' , 'bridge' , 'passthru' ]:
1327 print ( f
'### test_macvtap(mode= {mode} )' )
1328 with self
. subTest ( mode
= mode
):
1329 copy_network_unit ( '21-macvtap.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1330 '11-dummy.netdev' , '25-macvtap.network' )
1331 with
open ( os
. path
. join ( network_unit_dir
, '21-macvtap.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1332 f
. write ( '[MACVTAP] \n Mode=' + mode
)
1335 self
. wait_online ([ 'macvtap99:degraded' ,
1336 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1338 output
= check_output ( 'ip -d link show macvtap99' )
1340 self
. assertRegex ( output
, 'macvtap mode ' + mode
+ ' ' )
1342 def test_macvlan ( self
):
1344 for mode
in [ 'private' , 'vepa' , 'bridge' , 'passthru' ]:
1350 print ( f
'### test_macvlan(mode= {mode} )' )
1351 with self
. subTest ( mode
= mode
):
1352 copy_network_unit ( '21-macvlan.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1353 '11-dummy.netdev' , '25-macvlan.network' )
1354 with
open ( os
. path
. join ( network_unit_dir
, '21-macvlan.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1355 f
. write ( '[MACVLAN] \n Mode=' + mode
)
1358 self
. wait_online ([ 'macvlan99:degraded' ,
1359 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1361 output
= check_output ( 'ip -d link show test1' )
1363 self
. assertRegex ( output
, ' mtu 2000 ' )
1365 output
= check_output ( 'ip -d link show macvlan99' )
1367 self
. assertRegex ( output
, ' mtu 2000 ' )
1368 self
. assertRegex ( output
, 'macvlan mode ' + mode
+ ' ' )
1370 remove_link ( 'test1' )
1373 check_output ( "ip link add test1 type dummy" )
1374 self
. wait_online ([ 'macvlan99:degraded' ,
1375 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' ])
1377 output
= check_output ( 'ip -d link show test1' )
1379 self
. assertRegex ( output
, ' mtu 2000 ' )
1381 output
= check_output ( 'ip -d link show macvlan99' )
1383 self
. assertRegex ( output
, ' mtu 2000 ' )
1384 self
. assertRegex ( output
, 'macvlan mode ' + mode
+ ' ' )
1386 @expectedFailureIfModuleIsNotAvailable ( 'ipvlan' )
1387 def test_ipvlan ( self
):
1389 for mode
, flag
in [[ 'L2' , 'private' ], [ 'L3' , 'vepa' ], [ 'L3S' , 'bridge' ]]:
1395 print ( f
'### test_ipvlan(mode= {mode} , flag= {flag} )' )
1396 with self
. subTest ( mode
= mode
, flag
= flag
):
1397 copy_network_unit ( '25-ipvlan.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1398 '11-dummy.netdev' , '25-ipvlan.network' )
1399 with
open ( os
. path
. join ( network_unit_dir
, '25-ipvlan.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1400 f
. write ( '[IPVLAN] \n Mode=' + mode
+ ' \n Flags=' + flag
)
1403 self
. wait_online ([ 'ipvlan99:degraded' , 'test1:degraded' ])
1405 output
= check_output ( 'ip -d link show ipvlan99' )
1407 self
. assertRegex ( output
, 'ipvlan *mode ' + mode
. lower () + ' ' + flag
)
1409 @expectedFailureIfModuleIsNotAvailable ( 'ipvtap' )
1410 def test_ipvtap ( self
):
1412 for mode
, flag
in [[ 'L2' , 'private' ], [ 'L3' , 'vepa' ], [ 'L3S' , 'bridge' ]]:
1418 print ( f
'### test_ipvtap(mode= {mode} , flag= {flag} )' )
1419 with self
. subTest ( mode
= mode
, flag
= flag
):
1420 copy_network_unit ( '25-ipvtap.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1421 '11-dummy.netdev' , '25-ipvtap.network' )
1422 with
open ( os
. path
. join ( network_unit_dir
, '25-ipvtap.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1423 f
. write ( '[IPVTAP] \n Mode=' + mode
+ ' \n Flags=' + flag
)
1426 self
. wait_online ([ 'ipvtap99:degraded' , 'test1:degraded' ])
1428 output
= check_output ( 'ip -d link show ipvtap99' )
1430 self
. assertRegex ( output
, 'ipvtap *mode ' + mode
. lower () + ' ' + flag
)
1432 def test_veth ( self
):
1433 copy_network_unit ( '25-veth.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1434 '25-veth-mtu.netdev' )
1437 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:degraded' , 'veth-mtu:degraded' , 'veth-mtu-peer:degraded' ])
1439 output
= check_output ( 'ip -d link show veth99' )
1441 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bc' )
1442 output
= check_output ( 'ip -d link show veth-peer' )
1444 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bd' )
1446 output
= check_output ( 'ip -d link show veth-mtu' )
1448 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:be' )
1449 self
. assertRegex ( output
, 'mtu 1800' )
1450 output
= check_output ( 'ip -d link show veth-mtu-peer' )
1452 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bf' )
1453 self
. assertRegex ( output
, 'mtu 1800' )
1455 def test_tuntap ( self
):
1456 copy_network_unit ( '25-tun.netdev' , '25-tap.netdev' , '26-netdev-link-local-addressing-yes.network' )
1459 self
. wait_online ([ 'testtun99:degraded' , 'testtap99:degraded' ])
1461 pid
= networkd_pid ()
1462 name
= psutil
. Process ( pid
). name ()[: 15 ]
1464 output
= check_output ( 'ip -d tuntap show' )
1466 self
. assertRegex ( output
, fr
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1467 self
. assertRegex ( output
, fr
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1469 output
= check_output ( 'ip -d link show testtun99' )
1471 # Old ip command does not support IFF_ flags
1472 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1473 self
. assertIn ( 'UP,LOWER_UP' , output
)
1475 output
= check_output ( 'ip -d link show testtap99' )
1477 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1478 self
. assertIn ( 'UP,LOWER_UP' , output
)
1480 remove_network_unit ( '26-netdev-link-local-addressing-yes.network' )
1483 self
. wait_online ([ 'testtun99:degraded' , 'testtap99:degraded' ], setup_state
= 'unmanaged' )
1485 pid
= networkd_pid ()
1486 name
= psutil
. Process ( pid
). name ()[: 15 ]
1488 output
= check_output ( 'ip -d tuntap show' )
1490 self
. assertRegex ( output
, fr
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1491 self
. assertRegex ( output
, fr
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1493 output
= check_output ( 'ip -d link show testtun99' )
1495 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1496 self
. assertIn ( 'UP,LOWER_UP' , output
)
1498 output
= check_output ( 'ip -d link show testtap99' )
1500 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1501 self
. assertIn ( 'UP,LOWER_UP' , output
)
1503 clear_network_units ()
1505 self
. wait_online ([ 'testtun99:off' , 'testtap99:off' ], setup_state
= 'unmanaged' )
1507 output
= check_output ( 'ip -d tuntap show' )
1509 self
. assertRegex ( output
, r
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$' )
1510 self
. assertRegex ( output
, r
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$' )
1515 output
= check_output ( 'ip -d link show testtun99' )
1517 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1518 if 'NO-CARRIER' in output
:
1526 output
= check_output ( 'ip -d link show testtap99' )
1528 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1529 if 'NO-CARRIER' in output
:
1534 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
1536 copy_network_unit ( '25-vrf.netdev' , '26-netdev-link-local-addressing-yes.network' )
1539 self
. wait_online ([ 'vrf99:carrier' ])
1541 @expectedFailureIfModuleIsNotAvailable ( 'vcan' )
1542 def test_vcan ( self
):
1543 copy_network_unit ( '25-vcan.netdev' , '26-netdev-link-local-addressing-yes.network' )
1546 self
. wait_online ([ 'vcan99:carrier' ])
1548 @expectedFailureIfModuleIsNotAvailable ( 'vxcan' )
1549 def test_vxcan ( self
):
1550 copy_network_unit ( '25-vxcan.netdev' , '26-netdev-link-local-addressing-yes.network' )
1553 self
. wait_online ([ 'vxcan99:carrier' , 'vxcan-peer:carrier' ])
1555 @expectedFailureIfModuleIsNotAvailable ( 'wireguard' )
1556 def test_wireguard ( self
):
1557 copy_network_unit ( '25-wireguard.netdev' , '25-wireguard.network' ,
1558 '25-wireguard-23-peers.netdev' , '25-wireguard-23-peers.network' ,
1559 '25-wireguard-preshared-key.txt' , '25-wireguard-private-key.txt' ,
1560 '25-wireguard-no-peer.netdev' , '25-wireguard-no-peer.network' )
1562 self
. wait_online ([ 'wg99:routable' , 'wg98:routable' , 'wg97:carrier' ])
1564 output
= check_output ( 'ip -4 address show dev wg99' )
1566 self
. assertIn ( 'inet 192.168.124.1/24 scope global wg99' , output
)
1568 output
= check_output ( 'ip -4 address show dev wg99' )
1570 self
. assertIn ( 'inet 169.254.11.1/24 scope link wg99' , output
)
1572 output
= check_output ( 'ip -6 address show dev wg99' )
1574 self
. assertIn ( 'inet6 fe80::1/64 scope link' , output
)
1576 output
= check_output ( 'ip -4 address show dev wg98' )
1578 self
. assertIn ( 'inet 192.168.123.123/24 scope global wg98' , output
)
1580 output
= check_output ( 'ip -6 address show dev wg98' )
1582 self
. assertIn ( 'inet6 fd8d:4d6d:3ccb:500::1/64 scope global' , output
)
1584 output
= check_output ( 'ip -4 route show dev wg99 table 1234' )
1586 self
. assertIn ( '192.168.26.0/24 proto static metric 123' , output
)
1588 output
= check_output ( 'ip -6 route show dev wg99 table 1234' )
1590 self
. assertIn ( 'fd31:bf08:57cb::/48 proto static metric 123 pref medium' , output
)
1592 output
= check_output ( 'ip -6 route show dev wg98 table 1234' )
1594 self
. assertIn ( 'fd8d:4d6d:3ccb:500:c79:2339:edce:ece1 proto static metric 123 pref medium' , output
)
1595 self
. assertIn ( 'fd8d:4d6d:3ccb:500:1dbf:ca8a:32d3:dd81 proto static metric 123 pref medium' , output
)
1596 self
. assertIn ( 'fd8d:4d6d:3ccb:500:1e54:1415:35d0:a47c proto static metric 123 pref medium' , output
)
1597 self
. assertIn ( 'fd8d:4d6d:3ccb:500:270d:b5dd:4a3f:8909 proto static metric 123 pref medium' , output
)
1598 self
. assertIn ( 'fd8d:4d6d:3ccb:500:5660:679d:3532:94d8 proto static metric 123 pref medium' , output
)
1599 self
. assertIn ( 'fd8d:4d6d:3ccb:500:6825:573f:30f3:9472 proto static metric 123 pref medium' , output
)
1600 self
. assertIn ( 'fd8d:4d6d:3ccb:500:6f2e:6888:c6fd:dfb9 proto static metric 123 pref medium' , output
)
1601 self
. assertIn ( 'fd8d:4d6d:3ccb:500:8d4d:bab:7280:a09a proto static metric 123 pref medium' , output
)
1602 self
. assertIn ( 'fd8d:4d6d:3ccb:500:900c:d437:ec27:8822 proto static metric 123 pref medium' , output
)
1603 self
. assertIn ( 'fd8d:4d6d:3ccb:500:9742:9931:5217:18d5 proto static metric 123 pref medium' , output
)
1604 self
. assertIn ( 'fd8d:4d6d:3ccb:500:9c11:d820:2e96:9be0 proto static metric 123 pref medium' , output
)
1605 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a072:80da:de4f:add1 proto static metric 123 pref medium' , output
)
1606 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a3f3:df38:19b0:721 proto static metric 123 pref medium' , output
)
1607 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a94b:cd6a:a32d:90e6 proto static metric 123 pref medium' , output
)
1608 self
. assertIn ( 'fd8d:4d6d:3ccb:500:b39c:9cdc:755a:ead3 proto static metric 123 pref medium' , output
)
1609 self
. assertIn ( 'fd8d:4d6d:3ccb:500:b684:4f81:2e3e:132e proto static metric 123 pref medium' , output
)
1610 self
. assertIn ( 'fd8d:4d6d:3ccb:500:bad5:495d:8e9c:3427 proto static metric 123 pref medium' , output
)
1611 self
. assertIn ( 'fd8d:4d6d:3ccb:500:bfe5:c3c3:5d77:fcb proto static metric 123 pref medium' , output
)
1612 self
. assertIn ( 'fd8d:4d6d:3ccb:500:c624:6bf7:4c09:3b59 proto static metric 123 pref medium' , output
)
1613 self
. assertIn ( 'fd8d:4d6d:3ccb:500:d4f9:5dc:9296:a1a proto static metric 123 pref medium' , output
)
1614 self
. assertIn ( 'fd8d:4d6d:3ccb:500:dcdd:d33b:90c9:6088 proto static metric 123 pref medium' , output
)
1615 self
. assertIn ( 'fd8d:4d6d:3ccb:500:e2e1:ae15:103f:f376 proto static metric 123 pref medium' , output
)
1616 self
. assertIn ( 'fd8d:4d6d:3ccb:500:f349:c4f0:10c1:6b4 proto static metric 123 pref medium' , output
)
1617 self
. assertIn ( 'fd8d:4d6d:3ccb:c79:2339:edce::/96 proto static metric 123 pref medium' , output
)
1618 self
. assertIn ( 'fd8d:4d6d:3ccb:1dbf:ca8a:32d3::/96 proto static metric 123 pref medium' , output
)
1619 self
. assertIn ( 'fd8d:4d6d:3ccb:1e54:1415:35d0::/96 proto static metric 123 pref medium' , output
)
1620 self
. assertIn ( 'fd8d:4d6d:3ccb:270d:b5dd:4a3f::/96 proto static metric 123 pref medium' , output
)
1621 self
. assertIn ( 'fd8d:4d6d:3ccb:5660:679d:3532::/96 proto static metric 123 pref medium' , output
)
1622 self
. assertIn ( 'fd8d:4d6d:3ccb:6825:573f:30f3::/96 proto static metric 123 pref medium' , output
)
1623 self
. assertIn ( 'fd8d:4d6d:3ccb:6f2e:6888:c6fd::/96 proto static metric 123 pref medium' , output
)
1624 self
. assertIn ( 'fd8d:4d6d:3ccb:8d4d:bab:7280::/96 proto static metric 123 pref medium' , output
)
1625 self
. assertIn ( 'fd8d:4d6d:3ccb:900c:d437:ec27::/96 proto static metric 123 pref medium' , output
)
1626 self
. assertIn ( 'fd8d:4d6d:3ccb:9742:9931:5217::/96 proto static metric 123 pref medium' , output
)
1627 self
. assertIn ( 'fd8d:4d6d:3ccb:9c11:d820:2e96::/96 proto static metric 123 pref medium' , output
)
1628 self
. assertIn ( 'fd8d:4d6d:3ccb:a072:80da:de4f::/96 proto static metric 123 pref medium' , output
)
1629 self
. assertIn ( 'fd8d:4d6d:3ccb:a3f3:df38:19b0::/96 proto static metric 123 pref medium' , output
)
1630 self
. assertIn ( 'fd8d:4d6d:3ccb:a94b:cd6a:a32d::/96 proto static metric 123 pref medium' , output
)
1631 self
. assertIn ( 'fd8d:4d6d:3ccb:b39c:9cdc:755a::/96 proto static metric 123 pref medium' , output
)
1632 self
. assertIn ( 'fd8d:4d6d:3ccb:b684:4f81:2e3e::/96 proto static metric 123 pref medium' , output
)
1633 self
. assertIn ( 'fd8d:4d6d:3ccb:bad5:495d:8e9c::/96 proto static metric 123 pref medium' , output
)
1634 self
. assertIn ( 'fd8d:4d6d:3ccb:bfe5:c3c3:5d77::/96 proto static metric 123 pref medium' , output
)
1635 self
. assertIn ( 'fd8d:4d6d:3ccb:c624:6bf7:4c09::/96 proto static metric 123 pref medium' , output
)
1636 self
. assertIn ( 'fd8d:4d6d:3ccb:d4f9:5dc:9296::/96 proto static metric 123 pref medium' , output
)
1637 self
. assertIn ( 'fd8d:4d6d:3ccb:dcdd:d33b:90c9::/96 proto static metric 123 pref medium' , output
)
1638 self
. assertIn ( 'fd8d:4d6d:3ccb:e2e1:ae15:103f::/96 proto static metric 123 pref medium' , output
)
1639 self
. assertIn ( 'fd8d:4d6d:3ccb:f349:c4f0:10c1::/96 proto static metric 123 pref medium' , output
)
1641 if shutil
. which ( 'wg' ):
1644 output
= check_output ( 'wg show wg99 listen-port' )
1645 self
. assertEqual ( output
, '51820' )
1646 output
= check_output ( 'wg show wg99 fwmark' )
1647 self
. assertEqual ( output
, '0x4d2' )
1648 output
= check_output ( 'wg show wg99 private-key' )
1649 self
. assertEqual ( output
, 'EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=' )
1650 output
= check_output ( 'wg show wg99 allowed-ips' )
1651 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t 192.168.124.3/32' , output
)
1652 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t 192.168.124.2/32' , output
)
1653 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t fdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128' , output
)
1654 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 192.168.26.0/24 fd31:bf08:57cb::/48' , output
)
1655 output
= check_output ( 'wg show wg99 persistent-keepalive' )
1656 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t off' , output
)
1657 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t off' , output
)
1658 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t off' , output
)
1659 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 20' , output
)
1660 output
= check_output ( 'wg show wg99 endpoints' )
1661 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t (none)' , output
)
1662 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t (none)' , output
)
1663 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t (none)' , output
)
1664 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 192.168.27.3:51820' , output
)
1665 output
= check_output ( 'wg show wg99 preshared-keys' )
1666 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t 6Fsg8XN0DE6aPQgAX4r2oazEYJOGqyHUz3QRH/jCB+I=' , output
)
1667 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t it7nd33chCT/tKT2ZZWfYyp43Zs+6oif72hexnSNMqA=' , output
)
1668 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=' , output
)
1669 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=' , output
)
1671 output
= check_output ( 'wg show wg98 private-key' )
1672 self
. assertEqual ( output
, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr+WHtZLZ90FU=' )
1674 output
= check_output ( 'wg show wg97 listen-port' )
1675 self
. assertEqual ( output
, '51821' )
1676 output
= check_output ( 'wg show wg97 fwmark' )
1677 self
. assertEqual ( output
, '0x4d3' )
1679 def test_geneve ( self
):
1680 copy_network_unit ( '25-geneve.netdev' , '26-netdev-link-local-addressing-yes.network' )
1683 self
. wait_online ([ 'geneve99:degraded' ])
1685 output
= check_output ( 'ip -d link show geneve99' )
1687 self
. assertRegex ( output
, '192.168.22.1' )
1688 self
. assertRegex ( output
, '6082' )
1689 self
. assertRegex ( output
, 'udpcsum' )
1690 self
. assertRegex ( output
, 'udp6zerocsumrx' )
1692 def test_ipip_tunnel ( self
):
1693 copy_network_unit ( '12-dummy.netdev' , '25-ipip.network' ,
1694 '25-ipip-tunnel.netdev' , '25-tunnel.network' ,
1695 '25-ipip-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1696 '25-ipip-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1697 '25-ipip-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1699 self
. wait_online ([ 'ipiptun99:routable' , 'ipiptun98:routable' , 'ipiptun97:routable' , 'ipiptun96:routable' , 'dummy98:degraded' ])
1701 output
= check_output ( 'ip -d link show ipiptun99' )
1703 self
. assertRegex ( output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98' )
1704 output
= check_output ( 'ip -d link show ipiptun98' )
1706 self
. assertRegex ( output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98' )
1707 output
= check_output ( 'ip -d link show ipiptun97' )
1709 self
. assertRegex ( output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98' )
1710 output
= check_output ( 'ip -d link show ipiptun96' )
1712 self
. assertRegex ( output
, 'ipip (ipip )?remote any local any dev dummy98' )
1714 def test_gre_tunnel ( self
):
1715 copy_network_unit ( '12-dummy.netdev' , '25-gretun.network' ,
1716 '25-gre-tunnel.netdev' , '25-tunnel.network' ,
1717 '25-gre-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1718 '25-gre-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1719 '25-gre-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1721 self
. wait_online ([ 'gretun99:routable' , 'gretun98:routable' , 'gretun97:routable' , 'gretun96:routable' , 'dummy98:degraded' ])
1723 output
= check_output ( 'ip -d link show gretun99' )
1725 self
. assertRegex ( output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1726 self
. assertRegex ( output
, 'ikey 1.2.3.103' )
1727 self
. assertRegex ( output
, 'okey 1.2.4.103' )
1728 self
. assertRegex ( output
, 'iseq' )
1729 self
. assertRegex ( output
, 'oseq' )
1730 output
= check_output ( 'ip -d link show gretun98' )
1732 self
. assertRegex ( output
, 'gre remote 10.65.223.239 local any dev dummy98' )
1733 self
. assertRegex ( output
, 'ikey 0.0.0.104' )
1734 self
. assertRegex ( output
, 'okey 0.0.0.104' )
1735 self
. assertNotRegex ( output
, 'iseq' )
1736 self
. assertNotRegex ( output
, 'oseq' )
1737 output
= check_output ( 'ip -d link show gretun97' )
1739 self
. assertRegex ( output
, 'gre remote any local 10.65.223.238 dev dummy98' )
1740 self
. assertRegex ( output
, 'ikey 0.0.0.105' )
1741 self
. assertRegex ( output
, 'okey 0.0.0.105' )
1742 self
. assertNotRegex ( output
, 'iseq' )
1743 self
. assertNotRegex ( output
, 'oseq' )
1744 output
= check_output ( 'ip -d link show gretun96' )
1746 self
. assertRegex ( output
, 'gre remote any local any dev dummy98' )
1747 self
. assertRegex ( output
, 'ikey 0.0.0.106' )
1748 self
. assertRegex ( output
, 'okey 0.0.0.106' )
1749 self
. assertNotRegex ( output
, 'iseq' )
1750 self
. assertNotRegex ( output
, 'oseq' )
1752 def test_ip6gre_tunnel ( self
):
1753 copy_network_unit ( '12-dummy.netdev' , '25-ip6gretun.network' ,
1754 '25-ip6gre-tunnel.netdev' , '25-tunnel.network' ,
1755 '25-ip6gre-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1756 '25-ip6gre-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1757 '25-ip6gre-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1760 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1762 self
. wait_links ( 'dummy98' , 'ip6gretun99' , 'ip6gretun98' , 'ip6gretun97' , 'ip6gretun96' )
1764 output
= check_output ( 'ip -d link show ip6gretun99' )
1766 self
. assertRegex ( output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1767 output
= check_output ( 'ip -d link show ip6gretun98' )
1769 self
. assertRegex ( output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98' )
1770 output
= check_output ( 'ip -d link show ip6gretun97' )
1772 self
. assertRegex ( output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98' )
1773 output
= check_output ( 'ip -d link show ip6gretun96' )
1775 self
. assertRegex ( output
, 'ip6gre remote any local any dev dummy98' )
1777 def test_gretap_tunnel ( self
):
1778 copy_network_unit ( '12-dummy.netdev' , '25-gretap.network' ,
1779 '25-gretap-tunnel.netdev' , '25-tunnel.network' ,
1780 '25-gretap-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1782 self
. wait_online ([ 'gretap99:routable' , 'gretap98:routable' , 'dummy98:degraded' ])
1784 output
= check_output ( 'ip -d link show gretap99' )
1786 self
. assertRegex ( output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1787 self
. assertRegex ( output
, 'ikey 0.0.0.106' )
1788 self
. assertRegex ( output
, 'okey 0.0.0.106' )
1789 self
. assertRegex ( output
, 'iseq' )
1790 self
. assertRegex ( output
, 'oseq' )
1791 self
. assertIn ( 'nopmtudisc' , output
)
1792 self
. assertIn ( 'ignore-df' , output
)
1793 output
= check_output ( 'ip -d link show gretap98' )
1795 self
. assertRegex ( output
, 'gretap remote 10.65.223.239 local any dev dummy98' )
1796 self
. assertRegex ( output
, 'ikey 0.0.0.107' )
1797 self
. assertRegex ( output
, 'okey 0.0.0.107' )
1798 self
. assertRegex ( output
, 'iseq' )
1799 self
. assertRegex ( output
, 'oseq' )
1801 def test_ip6gretap_tunnel ( self
):
1802 copy_network_unit ( '12-dummy.netdev' , '25-ip6gretap.network' ,
1803 '25-ip6gretap-tunnel.netdev' , '25-tunnel.network' ,
1804 '25-ip6gretap-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1806 self
. wait_online ([ 'ip6gretap99:routable' , 'ip6gretap98:routable' , 'dummy98:degraded' ])
1808 output
= check_output ( 'ip -d link show ip6gretap99' )
1810 self
. assertRegex ( output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1811 output
= check_output ( 'ip -d link show ip6gretap98' )
1813 self
. assertRegex ( output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98' )
1815 def test_vti_tunnel ( self
):
1816 copy_network_unit ( '12-dummy.netdev' , '25-vti.network' ,
1817 '25-vti-tunnel.netdev' , '25-tunnel.network' ,
1818 '25-vti-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1819 '25-vti-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1820 '25-vti-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1822 self
. wait_online ([ 'vtitun99:routable' , 'vtitun98:routable' , 'vtitun97:routable' , 'vtitun96:routable' , 'dummy98:degraded' ])
1824 output
= check_output ( 'ip -d link show vtitun99' )
1826 self
. assertRegex ( output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
1827 output
= check_output ( 'ip -d link show vtitun98' )
1829 self
. assertRegex ( output
, 'vti remote 10.65.223.239 local any dev dummy98' )
1830 output
= check_output ( 'ip -d link show vtitun97' )
1832 self
. assertRegex ( output
, 'vti remote any local 10.65.223.238 dev dummy98' )
1833 output
= check_output ( 'ip -d link show vtitun96' )
1835 self
. assertRegex ( output
, 'vti remote any local any dev dummy98' )
1837 def test_vti6_tunnel ( self
):
1838 copy_network_unit ( '12-dummy.netdev' , '25-vti6.network' ,
1839 '25-vti6-tunnel.netdev' , '25-tunnel.network' ,
1840 '25-vti6-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1841 '25-vti6-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' )
1843 self
. wait_online ([ 'vti6tun99:routable' , 'vti6tun98:routable' , 'vti6tun97:routable' , 'dummy98:degraded' ])
1845 output
= check_output ( 'ip -d link show vti6tun99' )
1847 self
. assertRegex ( output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
1848 output
= check_output ( 'ip -d link show vti6tun98' )
1850 self
. assertRegex ( output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98' )
1851 output
= check_output ( 'ip -d link show vti6tun97' )
1853 self
. assertRegex ( output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98' )
1855 def test_ip6tnl_tunnel ( self
):
1856 copy_network_unit ( '12-dummy.netdev' , '25-ip6tnl.network' ,
1857 '25-ip6tnl-tunnel.netdev' , '25-tunnel.network' ,
1858 '25-ip6tnl-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1859 '25-ip6tnl-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1860 '25-veth.netdev' , '25-ip6tnl-slaac.network' , '25-ipv6-prefix.network' ,
1861 '25-ip6tnl-tunnel-local-slaac.netdev' , '25-ip6tnl-tunnel-local-slaac.network' ,
1862 '25-ip6tnl-tunnel-external.netdev' , '26-netdev-link-local-addressing-yes.network' )
1864 self
. wait_online ([ 'ip6tnl99:routable' , 'ip6tnl98:routable' , 'ip6tnl97:routable' ,
1865 'ip6tnl-slaac:degraded' , 'ip6tnl-external:degraded' ,
1866 'dummy98:degraded' , 'veth99:routable' , 'veth-peer:degraded' ])
1868 output
= check_output ( 'ip -d link show ip6tnl99' )
1870 self
. assertIn ( 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' , output
)
1871 output
= check_output ( 'ip -d link show ip6tnl98' )
1873 self
. assertRegex ( output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98' )
1874 output
= check_output ( 'ip -d link show ip6tnl97' )
1876 self
. assertRegex ( output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98' )
1877 output
= check_output ( 'ip -d link show ip6tnl-external' )
1879 self
. assertIn ( 'ip6tnl-external@NONE:' , output
)
1880 self
. assertIn ( 'ip6tnl external ' , output
)
1881 output
= check_output ( 'ip -d link show ip6tnl-slaac' )
1883 self
. assertIn ( 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99' , output
)
1885 output
= check_output ( 'ip -6 address show veth99' )
1887 self
. assertIn ( 'inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic' , output
)
1889 output
= check_output ( 'ip -4 route show default' )
1891 self
. assertIn ( 'default dev ip6tnl-slaac proto static' , output
)
1893 def test_sit_tunnel ( self
):
1894 copy_network_unit ( '12-dummy.netdev' , '25-sit.network' ,
1895 '25-sit-tunnel.netdev' , '25-tunnel.network' ,
1896 '25-sit-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
1897 '25-sit-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
1898 '25-sit-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
1900 self
. wait_online ([ 'sittun99:routable' , 'sittun98:routable' , 'sittun97:routable' , 'sittun96:routable' , 'dummy98:degraded' ])
1902 output
= check_output ( 'ip -d link show sittun99' )
1904 self
. assertRegex ( output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98" )
1905 output
= check_output ( 'ip -d link show sittun98' )
1907 self
. assertRegex ( output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98" )
1908 output
= check_output ( 'ip -d link show sittun97' )
1910 self
. assertRegex ( output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98" )
1911 output
= check_output ( 'ip -d link show sittun96' )
1913 self
. assertRegex ( output
, "sit (ip6ip )?remote any local any dev dummy98" )
1915 def test_isatap_tunnel ( self
):
1916 copy_network_unit ( '12-dummy.netdev' , '25-isatap.network' ,
1917 '25-isatap-tunnel.netdev' , '25-tunnel.network' )
1919 self
. wait_online ([ 'isataptun99:routable' , 'dummy98:degraded' ])
1921 output
= check_output ( 'ip -d link show isataptun99' )
1923 self
. assertRegex ( output
, "isatap " )
1925 def test_6rd_tunnel ( self
):
1926 copy_network_unit ( '12-dummy.netdev' , '25-6rd.network' ,
1927 '25-6rd-tunnel.netdev' , '25-tunnel.network' )
1929 self
. wait_online ([ 'sittun99:routable' , 'dummy98:degraded' ])
1931 output
= check_output ( 'ip -d link show sittun99' )
1933 self
. assertRegex ( output
, '6rd-prefix 2602::/24' )
1935 @expectedFailureIfERSPANv0IsNotSupported ()
1936 def test_erspan_tunnel_v0 ( self
):
1937 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
1938 '25-erspan0-tunnel.netdev' , '25-tunnel.network' ,
1939 '25-erspan0-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1941 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
1943 output
= check_output ( 'ip -d link show erspan99' )
1945 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
1946 self
. assertIn ( 'erspan_ver 0' , output
)
1947 self
. assertNotIn ( 'erspan_index 123' , output
)
1948 self
. assertNotIn ( 'erspan_dir ingress' , output
)
1949 self
. assertNotIn ( 'erspan_hwid 1f' , output
)
1950 self
. assertIn ( 'ikey 0.0.0.101' , output
)
1951 self
. assertIn ( 'iseq' , output
)
1952 self
. assertIn ( 'nopmtudisc' , output
)
1953 self
. assertIn ( 'ignore-df' , output
)
1954 output
= check_output ( 'ip -d link show erspan98' )
1956 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
1957 self
. assertIn ( 'erspan_ver 0' , output
)
1958 self
. assertNotIn ( 'erspan_index 124' , output
)
1959 self
. assertNotIn ( 'erspan_dir egress' , output
)
1960 self
. assertNotIn ( 'erspan_hwid 2f' , output
)
1961 self
. assertIn ( 'ikey 0.0.0.102' , output
)
1962 self
. assertIn ( 'iseq' , output
)
1964 def test_erspan_tunnel_v1 ( self
):
1965 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
1966 '25-erspan1-tunnel.netdev' , '25-tunnel.network' ,
1967 '25-erspan1-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
1969 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
1971 output
= check_output ( 'ip -d link show erspan99' )
1973 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
1974 self
. assertIn ( 'erspan_ver 1' , output
)
1975 self
. assertIn ( 'erspan_index 123' , output
)
1976 self
. assertNotIn ( 'erspan_dir ingress' , output
)
1977 self
. assertNotIn ( 'erspan_hwid 1f' , output
)
1978 self
. assertIn ( 'ikey 0.0.0.101' , output
)
1979 self
. assertIn ( 'okey 0.0.0.101' , output
)
1980 self
. assertIn ( 'iseq' , output
)
1981 self
. assertIn ( 'oseq' , output
)
1982 output
= check_output ( 'ip -d link show erspan98' )
1984 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
1985 self
. assertIn ( 'erspan_ver 1' , output
)
1986 self
. assertIn ( 'erspan_index 124' , output
)
1987 self
. assertNotIn ( 'erspan_dir egress' , output
)
1988 self
. assertNotIn ( 'erspan_hwid 2f' , output
)
1989 self
. assertIn ( 'ikey 0.0.0.102' , output
)
1990 self
. assertIn ( 'okey 0.0.0.102' , output
)
1991 self
. assertIn ( 'iseq' , output
)
1992 self
. assertIn ( 'oseq' , output
)
1994 @expectedFailureIfERSPANv2IsNotSupported ()
1995 def test_erspan_tunnel_v2 ( self
):
1996 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
1997 '25-erspan2-tunnel.netdev' , '25-tunnel.network' ,
1998 '25-erspan2-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
2000 self
. wait_online ([ 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' ])
2002 output
= check_output ( 'ip -d link show erspan99' )
2004 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
2005 self
. assertIn ( 'erspan_ver 2' , output
)
2006 self
. assertNotIn ( 'erspan_index 123' , output
)
2007 self
. assertIn ( 'erspan_dir ingress' , output
)
2008 self
. assertIn ( 'erspan_hwid 0x1f' , output
)
2009 self
. assertIn ( 'ikey 0.0.0.101' , output
)
2010 self
. assertIn ( 'okey 0.0.0.101' , output
)
2011 self
. assertIn ( 'iseq' , output
)
2012 self
. assertIn ( 'oseq' , output
)
2013 output
= check_output ( 'ip -d link show erspan98' )
2015 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
2016 self
. assertIn ( 'erspan_ver 2' , output
)
2017 self
. assertNotIn ( 'erspan_index 124' , output
)
2018 self
. assertIn ( 'erspan_dir egress' , output
)
2019 self
. assertIn ( 'erspan_hwid 0x2f' , output
)
2020 self
. assertIn ( 'ikey 0.0.0.102' , output
)
2021 self
. assertIn ( 'okey 0.0.0.102' , output
)
2022 self
. assertIn ( 'iseq' , output
)
2023 self
. assertIn ( 'oseq' , output
)
2025 def test_tunnel_independent ( self
):
2026 copy_network_unit ( '25-ipip-tunnel-independent.netdev' , '26-netdev-link-local-addressing-yes.network' )
2029 self
. wait_online ([ 'ipiptun99:carrier' ])
2031 def test_tunnel_independent_loopback ( self
):
2032 copy_network_unit ( '25-ipip-tunnel-independent-loopback.netdev' , '26-netdev-link-local-addressing-yes.network' )
2035 self
. wait_online ([ 'ipiptun99:carrier' ])
2037 @expectedFailureIfModuleIsNotAvailable ( 'xfrm_interface' )
2038 def test_xfrm ( self
):
2039 copy_network_unit ( '12-dummy.netdev' , '25-xfrm.network' ,
2040 '25-xfrm.netdev' , '25-xfrm-independent.netdev' ,
2041 '26-netdev-link-local-addressing-yes.network' )
2044 self
. wait_online ([ 'dummy98:degraded' , 'xfrm98:degraded' , 'xfrm99:degraded' ])
2046 output
= check_output ( 'ip -d link show dev xfrm98' )
2048 self
. assertIn ( 'xfrm98@dummy98:' , output
)
2049 self
. assertIn ( 'xfrm if_id 0x98 ' , output
)
2051 output
= check_output ( 'ip -d link show dev xfrm99' )
2053 self
. assertIn ( 'xfrm99@lo:' , output
)
2054 self
. assertIn ( 'xfrm if_id 0x99 ' , output
)
2056 @expectedFailureIfModuleIsNotAvailable ( 'fou' )
2058 # The following redundant check is necessary for CentOS CI.
2059 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
2060 self
. assertTrue ( is_module_available ( 'fou' ))
2062 copy_network_unit ( '25-fou-ipproto-ipip.netdev' , '25-fou-ipproto-gre.netdev' ,
2063 '25-fou-ipip.netdev' , '25-fou-sit.netdev' ,
2064 '25-fou-gre.netdev' , '25-fou-gretap.netdev' )
2067 self
. wait_online ([ 'ipiptun96:off' , 'sittun96:off' , 'gretun96:off' , 'gretap96:off' ], setup_state
= 'unmanaged' )
2069 output
= check_output ( 'ip fou show' )
2071 self
. assertRegex ( output
, 'port 55555 ipproto 4' )
2072 self
. assertRegex ( output
, 'port 55556 ipproto 47' )
2074 output
= check_output ( 'ip -d link show ipiptun96' )
2076 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55555' )
2077 output
= check_output ( 'ip -d link show sittun96' )
2079 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55555' )
2080 output
= check_output ( 'ip -d link show gretun96' )
2082 self
. assertRegex ( output
, 'encap fou encap-sport 1001 encap-dport 55556' )
2083 output
= check_output ( 'ip -d link show gretap96' )
2085 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55556' )
2087 def test_vxlan ( self
):
2088 copy_network_unit ( '11-dummy.netdev' , '25-vxlan-test1.network' ,
2089 '25-vxlan.netdev' , '25-vxlan.network' ,
2090 '25-vxlan-ipv6.netdev' , '25-vxlan-ipv6.network' ,
2091 '25-vxlan-independent.netdev' , '26-netdev-link-local-addressing-yes.network' ,
2092 '25-veth.netdev' , '25-vxlan-veth99.network' , '25-ipv6-prefix.network' ,
2093 '25-vxlan-local-slaac.netdev' , '25-vxlan-local-slaac.network' )
2096 self
. wait_online ([ 'test1:degraded' , 'veth99:routable' , 'veth-peer:degraded' ,
2097 'vxlan99:degraded' , 'vxlan98:degraded' , 'vxlan97:degraded' , 'vxlan-slaac:degraded' ])
2099 output
= check_output ( 'ip -d -d link show vxlan99' )
2101 self
. assertIn ( '999' , output
)
2102 self
. assertIn ( '5555' , output
)
2103 self
. assertIn ( 'l2miss' , output
)
2104 self
. assertIn ( 'l3miss' , output
)
2105 self
. assertIn ( 'gbp' , output
)
2106 # Since [0] some of the options use slightly different names and some
2107 # options with default values are shown only if the -d(etails) setting
2109 # [0] https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit/?id=1215e9d3862387353d8672296cb4c6c16e8cbb72
2110 self
. assertRegex ( output
, '(udpcsum|udp_csum)' )
2111 self
. assertRegex ( output
, '(udp6zerocsumtx|udp_zero_csum6_tx)' )
2112 self
. assertRegex ( output
, '(udp6zerocsumrx|udp_zero_csum6_rx)' )
2113 self
. assertRegex ( output
, '(remcsumtx|remcsum_tx)' )
2114 self
. assertRegex ( output
, '(remcsumrx|remcsum_rx)' )
2116 output
= check_output ( 'bridge fdb show dev vxlan99' )
2118 self
. assertIn ( '00:11:22:33:44:55 dst 10.0.0.5 self permanent' , output
)
2119 self
. assertIn ( '00:11:22:33:44:66 dst 10.0.0.6 self permanent' , output
)
2120 self
. assertIn ( '00:11:22:33:44:77 dst 10.0.0.7 via test1 self permanent' , output
)
2122 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'vxlan99' , env
= env
)
2124 self
. assertIn ( 'VNI: 999' , output
)
2125 self
. assertIn ( 'Destination Port: 5555' , output
)
2126 self
. assertIn ( 'Underlying Device: test1' , output
)
2128 output
= check_output ( 'bridge fdb show dev vxlan97' )
2130 self
. assertIn ( '00:00:00:00:00:00 dst fe80::23b:d2ff:fe95:967f via test1 self permanent' , output
)
2131 self
. assertIn ( '00:00:00:00:00:00 dst fe80::27c:16ff:fec0:6c74 via test1 self permanent' , output
)
2132 self
. assertIn ( '00:00:00:00:00:00 dst fe80::2a2:e4ff:fef9:2269 via test1 self permanent' , output
)
2134 output
= check_output ( 'ip -d link show vxlan-slaac' )
2136 self
. assertIn ( 'vxlan id 4831584 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99' , output
)
2138 output
= check_output ( 'ip -6 address show veth99' )
2140 self
. assertIn ( 'inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic' , output
)
2142 @unittest . skipUnless ( compare_kernel_version ( "6" ), reason
= "Causes kernel panic on unpatched kernels: https://bugzilla.kernel.org/show_bug.cgi?id=208315" )
2143 def test_macsec ( self
):
2144 copy_network_unit ( '25-macsec.netdev' , '25-macsec.network' , '25-macsec.key' ,
2145 '26-macsec.network' , '12-dummy.netdev' )
2148 self
. wait_online ([ 'dummy98:degraded' , 'macsec99:routable' ])
2150 output
= check_output ( 'ip -d link show macsec99' )
2152 self
. assertRegex ( output
, 'macsec99@dummy98' )
2153 self
. assertRegex ( output
, 'macsec sci [0-9a-f]*000b' )
2154 self
. assertRegex ( output
, 'encrypt on' )
2156 output
= check_output ( 'ip macsec show macsec99' )
2158 self
. assertRegex ( output
, 'encrypt on' )
2159 self
. assertRegex ( output
, 'TXSC: [0-9a-f]*000b on SA 1' )
2160 self
. assertRegex ( output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000' )
2161 self
. assertRegex ( output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000' )
2162 self
. assertRegex ( output
, 'RXSC: c619528fe6a00100, state on' )
2163 self
. assertRegex ( output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000' )
2164 self
. assertRegex ( output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000' )
2165 self
. assertRegex ( output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000' )
2166 self
. assertRegex ( output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000' )
2167 self
. assertNotRegex ( output
, 'key 02030405067080900000000000000000' )
2168 self
. assertRegex ( output
, 'RXSC: 8c16456c83a90002, state on' )
2169 self
. assertRegex ( output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000' )
2171 def test_nlmon ( self
):
2172 copy_network_unit ( '25-nlmon.netdev' , '26-netdev-link-local-addressing-yes.network' )
2175 self
. wait_online ([ 'nlmon99:carrier' ])
2177 @expectedFailureIfModuleIsNotAvailable ( 'ifb' )
2179 copy_network_unit ( '25-ifb.netdev' , '26-netdev-link-local-addressing-yes.network' )
2182 self
. wait_online ([ 'ifb99:degraded' ])
2184 class NetworkdL2TPTests ( unittest
. TestCase
, Utilities
):
2192 @expectedFailureIfModuleIsNotAvailable ( 'l2tp_eth' , 'l2tp_netlink' )
2193 def test_l2tp_udp ( self
):
2194 copy_network_unit ( '11-dummy.netdev' , '25-l2tp-dummy.network' ,
2195 '25-l2tp-udp.netdev' , '25-l2tp.network' )
2198 self
. wait_online ([ 'test1:routable' , 'l2tp-ses1:degraded' , 'l2tp-ses2:degraded' ])
2200 output
= check_output ( 'ip l2tp show tunnel tunnel_id 10' )
2202 self
. assertRegex ( output
, "Tunnel 10, encap UDP" )
2203 self
. assertRegex ( output
, "From 192.168.30.100 to 192.168.30.101" )
2204 self
. assertRegex ( output
, "Peer tunnel 11" )
2205 self
. assertRegex ( output
, "UDP source / dest ports: 3000/4000" )
2206 self
. assertRegex ( output
, "UDP checksum: enabled" )
2208 output
= check_output ( 'ip l2tp show session tid 10 session_id 15' )
2210 self
. assertRegex ( output
, "Session 15 in tunnel 10" )
2211 self
. assertRegex ( output
, "Peer session 16, tunnel 11" )
2212 self
. assertRegex ( output
, "interface name: l2tp-ses1" )
2214 output
= check_output ( 'ip l2tp show session tid 10 session_id 17' )
2216 self
. assertRegex ( output
, "Session 17 in tunnel 10" )
2217 self
. assertRegex ( output
, "Peer session 18, tunnel 11" )
2218 self
. assertRegex ( output
, "interface name: l2tp-ses2" )
2220 @expectedFailureIfModuleIsNotAvailable ( 'l2tp_eth' , 'l2tp_ip' , 'l2tp_netlink' )
2221 def test_l2tp_ip ( self
):
2222 copy_network_unit ( '11-dummy.netdev' , '25-l2tp-dummy.network' ,
2223 '25-l2tp-ip.netdev' , '25-l2tp.network' )
2226 self
. wait_online ([ 'test1:routable' , 'l2tp-ses3:degraded' , 'l2tp-ses4:degraded' ])
2228 output
= check_output ( 'ip l2tp show tunnel tunnel_id 10' )
2230 self
. assertRegex ( output
, "Tunnel 10, encap IP" )
2231 self
. assertRegex ( output
, "From 192.168.30.100 to 192.168.30.101" )
2232 self
. assertRegex ( output
, "Peer tunnel 12" )
2234 output
= check_output ( 'ip l2tp show session tid 10 session_id 25' )
2236 self
. assertRegex ( output
, "Session 25 in tunnel 10" )
2237 self
. assertRegex ( output
, "Peer session 26, tunnel 12" )
2238 self
. assertRegex ( output
, "interface name: l2tp-ses3" )
2240 output
= check_output ( 'ip l2tp show session tid 10 session_id 27' )
2242 self
. assertRegex ( output
, "Session 27 in tunnel 10" )
2243 self
. assertRegex ( output
, "Peer session 28, tunnel 12" )
2244 self
. assertRegex ( output
, "interface name: l2tp-ses4" )
2246 class NetworkdNetworkTests ( unittest
. TestCase
, Utilities
):
2254 def test_address_static ( self
):
2255 # test for #22515. The address will be removed and replaced with /64 prefix.
2256 check_output ( 'ip link add dummy98 type dummy' )
2257 check_output ( 'ip link set dev dummy98 up' )
2258 check_output ( 'ip -6 address add 2001:db8:0:f101::15/128 dev dummy98' )
2259 self
. wait_address ( 'dummy98' , '2001:db8:0:f101::15/128' , ipv
= '-6' )
2260 check_output ( 'ip -4 address add 10.3.2.3/16 brd 10.3.255.250 scope global label dummy98:hoge dev dummy98' )
2261 self
. wait_address ( 'dummy98' , '10.3.2.3/16 brd 10.3.255.250' , ipv
= '-4' )
2263 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' )
2266 self
. wait_online ([ 'dummy98:routable' ])
2268 output
= check_output ( 'ip -4 address show dev dummy98' )
2270 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
2271 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
2272 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
2273 self
. assertIn ( 'inet 10.7.8.9/16 brd 10.7.255.255 scope link deprecated dummy98' , output
)
2274 self
. assertIn ( 'inet 10.8.8.1/16 scope global dummy98' , output
)
2275 self
. assertIn ( 'inet 10.8.8.2/16 brd 10.8.8.128 scope global secondary dummy98' , output
)
2276 self
. assertRegex ( output
, 'inet 10.9.0.1/16 (metric 128 |)brd 10.9.255.255 scope global dummy98' )
2278 # test for ENOBUFS issue #17012
2279 for i
in range ( 1 , 254 ):
2280 self
. assertIn ( f
'inet 10.3.3. {i} /16 brd 10.3.255.255' , output
)
2283 self
. assertNotIn ( '10.10.0.1/16' , output
)
2284 self
. assertNotIn ( '10.10.0.2/16' , output
)
2286 output
= check_output ( 'ip -4 address show dev dummy98 label 32' )
2287 self
. assertIn ( 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32' , output
)
2289 output
= check_output ( 'ip -4 address show dev dummy98 label 33' )
2290 self
. assertIn ( 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33' , output
)
2292 output
= check_output ( 'ip -4 address show dev dummy98 label 34' )
2293 self
. assertRegex ( output
, r
'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34' )
2295 output
= check_output ( 'ip -4 address show dev dummy98 label 35' )
2296 self
. assertRegex ( output
, r
'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35' )
2298 output
= check_output ( 'ip -4 route show dev dummy98' )
2300 self
. assertIn ( '10.9.0.0/16 proto kernel scope link src 10.9.0.1 metric 128' , output
)
2302 output
= check_output ( 'ip -6 address show dev dummy98' )
2304 self
. assertIn ( 'inet6 2001:db8:0:f101::15/64 scope global' , output
)
2305 self
. assertIn ( 'inet6 2001:db8:0:f101::16/64 scope global' , output
)
2306 self
. assertIn ( 'inet6 2001:db8:0:f102::15/64 scope global' , output
)
2307 self
. assertIn ( 'inet6 2001:db8:0:f102::16/64 scope global' , output
)
2308 self
. assertIn ( 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global' , output
)
2309 self
. assertIn ( 'inet6 2001:db8:1:f101::1/64 scope global deprecated' , output
)
2310 self
. assertRegex ( output
, r
'inet6 fd[0-9a-f:]*1/64 scope global' )
2312 self
. check_netlabel ( 'dummy98' , r
'10\.4\.3\.0/24' )
2315 # 1. set preferred lifetime forever to drop the deprecated flag for testing #20891.
2316 check_output ( 'ip address change 10.7.8.9/16 dev dummy98 preferred_lft forever' )
2317 check_output ( 'ip address change 2001:db8:1:f101::1/64 dev dummy98 preferred_lft forever' )
2318 output
= check_output ( 'ip -4 address show dev dummy98' )
2320 self
. assertNotIn ( 'deprecated' , output
)
2321 output
= check_output ( 'ip -6 address show dev dummy98' )
2323 self
. assertNotIn ( 'deprecated' , output
)
2325 # 2. reconfigure the interface.
2326 networkctl_reconfigure ( 'dummy98' )
2327 self
. wait_online ([ 'dummy98:routable' ])
2329 # 3. check the deprecated flag is set for the address configured with PreferredLifetime=0
2330 output
= check_output ( 'ip -4 address show dev dummy98' )
2332 self
. assertIn ( 'inet 10.7.8.9/16 brd 10.7.255.255 scope link deprecated dummy98' , output
)
2333 output
= check_output ( 'ip -6 address show dev dummy98' )
2335 self
. assertIn ( 'inet6 2001:db8:1:f101::1/64 scope global deprecated' , output
)
2337 # test for ENOBUFS issue #17012
2338 output
= check_output ( 'ip -4 address show dev dummy98' )
2339 for i
in range ( 1 , 254 ):
2340 self
. assertIn ( f
'inet 10.3.3. {i} /16 brd 10.3.255.255' , output
)
2342 # TODO: check json string
2343 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2345 def test_address_null ( self
):
2346 copy_network_unit ( '25-address-null.network' , '12-dummy.netdev' )
2349 self
. wait_online ([ 'dummy98:routable' ])
2351 output
= check_output ( 'ip address show dev dummy98 scope global' )
2354 ipv4_address_16
= re
. findall ( r
'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255' , output
)
2355 self
. assertEqual ( len ( ipv4_address_16
), 1 )
2356 ipv4_address_24
= re
. findall ( r
'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255' , output
)
2357 self
. assertEqual ( len ( ipv4_address_24
), 1 )
2358 ipv4_address_30
= re
. findall ( r
'inet 192.168.[0-9]*.[0-9]*/30 brd 192.168.[0-9]*.[0-9]*' , output
)
2359 self
. assertEqual ( len ( ipv4_address_30
), 1 )
2360 ipv6_address
= re
. findall ( r
'inet6 fd[0-9a-f:]*/64' , output
)
2361 self
. assertEqual ( len ( ipv6_address
), 1 )
2363 networkctl_reconfigure ( 'dummy98' )
2364 self
. wait_online ([ 'dummy98:routable' ])
2366 output
= check_output ( 'ip address show dev dummy98 scope global' )
2368 self
. assertIn ( ipv4_address_16
[ 0 ], output
)
2369 self
. assertIn ( ipv4_address_24
[ 0 ], output
)
2370 self
. assertIn ( ipv4_address_30
[ 0 ], output
)
2371 self
. assertIn ( ipv6_address
[ 0 ], output
)
2373 def test_address_ipv4acd ( self
):
2374 check_output ( 'ip netns add ns99' )
2375 check_output ( 'ip link add veth99 type veth peer veth-peer' )
2376 check_output ( 'ip link set veth-peer netns ns99' )
2377 check_output ( 'ip link set veth99 up' )
2378 check_output ( 'ip netns exec ns99 ip link set veth-peer up' )
2379 check_output ( 'ip netns exec ns99 ip address add 192.168.100.10/24 dev veth-peer' )
2381 copy_network_unit ( '25-address-ipv4acd-veth99.network' , copy_dropins
= False )
2383 self
. wait_online ([ 'veth99:routable' ])
2385 output
= check_output ( 'ip -4 address show dev veth99' )
2387 self
. assertNotIn ( '192.168.100.10/24' , output
)
2388 self
. assertIn ( '192.168.100.11/24' , output
)
2390 copy_network_unit ( '25-address-ipv4acd-veth99.network.d/conflict-address.conf' )
2392 self
. wait_operstate ( 'veth99' , operstate
= 'routable' , setup_state
= 'configuring' , setup_timeout
= 10 )
2394 output
= check_output ( 'ip -4 address show dev veth99' )
2396 self
. assertNotIn ( '192.168.100.10/24' , output
)
2397 self
. assertIn ( '192.168.100.11/24' , output
)
2399 def test_address_peer_ipv4 ( self
):
2400 # test for issue #17304
2401 copy_network_unit ( '25-address-peer-ipv4.network' , '12-dummy.netdev' )
2403 for trial
in range ( 2 ):
2409 self
. wait_online ([ 'dummy98:routable' ])
2411 output
= check_output ( 'ip -4 address show dev dummy98' )
2412 self
. assertIn ( 'inet 100.64.0.1 peer 100.64.0.2/32 scope global' , output
)
2414 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
2415 def test_prefix_route ( self
):
2416 copy_network_unit ( '25-prefix-route-with-vrf.network' , '12-dummy.netdev' ,
2417 '25-prefix-route-without-vrf.network' , '11-dummy.netdev' ,
2418 '25-vrf.netdev' , '25-vrf.network' )
2419 for trial
in range ( 2 ):
2425 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' , 'vrf99:carrier' ])
2427 output
= check_output ( 'ip route show table 42 dev dummy98' )
2428 print ( '### ip route show table 42 dev dummy98' )
2430 self
. assertRegex ( output
, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1' )
2431 self
. assertRegex ( output
, '10.20.33.0/24 proto kernel scope link src 10.20.33.1' )
2432 self
. assertRegex ( output
, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1' )
2433 self
. assertRegex ( output
, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1' )
2434 self
. assertRegex ( output
, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1' )
2435 self
. assertRegex ( output
, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1' )
2436 self
. assertRegex ( output
, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1' )
2437 output
= check_output ( 'ip -6 route show table 42 dev dummy98' )
2438 print ( '### ip -6 route show table 42 dev dummy98' )
2442 self
. assertRegex ( output
, 'local fdde:11:22::1 proto kernel metric 0 pref medium' )
2443 #self.assertRegex(output, 'fdde:11:22::1 proto kernel metric 256 pref medium')
2444 self
. assertRegex ( output
, 'local fdde:11:33::1 proto kernel metric 0 pref medium' )
2445 self
. assertRegex ( output
, 'fdde:11:33::/64 proto kernel metric 256 pref medium' )
2446 self
. assertRegex ( output
, 'local fdde:11:44::1 proto kernel metric 0 pref medium' )
2447 self
. assertRegex ( output
, 'local fdde:11:55::1 proto kernel metric 0 pref medium' )
2448 self
. assertRegex ( output
, 'fe80::/64 proto kernel metric 256 pref medium' )
2449 self
. assertRegex ( output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium' )
2453 output
= check_output ( 'ip route show dev test1' )
2454 print ( '### ip route show dev test1' )
2456 self
. assertRegex ( output
, '10.21.33.0/24 proto kernel scope link src 10.21.33.1' )
2457 output
= check_output ( 'ip route show table local dev test1' )
2458 print ( '### ip route show table local dev test1' )
2460 self
. assertRegex ( output
, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1' )
2461 self
. assertRegex ( output
, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1' )
2462 self
. assertRegex ( output
, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1' )
2463 self
. assertRegex ( output
, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1' )
2464 self
. assertRegex ( output
, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1' )
2465 self
. assertRegex ( output
, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1' )
2466 output
= check_output ( 'ip -6 route show dev test1' )
2467 print ( '### ip -6 route show dev test1' )
2469 self
. assertRegex ( output
, 'fdde:12:22::1 proto kernel metric 256 pref medium' )
2470 self
. assertRegex ( output
, 'fdde:12:33::/64 proto kernel metric 256 pref medium' )
2471 self
. assertRegex ( output
, 'fe80::/64 proto kernel metric 256 pref medium' )
2472 output
= check_output ( 'ip -6 route show table local dev test1' )
2473 print ( '### ip -6 route show table local dev test1' )
2475 self
. assertRegex ( output
, 'local fdde:12:22::1 proto kernel metric 0 pref medium' )
2476 self
. assertRegex ( output
, 'local fdde:12:33::1 proto kernel metric 0 pref medium' )
2477 self
. assertRegex ( output
, 'local fdde:12:44::1 proto kernel metric 0 pref medium' )
2478 self
. assertRegex ( output
, 'local fdde:12:55::1 proto kernel metric 0 pref medium' )
2479 self
. assertRegex ( output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium' )
2481 def test_configure_without_carrier ( self
):
2482 copy_network_unit ( '11-dummy.netdev' )
2484 self
. wait_operstate ( 'test1' , 'off' , '' )
2485 check_output ( 'ip link set dev test1 up carrier off' )
2487 copy_network_unit ( '25-test1.network.d/configure-without-carrier.conf' , copy_dropins
= False )
2489 self
. wait_online ([ 'test1:no-carrier' ])
2491 carrier_map
= { 'on' : '1' , 'off' : '0' }
2492 routable_map
= { 'on' : 'routable' , 'off' : 'no-carrier' }
2493 for carrier
in [ 'off' , 'on' , 'off' ]:
2494 with self
. subTest ( carrier
= carrier
):
2495 if carrier_map
[ carrier
] != read_link_attr ( 'test1' , 'carrier' ):
2496 check_output ( f
'ip link set dev test1 carrier {carrier} ' )
2497 self
. wait_online ([ f
'test1:{routable_map[carrier]}:{routable_map[carrier]}' ])
2499 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
2501 self
. assertRegex ( output
, '192.168.0.15' )
2502 self
. assertRegex ( output
, '192.168.0.1' )
2503 self
. assertRegex ( output
, routable_map
[ carrier
])
2505 def test_configure_without_carrier_yes_ignore_carrier_loss_no ( self
):
2506 copy_network_unit ( '11-dummy.netdev' )
2508 self
. wait_operstate ( 'test1' , 'off' , '' )
2509 check_output ( 'ip link set dev test1 up carrier off' )
2511 copy_network_unit ( '25-test1.network' )
2513 self
. wait_online ([ 'test1:no-carrier' ])
2515 carrier_map
= { 'on' : '1' , 'off' : '0' }
2516 routable_map
= { 'on' : 'routable' , 'off' : 'no-carrier' }
2517 for ( carrier
, have_config
) in [( 'off' , True ), ( 'on' , True ), ( 'off' , False )]:
2518 with self
. subTest ( carrier
= carrier
, have_config
= have_config
):
2519 if carrier_map
[ carrier
] != read_link_attr ( 'test1' , 'carrier' ):
2520 check_output ( f
'ip link set dev test1 carrier {carrier} ' )
2521 self
. wait_online ([ f
'test1:{routable_map[carrier]}:{routable_map[carrier]}' ])
2523 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
2526 self
. assertRegex ( output
, '192.168.0.15' )
2527 self
. assertRegex ( output
, '192.168.0.1' )
2529 self
. assertNotRegex ( output
, '192.168.0.15' )
2530 self
. assertNotRegex ( output
, '192.168.0.1' )
2531 self
. assertRegex ( output
, routable_map
[ carrier
])
2533 def test_routing_policy_rule ( self
):
2534 copy_network_unit ( '25-routing-policy-rule-test1.network' , '11-dummy.netdev' )
2536 self
. wait_online ([ 'test1:degraded' ])
2538 output
= check_output ( 'ip rule list iif test1 priority 111' )
2540 self
. assertRegex ( output
, '111:' )
2541 self
. assertRegex ( output
, 'from 192.168.100.18' )
2542 self
. assertRegex ( output
, r
'tos (0x08|throughput)\s' )
2543 self
. assertRegex ( output
, 'iif test1' )
2544 self
. assertRegex ( output
, 'oif test1' )
2545 self
. assertRegex ( output
, 'lookup 7' )
2547 output
= check_output ( 'ip rule list iif test1 priority 101' )
2549 self
. assertRegex ( output
, '101:' )
2550 self
. assertRegex ( output
, 'from all' )
2551 self
. assertRegex ( output
, 'iif test1' )
2552 self
. assertRegex ( output
, 'lookup 9' )
2554 output
= check_output ( 'ip -6 rule list iif test1 priority 100' )
2556 self
. assertRegex ( output
, '100:' )
2557 self
. assertRegex ( output
, 'from all' )
2558 self
. assertRegex ( output
, 'iif test1' )
2559 self
. assertRegex ( output
, 'lookup 8' )
2561 output
= check_output ( 'ip rule list iif test1 priority 102' )
2563 self
. assertRegex ( output
, '102:' )
2564 self
. assertRegex ( output
, 'from 0.0.0.0/8' )
2565 self
. assertRegex ( output
, 'iif test1' )
2566 self
. assertRegex ( output
, 'lookup 10' )
2568 # TODO: check json string
2569 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2571 def test_routing_policy_rule_issue_11280 ( self
):
2572 copy_network_unit ( '25-routing-policy-rule-test1.network' , '11-dummy.netdev' ,
2573 '25-routing-policy-rule-dummy98.network' , '12-dummy.netdev' )
2575 for trial
in range ( 3 ):
2576 restart_networkd ( show_logs
=( trial
> 0 ))
2577 self
. wait_online ([ 'test1:degraded' , 'dummy98:degraded' ])
2579 output
= check_output ( 'ip rule list table 7' )
2581 self
. assertRegex ( output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7' )
2583 output
= check_output ( 'ip rule list table 8' )
2585 self
. assertRegex ( output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8' )
2587 def test_routing_policy_rule_reconfigure ( self
):
2588 copy_network_unit ( '25-routing-policy-rule-reconfigure2.network' , '11-dummy.netdev' )
2590 self
. wait_online ([ 'test1:degraded' ])
2592 output
= check_output ( 'ip rule list table 1011' )
2594 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2595 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2596 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2597 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2599 output
= check_output ( 'ip -6 rule list table 1011' )
2601 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2603 copy_network_unit ( '25-routing-policy-rule-reconfigure1.network' , '11-dummy.netdev' )
2605 self
. wait_online ([ 'test1:degraded' ])
2607 output
= check_output ( 'ip rule list table 1011' )
2609 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2610 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2611 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2612 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2614 output
= check_output ( 'ip -6 rule list table 1011' )
2616 self
. assertNotIn ( '10112: from all oif test1 lookup 1011' , output
)
2617 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2619 call ( 'ip rule delete priority 10111' )
2620 call ( 'ip rule delete priority 10112' )
2621 call ( 'ip rule delete priority 10113' )
2622 call ( 'ip rule delete priority 10114' )
2623 call ( 'ip -6 rule delete priority 10113' )
2625 output
= check_output ( 'ip rule list table 1011' )
2627 self
. assertEqual ( output
, '' )
2629 output
= check_output ( 'ip -6 rule list table 1011' )
2631 self
. assertEqual ( output
, '' )
2633 networkctl_reconfigure ( 'test1' )
2634 self
. wait_online ([ 'test1:degraded' ])
2636 output
= check_output ( 'ip rule list table 1011' )
2638 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
2639 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
2640 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2641 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
2643 output
= check_output ( 'ip -6 rule list table 1011' )
2645 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
2647 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable ()
2648 def test_routing_policy_rule_port_range ( self
):
2649 copy_network_unit ( '25-fibrule-port-range.network' , '11-dummy.netdev' )
2651 self
. wait_online ([ 'test1:degraded' ])
2653 output
= check_output ( 'ip rule' )
2655 self
. assertRegex ( output
, '111' )
2656 self
. assertRegex ( output
, 'from 192.168.100.18' )
2657 self
. assertRegex ( output
, '1123-1150' )
2658 self
. assertRegex ( output
, '3224-3290' )
2659 self
. assertRegex ( output
, 'tcp' )
2660 self
. assertRegex ( output
, 'lookup 7' )
2662 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable ()
2663 def test_routing_policy_rule_invert ( self
):
2664 copy_network_unit ( '25-fibrule-invert.network' , '11-dummy.netdev' )
2666 self
. wait_online ([ 'test1:degraded' ])
2668 output
= check_output ( 'ip rule' )
2670 self
. assertRegex ( output
, '111' )
2671 self
. assertRegex ( output
, 'not.*?from.*?192.168.100.18' )
2672 self
. assertRegex ( output
, 'tcp' )
2673 self
. assertRegex ( output
, 'lookup 7' )
2675 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable ()
2676 def test_routing_policy_rule_uidrange ( self
):
2677 copy_network_unit ( '25-fibrule-uidrange.network' , '11-dummy.netdev' )
2679 self
. wait_online ([ 'test1:degraded' ])
2681 output
= check_output ( 'ip rule' )
2683 self
. assertRegex ( output
, '111' )
2684 self
. assertRegex ( output
, 'from 192.168.100.18' )
2685 self
. assertRegex ( output
, 'lookup 7' )
2686 self
. assertRegex ( output
, 'uidrange 100-200' )
2688 def _test_route_static ( self
, manage_foreign_routes
):
2689 if not manage_foreign_routes
:
2690 copy_networkd_conf_dropin ( 'networkd-manage-foreign-routes-no.conf' )
2692 copy_network_unit ( '25-route-static.network' , '12-dummy.netdev' )
2694 self
. wait_online ([ 'dummy98:routable' ])
2696 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
2699 print ( '### ip -6 route show dev dummy98' )
2700 output
= check_output ( 'ip -6 route show dev dummy98' )
2702 self
. assertIn ( '2001:1234:5:8fff:ff:ff:ff:ff proto static' , output
)
2703 self
. assertIn ( '2001:1234:5:8f63::1 proto kernel' , output
)
2704 self
. assertIn ( '2001:1234:5:afff:ff:ff:ff:ff via fe80:0:222:4dff:ff:ff:ff:ff proto static' , output
)
2706 print ( '### ip -6 route show default' )
2707 output
= check_output ( 'ip -6 route show default' )
2709 self
. assertIn ( 'default' , output
)
2710 self
. assertIn ( 'via 2001:1234:5:8fff:ff:ff:ff:ff' , output
)
2712 print ( '### ip -4 route show dev dummy98' )
2713 output
= check_output ( 'ip -4 route show dev dummy98' )
2715 self
. assertIn ( '149.10.124.48/28 proto kernel scope link src 149.10.124.58' , output
)
2716 self
. assertIn ( '149.10.124.64 proto static scope link' , output
)
2717 self
. assertIn ( '169.254.0.0/16 proto static scope link metric 2048' , output
)
2718 self
. assertIn ( '192.168.1.1 proto static scope link initcwnd 20' , output
)
2719 self
. assertIn ( '192.168.1.2 proto static scope link initrwnd 30' , output
)
2720 self
. assertIn ( '192.168.1.3 proto static scope link advmss 30' , output
)
2721 self
. assertIn ( 'multicast 149.10.123.4 proto static' , output
)
2723 print ( '### ip -4 route show dev dummy98 default' )
2724 output
= check_output ( 'ip -4 route show dev dummy98 default' )
2726 self
. assertIn ( 'default via 149.10.125.65 proto static onlink' , output
)
2727 self
. assertIn ( 'default via 149.10.124.64 proto static' , output
)
2728 self
. assertIn ( 'default proto static' , output
)
2730 print ( '### ip -4 route show table local dev dummy98' )
2731 output
= check_output ( 'ip -4 route show table local dev dummy98' )
2733 self
. assertIn ( 'local 149.10.123.1 proto static scope host' , output
)
2734 self
. assertIn ( 'anycast 149.10.123.2 proto static scope link' , output
)
2735 self
. assertIn ( 'broadcast 149.10.123.3 proto static scope link' , output
)
2737 print ( '### ip -4 route show type blackhole' )
2738 output
= check_output ( 'ip -4 route show type blackhole' )
2740 self
. assertIn ( 'blackhole 202.54.1.2 proto static' , output
)
2742 print ( '### ip -4 route show type unreachable' )
2743 output
= check_output ( 'ip -4 route show type unreachable' )
2745 self
. assertIn ( 'unreachable 202.54.1.3 proto static' , output
)
2747 print ( '### ip -4 route show type prohibit' )
2748 output
= check_output ( 'ip -4 route show type prohibit' )
2750 self
. assertIn ( 'prohibit 202.54.1.4 proto static' , output
)
2752 print ( '### ip -6 route show type blackhole' )
2753 output
= check_output ( 'ip -6 route show type blackhole' )
2755 self
. assertIn ( 'blackhole 2001:1234:5678::2 dev lo proto static' , output
)
2757 print ( '### ip -6 route show type unreachable' )
2758 output
= check_output ( 'ip -6 route show type unreachable' )
2760 self
. assertIn ( 'unreachable 2001:1234:5678::3 dev lo proto static' , output
)
2762 print ( '### ip -6 route show type prohibit' )
2763 output
= check_output ( 'ip -6 route show type prohibit' )
2765 self
. assertIn ( 'prohibit 2001:1234:5678::4 dev lo proto static' , output
)
2767 print ( '### ip route show 192.168.10.1' )
2768 output
= check_output ( 'ip route show 192.168.10.1' )
2770 self
. assertIn ( '192.168.10.1 proto static' , output
)
2771 self
. assertIn ( 'nexthop via 149.10.124.59 dev dummy98 weight 10' , output
)
2772 self
. assertIn ( 'nexthop via 149.10.124.60 dev dummy98 weight 5' , output
)
2774 print ( '### ip route show 192.168.10.2' )
2775 output
= check_output ( 'ip route show 192.168.10.2' )
2777 # old ip command does not show IPv6 gateways...
2778 self
. assertIn ( '192.168.10.2 proto static' , output
)
2779 self
. assertIn ( 'nexthop' , output
)
2780 self
. assertIn ( 'dev dummy98 weight 10' , output
)
2781 self
. assertIn ( 'dev dummy98 weight 5' , output
)
2783 print ( '### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff' )
2784 output
= check_output ( 'ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff' )
2786 # old ip command does not show 'nexthop' keyword and weight...
2787 self
. assertIn ( '2001:1234:5:7fff:ff:ff:ff:ff' , output
)
2788 self
. assertIn ( 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98' , output
)
2789 self
. assertIn ( 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98' , output
)
2791 # TODO: check json string
2792 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
2794 copy_network_unit ( '25-address-static.network' )
2796 self
. wait_online ([ 'dummy98:routable' ])
2798 # check all routes managed by Manager are removed
2799 print ( '### ip -4 route show type blackhole' )
2800 output
= check_output ( 'ip -4 route show type blackhole' )
2802 self
. assertEqual ( output
, '' )
2804 print ( '### ip -4 route show type unreachable' )
2805 output
= check_output ( 'ip -4 route show type unreachable' )
2807 self
. assertEqual ( output
, '' )
2809 print ( '### ip -4 route show type prohibit' )
2810 output
= check_output ( 'ip -4 route show type prohibit' )
2812 self
. assertEqual ( output
, '' )
2814 print ( '### ip -6 route show type blackhole' )
2815 output
= check_output ( 'ip -6 route show type blackhole' )
2817 self
. assertEqual ( output
, '' )
2819 print ( '### ip -6 route show type unreachable' )
2820 output
= check_output ( 'ip -6 route show type unreachable' )
2822 self
. assertEqual ( output
, '' )
2824 print ( '### ip -6 route show type prohibit' )
2825 output
= check_output ( 'ip -6 route show type prohibit' )
2827 self
. assertEqual ( output
, '' )
2829 remove_network_unit ( '25-address-static.network' )
2831 self
. wait_online ([ 'dummy98:routable' ])
2833 # check all routes managed by Manager are reconfigured
2834 print ( '### ip -4 route show type blackhole' )
2835 output
= check_output ( 'ip -4 route show type blackhole' )
2837 self
. assertIn ( 'blackhole 202.54.1.2 proto static' , output
)
2839 print ( '### ip -4 route show type unreachable' )
2840 output
= check_output ( 'ip -4 route show type unreachable' )
2842 self
. assertIn ( 'unreachable 202.54.1.3 proto static' , output
)
2844 print ( '### ip -4 route show type prohibit' )
2845 output
= check_output ( 'ip -4 route show type prohibit' )
2847 self
. assertIn ( 'prohibit 202.54.1.4 proto static' , output
)
2849 print ( '### ip -6 route show type blackhole' )
2850 output
= check_output ( 'ip -6 route show type blackhole' )
2852 self
. assertIn ( 'blackhole 2001:1234:5678::2 dev lo proto static' , output
)
2854 print ( '### ip -6 route show type unreachable' )
2855 output
= check_output ( 'ip -6 route show type unreachable' )
2857 self
. assertIn ( 'unreachable 2001:1234:5678::3 dev lo proto static' , output
)
2859 print ( '### ip -6 route show type prohibit' )
2860 output
= check_output ( 'ip -6 route show type prohibit' )
2862 self
. assertIn ( 'prohibit 2001:1234:5678::4 dev lo proto static' , output
)
2864 remove_link ( 'dummy98' )
2867 # check all routes managed by Manager are removed
2868 print ( '### ip -4 route show type blackhole' )
2869 output
= check_output ( 'ip -4 route show type blackhole' )
2871 self
. assertEqual ( output
, '' )
2873 print ( '### ip -4 route show type unreachable' )
2874 output
= check_output ( 'ip -4 route show type unreachable' )
2876 self
. assertEqual ( output
, '' )
2878 print ( '### ip -4 route show type prohibit' )
2879 output
= check_output ( 'ip -4 route show type prohibit' )
2881 self
. assertEqual ( output
, '' )
2883 print ( '### ip -6 route show type blackhole' )
2884 output
= check_output ( 'ip -6 route show type blackhole' )
2886 self
. assertEqual ( output
, '' )
2888 print ( '### ip -6 route show type unreachable' )
2889 output
= check_output ( 'ip -6 route show type unreachable' )
2891 self
. assertEqual ( output
, '' )
2893 print ( '### ip -6 route show type prohibit' )
2894 output
= check_output ( 'ip -6 route show type prohibit' )
2896 self
. assertEqual ( output
, '' )
2900 def test_route_static ( self
):
2902 for manage_foreign_routes
in [ True , False ]:
2908 print ( f
'### test_route_static(manage_foreign_routes= {manage_foreign_routes} )' )
2909 with self
. subTest ( manage_foreign_routes
= manage_foreign_routes
):
2910 self
._ test
_ route
_ static
( manage_foreign_routes
)
2912 @expectedFailureIfRTA_VIAIsNotSupported ()
2913 def test_route_via_ipv6 ( self
):
2914 copy_network_unit ( '25-route-via-ipv6.network' , '12-dummy.netdev' )
2916 self
. wait_online ([ 'dummy98:routable' ])
2918 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
2921 print ( '### ip -6 route show dev dummy98' )
2922 output
= check_output ( 'ip -6 route show dev dummy98' )
2924 self
. assertRegex ( output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static' )
2925 self
. assertRegex ( output
, '2001:1234:5:8f63::1 proto kernel' )
2927 print ( '### ip -4 route show dev dummy98' )
2928 output
= check_output ( 'ip -4 route show dev dummy98' )
2930 self
. assertRegex ( output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58' )
2931 self
. assertRegex ( output
, '149.10.124.66 via inet6 2001:1234:5:8fff:ff:ff:ff:ff proto static' )
2933 @expectedFailureIfModuleIsNotAvailable ( 'tcp_dctcp' )
2934 def test_route_congctl ( self
):
2935 copy_network_unit ( '25-route-congctl.network' , '12-dummy.netdev' )
2937 self
. wait_online ([ 'dummy98:routable' ])
2939 print ( '### ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff' )
2940 output
= check_output ( 'ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff' )
2942 self
. assertIn ( '2001:1234:5:8fff:ff:ff:ff:ff proto static' , output
)
2943 self
. assertIn ( 'congctl dctcp' , output
)
2945 print ( '### ip -4 route show dev dummy98 149.10.124.66' )
2946 output
= check_output ( 'ip -4 route show dev dummy98 149.10.124.66' )
2948 self
. assertIn ( '149.10.124.66 proto static' , output
)
2949 self
. assertIn ( 'congctl dctcp' , output
)
2951 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
2952 def test_route_vrf ( self
):
2953 copy_network_unit ( '25-route-vrf.network' , '12-dummy.netdev' ,
2954 '25-vrf.netdev' , '25-vrf.network' )
2956 self
. wait_online ([ 'dummy98:routable' , 'vrf99:carrier' ])
2958 output
= check_output ( 'ip route show vrf vrf99' )
2960 self
. assertRegex ( output
, 'default via 192.168.100.1' )
2962 output
= check_output ( 'ip route show' )
2964 self
. assertNotRegex ( output
, 'default via 192.168.100.1' )
2966 def test_gateway_reconfigure ( self
):
2967 copy_network_unit ( '25-gateway-static.network' , '12-dummy.netdev' )
2969 self
. wait_online ([ 'dummy98:routable' ])
2970 print ( '### ip -4 route show dev dummy98 default' )
2971 output
= check_output ( 'ip -4 route show dev dummy98 default' )
2973 self
. assertIn ( 'default via 149.10.124.59 proto static' , output
)
2974 self
. assertNotIn ( '149.10.124.60' , output
)
2976 remove_network_unit ( '25-gateway-static.network' )
2977 copy_network_unit ( '25-gateway-next-static.network' )
2979 self
. wait_online ([ 'dummy98:routable' ])
2980 print ( '### ip -4 route show dev dummy98 default' )
2981 output
= check_output ( 'ip -4 route show dev dummy98 default' )
2983 self
. assertNotIn ( '149.10.124.59' , output
)
2984 self
. assertIn ( 'default via 149.10.124.60 proto static' , output
)
2986 def test_ip_route_ipv6_src_route ( self
):
2987 # a dummy device does not make the addresses go through tentative state, so we
2988 # reuse a bond from an earlier test, which does make the addresses go through
2989 # tentative state, and do our test on that
2990 copy_network_unit ( '23-active-slave.network' , '25-route-ipv6-src.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
2992 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:routable' ])
2994 output
= check_output ( 'ip -6 route list dev bond199' )
2996 self
. assertIn ( 'abcd::/16 via 2001:1234:56:8f63::1:1 proto static src 2001:1234:56:8f63::2' , output
)
2998 def test_route_preferred_source_with_existing_address ( self
):
3000 copy_network_unit ( '25-route-preferred-source.network' , '12-dummy.netdev' )
3005 networkctl_reconfigure ( 'dummy98' )
3007 self
. wait_online ([ 'dummy98:routable' ])
3009 output
= check_output ( 'ip -6 route list dev dummy98' )
3011 self
. assertIn ( 'abcd::/16 via 2001:1234:56:8f63::1:1 proto static src 2001:1234:56:8f63::1' , output
)
3013 def test_ip_link_mac_address ( self
):
3014 copy_network_unit ( '25-address-link-section.network' , '12-dummy.netdev' )
3016 self
. wait_online ([ 'dummy98:degraded' ])
3018 output
= check_output ( 'ip link show dummy98' )
3020 self
. assertRegex ( output
, '00:01:02:aa:bb:cc' )
3022 def test_ip_link_unmanaged ( self
):
3023 copy_network_unit ( '25-link-section-unmanaged.network' , '12-dummy.netdev' )
3026 self
. wait_operstate ( 'dummy98' , 'off' , setup_state
= 'unmanaged' )
3028 def test_ipv6_address_label ( self
):
3029 copy_network_unit ( '25-ipv6-address-label-section.network' , '12-dummy.netdev' )
3031 self
. wait_online ([ 'dummy98:degraded' ])
3033 output
= check_output ( 'ip addrlabel list' )
3035 self
. assertRegex ( output
, '2004:da8:1::/64' )
3037 def test_ipv6_proxy_ndp ( self
):
3038 copy_network_unit ( '25-ipv6-proxy-ndp.network' , '12-dummy.netdev' )
3041 self
. wait_online ([ 'dummy98:routable' ])
3043 output
= check_output ( 'ip neighbor show proxy dev dummy98' )
3045 for i
in range ( 1 , 5 ):
3046 self
. assertRegex ( output
, f
'2607:5300:203:5215: {i} ::1 *proxy' )
3048 def test_neighbor_section ( self
):
3049 copy_network_unit ( '25-neighbor-section.network' , '12-dummy.netdev' )
3051 self
. wait_online ([ 'dummy98:degraded' ], timeout
= '40s' )
3053 print ( '### ip neigh list dev dummy98' )
3054 output
= check_output ( 'ip neigh list dev dummy98' )
3056 self
. assertRegex ( output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT' )
3057 self
. assertRegex ( output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT' )
3059 # TODO: check json string
3060 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3062 def test_neighbor_reconfigure ( self
):
3063 copy_network_unit ( '25-neighbor-section.network' , '12-dummy.netdev' )
3065 self
. wait_online ([ 'dummy98:degraded' ], timeout
= '40s' )
3067 print ( '### ip neigh list dev dummy98' )
3068 output
= check_output ( 'ip neigh list dev dummy98' )
3070 self
. assertRegex ( output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT' )
3071 self
. assertRegex ( output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT' )
3073 remove_network_unit ( '25-neighbor-section.network' )
3074 copy_network_unit ( '25-neighbor-next.network' )
3076 self
. wait_online ([ 'dummy98:degraded' ], timeout
= '40s' )
3077 print ( '### ip neigh list dev dummy98' )
3078 output
= check_output ( 'ip neigh list dev dummy98' )
3080 self
. assertNotRegex ( output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT' )
3081 self
. assertRegex ( output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT' )
3082 self
. assertNotRegex ( output
, '2004:da8:1::1.*PERMANENT' )
3084 def test_neighbor_gre ( self
):
3085 copy_network_unit ( '25-neighbor-ip.network' , '25-neighbor-ipv6.network' , '25-neighbor-ip-dummy.network' ,
3086 '12-dummy.netdev' , '25-gre-tunnel-remote-any.netdev' , '25-ip6gre-tunnel-remote-any.netdev' )
3088 self
. wait_online ([ 'dummy98:degraded' , 'gretun97:routable' , 'ip6gretun97:routable' ], timeout
= '40s' )
3090 output
= check_output ( 'ip neigh list dev gretun97' )
3092 self
. assertRegex ( output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT' )
3094 output
= check_output ( 'ip neigh list dev ip6gretun97' )
3096 self
. assertRegex ( output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT' )
3098 # TODO: check json string
3099 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3101 def test_link_local_addressing ( self
):
3102 copy_network_unit ( '25-link-local-addressing-yes.network' , '11-dummy.netdev' ,
3103 '25-link-local-addressing-no.network' , '12-dummy.netdev' )
3105 self
. wait_online ([ 'test1:degraded' , 'dummy98:carrier' ])
3107 output
= check_output ( 'ip address show dev test1' )
3109 self
. assertRegex ( output
, 'inet .* scope link' )
3110 self
. assertRegex ( output
, 'inet6 .* scope link' )
3112 output
= check_output ( 'ip address show dev dummy98' )
3114 self
. assertNotRegex ( output
, 'inet6* .* scope link' )
3116 # Documentation/networking/ip-sysctl.txt
3118 # addr_gen_mode - INTEGER
3119 # Defines how link-local and autoconf addresses are generated.
3121 # 0: generate address based on EUI64 (default)
3122 # 1: do no generate a link-local address, use EUI64 for addresses generated
3124 # 2: generate stable privacy addresses, using the secret from
3125 # stable_secret (RFC7217)
3126 # 3: generate stable privacy addresses, using a random secret if unset
3128 self
. check_ipv6_sysctl_attr ( 'test1' , 'stable_secret' , '0123:4567:89ab:cdef:0123:4567:89ab:cdef' )
3129 self
. check_ipv6_sysctl_attr ( 'test1' , 'addr_gen_mode' , '2' )
3130 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'addr_gen_mode' , '1' )
3132 def test_link_local_addressing_ipv6ll ( self
):
3133 copy_network_unit ( '26-link-local-addressing-ipv6.network' , '12-dummy.netdev' )
3135 self
. wait_online ([ 'dummy98:degraded' ])
3137 # An IPv6LL address exists by default.
3138 output
= check_output ( 'ip address show dev dummy98' )
3140 self
. assertRegex ( output
, 'inet6 .* scope link' )
3142 copy_network_unit ( '25-link-local-addressing-no.network' )
3144 self
. wait_online ([ 'dummy98:carrier' ])
3146 # Check if the IPv6LL address is removed.
3147 output
= check_output ( 'ip address show dev dummy98' )
3149 self
. assertNotRegex ( output
, 'inet6 .* scope link' )
3151 remove_network_unit ( '25-link-local-addressing-no.network' )
3153 self
. wait_online ([ 'dummy98:degraded' ])
3155 # Check if a new IPv6LL address is assigned.
3156 output
= check_output ( 'ip address show dev dummy98' )
3158 self
. assertRegex ( output
, 'inet6 .* scope link' )
3160 def test_sysctl ( self
):
3161 copy_networkd_conf_dropin ( '25-global-ipv6-privacy-extensions.conf' )
3162 copy_network_unit ( '25-sysctl.network' , '12-dummy.netdev' , copy_dropins
= False )
3164 self
. wait_online ([ 'dummy98:degraded' ])
3166 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
3167 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'use_tempaddr' , '1' )
3168 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'dad_transmits' , '3' )
3169 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'hop_limit' , '5' )
3170 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'proxy_ndp' , '1' )
3171 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
3172 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'proxy_arp' , '1' )
3173 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'accept_local' , '1' )
3175 copy_network_unit ( '25-sysctl.network.d/25-ipv6-privacy-extensions.conf' )
3177 self
. wait_online ([ 'dummy98:degraded' ])
3179 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'use_tempaddr' , '2' )
3181 def test_sysctl_disable_ipv6 ( self
):
3182 copy_network_unit ( '25-sysctl-disable-ipv6.network' , '12-dummy.netdev' )
3184 print ( '## Disable ipv6' )
3185 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=1' )
3186 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=1' )
3189 self
. wait_online ([ 'dummy98:routable' ])
3191 output
= check_output ( 'ip -4 address show dummy98' )
3193 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3194 output
= check_output ( 'ip -6 address show dummy98' )
3196 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3197 self
. assertRegex ( output
, 'inet6 .* scope link' )
3198 output
= check_output ( 'ip -4 route show dev dummy98' )
3200 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3201 output
= check_output ( 'ip -6 route show default' )
3203 self
. assertRegex ( output
, 'default' )
3204 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3206 remove_link ( 'dummy98' )
3208 print ( '## Enable ipv6' )
3209 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=0' )
3210 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=0' )
3213 self
. wait_online ([ 'dummy98:routable' ])
3215 output
= check_output ( 'ip -4 address show dummy98' )
3217 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3218 output
= check_output ( 'ip -6 address show dummy98' )
3220 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3221 self
. assertRegex ( output
, 'inet6 .* scope link' )
3222 output
= check_output ( 'ip -4 route show dev dummy98' )
3224 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3225 output
= check_output ( 'ip -6 route show default' )
3227 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3229 def test_bind_carrier ( self
):
3230 copy_network_unit ( '25-bind-carrier.network' , '11-dummy.netdev' )
3233 # no bound interface.
3234 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
3235 output
= check_output ( 'ip address show test1' )
3237 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3238 self
. assertIn ( 'DOWN' , output
)
3239 self
. assertNotIn ( '192.168.10' , output
)
3241 # add one bound interface. The interface will be up.
3242 check_output ( 'ip link add dummy98 type dummy' )
3243 check_output ( 'ip link set dummy98 up' )
3244 self
. wait_online ([ 'test1:routable' ])
3245 output
= check_output ( 'ip address show test1' )
3247 self
. assertIn ( 'UP,LOWER_UP' , output
)
3248 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3250 # add another bound interface. The interface is still up.
3251 check_output ( 'ip link add dummy99 type dummy' )
3252 check_output ( 'ip link set dummy99 up' )
3253 self
. wait_operstate ( 'dummy99' , 'degraded' , setup_state
= 'unmanaged' )
3254 output
= check_output ( 'ip address show test1' )
3256 self
. assertIn ( 'UP,LOWER_UP' , output
)
3257 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3259 # remove one of the bound interfaces. The interface is still up
3260 remove_link ( 'dummy98' )
3261 output
= check_output ( 'ip address show test1' )
3263 self
. assertIn ( 'UP,LOWER_UP' , output
)
3264 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3266 # bring down the remaining bound interface. The interface will be down.
3267 check_output ( 'ip link set dummy99 down' )
3268 self
. wait_operstate ( 'test1' , 'off' )
3269 self
. wait_address_dropped ( 'test1' , r
'192.168.10' , ipv
= '-4' , timeout_sec
= 10 )
3270 output
= check_output ( 'ip address show test1' )
3272 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3273 self
. assertIn ( 'DOWN' , output
)
3274 self
. assertNotIn ( '192.168.10' , output
)
3276 # bring up the bound interface. The interface will be up.
3277 check_output ( 'ip link set dummy99 up' )
3278 self
. wait_online ([ 'test1:routable' ])
3279 output
= check_output ( 'ip address show test1' )
3281 self
. assertIn ( 'UP,LOWER_UP' , output
)
3282 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3284 # remove the remaining bound interface. The interface will be down.
3285 remove_link ( 'dummy99' )
3286 self
. wait_operstate ( 'test1' , 'off' )
3287 self
. wait_address_dropped ( 'test1' , r
'192.168.10' , ipv
= '-4' , timeout_sec
= 10 )
3288 output
= check_output ( 'ip address show test1' )
3290 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3291 self
. assertIn ( 'DOWN' , output
)
3292 self
. assertNotIn ( '192.168.10' , output
)
3294 # re-add one bound interface. The interface will be up.
3295 check_output ( 'ip link add dummy98 type dummy' )
3296 check_output ( 'ip link set dummy98 up' )
3297 self
. wait_online ([ 'test1:routable' ])
3298 output
= check_output ( 'ip address show test1' )
3300 self
. assertIn ( 'UP,LOWER_UP' , output
)
3301 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3303 def _test_activation_policy ( self
, interface
, test
):
3304 conffile
= '25-activation-policy.network'
3306 conffile
= f
' {conffile} .d/ {test} .conf'
3307 if interface
== 'vlan99' :
3308 copy_network_unit ( '21-vlan.netdev' , '21-vlan-test1.network' )
3309 copy_network_unit ( '11-dummy.netdev' , conffile
, copy_dropins
= False )
3312 always
= test
. startswith ( 'always' )
3313 initial_up
= test
!= 'manual' and not test
. endswith ( 'down' ) # note: default is up
3314 expect_up
= initial_up
3315 next_up
= not expect_up
3317 if test
. endswith ( 'down' ):
3318 self
. wait_activated ( interface
)
3320 for iteration
in range ( 4 ):
3321 with self
. subTest ( iteration
= iteration
, expect_up
= expect_up
):
3322 operstate
= 'routable' if expect_up
else 'off'
3323 setup_state
= 'configured' if expect_up
else ( 'configuring' if iteration
== 0 else None )
3324 self
. wait_operstate ( interface
, operstate
, setup_state
= setup_state
, setup_timeout
= 20 )
3327 self
. assertIn ( 'UP' , check_output ( f
'ip link show {interface} ' ))
3328 self
. assertIn ( '192.168.10.30/24' , check_output ( f
'ip address show {interface} ' ))
3329 self
. assertIn ( 'default via 192.168.10.1' , check_output ( f
'ip route show dev {interface} ' ))
3331 self
. assertIn ( 'DOWN' , check_output ( f
'ip link show {interface} ' ))
3334 check_output ( f
'ip link set dev {interface} up' )
3336 check_output ( f
'ip link set dev {interface} down' )
3337 expect_up
= initial_up
if always
else next_up
3338 next_up
= not next_up
3342 def test_activation_policy ( self
):
3344 for interface
in [ 'test1' , 'vlan99' ]:
3345 for test
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , '' ]:
3351 print ( f
'### test_activation_policy(interface= {interface} , test= {test} )' )
3352 with self
. subTest ( interface
= interface
, test
= test
):
3353 self
._ test
_ activation
_ policy
( interface
, test
)
3355 def _test_activation_policy_required_for_online ( self
, policy
, required
):
3356 conffile
= '25-activation-policy.network'
3357 units
= [ '11-dummy.netdev' , '12-dummy.netdev' , '12-dummy.network' , conffile
]
3359 units
+= [ f
' {conffile} .d/ {policy} .conf' ]
3361 units
+= [ f
' {conffile} .d/required- {required} .conf' ]
3362 copy_network_unit (* units
, copy_dropins
= False )
3365 if policy
. endswith ( 'down' ):
3366 self
. wait_activated ( 'test1' )
3368 if policy
. endswith ( 'down' ) or policy
== 'manual' :
3369 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
3371 self
. wait_online ([ 'test1' ])
3373 if policy
== 'always-down' :
3374 # if always-down, required for online is forced to no
3377 # otherwise if required for online is specified, it should match that
3378 expected
= required
== 'yes'
3380 # otherwise if only policy specified, required for online defaults to
3381 # true if policy is up, always-up, or bound
3382 expected
= policy
. endswith ( 'up' ) or policy
== 'bound'
3384 # default is true, if neither are specified
3387 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'test1' , env
= env
)
3390 yesno
= 'yes' if expected
else 'no'
3391 self
. assertRegex ( output
, f
'Required For Online: {yesno} ' )
3393 def test_activation_policy_required_for_online ( self
):
3395 for policy
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , 'bound' , '' ]:
3396 for required
in [ 'yes' , 'no' , '' ]:
3402 print ( f
'### test_activation_policy_required_for_online(policy= {policy} , required= {required} )' )
3403 with self
. subTest ( policy
= policy
, required
= required
):
3404 self
._ test
_ activation
_ policy
_ required
_ for
_ online
( policy
, required
)
3406 def test_domain ( self
):
3407 copy_network_unit ( '12-dummy.netdev' , '24-search-domain.network' )
3409 self
. wait_online ([ 'dummy98:routable' ])
3411 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'dummy98' , env
= env
)
3413 self
. assertRegex ( output
, 'Address: 192.168.42.100' )
3414 self
. assertRegex ( output
, 'DNS: 192.168.42.1' )
3415 self
. assertRegex ( output
, 'Search Domains: one' )
3417 def test_keep_configuration_static ( self
):
3418 check_output ( 'ip link add name dummy98 type dummy' )
3419 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
3420 check_output ( 'ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500' )
3421 output
= check_output ( 'ip address show dummy98' )
3423 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
3424 self
. assertRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
3425 output
= check_output ( 'ip route show dev dummy98' )
3428 copy_network_unit ( '24-keep-configuration-static.network' )
3430 self
. wait_online ([ 'dummy98:routable' ])
3432 output
= check_output ( 'ip address show dummy98' )
3434 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
3435 self
. assertNotRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
3437 @expectedFailureIfNexthopIsNotAvailable ()
3438 def test_nexthop ( self
):
3439 def check_nexthop ( self
):
3440 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
3442 output
= check_output ( 'ip nexthop list dev veth99' )
3444 self
. assertIn ( 'id 1 via 192.168.5.1 dev veth99' , output
)
3445 self
. assertIn ( 'id 2 via 2001:1234:5:8f63::2 dev veth99' , output
)
3446 self
. assertIn ( 'id 3 dev veth99' , output
)
3447 self
. assertIn ( 'id 4 dev veth99' , output
)
3448 self
. assertRegex ( output
, 'id 5 via 192.168.10.1 dev veth99 .*onlink' )
3449 self
. assertIn ( 'id 8 via fe80:0:222:4dff:ff:ff:ff:ff dev veth99' , output
)
3450 self
. assertRegex ( output
, r
'id [0-9]* via 192.168.5.2 dev veth99' )
3452 output
= check_output ( 'ip nexthop list dev dummy98' )
3454 self
. assertIn ( 'id 20 via 192.168.20.1 dev dummy98' , output
)
3456 # kernel manages blackhole nexthops on lo
3457 output
= check_output ( 'ip nexthop list dev lo' )
3459 self
. assertIn ( 'id 6 blackhole' , output
)
3460 self
. assertIn ( 'id 7 blackhole' , output
)
3462 # group nexthops are shown with -0 option
3463 output
= check_output ( 'ip -0 nexthop list id 21' )
3465 self
. assertRegex ( output
, r
'id 21 group (1,3/20|20/1,3)' )
3467 output
= check_output ( 'ip route show dev veth99 10.10.10.10' )
3469 self
. assertEqual ( '10.10.10.10 nhid 1 via 192.168.5.1 proto static' , output
)
3471 output
= check_output ( 'ip route show dev veth99 10.10.10.11' )
3473 self
. assertEqual ( '10.10.10.11 nhid 2 via inet6 2001:1234:5:8f63::2 proto static' , output
)
3475 output
= check_output ( 'ip route show dev veth99 10.10.10.12' )
3477 self
. assertEqual ( '10.10.10.12 nhid 5 via 192.168.10.1 proto static onlink' , output
)
3479 output
= check_output ( 'ip -6 route show dev veth99 2001:1234:5:8f62::1' )
3481 self
. assertEqual ( '2001:1234:5:8f62::1 nhid 2 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium' , output
)
3483 output
= check_output ( 'ip route show 10.10.10.13' )
3485 self
. assertEqual ( 'blackhole 10.10.10.13 nhid 6 dev lo proto static' , output
)
3487 output
= check_output ( 'ip -6 route show 2001:1234:5:8f62::2' )
3489 self
. assertEqual ( 'blackhole 2001:1234:5:8f62::2 nhid 7 dev lo proto static metric 1024 pref medium' , output
)
3491 output
= check_output ( 'ip route show 10.10.10.14' )
3493 self
. assertIn ( '10.10.10.14 nhid 21 proto static' , output
)
3494 self
. assertIn ( 'nexthop via 192.168.20.1 dev dummy98 weight 1' , output
)
3495 self
. assertIn ( 'nexthop via 192.168.5.1 dev veth99 weight 3' , output
)
3497 # TODO: check json string
3498 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3500 copy_network_unit ( '25-nexthop.network' , '25-veth.netdev' , '25-veth-peer.network' ,
3501 '12-dummy.netdev' , '25-nexthop-dummy.network' )
3506 remove_network_unit ( '25-nexthop.network' )
3507 copy_network_unit ( '25-nexthop-nothing.network' )
3509 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
3511 output
= check_output ( 'ip nexthop list dev veth99' )
3513 self
. assertEqual ( output
, '' )
3514 output
= check_output ( 'ip nexthop list dev lo' )
3516 self
. assertEqual ( output
, '' )
3518 remove_network_unit ( '25-nexthop-nothing.network' )
3519 copy_network_unit ( '25-nexthop.network' )
3520 networkctl_reconfigure ( 'dummy98' )
3525 remove_link ( 'veth99' )
3528 output
= check_output ( 'ip nexthop list dev lo' )
3530 self
. assertEqual ( output
, '' )
3532 class NetworkdTCTests ( unittest
. TestCase
, Utilities
):
3540 @expectedFailureIfModuleIsNotAvailable ( 'sch_cake' )
3541 def test_qdisc_cake ( self
):
3542 copy_network_unit ( '25-qdisc-cake.network' , '12-dummy.netdev' )
3544 self
. wait_online ([ 'dummy98:routable' ])
3546 output
= check_output ( 'tc qdisc show dev dummy98' )
3548 self
. assertIn ( 'qdisc cake 3a: root' , output
)
3549 self
. assertIn ( 'bandwidth 500Mbit' , output
)
3550 self
. assertIn ( 'autorate-ingress' , output
)
3551 self
. assertIn ( 'diffserv8' , output
)
3552 self
. assertIn ( 'dual-dsthost' , output
)
3553 self
. assertIn ( ' nat' , output
)
3554 self
. assertIn ( ' wash' , output
)
3555 self
. assertIn ( ' split-gso' , output
)
3556 self
. assertIn ( ' raw' , output
)
3557 self
. assertIn ( ' atm' , output
)
3558 self
. assertIn ( 'overhead 128' , output
)
3559 self
. assertIn ( 'mpu 20' , output
)
3560 self
. assertIn ( 'fwmark 0xff00' , output
)
3561 self
. assertIn ( 'rtt 1s' , output
)
3562 self
. assertIn ( 'ack-filter-aggressive' , output
)
3564 @expectedFailureIfModuleIsNotAvailable ( 'sch_codel' )
3565 def test_qdisc_codel ( self
):
3566 copy_network_unit ( '25-qdisc-codel.network' , '12-dummy.netdev' )
3568 self
. wait_online ([ 'dummy98:routable' ])
3570 output
= check_output ( 'tc qdisc show dev dummy98' )
3572 self
. assertRegex ( output
, 'qdisc codel 33: root' )
3573 self
. assertRegex ( output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn' )
3575 @expectedFailureIfModuleIsNotAvailable ( 'sch_drr' )
3576 def test_qdisc_drr ( self
):
3577 copy_network_unit ( '25-qdisc-drr.network' , '12-dummy.netdev' )
3579 self
. wait_online ([ 'dummy98:routable' ])
3581 output
= check_output ( 'tc qdisc show dev dummy98' )
3583 self
. assertRegex ( output
, 'qdisc drr 2: root' )
3584 output
= check_output ( 'tc class show dev dummy98' )
3586 self
. assertRegex ( output
, 'class drr 2:30 root quantum 2000b' )
3588 @expectedFailureIfModuleIsNotAvailable ( 'sch_ets' )
3589 def test_qdisc_ets ( self
):
3590 copy_network_unit ( '25-qdisc-ets.network' , '12-dummy.netdev' )
3592 self
. wait_online ([ 'dummy98:routable' ])
3594 output
= check_output ( 'tc qdisc show dev dummy98' )
3597 self
. assertRegex ( output
, 'qdisc ets 3a: root' )
3598 self
. assertRegex ( output
, 'bands 10 strict 3' )
3599 self
. assertRegex ( output
, 'quanta 1 2 3 4 5' )
3600 self
. assertRegex ( output
, 'priomap 3 4 5 6 7' )
3602 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq' )
3603 def test_qdisc_fq ( self
):
3604 copy_network_unit ( '25-qdisc-fq.network' , '12-dummy.netdev' )
3606 self
. wait_online ([ 'dummy98:routable' ])
3608 output
= check_output ( 'tc qdisc show dev dummy98' )
3610 self
. assertRegex ( output
, 'qdisc fq 32: root' )
3611 self
. assertRegex ( output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511' )
3612 self
. assertRegex ( output
, 'quantum 1500' )
3613 self
. assertRegex ( output
, 'initial_quantum 13000' )
3614 self
. assertRegex ( output
, 'maxrate 1Mbit' )
3616 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_codel' )
3617 def test_qdisc_fq_codel ( self
):
3618 copy_network_unit ( '25-qdisc-fq_codel.network' , '12-dummy.netdev' )
3620 self
. wait_online ([ 'dummy98:routable' ])
3622 output
= check_output ( 'tc qdisc show dev dummy98' )
3624 self
. assertRegex ( output
, 'qdisc fq_codel 34: root' )
3625 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' )
3627 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_pie' )
3628 def test_qdisc_fq_pie ( self
):
3629 copy_network_unit ( '25-qdisc-fq_pie.network' , '12-dummy.netdev' )
3631 self
. wait_online ([ 'dummy98:routable' ])
3633 output
= check_output ( 'tc qdisc show dev dummy98' )
3636 self
. assertRegex ( output
, 'qdisc fq_pie 3a: root' )
3637 self
. assertRegex ( output
, 'limit 200000p' )
3639 @expectedFailureIfModuleIsNotAvailable ( 'sch_gred' )
3640 def test_qdisc_gred ( self
):
3641 copy_network_unit ( '25-qdisc-gred.network' , '12-dummy.netdev' )
3643 self
. wait_online ([ 'dummy98:routable' ])
3645 output
= check_output ( 'tc qdisc show dev dummy98' )
3647 self
. assertRegex ( output
, 'qdisc gred 38: root' )
3648 self
. assertRegex ( output
, 'vqs 12 default 10 grio' )
3650 @expectedFailureIfModuleIsNotAvailable ( 'sch_hhf' )
3651 def test_qdisc_hhf ( self
):
3652 copy_network_unit ( '25-qdisc-hhf.network' , '12-dummy.netdev' )
3654 self
. wait_online ([ 'dummy98:routable' ])
3656 output
= check_output ( 'tc qdisc show dev dummy98' )
3658 self
. assertRegex ( output
, 'qdisc hhf 3a: root' )
3659 self
. assertRegex ( output
, 'limit 1022p' )
3661 @expectedFailureIfModuleIsNotAvailable ( 'sch_htb' )
3662 def test_qdisc_htb_fifo ( self
):
3663 copy_network_unit ( '25-qdisc-htb-fifo.network' , '12-dummy.netdev' )
3665 self
. wait_online ([ 'dummy98:routable' ])
3667 output
= check_output ( 'tc qdisc show dev dummy98' )
3669 self
. assertRegex ( output
, 'qdisc htb 2: root' )
3670 self
. assertRegex ( output
, r
'default (0x30|30)' )
3672 self
. assertRegex ( output
, 'qdisc pfifo 37: parent 2:37' )
3673 self
. assertRegex ( output
, 'limit 100000p' )
3675 self
. assertRegex ( output
, 'qdisc bfifo 3a: parent 2:3a' )
3676 self
. assertRegex ( output
, 'limit 1000000' )
3678 self
. assertRegex ( output
, 'qdisc pfifo_head_drop 3b: parent 2:3b' )
3679 self
. assertRegex ( output
, 'limit 1023p' )
3681 self
. assertRegex ( output
, 'qdisc pfifo_fast 3c: parent 2:3c' )
3683 output
= check_output ( 'tc -d class show dev dummy98' )
3685 # Here (:|prio) is a workaround for a bug in iproute2 v6.2.0 caused by
3686 # https://github.com/shemminger/iproute2/commit/010a8388aea11e767ba3a2506728b9ad9760df0e
3687 # which is fixed in v6.3.0 by
3688 # https://github.com/shemminger/iproute2/commit/4e0e56e0ef05387f7f5d8ab41fe6ec6a1897b26d
3689 self
. assertRegex ( output
, 'class htb 2:37 root leaf 37(:|prio) ' )
3690 self
. assertRegex ( output
, 'class htb 2:3a root leaf 3a(:|prio) ' )
3691 self
. assertRegex ( output
, 'class htb 2:3b root leaf 3b(:|prio) ' )
3692 self
. assertRegex ( output
, 'class htb 2:3c root leaf 3c(:|prio) ' )
3693 self
. assertRegex ( output
, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit' )
3694 self
. assertRegex ( output
, 'burst 123456' )
3695 self
. assertRegex ( output
, 'cburst 123457' )
3697 @expectedFailureIfModuleIsNotAvailable ( 'sch_ingress' )
3698 def test_qdisc_ingress ( self
):
3699 copy_network_unit ( '25-qdisc-clsact.network' , '12-dummy.netdev' ,
3700 '25-qdisc-ingress.network' , '11-dummy.netdev' )
3702 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' ])
3704 output
= check_output ( 'tc qdisc show dev dummy98' )
3706 self
. assertRegex ( output
, 'qdisc clsact' )
3708 output
= check_output ( 'tc qdisc show dev test1' )
3710 self
. assertRegex ( output
, 'qdisc ingress' )
3712 @expectedFailureIfModuleIsNotAvailable ( 'sch_netem' )
3713 def test_qdisc_netem ( self
):
3714 copy_network_unit ( '25-qdisc-netem.network' , '12-dummy.netdev' ,
3715 '25-qdisc-netem-compat.network' , '11-dummy.netdev' )
3717 self
. wait_online ([ 'dummy98:routable' , 'test1:routable' ])
3719 output
= check_output ( 'tc qdisc show dev dummy98' )
3721 self
. assertRegex ( output
, 'qdisc netem 30: root' )
3722 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
3724 output
= check_output ( 'tc qdisc show dev test1' )
3726 self
. assertRegex ( output
, 'qdisc netem [0-9a-f]*: root' )
3727 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
3729 @expectedFailureIfModuleIsNotAvailable ( 'sch_pie' )
3730 def test_qdisc_pie ( self
):
3731 copy_network_unit ( '25-qdisc-pie.network' , '12-dummy.netdev' )
3733 self
. wait_online ([ 'dummy98:routable' ])
3735 output
= check_output ( 'tc qdisc show dev dummy98' )
3737 self
. assertRegex ( output
, 'qdisc pie 3a: root' )
3738 self
. assertRegex ( output
, 'limit 200000' )
3740 @expectedFailureIfModuleIsNotAvailable ( 'sch_qfq' )
3741 def test_qdisc_qfq ( self
):
3742 copy_network_unit ( '25-qdisc-qfq.network' , '12-dummy.netdev' )
3744 self
. wait_online ([ 'dummy98:routable' ])
3746 output
= check_output ( 'tc qdisc show dev dummy98' )
3748 self
. assertRegex ( output
, 'qdisc qfq 2: root' )
3749 output
= check_output ( 'tc class show dev dummy98' )
3751 self
. assertRegex ( output
, 'class qfq 2:30 root weight 2 maxpkt 16000' )
3752 self
. assertRegex ( output
, 'class qfq 2:31 root weight 10 maxpkt 8000' )
3754 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfb' )
3755 def test_qdisc_sfb ( self
):
3756 copy_network_unit ( '25-qdisc-sfb.network' , '12-dummy.netdev' )
3758 self
. wait_online ([ 'dummy98:routable' ])
3760 output
= check_output ( 'tc qdisc show dev dummy98' )
3762 self
. assertRegex ( output
, 'qdisc sfb 39: root' )
3763 self
. assertRegex ( output
, 'limit 200000' )
3765 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfq' )
3766 def test_qdisc_sfq ( self
):
3767 copy_network_unit ( '25-qdisc-sfq.network' , '12-dummy.netdev' )
3769 self
. wait_online ([ 'dummy98:routable' ])
3771 output
= check_output ( 'tc qdisc show dev dummy98' )
3773 self
. assertRegex ( output
, 'qdisc sfq 36: root' )
3774 self
. assertRegex ( output
, 'perturb 5sec' )
3776 @expectedFailureIfModuleIsNotAvailable ( 'sch_tbf' )
3777 def test_qdisc_tbf ( self
):
3778 copy_network_unit ( '25-qdisc-tbf.network' , '12-dummy.netdev' )
3780 self
. wait_online ([ 'dummy98:routable' ])
3782 output
= check_output ( 'tc qdisc show dev dummy98' )
3784 self
. assertRegex ( output
, 'qdisc tbf 35: root' )
3785 self
. assertRegex ( output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms' )
3787 @expectedFailureIfModuleIsNotAvailable ( 'sch_teql' )
3788 def test_qdisc_teql ( self
):
3789 call_quiet ( 'rmmod sch_teql' )
3791 copy_network_unit ( '25-qdisc-teql.network' , '12-dummy.netdev' )
3793 self
. wait_links ( 'dummy98' )
3794 check_output ( 'modprobe sch_teql max_equalizers=2' )
3795 self
. wait_online ([ 'dummy98:routable' ])
3797 output
= check_output ( 'tc qdisc show dev dummy98' )
3799 self
. assertRegex ( output
, 'qdisc teql1 31: root' )
3801 class NetworkdStateFileTests ( unittest
. TestCase
, Utilities
):
3809 def test_state_file ( self
):
3810 copy_network_unit ( '12-dummy.netdev' , '25-state-file-tests.network' )
3812 self
. wait_online ([ 'dummy98:routable' ])
3814 # make link state file updated
3815 check_output (* resolvectl_cmd
, 'revert' , 'dummy98' , env
= env
)
3817 # TODO: check json string
3818 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3820 output
= read_link_state_file ( 'dummy98' )
3822 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
3823 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
3824 self
. assertIn ( 'ADMIN_STATE=configured' , output
)
3825 self
. assertIn ( 'OPER_STATE=routable' , output
)
3826 self
. assertIn ( 'REQUIRED_FOR_ONLINE=yes' , output
)
3827 self
. assertIn ( 'REQUIRED_OPER_STATE_FOR_ONLINE=routable' , output
)
3828 self
. assertIn ( 'REQUIRED_FAMILY_FOR_ONLINE=both' , output
)
3829 self
. assertIn ( 'ACTIVATION_POLICY=up' , output
)
3830 self
. assertIn ( 'NETWORK_FILE=/run/systemd/network/25-state-file-tests.network' , output
)
3831 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
3832 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
3833 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
3834 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
3835 self
. assertIn ( 'LLMNR=no' , output
)
3836 self
. assertIn ( 'MDNS=yes' , output
)
3837 self
. assertIn ( 'DNSSEC=no' , output
)
3839 check_output (* resolvectl_cmd
, 'dns' , 'dummy98' , '10.10.10.12#ccc.com' , '10.10.10.13' , '1111:2222::3333' , env
= env
)
3840 check_output (* resolvectl_cmd
, 'domain' , 'dummy98' , 'hogehogehoge' , '~foofoofoo' , env
= env
)
3841 check_output (* resolvectl_cmd
, 'llmnr' , 'dummy98' , 'yes' , env
= env
)
3842 check_output (* resolvectl_cmd
, 'mdns' , 'dummy98' , 'no' , env
= env
)
3843 check_output (* resolvectl_cmd
, 'dnssec' , 'dummy98' , 'yes' , env
= env
)
3844 check_output (* timedatectl_cmd
, 'ntp-servers' , 'dummy98' , '2.fedora.pool.ntp.org' , '3.fedora.pool.ntp.org' , env
= env
)
3846 # TODO: check json string
3847 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3849 output
= read_link_state_file ( 'dummy98' )
3851 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
3852 self
. assertIn ( 'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org' , output
)
3853 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
3854 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
3855 self
. assertIn ( 'LLMNR=yes' , output
)
3856 self
. assertIn ( 'MDNS=no' , output
)
3857 self
. assertIn ( 'DNSSEC=yes' , output
)
3859 check_output (* timedatectl_cmd
, 'revert' , 'dummy98' , env
= env
)
3861 # TODO: check json string
3862 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3864 output
= read_link_state_file ( 'dummy98' )
3866 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
3867 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
3868 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
3869 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
3870 self
. assertIn ( 'LLMNR=yes' , output
)
3871 self
. assertIn ( 'MDNS=no' , output
)
3872 self
. assertIn ( 'DNSSEC=yes' , output
)
3874 check_output (* resolvectl_cmd
, 'revert' , 'dummy98' , env
= env
)
3876 # TODO: check json string
3877 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
3879 output
= read_link_state_file ( 'dummy98' )
3881 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
3882 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
3883 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
3884 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
3885 self
. assertIn ( 'LLMNR=no' , output
)
3886 self
. assertIn ( 'MDNS=yes' , output
)
3887 self
. assertIn ( 'DNSSEC=no' , output
)
3889 def test_address_state ( self
):
3890 copy_network_unit ( '12-dummy.netdev' , '12-dummy-no-address.network' )
3893 self
. wait_online ([ 'dummy98:degraded' ])
3895 output
= read_link_state_file ( 'dummy98' )
3896 self
. assertIn ( 'IPV4_ADDRESS_STATE=off' , output
)
3897 self
. assertIn ( 'IPV6_ADDRESS_STATE=degraded' , output
)
3899 # with a routable IPv4 address
3900 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
3901 self
. wait_online ([ 'dummy98:routable' ], ipv4
= True )
3902 self
. wait_online ([ 'dummy98:routable' ])
3904 output
= read_link_state_file ( 'dummy98' )
3905 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
3906 self
. assertIn ( 'IPV6_ADDRESS_STATE=degraded' , output
)
3908 check_output ( 'ip address del 10.1.2.3/16 dev dummy98' )
3910 # with a routable IPv6 address
3911 check_output ( 'ip address add 2002:da8:1:0:1034:56ff:fe78:9abc/64 dev dummy98' )
3912 self
. wait_online ([ 'dummy98:routable' ], ipv6
= True )
3913 self
. wait_online ([ 'dummy98:routable' ])
3915 output
= read_link_state_file ( 'dummy98' )
3916 self
. assertIn ( 'IPV4_ADDRESS_STATE=off' , output
)
3917 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
3919 class NetworkdBondTests ( unittest
. TestCase
, Utilities
):
3927 def test_bond_keep_master ( self
):
3928 check_output ( 'ip link add bond199 type bond mode active-backup' )
3929 check_output ( 'ip link add dummy98 type dummy' )
3930 check_output ( 'ip link set dummy98 master bond199' )
3932 copy_network_unit ( '23-keep-master.network' )
3934 self
. wait_online ([ 'dummy98:enslaved' ])
3936 output
= check_output ( 'ip -d link show bond199' )
3938 self
. assertRegex ( output
, 'active_slave dummy98' )
3940 output
= check_output ( 'ip -d link show dummy98' )
3942 self
. assertRegex ( output
, 'master bond199' )
3944 def test_bond_active_slave ( self
):
3945 copy_network_unit ( '23-active-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
3947 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
3949 output
= check_output ( 'ip -d link show bond199' )
3951 self
. assertIn ( 'active_slave dummy98' , output
)
3953 def test_bond_primary_slave ( self
):
3954 copy_network_unit ( '23-primary-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
3956 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
3958 output
= check_output ( 'ip -d link show bond199' )
3960 self
. assertIn ( 'primary dummy98' , output
)
3963 mkdir_p ( os
. path
. join ( network_unit_dir
, '23-bond199.network.d' ))
3964 for mac
in [ '00:11:22:33:44:55' , '00:11:22:33:44:56' ]:
3965 with
open ( os
. path
. join ( network_unit_dir
, '23-bond199.network.d/mac.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
3966 f
. write ( f
'[Link] \n MACAddress= {mac} \n ' )
3969 self
. wait_online ([ 'dummy98:enslaved' , 'bond199:degraded' ])
3971 output
= check_output ( 'ip -d link show bond199' )
3973 self
. assertIn ( f
'link/ether {mac} ' , output
)
3975 def test_bond_operstate ( self
):
3976 copy_network_unit ( '25-bond.netdev' , '11-dummy.netdev' , '12-dummy.netdev' ,
3977 '25-bond99.network' , '25-bond-slave.network' )
3979 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bond99:routable' ])
3981 output
= check_output ( 'ip -d link show dummy98' )
3983 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
3985 output
= check_output ( 'ip -d link show test1' )
3987 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
3989 output
= check_output ( 'ip -d link show bond99' )
3991 self
. assertRegex ( output
, 'MASTER,UP,LOWER_UP' )
3993 self
. wait_operstate ( 'dummy98' , 'enslaved' )
3994 self
. wait_operstate ( 'test1' , 'enslaved' )
3995 self
. wait_operstate ( 'bond99' , 'routable' )
3997 check_output ( 'ip link set dummy98 down' )
3999 self
. wait_operstate ( 'dummy98' , 'off' )
4000 self
. wait_operstate ( 'test1' , 'enslaved' )
4001 self
. wait_operstate ( 'bond99' , 'routable' )
4003 check_output ( 'ip link set dummy98 up' )
4005 self
. wait_operstate ( 'dummy98' , 'enslaved' )
4006 self
. wait_operstate ( 'test1' , 'enslaved' )
4007 self
. wait_operstate ( 'bond99' , 'routable' )
4009 check_output ( 'ip link set dummy98 down' )
4010 check_output ( 'ip link set test1 down' )
4012 self
. wait_operstate ( 'dummy98' , 'off' )
4013 self
. wait_operstate ( 'test1' , 'off' )
4015 if not self
. wait_operstate ( 'bond99' , 'no-carrier' , setup_timeout
= 30 , fail_assert
= False ):
4016 # Huh? Kernel does not recognize that all slave interfaces are down?
4017 # Let's confirm that networkd's operstate is consistent with ip's result.
4018 self
. assertNotRegex ( output
, 'NO-CARRIER' )
4020 class NetworkdBridgeTests ( unittest
. TestCase
, Utilities
):
4028 def test_bridge_vlan ( self
):
4029 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave.network' ,
4030 '26-bridge.netdev' , '26-bridge-vlan-master.network' )
4032 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' ])
4034 output
= check_output ( 'bridge vlan show dev test1' )
4036 self
. assertNotRegex ( output
, '4063' )
4037 for i
in range ( 4064 , 4095 ):
4038 self
. assertRegex ( output
, f
' {i} ' )
4039 self
. assertNotRegex ( output
, '4095' )
4041 output
= check_output ( 'bridge vlan show dev bridge99' )
4043 self
. assertNotRegex ( output
, '4059' )
4044 for i
in range ( 4060 , 4095 ):
4045 self
. assertRegex ( output
, f
' {i} ' )
4046 self
. assertNotRegex ( output
, '4095' )
4048 def test_bridge_vlan_issue_20373 ( self
):
4049 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave-issue-20373.network' ,
4050 '26-bridge-issue-20373.netdev' , '26-bridge-vlan-master-issue-20373.network' ,
4051 '21-vlan.netdev' , '21-vlan.network' )
4053 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' , 'vlan99:routable' ])
4055 output
= check_output ( 'bridge vlan show dev test1' )
4057 self
. assertIn ( '100 PVID Egress Untagged' , output
)
4058 self
. assertIn ( '560' , output
)
4059 self
. assertIn ( '600' , output
)
4061 output
= check_output ( 'bridge vlan show dev bridge99' )
4063 self
. assertIn ( '1 PVID Egress Untagged' , output
)
4064 self
. assertIn ( '100' , output
)
4065 self
. assertIn ( '600' , output
)
4067 def test_bridge_mdb ( self
):
4068 copy_network_unit ( '11-dummy.netdev' , '26-bridge-mdb-slave.network' ,
4069 '26-bridge.netdev' , '26-bridge-mdb-master.network' )
4071 self
. wait_online ([ 'test1:enslaved' , 'bridge99:degraded' ])
4073 output
= check_output ( 'bridge mdb show dev bridge99' )
4075 self
. assertRegex ( output
, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064' )
4076 self
. assertRegex ( output
, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065' )
4078 # Old kernel may not support bridge MDB entries on bridge master
4079 if call_quiet ( 'bridge mdb add dev bridge99 port bridge99 grp 224.0.1.3 temp vid 4068' ) == 0 :
4080 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp ff02:aaaa:fee5::1:4 temp *vid 4066' )
4081 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp 224.0.1.2 temp *vid 4067' )
4083 def test_bridge_keep_master ( self
):
4084 check_output ( 'ip link add bridge99 type bridge' )
4085 check_output ( 'ip link set bridge99 up' )
4086 check_output ( 'ip link add dummy98 type dummy' )
4087 check_output ( 'ip link set dummy98 master bridge99' )
4089 copy_network_unit ( '23-keep-master.network' )
4091 self
. wait_online ([ 'dummy98:enslaved' ])
4093 output
= check_output ( 'ip -d link show dummy98' )
4095 self
. assertRegex ( output
, 'master bridge99' )
4096 self
. assertRegex ( output
, 'bridge' )
4098 output
= check_output ( 'bridge -d link show dummy98' )
4100 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
4101 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
4102 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
4103 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
4104 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
4105 # CONFIG_BRIDGE_IGMP_SNOOPING=y
4106 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
4107 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
4108 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
4109 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
4110 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
4111 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
4113 def test_bridge_property ( self
):
4114 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
4115 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
4116 '25-bridge99.network' )
4118 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' ])
4120 output
= check_output ( 'ip -d link show bridge99' )
4122 self
. assertIn ( 'mtu 9000 ' , output
)
4124 output
= check_output ( 'ip -d link show test1' )
4126 self
. assertIn ( 'master bridge99 ' , output
)
4127 self
. assertIn ( 'bridge_slave' , output
)
4128 self
. assertIn ( 'mtu 9000 ' , output
)
4130 output
= check_output ( 'ip -d link show dummy98' )
4132 self
. assertIn ( 'master bridge99 ' , output
)
4133 self
. assertIn ( 'bridge_slave' , output
)
4134 self
. assertIn ( 'mtu 9000 ' , output
)
4136 output
= check_output ( 'ip addr show bridge99' )
4138 self
. assertIn ( '192.168.0.15/24' , output
)
4140 output
= check_output ( 'bridge -d link show dummy98' )
4142 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
4143 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
4144 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'isolated' , '1' )
4145 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
4146 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
4147 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
4148 # CONFIG_BRIDGE_IGMP_SNOOPING=y
4149 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
4150 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
4151 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
4152 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
4153 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
4154 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
4156 output
= check_output ( 'bridge -d link show test1' )
4158 self
. check_bridge_port_attr ( 'bridge99' , 'test1' , 'priority' , '0' )
4160 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
4161 output
= check_output ( 'ip addr show bridge99' )
4163 self
. assertIn ( '192.168.0.16/24' , output
)
4166 print ( '### ip -6 route list table all dev bridge99' )
4167 output
= check_output ( 'ip -6 route list table all dev bridge99' )
4169 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
4171 remove_link ( 'test1' )
4172 self
. wait_operstate ( 'bridge99' , 'routable' )
4174 output
= check_output ( 'ip -d link show bridge99' )
4176 self
. assertIn ( 'mtu 9000 ' , output
)
4178 output
= check_output ( 'ip -d link show dummy98' )
4180 self
. assertIn ( 'master bridge99 ' , output
)
4181 self
. assertIn ( 'bridge_slave' , output
)
4182 self
. assertIn ( 'mtu 9000 ' , output
)
4184 remove_link ( 'dummy98' )
4185 self
. wait_operstate ( 'bridge99' , 'no-carrier' )
4187 output
= check_output ( 'ip -d link show bridge99' )
4189 # When no carrier, the kernel may reset the MTU
4190 self
. assertIn ( 'NO-CARRIER' , output
)
4192 output
= check_output ( 'ip address show bridge99' )
4194 self
. assertNotIn ( '192.168.0.15/24' , output
)
4195 self
. assertIn ( '192.168.0.16/24' , output
) # foreign address is kept
4197 print ( '### ip -6 route list table all dev bridge99' )
4198 output
= check_output ( 'ip -6 route list table all dev bridge99' )
4200 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
4202 check_output ( 'ip link add dummy98 type dummy' )
4203 self
. wait_online ([ 'dummy98:enslaved' , 'bridge99:routable' ])
4205 output
= check_output ( 'ip -d link show bridge99' )
4207 self
. assertIn ( 'mtu 9000 ' , output
)
4209 output
= check_output ( 'ip -d link show dummy98' )
4211 self
. assertIn ( 'master bridge99 ' , output
)
4212 self
. assertIn ( 'bridge_slave' , output
)
4213 self
. assertIn ( 'mtu 9000 ' , output
)
4215 def test_bridge_configure_without_carrier ( self
):
4216 copy_network_unit ( '26-bridge.netdev' , '26-bridge-configure-without-carrier.network' ,
4220 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
4221 for test
in [ 'no-slave' , 'add-slave' , 'slave-up' , 'slave-no-carrier' , 'slave-carrier' , 'slave-down' ]:
4222 with self
. subTest ( test
= test
):
4223 if test
== 'no-slave' :
4224 # bridge has no slaves; it's up but *might* not have carrier
4225 self
. wait_operstate ( 'bridge99' , operstate
= r
'(no-carrier|routable)' , setup_state
= None , setup_timeout
= 30 )
4226 # due to a bug in the kernel, newly-created bridges are brought up
4227 # *with* carrier, unless they have had any setting changed; e.g.
4228 # their mac set, priority set, etc. Then, they will lose carrier
4229 # as soon as a (down) slave interface is added, and regain carrier
4230 # again once the slave interface is brought up.
4231 #self.check_link_attr('bridge99', 'carrier', '0')
4232 elif test
== 'add-slave' :
4233 # add slave to bridge, but leave it down; bridge is definitely no-carrier
4234 self
. check_link_attr ( 'test1' , 'operstate' , 'down' )
4235 check_output ( 'ip link set dev test1 master bridge99' )
4236 self
. wait_operstate ( 'bridge99' , operstate
= 'no-carrier' , setup_state
= None )
4237 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4238 elif test
== 'slave-up' :
4239 # bring up slave, which will have carrier; bridge gains carrier
4240 check_output ( 'ip link set dev test1 up' )
4241 self
. wait_online ([ 'bridge99:routable' ])
4242 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
4243 elif test
== 'slave-no-carrier' :
4244 # drop slave carrier; bridge loses carrier
4245 check_output ( 'ip link set dev test1 carrier off' )
4246 self
. wait_online ([ 'bridge99:no-carrier:no-carrier' ])
4247 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4248 elif test
== 'slave-carrier' :
4249 # restore slave carrier; bridge gains carrier
4250 check_output ( 'ip link set dev test1 carrier on' )
4251 self
. wait_online ([ 'bridge99:routable' ])
4252 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
4253 elif test
== 'slave-down' :
4254 # bring down slave; bridge loses carrier
4255 check_output ( 'ip link set dev test1 down' )
4256 self
. wait_online ([ 'bridge99:no-carrier:no-carrier' ])
4257 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
4259 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'bridge99' , env
= env
)
4260 self
. assertRegex ( output
, '10.1.2.3' )
4261 self
. assertRegex ( output
, '10.1.2.1' )
4263 def test_bridge_ignore_carrier_loss ( self
):
4264 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
4265 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
4266 '25-bridge99-ignore-carrier-loss.network' )
4268 self
. wait_online ([ 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' ])
4270 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
4271 remove_link ( 'test1' , 'dummy98' )
4274 output
= check_output ( 'ip address show bridge99' )
4276 self
. assertRegex ( output
, 'NO-CARRIER' )
4277 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
4278 self
. assertRegex ( output
, 'inet 192.168.0.16/24 scope global secondary bridge99' )
4280 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain ( self
):
4281 copy_network_unit ( '26-bridge.netdev' , '26-bridge-slave-interface-1.network' ,
4282 '25-bridge99-ignore-carrier-loss.network' )
4284 self
. wait_online ([ 'bridge99:no-carrier' ])
4286 for trial
in range ( 4 ):
4287 check_output ( 'ip link add dummy98 type dummy' )
4288 check_output ( 'ip link set dummy98 up' )
4290 remove_link ( 'dummy98' )
4292 self
. wait_online ([ 'bridge99:routable' , 'dummy98:enslaved' ])
4294 output
= check_output ( 'ip address show bridge99' )
4296 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
4298 output
= check_output ( 'ip rule list table 100' )
4300 self
. assertIn ( 'from all to 8.8.8.8 lookup 100' , output
)
4302 class NetworkdSRIOVTests ( unittest
. TestCase
, Utilities
):
4310 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
4311 def test_sriov ( self
):
4312 copy_network_unit ( '25-default.link' , '25-sriov.network' )
4314 call ( 'modprobe netdevsim' )
4316 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4319 with
open ( '/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4323 self
. wait_online ([ 'eni99np1:routable' ])
4325 output
= check_output ( 'ip link show dev eni99np1' )
4327 self
. assertRegex ( output
,
4328 '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 *'
4329 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4330 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4333 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
4334 def test_sriov_udev ( self
):
4335 copy_network_unit ( '25-sriov.link' , '25-sriov-udev.network' )
4337 call ( 'modprobe netdevsim' )
4339 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
4343 self
. wait_online ([ 'eni99np1:routable' ])
4345 # the name eni99np1 may be an alternative name.
4346 ifname
= link_resolve ( 'eni99np1' )
4348 output
= check_output ( 'ip link show dev eni99np1' )
4350 self
. assertRegex ( output
,
4351 'vf 0 .*00:11:22:33:44:55.*vlan 5, qos 1, vlan protocol 802.1ad, spoof checking on, link-state enable, trust on, query_rss on \n *'
4352 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4353 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4355 self
. assertNotIn ( 'vf 3' , output
)
4356 self
. assertNotIn ( 'vf 4' , output
)
4358 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4359 f
. write ( '[Link] \n SR-IOVVirtualFunctions=4 \n ' )
4362 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4364 output
= check_output ( 'ip link show dev eni99np1' )
4366 self
. assertRegex ( output
,
4367 'vf 0 .*00:11:22:33:44:55.*vlan 5, qos 1, vlan protocol 802.1ad, spoof checking on, link-state enable, trust on, query_rss on \n *'
4368 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4369 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
4372 self
. assertNotIn ( 'vf 4' , output
)
4374 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4375 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
4378 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4380 output
= check_output ( 'ip link show dev eni99np1' )
4382 self
. assertRegex ( output
,
4383 '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 *'
4384 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4385 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
4388 self
. assertNotIn ( 'vf 4' , output
)
4390 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4391 f
. write ( '[Link] \n SR-IOVVirtualFunctions=2 \n ' )
4394 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4396 output
= check_output ( 'ip link show dev eni99np1' )
4398 self
. assertRegex ( output
,
4399 '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 *'
4400 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off'
4402 self
. assertNotIn ( 'vf 2' , output
)
4403 self
. assertNotIn ( 'vf 3' , output
)
4404 self
. assertNotIn ( 'vf 4' , output
)
4406 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4407 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
4410 check_output (* udevadm_cmd
, 'trigger' , '--action=add' , '--settle' , f
'/sys/devices/netdevsim99/net/ {ifname} ' )
4412 output
= check_output ( 'ip link show dev eni99np1' )
4414 self
. assertRegex ( output
,
4415 '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 *'
4416 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
4417 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4419 self
. assertNotIn ( 'vf 3' , output
)
4420 self
. assertNotIn ( 'vf 4' , output
)
4422 class NetworkdLLDPTests ( unittest
. TestCase
, Utilities
):
4430 def test_lldp ( self
):
4431 copy_network_unit ( '23-emit-lldp.network' , '24-lldp.network' , '25-veth.netdev' )
4433 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:degraded' ])
4435 for trial
in range ( 10 ):
4439 output
= check_output (* networkctl_cmd
, 'lldp' , env
= env
)
4441 if re
. search ( r
'veth99 .* veth-peer' , output
):
4446 class NetworkdRATests ( unittest
. TestCase
, Utilities
):
4454 def test_ipv6_prefix_delegation ( self
):
4455 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth.network' )
4457 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4459 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth99' , env
= env
)
4461 self
. assertRegex ( output
, 'fe80::' )
4462 self
. assertRegex ( output
, '2002:da8:1::1' )
4464 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth99' , env
= env
)
4466 self
. assertIn ( 'hogehoge.test' , output
)
4468 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4470 self
. assertRegex ( output
, '2002:da8:1:0' )
4472 self
. check_netlabel ( 'veth99' , '2002:da8:1::/64' )
4473 self
. check_netlabel ( 'veth99' , '2002:da8:2::/64' )
4475 def test_ipv6_token_static ( self
):
4476 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-static.network' )
4478 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4480 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4482 self
. assertRegex ( output
, '2002:da8:1:0:1a:2b:3c:4d' )
4483 self
. assertRegex ( output
, '2002:da8:1:0:fa:de:ca:fe' )
4484 self
. assertRegex ( output
, '2002:da8:2:0:1a:2b:3c:4d' )
4485 self
. assertRegex ( output
, '2002:da8:2:0:fa:de:ca:fe' )
4487 def test_ipv6_token_prefixstable ( self
):
4488 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable.network' )
4490 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4492 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4494 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
4495 self
. assertIn ( '2002:da8:2:0:1034:56ff:fe78:9abc' , output
) # EUI64
4497 def test_ipv6_token_prefixstable_without_address ( self
):
4498 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable-without-address.network' )
4500 self
. wait_online ([ 'veth99:routable' , 'veth-peer:degraded' ])
4502 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4504 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
4505 self
. assertIn ( '2002:da8:2:0:f689:561a:8eda:7443' , output
)
4507 def test_router_preference ( self
):
4508 copy_network_unit ( '25-veth-client.netdev' ,
4509 '25-veth-router-high.netdev' ,
4510 '25-veth-router-low.netdev' ,
4512 '25-veth-bridge.network' ,
4513 '25-veth-client.network' ,
4514 '25-veth-router-high.network' ,
4515 '25-veth-router-low.network' ,
4516 '25-bridge99.network' )
4518 self
. wait_online ([ 'client-p:enslaved' ,
4519 'router-high:degraded' , 'router-high-p:enslaved' ,
4520 'router-low:degraded' , 'router-low-p:enslaved' ,
4521 'bridge99:routable' ])
4523 networkctl_reconfigure ( 'client' )
4524 self
. wait_online ([ 'client:routable' ])
4526 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4527 self
. wait_address ( 'client' , '2002:da8:1:98:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
4528 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 512' , ipv
= '-6' , timeout_sec
= 10 )
4529 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 2048' , ipv
= '-6' , timeout_sec
= 10 )
4531 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
4533 self
. assertIn ( 'pref high' , output
)
4534 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
4536 self
. assertIn ( 'pref low' , output
)
4538 with
open ( os
. path
. join ( network_unit_dir
, '25-veth-client.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4539 f
. write ( ' \n [Link] \n MACAddress=12:34:56:78:9a:01 \n [IPv6AcceptRA] \n RouteMetric=100:200:300 \n ' )
4542 self
. wait_online ([ 'client:routable' ])
4544 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a01/64' , ipv
= '-6' , timeout_sec
= 10 )
4545 self
. wait_address ( 'client' , '2002:da8:1:98:1034:56ff:fe78:9a01/64' , ipv
= '-6' , timeout_sec
= 10 )
4546 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 100' , ipv
= '-6' , timeout_sec
= 10 )
4547 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 300' , ipv
= '-6' , timeout_sec
= 10 )
4549 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
4551 self
. assertIn ( 'pref high' , output
)
4552 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
4554 self
. assertIn ( 'pref low' , output
)
4556 class NetworkdDHCPServerTests ( unittest
. TestCase
, Utilities
):
4564 def test_dhcp_server ( self
):
4565 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server.network' )
4567 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4569 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4571 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4572 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
4573 self
. assertRegex ( output
, 'DNS: 192.168.5.1 \n *192.168.5.10' )
4574 self
. assertRegex ( output
, 'NTP: 192.168.5.1 \n *192.168.5.11' )
4576 def test_dhcp_server_with_uplink ( self
):
4577 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-downstream.network' ,
4578 '12-dummy.netdev' , '25-dhcp-server-uplink.network' )
4580 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4582 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4584 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4585 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
4586 self
. assertIn ( 'DNS: 192.168.5.1' , output
)
4587 self
. assertIn ( 'NTP: 192.168.5.1' , output
)
4589 def test_emit_router_timezone ( self
):
4590 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-timezone-router.network' , '25-dhcp-server-timezone-router.network' )
4592 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4594 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4596 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
4597 self
. assertIn ( 'Gateway: 192.168.5.1' , output
)
4598 self
. assertIn ( 'Time Zone: Europe/Berlin' , output
)
4600 def test_dhcp_server_static_lease ( self
):
4601 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-static-lease.network' , '25-dhcp-server-static-lease.network' )
4603 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4605 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4607 self
. assertIn ( 'Address: 10.1.1.200 (DHCP4 via 10.1.1.1)' , output
)
4608 self
. assertIn ( 'DHCP4 Client ID: 12:34:56:78:9a:bc' , output
)
4610 def test_dhcp_server_static_lease_default_client_id ( self
):
4611 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-static-lease.network' )
4613 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4615 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
4617 self
. assertIn ( 'Address: 10.1.1.200 (DHCP4 via 10.1.1.1)' , output
)
4618 self
. assertRegex ( output
, 'DHCP4 Client ID: IAID:[0-9a-z]*/DUID' )
4620 class NetworkdDHCPServerRelayAgentTests ( unittest
. TestCase
, Utilities
):
4628 def test_relay_agent ( self
):
4629 copy_network_unit ( '25-agent-veth-client.netdev' ,
4630 '25-agent-veth-server.netdev' ,
4631 '25-agent-client.network' ,
4632 '25-agent-server.network' ,
4633 '25-agent-client-peer.network' ,
4634 '25-agent-server-peer.network' )
4637 self
. wait_online ([ 'client:routable' ])
4639 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'client' , env
= env
)
4641 self
. assertRegex ( output
, r
'Address: 192.168.5.150 \(DHCP4 via 192.168.5.1\)' )
4643 class NetworkdDHCPClientTests ( unittest
. TestCase
, Utilities
):
4651 def test_dhcp_client_ipv6_only ( self
):
4652 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv6-only.network' )
4655 self
. wait_online ([ 'veth-peer:carrier' ])
4657 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4660 output
= check_output ( 'ip address show dev veth99 scope global' )
4662 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
4663 self
. assertNotIn ( '192.168.5' , output
)
4665 # checking semi-static route
4666 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
4668 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
4670 # Confirm that ipv6 token is not set in the kernel
4671 output
= check_output ( 'ip token show dev veth99' )
4673 self
. assertRegex ( output
, 'token :: dev veth99' )
4675 print ( '## dnsmasq log' )
4676 output
= read_dnsmasq_log_file ()
4678 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
4679 self
. assertNotIn ( 'DHCPADVERTISE(veth-peer)' , output
)
4680 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
4681 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
4682 self
. assertIn ( 'sent size: 0 option: 14 rapid-commit' , output
)
4684 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-ipv6-only.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4685 f
. write ( ' \n [DHCPv6] \n RapidCommit=no \n ' )
4691 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4694 output
= check_output ( 'ip address show dev veth99 scope global' )
4696 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
4697 self
. assertNotIn ( '192.168.5' , output
)
4699 # checking semi-static route
4700 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
4702 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
4704 print ( '## dnsmasq log' )
4705 output
= read_dnsmasq_log_file ()
4707 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
4708 self
. assertIn ( 'DHCPADVERTISE(veth-peer)' , output
)
4709 self
. assertIn ( 'DHCPREQUEST(veth-peer)' , output
)
4710 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
4711 self
. assertNotIn ( 'rapid-commit' , output
)
4713 def test_dhcp_client_ipv4_only ( self
):
4714 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv4-only.network' )
4717 self
. wait_online ([ 'veth-peer:carrier' ])
4718 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7' ,
4719 '--dhcp-option=option:domain-search,example.com' ,
4720 '--dhcp-alternate-port=67,5555' ,
4721 ipv4_range
= '192.168.5.110,192.168.5.119' )
4722 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4723 self
. wait_address ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' )
4725 print ( '## ip address show dev veth99 scope global' )
4726 output
= check_output ( 'ip address show dev veth99 scope global' )
4728 self
. assertIn ( 'mtu 1492' , output
)
4729 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
4730 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' )
4731 self
. assertNotIn ( '2600::' , output
)
4733 print ( '## ip route show table main dev veth99' )
4734 output
= check_output ( 'ip route show table main dev veth99' )
4736 # no DHCP routes assigned to the main table
4737 self
. assertNotIn ( 'proto dhcp' , output
)
4739 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
4740 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
4741 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
4742 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
4744 print ( '## ip route show table 211 dev veth99' )
4745 output
= check_output ( 'ip route show table 211 dev veth99' )
4747 self
. assertRegex ( output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.11[0-9] metric 24' )
4748 self
. assertRegex ( output
, '192.168.5.0/24 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4749 self
. assertRegex ( output
, '192.168.5.1 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4750 self
. assertRegex ( output
, '192.168.5.6 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4751 self
. assertRegex ( output
, '192.168.5.7 proto dhcp scope link src 192.168.5.11[0-9] metric 24' )
4752 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
4754 print ( '## link state file' )
4755 output
= read_link_state_file ( 'veth99' )
4757 # checking DNS server and Domains
4758 self
. assertIn ( 'DNS=192.168.5.6 192.168.5.7' , output
)
4759 self
. assertIn ( 'DOMAINS=example.com' , output
)
4761 print ( '## dnsmasq log' )
4762 output
= read_dnsmasq_log_file ()
4764 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
4765 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc' , output
)
4766 self
. assertIn ( 'client provides name: test-hostname' , output
)
4767 self
. assertIn ( '26:mtu' , output
)
4769 # change address range, DNS servers, and Domains
4771 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8' ,
4772 '--dhcp-option=option:domain-search,foo.example.com' ,
4773 '--dhcp-alternate-port=67,5555' ,
4774 ipv4_range
= '192.168.5.120,192.168.5.129' ,)
4776 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4777 print ( 'Wait for the DHCP lease to be expired' )
4778 self
. wait_address_dropped ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' , timeout_sec
= 120 )
4779 self
. wait_address ( 'veth99' , r
'inet 192.168.5.12[0-9]*/24' , ipv
= '-4' )
4781 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4783 print ( '## ip address show dev veth99 scope global' )
4784 output
= check_output ( 'ip address show dev veth99 scope global' )
4786 self
. assertIn ( 'mtu 1492' , output
)
4787 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
4788 self
. assertNotIn ( '192.168.5.11' , output
)
4789 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' )
4790 self
. assertNotIn ( '2600::' , output
)
4792 print ( '## ip route show table main dev veth99' )
4793 output
= check_output ( 'ip route show table main dev veth99' )
4795 # no DHCP routes assigned to the main table
4796 self
. assertNotIn ( 'proto dhcp' , output
)
4798 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
4799 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
4800 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
4801 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
4803 print ( '## ip route show table 211 dev veth99' )
4804 output
= check_output ( 'ip route show table 211 dev veth99' )
4806 self
. assertRegex ( output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.12[0-9] metric 24' )
4807 self
. assertRegex ( output
, '192.168.5.0/24 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4808 self
. assertRegex ( output
, '192.168.5.1 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4809 self
. assertNotIn ( '192.168.5.6' , output
)
4810 self
. assertRegex ( output
, '192.168.5.7 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4811 self
. assertRegex ( output
, '192.168.5.8 proto dhcp scope link src 192.168.5.12[0-9] metric 24' )
4812 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
4814 print ( '## link state file' )
4815 output
= read_link_state_file ( 'veth99' )
4817 # checking DNS server and Domains
4818 self
. assertIn ( 'DNS=192.168.5.1 192.168.5.7 192.168.5.8' , output
)
4819 self
. assertIn ( 'DOMAINS=foo.example.com' , output
)
4821 print ( '## dnsmasq log' )
4822 output
= read_dnsmasq_log_file ()
4824 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
4825 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 192.168.5.11' , output
)
4826 self
. assertIn ( 'client provides name: test-hostname' , output
)
4827 self
. assertIn ( '26:mtu' , output
)
4829 self
. check_netlabel ( 'veth99' , r
'192\.168\.5\.0/24' )
4831 def test_dhcp_client_ipv4_use_routes_gateway ( self
):
4833 for ( routes
, gateway
, dns_and_ntp_routes
, classless
) in itertools
. product ([ True , False ], repeat
= 4 ):
4839 print ( f
'### test_dhcp_client_ipv4_use_routes_gateway(routes= {routes} , gateway= {gateway} , dns_and_ntp_routes= {dns_and_ntp_routes} , classless= {classless} )' )
4840 with self
. subTest ( routes
= routes
, gateway
= gateway
, dns_and_ntp_routes
= dns_and_ntp_routes
, classless
= classless
):
4841 self
._ test
_ dhcp
_ client
_ ipv
4_u se
_ routes
_ gateway
( routes
, gateway
, dns_and_ntp_routes
, classless
)
4843 def _test_dhcp_client_ipv4_use_routes_gateway ( self
, use_routes
, use_gateway
, dns_and_ntp_routes
, classless
):
4844 testunit
= '25-dhcp-client-ipv4-use-routes-use-gateway.network'
4845 testunits
= [ '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , testunit
]
4846 testunits
. append ( f
' {testunit} .d/use-routes- {use_routes} .conf' )
4847 testunits
. append ( f
' {testunit} .d/use-gateway- {use_gateway} .conf' )
4848 testunits
. append ( f
' {testunit} .d/use-dns-and-ntp-routes- {dns_and_ntp_routes} .conf' )
4849 copy_network_unit (* testunits
, copy_dropins
= False )
4852 self
. wait_online ([ 'veth-peer:carrier' ])
4853 additional_options
= [
4854 '--dhcp-option=option:dns-server,192.168.5.10,8.8.8.8' ,
4855 '--dhcp-option=option:ntp-server,192.168.5.11,9.9.9.9' ,
4856 '--dhcp-option=option:static-route,192.168.5.100,192.168.5.2,8.8.8.8,192.168.5.3'
4859 additional_options
+= [
4860 '--dhcp-option=option:classless-static-route,0.0.0.0/0,192.168.5.4,8.0.0.0/8,192.168.5.5,192.168.5.64/26,192.168.5.5'
4862 start_dnsmasq (* additional_options
)
4863 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4865 output
= check_output ( 'ip -4 route show dev veth99' )
4871 self
. assertRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4872 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4873 self
. assertRegex ( output
, r
'192.168.5.64/26 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4874 self
. assertRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4875 self
. assertRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4877 self
. assertRegex ( output
, r
'192.168.5.0/24 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4878 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4879 self
. assertRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4881 self
. assertNotRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4882 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4883 self
. assertNotRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4884 self
. assertNotRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4885 self
. assertNotRegex ( output
, r
'192.168.5.0/24 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4886 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4887 self
. assertNotRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4890 if use_gateway
and ( not classless
or not use_routes
):
4891 self
. assertRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4893 self
. assertNotRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4895 # Check route to gateway
4896 if ( use_gateway
or dns_and_ntp_routes
) and ( not classless
or not use_routes
):
4897 self
. assertRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4899 self
. assertNotRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4901 # Check RoutesToDNS= and RoutesToNTP=
4902 if dns_and_ntp_routes
:
4903 self
. assertRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4904 self
. assertRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4905 if classless
and use_routes
:
4906 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4907 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4909 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4910 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
4912 self
. assertNotRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4913 self
. assertNotRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
4914 self
. assertNotRegex ( output
, r
'8.8.8.8 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
4915 self
. assertNotRegex ( output
, r
'9.9.9.9 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
4917 # TODO: check json string
4918 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
4920 def test_dhcp_client_settings_anonymize ( self
):
4921 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-anonymize.network' )
4923 self
. wait_online ([ 'veth-peer:carrier' ])
4925 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4927 print ( '## dnsmasq log' )
4928 output
= read_dnsmasq_log_file ()
4930 self
. assertNotIn ( 'VendorClassIdentifier=SusantVendorTest' , output
)
4931 self
. assertNotIn ( 'test-hostname' , output
)
4932 self
. assertNotIn ( '26:mtu' , output
)
4934 def test_dhcp_keep_configuration_dhcp ( self
):
4935 copy_network_unit ( '25-veth.netdev' ,
4936 '25-dhcp-server-veth-peer.network' ,
4937 '25-dhcp-client-keep-configuration-dhcp.network' )
4939 self
. wait_online ([ 'veth-peer:carrier' ])
4941 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4943 output
= check_output ( 'ip address show dev veth99 scope global' )
4945 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4946 'valid_lft forever preferred_lft forever' )
4948 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
4951 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4952 print ( 'Wait for the DHCP lease to be expired' )
4955 # The lease address should be kept after the lease expired
4956 output
= check_output ( 'ip address show dev veth99 scope global' )
4958 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4959 'valid_lft forever preferred_lft forever' )
4963 # The lease address should be kept after networkd stopped
4964 output
= check_output ( 'ip address show dev veth99 scope global' )
4966 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4967 'valid_lft forever preferred_lft forever' )
4969 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-keep-configuration-dhcp.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
4970 f
. write ( '[Network] \n DHCP=no \n ' )
4973 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4975 # Still the lease address should be kept after networkd restarted
4976 output
= check_output ( 'ip address show dev veth99 scope global' )
4978 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4979 'valid_lft forever preferred_lft forever' )
4981 def test_dhcp_keep_configuration_dhcp_on_stop ( self
):
4982 copy_network_unit ( '25-veth.netdev' ,
4983 '25-dhcp-server-veth-peer.network' ,
4984 '25-dhcp-client-keep-configuration-dhcp-on-stop.network' )
4986 self
. wait_online ([ 'veth-peer:carrier' ])
4988 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
4990 output
= check_output ( 'ip address show dev veth99 scope global' )
4992 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
4997 output
= check_output ( 'ip address show dev veth99 scope global' )
4999 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5002 self
. wait_online ([ 'veth-peer:routable' ])
5004 output
= check_output ( 'ip address show dev veth99 scope global' )
5006 self
. assertNotIn ( '192.168.5.' , output
)
5008 def test_dhcp_client_reuse_address_as_static ( self
):
5009 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' )
5011 self
. wait_online ([ 'veth-peer:carrier' ])
5013 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5015 # link become 'routable' when at least one protocol provide an valid address.
5016 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5017 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5019 output
= check_output ( 'ip address show dev veth99 scope global' )
5020 ipv4_address
= re
. search ( r
'192.168.5.[0-9]*/24' , output
). group ()
5021 ipv6_address
= re
. search ( r
'2600::[0-9a-f:]*/128' , output
). group ()
5022 static_network
= ' \n ' . join ([ '[Match]' , 'Name=veth99' , '[Network]' , 'IPv6AcceptRA=no' , 'Address=' + ipv4_address
, 'Address=' + ipv6_address
])
5023 print ( static_network
)
5025 remove_network_unit ( '25-dhcp-client.network' )
5027 with
open ( os
. path
. join ( network_unit_dir
, '25-static.network' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5028 f
. write ( static_network
)
5031 self
. wait_online ([ 'veth99:routable' ])
5033 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
5035 self
. assertRegex ( output
, f
'inet {ipv4_address} brd 192.168.5.255 scope global veth99 \n *'
5036 'valid_lft forever preferred_lft forever' )
5038 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5040 self
. assertRegex ( output
, f
'inet6 {ipv6_address} scope global * \n *'
5041 'valid_lft forever preferred_lft forever' )
5043 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
5044 def test_dhcp_client_vrf ( self
):
5045 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-vrf.network' ,
5046 '25-vrf.netdev' , '25-vrf.network' )
5048 self
. wait_online ([ 'veth-peer:carrier' ])
5050 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'vrf99:carrier' ])
5052 # link become 'routable' when at least one protocol provide an valid address.
5053 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5054 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5056 print ( '## ip -d link show dev vrf99' )
5057 output
= check_output ( 'ip -d link show dev vrf99' )
5059 self
. assertRegex ( output
, 'vrf table 42' )
5061 print ( '## ip address show vrf vrf99' )
5062 output
= check_output ( 'ip address show vrf vrf99' )
5064 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5065 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5066 self
. assertRegex ( output
, 'inet6 .* scope link' )
5068 print ( '## ip address show dev veth99' )
5069 output
= check_output ( 'ip address show dev veth99' )
5071 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
5072 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5073 self
. assertRegex ( output
, 'inet6 .* scope link' )
5075 print ( '## ip route show vrf vrf99' )
5076 output
= check_output ( 'ip route show vrf vrf99' )
5078 self
. assertRegex ( output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.' )
5079 self
. assertRegex ( output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5' )
5080 self
. assertRegex ( output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5' )
5082 print ( '## ip route show table main dev veth99' )
5083 output
= check_output ( 'ip route show table main dev veth99' )
5085 self
. assertEqual ( output
, '' )
5087 def test_dhcp_client_gateway_onlink_implicit ( self
):
5088 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
5089 '25-dhcp-client-gateway-onlink-implicit.network' )
5091 self
. wait_online ([ 'veth-peer:carrier' ])
5093 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' ])
5095 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth99' , env
= env
)
5097 self
. assertRegex ( output
, '192.168.5' )
5099 output
= check_output ( 'ip route list dev veth99 10.0.0.0/8' )
5101 self
. assertRegex ( output
, 'onlink' )
5102 output
= check_output ( 'ip route list dev veth99 192.168.100.0/24' )
5104 self
. assertRegex ( output
, 'onlink' )
5106 def test_dhcp_client_with_ipv4ll ( self
):
5107 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
5108 '25-dhcp-client-with-ipv4ll.network' )
5110 # we need to increase timeout above default, as this will need to wait for
5111 # systemd-networkd to get the dhcpv4 transient failure event
5112 self
. wait_online ([ 'veth99:degraded' , 'veth-peer:routable' ], timeout
= '60s' )
5114 output
= check_output ( 'ip -4 address show dev veth99' )
5116 self
. assertNotIn ( '192.168.5.' , output
)
5117 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
5120 print ( 'Wait for a DHCP lease to be acquired and the IPv4LL address to be dropped' )
5121 self
. wait_address ( 'veth99' , r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic' , ipv
= '-4' )
5122 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' )
5123 self
. wait_online ([ 'veth99:routable' ])
5125 output
= check_output ( 'ip -4 address show dev veth99' )
5127 self
. assertRegex ( output
, r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99' )
5128 self
. assertNotIn ( '169.254.' , output
)
5129 self
. assertNotIn ( 'scope link' , output
)
5132 print ( 'Wait for the DHCP lease to be expired and an IPv4LL address to be acquired' )
5133 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 )
5134 self
. wait_address ( 'veth99' , r
'inet 169\.254\.133\.11/16 metric 2048 brd 169\.254\.255\.255 scope link' , scope
= 'link' , ipv
= '-4' )
5136 output
= check_output ( 'ip -4 address show dev veth99' )
5138 self
. assertNotIn ( '192.168.5.' , output
)
5139 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
5141 def test_dhcp_client_use_dns ( self
):
5142 def check ( self
, ipv4
, ipv6
):
5143 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5144 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5145 f
. write ( '[DHCPv4] \n UseDNS=' )
5146 f
. write ( 'yes' if ipv4
else 'no' )
5147 f
. write ( ' \n [DHCPv6] \n UseDNS=' )
5148 f
. write ( 'yes' if ipv6
else 'no' )
5149 f
. write ( ' \n [IPv6AcceptRA] \n UseDNS=no' )
5152 self
. wait_online ([ 'veth99:routable' ])
5154 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5155 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5156 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5158 # make resolved re-read the link state file
5159 check_output (* resolvectl_cmd
, 'revert' , 'veth99' , env
= env
)
5161 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth99' , env
= env
)
5164 self
. assertIn ( '192.168.5.1' , output
)
5166 self
. assertNotIn ( '192.168.5.1' , output
)
5168 self
. assertIn ( '2600::1' , output
)
5170 self
. assertNotIn ( '2600::1' , output
)
5172 # TODO: check json string
5173 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5175 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5178 self
. wait_online ([ 'veth-peer:carrier' ])
5179 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1' ,
5180 '--dhcp-option=option6:dns-server,[2600::1]' )
5182 check ( self
, True , True )
5183 check ( self
, True , False )
5184 check ( self
, False , True )
5185 check ( self
, False , False )
5187 def test_dhcp_client_use_captive_portal ( self
):
5188 def check ( self
, ipv4
, ipv6
):
5189 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5190 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5191 f
. write ( '[DHCPv4] \n UseCaptivePortal=' )
5192 f
. write ( 'yes' if ipv4
else 'no' )
5193 f
. write ( ' \n [DHCPv6] \n UseCaptivePortal=' )
5194 f
. write ( 'yes' if ipv6
else 'no' )
5195 f
. write ( ' \n [IPv6AcceptRA] \n UseCaptivePortal=no' )
5198 self
. wait_online ([ 'veth99:routable' ])
5200 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5201 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5202 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5204 output
= check_output (* networkctl_cmd
, 'status' , 'veth99' , env
= env
)
5207 self
. assertIn ( 'Captive Portal: http://systemd.io' , output
)
5209 self
. assertNotIn ( 'Captive Portal: http://systemd.io' , output
)
5211 # TODO: check json string
5212 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5214 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5217 self
. wait_online ([ 'veth-peer:carrier' ])
5218 start_dnsmasq ( '--dhcp-option=114,http://systemd.io' ,
5219 '--dhcp-option=option6:103,http://systemd.io' )
5221 check ( self
, True , True )
5222 check ( self
, True , False )
5223 check ( self
, False , True )
5224 check ( self
, False , False )
5226 def test_dhcp_client_reject_captive_portal ( self
):
5227 def check ( self
, ipv4
, ipv6
):
5228 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
5229 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5230 f
. write ( '[DHCPv4] \n UseCaptivePortal=' )
5231 f
. write ( 'yes' if ipv4
else 'no' )
5232 f
. write ( ' \n [DHCPv6] \n UseCaptivePortal=' )
5233 f
. write ( 'yes' if ipv6
else 'no' )
5234 f
. write ( ' \n [IPv6AcceptRA] \n UseCaptivePortal=no' )
5237 self
. wait_online ([ 'veth99:routable' ])
5239 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5240 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
5241 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
5243 output
= check_output (* networkctl_cmd
, 'status' , 'veth99' , env
= env
)
5245 self
. assertNotIn ( 'Captive Portal: ' , output
)
5246 self
. assertNotIn ( 'invalid/url' , output
)
5248 # TODO: check json string
5249 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5251 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
5254 self
. wait_online ([ 'veth-peer:carrier' ])
5255 masq
= lambda bs
: ':' . join ( f
'{b:02x}' for b
in bs
)
5256 start_dnsmasq ( '--dhcp-option=114,' + masq ( b
'http:// \x00 invalid/url' ),
5257 '--dhcp-option=option6:103,' + masq ( b
'http:// \x00 /invalid/url' ))
5259 check ( self
, True , True )
5260 check ( self
, True , False )
5261 check ( self
, False , True )
5262 check ( self
, False , False )
5264 class NetworkdDHCPPDTests ( unittest
. TestCase
, Utilities
):
5272 def test_dhcp6pd ( self
):
5273 copy_network_unit ( '25-veth.netdev' , '25-dhcp6pd-server.network' , '25-dhcp6pd-upstream.network' ,
5274 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
5275 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
5276 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
5277 '25-dhcp-pd-downstream-dummy97.network' ,
5278 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
5279 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' )
5282 self
. wait_online ([ 'veth-peer:routable' ])
5283 start_isc_dhcpd ( conf_file
= 'isc-dhcpd-dhcp6pd.conf' , ipv
= '-6' )
5284 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5285 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5287 print ( '### ip -6 address show dev veth-peer scope global' )
5288 output
= check_output ( 'ip -6 address show dev veth-peer scope global' )
5290 self
. assertIn ( 'inet6 3ffe:501:ffff:100::1/64 scope global' , output
)
5294 # dummy97: 0x01 (The link will appear later)
5296 # dummy99: auto -> 0x02 (No address assignment)
5301 print ( '### ip -6 address show dev veth99 scope global' )
5302 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5305 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:100::[0-9]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
5306 # address in IA_PD (Token=static)
5307 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic' )
5308 # address in IA_PD (Token=eui64)
5309 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic' )
5310 # address in IA_PD (temporary)
5311 # Note that the temporary addresses may appear after the link enters configured state
5312 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' )
5314 print ( '### ip -6 address show dev test1 scope global' )
5315 output
= check_output ( 'ip -6 address show dev test1 scope global' )
5317 # address in IA_PD (Token=static)
5318 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5319 # address in IA_PD (temporary)
5320 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' )
5322 print ( '### ip -6 address show dev dummy98 scope global' )
5323 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5325 # address in IA_PD (Token=static)
5326 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5327 # address in IA_PD (temporary)
5328 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' )
5330 print ( '### ip -6 address show dev dummy99 scope global' )
5331 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5334 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
5336 print ( '### ip -6 address show dev veth97 scope global' )
5337 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
5339 # address in IA_PD (Token=static)
5340 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5341 # address in IA_PD (Token=eui64)
5342 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5343 # address in IA_PD (temporary)
5344 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' )
5346 print ( '### ip -6 address show dev veth97-peer scope global' )
5347 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
5349 # NDisc address (Token=static)
5350 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5351 # NDisc address (Token=eui64)
5352 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5353 # NDisc address (temporary)
5354 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' )
5356 print ( '### ip -6 address show dev veth98 scope global' )
5357 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
5359 # address in IA_PD (Token=static)
5360 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5361 # address in IA_PD (Token=eui64)
5362 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5363 # address in IA_PD (temporary)
5364 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' )
5366 print ( '### ip -6 address show dev veth98-peer scope global' )
5367 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
5369 # NDisc address (Token=static)
5370 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5371 # NDisc address (Token=eui64)
5372 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5373 # NDisc address (temporary)
5374 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' )
5376 print ( '### ip -6 route show type unreachable' )
5377 output
= check_output ( 'ip -6 route show type unreachable' )
5379 self
. assertRegex ( output
, 'unreachable 3ffe:501:ffff:[2-9a-f]00::/56 dev lo proto dhcp' )
5381 print ( '### ip -6 route show dev veth99' )
5382 output
= check_output ( 'ip -6 route show dev veth99' )
5384 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]10::/64 proto kernel metric [0-9]* expires' )
5386 print ( '### ip -6 route show dev test1' )
5387 output
= check_output ( 'ip -6 route show dev test1' )
5389 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5391 print ( '### ip -6 route show dev dummy98' )
5392 output
= check_output ( 'ip -6 route show dev dummy98' )
5394 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5396 print ( '### ip -6 route show dev dummy99' )
5397 output
= check_output ( 'ip -6 route show dev dummy99' )
5399 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
5401 print ( '### ip -6 route show dev veth97' )
5402 output
= check_output ( 'ip -6 route show dev veth97' )
5404 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto kernel metric [0-9]* expires' )
5406 print ( '### ip -6 route show dev veth97-peer' )
5407 output
= check_output ( 'ip -6 route show dev veth97-peer' )
5409 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto ra metric [0-9]* expires' )
5411 print ( '### ip -6 route show dev veth98' )
5412 output
= check_output ( 'ip -6 route show dev veth98' )
5414 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto kernel metric [0-9]* expires' )
5416 print ( '### ip -6 route show dev veth98-peer' )
5417 output
= check_output ( 'ip -6 route show dev veth98-peer' )
5419 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto ra metric [0-9]* expires' )
5421 # Test case for a downstream which appears later
5422 check_output ( 'ip link add dummy97 type dummy' )
5423 self
. wait_online ([ 'dummy97:routable' ])
5425 print ( '### ip -6 address show dev dummy97 scope global' )
5426 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
5428 # address in IA_PD (Token=static)
5429 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5430 # address in IA_PD (temporary)
5431 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' )
5433 print ( '### ip -6 route show dev dummy97' )
5434 output
= check_output ( 'ip -6 route show dev dummy97' )
5436 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]01::/64 proto kernel metric [0-9]* expires' )
5438 # Test case for reconfigure
5439 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
5440 self
. wait_online ([ 'dummy98:routable' , 'dummy99:degraded' ])
5442 print ( '### ip -6 address show dev dummy98 scope global' )
5443 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5445 # address in IA_PD (Token=static)
5446 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5447 # address in IA_PD (temporary)
5448 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' )
5450 print ( '### ip -6 address show dev dummy99 scope global' )
5451 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5454 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
5456 print ( '### ip -6 route show dev dummy98' )
5457 output
= check_output ( 'ip -6 route show dev dummy98' )
5459 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
5461 print ( '### ip -6 route show dev dummy99' )
5462 output
= check_output ( 'ip -6 route show dev dummy99' )
5464 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
5466 self
. check_netlabel ( 'dummy98' , '3ffe:501:ffff:[2-9a-f]00::/64' )
5468 def verify_dhcp4_6rd ( self
, tunnel_name
):
5469 print ( '### ip -4 address show dev veth-peer scope global' )
5470 output
= check_output ( 'ip -4 address show dev veth-peer scope global' )
5472 self
. assertIn ( 'inet 10.0.0.1/8 brd 10.255.255.255 scope global veth-peer' , output
)
5476 # dummy97: 0x01 (The link will appear later)
5478 # dummy99: auto -> 0x0[23] (No address assignment)
5479 # 6rd-XXX: auto -> 0x0[23]
5484 print ( '### ip -4 address show dev veth99 scope global' )
5485 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
5487 self
. assertRegex ( output
, 'inet 10.100.100.[0-9]*/8 (metric 1024 |)brd 10.255.255.255 scope global dynamic veth99' )
5489 print ( '### ip -6 address show dev veth99 scope global' )
5490 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
5492 # address in IA_PD (Token=static)
5493 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5494 # address in IA_PD (Token=eui64)
5495 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5496 # address in IA_PD (temporary)
5497 # Note that the temporary addresses may appear after the link enters configured state
5498 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' )
5500 print ( '### ip -6 address show dev test1 scope global' )
5501 output
= check_output ( 'ip -6 address show dev test1 scope global' )
5503 # address in IA_PD (Token=static)
5504 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5505 # address in IA_PD (temporary)
5506 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' )
5508 print ( '### ip -6 address show dev dummy98 scope global' )
5509 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
5511 # address in IA_PD (Token=static)
5512 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5513 # address in IA_PD (temporary)
5514 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' )
5516 print ( '### ip -6 address show dev dummy99 scope global' )
5517 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
5520 self
. assertNotRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+0[23]' )
5522 print ( '### ip -6 address show dev veth97 scope global' )
5523 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
5525 # address in IA_PD (Token=static)
5526 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5527 # address in IA_PD (Token=eui64)
5528 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5529 # address in IA_PD (temporary)
5530 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' )
5532 print ( '### ip -6 address show dev veth97-peer scope global' )
5533 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
5535 # NDisc address (Token=static)
5536 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5537 # NDisc address (Token=eui64)
5538 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5539 # NDisc address (temporary)
5540 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' )
5542 print ( '### ip -6 address show dev veth98 scope global' )
5543 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
5545 # address in IA_PD (Token=static)
5546 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5547 # address in IA_PD (Token=eui64)
5548 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5549 # address in IA_PD (temporary)
5550 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' )
5552 print ( '### ip -6 address show dev veth98-peer scope global' )
5553 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
5555 # NDisc address (Token=static)
5556 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5557 # NDisc address (Token=eui64)
5558 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5559 # NDisc address (temporary)
5560 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' )
5562 print ( '### ip -6 route show type unreachable' )
5563 output
= check_output ( 'ip -6 route show type unreachable' )
5565 self
. assertRegex ( output
, 'unreachable 2001:db8:6464:[0-9a-f]+00::/56 dev lo proto dhcp' )
5567 print ( '### ip -6 route show dev veth99' )
5568 output
= check_output ( 'ip -6 route show dev veth99' )
5570 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+10::/64 proto kernel metric [0-9]* expires' )
5572 print ( '### ip -6 route show dev test1' )
5573 output
= check_output ( 'ip -6 route show dev test1' )
5575 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
5577 print ( '### ip -6 route show dev dummy98' )
5578 output
= check_output ( 'ip -6 route show dev dummy98' )
5580 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
5582 print ( '### ip -6 route show dev dummy99' )
5583 output
= check_output ( 'ip -6 route show dev dummy99' )
5585 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto dhcp metric [0-9]* expires' )
5587 print ( '### ip -6 route show dev veth97' )
5588 output
= check_output ( 'ip -6 route show dev veth97' )
5590 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto kernel metric [0-9]* expires' )
5592 print ( '### ip -6 route show dev veth97-peer' )
5593 output
= check_output ( 'ip -6 route show dev veth97-peer' )
5595 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto ra metric [0-9]* expires' )
5597 print ( '### ip -6 route show dev veth98' )
5598 output
= check_output ( 'ip -6 route show dev veth98' )
5600 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto kernel metric [0-9]* expires' )
5602 print ( '### ip -6 route show dev veth98-peer' )
5603 output
= check_output ( 'ip -6 route show dev veth98-peer' )
5605 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto ra metric [0-9]* expires' )
5607 print ( '### ip -6 address show dev dummy97 scope global' )
5608 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
5610 # address in IA_PD (Token=static)
5611 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
5612 # address in IA_PD (temporary)
5613 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' )
5615 print ( '### ip -6 route show dev dummy97' )
5616 output
= check_output ( 'ip -6 route show dev dummy97' )
5618 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+01::/64 proto kernel metric [0-9]* expires' )
5620 print ( f
'### ip -d link show dev {tunnel_name} ' )
5621 output
= check_output ( f
'ip -d link show dev {tunnel_name} ' )
5623 self
. assertIn ( 'link/sit 10.100.100.' , output
)
5624 self
. assertIn ( 'local 10.100.100.' , output
)
5625 self
. assertIn ( 'ttl 64' , output
)
5626 self
. assertIn ( '6rd-prefix 2001:db8::/32' , output
)
5627 self
. assertIn ( '6rd-relay_prefix 10.0.0.0/8' , output
)
5629 print ( f
'### ip -6 address show dev {tunnel_name} ' )
5630 output
= check_output ( f
'ip -6 address show dev {tunnel_name} ' )
5632 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' )
5633 self
. assertRegex ( output
, 'inet6 ::10.100.100.[0-9]+/96 scope global' )
5635 print ( f
'### ip -6 route show dev {tunnel_name} ' )
5636 output
= check_output ( f
'ip -6 route show dev {tunnel_name} ' )
5638 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto kernel metric [0-9]* expires' )
5639 self
. assertRegex ( output
, '::/96 proto kernel metric [0-9]*' )
5641 print ( '### ip -6 route show default' )
5642 output
= check_output ( 'ip -6 route show default' )
5644 self
. assertIn ( 'default' , output
)
5645 self
. assertIn ( f
'via ::10.0.0.1 dev {tunnel_name} ' , output
)
5647 def test_dhcp4_6rd ( self
):
5648 copy_network_unit ( '25-veth.netdev' , '25-dhcp4-6rd-server.network' , '25-dhcp4-6rd-upstream.network' ,
5649 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
5650 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
5651 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
5652 '25-dhcp-pd-downstream-dummy97.network' ,
5653 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
5654 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' ,
5655 '80-6rd-tunnel.network' )
5658 self
. wait_online ([ 'veth-peer:routable' ])
5661 # 6rd-prefix: 2001:db8::/32
5662 # br-addresss: 10.0.0.1
5664 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' ,
5665 ipv4_range
= '10.100.100.100,10.100.100.200' ,
5666 ipv4_router
= '10.0.0.1' )
5667 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5668 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5670 # Test case for a downstream which appears later
5671 check_output ( 'ip link add dummy97 type dummy' )
5672 self
. wait_online ([ 'dummy97:routable' ])
5676 for name
in os
. listdir ( '/sys/class/net/' ):
5677 if name
. startswith ( '6rd-' ):
5681 self
. wait_online ([ f
' {tunnel_name} :routable' ])
5683 self
. verify_dhcp4_6rd ( tunnel_name
)
5685 # Test case for reconfigure
5686 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
5687 self
. wait_online ([ 'dummy98:routable' , 'dummy99:degraded' ])
5689 self
. verify_dhcp4_6rd ( tunnel_name
)
5691 print ( 'Wait for the DHCP lease to be renewed/rebind' )
5694 self
. wait_online ([ 'veth99:routable' , 'test1:routable' , 'dummy97:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
5695 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' ])
5697 self
. verify_dhcp4_6rd ( tunnel_name
)
5699 class NetworkdIPv6PrefixTests ( unittest
. TestCase
, Utilities
):
5707 def test_ipv6_route_prefix ( self
):
5708 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client.network' , '25-ipv6ra-prefix.network' ,
5709 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
5712 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
5714 output
= check_output ( 'ip address show dev veth-peer' )
5716 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
5717 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
5718 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
5720 output
= check_output ( 'ip -6 route show dev veth-peer' )
5722 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
5723 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
5724 self
. assertNotIn ( '2001:db8:0:3::/64 proto ra' , output
)
5725 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
5726 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
5727 self
. assertNotIn ( '2001:db2:fff::/64 via ' , output
)
5729 output
= check_output ( 'ip address show dev veth99' )
5731 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
5732 self
. assertIn ( 'inet6 2001:db8:0:2:1a:2b:3c:4d' , output
)
5733 self
. assertIn ( 'inet6 2001:db8:0:2:fa:de:ca:fe' , output
)
5734 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
5736 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth-peer' , env
= env
)
5738 self
. assertRegex ( output
, '2001:db8:1:1::2' )
5740 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth-peer' , env
= env
)
5742 self
. assertIn ( 'example.com' , output
)
5744 # TODO: check json string
5745 check_output (* networkctl_cmd
, '--json=short' , 'status' , env
= env
)
5747 def test_ipv6_route_prefix_deny_list ( self
):
5748 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client-deny-list.network' , '25-ipv6ra-prefix.network' ,
5749 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
5752 self
. wait_online ([ 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' ])
5754 output
= check_output ( 'ip address show dev veth-peer' )
5756 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
5757 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
5759 output
= check_output ( 'ip -6 route show dev veth-peer' )
5761 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
5762 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
5763 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
5764 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
5766 output
= check_output ( 'ip address show dev veth99' )
5768 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
5769 self
. assertIn ( 'inet6 2001:db8:0:2:' , output
)
5771 output
= check_output (* resolvectl_cmd
, 'dns' , 'veth-peer' , env
= env
)
5773 self
. assertRegex ( output
, '2001:db8:1:1::2' )
5775 output
= check_output (* resolvectl_cmd
, 'domain' , 'veth-peer' , env
= env
)
5777 self
. assertIn ( 'example.com' , output
)
5779 class NetworkdMTUTests ( unittest
. TestCase
, Utilities
):
5787 def check_mtu ( self
, mtu
, ipv6_mtu
= None , reset
= True ):
5793 self
. wait_online ([ 'dummy98:routable' ])
5794 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
5795 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
5797 # test normal restart
5799 self
. wait_online ([ 'dummy98:routable' ])
5800 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
5801 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
5804 self
. reset_check_mtu ( mtu
, ipv6_mtu
)
5806 def reset_check_mtu ( self
, mtu
, ipv6_mtu
= None ):
5807 ''' test setting mtu/ipv6_mtu with interface already up '''
5810 # note - changing the device mtu resets the ipv6 mtu
5811 check_output ( 'ip link set up mtu 1501 dev dummy98' )
5812 check_output ( 'ip link set up mtu 1500 dev dummy98' )
5813 self
. check_link_attr ( 'dummy98' , 'mtu' , '1500' )
5814 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , '1500' )
5816 self
. check_mtu ( mtu
, ipv6_mtu
, reset
= False )
5818 def test_mtu_network ( self
):
5819 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' )
5820 self
. check_mtu ( '1600' )
5822 def test_mtu_netdev ( self
):
5823 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network' , copy_dropins
= False )
5824 # note - MTU set by .netdev happens ONLY at device creation!
5825 self
. check_mtu ( '1600' , reset
= False )
5827 def test_mtu_link ( self
):
5828 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network' , copy_dropins
= False )
5829 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
5830 self
. check_mtu ( '1600' , reset
= False )
5832 def test_ipv6_mtu ( self
):
5833 ''' set ipv6 mtu without setting device mtu '''
5834 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1400.conf' )
5835 self
. check_mtu ( '1500' , '1400' )
5837 def test_ipv6_mtu_toolarge ( self
):
5838 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
5839 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5840 self
. check_mtu ( '1500' , '1500' )
5842 def test_mtu_network_ipv6_mtu ( self
):
5843 ''' set ipv6 mtu and set device mtu via network file '''
5844 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5845 self
. check_mtu ( '1600' , '1550' )
5847 def test_mtu_netdev_ipv6_mtu ( self
):
5848 ''' set ipv6 mtu and set device mtu via netdev file '''
5849 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5850 self
. check_mtu ( '1600' , '1550' , reset
= False )
5852 def test_mtu_link_ipv6_mtu ( self
):
5853 ''' set ipv6 mtu and set device mtu via link file '''
5854 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
5855 self
. check_mtu ( '1600' , '1550' , reset
= False )
5858 if __name__
== '__main__' :
5859 parser
= argparse
. ArgumentParser ()
5860 parser
. add_argument ( '--build-dir' , help = 'Path to build dir' , dest
= 'build_dir' )
5861 parser
. add_argument ( '--networkd' , help = 'Path to systemd-networkd' , dest
= 'networkd_bin' )
5862 parser
. add_argument ( '--resolved' , help = 'Path to systemd-resolved' , dest
= 'resolved_bin' )
5863 parser
. add_argument ( '--timesyncd' , help = 'Path to systemd-timesyncd' , dest
= 'timesyncd_bin' )
5864 parser
. add_argument ( '--udevd' , help = 'Path to systemd-udevd' , dest
= 'udevd_bin' )
5865 parser
. add_argument ( '--wait-online' , help = 'Path to systemd-networkd-wait-online' , dest
= 'wait_online_bin' )
5866 parser
. add_argument ( '--networkctl' , help = 'Path to networkctl' , dest
= 'networkctl_bin' )
5867 parser
. add_argument ( '--resolvectl' , help = 'Path to resolvectl' , dest
= 'resolvectl_bin' )
5868 parser
. add_argument ( '--timedatectl' , help = 'Path to timedatectl' , dest
= 'timedatectl_bin' )
5869 parser
. add_argument ( '--udevadm' , help = 'Path to udevadm' , dest
= 'udevadm_bin' )
5870 parser
. add_argument ( '--valgrind' , help = 'Enable valgrind' , dest
= 'use_valgrind' , type = bool , nargs
= '?' , const
= True , default
= use_valgrind
)
5871 parser
. add_argument ( '--debug' , help = 'Generate debugging logs' , dest
= 'enable_debug' , type = bool , nargs
= '?' , const
= True , default
= enable_debug
)
5872 parser
. add_argument ( '--asan-options' , help = 'ASAN options' , dest
= 'asan_options' )
5873 parser
. add_argument ( '--lsan-options' , help = 'LSAN options' , dest
= 'lsan_options' )
5874 parser
. add_argument ( '--ubsan-options' , help = 'UBSAN options' , dest
= 'ubsan_options' )
5875 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
)
5876 ns
, unknown_args
= parser
. parse_known_args ( namespace
= unittest
)
5879 if ns
. networkd_bin
or ns
. resolved_bin
or ns
. timesyncd_bin
or ns
. udevd_bin
or \
5880 ns
. wait_online_bin
or ns
. networkctl_bin
or ns
. resolvectl_bin
or ns
. timedatectl_bin
or ns
. udevadm_bin
:
5881 print ( 'WARNING: --networkd, --resolved, --timesyncd, --udevd, --wait-online, --networkctl, --resolvectl, --timedatectl, or --udevadm options are ignored when --build-dir is specified.' )
5882 networkd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd' )
5883 resolved_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-resolved' )
5884 timesyncd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-timesyncd' )
5885 udevd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-udevd' )
5886 wait_online_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd-wait-online' )
5887 networkctl_bin
= os
. path
. join ( ns
. build_dir
, 'networkctl' )
5888 resolvectl_bin
= os
. path
. join ( ns
. build_dir
, 'resolvectl' )
5889 timedatectl_bin
= os
. path
. join ( ns
. build_dir
, 'timedatectl' )
5890 udevadm_bin
= os
. path
. join ( ns
. build_dir
, 'udevadm' )
5893 networkd_bin
= ns
. networkd_bin
5895 resolved_bin
= ns
. resolved_bin
5896 if ns
. timesyncd_bin
:
5897 timesyncd_bin
= ns
. timesyncd_bin
5899 udevd_bin
= ns
. udevd_bin
5900 if ns
. wait_online_bin
:
5901 wait_online_bin
= ns
. wait_online_bin
5902 if ns
. networkctl_bin
:
5903 networkctl_bin
= ns
. networkctl_bin
5904 if ns
. resolvectl_bin
:
5905 resolvectl_bin
= ns
. resolvectl_bin
5906 if ns
. timedatectl_bin
:
5907 timedatectl_bin
= ns
. timedatectl_bin
5909 udevadm_bin
= ns
. udevadm_bin
5911 use_valgrind
= ns
. use_valgrind
5912 enable_debug
= ns
. enable_debug
5913 asan_options
= ns
. asan_options
5914 lsan_options
= ns
. lsan_options
5915 ubsan_options
= ns
. ubsan_options
5916 with_coverage
= ns
. with_coverage
5919 # Do not forget the trailing space.
5920 valgrind_cmd
= 'valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all '
5922 networkctl_cmd
= valgrind_cmd
. split () + [ networkctl_bin
]
5923 resolvectl_cmd
= valgrind_cmd
. split () + [ resolvectl_bin
]
5924 timedatectl_cmd
= valgrind_cmd
. split () + [ timedatectl_bin
]
5925 udevadm_cmd
= valgrind_cmd
. split () + [ udevadm_bin
]
5926 wait_online_cmd
= valgrind_cmd
. split () + [ wait_online_bin
]
5929 env
. update ({ 'ASAN_OPTIONS' : asan_options
})
5931 env
. update ({ 'LSAN_OPTIONS' : lsan_options
})
5933 env
. update ({ 'UBSAN_OPTIONS' : ubsan_options
})
5935 env
. update ({ 'SYSTEMD_MEMPOOL' : '0' })
5937 wait_online_env
= env
. copy ()
5939 wait_online_env
. update ({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
5941 sys
. argv
[ 1 :] = unknown_args
5942 unittest
. main ( verbosity
= 3 )