]>
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 # systemd-networkd tests
5 # These tests can be executed in the systemd mkosi image when booted in QEMU. After booting the QEMU VM,
6 # simply run this file which can be found in the VM at /usr/lib/systemd/tests/testdata/test-network/systemd-networkd-tests.py.
8 # To run an individual test, specify it as a command line argument in the form
9 # of <class>.<test_function>. E.g. the NetworkdMTUTests class has a test
10 # function called test_ipv6_mtu(). To run just that test use:
12 # sudo ./systemd-networkd-tests.py NetworkdMTUTests.test_ipv6_mtu
14 # Similarly, other individual tests can be run, eg.:
16 # sudo ./systemd-networkd-tests.py NetworkdNetworkTests.test_ipv6_neigh_retrans_time
37 network_unit_dir
= '/run/systemd/network'
38 networkd_conf_dropin_dir
= '/run/systemd/networkd.conf.d'
39 networkd_ci_temp_dir
= '/run/networkd-ci'
40 udev_rules_dir
= '/run/udev/rules.d'
41 credstore_dir
= '/run/credstore'
43 dnsmasq_pid_file
= '/run/networkd-ci/test-dnsmasq.pid'
44 dnsmasq_log_file
= '/run/networkd-ci/test-dnsmasq.log'
45 dnsmasq_lease_file
= '/run/networkd-ci/test-dnsmasq.lease'
47 isc_dhcpd_pid_file
= '/run/networkd-ci/test-isc-dhcpd.pid'
48 isc_dhcpd_lease_file
= '/run/networkd-ci/test-isc-dhcpd.lease'
50 radvd_pid_file
= '/run/networkd-ci/test-radvd.pid'
52 systemd_lib_paths
= [ '/usr/lib/systemd' , '/lib/systemd' ]
53 which_paths
= ':' . join ( systemd_lib_paths
+ os
. getenv ( 'PATH' , os
. defpath
). lstrip ( ':' ). split ( ':' ))
55 networkd_bin
= shutil
. which ( 'systemd-networkd' , path
= which_paths
)
56 resolved_bin
= shutil
. which ( 'systemd-resolved' , path
= which_paths
)
57 timesyncd_bin
= shutil
. which ( 'systemd-timesyncd' , path
= which_paths
)
58 wait_online_bin
= shutil
. which ( 'systemd-networkd-wait-online' , path
= which_paths
)
59 networkctl_bin
= shutil
. which ( 'networkctl' , path
= which_paths
)
60 resolvectl_bin
= shutil
. which ( 'resolvectl' , path
= which_paths
)
61 timedatectl_bin
= shutil
. which ( 'timedatectl' , path
= which_paths
)
62 udevadm_bin
= shutil
. which ( 'udevadm' , path
= which_paths
)
92 saved_ipv4_rules
= None
93 saved_ipv6_rules
= None
97 if os
. path
. exists ( path
):
101 shutil
. rmtree ( path
, ignore_errors
= True )
104 shutil
. copy ( src
, dst
)
107 shutil
. copytree ( src
, dst
, copy_function
= shutil
. copy
)
110 os
. makedirs ( path
, exist_ok
= True )
113 pathlib
. Path ( path
). touch ()
115 # pylint: disable=R1710
116 def check_output (* command
, ** kwargs
):
117 # This checks the result and returns stdout (and stderr) on success.
118 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
119 ret
= subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. PIPE
, stderr
= subprocess
. STDOUT
, ** kwargs
)
120 if ret
. returncode
== 0 :
121 return ret
. stdout
. rstrip ()
122 # When returncode != 0, print stdout and stderr, then trigger CalledProcessError.
124 ret
. check_returncode ()
126 def call (* command
, ** kwargs
):
127 # This returns returncode. stdout and stderr are merged and shown in console
128 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
129 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stderr
= subprocess
. STDOUT
, ** kwargs
). returncode
131 def call_check (* command
, ** kwargs
):
132 # Same as call() above, but it triggers CalledProcessError if rc != 0
133 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
134 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stderr
= subprocess
. STDOUT
, ** kwargs
). check_returncode ()
136 def call_quiet (* command
, ** kwargs
):
137 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
138 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. DEVNULL
, stderr
= subprocess
. DEVNULL
, ** kwargs
). returncode
140 def run (* command
, ** kwargs
):
141 # This returns CompletedProcess instance.
142 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
143 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. PIPE
, stderr
= subprocess
. PIPE
, ** kwargs
)
145 def check_json ( string
):
148 except json
. JSONDecodeError
:
149 print ( f
"String is not a valid JSON: ' {string} '" )
152 def is_module_available (* module_names
):
153 for module_name
in module_names
:
154 lsmod_output
= check_output ( 'lsmod' )
155 module_re
= re
. compile ( rf
'^{re.escape(module_name)} \b ' , re
. MULTILINE
)
156 if not module_re
. search ( lsmod_output
) and call_quiet ( 'modprobe' , module_name
) != 0 :
160 def expectedFailureIfModuleIsNotAvailable (* module_names
):
162 return func
if is_module_available (* module_names
) else unittest
. expectedFailure ( func
)
166 def expectedFailureIfERSPANv0IsNotSupported ():
167 # erspan version 0 is supported since f989d546a2d5a9f001f6f8be49d98c10ab9b1897 (v5.8)
169 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' )
170 remove_link ( 'erspan99' )
171 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
175 def expectedFailureIfERSPANv2IsNotSupported ():
176 # erspan version 2 is supported since f551c91de262ba36b20c3ac19538afb4f4507441 (v4.16)
178 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' )
179 remove_link ( 'erspan99' )
180 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
184 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable ():
186 rc
= call_quiet ( 'ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7' )
187 call_quiet ( 'ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7' )
188 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
192 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable ():
194 rc
= call_quiet ( 'ip rule add not from 192.168.100.19 ipproto tcp table 7' )
195 call_quiet ( 'ip rule del not from 192.168.100.19 ipproto tcp table 7' )
196 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
200 def expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable ():
203 if call_quiet ( 'ip rule add from 192.168.100.19 table 7 uidrange 200-300' ) == 0 :
204 ret
= run ( 'ip rule list from 192.168.100.19 table 7' )
205 supported
= ret
. returncode
== 0 and 'uidrange 200-300' in ret
. stdout
206 call_quiet ( 'ip rule del from 192.168.100.19 table 7 uidrange 200-300' )
207 return func
if supported
else unittest
. expectedFailure ( func
)
211 def expectedFailureIfRoutingPolicyL3MasterDeviceIsNotAvailable ():
213 rc
= call_quiet ( 'ip rule add not from 192.168.100.19 l3mdev' )
214 call_quiet ( 'ip rule del not from 192.168.100.19 l3mdev' )
215 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
219 def expectedFailureIfNexthopIsNotAvailable ():
221 rc
= call_quiet ( 'ip nexthop list' )
222 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
226 def expectedFailureIfRTA_VIAIsNotSupported ():
228 call_quiet ( 'ip link add dummy98 type dummy' )
229 call_quiet ( 'ip link set up dev dummy98' )
230 call_quiet ( 'ip route add 2001:1234:5:8fff:ff:ff:ff:fe/128 dev dummy98' )
231 rc
= call_quiet ( 'ip route add 10.10.10.10 via inet6 2001:1234:5:8fff:ff:ff:ff:fe dev dummy98' )
232 remove_link ( 'dummy98' )
233 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
237 def expectedFailureIfAlternativeNameIsNotAvailable ():
239 call_quiet ( 'ip link add dummy98 type dummy' )
241 call_quiet ( 'ip link prop add dev dummy98 altname hogehogehogehogehoge' ) == 0 and \
242 call_quiet ( 'ip link show dev hogehogehogehogehoge' ) == 0
243 remove_link ( 'dummy98' )
244 return func
if supported
else unittest
. expectedFailure ( func
)
248 def expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ():
250 def finalize ( func
, supported
):
251 call_quiet ( 'rmmod netdevsim' )
252 return func
if supported
else unittest
. expectedFailure ( func
)
254 call_quiet ( 'rmmod netdevsim' )
255 if call_quiet ( 'modprobe netdevsim' ) != 0 :
256 return finalize ( func
, False )
259 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
262 return finalize ( func
, False )
264 return finalize ( func
, os
. path
. exists ( '/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs' ))
268 # pylint: disable=C0415
269 def compare_kernel_version ( min_kernel_version
):
272 from packaging
import version
274 print ( 'Failed to import either platform or packaging module, assuming the comparison failed' )
277 # Get only the actual kernel version without any build/distro/arch stuff
278 # e.g. '5.18.5-200.fc36.x86_64' -> '5.18.5'
279 kver
= platform
. release (). split ( '-' )[ 0 ]
280 # Get also rid of '+'
281 kver
= kver
. split ( '+' )[ 0 ]
283 return version
. parse ( kver
) >= version
. parse ( min_kernel_version
)
285 def copy_network_unit (* units
, copy_dropins
= True ):
287 Copy networkd unit files into the testbed.
289 Any networkd unit file type can be specified, as well as drop-in files.
291 By default, all drop-ins for a specified unit file are copied in;
292 to avoid that specify dropins=False.
294 When a drop-in file is specified, its unit file is also copied in automatically.
297 mkdir_p ( network_unit_dir
)
299 if copy_dropins
and os
. path
. exists ( os
. path
. join ( networkd_ci_temp_dir
, unit
+ '.d' )):
300 cp_r ( os
. path
. join ( networkd_ci_temp_dir
, unit
+ '.d' ), os
. path
. join ( network_unit_dir
, unit
+ '.d' ))
302 if unit
. endswith ( '.conf' ):
304 unit
= os
. path
. dirname ( dropin
). rstrip ( '.d' )
305 dropindir
= os
. path
. join ( network_unit_dir
, unit
+ '.d' )
307 cp ( os
. path
. join ( networkd_ci_temp_dir
, dropin
), dropindir
)
309 cp ( os
. path
. join ( networkd_ci_temp_dir
, unit
), network_unit_dir
)
311 if unit
. endswith ( '.link' ):
317 def copy_credential ( src
, target
):
318 mkdir_p ( credstore_dir
)
319 cp ( os
. path
. join ( networkd_ci_temp_dir
, src
),
320 os
. path
. join ( credstore_dir
, target
))
322 def remove_network_unit (* units
):
324 Remove previously copied unit files from the testbed.
326 Drop-ins will be removed automatically.
330 rm_f ( os
. path
. join ( network_unit_dir
, unit
))
331 rm_rf ( os
. path
. join ( network_unit_dir
, unit
+ '.d' ))
333 if unit
. endswith ( '.link' ) or unit
. endswith ( '.link.d' ):
339 def clear_network_units ():
341 if os
. path
. exists ( network_unit_dir
):
342 units
= os
. listdir ( network_unit_dir
)
344 if unit
. endswith ( '.link' ) or unit
. endswith ( '.link.d' ):
347 rm_rf ( network_unit_dir
)
352 def copy_networkd_conf_dropin (* dropins
):
353 """Copy networkd.conf dropin files into the testbed."""
354 mkdir_p ( networkd_conf_dropin_dir
)
355 for dropin
in dropins
:
356 cp ( os
. path
. join ( networkd_ci_temp_dir
, dropin
), networkd_conf_dropin_dir
)
358 def remove_networkd_conf_dropin (* dropins
):
359 """Remove previously copied networkd.conf dropin files from the testbed."""
360 for dropin
in dropins
:
361 rm_f ( os
. path
. join ( networkd_conf_dropin_dir
, dropin
))
363 def clear_networkd_conf_dropins ():
364 rm_rf ( networkd_conf_dropin_dir
)
366 def setup_systemd_udev_rules ():
370 mkdir_p ( udev_rules_dir
)
372 for path
in [ build_dir
, source_dir
]:
373 path
= os
. path
. join ( path
, "rules.d" )
374 print ( f
"Copying udev rules from {path} to {udev_rules_dir} " )
376 for rule
in os
. listdir ( path
):
377 if not rule
. endswith ( ".rules" ):
379 cp ( os
. path
. join ( path
, rule
), udev_rules_dir
)
381 def clear_networkd_state_files ():
382 rm_rf ( '/var/lib/systemd/network/' )
384 def copy_udev_rule (* rules
):
385 """Copy udev rules"""
386 mkdir_p ( udev_rules_dir
)
388 cp ( os
. path
. join ( networkd_ci_temp_dir
, rule
), udev_rules_dir
)
390 def remove_udev_rule (* rules
):
391 """Remove previously copied udev rules"""
393 rm_f ( os
. path
. join ( udev_rules_dir
, rule
))
395 def clear_udev_rules ():
396 rm_rf ( udev_rules_dir
)
398 def save_active_units ():
399 for u
in [ 'systemd-networkd.socket' , 'systemd-networkd.service' ,
400 'systemd-resolved.service' , 'systemd-timesyncd.service' ,
401 'firewalld.service' ]:
402 if call ( f
'systemctl is-active --quiet {u} ' ) == 0 :
403 call ( f
'systemctl stop {u} ' )
404 active_units
. append ( u
)
406 def restore_active_units ():
407 if 'systemd-networkd.socket' in active_units
:
408 call ( 'systemctl stop systemd-networkd.socket systemd-networkd.service' )
409 for u
in active_units
:
410 call ( f
'systemctl restart {u} ' )
412 def create_unit_dropin ( unit
, contents
):
413 mkdir_p ( f
'/run/systemd/system/ {unit} .d' )
414 with
open ( f
'/run/systemd/system/ {unit} .d/00-override.conf' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
415 f
. write ( ' \n ' . join ( contents
))
417 def create_service_dropin ( service
, command
, additional_settings
= None ):
418 drop_in
= [ '[Service]' ]
422 f
'ExecStart=!! {valgrind_cmd}{command} ' ,
425 drop_in
+= [ 'Environment=SYSTEMD_LOG_LEVEL=debug' ]
427 drop_in
+= [ f
'Environment=ASAN_OPTIONS=" {asan_options} "' ]
429 drop_in
+= [ f
'Environment=LSAN_OPTIONS=" {lsan_options} "' ]
431 drop_in
+= [ f
'Environment=UBSAN_OPTIONS=" {ubsan_options} "' ]
432 if asan_options
or lsan_options
or ubsan_options
:
433 drop_in
+= [ 'SystemCallFilter=' ]
434 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
435 drop_in
+= [ 'MemoryDenyWriteExecute=no' ]
438 'Environment=SYSTEMD_MEMPOOL=0' ,
446 if additional_settings
:
447 drop_in
+= additional_settings
449 create_unit_dropin ( f
' {service} .service' , drop_in
)
451 def setup_system_units ():
453 mkdir_p ( '/run/systemd/system/' )
456 'systemd-networkd.service' ,
457 'systemd-networkd.socket' ,
458 'systemd-networkd-persistent-storage.service' ,
459 'systemd-resolved.service' ,
460 'systemd-timesyncd.service' ,
461 'systemd-udevd.service' ,
463 for path
in [ build_dir
, source_dir
]:
464 fullpath
= os
. path
. join ( os
. path
. join ( path
, "units" ), unit
)
465 if os
. path
. exists ( fullpath
):
466 print ( f
"Copying unit file from {fullpath} to /run/systemd/system/" )
467 cp ( fullpath
, '/run/systemd/system/' )
470 create_service_dropin ( 'systemd-networkd' , networkd_bin
,
473 'Environment=SYSTEMD_NETWORK_TEST_MODE=yes' ,
475 'StartLimitIntervalSec=0' ])
476 create_service_dropin ( 'systemd-resolved' , resolved_bin
)
477 create_service_dropin ( 'systemd-timesyncd' , timesyncd_bin
)
479 # TODO: also run udevd with sanitizers, valgrind, or coverage
481 'systemd-udevd.service' ,
485 f
'ExecStart=!!@ {udevadm_bin} systemd-udevd' ,
489 'systemd-networkd.socket' ,
492 'StartLimitIntervalSec=0' ,
496 'systemd-networkd-persistent-storage.service' ,
499 'StartLimitIntervalSec=0' ,
502 f
'ExecStart= {networkctl_bin} persistent-storage yes' ,
504 f
'ExecStop= {networkctl_bin} persistent-storage no'
508 check_output ( 'systemctl daemon-reload' )
509 print ( check_output ( 'systemctl cat systemd-networkd.service' ))
510 print ( check_output ( 'systemctl cat systemd-networkd-persistent-storage.service' ))
511 print ( check_output ( 'systemctl cat systemd-resolved.service' ))
512 print ( check_output ( 'systemctl cat systemd-timesyncd.service' ))
513 print ( check_output ( 'systemctl cat systemd-udevd.service' ))
514 check_output ( 'systemctl restart systemd-resolved.service' )
515 check_output ( 'systemctl restart systemd-timesyncd.service' )
516 check_output ( 'systemctl restart systemd-udevd.service' )
518 def clear_system_units ():
520 rm_f ( f
'/run/systemd/system/ {name} ' )
521 rm_rf ( f
'/run/systemd/system/ {name} .d' )
523 rm_unit ( 'systemd-networkd.service' )
524 rm_unit ( 'systemd-networkd.socket' )
525 rm_unit ( 'systemd-networkd-persistent-storage.service' )
526 rm_unit ( 'systemd-resolved.service' )
527 rm_unit ( 'systemd-timesyncd.service' )
528 rm_unit ( 'systemd-udevd.service' )
529 check_output ( 'systemctl daemon-reload' )
530 check_output ( 'systemctl restart systemd-udevd.service' )
532 def link_exists ( link
):
533 return call_quiet ( f
'ip link show {link} ' ) == 0
535 def link_resolve ( link
):
536 return check_output ( f
'ip link show {link} ' ). split ( ':' )[ 1 ]. strip ()
538 def remove_link (* links
, protect
= False ):
540 if protect
and link
in protected_links
:
542 if link_exists ( link
):
543 call ( f
'ip link del dev {link} ' )
545 def save_existing_links ():
546 links
= os
. listdir ( '/sys/class/net' )
548 if link_exists ( link
):
549 protected_links
. add ( link
)
551 print ( '### The following links will be protected:' )
552 print ( ', ' . join ( sorted ( list ( protected_links
))))
555 links
= os
. listdir ( '/sys/class/net' )
556 remove_link (* links
, protect
= True )
558 def flush_nexthops ():
559 # Currently, the 'ip nexthop' command does not have 'save' and 'restore'.
560 # Hence, we cannot restore nexthops in a simple way.
561 # Let's assume there is no nexthop used in the system
562 call_quiet ( 'ip nexthop flush' )
565 # pylint: disable=global-statement
567 saved_routes
= check_output ( 'ip route show table all' )
568 print ( '### The following routes will be protected:' )
573 output
= check_output ( 'ip route show table all' )
574 for line
in output
. splitlines ():
575 if line
in saved_routes
:
577 if 'proto kernel' in line
:
579 if ' dev ' in line
and not ' dev lo ' in line
:
583 print ( '### Removing routes that did not exist when the test started.' )
585 call ( f
'ip route del {line} ' )
587 def save_routing_policy_rules ():
588 # pylint: disable=global-statement
589 global saved_ipv4_rules
, saved_ipv6_rules
591 output
= check_output ( f
'ip - {ipv} rule show' )
592 print ( f
'### The following IPv {ipv} routing policy rules will be protected:' )
596 saved_ipv4_rules
= save ( 4 )
597 saved_ipv6_rules
= save ( 6 )
599 def flush_routing_policy_rules ():
600 def flush ( ipv
, saved_rules
):
602 output
= check_output ( f
'ip - {ipv} rule show' )
603 for line
in output
. splitlines ():
604 if line
in saved_rules
:
608 print ( f
'### Removing IPv {ipv} routing policy rules that did not exist when the test started.' )
610 words
= line
. replace ( 'lookup [l3mdev-table]' , 'l3mdev' ). split ()
611 priority
= words
[ 0 ]. rstrip ( ':' )
612 call ( f
'ip - {ipv} rule del priority {priority} ' + ' ' . join ( words
[ 1 :]))
614 flush ( 4 , saved_ipv4_rules
)
615 flush ( 6 , saved_ipv6_rules
)
617 def flush_fou_ports ():
618 ret
= run ( 'ip fou show' )
619 if ret
. returncode
!= 0 :
620 return # fou may not be supported
621 for line
in ret
. stdout
. splitlines ():
622 port
= line
. split ()[ 1 ]
623 call ( f
'ip fou del port {port} ' )
625 def flush_l2tp_tunnels ():
627 ret
= run ( 'ip l2tp show tunnel' )
628 if ret
. returncode
!= 0 :
629 return # l2tp may not be supported
630 for line
in ret
. stdout
. splitlines ():
632 if words
[ 0 ] == 'Tunnel' :
633 tid
= words
[ 1 ]. rstrip ( ',' )
634 call ( f
'ip l2tp del tunnel tunnel_id {tid} ' )
637 # Removing L2TP tunnel is asynchronous and slightly takes a time.
640 r
= run ( f
'ip l2tp show tunnel tunnel_id {tid} ' )
641 if r
. returncode
!= 0 or len ( r
. stdout
. rstrip ()) == 0 :
645 print ( f
'Cannot remove L2TP tunnel {tid} , ignoring.' )
648 # pylint: disable=global-statement
649 global saved_timezone
650 r
= run (* timedatectl_cmd
, 'show' , '--value' , '--property' , 'Timezone' , env
= env
)
651 if r
. returncode
== 0 :
652 saved_timezone
= r
. stdout
. rstrip ()
653 print ( f
'### Saved timezone: {saved_timezone} ' )
655 def restore_timezone ():
657 call (* timedatectl_cmd
, 'set-timezone' , f
' {saved_timezone} ' , env
= env
)
659 def read_link_attr (* args
):
660 with
open ( os
. path
. join ( '/sys/class/net' , * args
), encoding
= 'utf-8' ) as f
:
661 return f
. readline (). strip ()
663 def read_manager_state_file ():
664 with
open ( '/run/systemd/netif/state' , encoding
= 'utf-8' ) as f
:
667 def read_link_state_file ( link
):
668 ifindex
= read_link_attr ( link
, 'ifindex' )
669 path
= os
. path
. join ( '/run/systemd/netif/links' , ifindex
)
670 with
open ( path
, encoding
= 'utf-8' ) as f
:
673 def read_ip_sysctl_attr ( link
, attribute
, ipv
):
674 with
open ( os
. path
. join ( '/proc/sys/net' , ipv
, 'conf' , link
, attribute
), encoding
= 'utf-8' ) as f
:
675 return f
. readline (). strip ()
677 def read_ip_neigh_sysctl_attr ( link
, attribute
, ipv
):
678 with
open ( os
. path
. join ( '/proc/sys/net' , ipv
, 'neigh' , link
, attribute
), encoding
= 'utf-8' ) as f
:
679 return f
. readline (). strip ()
681 def read_ipv6_sysctl_attr ( link
, attribute
):
682 return read_ip_sysctl_attr ( link
, attribute
, 'ipv6' )
684 def read_ipv6_neigh_sysctl_attr ( link
, attribute
):
685 return read_ip_neigh_sysctl_attr ( link
, attribute
, 'ipv6' )
687 def read_ipv4_sysctl_attr ( link
, attribute
):
688 return read_ip_sysctl_attr ( link
, attribute
, 'ipv4' )
690 def stop_by_pid_file ( pid_file
):
691 if not os
. path
. exists ( pid_file
):
693 with
open ( pid_file
, 'r' , encoding
= 'utf-8' ) as f
:
694 pid
= f
. read (). rstrip ( ' \t\r\n \0' )
695 os
. kill ( int ( pid
), signal
. SIGTERM
)
699 print ( f
"PID {pid} is still alive, waiting..." )
702 if e
. errno
== errno
. ESRCH
:
704 print ( f
"Unexpected exception when waiting for {pid} to die: {e.errno}" )
707 def start_dnsmasq (* additional_options
, interface
= 'veth-peer' , ra_mode
= None , ipv4_range
= '192.168.5.10,192.168.5.200' , ipv4_router
= '192.168.5.1' , ipv6_range
= '2600::10,2600::20' ):
709 ra_mode
= f
', {ra_mode} '
715 f
'--log-facility= {dnsmasq_log_file} ' ,
716 '--log-queries=extra' ,
718 f
'--pid-file= {dnsmasq_pid_file} ' ,
719 '--conf-file=/dev/null' ,
721 f
'--interface= {interface} ' ,
722 f
'--dhcp-leasefile= {dnsmasq_lease_file} ' ,
724 f
'--dhcp-range= {ipv6_range}{ra_mode} ,2m' ,
725 f
'--dhcp-range= {ipv4_range} ,2m' ,
726 '--dhcp-option=option:mtu,1492' ,
727 f
'--dhcp-option=option:router, {ipv4_router} ' ,
730 ) + additional_options
731 check_output (* command
)
734 stop_by_pid_file ( dnsmasq_pid_file
)
735 rm_f ( dnsmasq_lease_file
)
736 rm_f ( dnsmasq_log_file
)
738 def read_dnsmasq_log_file ():
739 with
open ( dnsmasq_log_file
, encoding
= 'utf-8' ) as f
:
742 def start_isc_dhcpd ( conf_file
, ipv
, interface
= 'veth-peer' ):
743 conf_file_path
= os
. path
. join ( networkd_ci_temp_dir
, conf_file
)
744 isc_dhcpd_command
= f
'dhcpd {ipv} -cf {conf_file_path} -lf {isc_dhcpd_lease_file} -pf {isc_dhcpd_pid_file} {interface} '
745 touch ( isc_dhcpd_lease_file
)
746 check_output ( isc_dhcpd_command
)
748 def stop_isc_dhcpd ():
749 stop_by_pid_file ( isc_dhcpd_pid_file
)
750 rm_f ( isc_dhcpd_lease_file
)
752 def get_dbus_link_path ( link
):
753 out
= subprocess
. check_output ([ 'busctl' , 'call' , 'org.freedesktop.network1' ,
754 '/org/freedesktop/network1' , 'org.freedesktop.network1.Manager' ,
755 'GetLinkByName' , 's' , link
])
757 assert out
. startswith ( b
'io ' )
759 assert out
. endswith ( b
'"' )
761 return out
[:- 1 ]. split ( '"' )[ 1 ]
763 def get_dhcp_client_state ( link
, family
):
764 link_path
= get_dbus_link_path ( link
)
766 out
= subprocess
. check_output ([ 'busctl' , 'get-property' , 'org.freedesktop.network1' ,
767 link_path
, f
'org.freedesktop.network1.DHCPv {family} Client' , 'State' ])
768 assert out
. startswith ( b
's "' )
770 assert out
. endswith ( b
'"' )
771 return out
[ 3 :- 1 ]. decode ()
773 def get_dhcp4_client_state ( link
):
774 return get_dhcp_client_state ( link
, '4' )
776 def get_dhcp6_client_state ( link
):
777 return get_dhcp_client_state ( link
, '6' )
779 def get_link_description ( link
):
780 link_path
= get_dbus_link_path ( link
)
782 out
= subprocess
. check_output ([ 'busctl' , 'call' , 'org.freedesktop.network1' ,
783 link_path
, 'org.freedesktop.network1.Link' , 'Describe' ])
784 assert out
. startswith ( b
's "' )
786 assert out
. endswith ( b
'"' )
787 json_raw
= out
[ 2 :]. decode ()
789 description
= json
. loads ( json_raw
) # Convert from escaped sequences to json
790 check_json ( description
)
791 return json
. loads ( description
) # Now parse the json
793 def start_radvd (* additional_options
, config_file
):
794 config_file_path
= os
. path
. join ( networkd_ci_temp_dir
, 'radvd' , config_file
)
797 f
'--pidfile= {radvd_pid_file} ' ,
798 f
'--config= {config_file_path} ' ,
799 '--logmethod=stderr' ,
800 ) + additional_options
801 check_output (* command
)
804 stop_by_pid_file ( radvd_pid_file
)
806 def radvd_check_config ( config_file
):
807 if not shutil
. which ( 'radvd' ):
808 print ( 'radvd is not installed, assuming the config check failed' )
811 # Note: can't use networkd_ci_temp_dir here, as this command may run before that dir is
812 # set up (one instance is @unittest.skipX())
813 config_file_path
= os
. path
. join ( os
. path
. dirname ( os
. path
. abspath ( __file__
)), 'conf/radvd' , config_file
)
814 return call ( f
'radvd --config= {config_file_path} --configtest' ) == 0
816 def networkd_invocation_id ():
817 return check_output ( 'systemctl show --value -p InvocationID systemd-networkd.service' )
819 def read_networkd_log ( invocation_id
= None , since
= None ):
820 if not invocation_id
:
821 invocation_id
= networkd_invocation_id ()
825 '--output=short-monotonic' ,
826 f
'_SYSTEMD_INVOCATION_ID= {invocation_id} ' ,
829 command
. append ( f
'--since= {since} ' )
830 check_output ( 'journalctl --sync' )
831 return check_output (* command
)
833 def networkd_is_failed ():
834 return call_quiet ( 'systemctl is-failed -q systemd-networkd.service' ) != 1
836 def stop_networkd ( show_logs
= True ):
838 invocation_id
= networkd_invocation_id ()
839 check_output ( 'systemctl stop systemd-networkd.socket' )
840 check_output ( 'systemctl stop systemd-networkd.service' )
842 print ( read_networkd_log ( invocation_id
))
843 # Check if networkd exits cleanly.
844 assert not networkd_is_failed ()
846 def start_networkd ():
847 check_output ( 'systemctl start systemd-networkd' )
849 def restart_networkd ( show_logs
= True ):
851 invocation_id
= networkd_invocation_id ()
852 check_output ( 'systemctl restart systemd-networkd.service' )
854 print ( read_networkd_log ( invocation_id
))
857 return int ( check_output ( 'systemctl show --value -p MainPID systemd-networkd.service' ))
859 def networkctl (* args
):
860 # Do not call networkctl if networkd is in failed state.
861 # Otherwise, networkd may be restarted and we may get wrong results.
862 assert not networkd_is_failed ()
863 return check_output (*( networkctl_cmd
+ list ( args
)), env
= env
)
865 def networkctl_status (* args
):
866 return networkctl ( '-n' , '0' , 'status' , * args
)
868 def networkctl_json (* args
):
869 return networkctl ( '--json=short' , 'status' , * args
)
871 def networkctl_reconfigure (* links
):
872 networkctl ( 'reconfigure' , * links
)
874 def networkctl_reload ():
877 def resolvectl (* args
):
878 return check_output (*( resolvectl_cmd
+ list ( args
)), env
= env
)
880 def timedatectl (* args
):
881 return check_output (*( timedatectl_cmd
+ list ( args
)), env
= env
)
884 return check_output (*( udevadm_cmd
+ list ( args
)))
886 def udevadm_reload ():
887 udevadm ( 'control' , '--reload' )
889 def udevadm_trigger (* args
, action
= 'add' ):
890 udevadm ( 'trigger' , '--settle' , f
'--action= {action} ' , * args
)
895 def tear_down_common ():
896 # 1. stop DHCP/RA servers
902 call_quiet ( 'rmmod netdevsim' )
903 call_quiet ( 'rmmod sch_teql' )
905 # 3. remove network namespace
906 call_quiet ( 'ip netns del ns99' )
916 clear_network_units ()
917 clear_networkd_conf_dropins ()
918 clear_networkd_state_files ()
923 flush_routing_policy_rules ()
927 rm_rf ( networkd_ci_temp_dir
)
928 cp_r ( os
. path
. join ( os
. path
. dirname ( os
. path
. abspath ( __file__
)), 'conf' ), networkd_ci_temp_dir
)
930 clear_network_units ()
931 clear_networkd_conf_dropins ()
932 clear_networkd_state_files ()
935 setup_systemd_udev_rules ()
936 copy_udev_rule ( '00-debug-net.rules' )
940 save_existing_links ()
942 save_routing_policy_rules ()
947 def tearDownModule ():
948 rm_rf ( networkd_ci_temp_dir
)
950 clear_network_units ()
951 clear_networkd_conf_dropins ()
952 clear_networkd_state_files ()
957 restore_active_units ()
960 # pylint: disable=no-member
962 def check_link_exists ( self
, link
, expected
= True ):
964 self
. assertTrue ( link_exists ( link
))
966 self
. assertFalse ( link_exists ( link
))
968 def check_link_attr ( self
, * args
):
969 self
. assertEqual ( read_link_attr (* args
[:- 1 ]), args
[- 1 ])
971 def check_bridge_port_attr ( self
, master
, port
, attribute
, expected
, allow_enoent
= False ):
972 path
= os
. path
. join ( '/sys/devices/virtual/net' , master
, 'lower_' + port
, 'brport' , attribute
)
973 if allow_enoent
and not os
. path
. exists ( path
):
975 with
open ( path
, encoding
= 'utf-8' ) as f
:
976 self
. assertEqual ( f
. readline (). strip (), expected
)
978 def check_ipv4_sysctl_attr ( self
, link
, attribute
, expected
):
979 self
. assertEqual ( read_ipv4_sysctl_attr ( link
, attribute
), expected
)
981 def check_ipv6_sysctl_attr ( self
, link
, attribute
, expected
):
982 self
. assertEqual ( read_ipv6_sysctl_attr ( link
, attribute
), expected
)
984 def check_ipv6_neigh_sysctl_attr ( self
, link
, attribute
, expected
):
985 self
. assertEqual ( read_ipv6_neigh_sysctl_attr ( link
, attribute
), expected
)
987 def wait_links ( self
, * links
, timeout
= 20 , fail_assert
= True ):
988 def links_exist (* links
):
990 if not link_exists ( link
):
994 for iteration
in range ( timeout
+ 1 ):
998 if links_exist (* links
):
1001 self
. fail ( 'Timed out waiting for all links to be created: ' + ', ' . join ( list ( links
)))
1004 def wait_activated ( self
, link
, state
= 'down' , timeout
= 20 , fail_assert
= True ):
1005 # wait for the interface is activated.
1006 needle
= f
' {link} : Bringing link {state} '
1007 flag
= state
. upper ()
1008 for iteration
in range ( timeout
+ 1 ):
1011 if not link_exists ( link
):
1013 output
= read_networkd_log ()
1014 if needle
in output
and flag
in check_output ( f
'ip link show {link} ' ):
1017 self
. fail ( f
'Timed out waiting for {link} activated.' )
1020 def wait_operstate ( self
, link
, operstate
= 'degraded' , setup_state
= 'configured' , setup_timeout
= 5 , fail_assert
= True ):
1021 """Wait for the link to reach the specified operstate and/or setup state.
1023 Specify None or '' for either operstate or setup_state to ignore that state.
1024 This will recheck until the state conditions are met or the timeout expires.
1026 If the link successfully matches the requested state, this returns True.
1027 If this times out waiting for the link to match, the behavior depends on the
1028 'fail_assert' parameter; if True, this causes a test assertion failure,
1029 otherwise this returns False. The default is to cause assertion failure.
1031 Note that this function matches on *exactly* the given operstate and setup_state.
1032 To wait for a link to reach *or exceed* a given operstate, use wait_online().
1037 setup_state
= r
'\S+'
1039 for secs
in range ( setup_timeout
+ 1 ):
1042 if not link_exists ( link
):
1044 output
= networkctl_status ( link
)
1045 if re
. search ( rf
'(?m)^\s*State:\s+ {operstate} \s+\( {setup_state} \)\s*$' , output
):
1049 self
. fail ( f
'Timed out waiting for {link} to reach state {operstate} / {setup_state} ' )
1052 def wait_online ( self
, * links_with_operstate
, timeout
= '20s' , bool_any
= False , ipv4
= False , ipv6
= False , setup_state
= 'configured' , setup_timeout
= 5 ):
1053 """Wait for the links to reach the specified operstate and/or setup state.
1055 This is similar to wait_operstate() but can be used for multiple links,
1056 and it also calls systemd-networkd-wait-online to wait for the given operstate.
1057 The operstate should be specified in the link name, like 'eth0:degraded'.
1058 If just a link name is provided, wait-online's default operstate to wait for is degraded.
1060 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
1061 'setup_timeout' controls the per-link timeout waiting for the setup_state.
1063 Set 'bool_any' to True to wait for any (instead of all) of the given links.
1064 If this is set, no setup_state checks are done.
1066 Set 'ipv4' or 'ipv6' to True to wait for IPv4 address or IPv6 address, respectively, of each of the given links.
1067 This is applied only for the operational state 'degraded' or above.
1069 Note that this function waits for the links to reach *or exceed* the given operstate.
1070 However, the setup_state, if specified, must be matched *exactly*.
1072 This returns if the links reached the requested operstate/setup_state; otherwise it
1073 raises CalledProcessError or fails test assertion.
1075 args
= wait_online_cmd
+ [ f
'--timeout= {timeout} ' ] + [ f
'--interface= {link} ' for link
in links_with_operstate
] + [ f
'--ignore= {link} ' for link
in protected_links
]
1083 check_output (* args
, env
= wait_online_env
)
1084 except subprocess
. CalledProcessError
:
1085 if networkd_is_failed ():
1086 print ( '!!!!! systemd-networkd.service is failed !!!!!' )
1087 call ( 'systemctl status systemd-networkd.service' )
1089 # show detailed status on failure
1090 for link
in links_with_operstate
:
1091 name
= link
. split ( ':' )[ 0 ]
1092 if link_exists ( name
):
1093 print ( networkctl_status ( name
))
1095 print ( f
'Interface {name} not found.' )
1097 if not bool_any
and setup_state
:
1098 for link
in links_with_operstate
:
1099 self
. wait_operstate ( link
. split ( ':' )[ 0 ], None , setup_state
, setup_timeout
)
1101 def wait_address ( self
, link
, address_regex
, scope
= 'global' , ipv
= '' , timeout_sec
= 100 ):
1102 for i
in range ( timeout_sec
):
1105 output
= check_output ( f
'ip {ipv} address show dev {link} scope {scope} ' )
1106 if re
. search ( address_regex
, output
) and 'tentative' not in output
:
1109 self
. assertRegex ( output
, address_regex
)
1111 def wait_address_dropped ( self
, link
, address_regex
, scope
= 'global' , ipv
= '' , timeout_sec
= 100 ):
1112 for i
in range ( timeout_sec
):
1115 output
= check_output ( f
'ip {ipv} address show dev {link} scope {scope} ' )
1116 if not re
. search ( address_regex
, output
):
1119 self
. assertNotRegex ( output
, address_regex
)
1121 def wait_route ( self
, link
, route_regex
, table
= 'main' , ipv
= '' , timeout_sec
= 100 ):
1122 for i
in range ( timeout_sec
):
1125 output
= check_output ( f
'ip {ipv} route show dev {link} table {table} ' )
1126 if re
. search ( route_regex
, output
):
1129 self
. assertRegex ( output
, route_regex
)
1131 def check_netlabel ( self
, interface
, address
, label
= 'system_u:object_r:root_t:s0' ):
1132 if not shutil
. which ( 'selinuxenabled' ):
1133 print ( '## Checking NetLabel skipped: selinuxenabled command not found.' )
1134 elif call_quiet ( 'selinuxenabled' ) != 0 :
1135 print ( '## Checking NetLabel skipped: SELinux disabled.' )
1136 elif not shutil
. which ( 'netlabelctl' ): # not packaged by all distros
1137 print ( '## Checking NetLabel skipped: netlabelctl command not found.' )
1139 output
= check_output ( 'netlabelctl unlbl list' )
1141 self
. assertRegex ( output
, f
'interface: {interface} ,address: {address} ,label:" {label} "' )
1143 def setup_nftset ( self
, filter_name
, filter_type
, flags
= '' ):
1144 if not shutil
. which ( 'nft' ):
1145 print ( '## Setting up NFT sets skipped: nft command not found.' )
1147 if call ( f
'nft add table inet sd_test' ) != 0 :
1148 print ( '## Setting up NFT table failed.' )
1150 if call ( f
'nft add set inet sd_test {filter_name} {{ type {filter_type} ; {flags} }}' ) != 0 :
1151 print ( '## Setting up NFT sets failed.' )
1154 def teardown_nftset ( self
, * filters
):
1155 if not shutil
. which ( 'nft' ):
1156 print ( '## Tearing down NFT sets skipped: nft command not found.' )
1158 for filter_name
in filters
:
1159 if call ( f
'nft delete set inet sd_test {filter_name} ' ) != 0 :
1160 print ( '## Tearing down NFT sets failed.' )
1162 if call ( f
'nft delete table inet sd_test' ) != 0 :
1163 print ( '## Tearing down NFT table failed.' )
1166 def check_nftset ( self
, filter_name
, contents
):
1167 if not shutil
. which ( 'nft' ):
1168 print ( '## Checking NFT sets skipped: nft command not found.' )
1170 output
= check_output ( f
'nft list set inet sd_test {filter_name} ' )
1172 self
. assertRegex ( output
, r
'.*elements = { [^}]*' + contents
+ r
'[^}]* }.*' )
1174 class NetworkctlTests ( unittest
. TestCase
, Utilities
):
1182 @expectedFailureIfAlternativeNameIsNotAvailable ()
1183 def test_altname ( self
):
1184 copy_network_unit ( '26-netdev-link-local-addressing-yes.network' , '12-dummy.netdev' , '12-dummy.link' )
1186 self
. wait_online ( 'dummy98:degraded' )
1188 output
= networkctl_status ( 'dummy98' )
1189 self
. assertRegex ( output
, 'hogehogehogehogehogehoge' )
1191 @expectedFailureIfAlternativeNameIsNotAvailable ()
1192 def test_rename_to_altname ( self
):
1193 copy_network_unit ( '26-netdev-link-local-addressing-yes.network' ,
1194 '12-dummy.netdev' , '12-dummy-rename-to-altname.link' )
1196 self
. wait_online ( 'dummyalt:degraded' )
1198 output
= networkctl_status ( 'dummyalt' )
1199 self
. assertIn ( 'hogehogehogehogehogehoge' , output
)
1200 self
. assertNotIn ( 'dummy98' , output
)
1202 def test_reconfigure ( self
):
1203 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' , copy_dropins
= False )
1205 self
. wait_online ( 'dummy98:routable' )
1207 output
= check_output ( 'ip -4 address show dev dummy98' )
1209 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
1210 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
1211 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
1213 check_output ( 'ip address del 10.1.2.3/16 dev dummy98' )
1214 check_output ( 'ip address del 10.1.2.4/16 dev dummy98' )
1215 check_output ( 'ip address del 10.2.2.4/16 dev dummy98' )
1217 networkctl_reconfigure ( 'dummy98' )
1218 self
. wait_online ( 'dummy98:routable' )
1220 output
= check_output ( 'ip -4 address show dev dummy98' )
1222 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
1223 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
1224 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
1226 remove_network_unit ( '25-address-static.network' )
1229 self
. wait_operstate ( 'dummy98' , 'degraded' , setup_state
= 'unmanaged' )
1231 output
= check_output ( 'ip -4 address show dev dummy98' )
1233 self
. assertNotIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
1234 self
. assertNotIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
1235 self
. assertNotIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
1237 copy_network_unit ( '25-address-static.network' , copy_dropins
= False )
1239 self
. wait_online ( 'dummy98:routable' )
1241 output
= check_output ( 'ip -4 address show dev dummy98' )
1243 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
1244 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
1245 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
1247 def test_renew ( self
):
1249 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
1250 output
= networkctl_status ( 'veth99' )
1252 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
1253 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
1254 self
. assertRegex ( output
, 'DNS: 192.168.5.1 \n *192.168.5.10' )
1255 self
. assertRegex ( output
, 'NTP: 192.168.5.1 \n *192.168.5.11' )
1257 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server.network' )
1260 check_json ( networkctl_json ( '--lines=0' , '--stats' , '--all' , '--full' ))
1262 for verb
in [ 'renew' , 'forcerenew' ]:
1263 networkctl ( verb
, 'veth99' )
1265 networkctl ( verb
, 'veth99' , 'veth99' , 'veth99' )
1268 def test_up_down ( self
):
1269 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' , copy_dropins
= False )
1271 self
. wait_online ( 'dummy98:routable' )
1273 networkctl ( 'down' , 'dummy98' )
1274 self
. wait_online ( 'dummy98:off' )
1275 networkctl ( 'up' , 'dummy98' )
1276 self
. wait_online ( 'dummy98:routable' )
1277 networkctl ( 'down' , 'dummy98' , 'dummy98' , 'dummy98' )
1278 self
. wait_online ( 'dummy98:off' )
1279 networkctl ( 'up' , 'dummy98' , 'dummy98' , 'dummy98' )
1280 self
. wait_online ( 'dummy98:routable' )
1282 def test_reload ( self
):
1285 copy_network_unit ( '11-dummy.netdev' )
1287 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'unmanaged' )
1289 copy_network_unit ( '11-dummy.network' )
1291 self
. wait_online ( 'test1:degraded' )
1293 remove_network_unit ( '11-dummy.network' )
1295 self
. wait_operstate ( 'test1' , 'degraded' , setup_state
= 'unmanaged' )
1297 remove_network_unit ( '11-dummy.netdev' )
1299 self
. wait_operstate ( 'test1' , 'degraded' , setup_state
= 'unmanaged' )
1301 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1303 self
. wait_operstate ( 'test1' , 'degraded' )
1305 def test_glob ( self
):
1306 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1309 self
. wait_online ( 'test1:degraded' )
1311 output
= networkctl ( 'list' )
1312 self
. assertRegex ( output
, '1 lo ' )
1313 self
. assertRegex ( output
, 'test1' )
1315 output
= networkctl ( 'list' , 'test1' )
1316 self
. assertNotRegex ( output
, '1 lo ' )
1317 self
. assertRegex ( output
, 'test1' )
1319 output
= networkctl ( 'list' , 'te*' )
1320 self
. assertNotRegex ( output
, '1 lo ' )
1321 self
. assertRegex ( output
, 'test1' )
1323 output
= networkctl_status ( 'te*' )
1324 self
. assertNotRegex ( output
, '1: lo ' )
1325 self
. assertRegex ( output
, 'test1' )
1327 output
= networkctl_status ( 'tes[a-z][0-9]' )
1328 self
. assertNotRegex ( output
, '1: lo ' )
1329 self
. assertRegex ( output
, 'test1' )
1332 copy_network_unit ( '11-dummy-mtu.netdev' , '11-dummy.network' )
1335 self
. wait_online ( 'test1:degraded' )
1337 output
= networkctl_status ( 'test1' )
1338 self
. assertRegex ( output
, 'MTU: 1600' )
1340 def test_type ( self
):
1341 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1343 self
. wait_online ( 'test1:degraded' )
1345 output
= networkctl_status ( 'test1' )
1347 self
. assertRegex ( output
, 'Type: ether' )
1349 output
= networkctl_status ( 'lo' )
1351 self
. assertRegex ( output
, 'Type: loopback' )
1353 def test_unit_file ( self
):
1354 copy_network_unit ( '11-test-unit-file.netdev' , '11-test-unit-file.network' , '11-test-unit-file.link' )
1356 self
. wait_online ( 'test1:degraded' )
1358 output
= networkctl_status ( 'test1' )
1360 self
. assertIn ( 'Link File: /run/systemd/network/11-test-unit-file.link' , output
)
1361 self
. assertIn ( '/run/systemd/network/11-test-unit-file.link.d/dropin.conf' , output
)
1362 self
. assertIn ( 'Network File: /run/systemd/network/11-test-unit-file.network' , output
)
1363 self
. assertIn ( '/run/systemd/network/11-test-unit-file.network.d/dropin.conf' , output
)
1365 output
= read_networkd_log ()
1366 self
. assertIn ( 'test1: Configuring with /run/systemd/network/11-test-unit-file.network (dropins: /run/systemd/network/11-test-unit-file.network.d/dropin.conf).' , output
)
1368 # This test may be run on the system that has older udevd than 70f32a260b5ebb68c19ecadf5d69b3844896ba55 (v249).
1369 # In that case, the udev DB for the loopback network interface may already have ID_NET_LINK_FILE property.
1370 # Let's reprocess the interface and drop the property.
1371 udevadm_trigger ( '/sys/class/net/lo' )
1372 output
= networkctl_status ( 'lo' )
1374 self
. assertIn ( 'Link File: n/a' , output
)
1375 self
. assertIn ( 'Network File: n/a' , output
)
1377 def test_delete_links ( self
):
1378 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' ,
1379 '25-veth.netdev' , '26-netdev-link-local-addressing-yes.network' )
1382 self
. wait_online ( 'test1:degraded' , 'veth99:degraded' , 'veth-peer:degraded' )
1384 networkctl ( 'delete' , 'test1' , 'veth99' )
1385 self
. check_link_exists ( 'test1' , expected
= False )
1386 self
. check_link_exists ( 'veth99' , expected
= False )
1387 self
. check_link_exists ( 'veth-peer' , expected
= False )
1389 def test_label ( self
):
1392 class NetworkdMatchTests ( unittest
. TestCase
, Utilities
):
1400 @expectedFailureIfAlternativeNameIsNotAvailable ()
1401 def test_match ( self
):
1402 copy_network_unit ( '12-dummy-mac.netdev' ,
1403 '12-dummy-match-mac-01.network' ,
1404 '12-dummy-match-mac-02.network' ,
1405 '12-dummy-match-renamed.network' ,
1406 '12-dummy-match-altname.network' ,
1407 '12-dummy-altname.link' )
1410 self
. wait_online ( 'dummy98:routable' )
1411 output
= networkctl_status ( 'dummy98' )
1412 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-mac-01.network' , output
)
1413 output
= check_output ( 'ip -4 address show dev dummy98' )
1414 self
. assertIn ( '10.0.0.1/16' , output
)
1416 check_output ( 'ip link set dev dummy98 down' )
1417 check_output ( 'ip link set dev dummy98 address 12:34:56:78:9a:02' )
1419 self
. wait_address ( 'dummy98' , '10.0.0.2/16' , ipv
= '-4' , timeout_sec
= 10 )
1420 self
. wait_online ( 'dummy98:routable' )
1421 output
= networkctl_status ( 'dummy98' )
1422 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-mac-02.network' , output
)
1424 check_output ( 'ip link set dev dummy98 down' )
1425 check_output ( 'ip link set dev dummy98 name dummy98-1' )
1427 self
. wait_address ( 'dummy98-1' , '10.0.1.2/16' , ipv
= '-4' , timeout_sec
= 10 )
1428 self
. wait_online ( 'dummy98-1:routable' )
1429 output
= networkctl_status ( 'dummy98-1' )
1430 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-renamed.network' , output
)
1432 check_output ( 'ip link set dev dummy98-1 down' )
1433 check_output ( 'ip link set dev dummy98-1 name dummy98-2' )
1434 udevadm_trigger ( '/sys/class/net/dummy98-2' )
1436 self
. wait_address ( 'dummy98-2' , '10.0.2.2/16' , ipv
= '-4' , timeout_sec
= 10 )
1437 self
. wait_online ( 'dummy98-2:routable' )
1438 output
= networkctl_status ( 'dummy98-2' )
1439 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-altname.network' , output
)
1441 def test_match_udev_property ( self
):
1442 copy_network_unit ( '12-dummy.netdev' , '13-not-match-udev-property.network' , '14-match-udev-property.network' )
1444 self
. wait_online ( 'dummy98:routable' )
1446 output
= networkctl_status ( 'dummy98' )
1448 self
. assertRegex ( output
, 'Network File: /run/systemd/network/14-match-udev-property' )
1450 class WaitOnlineTests ( unittest
. TestCase
, Utilities
):
1458 def test_wait_online_any ( self
):
1459 copy_network_unit ( '25-bridge.netdev' , '25-bridge.network' , '11-dummy.netdev' , '11-dummy.network' )
1462 self
. wait_online ( 'bridge99' , 'test1:degraded' , bool_any
= True )
1464 self
. wait_operstate ( 'bridge99' , '(off|no-carrier)' , setup_state
= 'configuring' )
1465 self
. wait_operstate ( 'test1' , 'degraded' )
1467 class NetworkdNetDevTests ( unittest
. TestCase
, Utilities
):
1475 def test_dropin_and_name_conflict ( self
):
1476 copy_network_unit ( '10-dropin-test.netdev' , '15-name-conflict-test.netdev' )
1479 self
. wait_online ( 'dropin-test:off' , setup_state
= 'unmanaged' )
1481 output
= check_output ( 'ip link show dropin-test' )
1483 self
. assertRegex ( output
, '00:50:56:c0:00:28' )
1485 @expectedFailureIfModuleIsNotAvailable ( 'bareudp' )
1486 def test_bareudp ( self
):
1487 copy_network_unit ( '25-bareudp.netdev' , '26-netdev-link-local-addressing-yes.network' )
1490 self
. wait_online ( 'bareudp99:degraded' )
1492 output
= check_output ( 'ip -d link show bareudp99' )
1494 self
. assertRegex ( output
, 'dstport 1000 ' )
1495 self
. assertRegex ( output
, 'ethertype ip ' )
1497 @expectedFailureIfModuleIsNotAvailable ( 'batman-adv' )
1498 def test_batadv ( self
):
1499 copy_network_unit ( '25-batadv.netdev' , '26-netdev-link-local-addressing-yes.network' )
1502 self
. wait_online ( 'batadv99:degraded' )
1504 output
= check_output ( 'ip -d link show batadv99' )
1506 self
. assertRegex ( output
, 'batadv' )
1508 def test_bridge ( self
):
1509 copy_network_unit ( '25-bridge.netdev' , '25-bridge-configure-without-carrier.network' )
1512 self
. wait_online ( 'bridge99:no-carrier' )
1514 tick
= os
. sysconf ( 'SC_CLK_TCK' )
1515 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'hello_time' )) / tick
))
1516 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'max_age' )) / tick
))
1517 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'forward_delay' )) / tick
))
1518 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'ageing_time' )) / tick
))
1519 self
. assertEqual ( 9 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'priority' )))
1520 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_querier' )))
1521 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_snooping' )))
1522 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'stp_state' )))
1523 self
. assertEqual ( 3 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_igmp_version' )))
1525 output
= networkctl_status ( 'bridge99' )
1527 self
. assertRegex ( output
, 'Priority: 9' )
1528 self
. assertRegex ( output
, 'STP: yes' )
1529 self
. assertRegex ( output
, 'Multicast IGMP Version: 3' )
1531 output
= check_output ( 'ip -d link show bridge99' )
1533 self
. assertIn ( 'vlan_filtering 1 ' , output
)
1534 self
. assertIn ( 'vlan_protocol 802.1ad ' , output
)
1535 self
. assertIn ( 'vlan_default_pvid 9 ' , output
)
1537 def test_bond ( self
):
1538 copy_network_unit ( '25-bond.netdev' , '25-bond-balanced-tlb.netdev' , '25-bond-property.netdev' )
1541 self
. wait_online ( 'bond99:off' , 'bond98:off' , 'bond97:off' , setup_state
= 'unmanaged' )
1543 self
. check_link_attr ( 'bond99' , 'bonding' , 'mode' , '802.3ad 4' )
1544 self
. check_link_attr ( 'bond99' , 'bonding' , 'xmit_hash_policy' , 'layer3+4 1' )
1545 self
. check_link_attr ( 'bond99' , 'bonding' , 'miimon' , '1000' )
1546 self
. check_link_attr ( 'bond99' , 'bonding' , 'lacp_rate' , 'fast 1' )
1547 self
. check_link_attr ( 'bond99' , 'bonding' , 'updelay' , '2000' )
1548 self
. check_link_attr ( 'bond99' , 'bonding' , 'downdelay' , '2000' )
1549 self
. check_link_attr ( 'bond99' , 'bonding' , 'resend_igmp' , '4' )
1550 self
. check_link_attr ( 'bond99' , 'bonding' , 'min_links' , '1' )
1551 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_actor_sys_prio' , '1218' )
1552 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_user_port_key' , '811' )
1553 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_actor_system' , '00:11:22:33:44:55' )
1555 self
. check_link_attr ( 'bond98' , 'bonding' , 'mode' , 'balance-tlb 5' )
1556 self
. check_link_attr ( 'bond98' , 'bonding' , 'tlb_dynamic_lb' , '1' )
1558 output
= networkctl_status ( 'bond99' )
1560 self
. assertIn ( 'Mode: 802.3ad' , output
)
1561 self
. assertIn ( 'Miimon: 1s' , output
)
1562 self
. assertIn ( 'Updelay: 2s' , output
)
1563 self
. assertIn ( 'Downdelay: 2s' , output
)
1565 output
= networkctl_status ( 'bond98' )
1567 self
. assertIn ( 'Mode: balance-tlb' , output
)
1569 output
= networkctl_status ( 'bond97' )
1572 self
. check_link_attr ( 'bond97' , 'bonding' , 'arp_missed_max' , '10' )
1573 self
. check_link_attr ( 'bond97' , 'bonding' , 'peer_notif_delay' , '300000' )
1575 def test_vlan ( self
):
1576 copy_network_unit ( '21-vlan.netdev' , '11-dummy.netdev' ,
1577 '21-vlan.network' , '21-vlan-test1.network' )
1580 self
. wait_online ( 'test1:degraded' , 'vlan99:routable' )
1582 output
= check_output ( 'ip -d link show test1' )
1584 self
. assertRegex ( output
, ' mtu 2000 ' )
1586 output
= check_output ( 'ip -d link show vlan99' )
1588 self
. assertIn ( ' mtu 2000 ' , output
)
1589 self
. assertIn ( 'REORDER_HDR' , output
)
1590 self
. assertIn ( 'LOOSE_BINDING' , output
)
1591 self
. assertIn ( 'GVRP' , output
)
1592 self
. assertIn ( 'MVRP' , output
)
1593 self
. assertIn ( ' id 99 ' , output
)
1594 self
. assertIn ( 'ingress-qos-map { 4:100 7:13 }' , output
)
1595 self
. assertIn ( 'egress-qos-map { 0:1 1:3 6:6 7:7 10:3 }' , output
)
1597 output
= check_output ( 'ip -4 address show dev test1' )
1599 self
. assertRegex ( output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1' )
1600 self
. assertRegex ( output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1' )
1602 output
= check_output ( 'ip -4 address show dev vlan99' )
1604 self
. assertRegex ( output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99' )
1606 def test_vlan_on_bond ( self
):
1607 # For issue #24377 (https://github.com/systemd/systemd/issues/24377),
1608 # which is fixed by b05e52000b4eee764b383cc3031da0a3739e996e (PR#24020).
1610 copy_network_unit ( '21-bond-802.3ad.netdev' , '21-bond-802.3ad.network' ,
1611 '21-vlan-on-bond.netdev' , '21-vlan-on-bond.network' )
1613 self
. wait_online ( 'bond99:off' )
1614 self
. wait_operstate ( 'vlan99' , operstate
= 'off' , setup_state
= 'configuring' , setup_timeout
= 10 )
1616 # The commit b05e52000b4eee764b383cc3031da0a3739e996e adds ", ignoring". To make it easily confirmed
1617 # that the issue is fixed by the commit, let's allow to match both string.
1618 log_re
= re
. compile ( 'vlan99: Could not bring up interface(, ignoring|): Network is down$' , re
. MULTILINE
)
1622 if log_re
. search ( read_networkd_log ()):
1627 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '21-dummy-bond-slave.network' )
1629 self
. wait_online ( 'test1:enslaved' , 'dummy98:enslaved' , 'bond99:carrier' , 'vlan99:routable' )
1631 def test_macvtap ( self
):
1633 for mode
in [ 'private' , 'vepa' , 'bridge' , 'passthru' ]:
1639 print ( f
'### test_macvtap(mode= {mode} )' )
1640 with self
. subTest ( mode
= mode
):
1641 copy_network_unit ( '21-macvtap.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1642 '11-dummy.netdev' , '25-macvtap.network' )
1643 with
open ( os
. path
. join ( network_unit_dir
, '21-macvtap.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1644 f
. write ( '[MACVTAP] \n Mode=' + mode
)
1647 self
. wait_online ( 'macvtap99:degraded' ,
1648 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' )
1650 output
= check_output ( 'ip -d link show macvtap99' )
1652 self
. assertRegex ( output
, 'macvtap mode ' + mode
+ ' ' )
1654 def test_macvlan ( self
):
1656 for mode
in [ 'private' , 'vepa' , 'bridge' , 'passthru' ]:
1662 print ( f
'### test_macvlan(mode= {mode} )' )
1663 with self
. subTest ( mode
= mode
):
1664 copy_network_unit ( '21-macvlan.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1665 '11-dummy.netdev' , '25-macvlan.network' )
1666 with
open ( os
. path
. join ( network_unit_dir
, '21-macvlan.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1667 f
. write ( '[MACVLAN] \n Mode=' + mode
)
1670 self
. wait_online ( 'macvlan99:degraded' ,
1671 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' )
1673 output
= check_output ( 'ip -d link show test1' )
1675 self
. assertIn ( ' mtu 2000 ' , output
)
1677 output
= check_output ( 'ip -d link show macvlan99' )
1679 self
. assertIn ( ' mtu 2000 ' , output
)
1680 self
. assertIn ( f
' macvlan mode {mode} ' , output
)
1682 remove_link ( 'test1' )
1685 check_output ( "ip link add test1 type dummy" )
1686 self
. wait_online ( 'macvlan99:degraded' ,
1687 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' )
1689 output
= check_output ( 'ip -d link show test1' )
1691 self
. assertIn ( ' mtu 2000 ' , output
)
1693 output
= check_output ( 'ip -d link show macvlan99' )
1695 self
. assertIn ( ' mtu 2000 ' , output
)
1696 self
. assertIn ( f
' macvlan mode {mode} ' , output
)
1697 self
. assertIn ( ' bcqueuelen 1234 ' , output
)
1698 self
. assertIn ( ' bclim 2147483647 ' , output
)
1700 @expectedFailureIfModuleIsNotAvailable ( 'ipvlan' )
1701 def test_ipvlan ( self
):
1703 for mode
, flag
in [[ 'L2' , 'private' ], [ 'L3' , 'vepa' ], [ 'L3S' , 'bridge' ]]:
1709 print ( f
'### test_ipvlan(mode= {mode} , flag= {flag} )' )
1710 with self
. subTest ( mode
= mode
, flag
= flag
):
1711 copy_network_unit ( '25-ipvlan.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1712 '11-dummy.netdev' , '25-ipvlan.network' )
1713 with
open ( os
. path
. join ( network_unit_dir
, '25-ipvlan.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1714 f
. write ( '[IPVLAN] \n Mode=' + mode
+ ' \n Flags=' + flag
)
1717 self
. wait_online ( 'ipvlan99:degraded' , 'test1:degraded' )
1719 output
= check_output ( 'ip -d link show ipvlan99' )
1721 self
. assertRegex ( output
, 'ipvlan *mode ' + mode
. lower () + ' ' + flag
)
1723 @expectedFailureIfModuleIsNotAvailable ( 'ipvtap' )
1724 def test_ipvtap ( self
):
1726 for mode
, flag
in [[ 'L2' , 'private' ], [ 'L3' , 'vepa' ], [ 'L3S' , 'bridge' ]]:
1732 print ( f
'### test_ipvtap(mode= {mode} , flag= {flag} )' )
1733 with self
. subTest ( mode
= mode
, flag
= flag
):
1734 copy_network_unit ( '25-ipvtap.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1735 '11-dummy.netdev' , '25-ipvtap.network' )
1736 with
open ( os
. path
. join ( network_unit_dir
, '25-ipvtap.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1737 f
. write ( '[IPVTAP] \n Mode=' + mode
+ ' \n Flags=' + flag
)
1740 self
. wait_online ( 'ipvtap99:degraded' , 'test1:degraded' )
1742 output
= check_output ( 'ip -d link show ipvtap99' )
1744 self
. assertRegex ( output
, 'ipvtap *mode ' + mode
. lower () + ' ' + flag
)
1746 def test_veth ( self
):
1747 copy_network_unit ( '25-veth.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1748 '25-veth-mtu.netdev' )
1751 self
. wait_online ( 'veth99:degraded' , 'veth-peer:degraded' , 'veth-mtu:degraded' , 'veth-mtu-peer:degraded' )
1753 output
= check_output ( 'ip -d link show veth99' )
1755 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bc' )
1756 output
= check_output ( 'ip -d link show veth-peer' )
1758 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bd' )
1760 output
= check_output ( 'ip -d link show veth-mtu' )
1762 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:be' )
1763 self
. assertRegex ( output
, 'mtu 1800' )
1764 output
= check_output ( 'ip -d link show veth-mtu-peer' )
1766 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bf' )
1767 self
. assertRegex ( output
, 'mtu 1800' )
1769 def test_tuntap ( self
):
1770 copy_network_unit ( '25-tun.netdev' , '25-tap.netdev' , '26-netdev-link-local-addressing-yes.network' )
1773 self
. wait_online ( 'testtun99:degraded' , 'testtap99:degraded' )
1775 pid
= networkd_pid ()
1776 name
= psutil
. Process ( pid
). name ()[: 15 ]
1778 output
= check_output ( 'ip -d tuntap show' )
1780 self
. assertRegex ( output
, fr
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1781 self
. assertRegex ( output
, fr
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1783 output
= check_output ( 'ip -d link show testtun99' )
1785 # Old ip command does not support IFF_ flags
1786 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1787 self
. assertIn ( 'UP,LOWER_UP' , output
)
1789 output
= check_output ( 'ip -d link show testtap99' )
1791 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1792 self
. assertIn ( 'UP,LOWER_UP' , output
)
1794 remove_network_unit ( '26-netdev-link-local-addressing-yes.network' )
1797 self
. wait_online ( 'testtun99:degraded' , 'testtap99:degraded' , setup_state
= 'unmanaged' )
1799 pid
= networkd_pid ()
1800 name
= psutil
. Process ( pid
). name ()[: 15 ]
1802 output
= check_output ( 'ip -d tuntap show' )
1804 self
. assertRegex ( output
, fr
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1805 self
. assertRegex ( output
, fr
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes: {name} \( {pid} \)systemd\(1\)$' )
1807 output
= check_output ( 'ip -d link show testtun99' )
1809 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1810 self
. assertIn ( 'UP,LOWER_UP' , output
)
1812 output
= check_output ( 'ip -d link show testtap99' )
1814 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1815 self
. assertIn ( 'UP,LOWER_UP' , output
)
1817 clear_network_units ()
1819 self
. wait_online ( 'testtun99:off' , 'testtap99:off' , setup_state
= 'unmanaged' )
1821 output
= check_output ( 'ip -d tuntap show' )
1823 self
. assertRegex ( output
, r
'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$' )
1824 self
. assertRegex ( output
, r
'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$' )
1829 output
= check_output ( 'ip -d link show testtun99' )
1831 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1832 if 'NO-CARRIER' in output
:
1840 output
= check_output ( 'ip -d link show testtap99' )
1842 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1843 if 'NO-CARRIER' in output
:
1848 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
1850 copy_network_unit ( '25-vrf.netdev' , '26-netdev-link-local-addressing-yes.network' )
1853 self
. wait_online ( 'vrf99:carrier' )
1855 @expectedFailureIfModuleIsNotAvailable ( 'vcan' )
1856 def test_vcan ( self
):
1857 copy_network_unit ( '25-vcan.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1858 '25-vcan98.netdev' , '25-vcan98.network' )
1861 self
. wait_online ( 'vcan99:carrier' , 'vcan98:carrier' )
1862 # For can devices, 'carrier' is the default required operational state.
1863 self
. wait_online ( 'vcan99' , 'vcan98' )
1865 # https://github.com/systemd/systemd/issues/30140
1866 output
= check_output ( 'ip -d link show vcan99' )
1868 self
. assertIn ( 'mtu 16 ' , output
)
1870 output
= check_output ( 'ip -d link show vcan98' )
1872 self
. assertIn ( 'mtu 16 ' , output
)
1874 @expectedFailureIfModuleIsNotAvailable ( 'vxcan' )
1875 def test_vxcan ( self
):
1876 copy_network_unit ( '25-vxcan.netdev' , '26-netdev-link-local-addressing-yes.network' )
1879 self
. wait_online ( 'vxcan99:carrier' , 'vxcan-peer:carrier' )
1880 # For can devices, 'carrier' is the default required operational state.
1881 self
. wait_online ( 'vxcan99' , 'vxcan-peer' )
1883 @expectedFailureIfModuleIsNotAvailable ( 'wireguard' )
1884 def test_wireguard ( self
):
1885 copy_credential ( '25-wireguard-endpoint-peer0-cred.txt' , 'network.wireguard.peer0.endpoint' )
1886 copy_credential ( '25-wireguard-preshared-key-peer2-cred.txt' , 'network.wireguard.peer2.psk' )
1887 copy_credential ( '25-wireguard-no-peer-private-key-cred.txt' , 'network.wireguard.private.25-wireguard-no-peer' )
1889 copy_network_unit ( '25-wireguard.netdev' , '25-wireguard.network' ,
1890 '25-wireguard-23-peers.netdev' , '25-wireguard-23-peers.network' ,
1891 '25-wireguard-preshared-key.txt' , '25-wireguard-private-key.txt' ,
1892 '25-wireguard-no-peer.netdev' , '25-wireguard-no-peer.network' )
1894 self
. wait_online ( 'wg99:routable' , 'wg98:routable' , 'wg97:carrier' )
1896 output
= check_output ( 'ip -4 address show dev wg99' )
1898 self
. assertIn ( 'inet 192.168.124.1/24 scope global wg99' , output
)
1900 output
= check_output ( 'ip -4 address show dev wg99' )
1902 self
. assertIn ( 'inet 169.254.11.1/24 scope link wg99' , output
)
1904 output
= check_output ( 'ip -6 address show dev wg99' )
1906 self
. assertIn ( 'inet6 fe80::1/64 scope link' , output
)
1908 output
= check_output ( 'ip -4 address show dev wg98' )
1910 self
. assertIn ( 'inet 192.168.123.123/24 scope global wg98' , output
)
1912 output
= check_output ( 'ip -6 address show dev wg98' )
1914 self
. assertIn ( 'inet6 fd8d:4d6d:3ccb:500::1/64 scope global' , output
)
1916 output
= check_output ( 'ip -4 route show dev wg99 table 1234' )
1918 self
. assertIn ( '192.168.26.0/24 proto static scope link metric 123' , output
)
1920 output
= check_output ( 'ip -6 route show dev wg99 table 1234' )
1922 self
. assertIn ( 'fd31:bf08:57cb::/48 proto static metric 123 pref medium' , output
)
1924 output
= check_output ( 'ip -6 route show dev wg98 table 1234' )
1926 self
. assertIn ( 'fd8d:4d6d:3ccb:500:c79:2339:edce:ece1 proto static metric 123 pref medium' , output
)
1927 self
. assertIn ( 'fd8d:4d6d:3ccb:500:1dbf:ca8a:32d3:dd81 proto static metric 123 pref medium' , output
)
1928 self
. assertIn ( 'fd8d:4d6d:3ccb:500:1e54:1415:35d0:a47c proto static metric 123 pref medium' , output
)
1929 self
. assertIn ( 'fd8d:4d6d:3ccb:500:270d:b5dd:4a3f:8909 proto static metric 123 pref medium' , output
)
1930 self
. assertIn ( 'fd8d:4d6d:3ccb:500:5660:679d:3532:94d8 proto static metric 123 pref medium' , output
)
1931 self
. assertIn ( 'fd8d:4d6d:3ccb:500:6825:573f:30f3:9472 proto static metric 123 pref medium' , output
)
1932 self
. assertIn ( 'fd8d:4d6d:3ccb:500:6f2e:6888:c6fd:dfb9 proto static metric 123 pref medium' , output
)
1933 self
. assertIn ( 'fd8d:4d6d:3ccb:500:8d4d:bab:7280:a09a proto static metric 123 pref medium' , output
)
1934 self
. assertIn ( 'fd8d:4d6d:3ccb:500:900c:d437:ec27:8822 proto static metric 123 pref medium' , output
)
1935 self
. assertIn ( 'fd8d:4d6d:3ccb:500:9742:9931:5217:18d5 proto static metric 123 pref medium' , output
)
1936 self
. assertIn ( 'fd8d:4d6d:3ccb:500:9c11:d820:2e96:9be0 proto static metric 123 pref medium' , output
)
1937 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a072:80da:de4f:add1 proto static metric 123 pref medium' , output
)
1938 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a3f3:df38:19b0:721 proto static metric 123 pref medium' , output
)
1939 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a94b:cd6a:a32d:90e6 proto static metric 123 pref medium' , output
)
1940 self
. assertIn ( 'fd8d:4d6d:3ccb:500:b39c:9cdc:755a:ead3 proto static metric 123 pref medium' , output
)
1941 self
. assertIn ( 'fd8d:4d6d:3ccb:500:b684:4f81:2e3e:132e proto static metric 123 pref medium' , output
)
1942 self
. assertIn ( 'fd8d:4d6d:3ccb:500:bad5:495d:8e9c:3427 proto static metric 123 pref medium' , output
)
1943 self
. assertIn ( 'fd8d:4d6d:3ccb:500:bfe5:c3c3:5d77:fcb proto static metric 123 pref medium' , output
)
1944 self
. assertIn ( 'fd8d:4d6d:3ccb:500:c624:6bf7:4c09:3b59 proto static metric 123 pref medium' , output
)
1945 self
. assertIn ( 'fd8d:4d6d:3ccb:500:d4f9:5dc:9296:a1a proto static metric 123 pref medium' , output
)
1946 self
. assertIn ( 'fd8d:4d6d:3ccb:500:dcdd:d33b:90c9:6088 proto static metric 123 pref medium' , output
)
1947 self
. assertIn ( 'fd8d:4d6d:3ccb:500:e2e1:ae15:103f:f376 proto static metric 123 pref medium' , output
)
1948 self
. assertIn ( 'fd8d:4d6d:3ccb:500:f349:c4f0:10c1:6b4 proto static metric 123 pref medium' , output
)
1949 self
. assertIn ( 'fd8d:4d6d:3ccb:c79:2339:edce::/96 proto static metric 123 pref medium' , output
)
1950 self
. assertIn ( 'fd8d:4d6d:3ccb:1dbf:ca8a:32d3::/96 proto static metric 123 pref medium' , output
)
1951 self
. assertIn ( 'fd8d:4d6d:3ccb:1e54:1415:35d0::/96 proto static metric 123 pref medium' , output
)
1952 self
. assertIn ( 'fd8d:4d6d:3ccb:270d:b5dd:4a3f::/96 proto static metric 123 pref medium' , output
)
1953 self
. assertIn ( 'fd8d:4d6d:3ccb:5660:679d:3532::/96 proto static metric 123 pref medium' , output
)
1954 self
. assertIn ( 'fd8d:4d6d:3ccb:6825:573f:30f3::/96 proto static metric 123 pref medium' , output
)
1955 self
. assertIn ( 'fd8d:4d6d:3ccb:6f2e:6888:c6fd::/96 proto static metric 123 pref medium' , output
)
1956 self
. assertIn ( 'fd8d:4d6d:3ccb:8d4d:bab:7280::/96 proto static metric 123 pref medium' , output
)
1957 self
. assertIn ( 'fd8d:4d6d:3ccb:900c:d437:ec27::/96 proto static metric 123 pref medium' , output
)
1958 self
. assertIn ( 'fd8d:4d6d:3ccb:9742:9931:5217::/96 proto static metric 123 pref medium' , output
)
1959 self
. assertIn ( 'fd8d:4d6d:3ccb:9c11:d820:2e96::/96 proto static metric 123 pref medium' , output
)
1960 self
. assertIn ( 'fd8d:4d6d:3ccb:a072:80da:de4f::/96 proto static metric 123 pref medium' , output
)
1961 self
. assertIn ( 'fd8d:4d6d:3ccb:a3f3:df38:19b0::/96 proto static metric 123 pref medium' , output
)
1962 self
. assertIn ( 'fd8d:4d6d:3ccb:a94b:cd6a:a32d::/96 proto static metric 123 pref medium' , output
)
1963 self
. assertIn ( 'fd8d:4d6d:3ccb:b39c:9cdc:755a::/96 proto static metric 123 pref medium' , output
)
1964 self
. assertIn ( 'fd8d:4d6d:3ccb:b684:4f81:2e3e::/96 proto static metric 123 pref medium' , output
)
1965 self
. assertIn ( 'fd8d:4d6d:3ccb:bad5:495d:8e9c::/96 proto static metric 123 pref medium' , output
)
1966 self
. assertIn ( 'fd8d:4d6d:3ccb:bfe5:c3c3:5d77::/96 proto static metric 123 pref medium' , output
)
1967 self
. assertIn ( 'fd8d:4d6d:3ccb:c624:6bf7:4c09::/96 proto static metric 123 pref medium' , output
)
1968 self
. assertIn ( 'fd8d:4d6d:3ccb:d4f9:5dc:9296::/96 proto static metric 123 pref medium' , output
)
1969 self
. assertIn ( 'fd8d:4d6d:3ccb:dcdd:d33b:90c9::/96 proto static metric 123 pref medium' , output
)
1970 self
. assertIn ( 'fd8d:4d6d:3ccb:e2e1:ae15:103f::/96 proto static metric 123 pref medium' , output
)
1971 self
. assertIn ( 'fd8d:4d6d:3ccb:f349:c4f0:10c1::/96 proto static metric 123 pref medium' , output
)
1973 if shutil
. which ( 'wg' ):
1976 output
= check_output ( 'wg show wg99 listen-port' )
1977 self
. assertEqual ( output
, '51820' )
1978 output
= check_output ( 'wg show wg99 fwmark' )
1979 self
. assertEqual ( output
, '0x4d2' )
1980 output
= check_output ( 'wg show wg99 private-key' )
1981 self
. assertEqual ( output
, 'EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=' )
1982 output
= check_output ( 'wg show wg99 allowed-ips' )
1983 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t 192.168.124.3/32' , output
)
1984 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t 192.168.124.2/32' , output
)
1985 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t fdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128' , output
)
1986 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 192.168.26.0/24 fd31:bf08:57cb::/48' , output
)
1987 output
= check_output ( 'wg show wg99 persistent-keepalive' )
1988 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t off' , output
)
1989 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t off' , output
)
1990 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t off' , output
)
1991 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 20' , output
)
1992 output
= check_output ( 'wg show wg99 endpoints' )
1993 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t (none)' , output
)
1994 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t (none)' , output
)
1995 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t (none)' , output
)
1996 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 192.168.27.3:51820' , output
)
1997 output
= check_output ( 'wg show wg99 preshared-keys' )
1998 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t 6Fsg8XN0DE6aPQgAX4r2oazEYJOGqyHUz3QRH/jCB+I=' , output
)
1999 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t it7nd33chCT/tKT2ZZWfYyp43Zs+6oif72hexnSNMqA=' , output
)
2000 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=' , output
)
2001 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=' , output
)
2003 output
= check_output ( 'wg show wg98 private-key' )
2004 self
. assertEqual ( output
, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr+WHtZLZ90FU=' )
2006 output
= check_output ( 'wg show wg97 listen-port' )
2007 self
. assertEqual ( output
, '51821' )
2008 output
= check_output ( 'wg show wg97 fwmark' )
2009 self
. assertEqual ( output
, '0x4d3' )
2011 def test_geneve ( self
):
2012 copy_network_unit ( '25-geneve.netdev' , '26-netdev-link-local-addressing-yes.network' )
2015 self
. wait_online ( 'geneve99:degraded' )
2017 output
= check_output ( 'ip -d link show geneve99' )
2019 self
. assertRegex ( output
, '192.168.22.1' )
2020 self
. assertRegex ( output
, '6082' )
2021 self
. assertRegex ( output
, 'udpcsum' )
2022 self
. assertRegex ( output
, 'udp6zerocsumrx' )
2024 def test_ipip_tunnel ( self
):
2025 copy_network_unit ( '12-dummy.netdev' , '25-ipip.network' ,
2026 '25-ipip-tunnel.netdev' , '25-tunnel.network' ,
2027 '25-ipip-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
2028 '25-ipip-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
2029 '25-ipip-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
2031 self
. wait_online ( 'ipiptun99:routable' , 'ipiptun98:routable' , 'ipiptun97:routable' , 'ipiptun96:routable' , 'dummy98:degraded' )
2033 output
= check_output ( 'ip -d link show ipiptun99' )
2035 self
. assertRegex ( output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98' )
2036 output
= check_output ( 'ip -d link show ipiptun98' )
2038 self
. assertRegex ( output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98' )
2039 output
= check_output ( 'ip -d link show ipiptun97' )
2041 self
. assertRegex ( output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98' )
2042 output
= check_output ( 'ip -d link show ipiptun96' )
2044 self
. assertRegex ( output
, 'ipip (ipip )?remote any local any dev dummy98' )
2046 def test_gre_tunnel ( self
):
2047 copy_network_unit ( '12-dummy.netdev' , '25-gretun.network' ,
2048 '25-gre-tunnel.netdev' , '25-tunnel.network' ,
2049 '25-gre-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
2050 '25-gre-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
2051 '25-gre-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
2053 self
. wait_online ( 'gretun99:routable' , 'gretun98:routable' , 'gretun97:routable' , 'gretun96:routable' , 'dummy98:degraded' )
2055 output
= check_output ( 'ip -d link show gretun99' )
2057 self
. assertRegex ( output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
2058 self
. assertRegex ( output
, 'ikey 1.2.3.103' )
2059 self
. assertRegex ( output
, 'okey 1.2.4.103' )
2060 self
. assertRegex ( output
, 'iseq' )
2061 self
. assertRegex ( output
, 'oseq' )
2062 output
= check_output ( 'ip -d link show gretun98' )
2064 self
. assertRegex ( output
, 'gre remote 10.65.223.239 local any dev dummy98' )
2065 self
. assertRegex ( output
, 'ikey 0.0.0.104' )
2066 self
. assertRegex ( output
, 'okey 0.0.0.104' )
2067 self
. assertNotRegex ( output
, 'iseq' )
2068 self
. assertNotRegex ( output
, 'oseq' )
2069 output
= check_output ( 'ip -d link show gretun97' )
2071 self
. assertRegex ( output
, 'gre remote any local 10.65.223.238 dev dummy98' )
2072 self
. assertRegex ( output
, 'ikey 0.0.0.105' )
2073 self
. assertRegex ( output
, 'okey 0.0.0.105' )
2074 self
. assertNotRegex ( output
, 'iseq' )
2075 self
. assertNotRegex ( output
, 'oseq' )
2076 output
= check_output ( 'ip -d link show gretun96' )
2078 self
. assertRegex ( output
, 'gre remote any local any dev dummy98' )
2079 self
. assertRegex ( output
, 'ikey 0.0.0.106' )
2080 self
. assertRegex ( output
, 'okey 0.0.0.106' )
2081 self
. assertNotRegex ( output
, 'iseq' )
2082 self
. assertNotRegex ( output
, 'oseq' )
2084 def test_ip6gre_tunnel ( self
):
2085 copy_network_unit ( '12-dummy.netdev' , '25-ip6gretun.network' ,
2086 '25-ip6gre-tunnel.netdev' , '25-tunnel.network' ,
2087 '25-ip6gre-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
2088 '25-ip6gre-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
2089 '25-ip6gre-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
2092 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
2094 self
. wait_links ( 'dummy98' , 'ip6gretun99' , 'ip6gretun98' , 'ip6gretun97' , 'ip6gretun96' )
2096 output
= check_output ( 'ip -d link show ip6gretun99' )
2098 self
. assertRegex ( output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
2099 output
= check_output ( 'ip -d link show ip6gretun98' )
2101 self
. assertRegex ( output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98' )
2102 output
= check_output ( 'ip -d link show ip6gretun97' )
2104 self
. assertRegex ( output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98' )
2105 output
= check_output ( 'ip -d link show ip6gretun96' )
2107 self
. assertRegex ( output
, 'ip6gre remote any local any dev dummy98' )
2109 def test_gretap_tunnel ( self
):
2110 copy_network_unit ( '12-dummy.netdev' , '25-gretap.network' ,
2111 '25-gretap-tunnel.netdev' , '25-tunnel.network' ,
2112 '25-gretap-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
2114 self
. wait_online ( 'gretap99:routable' , 'gretap98:routable' , 'dummy98:degraded' )
2116 output
= check_output ( 'ip -d link show gretap99' )
2118 self
. assertRegex ( output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
2119 self
. assertRegex ( output
, 'ikey 0.0.0.106' )
2120 self
. assertRegex ( output
, 'okey 0.0.0.106' )
2121 self
. assertRegex ( output
, 'iseq' )
2122 self
. assertRegex ( output
, 'oseq' )
2123 self
. assertIn ( 'nopmtudisc' , output
)
2124 self
. assertIn ( 'ignore-df' , output
)
2125 output
= check_output ( 'ip -d link show gretap98' )
2127 self
. assertRegex ( output
, 'gretap remote 10.65.223.239 local any dev dummy98' )
2128 self
. assertRegex ( output
, 'ikey 0.0.0.107' )
2129 self
. assertRegex ( output
, 'okey 0.0.0.107' )
2130 self
. assertRegex ( output
, 'iseq' )
2131 self
. assertRegex ( output
, 'oseq' )
2133 def test_ip6gretap_tunnel ( self
):
2134 copy_network_unit ( '12-dummy.netdev' , '25-ip6gretap.network' ,
2135 '25-ip6gretap-tunnel.netdev' , '25-tunnel.network' ,
2136 '25-ip6gretap-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
2138 self
. wait_online ( 'ip6gretap99:routable' , 'ip6gretap98:routable' , 'dummy98:degraded' )
2140 output
= check_output ( 'ip -d link show ip6gretap99' )
2142 self
. assertRegex ( output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
2143 output
= check_output ( 'ip -d link show ip6gretap98' )
2145 self
. assertRegex ( output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98' )
2147 def test_vti_tunnel ( self
):
2148 copy_network_unit ( '12-dummy.netdev' , '25-vti.network' ,
2149 '25-vti-tunnel.netdev' , '25-tunnel.network' ,
2150 '25-vti-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
2151 '25-vti-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
2152 '25-vti-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
2154 self
. wait_online ( 'vtitun99:routable' , 'vtitun98:routable' , 'vtitun97:routable' , 'vtitun96:routable' , 'dummy98:degraded' )
2156 output
= check_output ( 'ip -d link show vtitun99' )
2158 self
. assertRegex ( output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
2159 output
= check_output ( 'ip -d link show vtitun98' )
2161 self
. assertRegex ( output
, 'vti remote 10.65.223.239 local any dev dummy98' )
2162 output
= check_output ( 'ip -d link show vtitun97' )
2164 self
. assertRegex ( output
, 'vti remote any local 10.65.223.238 dev dummy98' )
2165 output
= check_output ( 'ip -d link show vtitun96' )
2167 self
. assertRegex ( output
, 'vti remote any local any dev dummy98' )
2169 def test_vti6_tunnel ( self
):
2170 copy_network_unit ( '12-dummy.netdev' , '25-vti6.network' ,
2171 '25-vti6-tunnel.netdev' , '25-tunnel.network' ,
2172 '25-vti6-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
2173 '25-vti6-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' )
2175 self
. wait_online ( 'vti6tun99:routable' , 'vti6tun98:routable' , 'vti6tun97:routable' , 'dummy98:degraded' )
2177 output
= check_output ( 'ip -d link show vti6tun99' )
2179 self
. assertRegex ( output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
2180 output
= check_output ( 'ip -d link show vti6tun98' )
2182 self
. assertRegex ( output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98' )
2183 output
= check_output ( 'ip -d link show vti6tun97' )
2185 self
. assertRegex ( output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98' )
2187 def test_ip6tnl_tunnel ( self
):
2188 copy_network_unit ( '12-dummy.netdev' , '25-ip6tnl.network' ,
2189 '25-ip6tnl-tunnel.netdev' , '25-tunnel.network' ,
2190 '25-ip6tnl-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
2191 '25-ip6tnl-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
2192 '25-veth.netdev' , '25-ip6tnl-slaac.network' , '25-ipv6-prefix.network' ,
2193 '25-ip6tnl-tunnel-local-slaac.netdev' , '25-ip6tnl-tunnel-local-slaac.network' ,
2194 '25-ip6tnl-tunnel-external.netdev' , '26-netdev-link-local-addressing-yes.network' )
2196 self
. wait_online ( 'ip6tnl99:routable' , 'ip6tnl98:routable' , 'ip6tnl97:routable' ,
2197 'ip6tnl-slaac:degraded' , 'ip6tnl-external:degraded' ,
2198 'dummy98:degraded' , 'veth99:routable' , 'veth-peer:degraded' )
2200 output
= check_output ( 'ip -d link show ip6tnl99' )
2202 self
. assertIn ( 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' , output
)
2203 output
= check_output ( 'ip -d link show ip6tnl98' )
2205 self
. assertRegex ( output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98' )
2206 output
= check_output ( 'ip -d link show ip6tnl97' )
2208 self
. assertRegex ( output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98' )
2209 output
= check_output ( 'ip -d link show ip6tnl-external' )
2211 self
. assertIn ( 'ip6tnl-external@NONE:' , output
)
2212 self
. assertIn ( 'ip6tnl external ' , output
)
2213 output
= check_output ( 'ip -d link show ip6tnl-slaac' )
2215 self
. assertIn ( 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99' , output
)
2217 output
= check_output ( 'ip -6 address show veth99' )
2219 self
. assertIn ( 'inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic' , output
)
2221 output
= check_output ( 'ip -4 route show default' )
2223 self
. assertIn ( 'default dev ip6tnl-slaac proto static' , output
)
2225 def test_sit_tunnel ( self
):
2226 copy_network_unit ( '12-dummy.netdev' , '25-sit.network' ,
2227 '25-sit-tunnel.netdev' , '25-tunnel.network' ,
2228 '25-sit-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
2229 '25-sit-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
2230 '25-sit-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
2232 self
. wait_online ( 'sittun99:routable' , 'sittun98:routable' , 'sittun97:routable' , 'sittun96:routable' , 'dummy98:degraded' )
2234 output
= check_output ( 'ip -d link show sittun99' )
2236 self
. assertRegex ( output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98" )
2237 output
= check_output ( 'ip -d link show sittun98' )
2239 self
. assertRegex ( output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98" )
2240 output
= check_output ( 'ip -d link show sittun97' )
2242 self
. assertRegex ( output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98" )
2243 output
= check_output ( 'ip -d link show sittun96' )
2245 self
. assertRegex ( output
, "sit (ip6ip )?remote any local any dev dummy98" )
2247 def test_isatap_tunnel ( self
):
2248 copy_network_unit ( '12-dummy.netdev' , '25-isatap.network' ,
2249 '25-isatap-tunnel.netdev' , '25-tunnel.network' )
2251 self
. wait_online ( 'isataptun99:routable' , 'dummy98:degraded' )
2253 output
= check_output ( 'ip -d link show isataptun99' )
2255 self
. assertRegex ( output
, "isatap " )
2257 def test_6rd_tunnel ( self
):
2258 copy_network_unit ( '12-dummy.netdev' , '25-6rd.network' ,
2259 '25-6rd-tunnel.netdev' , '25-tunnel.network' )
2261 self
. wait_online ( 'sittun99:routable' , 'dummy98:degraded' )
2263 output
= check_output ( 'ip -d link show sittun99' )
2265 self
. assertRegex ( output
, '6rd-prefix 2602::/24' )
2267 @expectedFailureIfERSPANv0IsNotSupported ()
2268 def test_erspan_tunnel_v0 ( self
):
2269 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
2270 '25-erspan0-tunnel.netdev' , '25-tunnel.network' ,
2271 '25-erspan0-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
2273 self
. wait_online ( 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' )
2275 output
= check_output ( 'ip -d link show erspan99' )
2277 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
2278 self
. assertIn ( 'erspan_ver 0' , output
)
2279 self
. assertNotIn ( 'erspan_index 123' , output
)
2280 self
. assertNotIn ( 'erspan_dir ingress' , output
)
2281 self
. assertNotIn ( 'erspan_hwid 1f' , output
)
2282 self
. assertIn ( 'ikey 0.0.0.101' , output
)
2283 self
. assertIn ( 'iseq' , output
)
2284 self
. assertIn ( 'nopmtudisc' , output
)
2285 self
. assertIn ( 'ignore-df' , output
)
2286 output
= check_output ( 'ip -d link show erspan98' )
2288 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
2289 self
. assertIn ( 'erspan_ver 0' , output
)
2290 self
. assertNotIn ( 'erspan_index 124' , output
)
2291 self
. assertNotIn ( 'erspan_dir egress' , output
)
2292 self
. assertNotIn ( 'erspan_hwid 2f' , output
)
2293 self
. assertIn ( 'ikey 0.0.0.102' , output
)
2294 self
. assertIn ( 'iseq' , output
)
2296 def test_erspan_tunnel_v1 ( self
):
2297 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
2298 '25-erspan1-tunnel.netdev' , '25-tunnel.network' ,
2299 '25-erspan1-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
2301 self
. wait_online ( 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' )
2303 output
= check_output ( 'ip -d link show erspan99' )
2305 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
2306 self
. assertIn ( 'erspan_ver 1' , output
)
2307 self
. assertIn ( 'erspan_index 123' , output
)
2308 self
. assertNotIn ( 'erspan_dir ingress' , output
)
2309 self
. assertNotIn ( 'erspan_hwid 1f' , output
)
2310 self
. assertIn ( 'ikey 0.0.0.101' , output
)
2311 self
. assertIn ( 'okey 0.0.0.101' , output
)
2312 self
. assertIn ( 'iseq' , output
)
2313 self
. assertIn ( 'oseq' , output
)
2314 output
= check_output ( 'ip -d link show erspan98' )
2316 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
2317 self
. assertIn ( 'erspan_ver 1' , output
)
2318 self
. assertIn ( 'erspan_index 124' , output
)
2319 self
. assertNotIn ( 'erspan_dir egress' , output
)
2320 self
. assertNotIn ( 'erspan_hwid 2f' , output
)
2321 self
. assertIn ( 'ikey 0.0.0.102' , output
)
2322 self
. assertIn ( 'okey 0.0.0.102' , output
)
2323 self
. assertIn ( 'iseq' , output
)
2324 self
. assertIn ( 'oseq' , output
)
2326 @expectedFailureIfERSPANv2IsNotSupported ()
2327 def test_erspan_tunnel_v2 ( self
):
2328 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
2329 '25-erspan2-tunnel.netdev' , '25-tunnel.network' ,
2330 '25-erspan2-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
2332 self
. wait_online ( 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' )
2334 output
= check_output ( 'ip -d link show erspan99' )
2336 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
2337 self
. assertIn ( 'erspan_ver 2' , output
)
2338 self
. assertNotIn ( 'erspan_index 123' , output
)
2339 self
. assertIn ( 'erspan_dir ingress' , output
)
2340 self
. assertIn ( 'erspan_hwid 0x1f' , output
)
2341 self
. assertIn ( 'ikey 0.0.0.101' , output
)
2342 self
. assertIn ( 'okey 0.0.0.101' , output
)
2343 self
. assertIn ( 'iseq' , output
)
2344 self
. assertIn ( 'oseq' , output
)
2345 output
= check_output ( 'ip -d link show erspan98' )
2347 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
2348 self
. assertIn ( 'erspan_ver 2' , output
)
2349 self
. assertNotIn ( 'erspan_index 124' , output
)
2350 self
. assertIn ( 'erspan_dir egress' , output
)
2351 self
. assertIn ( 'erspan_hwid 0x2f' , output
)
2352 self
. assertIn ( 'ikey 0.0.0.102' , output
)
2353 self
. assertIn ( 'okey 0.0.0.102' , output
)
2354 self
. assertIn ( 'iseq' , output
)
2355 self
. assertIn ( 'oseq' , output
)
2357 def test_tunnel_independent ( self
):
2358 copy_network_unit ( '25-ipip-tunnel-independent.netdev' , '26-netdev-link-local-addressing-yes.network' )
2361 self
. wait_online ( 'ipiptun99:carrier' )
2363 def test_tunnel_independent_loopback ( self
):
2364 copy_network_unit ( '25-ipip-tunnel-independent-loopback.netdev' , '26-netdev-link-local-addressing-yes.network' )
2367 self
. wait_online ( 'ipiptun99:carrier' )
2369 @expectedFailureIfModuleIsNotAvailable ( 'xfrm_interface' )
2370 def test_xfrm ( self
):
2371 copy_network_unit ( '12-dummy.netdev' , '25-xfrm.network' ,
2372 '25-xfrm.netdev' , '25-xfrm-independent.netdev' ,
2373 '26-netdev-link-local-addressing-yes.network' )
2376 self
. wait_online ( 'dummy98:degraded' , 'xfrm98:degraded' , 'xfrm99:degraded' )
2378 output
= check_output ( 'ip -d link show dev xfrm98' )
2380 self
. assertIn ( 'xfrm98@dummy98:' , output
)
2381 self
. assertIn ( 'xfrm if_id 0x98 ' , output
)
2383 output
= check_output ( 'ip -d link show dev xfrm99' )
2385 self
. assertIn ( 'xfrm99@lo:' , output
)
2386 self
. assertIn ( 'xfrm if_id 0x99 ' , output
)
2388 @expectedFailureIfModuleIsNotAvailable ( 'fou' )
2390 # The following redundant check is necessary for CentOS CI.
2391 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
2392 self
. assertTrue ( is_module_available ( 'fou' ))
2394 copy_network_unit ( '25-fou-ipproto-ipip.netdev' , '25-fou-ipproto-gre.netdev' ,
2395 '25-fou-ipip.netdev' , '25-fou-sit.netdev' ,
2396 '25-fou-gre.netdev' , '25-fou-gretap.netdev' )
2399 self
. wait_online ( 'ipiptun96:off' , 'sittun96:off' , 'gretun96:off' , 'gretap96:off' , setup_state
= 'unmanaged' )
2401 output
= check_output ( 'ip fou show' )
2403 self
. assertRegex ( output
, 'port 55555 ipproto 4' )
2404 self
. assertRegex ( output
, 'port 55556 ipproto 47' )
2406 output
= check_output ( 'ip -d link show ipiptun96' )
2408 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55555' )
2409 output
= check_output ( 'ip -d link show sittun96' )
2411 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55555' )
2412 output
= check_output ( 'ip -d link show gretun96' )
2414 self
. assertRegex ( output
, 'encap fou encap-sport 1001 encap-dport 55556' )
2415 output
= check_output ( 'ip -d link show gretap96' )
2417 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55556' )
2419 def test_vxlan ( self
):
2420 copy_network_unit ( '11-dummy.netdev' , '25-vxlan-test1.network' ,
2421 '25-vxlan.netdev' , '25-vxlan.network' ,
2422 '25-vxlan-ipv6.netdev' , '25-vxlan-ipv6.network' ,
2423 '25-vxlan-independent.netdev' , '26-netdev-link-local-addressing-yes.network' ,
2424 '25-veth.netdev' , '25-vxlan-veth99.network' , '25-ipv6-prefix.network' ,
2425 '25-vxlan-local-slaac.netdev' , '25-vxlan-local-slaac.network' )
2428 self
. wait_online ( 'test1:degraded' , 'veth99:routable' , 'veth-peer:degraded' ,
2429 'vxlan99:degraded' , 'vxlan98:degraded' , 'vxlan97:degraded' , 'vxlan-slaac:degraded' )
2431 output
= check_output ( 'ip -d -d link show vxlan99' )
2433 self
. assertIn ( '999' , output
)
2434 self
. assertIn ( '5555' , output
)
2435 self
. assertIn ( 'l2miss' , output
)
2436 self
. assertIn ( 'l3miss' , output
)
2437 self
. assertIn ( 'gbp' , output
)
2438 # Since [0] some of the options use slightly different names and some
2439 # options with default values are shown only if the -d(etails) setting
2441 # [0] https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit/?id=1215e9d3862387353d8672296cb4c6c16e8cbb72
2442 self
. assertRegex ( output
, '(udpcsum|udp_csum)' )
2443 self
. assertRegex ( output
, '(udp6zerocsumtx|udp_zero_csum6_tx)' )
2444 self
. assertRegex ( output
, '(udp6zerocsumrx|udp_zero_csum6_rx)' )
2445 self
. assertRegex ( output
, '(remcsumtx|remcsum_tx)' )
2446 self
. assertRegex ( output
, '(remcsumrx|remcsum_rx)' )
2448 output
= check_output ( 'bridge fdb show dev vxlan99' )
2450 self
. assertIn ( '00:11:22:33:44:55 dst 10.0.0.5 self permanent' , output
)
2451 self
. assertIn ( '00:11:22:33:44:66 dst 10.0.0.6 self permanent' , output
)
2452 self
. assertIn ( '00:11:22:33:44:77 dst 10.0.0.7 via test1 self permanent' , output
)
2454 output
= networkctl_status ( 'vxlan99' )
2456 self
. assertIn ( 'VNI: 999' , output
)
2457 self
. assertIn ( 'Destination Port: 5555' , output
)
2458 self
. assertIn ( 'Underlying Device: test1' , output
)
2460 output
= check_output ( 'bridge fdb show dev vxlan97' )
2462 self
. assertIn ( '00:00:00:00:00:00 dst fe80::23b:d2ff:fe95:967f via test1 self permanent' , output
)
2463 self
. assertIn ( '00:00:00:00:00:00 dst fe80::27c:16ff:fec0:6c74 via test1 self permanent' , output
)
2464 self
. assertIn ( '00:00:00:00:00:00 dst fe80::2a2:e4ff:fef9:2269 via test1 self permanent' , output
)
2466 output
= check_output ( 'ip -d link show vxlan-slaac' )
2468 self
. assertIn ( 'vxlan id 4831584 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99' , output
)
2470 output
= check_output ( 'ip -6 address show veth99' )
2472 self
. assertIn ( 'inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic' , output
)
2474 @unittest . skipUnless ( compare_kernel_version ( "6" ), reason
= "Causes kernel panic on unpatched kernels: https://bugzilla.kernel.org/show_bug.cgi?id=208315" )
2475 def test_macsec ( self
):
2476 copy_network_unit ( '25-macsec.netdev' , '25-macsec.network' , '25-macsec.key' ,
2477 '26-macsec.network' , '12-dummy.netdev' )
2480 self
. wait_online ( 'dummy98:degraded' , 'macsec99:routable' )
2482 output
= check_output ( 'ip -d link show macsec99' )
2484 self
. assertRegex ( output
, 'macsec99@dummy98' )
2485 self
. assertRegex ( output
, 'macsec sci [0-9a-f]*000b' )
2486 self
. assertRegex ( output
, 'encrypt on' )
2488 output
= check_output ( 'ip macsec show macsec99' )
2490 self
. assertRegex ( output
, 'encrypt on' )
2491 self
. assertRegex ( output
, 'TXSC: [0-9a-f]*000b on SA 1' )
2492 self
. assertRegex ( output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000' )
2493 self
. assertRegex ( output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000' )
2494 self
. assertRegex ( output
, 'RXSC: c619528fe6a00100, state on' )
2495 self
. assertRegex ( output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000' )
2496 self
. assertRegex ( output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000' )
2497 self
. assertRegex ( output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000' )
2498 self
. assertRegex ( output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000' )
2499 self
. assertNotRegex ( output
, 'key 02030405067080900000000000000000' )
2500 self
. assertRegex ( output
, 'RXSC: 8c16456c83a90002, state on' )
2501 self
. assertRegex ( output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000' )
2503 def test_nlmon ( self
):
2504 copy_network_unit ( '25-nlmon.netdev' , '26-netdev-link-local-addressing-yes.network' )
2507 self
. wait_online ( 'nlmon99:carrier' )
2509 @expectedFailureIfModuleIsNotAvailable ( 'ifb' )
2511 copy_network_unit ( '25-ifb.netdev' , '26-netdev-link-local-addressing-yes.network' )
2514 self
. wait_online ( 'ifb99:degraded' )
2516 @unittest . skipUnless ( os
. cpu_count () >= 2 , reason
= "CPU count should be >= 2 to pass this test" )
2517 def test_rps_cpu_1 ( self
):
2518 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network' , '25-rps-cpu-1.link' )
2521 self
. wait_online ( 'dummy98:carrier' )
2523 output
= check_output ( 'cat /sys/class/net/dummy98/queues/rx-0/rps_cpus' )
2525 self
. assertEqual ( int ( output
. replace ( ',' , '' ), base
= 16 ), 2 )
2527 @unittest . skipUnless ( os
. cpu_count () >= 2 , reason
= "CPU count should be >= 2 to pass this test" )
2528 def test_rps_cpu_0_1 ( self
):
2529 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network' , '25-rps-cpu-0-1.link' )
2532 self
. wait_online ( 'dummy98:carrier' )
2534 output
= check_output ( 'cat /sys/class/net/dummy98/queues/rx-0/rps_cpus' )
2536 self
. assertEqual ( int ( output
. replace ( ',' , '' ), base
= 16 ), 3 )
2538 @unittest . skipUnless ( os
. cpu_count () >= 4 , reason
= "CPU count should be >= 4 to pass this test" )
2539 def test_rps_cpu_multi ( self
):
2540 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network' , '25-rps-cpu-multi.link' )
2543 self
. wait_online ( 'dummy98:carrier' )
2545 output
= check_output ( 'cat /sys/class/net/dummy98/queues/rx-0/rps_cpus' )
2547 self
. assertEqual ( int ( output
. replace ( ',' , '' ), base
= 16 ), 15 )
2549 def test_rps_cpu ( self
):
2550 cpu_count
= os
. cpu_count ()
2552 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network' )
2555 self
. wait_online ( 'dummy98:carrier' )
2558 copy_network_unit ( '25-rps-cpu-0.link' )
2559 udevadm_trigger ( '/sys/class/net/dummy98' )
2560 output
= check_output ( 'cat /sys/class/net/dummy98/queues/rx-0/rps_cpus' )
2562 self
. assertEqual ( int ( output
. replace ( ',' , '' ), base
= 16 ), 1 )
2563 remove_network_unit ( '25-rps-cpu-0.link' )
2566 copy_network_unit ( '25-rps-cpu-all.link' )
2567 udevadm_trigger ( '/sys/class/net/dummy98' )
2568 output
= check_output ( 'cat /sys/class/net/dummy98/queues/rx-0/rps_cpus' )
2570 self
. assertEqual ( f
"{int(output.replace(',', ''), base=16):x}" , f
'{(1 << cpu_count) - 1:x}' )
2571 remove_network_unit ( '25-rps-cpu-all.link' )
2574 copy_network_unit ( '24-rps-cpu-disable.link' )
2575 udevadm_trigger ( '/sys/class/net/dummy98' )
2576 output
= check_output ( 'cat /sys/class/net/dummy98/queues/rx-0/rps_cpus' )
2578 self
. assertEqual ( int ( output
. replace ( ',' , '' ), base
= 16 ), 0 )
2579 remove_network_unit ( '24-rps-cpu-disable.link' )
2582 copy_network_unit ( '25-rps-cpu-all.link' )
2583 udevadm_trigger ( '/sys/class/net/dummy98' )
2584 output
= check_output ( 'cat /sys/class/net/dummy98/queues/rx-0/rps_cpus' )
2586 self
. assertEqual ( f
"{int(output.replace(',', ''), base=16):x}" , f
'{(1 << cpu_count) - 1:x}' )
2587 remove_network_unit ( '25-rps-cpu-all.link' )
2589 # empty -> unchanged
2590 copy_network_unit ( '24-rps-cpu-empty.link' )
2591 udevadm_trigger ( '/sys/class/net/dummy98' )
2592 output
= check_output ( 'cat /sys/class/net/dummy98/queues/rx-0/rps_cpus' )
2594 self
. assertEqual ( f
"{int(output.replace(',', ''), base=16):x}" , f
'{(1 << cpu_count) - 1:x}' )
2595 remove_network_unit ( '24-rps-cpu-empty.link' )
2597 # 0, then empty -> unchanged
2598 copy_network_unit ( '25-rps-cpu-0-empty.link' )
2599 udevadm_trigger ( '/sys/class/net/dummy98' )
2600 output
= check_output ( 'cat /sys/class/net/dummy98/queues/rx-0/rps_cpus' )
2602 self
. assertEqual ( f
"{int(output.replace(',', ''), base=16):x}" , f
'{(1 << cpu_count) - 1:x}' )
2603 remove_network_unit ( '25-rps-cpu-0-empty.link' )
2605 # 0, then invalid -> 0
2606 copy_network_unit ( '25-rps-cpu-0-invalid.link' )
2607 udevadm_trigger ( '/sys/class/net/dummy98' )
2608 output
= check_output ( 'cat /sys/class/net/dummy98/queues/rx-0/rps_cpus' )
2610 self
. assertEqual ( int ( output
. replace ( ',' , '' ), base
= 16 ), 1 )
2611 remove_network_unit ( '25-rps-cpu-0-invalid.link' )
2613 # invalid -> unchanged
2614 copy_network_unit ( '24-rps-cpu-invalid.link' )
2615 udevadm_trigger ( '/sys/class/net/dummy98' )
2616 output
= check_output ( 'cat /sys/class/net/dummy98/queues/rx-0/rps_cpus' )
2618 self
. assertEqual ( int ( output
. replace ( ',' , '' ), base
= 16 ), 1 )
2619 remove_network_unit ( '24-rps-cpu-invalid.link' )
2621 class NetworkdL2TPTests ( unittest
. TestCase
, Utilities
):
2629 @expectedFailureIfModuleIsNotAvailable ( 'l2tp_eth' , 'l2tp_netlink' )
2630 def test_l2tp_udp ( self
):
2631 copy_network_unit ( '11-dummy.netdev' , '25-l2tp-dummy.network' ,
2632 '25-l2tp-udp.netdev' , '25-l2tp.network' )
2635 self
. wait_online ( 'test1:routable' , 'l2tp-ses1:degraded' , 'l2tp-ses2:degraded' )
2637 output
= check_output ( 'ip l2tp show tunnel tunnel_id 10' )
2639 self
. assertRegex ( output
, "Tunnel 10, encap UDP" )
2640 self
. assertRegex ( output
, "From 192.168.30.100 to 192.168.30.101" )
2641 self
. assertRegex ( output
, "Peer tunnel 11" )
2642 self
. assertRegex ( output
, "UDP source / dest ports: 3000/4000" )
2643 self
. assertRegex ( output
, "UDP checksum: enabled" )
2645 output
= check_output ( 'ip l2tp show session tid 10 session_id 15' )
2647 self
. assertRegex ( output
, "Session 15 in tunnel 10" )
2648 self
. assertRegex ( output
, "Peer session 16, tunnel 11" )
2649 self
. assertRegex ( output
, "interface name: l2tp-ses1" )
2651 output
= check_output ( 'ip l2tp show session tid 10 session_id 17' )
2653 self
. assertRegex ( output
, "Session 17 in tunnel 10" )
2654 self
. assertRegex ( output
, "Peer session 18, tunnel 11" )
2655 self
. assertRegex ( output
, "interface name: l2tp-ses2" )
2657 @expectedFailureIfModuleIsNotAvailable ( 'l2tp_eth' , 'l2tp_ip' , 'l2tp_netlink' )
2658 def test_l2tp_ip ( self
):
2659 copy_network_unit ( '11-dummy.netdev' , '25-l2tp-dummy.network' ,
2660 '25-l2tp-ip.netdev' , '25-l2tp.network' )
2663 self
. wait_online ( 'test1:routable' , 'l2tp-ses3:degraded' , 'l2tp-ses4:degraded' )
2665 output
= check_output ( 'ip l2tp show tunnel tunnel_id 10' )
2667 self
. assertRegex ( output
, "Tunnel 10, encap IP" )
2668 self
. assertRegex ( output
, "From 192.168.30.100 to 192.168.30.101" )
2669 self
. assertRegex ( output
, "Peer tunnel 12" )
2671 output
= check_output ( 'ip l2tp show session tid 10 session_id 25' )
2673 self
. assertRegex ( output
, "Session 25 in tunnel 10" )
2674 self
. assertRegex ( output
, "Peer session 26, tunnel 12" )
2675 self
. assertRegex ( output
, "interface name: l2tp-ses3" )
2677 output
= check_output ( 'ip l2tp show session tid 10 session_id 27' )
2679 self
. assertRegex ( output
, "Session 27 in tunnel 10" )
2680 self
. assertRegex ( output
, "Peer session 28, tunnel 12" )
2681 self
. assertRegex ( output
, "interface name: l2tp-ses4" )
2683 class NetworkdNetworkTests ( unittest
. TestCase
, Utilities
):
2691 def verify_address_static (
2721 output
= check_output ( 'ip address show dev dummy98' )
2725 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
2726 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
2727 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
2728 self
. assertIn ( 'inet6 2001:db8:0:f101::15/64 scope global' , output
)
2729 self
. assertIn ( 'inet6 2001:db8:0:f101::16/64 scope global' , output
)
2730 self
. assertIn ( 'inet6 2001:db8:0:f102::15/64 scope global' , output
)
2733 self
. assertIn ( f
'inet 10.3.1.1/24 brd 10.3.1.255 scope global {label1} ' , output
)
2734 self
. assertIn ( f
'inet 10.3.2.1/24 brd 10.3.2.255 scope global {label2} ' , output
)
2735 self
. assertIn ( f
'inet 10.3.3.1/24 brd 10.3.3.255 scope global {label3} ' , output
)
2738 self
. assertIn ( f
'inet 10.4.1.1/24 {broadcast1} scope global dummy98' , output
)
2739 self
. assertIn ( f
'inet 10.4.2.1/24 {broadcast2} scope global dummy98' , output
)
2740 self
. assertIn ( f
'inet 10.4.3.1/24 {broadcast3} scope global dummy98' , output
)
2743 self
. assertIn ( f
'inet 10.5.1.1 {peer1} scope global dummy98' , output
)
2744 self
. assertIn ( f
'inet 10.5.2.1 {peer2} scope global dummy98' , output
)
2745 self
. assertIn ( f
'inet 10.5.3.1 {peer3} scope global dummy98' , output
)
2746 self
. assertIn ( f
'inet6 2001:db8:0:f103::1 {peer4} scope global' , output
)
2747 self
. assertIn ( f
'inet6 2001:db8:0:f103::2 {peer5} scope global' , output
)
2748 self
. assertIn ( f
'inet6 2001:db8:0:f103::3 {peer6} scope global' , output
)
2751 self
. assertIn ( f
'inet 10.6.1.1/24 brd 10.6.1.255 scope {scope1} dummy98' , output
)
2752 self
. assertIn ( f
'inet 10.6.2.1/24 brd 10.6.2.255 scope {scope2} dummy98' , output
)
2755 self
. assertIn ( f
'inet 10.7.1.1/24 brd 10.7.1.255 scope global {deprecated1} dummy98' , output
)
2756 self
. assertIn ( f
'inet 10.7.2.1/24 brd 10.7.2.255 scope global {deprecated2} dummy98' , output
)
2757 self
. assertIn ( f
'inet6 2001:db8:0:f104::1/64 scope global {deprecated3} ' , output
)
2758 self
. assertIn ( f
'inet6 2001:db8:0:f104::2/64 scope global {deprecated4} ' , output
)
2761 self
. assertRegex ( output
, rf
'inet 10.8.1.1/24 (metric {route_metric} |)brd 10.8.1.255 scope global dummy98' )
2762 self
. assertRegex ( output
, rf
'inet6 2001:db8:0:f105::1/64 (metric {route_metric} |)scope global' )
2764 output_route
= check_output ( 'ip -4 route show dev dummy98 10.8.1.0/24' )
2766 self
. assertIn ( f
'10.8.1.0/24 proto kernel scope link src 10.8.1.1 metric {route_metric} ' , output_route
)
2768 output_route
= check_output ( 'ip -6 route show dev dummy98 2001:db8:0:f105::/64' )
2770 self
. assertIn ( f
'2001:db8:0:f105::/64 proto kernel metric {route_metric} ' , output_route
)
2773 self
. assertIn ( f
'inet 10.9.1.1/24 brd 10.9.1.255 scope global {flag1} dummy98' , output
)
2774 self
. assertIn ( f
'inet 10.9.2.1/24 brd 10.9.2.255 scope global {flag2} dummy98' , output
)
2775 self
. assertIn ( f
'inet6 2001:db8:0:f106::1/64 scope global {flag3} ' , output
)
2776 self
. assertIn ( f
'inet6 2001:db8:0:f106::2/64 scope global {flag4} ' , output
)
2779 self
. assertTrue ( ip4_null_16
. endswith ( '.0.1' ))
2780 prefix16
= ip4_null_16
[:- len ( '.0.1' )]
2781 self
. assertTrue ( ip4_null_24
. endswith ( '.1' ))
2782 prefix24
= ip4_null_24
[:- len ( '.1' )]
2783 self
. assertIn ( f
'inet {ip4_null_16} /16 brd {prefix16} .255.255 scope global subnet16' , output
)
2784 self
. assertIn ( f
'inet {ip4_null_24} /24 brd {prefix24} .255 scope global subnet24' , output
)
2785 self
. assertIn ( f
'inet6 {ip6_null_73} /73 scope global' , output
)
2786 self
. assertIn ( f
'inet6 {ip6_null_74} /74 scope global' , output
)
2789 self
. assertNotIn ( '10.4.4.1' , output
)
2790 self
. assertNotIn ( '10.5.4.1' , output
)
2791 self
. assertNotIn ( '10.5.5.1' , output
)
2792 self
. assertNotIn ( '10.8.2.1' , output
)
2793 self
. assertNotIn ( '10.9.3.1' , output
)
2794 self
. assertNotIn ( '2001:db8:0:f101::2' , output
)
2795 self
. assertNotIn ( '2001:db8:0:f103::4' , output
)
2798 self
. check_netlabel ( 'dummy98' , r
'10\.10\.1\.0/24' )
2800 check_json ( networkctl_json ())
2802 def test_address_static ( self
):
2803 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' , copy_dropins
= False )
2804 self
. setup_nftset ( 'addr4' , 'ipv4_addr' )
2805 self
. setup_nftset ( 'network4' , 'ipv4_addr' , 'flags interval;' )
2806 self
. setup_nftset ( 'ifindex' , 'iface_index' )
2809 self
. wait_online ( 'dummy98:routable' )
2813 output
= check_output ( 'ip -4 --json address show dev dummy98' )
2814 for i
in json
. loads ( output
)[ 0 ][ 'addr_info' ]:
2815 if i
[ 'label' ] == 'subnet16' :
2816 ip4_null_16
= i
[ 'local' ]
2817 elif i
[ 'label' ] == 'subnet24' :
2818 ip4_null_24
= i
[ 'local' ]
2819 self
. assertTrue ( ip4_null_16
. endswith ( '.0.1' ))
2820 self
. assertTrue ( ip4_null_24
. endswith ( '.1' ))
2824 output
= check_output ( 'ip -6 --json address show dev dummy98' )
2825 for i
in json
. loads ( output
)[ 0 ][ 'addr_info' ]:
2826 if i
[ 'prefixlen' ] == 73 :
2827 ip6_null_73
= i
[ 'local' ]
2828 elif i
[ 'prefixlen' ] == 74 :
2829 ip6_null_74
= i
[ 'local' ]
2830 self
. assertTrue ( ip6_null_73
. endswith ( ':1' ))
2831 self
. assertTrue ( ip6_null_74
. endswith ( ':1' ))
2833 self
. verify_address_static (
2838 broadcast2
= ' brd 10.4.2.255' ,
2839 broadcast3
= ' brd 10.4.3.63' ,
2840 peer1
= ' peer 10.5.1.101/24' ,
2841 peer2
= ' peer 10.5.2.101/24' ,
2842 peer3
= '/24 brd 10.5.3.255' ,
2843 peer4
= ' peer 2001:db8:0:f103::101/128' ,
2844 peer5
= ' peer 2001:db8:0:f103::102/128' ,
2849 deprecated2
= ' deprecated' ,
2851 deprecated4
= ' deprecated' ,
2853 flag1
= ' noprefixroute' ,
2855 flag3
= ' noprefixroute' ,
2856 flag4
= ' home mngtmpaddr' ,
2857 ip4_null_16
= ip4_null_16
,
2858 ip4_null_24
= ip4_null_24
,
2859 ip6_null_73
= ip6_null_73
,
2860 ip6_null_74
= ip6_null_74
,
2863 self
. check_nftset ( 'addr4' , r
'10\.10\.1\.1' )
2864 self
. check_nftset ( 'network4' , r
'10\.10\.1\.0/24' )
2865 self
. check_nftset ( 'ifindex' , 'dummy98' )
2867 self
. teardown_nftset ( 'addr4' , 'network4' , 'ifindex' )
2869 copy_network_unit ( '25-address-static.network.d/10-override.conf' )
2871 self
. wait_online ( 'dummy98:routable' )
2872 self
. verify_address_static (
2873 label1
= 'new-label1' ,
2875 label3
= 'new-label3' ,
2876 broadcast1
= ' brd 10.4.1.255' ,
2878 broadcast3
= ' brd 10.4.3.31' ,
2879 peer1
= ' peer 10.5.1.102/24' ,
2880 peer2
= '/24 brd 10.5.2.255' ,
2881 peer3
= ' peer 10.5.3.102/24' ,
2882 peer4
= ' peer 2001:db8:0:f103::201/128' ,
2884 peer6
= ' peer 2001:db8:0:f103::203/128' ,
2887 deprecated1
= ' deprecated' ,
2889 deprecated3
= ' deprecated' ,
2893 flag2
= ' noprefixroute' ,
2894 flag3
= ' home mngtmpaddr' ,
2895 flag4
= ' noprefixroute' ,
2896 ip4_null_16
= ip4_null_16
,
2897 ip4_null_24
= ip4_null_24
,
2898 ip6_null_73
= ip6_null_73
,
2899 ip6_null_74
= ip6_null_74
,
2902 networkctl_reconfigure ( 'dummy98' )
2903 self
. wait_online ( 'dummy98:routable' )
2904 self
. verify_address_static (
2905 label1
= 'new-label1' ,
2907 label3
= 'new-label3' ,
2908 broadcast1
= ' brd 10.4.1.255' ,
2910 broadcast3
= ' brd 10.4.3.31' ,
2911 peer1
= ' peer 10.5.1.102/24' ,
2912 peer2
= '/24 brd 10.5.2.255' ,
2913 peer3
= ' peer 10.5.3.102/24' ,
2914 peer4
= ' peer 2001:db8:0:f103::201/128' ,
2916 peer6
= ' peer 2001:db8:0:f103::203/128' ,
2919 deprecated1
= ' deprecated' ,
2921 deprecated3
= ' deprecated' ,
2925 flag2
= ' noprefixroute' ,
2926 flag3
= ' home mngtmpaddr' ,
2927 flag4
= ' noprefixroute' ,
2928 ip4_null_16
= ip4_null_16
,
2929 ip4_null_24
= ip4_null_24
,
2930 ip6_null_73
= ip6_null_73
,
2931 ip6_null_74
= ip6_null_74
,
2935 # 1. set preferred lifetime forever to drop the deprecated flag for testing #20891.
2936 check_output ( 'ip address change 10.7.1.1/24 dev dummy98 preferred_lft forever' )
2937 check_output ( 'ip address change 2001:db8:0:f104::1/64 dev dummy98 preferred_lft forever' )
2938 output
= check_output ( 'ip address show dev dummy98' )
2940 self
. assertNotRegex ( output
, '10.7.1.1/24 .* deprecated' )
2941 self
. assertNotRegex ( output
, '2001:db8:0:f104::1/64 .* deprecated' )
2943 # 2. reconfigure the interface, and check the deprecated flag is set again
2944 networkctl_reconfigure ( 'dummy98' )
2945 self
. wait_online ( 'dummy98:routable' )
2946 self
. verify_address_static (
2947 label1
= 'new-label1' ,
2949 label3
= 'new-label3' ,
2950 broadcast1
= ' brd 10.4.1.255' ,
2952 broadcast3
= ' brd 10.4.3.31' ,
2953 peer1
= ' peer 10.5.1.102/24' ,
2954 peer2
= '/24 brd 10.5.2.255' ,
2955 peer3
= ' peer 10.5.3.102/24' ,
2956 peer4
= ' peer 2001:db8:0:f103::201/128' ,
2958 peer6
= ' peer 2001:db8:0:f103::203/128' ,
2961 deprecated1
= ' deprecated' ,
2963 deprecated3
= ' deprecated' ,
2967 flag2
= ' noprefixroute' ,
2968 flag3
= ' home mngtmpaddr' ,
2969 flag4
= ' noprefixroute' ,
2970 ip4_null_16
= ip4_null_16
,
2971 ip4_null_24
= ip4_null_24
,
2972 ip6_null_73
= ip6_null_73
,
2973 ip6_null_74
= ip6_null_74
,
2976 # test for ENOBUFS issue #17012 (with reload)
2977 copy_network_unit ( '25-address-static.network.d/10-many-address.conf' )
2979 self
. wait_online ( 'dummy98:routable' )
2980 output
= check_output ( 'ip -4 address show dev dummy98' )
2981 for i
in range ( 1 , 254 ):
2982 self
. assertIn ( f
'inet 10.3.3. {i} /16 brd 10.3.255.255' , output
)
2984 # (with reconfigure)
2985 networkctl_reconfigure ( 'dummy98' )
2986 self
. wait_online ( 'dummy98:routable' )
2987 output
= check_output ( 'ip -4 address show dev dummy98' )
2988 for i
in range ( 1 , 254 ):
2989 self
. assertIn ( f
'inet 10.3.3. {i} /16 brd 10.3.255.255' , output
)
2991 # test for an empty string assignment for Address= in [Network]
2992 copy_network_unit ( '25-address-static.network.d/20-clear-addresses.conf' )
2994 self
. wait_online ( 'dummy98:routable' )
2995 output
= check_output ( 'ip -4 address show dev dummy98' )
2996 for i
in range ( 1 , 254 ):
2997 self
. assertNotIn ( f
'inet 10.3.3. {i} /16 brd 10.3.255.255' , output
)
2998 self
. assertIn ( 'inet 10.4.0.1/16 brd 10.4.255.255' , output
)
3000 def test_address_ipv4acd ( self
):
3001 check_output ( 'ip netns add ns99' )
3002 check_output ( 'ip link add veth99 type veth peer veth-peer' )
3003 check_output ( 'ip link set veth-peer netns ns99' )
3004 check_output ( 'ip link set veth99 up' )
3005 check_output ( 'ip netns exec ns99 ip link set veth-peer up' )
3006 check_output ( 'ip netns exec ns99 ip address add 192.168.100.10/24 dev veth-peer' )
3008 copy_network_unit ( '25-address-ipv4acd-veth99.network' , copy_dropins
= False )
3010 self
. wait_online ( 'veth99:routable' )
3012 output
= check_output ( 'ip -4 address show dev veth99' )
3014 self
. assertNotIn ( '192.168.100.10/24' , output
)
3015 self
. assertIn ( '192.168.100.11/24' , output
)
3017 copy_network_unit ( '25-address-ipv4acd-veth99.network.d/conflict-address.conf' )
3019 self
. wait_operstate ( 'veth99' , operstate
= 'routable' , setup_state
= 'configuring' , setup_timeout
= 10 )
3021 output
= check_output ( 'ip -4 address show dev veth99' )
3023 self
. assertNotIn ( '192.168.100.10/24' , output
)
3024 self
. assertIn ( '192.168.100.11/24' , output
)
3026 def test_address_peer_ipv4 ( self
):
3027 # test for issue #17304
3028 copy_network_unit ( '25-address-peer-ipv4.network' , '12-dummy.netdev' )
3030 for trial
in range ( 2 ):
3036 self
. wait_online ( 'dummy98:routable' )
3038 output
= check_output ( 'ip -4 address show dev dummy98' )
3039 self
. assertIn ( 'inet 100.64.0.1 peer 100.64.0.2/32 scope global' , output
)
3041 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
3042 def test_prefix_route ( self
):
3043 copy_network_unit ( '25-prefix-route-with-vrf.network' , '12-dummy.netdev' ,
3044 '25-prefix-route-without-vrf.network' , '11-dummy.netdev' ,
3045 '25-vrf.netdev' , '25-vrf.network' )
3046 for trial
in range ( 2 ):
3052 self
. wait_online ( 'dummy98:routable' , 'test1:routable' , 'vrf99:carrier' )
3054 output
= check_output ( 'ip route show table 42 dev dummy98' )
3055 print ( '### ip route show table 42 dev dummy98' )
3057 self
. assertRegex ( output
, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1' )
3058 self
. assertRegex ( output
, '10.20.33.0/24 proto kernel scope link src 10.20.33.1' )
3059 self
. assertRegex ( output
, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1' )
3060 self
. assertRegex ( output
, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1' )
3061 self
. assertRegex ( output
, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1' )
3062 self
. assertRegex ( output
, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1' )
3063 self
. assertRegex ( output
, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1' )
3064 output
= check_output ( 'ip -6 route show table 42 dev dummy98' )
3065 print ( '### ip -6 route show table 42 dev dummy98' )
3069 self
. assertRegex ( output
, 'local fdde:11:22::1 proto kernel metric 0 pref medium' )
3070 #self.assertRegex(output, 'fdde:11:22::1 proto kernel metric 256 pref medium')
3071 self
. assertRegex ( output
, 'local fdde:11:33::1 proto kernel metric 0 pref medium' )
3072 self
. assertRegex ( output
, 'fdde:11:33::/64 proto kernel metric 256 pref medium' )
3073 self
. assertRegex ( output
, 'local fdde:11:44::1 proto kernel metric 0 pref medium' )
3074 self
. assertRegex ( output
, 'local fdde:11:55::1 proto kernel metric 0 pref medium' )
3075 self
. assertRegex ( output
, 'fe80::/64 proto kernel metric 256 pref medium' )
3076 self
. assertRegex ( output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium' )
3080 output
= check_output ( 'ip route show dev test1' )
3081 print ( '### ip route show dev test1' )
3083 self
. assertRegex ( output
, '10.21.33.0/24 proto kernel scope link src 10.21.33.1' )
3084 output
= check_output ( 'ip route show table local dev test1' )
3085 print ( '### ip route show table local dev test1' )
3087 self
. assertRegex ( output
, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1' )
3088 self
. assertRegex ( output
, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1' )
3089 self
. assertRegex ( output
, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1' )
3090 self
. assertRegex ( output
, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1' )
3091 self
. assertRegex ( output
, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1' )
3092 self
. assertRegex ( output
, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1' )
3093 output
= check_output ( 'ip -6 route show dev test1' )
3094 print ( '### ip -6 route show dev test1' )
3096 self
. assertRegex ( output
, 'fdde:12:22::1 proto kernel metric 256 pref medium' )
3097 self
. assertRegex ( output
, 'fdde:12:33::/64 proto kernel metric 256 pref medium' )
3098 self
. assertRegex ( output
, 'fe80::/64 proto kernel metric 256 pref medium' )
3099 output
= check_output ( 'ip -6 route show table local dev test1' )
3100 print ( '### ip -6 route show table local dev test1' )
3102 self
. assertRegex ( output
, 'local fdde:12:22::1 proto kernel metric 0 pref medium' )
3103 self
. assertRegex ( output
, 'local fdde:12:33::1 proto kernel metric 0 pref medium' )
3104 self
. assertRegex ( output
, 'local fdde:12:44::1 proto kernel metric 0 pref medium' )
3105 self
. assertRegex ( output
, 'local fdde:12:55::1 proto kernel metric 0 pref medium' )
3106 self
. assertRegex ( output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium' )
3108 def test_configure_without_carrier ( self
):
3109 copy_network_unit ( '11-dummy.netdev' )
3111 self
. wait_operstate ( 'test1' , 'off' , '' )
3112 check_output ( 'ip link set dev test1 up carrier off' )
3114 copy_network_unit ( '25-test1.network.d/configure-without-carrier.conf' , copy_dropins
= False )
3116 self
. wait_online ( 'test1:no-carrier' )
3118 carrier_map
= { 'on' : '1' , 'off' : '0' }
3119 routable_map
= { 'on' : 'routable' , 'off' : 'no-carrier' }
3120 for carrier
in [ 'off' , 'on' , 'off' ]:
3121 with self
. subTest ( carrier
= carrier
):
3122 if carrier_map
[ carrier
] != read_link_attr ( 'test1' , 'carrier' ):
3123 check_output ( f
'ip link set dev test1 carrier {carrier} ' )
3124 self
. wait_online ( f
'test1:{routable_map[carrier]}:{routable_map[carrier]}' )
3126 output
= networkctl_status ( 'test1' )
3128 self
. assertRegex ( output
, '192.168.0.15' )
3129 self
. assertRegex ( output
, '192.168.0.1' )
3130 self
. assertRegex ( output
, routable_map
[ carrier
])
3132 def test_configure_without_carrier_yes_ignore_carrier_loss_no ( self
):
3133 copy_network_unit ( '11-dummy.netdev' )
3135 self
. wait_operstate ( 'test1' , 'off' , '' )
3136 check_output ( 'ip link set dev test1 up carrier off' )
3138 copy_network_unit ( '25-test1.network' )
3140 self
. wait_online ( 'test1:no-carrier' )
3142 carrier_map
= { 'on' : '1' , 'off' : '0' }
3143 routable_map
= { 'on' : 'routable' , 'off' : 'no-carrier' }
3144 for ( carrier
, have_config
) in [( 'off' , True ), ( 'on' , True ), ( 'off' , False )]:
3145 with self
. subTest ( carrier
= carrier
, have_config
= have_config
):
3146 if carrier_map
[ carrier
] != read_link_attr ( 'test1' , 'carrier' ):
3147 check_output ( f
'ip link set dev test1 carrier {carrier} ' )
3148 self
. wait_online ( f
'test1:{routable_map[carrier]}:{routable_map[carrier]}' )
3150 output
= networkctl_status ( 'test1' )
3153 self
. assertRegex ( output
, '192.168.0.15' )
3154 self
. assertRegex ( output
, '192.168.0.1' )
3156 self
. assertNotRegex ( output
, '192.168.0.15' )
3157 self
. assertNotRegex ( output
, '192.168.0.1' )
3158 self
. assertRegex ( output
, routable_map
[ carrier
])
3160 def test_routing_policy_rule ( self
):
3161 copy_network_unit ( '25-routing-policy-rule-test1.network' , '11-dummy.netdev' )
3163 self
. wait_online ( 'test1:degraded' )
3165 output
= check_output ( 'ip rule list iif test1 priority 111' )
3167 self
. assertRegex ( output
, '111:' )
3168 self
. assertRegex ( output
, 'from 192.168.100.18' )
3169 self
. assertRegex ( output
, r
'tos (0x08|throughput)\s' )
3170 self
. assertRegex ( output
, 'iif test1' )
3171 self
. assertRegex ( output
, 'oif test1' )
3172 self
. assertRegex ( output
, 'lookup 7' )
3174 output
= check_output ( 'ip rule list iif test1 priority 101' )
3176 self
. assertRegex ( output
, '101:' )
3177 self
. assertRegex ( output
, 'from all' )
3178 self
. assertRegex ( output
, 'iif test1' )
3179 self
. assertRegex ( output
, 'lookup 9' )
3181 output
= check_output ( 'ip -6 rule list iif test1 priority 100' )
3183 self
. assertRegex ( output
, '100:' )
3184 self
. assertRegex ( output
, 'from all' )
3185 self
. assertRegex ( output
, 'iif test1' )
3186 self
. assertRegex ( output
, 'lookup 8' )
3188 output
= check_output ( 'ip rule list iif test1 priority 102' )
3190 self
. assertRegex ( output
, '102:' )
3191 self
. assertRegex ( output
, 'from 0.0.0.0/8' )
3192 self
. assertRegex ( output
, 'iif test1' )
3193 self
. assertRegex ( output
, 'lookup 10' )
3195 check_json ( networkctl_json ())
3197 def test_routing_policy_rule_issue_11280 ( self
):
3198 copy_network_unit ( '25-routing-policy-rule-test1.network' , '11-dummy.netdev' ,
3199 '25-routing-policy-rule-dummy98.network' , '12-dummy.netdev' )
3201 for trial
in range ( 3 ):
3202 restart_networkd ( show_logs
=( trial
> 0 ))
3203 self
. wait_online ( 'test1:degraded' , 'dummy98:degraded' )
3205 output
= check_output ( 'ip rule list table 7' )
3207 self
. assertRegex ( output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7' )
3209 output
= check_output ( 'ip rule list table 8' )
3211 self
. assertRegex ( output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8' )
3213 def test_routing_policy_rule_reconfigure ( self
):
3214 copy_network_unit ( '25-routing-policy-rule-reconfigure2.network' , '11-dummy.netdev' )
3216 self
. wait_online ( 'test1:degraded' )
3218 output
= check_output ( 'ip rule list table 1011' )
3220 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
3221 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
3222 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
3223 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
3225 output
= check_output ( 'ip -6 rule list table 1011' )
3227 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
3229 copy_network_unit ( '25-routing-policy-rule-reconfigure1.network' , '11-dummy.netdev' )
3231 self
. wait_online ( 'test1:degraded' )
3233 output
= check_output ( 'ip rule list table 1011' )
3235 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
3236 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
3237 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
3238 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
3240 output
= check_output ( 'ip -6 rule list table 1011' )
3242 self
. assertNotIn ( '10112: from all oif test1 lookup 1011' , output
)
3243 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
3245 call ( 'ip rule delete priority 10111' )
3246 call ( 'ip rule delete priority 10112' )
3247 call ( 'ip rule delete priority 10113' )
3248 call ( 'ip rule delete priority 10114' )
3249 call ( 'ip -6 rule delete priority 10113' )
3251 output
= check_output ( 'ip rule list table 1011' )
3253 self
. assertEqual ( output
, '' )
3255 output
= check_output ( 'ip -6 rule list table 1011' )
3257 self
. assertEqual ( output
, '' )
3259 networkctl_reconfigure ( 'test1' )
3260 self
. wait_online ( 'test1:degraded' )
3262 output
= check_output ( 'ip rule list table 1011' )
3264 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
3265 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
3266 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
3267 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
3269 output
= check_output ( 'ip -6 rule list table 1011' )
3271 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
3273 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable ()
3274 def test_routing_policy_rule_port_range ( self
):
3275 copy_network_unit ( '25-fibrule-port-range.network' , '11-dummy.netdev' )
3277 self
. wait_online ( 'test1:degraded' )
3279 output
= check_output ( 'ip rule' )
3281 self
. assertRegex ( output
, '111' )
3282 self
. assertRegex ( output
, 'from 192.168.100.18' )
3283 self
. assertRegex ( output
, '1123-1150' )
3284 self
. assertRegex ( output
, '3224-3290' )
3285 self
. assertRegex ( output
, 'tcp' )
3286 self
. assertRegex ( output
, 'lookup 7' )
3288 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable ()
3289 def test_routing_policy_rule_invert ( self
):
3290 copy_network_unit ( '25-fibrule-invert.network' , '11-dummy.netdev' )
3292 self
. wait_online ( 'test1:degraded' )
3294 output
= check_output ( 'ip rule' )
3296 self
. assertRegex ( output
, '111' )
3297 self
. assertRegex ( output
, 'not.*?from.*?192.168.100.18' )
3298 self
. assertRegex ( output
, 'tcp' )
3299 self
. assertRegex ( output
, 'lookup 7' )
3301 @expectedFailureIfRoutingPolicyL3MasterDeviceIsNotAvailable ()
3302 def test_routing_policy_rule_l3mdev ( self
):
3303 copy_network_unit ( '25-fibrule-l3mdev.network' , '11-dummy.netdev' )
3305 self
. wait_online ( 'test1:degraded' )
3307 output
= check_output ( 'ip rule' )
3309 self
. assertIn ( '1500: from all lookup [l3mdev-table]' , output
)
3310 self
. assertIn ( '2000: from all lookup [l3mdev-table] unreachable' , output
)
3312 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable ()
3313 def test_routing_policy_rule_uidrange ( self
):
3314 copy_network_unit ( '25-fibrule-uidrange.network' , '11-dummy.netdev' )
3316 self
. wait_online ( 'test1:degraded' )
3318 output
= check_output ( 'ip rule' )
3320 self
. assertRegex ( output
, '111' )
3321 self
. assertRegex ( output
, 'from 192.168.100.18' )
3322 self
. assertRegex ( output
, 'lookup 7' )
3323 self
. assertRegex ( output
, 'uidrange 100-200' )
3325 def _test_route_static ( self
, manage_foreign_routes
):
3326 if not manage_foreign_routes
:
3327 copy_networkd_conf_dropin ( 'networkd-manage-foreign-routes-no.conf' )
3329 copy_network_unit ( '25-route-static.network' , '12-dummy.netdev' ,
3330 '25-route-static-test1.network' , '11-dummy.netdev' )
3332 self
. wait_online ( 'dummy98:routable' )
3334 output
= networkctl_status ( 'dummy98' )
3337 print ( '### ip -6 route show dev dummy98' )
3338 output
= check_output ( 'ip -6 route show dev dummy98' )
3340 self
. assertIn ( '2001:1234:5:8fff:ff:ff:ff:ff proto static' , output
)
3341 self
. assertIn ( '2001:1234:5:8f63::1 proto kernel' , output
)
3342 self
. assertIn ( '2001:1234:5:afff:ff:ff:ff:ff via fe80:0:222:4dff:ff:ff:ff:ff proto static' , output
)
3344 print ( '### ip -6 route show default' )
3345 output
= check_output ( 'ip -6 route show default' )
3347 self
. assertIn ( 'default' , output
)
3348 self
. assertIn ( 'via 2001:1234:5:8fff:ff:ff:ff:ff' , output
)
3350 print ( '### ip -4 route show dev dummy98' )
3351 output
= check_output ( 'ip -4 route show dev dummy98' )
3353 self
. assertIn ( '149.10.124.48/28 proto kernel scope link src 149.10.124.58' , output
)
3354 self
. assertIn ( '149.10.124.64 proto static scope link' , output
)
3355 self
. assertIn ( '169.254.0.0/16 proto static scope link metric 2048' , output
)
3356 self
. assertIn ( '192.168.1.1 proto static scope link initcwnd 20' , output
)
3357 self
. assertIn ( '192.168.1.2 proto static scope link initrwnd 30' , output
)
3358 self
. assertIn ( '192.168.1.3 proto static scope link advmss 30' , output
)
3359 self
. assertIn ( '192.168.1.4 proto static scope link hoplimit 122' , output
)
3360 self
. assertIn ( 'multicast 149.10.123.4 proto static' , output
)
3362 print ( '### ip -4 route show dev dummy98 default' )
3363 output
= check_output ( 'ip -4 route show dev dummy98 default' )
3365 self
. assertIn ( 'default via 149.10.125.65 proto static onlink' , output
)
3366 self
. assertIn ( 'default via 149.10.124.64 proto static' , output
)
3367 self
. assertIn ( 'default proto static' , output
)
3368 self
. assertIn ( 'default via 1.1.8.104 proto static' , output
)
3370 print ( '### ip -4 route show table local dev dummy98' )
3371 output
= check_output ( 'ip -4 route show table local dev dummy98' )
3373 self
. assertIn ( 'local 149.10.123.1 proto static scope host' , output
)
3374 self
. assertIn ( 'anycast 149.10.123.2 proto static scope link' , output
)
3375 self
. assertIn ( 'broadcast 149.10.123.3 proto static scope link' , output
)
3377 print ( '### ip -4 route show type blackhole' )
3378 output
= check_output ( 'ip -4 route show type blackhole' )
3380 self
. assertIn ( 'blackhole 202.54.1.2 proto static' , output
)
3382 print ( '### ip -4 route show type unreachable' )
3383 output
= check_output ( 'ip -4 route show type unreachable' )
3385 self
. assertIn ( 'unreachable 202.54.1.3 proto static' , output
)
3387 print ( '### ip -4 route show type prohibit' )
3388 output
= check_output ( 'ip -4 route show type prohibit' )
3390 self
. assertIn ( 'prohibit 202.54.1.4 proto static' , output
)
3392 print ( '### ip -6 route show type blackhole' )
3393 output
= check_output ( 'ip -6 route show type blackhole' )
3395 self
. assertIn ( 'blackhole 2001:1234:5678::2 dev lo proto static' , output
)
3397 print ( '### ip -6 route show type unreachable' )
3398 output
= check_output ( 'ip -6 route show type unreachable' )
3400 self
. assertIn ( 'unreachable 2001:1234:5678::3 dev lo proto static' , output
)
3402 print ( '### ip -6 route show type prohibit' )
3403 output
= check_output ( 'ip -6 route show type prohibit' )
3405 self
. assertIn ( 'prohibit 2001:1234:5678::4 dev lo proto static' , output
)
3407 print ( '### ip route show 192.168.10.1' )
3408 output
= check_output ( 'ip route show 192.168.10.1' )
3410 self
. assertIn ( '192.168.10.1 proto static' , output
)
3411 self
. assertIn ( 'nexthop via 149.10.123.59 dev test1 weight 20' , output
)
3412 self
. assertIn ( 'nexthop via 149.10.123.60 dev test1 weight 30' , output
)
3413 self
. assertIn ( 'nexthop via 149.10.124.59 dev dummy98 weight 10' , output
)
3414 self
. assertIn ( 'nexthop via 149.10.124.60 dev dummy98 weight 5' , output
)
3416 print ( '### ip route show 192.168.10.2' )
3417 output
= check_output ( 'ip route show 192.168.10.2' )
3419 # old ip command does not show IPv6 gateways...
3420 self
. assertIn ( '192.168.10.2 proto static' , output
)
3421 self
. assertIn ( 'nexthop' , output
)
3422 self
. assertIn ( 'dev test1 weight 20' , output
)
3423 self
. assertIn ( 'dev test1 weight 30' , output
)
3424 self
. assertIn ( 'dev dummy98 weight 10' , output
)
3425 self
. assertIn ( 'dev dummy98 weight 5' , output
)
3427 print ( '### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff' )
3428 output
= check_output ( 'ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff' )
3430 # old ip command does not show 'nexthop' keyword and weight...
3431 self
. assertIn ( '2001:1234:5:7fff:ff:ff:ff:ff' , output
)
3432 self
. assertIn ( 'via 2001:1234:5:6fff:ff:ff:ff:ff dev test1' , output
)
3433 self
. assertIn ( 'via 2001:1234:5:7fff:ff:ff:ff:ff dev test1' , output
)
3434 self
. assertIn ( 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98' , output
)
3435 self
. assertIn ( 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98' , output
)
3437 check_json ( networkctl_json ())
3439 copy_network_unit ( '25-address-static.network' , copy_dropins
= False )
3441 self
. wait_online ( 'dummy98:routable' )
3443 # check all routes managed by Manager are removed
3444 print ( '### ip -4 route show type blackhole' )
3445 output
= check_output ( 'ip -4 route show type blackhole' )
3447 self
. assertEqual ( output
, '' )
3449 print ( '### ip -4 route show type unreachable' )
3450 output
= check_output ( 'ip -4 route show type unreachable' )
3452 self
. assertEqual ( output
, '' )
3454 print ( '### ip -4 route show type prohibit' )
3455 output
= check_output ( 'ip -4 route show type prohibit' )
3457 self
. assertEqual ( output
, '' )
3459 print ( '### ip -6 route show type blackhole' )
3460 output
= check_output ( 'ip -6 route show type blackhole' )
3462 self
. assertEqual ( output
, '' )
3464 print ( '### ip -6 route show type unreachable' )
3465 output
= check_output ( 'ip -6 route show type unreachable' )
3467 self
. assertEqual ( output
, '' )
3469 print ( '### ip -6 route show type prohibit' )
3470 output
= check_output ( 'ip -6 route show type prohibit' )
3472 self
. assertEqual ( output
, '' )
3474 remove_network_unit ( '25-address-static.network' )
3476 self
. wait_online ( 'dummy98:routable' )
3478 # check all routes managed by Manager are reconfigured
3479 print ( '### ip -4 route show type blackhole' )
3480 output
= check_output ( 'ip -4 route show type blackhole' )
3482 self
. assertIn ( 'blackhole 202.54.1.2 proto static' , output
)
3484 print ( '### ip -4 route show type unreachable' )
3485 output
= check_output ( 'ip -4 route show type unreachable' )
3487 self
. assertIn ( 'unreachable 202.54.1.3 proto static' , output
)
3489 print ( '### ip -4 route show type prohibit' )
3490 output
= check_output ( 'ip -4 route show type prohibit' )
3492 self
. assertIn ( 'prohibit 202.54.1.4 proto static' , output
)
3494 print ( '### ip -6 route show type blackhole' )
3495 output
= check_output ( 'ip -6 route show type blackhole' )
3497 self
. assertIn ( 'blackhole 2001:1234:5678::2 dev lo proto static' , output
)
3499 print ( '### ip -6 route show type unreachable' )
3500 output
= check_output ( 'ip -6 route show type unreachable' )
3502 self
. assertIn ( 'unreachable 2001:1234:5678::3 dev lo proto static' , output
)
3504 print ( '### ip -6 route show type prohibit' )
3505 output
= check_output ( 'ip -6 route show type prohibit' )
3507 self
. assertIn ( 'prohibit 2001:1234:5678::4 dev lo proto static' , output
)
3509 remove_link ( 'dummy98' )
3512 # check all routes managed by Manager are removed
3513 print ( '### ip -4 route show type blackhole' )
3514 output
= check_output ( 'ip -4 route show type blackhole' )
3516 self
. assertEqual ( output
, '' )
3518 print ( '### ip -4 route show type unreachable' )
3519 output
= check_output ( 'ip -4 route show type unreachable' )
3521 self
. assertEqual ( output
, '' )
3523 print ( '### ip -4 route show type prohibit' )
3524 output
= check_output ( 'ip -4 route show type prohibit' )
3526 self
. assertEqual ( output
, '' )
3528 print ( '### ip -6 route show type blackhole' )
3529 output
= check_output ( 'ip -6 route show type blackhole' )
3531 self
. assertEqual ( output
, '' )
3533 print ( '### ip -6 route show type unreachable' )
3534 output
= check_output ( 'ip -6 route show type unreachable' )
3536 self
. assertEqual ( output
, '' )
3538 print ( '### ip -6 route show type prohibit' )
3539 output
= check_output ( 'ip -6 route show type prohibit' )
3541 self
. assertEqual ( output
, '' )
3543 def test_route_static ( self
):
3545 for manage_foreign_routes
in [ True , False ]:
3551 print ( f
'### test_route_static(manage_foreign_routes= {manage_foreign_routes} )' )
3552 with self
. subTest ( manage_foreign_routes
= manage_foreign_routes
):
3553 self
._ test
_ route
_ static
( manage_foreign_routes
)
3555 @expectedFailureIfRTA_VIAIsNotSupported ()
3556 def test_route_via_ipv6 ( self
):
3557 copy_network_unit ( '25-route-via-ipv6.network' , '12-dummy.netdev' )
3559 self
. wait_online ( 'dummy98:routable' )
3561 output
= networkctl_status ( 'dummy98' )
3564 print ( '### ip -6 route show dev dummy98' )
3565 output
= check_output ( 'ip -6 route show dev dummy98' )
3567 self
. assertRegex ( output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static' )
3568 self
. assertRegex ( output
, '2001:1234:5:8f63::1 proto kernel' )
3570 print ( '### ip -4 route show dev dummy98' )
3571 output
= check_output ( 'ip -4 route show dev dummy98' )
3573 self
. assertRegex ( output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58' )
3574 self
. assertRegex ( output
, '149.10.124.66 via inet6 2001:1234:5:8fff:ff:ff:ff:ff proto static' )
3576 @expectedFailureIfModuleIsNotAvailable ( 'tcp_dctcp' )
3577 def test_route_congctl ( self
):
3578 copy_network_unit ( '25-route-congctl.network' , '12-dummy.netdev' )
3580 self
. wait_online ( 'dummy98:routable' )
3582 print ( '### ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff' )
3583 output
= check_output ( 'ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff' )
3585 self
. assertIn ( '2001:1234:5:8fff:ff:ff:ff:ff proto static' , output
)
3586 self
. assertIn ( 'congctl dctcp' , output
)
3588 print ( '### ip -4 route show dev dummy98 149.10.124.66' )
3589 output
= check_output ( 'ip -4 route show dev dummy98 149.10.124.66' )
3591 self
. assertIn ( '149.10.124.66 proto static' , output
)
3592 self
. assertIn ( 'congctl dctcp' , output
)
3593 self
. assertIn ( 'rto_min 300s' , output
)
3595 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
3596 def test_route_vrf ( self
):
3597 copy_network_unit ( '25-route-vrf.network' , '12-dummy.netdev' ,
3598 '25-vrf.netdev' , '25-vrf.network' )
3600 self
. wait_online ( 'dummy98:routable' , 'vrf99:carrier' )
3602 output
= check_output ( 'ip route show vrf vrf99' )
3604 self
. assertRegex ( output
, 'default via 192.168.100.1' )
3606 output
= check_output ( 'ip route show' )
3608 self
. assertNotRegex ( output
, 'default via 192.168.100.1' )
3610 def test_gateway_reconfigure ( self
):
3611 copy_network_unit ( '25-gateway-static.network' , '12-dummy.netdev' )
3613 self
. wait_online ( 'dummy98:routable' )
3614 print ( '### ip -4 route show dev dummy98 default' )
3615 output
= check_output ( 'ip -4 route show dev dummy98 default' )
3617 self
. assertIn ( 'default via 149.10.124.59 proto static' , output
)
3618 self
. assertNotIn ( '149.10.124.60' , output
)
3620 remove_network_unit ( '25-gateway-static.network' )
3621 copy_network_unit ( '25-gateway-next-static.network' )
3623 self
. wait_online ( 'dummy98:routable' )
3624 print ( '### ip -4 route show dev dummy98 default' )
3625 output
= check_output ( 'ip -4 route show dev dummy98 default' )
3627 self
. assertNotIn ( '149.10.124.59' , output
)
3628 self
. assertIn ( 'default via 149.10.124.60 proto static' , output
)
3630 def test_ip_route_ipv6_src_route ( self
):
3631 # a dummy device does not make the addresses go through tentative state, so we
3632 # reuse a bond from an earlier test, which does make the addresses go through
3633 # tentative state, and do our test on that
3634 copy_network_unit ( '23-active-slave.network' , '25-route-ipv6-src.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
3636 self
. wait_online ( 'dummy98:enslaved' , 'bond199:routable' )
3638 output
= check_output ( 'ip -6 route list dev bond199' )
3640 self
. assertIn ( 'abcd::/16 via 2001:1234:56:8f63::1:1 proto static src 2001:1234:56:8f63::2' , output
)
3642 def test_route_preferred_source_with_existing_address ( self
):
3644 copy_network_unit ( '25-route-preferred-source.network' , '12-dummy.netdev' )
3649 networkctl_reconfigure ( 'dummy98' )
3651 self
. wait_online ( 'dummy98:routable' )
3653 output
= check_output ( 'ip -6 route list dev dummy98' )
3655 self
. assertIn ( 'abcd::/16 via 2001:1234:56:8f63::1:1 proto static src 2001:1234:56:8f63::1' , output
)
3657 def test_ip_link_mac_address ( self
):
3658 copy_network_unit ( '25-address-link-section.network' , '12-dummy.netdev' )
3660 self
. wait_online ( 'dummy98:degraded' )
3662 output
= check_output ( 'ip link show dummy98' )
3664 self
. assertRegex ( output
, '00:01:02:aa:bb:cc' )
3666 def test_ip_link_unmanaged ( self
):
3667 copy_network_unit ( '25-link-section-unmanaged.network' , '12-dummy.netdev' )
3670 self
. wait_operstate ( 'dummy98' , 'off' , setup_state
= 'unmanaged' )
3672 def test_ipv6_address_label ( self
):
3673 copy_network_unit ( '25-ipv6-address-label-section.network' , '12-dummy.netdev' )
3675 self
. wait_online ( 'dummy98:degraded' )
3677 output
= check_output ( 'ip addrlabel list' )
3679 self
. assertRegex ( output
, '2004:da8:1::/64' )
3681 def test_ipv6_proxy_ndp ( self
):
3682 copy_network_unit ( '25-ipv6-proxy-ndp.network' , '12-dummy.netdev' )
3685 self
. wait_online ( 'dummy98:routable' )
3687 output
= check_output ( 'ip neighbor show proxy dev dummy98' )
3689 for i
in range ( 1 , 5 ):
3690 self
. assertRegex ( output
, f
'2607:5300:203:5215: {i} ::1 *proxy' )
3692 def test_ipv6_neigh_retrans_time ( self
):
3694 copy_network_unit ( '25-dummy.netdev' , '25-dummy.network' )
3697 self
. wait_online ( f
' {link} :degraded' )
3698 remove_network_unit ( '25-dummy.network' )
3700 # expect retrans_time_ms updated
3701 copy_network_unit ( '25-ipv6-neigh-retrans-time-3s.network' )
3703 self
. wait_online ( f
' {link} :degraded' )
3704 self
. check_ipv6_neigh_sysctl_attr ( link
, 'retrans_time_ms' , '3000' )
3705 remove_network_unit ( '25-ipv6-neigh-retrans-time-3s.network' )
3707 # expect retrans_time_ms unchanged
3708 copy_network_unit ( '25-ipv6-neigh-retrans-time-0s.network' )
3710 self
. wait_online ( f
' {link} :degraded' )
3711 self
. check_ipv6_neigh_sysctl_attr ( link
, 'retrans_time_ms' , '3000' )
3712 remove_network_unit ( '25-ipv6-neigh-retrans-time-0s.network' )
3714 # expect retrans_time_ms unchanged
3715 copy_network_unit ( '25-ipv6-neigh-retrans-time-toobig.network' )
3717 self
. wait_online ( f
' {link} :degraded' )
3718 self
. check_ipv6_neigh_sysctl_attr ( link
, 'retrans_time_ms' , '3000' )
3719 remove_network_unit ( '25-ipv6-neigh-retrans-time-toobig.network' )
3721 # expect retrans_time_ms unchanged
3722 copy_network_unit ( '25-ipv6-neigh-retrans-time-infinity.network' )
3724 self
. wait_online ( f
' {link} :degraded' )
3725 self
. check_ipv6_neigh_sysctl_attr ( link
, 'retrans_time_ms' , '3000' )
3726 remove_network_unit ( '25-ipv6-neigh-retrans-time-infinity.network' )
3728 # expect retrans_time_ms unchanged
3729 copy_network_unit ( '25-ipv6-neigh-retrans-time-invalid.network' )
3731 self
. wait_online ( f
' {link} :degraded' )
3732 self
. check_ipv6_neigh_sysctl_attr ( link
, 'retrans_time_ms' , '3000' )
3733 remove_network_unit ( '25-ipv6-neigh-retrans-time-invalid.network' )
3735 # expect retrans_time_ms updated
3736 copy_network_unit ( '25-ipv6-neigh-retrans-time-4s.network' )
3738 self
. wait_online ( f
' {link} :degraded' )
3739 self
. check_ipv6_neigh_sysctl_attr ( link
, 'retrans_time_ms' , '4000' )
3740 remove_network_unit ( '25-ipv6-neigh-retrans-time-4s.network' )
3742 def test_neighbor ( self
):
3743 copy_network_unit ( '12-dummy.netdev' , '25-neighbor-dummy.network' , '25-neighbor-dummy.network.d/10-step1.conf' ,
3744 '25-gre-tunnel-remote-any.netdev' , '25-neighbor-ip.network' ,
3745 '25-ip6gre-tunnel-remote-any.netdev' , '25-neighbor-ipv6.network' ,
3748 self
. wait_online ( 'dummy98:degraded' , 'gretun97:routable' , 'ip6gretun97:routable' )
3750 print ( '### ip neigh list dev gretun97' )
3751 output
= check_output ( 'ip neigh list dev gretun97' )
3753 self
. assertIn ( '10.0.0.22 lladdr 10.65.223.239 PERMANENT' , output
)
3754 self
. assertNotIn ( '10.0.0.23' , output
)
3756 print ( '### ip neigh list dev ip6gretun97' )
3757 output
= check_output ( 'ip neigh list dev ip6gretun97' )
3759 self
. assertRegex ( output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT' )
3760 self
. assertNotIn ( '2001:db8:0:f102::18' , output
)
3762 print ( '### ip neigh list dev dummy98' )
3763 output
= check_output ( 'ip neigh list dev dummy98' )
3765 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:02:65 PERMANENT' , output
)
3766 self
. assertIn ( '2004:da8:1::1 lladdr 00:00:5e:00:02:66 PERMANENT' , output
)
3767 self
. assertNotIn ( '2004:da8:1:0::2' , output
)
3768 self
. assertNotIn ( '192.168.10.2' , output
)
3769 self
. assertNotIn ( '00:00:5e:00:02:67' , output
)
3771 check_json ( networkctl_json ())
3773 # Here, 10-step1.conf is intendedly kept, to verify that 10-step2.conf overrides
3774 # the valid configurations in 10-step1.conf.
3775 copy_network_unit ( '25-neighbor-dummy.network.d/10-step2.conf' )
3777 self
. wait_online ( 'dummy98:degraded' )
3779 print ( '### ip neigh list dev dummy98' )
3780 output
= check_output ( 'ip neigh list dev dummy98' )
3782 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:03:65 PERMANENT' , output
)
3783 self
. assertIn ( '2004:da8:1::1 lladdr 00:00:5e:00:03:66 PERMANENT' , output
)
3784 self
. assertNotIn ( '2004:da8:1:0::2' , output
)
3785 self
. assertNotIn ( '192.168.10.2' , output
)
3786 self
. assertNotIn ( '00:00:5e:00:02:67' , output
)
3788 check_json ( networkctl_json ())
3790 remove_network_unit ( '25-neighbor-dummy.network.d/10-step1.conf' ,
3791 '25-neighbor-dummy.network.d/10-step2.conf' )
3792 copy_network_unit ( '25-neighbor-dummy.network.d/10-step3.conf' )
3794 self
. wait_online ( 'dummy98:degraded' )
3796 print ( '### ip neigh list dev dummy98' )
3797 output
= check_output ( 'ip neigh list dev dummy98' )
3799 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:03:66 PERMANENT' , output
)
3800 self
. assertNotIn ( '00:00:5e:00:02:65' , output
)
3801 self
. assertNotIn ( '00:00:5e:00:02:66' , output
)
3802 self
. assertNotIn ( '00:00:5e:00:03:65' , output
)
3803 self
. assertNotIn ( '2004:da8:1::1' , output
)
3805 def test_link_local_addressing ( self
):
3806 copy_network_unit ( '25-link-local-addressing-yes.network' , '11-dummy.netdev' ,
3807 '25-link-local-addressing-no.network' , '12-dummy.netdev' )
3809 self
. wait_online ( 'test1:degraded' , 'dummy98:carrier' )
3811 output
= check_output ( 'ip address show dev test1' )
3813 self
. assertRegex ( output
, 'inet .* scope link' )
3814 self
. assertRegex ( output
, 'inet6 .* scope link' )
3816 output
= check_output ( 'ip address show dev dummy98' )
3818 self
. assertNotRegex ( output
, 'inet6* .* scope link' )
3820 # Documentation/networking/ip-sysctl.txt
3822 # addr_gen_mode - INTEGER
3823 # Defines how link-local and autoconf addresses are generated.
3825 # 0: generate address based on EUI64 (default)
3826 # 1: do no generate a link-local address, use EUI64 for addresses generated
3828 # 2: generate stable privacy addresses, using the secret from
3829 # stable_secret (RFC7217)
3830 # 3: generate stable privacy addresses, using a random secret if unset
3832 self
. check_ipv6_sysctl_attr ( 'test1' , 'stable_secret' , '0123:4567:89ab:cdef:0123:4567:89ab:cdef' )
3833 self
. check_ipv6_sysctl_attr ( 'test1' , 'addr_gen_mode' , '2' )
3834 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'addr_gen_mode' , '1' )
3836 def test_link_local_addressing_ipv6ll ( self
):
3837 copy_network_unit ( '26-link-local-addressing-ipv6.network' , '12-dummy.netdev' )
3839 self
. wait_online ( 'dummy98:degraded' )
3841 # An IPv6LL address exists by default.
3842 output
= check_output ( 'ip address show dev dummy98' )
3844 self
. assertRegex ( output
, 'inet6 .* scope link' )
3846 copy_network_unit ( '25-link-local-addressing-no.network' )
3848 self
. wait_online ( 'dummy98:carrier' )
3850 # Check if the IPv6LL address is removed.
3851 output
= check_output ( 'ip address show dev dummy98' )
3853 self
. assertNotRegex ( output
, 'inet6 .* scope link' )
3855 remove_network_unit ( '25-link-local-addressing-no.network' )
3857 self
. wait_online ( 'dummy98:degraded' )
3859 # Check if a new IPv6LL address is assigned.
3860 output
= check_output ( 'ip address show dev dummy98' )
3862 self
. assertRegex ( output
, 'inet6 .* scope link' )
3864 def test_sysctl ( self
):
3865 copy_networkd_conf_dropin ( '25-global-ipv6-privacy-extensions.conf' )
3866 copy_network_unit ( '25-sysctl.network' , '12-dummy.netdev' , copy_dropins
= False )
3868 self
. wait_online ( 'dummy98:degraded' )
3870 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
3871 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'use_tempaddr' , '1' )
3872 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'dad_transmits' , '3' )
3873 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'hop_limit' , '5' )
3874 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'proxy_ndp' , '1' )
3875 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
3876 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'proxy_arp' , '1' )
3877 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'proxy_arp_pvlan' , '1' )
3878 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'accept_local' , '1' )
3879 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'rp_filter' , '0' )
3881 copy_network_unit ( '25-sysctl.network.d/25-ipv6-privacy-extensions.conf' )
3883 self
. wait_online ( 'dummy98:degraded' )
3885 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'use_tempaddr' , '2' )
3887 def test_sysctl_disable_ipv6 ( self
):
3888 copy_network_unit ( '25-sysctl-disable-ipv6.network' , '12-dummy.netdev' )
3890 print ( '## Disable ipv6' )
3891 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=1' )
3892 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=1' )
3895 self
. wait_online ( 'dummy98:routable' )
3897 output
= check_output ( 'ip -4 address show dummy98' )
3899 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3900 output
= check_output ( 'ip -6 address show dummy98' )
3902 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3903 self
. assertRegex ( output
, 'inet6 .* scope link' )
3904 output
= check_output ( 'ip -4 route show dev dummy98' )
3906 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3907 output
= check_output ( 'ip -6 route show default' )
3909 self
. assertRegex ( output
, 'default' )
3910 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3912 remove_link ( 'dummy98' )
3914 print ( '## Enable ipv6' )
3915 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=0' )
3916 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=0' )
3919 self
. wait_online ( 'dummy98:routable' )
3921 output
= check_output ( 'ip -4 address show dummy98' )
3923 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3924 output
= check_output ( 'ip -6 address show dummy98' )
3926 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3927 self
. assertRegex ( output
, 'inet6 .* scope link' )
3928 output
= check_output ( 'ip -4 route show dev dummy98' )
3930 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3931 output
= check_output ( 'ip -6 route show default' )
3933 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3935 def test_bind_carrier ( self
):
3936 copy_network_unit ( '25-bind-carrier.network' , '11-dummy.netdev' )
3939 # no bound interface.
3940 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
3941 output
= check_output ( 'ip address show test1' )
3943 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3944 self
. assertIn ( 'DOWN' , output
)
3945 self
. assertNotIn ( '192.168.10' , output
)
3947 # add one bound interface. The interface will be up.
3948 check_output ( 'ip link add dummy98 type dummy' )
3949 check_output ( 'ip link set dummy98 up' )
3950 self
. wait_online ( 'test1:routable' )
3951 output
= check_output ( 'ip address show test1' )
3953 self
. assertIn ( 'UP,LOWER_UP' , output
)
3954 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3956 # add another bound interface. The interface is still up.
3957 check_output ( 'ip link add dummy99 type dummy' )
3958 check_output ( 'ip link set dummy99 up' )
3959 self
. wait_operstate ( 'dummy99' , 'degraded' , setup_state
= 'unmanaged' )
3960 output
= check_output ( 'ip address show test1' )
3962 self
. assertIn ( 'UP,LOWER_UP' , output
)
3963 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3965 # remove one of the bound interfaces. The interface is still up
3966 remove_link ( 'dummy98' )
3967 output
= check_output ( 'ip address show test1' )
3969 self
. assertIn ( 'UP,LOWER_UP' , output
)
3970 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3972 # bring down the remaining bound interface. The interface will be down.
3973 check_output ( 'ip link set dummy99 down' )
3974 self
. wait_operstate ( 'test1' , 'off' )
3975 self
. wait_address_dropped ( 'test1' , r
'192.168.10' , ipv
= '-4' , timeout_sec
= 10 )
3976 output
= check_output ( 'ip address show test1' )
3978 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3979 self
. assertIn ( 'DOWN' , output
)
3980 self
. assertNotIn ( '192.168.10' , output
)
3982 # bring up the bound interface. The interface will be up.
3983 check_output ( 'ip link set dummy99 up' )
3984 self
. wait_online ( 'test1:routable' )
3985 output
= check_output ( 'ip address show test1' )
3987 self
. assertIn ( 'UP,LOWER_UP' , output
)
3988 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
3990 # remove the remaining bound interface. The interface will be down.
3991 remove_link ( 'dummy99' )
3992 self
. wait_operstate ( 'test1' , 'off' )
3993 self
. wait_address_dropped ( 'test1' , r
'192.168.10' , ipv
= '-4' , timeout_sec
= 10 )
3994 output
= check_output ( 'ip address show test1' )
3996 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3997 self
. assertIn ( 'DOWN' , output
)
3998 self
. assertNotIn ( '192.168.10' , output
)
4000 # re-add one bound interface. The interface will be up.
4001 check_output ( 'ip link add dummy98 type dummy' )
4002 check_output ( 'ip link set dummy98 up' )
4003 self
. wait_online ( 'test1:routable' )
4004 output
= check_output ( 'ip address show test1' )
4006 self
. assertIn ( 'UP,LOWER_UP' , output
)
4007 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
4009 def _test_activation_policy ( self
, interface
, test
):
4010 conffile
= '25-activation-policy.network'
4012 conffile
= f
' {conffile} .d/ {test} .conf'
4013 if interface
== 'vlan99' :
4014 copy_network_unit ( '21-vlan.netdev' , '21-vlan-test1.network' )
4015 copy_network_unit ( '11-dummy.netdev' , conffile
, copy_dropins
= False )
4018 always
= test
. startswith ( 'always' )
4019 initial_up
= test
!= 'manual' and not test
. endswith ( 'down' ) # note: default is up
4020 expect_up
= initial_up
4021 next_up
= not expect_up
4023 if test
. endswith ( 'down' ):
4024 self
. wait_activated ( interface
)
4026 for iteration
in range ( 4 ):
4027 with self
. subTest ( iteration
= iteration
, expect_up
= expect_up
):
4028 operstate
= 'routable' if expect_up
else 'off'
4029 setup_state
= 'configured' if expect_up
else ( 'configuring' if iteration
== 0 else None )
4030 self
. wait_operstate ( interface
, operstate
, setup_state
= setup_state
, setup_timeout
= 20 )
4033 self
. assertIn ( 'UP' , check_output ( f
'ip link show {interface} ' ))
4034 self
. assertIn ( '192.168.10.30/24' , check_output ( f
'ip address show {interface} ' ))
4035 self
. assertIn ( 'default via 192.168.10.1' , check_output ( f
'ip route show dev {interface} ' ))
4037 self
. assertIn ( 'DOWN' , check_output ( f
'ip link show {interface} ' ))
4040 check_output ( f
'ip link set dev {interface} up' )
4042 check_output ( f
'ip link set dev {interface} down' )
4043 expect_up
= initial_up
if always
else next_up
4044 next_up
= not next_up
4048 def test_activation_policy ( self
):
4050 for interface
in [ 'test1' , 'vlan99' ]:
4051 for test
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , '' ]:
4057 print ( f
'### test_activation_policy(interface= {interface} , test= {test} )' )
4058 with self
. subTest ( interface
= interface
, test
= test
):
4059 self
._ test
_ activation
_ policy
( interface
, test
)
4061 def _test_activation_policy_required_for_online ( self
, policy
, required
):
4062 conffile
= '25-activation-policy.network'
4063 units
= [ '11-dummy.netdev' , '12-dummy.netdev' , '12-dummy.network' , conffile
]
4065 units
+= [ f
' {conffile} .d/ {policy} .conf' ]
4067 units
+= [ f
' {conffile} .d/required- {required} .conf' ]
4068 copy_network_unit (* units
, copy_dropins
= False )
4071 if policy
. endswith ( 'down' ):
4072 self
. wait_activated ( 'test1' )
4074 if policy
. endswith ( 'down' ) or policy
== 'manual' :
4075 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
4077 self
. wait_online ( 'test1' )
4079 if policy
== 'always-down' :
4080 # if always-down, required for online is forced to no
4083 # otherwise if required for online is specified, it should match that
4084 expected
= required
== 'yes'
4086 # otherwise if only policy specified, required for online defaults to
4087 # true if policy is up, always-up, or bound
4088 expected
= policy
. endswith ( 'up' ) or policy
== 'bound'
4090 # default is true, if neither are specified
4093 output
= networkctl_status ( 'test1' )
4096 yesno
= 'yes' if expected
else 'no'
4097 self
. assertRegex ( output
, f
'Required For Online: {yesno} ' )
4099 def test_activation_policy_required_for_online ( self
):
4101 for policy
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , 'bound' , '' ]:
4102 for required
in [ 'yes' , 'no' , '' ]:
4108 print ( f
'### test_activation_policy_required_for_online(policy= {policy} , required= {required} )' )
4109 with self
. subTest ( policy
= policy
, required
= required
):
4110 self
._ test
_ activation
_ policy
_ required
_ for
_ online
( policy
, required
)
4112 def test_domain ( self
):
4113 copy_network_unit ( '12-dummy.netdev' , '24-search-domain.network' )
4115 self
. wait_online ( 'dummy98:routable' )
4117 output
= networkctl_status ( 'dummy98' )
4119 self
. assertRegex ( output
, 'Address: 192.168.42.100' )
4120 self
. assertRegex ( output
, 'DNS: 192.168.42.1' )
4121 self
. assertRegex ( output
, 'Search Domains: one' )
4123 def test_keep_configuration_static ( self
):
4124 check_output ( 'ip link add name dummy98 type dummy' )
4125 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
4126 check_output ( 'ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500' )
4127 output
= check_output ( 'ip address show dummy98' )
4129 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
4130 self
. assertRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
4131 output
= check_output ( 'ip route show dev dummy98' )
4134 copy_network_unit ( '24-keep-configuration-static.network' )
4136 self
. wait_online ( 'dummy98:routable' )
4138 output
= check_output ( 'ip address show dummy98' )
4140 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
4141 self
. assertNotRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
4143 def check_nexthop ( self
, manage_foreign_nexthops
, first
):
4144 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' )
4146 output
= check_output ( 'ip nexthop list dev veth99' )
4149 self
. assertIn ( 'id 1 via 192.168.5.1 dev veth99' , output
)
4150 self
. assertIn ( 'id 2 via 2001:1234:5:8f63::2 dev veth99' , output
)
4152 self
. assertIn ( 'id 6 via 192.168.5.1 dev veth99' , output
)
4153 self
. assertIn ( 'id 7 via 2001:1234:5:8f63::2 dev veth99' , output
)
4154 self
. assertIn ( 'id 3 dev veth99' , output
)
4155 self
. assertIn ( 'id 4 dev veth99' , output
)
4157 self
. assertRegex ( output
, 'id 5 via 192.168.10.1 dev veth99 .*onlink' )
4159 self
. assertIn ( 'id 5 via 192.168.5.3 dev veth99' , output
)
4160 self
. assertNotRegex ( output
, 'id 5 via 192.168.5.3 dev veth99 .*onlink' )
4161 self
. assertIn ( 'id 8 via fe80:0:222:4dff:ff:ff:ff:ff dev veth99' , output
)
4162 if manage_foreign_nexthops
:
4163 self
. assertRegex ( output
, r
'id [0-9]* via 192.168.5.2 dev veth99' )
4165 output
= check_output ( 'ip nexthop list dev dummy98' )
4168 self
. assertIn ( 'id 20 via 192.168.20.1 dev dummy98' , output
)
4170 self
. assertIn ( 'id 21 via 192.168.20.1 dev dummy98' , output
)
4171 if manage_foreign_nexthops
:
4172 self
. assertNotIn ( 'id 42 via 192.168.20.2 dev dummy98' , output
)
4174 self
. assertIn ( 'id 42 via 192.168.20.2 dev dummy98' , output
)
4176 # kernel manages blackhole nexthops on lo
4177 output
= check_output ( 'ip nexthop list dev lo' )
4180 self
. assertIn ( 'id 6 blackhole' , output
)
4181 self
. assertIn ( 'id 7 blackhole' , output
)
4183 self
. assertIn ( 'id 1 blackhole' , output
)
4184 self
. assertIn ( 'id 2 blackhole' , output
)
4186 # group nexthops are shown with -0 option
4188 output
= check_output ( 'ip -0 nexthop list id 21' )
4190 self
. assertRegex ( output
, r
'id 21 group (1,3/20|20/1,3)' )
4192 output
= check_output ( 'ip -0 nexthop list id 20' )
4194 self
. assertRegex ( output
, r
'id 20 group (5,3/21|21/5,3)' )
4196 output
= check_output ( 'ip route show dev veth99 10.10.10.10' )
4199 self
. assertEqual ( '10.10.10.10 nhid 1 via 192.168.5.1 proto static' , output
)
4201 self
. assertEqual ( '10.10.10.10 nhid 6 via 192.168.5.1 proto static' , output
)
4203 output
= check_output ( 'ip route show dev veth99 10.10.10.11' )
4206 self
. assertEqual ( '10.10.10.11 nhid 2 via inet6 2001:1234:5:8f63::2 proto static' , output
)
4208 self
. assertEqual ( '10.10.10.11 nhid 7 via inet6 2001:1234:5:8f63::2 proto static' , output
)
4210 output
= check_output ( 'ip route show dev veth99 10.10.10.12' )
4213 self
. assertEqual ( '10.10.10.12 nhid 5 via 192.168.10.1 proto static onlink' , output
)
4215 self
. assertEqual ( '10.10.10.12 nhid 5 via 192.168.5.3 proto static' , output
)
4217 output
= check_output ( 'ip -6 route show dev veth99 2001:1234:5:8f62::1' )
4220 self
. assertEqual ( '2001:1234:5:8f62::1 nhid 2 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium' , output
)
4222 self
. assertEqual ( '2001:1234:5:8f62::1 nhid 7 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium' , output
)
4224 output
= check_output ( 'ip route show 10.10.10.13' )
4227 self
. assertEqual ( 'blackhole 10.10.10.13 nhid 6 dev lo proto static' , output
)
4229 self
. assertEqual ( 'blackhole 10.10.10.13 nhid 1 dev lo proto static' , output
)
4231 output
= check_output ( 'ip -6 route show 2001:1234:5:8f62::2' )
4234 self
. assertEqual ( 'blackhole 2001:1234:5:8f62::2 nhid 7 dev lo proto static metric 1024 pref medium' , output
)
4236 self
. assertEqual ( 'blackhole 2001:1234:5:8f62::2 nhid 2 dev lo proto static metric 1024 pref medium' , output
)
4238 output
= check_output ( 'ip route show 10.10.10.14' )
4241 self
. assertIn ( '10.10.10.14 nhid 21 proto static' , output
)
4242 self
. assertIn ( 'nexthop via 192.168.5.1 dev veth99 weight 3' , output
)
4244 self
. assertIn ( '10.10.10.14 nhid 20 proto static' , output
)
4245 self
. assertIn ( 'nexthop via 192.168.5.3 dev veth99 weight 3' , output
)
4246 self
. assertIn ( 'nexthop via 192.168.20.1 dev dummy98 weight 1' , output
)
4248 output
= networkctl_json ()
4250 self
. assertNotIn ( '"Destination":[10.10.10.14]' , output
)
4252 def _test_nexthop ( self
, manage_foreign_nexthops
):
4253 if not manage_foreign_nexthops
:
4254 copy_networkd_conf_dropin ( 'networkd-manage-foreign-nexthops-no.conf' )
4256 check_output ( 'ip link add dummy98 type dummy' )
4257 check_output ( 'ip link set dummy98 up' )
4258 check_output ( 'ip address add 192.168.20.20/24 dev dummy98' )
4259 check_output ( 'ip nexthop add id 42 via 192.168.20.2 dev dummy98' )
4261 copy_network_unit ( '25-nexthop-1.network' , '25-veth.netdev' , '25-veth-peer.network' ,
4262 '12-dummy.netdev' , '25-nexthop-dummy-1.network' )
4265 self
. check_nexthop ( manage_foreign_nexthops
, first
= True )
4267 remove_network_unit ( '25-nexthop-1.network' , '25-nexthop-dummy-1.network' )
4268 copy_network_unit ( '25-nexthop-2.network' , '25-nexthop-dummy-2.network' )
4270 self
. check_nexthop ( manage_foreign_nexthops
, first
= False )
4272 remove_network_unit ( '25-nexthop-2.network' )
4273 copy_network_unit ( '25-nexthop-nothing.network' )
4275 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
4277 output
= check_output ( 'ip nexthop list dev veth99' )
4279 self
. assertEqual ( output
, '' )
4280 output
= check_output ( 'ip nexthop list dev lo' )
4282 self
. assertEqual ( output
, '' )
4284 remove_network_unit ( '25-nexthop-nothing.network' , '25-nexthop-dummy-2.network' )
4285 copy_network_unit ( '25-nexthop-1.network' , '25-nexthop-dummy-1.network' )
4286 # Of course, networkctl_reconfigure() below is unnecessary in normal operation, but it is intentional
4287 # here to test reconfiguring with different .network files does not trigger race.
4288 # See also comments in link_drop_requests().
4289 networkctl_reconfigure ( 'dummy98' ) # reconfigured with 25-nexthop-dummy-2.network
4290 networkctl_reload () # reconfigured with 25-nexthop-dummy-1.network
4292 self
. check_nexthop ( manage_foreign_nexthops
, first
= True )
4294 # Remove nexthop with ID 20
4295 check_output ( 'ip nexthop del id 20' )
4296 copy_network_unit ( '11-dummy.netdev' , '25-nexthop-test1.network' )
4299 # 25-nexthop-test1.network requests a route with nexthop ID 21,
4300 # which is silently removed by the kernel when nexthop with ID 20 is removed in the above,
4301 # hence test1 should be stuck in the configuring state.
4302 self
. wait_operstate ( 'test1' , operstate
= 'routable' , setup_state
= 'configuring' )
4304 # Wait for a while, and check if the interface is still in the configuring state.
4306 output
= networkctl_status ( 'test1' )
4307 self
. assertIn ( 'State: routable (configuring)' , output
)
4309 # Check if the route which needs nexthop 20 and 21 are forgotten.
4310 output
= networkctl_json ()
4312 self
. assertNotIn ( '"Destination":[10.10.10.14]' , output
)
4314 # Reconfigure the interface that has nexthop with ID 20 and 21,
4315 # then the route requested by test1 can be configured.
4316 networkctl_reconfigure ( 'dummy98' )
4317 self
. wait_online ( 'test1:routable' )
4319 # Check if the requested route actually configured.
4320 output
= check_output ( 'ip route show 10.10.11.10' )
4322 self
. assertIn ( '10.10.11.10 nhid 21 proto static' , output
)
4323 self
. assertIn ( 'nexthop via 192.168.5.1 dev veth99 weight 3' , output
)
4324 self
. assertIn ( 'nexthop via 192.168.20.1 dev dummy98 weight 1' , output
)
4326 remove_link ( 'veth99' )
4329 output
= check_output ( 'ip nexthop list dev lo' )
4331 self
. assertEqual ( output
, '' )
4333 @expectedFailureIfNexthopIsNotAvailable ()
4334 def test_nexthop ( self
):
4336 for manage_foreign_nexthops
in [ True , False ]:
4342 print ( f
'### test_nexthop(manage_foreign_nexthops= {manage_foreign_nexthops} )' )
4343 with self
. subTest ( manage_foreign_nexthops
= manage_foreign_nexthops
):
4344 self
._ test
_ nexthop
( manage_foreign_nexthops
)
4346 class NetworkdTCTests ( unittest
. TestCase
, Utilities
):
4354 @expectedFailureIfModuleIsNotAvailable ( 'sch_cake' )
4355 def test_qdisc_cake ( self
):
4356 copy_network_unit ( '25-qdisc-cake.network' , '12-dummy.netdev' )
4358 self
. wait_online ( 'dummy98:routable' )
4360 output
= check_output ( 'tc qdisc show dev dummy98' )
4362 self
. assertIn ( 'qdisc cake 3a: root' , output
)
4363 self
. assertIn ( 'bandwidth 500Mbit' , output
)
4364 self
. assertIn ( 'autorate-ingress' , output
)
4365 self
. assertIn ( 'diffserv8' , output
)
4366 self
. assertIn ( 'dual-dsthost' , output
)
4367 self
. assertIn ( ' nat' , output
)
4368 self
. assertIn ( ' wash' , output
)
4369 self
. assertIn ( ' split-gso' , output
)
4370 self
. assertIn ( ' raw' , output
)
4371 self
. assertIn ( ' atm' , output
)
4372 self
. assertIn ( 'overhead 128' , output
)
4373 self
. assertIn ( 'mpu 20' , output
)
4374 self
. assertIn ( 'fwmark 0xff00' , output
)
4375 self
. assertIn ( 'rtt 1s' , output
)
4376 self
. assertIn ( 'ack-filter-aggressive' , output
)
4378 @expectedFailureIfModuleIsNotAvailable ( 'sch_codel' )
4379 def test_qdisc_codel ( self
):
4380 copy_network_unit ( '25-qdisc-codel.network' , '12-dummy.netdev' )
4382 self
. wait_online ( 'dummy98:routable' )
4384 output
= check_output ( 'tc qdisc show dev dummy98' )
4386 self
. assertRegex ( output
, 'qdisc codel 33: root' )
4387 self
. assertRegex ( output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn' )
4389 @expectedFailureIfModuleIsNotAvailable ( 'sch_drr' )
4390 def test_qdisc_drr ( self
):
4391 copy_network_unit ( '25-qdisc-drr.network' , '12-dummy.netdev' )
4393 self
. wait_online ( 'dummy98:routable' )
4395 output
= check_output ( 'tc qdisc show dev dummy98' )
4397 self
. assertRegex ( output
, 'qdisc drr 2: root' )
4398 output
= check_output ( 'tc class show dev dummy98' )
4400 self
. assertRegex ( output
, 'class drr 2:30 root quantum 2000b' )
4402 @expectedFailureIfModuleIsNotAvailable ( 'sch_ets' )
4403 def test_qdisc_ets ( self
):
4404 copy_network_unit ( '25-qdisc-ets.network' , '12-dummy.netdev' )
4406 self
. wait_online ( 'dummy98:routable' )
4408 output
= check_output ( 'tc qdisc show dev dummy98' )
4411 self
. assertRegex ( output
, 'qdisc ets 3a: root' )
4412 self
. assertRegex ( output
, 'bands 10 strict 3' )
4413 self
. assertRegex ( output
, 'quanta 1 2 3 4 5' )
4414 self
. assertRegex ( output
, 'priomap 3 4 5 6 7' )
4416 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq' )
4417 def test_qdisc_fq ( self
):
4418 copy_network_unit ( '25-qdisc-fq.network' , '12-dummy.netdev' )
4420 self
. wait_online ( 'dummy98:routable' )
4422 output
= check_output ( 'tc qdisc show dev dummy98' )
4424 self
. assertRegex ( output
, 'qdisc fq 32: root' )
4425 self
. assertRegex ( output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511' )
4426 self
. assertRegex ( output
, 'quantum 1500' )
4427 self
. assertRegex ( output
, 'initial_quantum 13000' )
4428 self
. assertRegex ( output
, 'maxrate 1Mbit' )
4430 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_codel' )
4431 def test_qdisc_fq_codel ( self
):
4432 copy_network_unit ( '25-qdisc-fq_codel.network' , '12-dummy.netdev' )
4434 self
. wait_online ( 'dummy98:routable' )
4436 output
= check_output ( 'tc qdisc show dev dummy98' )
4438 self
. assertRegex ( output
, 'qdisc fq_codel 34: root' )
4439 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' )
4441 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_pie' )
4442 def test_qdisc_fq_pie ( self
):
4443 copy_network_unit ( '25-qdisc-fq_pie.network' , '12-dummy.netdev' )
4445 self
. wait_online ( 'dummy98:routable' )
4447 output
= check_output ( 'tc qdisc show dev dummy98' )
4450 self
. assertRegex ( output
, 'qdisc fq_pie 3a: root' )
4451 self
. assertRegex ( output
, 'limit 200000p' )
4453 @expectedFailureIfModuleIsNotAvailable ( 'sch_gred' )
4454 def test_qdisc_gred ( self
):
4455 copy_network_unit ( '25-qdisc-gred.network' , '12-dummy.netdev' )
4457 self
. wait_online ( 'dummy98:routable' )
4459 output
= check_output ( 'tc qdisc show dev dummy98' )
4461 self
. assertRegex ( output
, 'qdisc gred 38: root' )
4462 self
. assertRegex ( output
, 'vqs 12 default 10 grio' )
4464 @expectedFailureIfModuleIsNotAvailable ( 'sch_hhf' )
4465 def test_qdisc_hhf ( self
):
4466 copy_network_unit ( '25-qdisc-hhf.network' , '12-dummy.netdev' )
4468 self
. wait_online ( 'dummy98:routable' )
4470 output
= check_output ( 'tc qdisc show dev dummy98' )
4472 self
. assertRegex ( output
, 'qdisc hhf 3a: root' )
4473 self
. assertRegex ( output
, 'limit 1022p' )
4475 @expectedFailureIfModuleIsNotAvailable ( 'sch_htb' )
4476 def test_qdisc_htb_fifo ( self
):
4477 copy_network_unit ( '25-qdisc-htb-fifo.network' , '12-dummy.netdev' )
4479 self
. wait_online ( 'dummy98:routable' )
4481 output
= check_output ( 'tc qdisc show dev dummy98' )
4483 self
. assertRegex ( output
, 'qdisc htb 2: root' )
4484 self
. assertRegex ( output
, r
'default (0x30|30)' )
4486 self
. assertRegex ( output
, 'qdisc pfifo 37: parent 2:37' )
4487 self
. assertRegex ( output
, 'limit 100000p' )
4489 self
. assertRegex ( output
, 'qdisc bfifo 3a: parent 2:3a' )
4490 self
. assertRegex ( output
, 'limit 1000000' )
4492 self
. assertRegex ( output
, 'qdisc pfifo_head_drop 3b: parent 2:3b' )
4493 self
. assertRegex ( output
, 'limit 1023p' )
4495 self
. assertRegex ( output
, 'qdisc pfifo_fast 3c: parent 2:3c' )
4497 output
= check_output ( 'tc -d class show dev dummy98' )
4499 # Here (:|prio) is a workaround for a bug in iproute2 v6.2.0 caused by
4500 # https://github.com/shemminger/iproute2/commit/010a8388aea11e767ba3a2506728b9ad9760df0e
4501 # which is fixed in v6.3.0 by
4502 # https://github.com/shemminger/iproute2/commit/4e0e56e0ef05387f7f5d8ab41fe6ec6a1897b26d
4503 self
. assertRegex ( output
, 'class htb 2:37 root leaf 37(:|prio) ' )
4504 self
. assertRegex ( output
, 'class htb 2:3a root leaf 3a(:|prio) ' )
4505 self
. assertRegex ( output
, 'class htb 2:3b root leaf 3b(:|prio) ' )
4506 self
. assertRegex ( output
, 'class htb 2:3c root leaf 3c(:|prio) ' )
4507 self
. assertRegex ( output
, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit' )
4508 self
. assertRegex ( output
, 'burst 123456' )
4509 self
. assertRegex ( output
, 'cburst 123457' )
4511 @expectedFailureIfModuleIsNotAvailable ( 'sch_ingress' )
4512 def test_qdisc_ingress ( self
):
4513 copy_network_unit ( '25-qdisc-clsact.network' , '12-dummy.netdev' ,
4514 '25-qdisc-ingress.network' , '11-dummy.netdev' )
4516 self
. wait_online ( 'dummy98:routable' , 'test1:routable' )
4518 output
= check_output ( 'tc qdisc show dev dummy98' )
4520 self
. assertRegex ( output
, 'qdisc clsact' )
4522 output
= check_output ( 'tc qdisc show dev test1' )
4524 self
. assertRegex ( output
, 'qdisc ingress' )
4526 @expectedFailureIfModuleIsNotAvailable ( 'sch_netem' )
4527 def test_qdisc_netem ( self
):
4528 copy_network_unit ( '25-qdisc-netem.network' , '12-dummy.netdev' ,
4529 '25-qdisc-netem-compat.network' , '11-dummy.netdev' )
4531 self
. wait_online ( 'dummy98:routable' , 'test1:routable' )
4533 output
= check_output ( 'tc qdisc show dev dummy98' )
4535 self
. assertRegex ( output
, 'qdisc netem 30: root' )
4536 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
4538 output
= check_output ( 'tc qdisc show dev test1' )
4540 self
. assertRegex ( output
, 'qdisc netem [0-9a-f]*: root' )
4541 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
4543 @expectedFailureIfModuleIsNotAvailable ( 'sch_pie' )
4544 def test_qdisc_pie ( self
):
4545 copy_network_unit ( '25-qdisc-pie.network' , '12-dummy.netdev' )
4547 self
. wait_online ( 'dummy98:routable' )
4549 output
= check_output ( 'tc qdisc show dev dummy98' )
4551 self
. assertRegex ( output
, 'qdisc pie 3a: root' )
4552 self
. assertRegex ( output
, 'limit 200000' )
4554 @expectedFailureIfModuleIsNotAvailable ( 'sch_qfq' )
4555 def test_qdisc_qfq ( self
):
4556 copy_network_unit ( '25-qdisc-qfq.network' , '12-dummy.netdev' )
4558 self
. wait_online ( 'dummy98:routable' )
4560 output
= check_output ( 'tc qdisc show dev dummy98' )
4562 self
. assertRegex ( output
, 'qdisc qfq 2: root' )
4563 output
= check_output ( 'tc class show dev dummy98' )
4565 self
. assertRegex ( output
, 'class qfq 2:30 root weight 2 maxpkt 16000' )
4566 self
. assertRegex ( output
, 'class qfq 2:31 root weight 10 maxpkt 8000' )
4568 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfb' )
4569 def test_qdisc_sfb ( self
):
4570 copy_network_unit ( '25-qdisc-sfb.network' , '12-dummy.netdev' )
4572 self
. wait_online ( 'dummy98:routable' )
4574 output
= check_output ( 'tc qdisc show dev dummy98' )
4576 self
. assertRegex ( output
, 'qdisc sfb 39: root' )
4577 self
. assertRegex ( output
, 'limit 200000' )
4579 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfq' )
4580 def test_qdisc_sfq ( self
):
4581 copy_network_unit ( '25-qdisc-sfq.network' , '12-dummy.netdev' )
4583 self
. wait_online ( 'dummy98:routable' )
4585 output
= check_output ( 'tc qdisc show dev dummy98' )
4587 self
. assertRegex ( output
, 'qdisc sfq 36: root' )
4588 self
. assertRegex ( output
, 'perturb 5sec' )
4590 @expectedFailureIfModuleIsNotAvailable ( 'sch_tbf' )
4591 def test_qdisc_tbf ( self
):
4592 copy_network_unit ( '25-qdisc-tbf.network' , '12-dummy.netdev' )
4594 self
. wait_online ( 'dummy98:routable' )
4596 output
= check_output ( 'tc qdisc show dev dummy98' )
4598 self
. assertRegex ( output
, 'qdisc tbf 35: root' )
4599 self
. assertRegex ( output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms' )
4601 @expectedFailureIfModuleIsNotAvailable ( 'sch_teql' )
4602 def test_qdisc_teql ( self
):
4603 call_quiet ( 'rmmod sch_teql' )
4605 copy_network_unit ( '25-qdisc-teql.network' , '12-dummy.netdev' )
4607 self
. wait_links ( 'dummy98' )
4608 check_output ( 'modprobe sch_teql max_equalizers=2' )
4609 self
. wait_online ( 'dummy98:routable' )
4611 output
= check_output ( 'tc qdisc show dev dummy98' )
4613 self
. assertRegex ( output
, 'qdisc teql1 31: root' )
4615 class NetworkdStateFileTests ( unittest
. TestCase
, Utilities
):
4623 def test_state_file ( self
):
4624 copy_network_unit ( '12-dummy.netdev' , '25-state-file-tests.network' )
4626 self
. wait_online ( 'dummy98:routable' )
4628 # make link state file updated
4629 resolvectl ( 'revert' , 'dummy98' )
4631 check_json ( networkctl_json ())
4633 output
= read_link_state_file ( 'dummy98' )
4635 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
4636 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
4637 self
. assertIn ( 'ADMIN_STATE=configured' , output
)
4638 self
. assertIn ( 'OPER_STATE=routable' , output
)
4639 self
. assertIn ( 'REQUIRED_FOR_ONLINE=yes' , output
)
4640 self
. assertIn ( 'REQUIRED_OPER_STATE_FOR_ONLINE=routable' , output
)
4641 self
. assertIn ( 'REQUIRED_FAMILY_FOR_ONLINE=both' , output
)
4642 self
. assertIn ( 'ACTIVATION_POLICY=up' , output
)
4643 self
. assertIn ( 'NETWORK_FILE=/run/systemd/network/25-state-file-tests.network' , output
)
4644 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
4645 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
4646 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
4647 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
4648 self
. assertIn ( 'LLMNR=no' , output
)
4649 self
. assertIn ( 'MDNS=yes' , output
)
4650 self
. assertIn ( 'DNSSEC=no' , output
)
4652 resolvectl ( 'dns' , 'dummy98' , '10.10.10.12#ccc.com' , '10.10.10.13' , '1111:2222::3333' )
4653 resolvectl ( 'domain' , 'dummy98' , 'hogehogehoge' , '~foofoofoo' )
4654 resolvectl ( 'llmnr' , 'dummy98' , 'yes' )
4655 resolvectl ( 'mdns' , 'dummy98' , 'no' )
4656 resolvectl ( 'dnssec' , 'dummy98' , 'yes' )
4657 timedatectl ( 'ntp-servers' , 'dummy98' , '2.fedora.pool.ntp.org' , '3.fedora.pool.ntp.org' )
4659 check_json ( networkctl_json ())
4661 output
= read_link_state_file ( 'dummy98' )
4663 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
4664 self
. assertIn ( 'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org' , output
)
4665 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
4666 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
4667 self
. assertIn ( 'LLMNR=yes' , output
)
4668 self
. assertIn ( 'MDNS=no' , output
)
4669 self
. assertIn ( 'DNSSEC=yes' , output
)
4671 timedatectl ( 'revert' , 'dummy98' )
4673 check_json ( networkctl_json ())
4675 output
= read_link_state_file ( 'dummy98' )
4677 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
4678 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
4679 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
4680 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
4681 self
. assertIn ( 'LLMNR=yes' , output
)
4682 self
. assertIn ( 'MDNS=no' , output
)
4683 self
. assertIn ( 'DNSSEC=yes' , output
)
4685 resolvectl ( 'revert' , 'dummy98' )
4687 check_json ( networkctl_json ())
4689 output
= read_link_state_file ( 'dummy98' )
4691 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
4692 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
4693 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
4694 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
4695 self
. assertIn ( 'LLMNR=no' , output
)
4696 self
. assertIn ( 'MDNS=yes' , output
)
4697 self
. assertIn ( 'DNSSEC=no' , output
)
4699 def test_address_state ( self
):
4700 copy_network_unit ( '12-dummy.netdev' , '12-dummy-no-address.network' )
4703 self
. wait_online ( 'dummy98:degraded' )
4705 output
= read_link_state_file ( 'dummy98' )
4706 self
. assertIn ( 'IPV4_ADDRESS_STATE=off' , output
)
4707 self
. assertIn ( 'IPV6_ADDRESS_STATE=degraded' , output
)
4709 # with a routable IPv4 address
4710 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
4711 self
. wait_online ( 'dummy98:routable' , ipv4
= True )
4712 self
. wait_online ( 'dummy98:routable' )
4714 output
= read_link_state_file ( 'dummy98' )
4715 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
4716 self
. assertIn ( 'IPV6_ADDRESS_STATE=degraded' , output
)
4718 check_output ( 'ip address del 10.1.2.3/16 dev dummy98' )
4720 # with a routable IPv6 address
4721 check_output ( 'ip address add 2002:da8:1:0:1034:56ff:fe78:9abc/64 dev dummy98' )
4722 self
. wait_online ( 'dummy98:routable' , ipv6
= True )
4723 self
. wait_online ( 'dummy98:routable' )
4725 output
= read_link_state_file ( 'dummy98' )
4726 self
. assertIn ( 'IPV4_ADDRESS_STATE=off' , output
)
4727 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
4729 class NetworkdBondTests ( unittest
. TestCase
, Utilities
):
4737 def test_bond_keep_master ( self
):
4738 check_output ( 'ip link add bond199 type bond mode active-backup' )
4739 check_output ( 'ip link add dummy98 type dummy' )
4740 check_output ( 'ip link set dummy98 master bond199' )
4742 copy_network_unit ( '23-keep-master.network' )
4744 self
. wait_online ( 'dummy98:enslaved' )
4746 output
= check_output ( 'ip -d link show bond199' )
4748 self
. assertRegex ( output
, 'active_slave dummy98' )
4750 output
= check_output ( 'ip -d link show dummy98' )
4752 self
. assertRegex ( output
, 'master bond199' )
4754 def test_bond_active_slave ( self
):
4755 copy_network_unit ( '23-active-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
4757 self
. wait_online ( 'dummy98:enslaved' , 'bond199:degraded' )
4759 output
= check_output ( 'ip -d link show bond199' )
4761 self
. assertIn ( 'active_slave dummy98' , output
)
4763 # test case for issue #31165.
4764 since
= datetime
. datetime
. now ()
4765 networkctl_reconfigure ( 'dummy98' )
4766 self
. wait_online ( 'dummy98:enslaved' , 'bond199:degraded' )
4767 self
. assertNotIn ( 'dummy98: Bringing link down' , read_networkd_log ( since
= since
))
4769 def test_bond_primary_slave ( self
):
4770 copy_network_unit ( '23-primary-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
4772 self
. wait_online ( 'dummy98:enslaved' , 'bond199:degraded' )
4774 output
= check_output ( 'ip -d link show bond199' )
4776 self
. assertIn ( 'primary dummy98' , output
)
4779 mkdir_p ( os
. path
. join ( network_unit_dir
, '23-bond199.network.d' ))
4780 for mac
in [ '00:11:22:33:44:55' , '00:11:22:33:44:56' ]:
4781 with
open ( os
. path
. join ( network_unit_dir
, '23-bond199.network.d/mac.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
4782 f
. write ( f
'[Link] \n MACAddress= {mac} \n ' )
4785 self
. wait_online ( 'dummy98:enslaved' , 'bond199:degraded' )
4787 output
= check_output ( 'ip -d link show bond199' )
4789 self
. assertIn ( f
'link/ether {mac} ' , output
)
4791 def test_bond_operstate ( self
):
4792 copy_network_unit ( '25-bond.netdev' , '11-dummy.netdev' , '12-dummy.netdev' ,
4793 '25-bond99.network' , '25-bond-slave.network' )
4795 self
. wait_online ( 'dummy98:enslaved' , 'test1:enslaved' , 'bond99:routable' )
4797 output
= check_output ( 'ip -d link show dummy98' )
4799 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
4801 output
= check_output ( 'ip -d link show test1' )
4803 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
4805 output
= check_output ( 'ip -d link show bond99' )
4807 self
. assertRegex ( output
, 'MASTER,UP,LOWER_UP' )
4809 self
. wait_operstate ( 'dummy98' , 'enslaved' )
4810 self
. wait_operstate ( 'test1' , 'enslaved' )
4811 self
. wait_operstate ( 'bond99' , 'routable' )
4813 check_output ( 'ip link set dummy98 down' )
4815 self
. wait_operstate ( 'dummy98' , 'off' )
4816 self
. wait_operstate ( 'test1' , 'enslaved' )
4817 self
. wait_operstate ( 'bond99' , 'routable' )
4819 check_output ( 'ip link set dummy98 up' )
4821 self
. wait_operstate ( 'dummy98' , 'enslaved' )
4822 self
. wait_operstate ( 'test1' , 'enslaved' )
4823 self
. wait_operstate ( 'bond99' , 'routable' )
4825 check_output ( 'ip link set dummy98 down' )
4826 check_output ( 'ip link set test1 down' )
4828 self
. wait_operstate ( 'dummy98' , 'off' )
4829 self
. wait_operstate ( 'test1' , 'off' )
4831 if not self
. wait_operstate ( 'bond99' , 'no-carrier' , setup_timeout
= 30 , fail_assert
= False ):
4832 # Huh? Kernel does not recognize that all slave interfaces are down?
4833 # Let's confirm that networkd's operstate is consistent with ip's result.
4834 self
. assertNotRegex ( output
, 'NO-CARRIER' )
4836 class NetworkdBridgeTests ( unittest
. TestCase
, Utilities
):
4844 def test_bridge_mac_none ( self
):
4845 copy_network_unit ( '12-dummy-mac.netdev' , '26-bridge-mac-slave.network' ,
4846 '26-bridge-mac.netdev' , '26-bridge-mac-master.network' , '26-bridge-mac.link' )
4848 self
. wait_online ( 'dummy98:enslaved' , 'bridge99:degraded' )
4850 output
= check_output ( 'ip link show dev dummy98' )
4852 self
. assertIn ( 'link/ether 12:34:56:78:9a:01' , output
)
4854 output
= check_output ( 'ip link show dev bridge99' )
4856 self
. assertIn ( 'link/ether 12:34:56:78:9a:01' , output
)
4858 def test_bridge_vlan ( self
):
4859 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave.network' ,
4860 '26-bridge.netdev' , '26-bridge-vlan-master.network' ,
4863 self
. wait_online ( 'test1:enslaved' , 'bridge99:degraded' )
4865 output
= check_output ( 'bridge vlan show dev test1' )
4867 # check if the default VID is removed
4868 self
. assertNotIn ( '1 Egress Untagged' , output
)
4869 for i
in range ( 1000 , 3000 ):
4871 self
. assertIn ( f
' {i} PVID' , output
)
4872 elif i
in range ( 1012 , 1016 ) or i
in range ( 1103 , 1109 ):
4873 self
. assertIn ( f
' {i} Egress Untagged' , output
)
4874 elif i
in range ( 1008 , 1014 ) or i
in range ( 1100 , 1111 ):
4875 self
. assertIn ( f
' {i} ' , output
)
4877 self
. assertNotIn ( f
' {i} ' , output
)
4879 output
= check_output ( 'bridge vlan show dev bridge99' )
4881 # check if the default VID is removed
4882 self
. assertNotIn ( '1 Egress Untagged' , output
)
4883 for i
in range ( 1000 , 3000 ):
4885 self
. assertIn ( f
' {i} PVID' , output
)
4886 elif i
in range ( 1022 , 1026 ) or i
in range ( 1203 , 1209 ):
4887 self
. assertIn ( f
' {i} Egress Untagged' , output
)
4888 elif i
in range ( 1018 , 1024 ) or i
in range ( 1200 , 1211 ):
4889 self
. assertIn ( f
' {i} ' , output
)
4891 self
. assertNotIn ( f
' {i} ' , output
)
4894 copy_network_unit ( '26-bridge-vlan-slave.network.d/10-override.conf' ,
4895 '26-bridge-vlan-master.network.d/10-override.conf' )
4897 self
. wait_online ( 'test1:enslaved' , 'bridge99:degraded' )
4899 output
= check_output ( 'bridge vlan show dev test1' )
4901 for i
in range ( 1000 , 3000 ):
4903 self
. assertIn ( f
' {i} PVID' , output
)
4904 elif i
in range ( 2012 , 2016 ) or i
in range ( 2103 , 2109 ):
4905 self
. assertIn ( f
' {i} Egress Untagged' , output
)
4906 elif i
in range ( 2008 , 2014 ) or i
in range ( 2100 , 2111 ):
4907 self
. assertIn ( f
' {i} ' , output
)
4909 self
. assertNotIn ( f
' {i} ' , output
)
4911 output
= check_output ( 'bridge vlan show dev bridge99' )
4913 for i
in range ( 1000 , 3000 ):
4915 self
. assertIn ( f
' {i} PVID' , output
)
4916 elif i
in range ( 2022 , 2026 ) or i
in range ( 2203 , 2209 ):
4917 self
. assertIn ( f
' {i} Egress Untagged' , output
)
4918 elif i
in range ( 2018 , 2024 ) or i
in range ( 2200 , 2211 ):
4919 self
. assertIn ( f
' {i} ' , output
)
4921 self
. assertNotIn ( f
' {i} ' , output
)
4923 # Remove several vlan IDs
4924 copy_network_unit ( '26-bridge-vlan-slave.network.d/20-override.conf' ,
4925 '26-bridge-vlan-master.network.d/20-override.conf' )
4927 self
. wait_online ( 'test1:enslaved' , 'bridge99:degraded' )
4929 output
= check_output ( 'bridge vlan show dev test1' )
4931 for i
in range ( 1000 , 3000 ):
4933 self
. assertIn ( f
' {i} PVID' , output
)
4934 elif i
in range ( 2012 , 2016 ):
4935 self
. assertIn ( f
' {i} Egress Untagged' , output
)
4936 elif i
in range ( 2008 , 2014 ):
4937 self
. assertIn ( f
' {i} ' , output
)
4939 self
. assertNotIn ( f
' {i} ' , output
)
4941 output
= check_output ( 'bridge vlan show dev bridge99' )
4943 for i
in range ( 1000 , 3000 ):
4945 self
. assertIn ( f
' {i} PVID' , output
)
4946 elif i
in range ( 2022 , 2026 ):
4947 self
. assertIn ( f
' {i} Egress Untagged' , output
)
4948 elif i
in range ( 2018 , 2024 ):
4949 self
. assertIn ( f
' {i} ' , output
)
4951 self
. assertNotIn ( f
' {i} ' , output
)
4953 # Remove all vlan IDs
4954 copy_network_unit ( '26-bridge-vlan-slave.network.d/30-override.conf' ,
4955 '26-bridge-vlan-master.network.d/30-override.conf' )
4957 self
. wait_online ( 'test1:enslaved' , 'bridge99:degraded' )
4959 output
= check_output ( 'bridge vlan show dev test1' )
4961 self
. assertNotIn ( 'PVID' , output
)
4962 for i
in range ( 1000 , 3000 ):
4963 self
. assertNotIn ( f
' {i} ' , output
)
4965 output
= check_output ( 'bridge vlan show dev bridge99' )
4967 self
. assertNotIn ( 'PVID' , output
)
4968 for i
in range ( 1000 , 3000 ):
4969 self
. assertNotIn ( f
' {i} ' , output
)
4971 def test_bridge_vlan_issue_20373 ( self
):
4972 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave-issue-20373.network' ,
4973 '26-bridge-issue-20373.netdev' , '26-bridge-vlan-master-issue-20373.network' ,
4974 '21-vlan.netdev' , '21-vlan.network' )
4976 self
. wait_online ( 'test1:enslaved' , 'bridge99:degraded' , 'vlan99:routable' )
4978 output
= check_output ( 'bridge vlan show dev test1' )
4980 self
. assertIn ( '100 PVID Egress Untagged' , output
)
4981 self
. assertIn ( '560' , output
)
4982 self
. assertIn ( '600' , output
)
4984 output
= check_output ( 'bridge vlan show dev bridge99' )
4986 self
. assertIn ( '1 PVID Egress Untagged' , output
)
4987 self
. assertIn ( '100' , output
)
4988 self
. assertIn ( '600' , output
)
4990 def test_bridge_mdb ( self
):
4991 copy_network_unit ( '11-dummy.netdev' , '26-bridge-mdb-slave.network' ,
4992 '26-bridge.netdev' , '26-bridge-mdb-master.network' )
4994 self
. wait_online ( 'test1:enslaved' , 'bridge99:degraded' )
4996 output
= check_output ( 'bridge mdb show dev bridge99' )
4998 self
. assertRegex ( output
, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064' )
4999 self
. assertRegex ( output
, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065' )
5001 # Old kernel may not support bridge MDB entries on bridge master
5002 if call_quiet ( 'bridge mdb add dev bridge99 port bridge99 grp 224.0.1.3 temp vid 4068' ) == 0 :
5003 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp ff02:aaaa:fee5::1:4 temp *vid 4066' )
5004 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp 224.0.1.2 temp *vid 4067' )
5006 def test_bridge_keep_master ( self
):
5007 check_output ( 'ip link add bridge99 type bridge' )
5008 check_output ( 'ip link set bridge99 up' )
5009 check_output ( 'ip link add dummy98 type dummy' )
5010 check_output ( 'ip link set dummy98 master bridge99' )
5012 copy_network_unit ( '23-keep-master.network' )
5014 self
. wait_online ( 'dummy98:enslaved' )
5016 output
= check_output ( 'ip -d link show dummy98' )
5018 self
. assertRegex ( output
, 'master bridge99' )
5019 self
. assertRegex ( output
, 'bridge' )
5021 output
= check_output ( 'bridge -d link show dummy98' )
5023 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
5024 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
5025 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
5026 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
5027 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
5028 # CONFIG_BRIDGE_IGMP_SNOOPING=y
5029 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
5030 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
5031 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
5032 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
5033 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
5034 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
5036 def test_bridge_property ( self
):
5037 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
5038 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
5039 '25-bridge99.network' )
5041 self
. wait_online ( 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' )
5043 output
= check_output ( 'ip -d link show bridge99' )
5045 self
. assertIn ( 'mtu 9000 ' , output
)
5047 output
= check_output ( 'ip -d link show test1' )
5049 self
. assertIn ( 'master bridge99 ' , output
)
5050 self
. assertIn ( 'bridge_slave' , output
)
5051 self
. assertIn ( 'mtu 9000 ' , output
)
5053 output
= check_output ( 'ip -d link show dummy98' )
5055 self
. assertIn ( 'master bridge99 ' , output
)
5056 self
. assertIn ( 'bridge_slave' , output
)
5057 self
. assertIn ( 'mtu 9000 ' , output
)
5059 output
= check_output ( 'ip addr show bridge99' )
5061 self
. assertIn ( '192.168.0.15/24' , output
)
5063 output
= check_output ( 'bridge -d link show dummy98' )
5065 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
5066 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
5067 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'isolated' , '1' )
5068 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
5069 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
5070 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
5071 # CONFIG_BRIDGE_IGMP_SNOOPING=y
5072 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
5073 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
5074 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
5075 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
5076 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
5077 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
5079 output
= check_output ( 'bridge -d link show test1' )
5081 self
. check_bridge_port_attr ( 'bridge99' , 'test1' , 'priority' , '0' )
5083 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
5084 output
= check_output ( 'ip addr show bridge99' )
5086 self
. assertIn ( '192.168.0.16/24' , output
)
5089 print ( '### ip -6 route list table all dev bridge99' )
5090 output
= check_output ( 'ip -6 route list table all dev bridge99' )
5092 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
5094 remove_link ( 'test1' )
5095 self
. wait_operstate ( 'bridge99' , 'routable' )
5097 output
= check_output ( 'ip -d link show bridge99' )
5099 self
. assertIn ( 'mtu 9000 ' , output
)
5101 output
= check_output ( 'ip -d link show dummy98' )
5103 self
. assertIn ( 'master bridge99 ' , output
)
5104 self
. assertIn ( 'bridge_slave' , output
)
5105 self
. assertIn ( 'mtu 9000 ' , output
)
5107 remove_link ( 'dummy98' )
5108 self
. wait_operstate ( 'bridge99' , 'no-carrier' )
5110 output
= check_output ( 'ip -d link show bridge99' )
5112 # When no carrier, the kernel may reset the MTU
5113 self
. assertIn ( 'NO-CARRIER' , output
)
5115 output
= check_output ( 'ip address show bridge99' )
5117 self
. assertNotIn ( '192.168.0.15/24' , output
)
5118 self
. assertIn ( '192.168.0.16/24' , output
) # foreign address is kept
5120 print ( '### ip -6 route list table all dev bridge99' )
5121 output
= check_output ( 'ip -6 route list table all dev bridge99' )
5123 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
5125 check_output ( 'ip link add dummy98 type dummy' )
5126 self
. wait_online ( 'dummy98:enslaved' , 'bridge99:routable' )
5128 output
= check_output ( 'ip -d link show bridge99' )
5130 self
. assertIn ( 'mtu 9000 ' , output
)
5132 output
= check_output ( 'ip -d link show dummy98' )
5134 self
. assertIn ( 'master bridge99 ' , output
)
5135 self
. assertIn ( 'bridge_slave' , output
)
5136 self
. assertIn ( 'mtu 9000 ' , output
)
5138 def test_bridge_configure_without_carrier ( self
):
5139 copy_network_unit ( '26-bridge.netdev' , '26-bridge-configure-without-carrier.network' ,
5143 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
5144 for test
in [ 'no-slave' , 'add-slave' , 'slave-up' , 'slave-no-carrier' , 'slave-carrier' , 'slave-down' ]:
5145 with self
. subTest ( test
= test
):
5146 if test
== 'no-slave' :
5147 # bridge has no slaves; it's up but *might* not have carrier
5148 self
. wait_operstate ( 'bridge99' , operstate
= r
'(no-carrier|routable)' , setup_state
= None , setup_timeout
= 30 )
5149 # due to a bug in the kernel, newly-created bridges are brought up
5150 # *with* carrier, unless they have had any setting changed; e.g.
5151 # their mac set, priority set, etc. Then, they will lose carrier
5152 # as soon as a (down) slave interface is added, and regain carrier
5153 # again once the slave interface is brought up.
5154 #self.check_link_attr('bridge99', 'carrier', '0')
5155 elif test
== 'add-slave' :
5156 # add slave to bridge, but leave it down; bridge is definitely no-carrier
5157 self
. check_link_attr ( 'test1' , 'operstate' , 'down' )
5158 check_output ( 'ip link set dev test1 master bridge99' )
5159 self
. wait_operstate ( 'bridge99' , operstate
= 'no-carrier' , setup_state
= None )
5160 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
5161 elif test
== 'slave-up' :
5162 # bring up slave, which will have carrier; bridge gains carrier
5163 check_output ( 'ip link set dev test1 up' )
5164 self
. wait_online ( 'bridge99:routable' )
5165 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
5166 elif test
== 'slave-no-carrier' :
5167 # drop slave carrier; bridge loses carrier
5168 check_output ( 'ip link set dev test1 carrier off' )
5169 self
. wait_online ( 'bridge99:no-carrier:no-carrier' )
5170 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
5171 elif test
== 'slave-carrier' :
5172 # restore slave carrier; bridge gains carrier
5173 check_output ( 'ip link set dev test1 carrier on' )
5174 self
. wait_online ( 'bridge99:routable' )
5175 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
5176 elif test
== 'slave-down' :
5177 # bring down slave; bridge loses carrier
5178 check_output ( 'ip link set dev test1 down' )
5179 self
. wait_online ( 'bridge99:no-carrier:no-carrier' )
5180 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
5182 output
= networkctl_status ( 'bridge99' )
5183 self
. assertRegex ( output
, '10.1.2.3' )
5184 self
. assertRegex ( output
, '10.1.2.1' )
5186 def test_bridge_ignore_carrier_loss ( self
):
5187 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
5188 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
5189 '25-bridge99-ignore-carrier-loss.network' )
5191 self
. wait_online ( 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' )
5193 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
5194 remove_link ( 'test1' , 'dummy98' )
5197 output
= check_output ( 'ip address show bridge99' )
5199 self
. assertRegex ( output
, 'NO-CARRIER' )
5200 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
5201 self
. assertRegex ( output
, 'inet 192.168.0.16/24 scope global secondary bridge99' )
5203 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain ( self
):
5204 copy_network_unit ( '26-bridge.netdev' , '26-bridge-slave-interface-1.network' ,
5205 '25-bridge99-ignore-carrier-loss.network' )
5207 self
. wait_online ( 'bridge99:no-carrier' )
5209 for trial
in range ( 4 ):
5210 check_output ( 'ip link add dummy98 type dummy' )
5211 check_output ( 'ip link set dummy98 up' )
5213 remove_link ( 'dummy98' )
5215 self
. wait_online ( 'bridge99:routable' , 'dummy98:enslaved' )
5217 output
= check_output ( 'ip address show bridge99' )
5219 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
5221 output
= check_output ( 'ip rule list table 100' )
5223 self
. assertIn ( 'from all to 8.8.8.8 lookup 100' , output
)
5225 class NetworkdSRIOVTests ( unittest
. TestCase
, Utilities
):
5233 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
5234 def test_sriov ( self
):
5235 copy_network_unit ( '25-default.link' , '25-sriov.network' )
5237 call ( 'modprobe netdevsim' )
5239 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
5242 with
open ( '/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
5246 self
. wait_online ( 'eni99np1:routable' )
5248 output
= check_output ( 'ip link show dev eni99np1' )
5250 self
. assertRegex ( output
,
5251 '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 *'
5252 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
5253 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
5256 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
5257 def test_sriov_udev ( self
):
5258 copy_network_unit ( '25-sriov.link' , '25-sriov-udev.network' )
5260 call ( 'modprobe netdevsim' )
5262 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
5266 self
. wait_online ( 'eni99np1:routable' )
5268 # the name eni99np1 may be an alternative name.
5269 ifname
= link_resolve ( 'eni99np1' )
5271 output
= check_output ( 'ip link show dev eni99np1' )
5273 self
. assertRegex ( output
,
5274 '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 *'
5275 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
5276 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
5278 self
. assertNotIn ( 'vf 3' , output
)
5279 self
. assertNotIn ( 'vf 4' , output
)
5281 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5282 f
. write ( '[Link] \n SR-IOVVirtualFunctions=4 \n ' )
5285 udevadm_trigger ( f
'/sys/devices/netdevsim99/net/ {ifname} ' )
5287 output
= check_output ( 'ip link show dev eni99np1' )
5289 self
. assertRegex ( output
,
5290 '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 *'
5291 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
5292 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
5295 self
. assertNotIn ( 'vf 4' , output
)
5297 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5298 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
5301 udevadm_trigger ( f
'/sys/devices/netdevsim99/net/ {ifname} ' )
5303 output
= check_output ( 'ip link show dev eni99np1' )
5305 self
. assertRegex ( output
,
5306 '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 *'
5307 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
5308 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
5311 self
. assertNotIn ( 'vf 4' , output
)
5313 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5314 f
. write ( '[Link] \n SR-IOVVirtualFunctions=2 \n ' )
5317 udevadm_trigger ( f
'/sys/devices/netdevsim99/net/ {ifname} ' )
5319 output
= check_output ( 'ip link show dev eni99np1' )
5321 self
. assertRegex ( output
,
5322 '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 *'
5323 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off'
5325 self
. assertNotIn ( 'vf 2' , output
)
5326 self
. assertNotIn ( 'vf 3' , output
)
5327 self
. assertNotIn ( 'vf 4' , output
)
5329 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5330 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
5333 udevadm_trigger ( f
'/sys/devices/netdevsim99/net/ {ifname} ' )
5335 output
= check_output ( 'ip link show dev eni99np1' )
5337 self
. assertRegex ( output
,
5338 '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 *'
5339 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
5340 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
5342 self
. assertNotIn ( 'vf 3' , output
)
5343 self
. assertNotIn ( 'vf 4' , output
)
5345 class NetworkdLLDPTests ( unittest
. TestCase
, Utilities
):
5353 def test_lldp ( self
):
5354 copy_network_unit ( '23-emit-lldp.network' , '24-lldp.network' , '25-veth.netdev' )
5356 self
. wait_online ( 'veth99:degraded' , 'veth-peer:degraded' )
5358 for trial
in range ( 10 ):
5362 output
= networkctl ( 'lldp' )
5364 if re
. search ( r
'veth99 .* veth-peer .* .......a...' , output
):
5369 # With interface name
5370 output
= networkctl ( 'lldp' , 'veth99' );
5372 self
. assertRegex ( output
, r
'veth99 .* veth-peer .* .......a...' )
5374 # With interface name pattern
5375 output
= networkctl ( 'lldp' , 've*9' );
5377 self
. assertRegex ( output
, r
'veth99 .* veth-peer .* .......a...' )
5380 output
= networkctl ( '--json=short' , 'lldp' )
5382 self
. assertIn ( '"InterfaceName":"veth99"' , output
)
5383 self
. assertIn ( '"PortID":"veth-peer"' , output
)
5384 self
. assertIn ( '"EnabledCapabilities":128' , output
)
5386 # json format with interface name
5387 output
= networkctl ( '--json=short' , 'lldp' , 'veth99' )
5389 self
. assertIn ( '"InterfaceName":"veth99"' , output
)
5390 self
. assertIn ( '"PortID":"veth-peer"' , output
)
5391 self
. assertIn ( '"EnabledCapabilities":128' , output
)
5393 # json format with interface name pattern
5394 output
= networkctl ( '--json=short' , 'lldp' , 've*9' )
5396 self
. assertIn ( '"InterfaceName":"veth99"' , output
)
5397 self
. assertIn ( '"PortID":"veth-peer"' , output
)
5398 self
. assertIn ( '"EnabledCapabilities":128' , output
)
5400 # LLDP neighbors in status
5401 output
= networkctl_status ( 'veth99' )
5403 self
. assertRegex ( output
, r
'Connected To: .* on port veth-peer' )
5405 # enable forwarding, to enable the Router flag
5406 with
open ( os
. path
. join ( network_unit_dir
, '23-emit-lldp.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5407 f
. write ( '[Network] \n IPv4Forwarding=yes \n ' )
5410 self
. wait_online ( 'veth-peer:degraded' )
5412 for trial
in range ( 10 ):
5416 output
= networkctl ( 'lldp' )
5418 if re
. search ( r
'veth99 .* veth-peer .* ....r......' , output
):
5423 # With interface name
5424 output
= networkctl ( 'lldp' , 'veth99' );
5426 self
. assertRegex ( output
, r
'veth99 .* veth-peer .* ....r......' )
5428 # With interface name pattern
5429 output
= networkctl ( 'lldp' , 've*9' );
5431 self
. assertRegex ( output
, r
'veth99 .* veth-peer .* ....r......' )
5434 output
= networkctl ( '--json=short' , 'lldp' )
5436 self
. assertIn ( '"InterfaceName":"veth99"' , output
)
5437 self
. assertIn ( '"PortID":"veth-peer"' , output
)
5438 self
. assertIn ( '"EnabledCapabilities":16' , output
)
5440 # json format with interface name
5441 output
= networkctl ( '--json=short' , 'lldp' , 'veth99' )
5443 self
. assertIn ( '"InterfaceName":"veth99"' , output
)
5444 self
. assertIn ( '"PortID":"veth-peer"' , output
)
5445 self
. assertIn ( '"EnabledCapabilities":16' , output
)
5447 # json format with interface name pattern
5448 output
= networkctl ( '--json=short' , 'lldp' , 've*9' )
5450 self
. assertIn ( '"InterfaceName":"veth99"' , output
)
5451 self
. assertIn ( '"PortID":"veth-peer"' , output
)
5452 self
. assertIn ( '"EnabledCapabilities":16' , output
)
5454 # LLDP neighbors in status
5455 output
= networkctl_status ( 'veth99' )
5457 self
. assertRegex ( output
, r
'Connected To: .* on port veth-peer' )
5459 class NetworkdRATests ( unittest
. TestCase
, Utilities
):
5467 def test_ipv6_prefix_delegation ( self
):
5468 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth.network' )
5469 self
. setup_nftset ( 'addr6' , 'ipv6_addr' )
5470 self
. setup_nftset ( 'network6' , 'ipv6_addr' , 'flags interval;' )
5471 self
. setup_nftset ( 'ifindex' , 'iface_index' )
5473 self
. wait_online ( 'veth99:routable' , 'veth-peer:degraded' )
5475 # IPv6SendRA=yes implies IPv6Forwarding.
5476 self
. check_ipv6_sysctl_attr ( 'veth-peer' , 'forwarding' , '1' )
5478 output
= resolvectl ( 'dns' , 'veth99' )
5480 self
. assertRegex ( output
, 'fe80::' )
5481 self
. assertRegex ( output
, '2002:da8:1::1' )
5483 output
= resolvectl ( 'domain' , 'veth99' )
5485 self
. assertIn ( 'hogehoge.test' , output
)
5487 output
= networkctl_status ( 'veth99' )
5489 self
. assertRegex ( output
, '2002:da8:1:0' )
5491 self
. check_netlabel ( 'veth99' , '2002:da8:1::/64' )
5492 self
. check_netlabel ( 'veth99' , '2002:da8:2::/64' )
5494 self
. check_nftset ( 'addr6' , '2002:da8:1:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*' )
5495 self
. check_nftset ( 'addr6' , '2002:da8:2:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*' )
5496 self
. check_nftset ( 'network6' , '2002:da8:1::/64' )
5497 self
. check_nftset ( 'network6' , '2002:da8:2::/64' )
5498 self
. check_nftset ( 'ifindex' , 'veth99' )
5500 self
. teardown_nftset ( 'addr6' , 'network6' , 'ifindex' )
5502 def check_ipv6_token_static ( self
):
5503 self
. wait_online ( 'veth99:routable' , 'veth-peer:degraded' )
5505 output
= networkctl_status ( 'veth99' )
5507 self
. assertRegex ( output
, '2002:da8:1:0:1a:2b:3c:4d' )
5508 self
. assertRegex ( output
, '2002:da8:1:0:fa:de:ca:fe' )
5509 self
. assertRegex ( output
, '2002:da8:2:0:1a:2b:3c:4d' )
5510 self
. assertRegex ( output
, '2002:da8:2:0:fa:de:ca:fe' )
5512 def test_ipv6_token_static ( self
):
5513 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-static.network' )
5516 self
. check_ipv6_token_static ()
5519 check_output ( 'ip link set veth99 down' )
5520 check_output ( 'ip link set veth99 up' )
5522 self
. check_ipv6_token_static ()
5525 check_output ( 'ip link set veth99 down' )
5526 time
. sleep ( random
. uniform ( 0 , 0.1 ))
5527 check_output ( 'ip link set veth99 up' )
5528 time
. sleep ( random
. uniform ( 0 , 0.1 ))
5530 self
. check_ipv6_token_static ()
5532 def test_ipv6_token_prefixstable ( self
):
5533 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable.network' )
5535 self
. wait_online ( 'veth99:routable' , 'veth-peer:degraded' )
5537 output
= networkctl_status ( 'veth99' )
5539 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
5540 self
. assertIn ( '2002:da8:2:0:1034:56ff:fe78:9abc' , output
) # EUI64
5542 def test_ipv6_token_prefixstable_without_address ( self
):
5543 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable-without-address.network' )
5545 self
. wait_online ( 'veth99:routable' , 'veth-peer:degraded' )
5547 output
= networkctl_status ( 'veth99' )
5549 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
5550 self
. assertIn ( '2002:da8:2:0:f689:561a:8eda:7443' , output
)
5552 def check_router_hop_limit ( self
, hop_limit
):
5553 self
. wait_route ( 'client' , rf
'default via fe80::1034:56ff:fe78:9a99 proto ra .* hoplimit {hop_limit} ' , ipv
= '-6' , timeout_sec
= 10 )
5555 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
5557 self
. assertIn ( f
'hoplimit {hop_limit} ' , output
)
5559 self
. check_ipv6_sysctl_attr ( 'client' , 'hop_limit' , f
' {hop_limit} ' )
5561 def test_router_hop_limit ( self
):
5562 copy_network_unit ( '25-veth-client.netdev' ,
5563 '25-veth-router.netdev' ,
5565 '25-veth-bridge.network' ,
5566 '25-veth-client.network' ,
5567 '25-veth-router-hop-limit.network' ,
5568 '25-bridge99.network' )
5570 self
. wait_online ( 'client-p:enslaved' ,
5571 'router:degraded' , 'router-p:enslaved' ,
5572 'bridge99:routable' )
5574 self
. check_router_hop_limit ( 42 )
5576 with
open ( os
. path
. join ( network_unit_dir
, '25-veth-router-hop-limit.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5577 f
. write ( ' \n [IPv6SendRA] \n HopLimit=43 \n ' )
5581 self
. check_router_hop_limit ( 43 )
5583 def test_router_preference ( self
):
5584 copy_network_unit ( '25-veth-client.netdev' ,
5585 '25-veth-router-high.netdev' ,
5586 '25-veth-router-low.netdev' ,
5588 '25-veth-bridge.network' ,
5589 '25-veth-client.network' ,
5590 '25-veth-router-high.network' ,
5591 '25-veth-router-low.network' ,
5592 '25-bridge99.network' )
5594 self
. wait_online ( 'client-p:enslaved' ,
5595 'router-high:degraded' , 'router-high-p:enslaved' ,
5596 'router-low:degraded' , 'router-low-p:enslaved' ,
5597 'bridge99:routable' )
5599 networkctl_reconfigure ( 'client' )
5600 self
. wait_online ( 'client:routable' )
5602 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
5603 self
. wait_address ( 'client' , '2002:da8:1:98:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
5604 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 512' , ipv
= '-6' , timeout_sec
= 10 )
5605 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 2048' , ipv
= '-6' , timeout_sec
= 10 )
5607 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
5609 self
. assertIn ( 'metric 512' , output
)
5610 self
. assertIn ( 'pref high' , output
)
5611 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
5613 self
. assertIn ( 'metric 2048' , output
)
5614 self
. assertIn ( 'pref low' , output
)
5616 with
open ( os
. path
. join ( network_unit_dir
, '25-veth-client.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5617 f
. write ( ' \n [Link] \n MACAddress=12:34:56:78:9a:01 \n [IPv6AcceptRA] \n RouteMetric=100:200:300 \n ' )
5620 self
. wait_online ( 'client:routable' )
5622 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a01/64' , ipv
= '-6' , timeout_sec
= 10 )
5623 self
. wait_address ( 'client' , '2002:da8:1:98:1034:56ff:fe78:9a01/64' , ipv
= '-6' , timeout_sec
= 10 )
5624 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 100' , ipv
= '-6' , timeout_sec
= 10 )
5625 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 300' , ipv
= '-6' , timeout_sec
= 10 )
5627 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
5629 self
. assertIn ( 'metric 100' , output
)
5630 self
. assertNotIn ( 'metric 512' , output
)
5631 self
. assertIn ( 'pref high' , output
)
5632 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
5634 self
. assertIn ( 'metric 300' , output
)
5635 self
. assertNotIn ( 'metric 2048' , output
)
5636 self
. assertIn ( 'pref low' , output
)
5638 # swap the preference (for issue #28439)
5639 remove_network_unit ( '25-veth-router-high.network' , '25-veth-router-low.network' )
5640 copy_network_unit ( '25-veth-router-high2.network' , '25-veth-router-low2.network' )
5642 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 300' , ipv
= '-6' , timeout_sec
= 10 )
5643 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 100' , ipv
= '-6' , timeout_sec
= 10 )
5645 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
5647 self
. assertIn ( 'metric 300' , output
)
5648 self
. assertNotIn ( 'metric 100' , output
)
5649 self
. assertIn ( 'pref low' , output
)
5650 self
. assertNotIn ( 'pref high' , output
)
5651 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
5653 self
. assertIn ( 'metric 100' , output
)
5654 self
. assertNotIn ( 'metric 300' , output
)
5655 self
. assertIn ( 'pref high' , output
)
5656 self
. assertNotIn ( 'pref low' , output
)
5658 @unittest . skipUnless ( radvd_check_config ( 'captive-portal.conf' ), "Installed radvd doesn't support captive portals" )
5659 def test_captive_portal ( self
):
5660 copy_network_unit ( '25-veth-client.netdev' ,
5661 '25-veth-router-captive.netdev' ,
5663 '25-veth-client-captive.network' ,
5664 '25-veth-router-captive.network' ,
5665 '25-veth-bridge-captive.network' ,
5666 '25-bridge99.network' )
5668 self
. wait_online ( 'bridge99:routable' , 'client-p:enslaved' ,
5669 'router-captive:degraded' , 'router-captivep:enslaved' )
5671 start_radvd ( config_file
= 'captive-portal.conf' )
5672 networkctl_reconfigure ( 'client' )
5673 self
. wait_online ( 'client:routable' )
5675 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
5676 output
= networkctl_status ( 'client' )
5678 self
. assertIn ( 'Captive Portal: http://systemd.io' , output
)
5680 @unittest . skipUnless ( radvd_check_config ( 'captive-portal.conf' ), "Installed radvd doesn't support captive portals" )
5681 def test_invalid_captive_portal ( self
):
5682 def radvd_write_config ( captive_portal_uri
):
5683 with
open ( os
. path
. join ( networkd_ci_temp_dir
, 'radvd/bogus-captive-portal.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5684 f
. write ( f
'interface router-captive {{ AdvSendAdvert on; AdvCaptivePortalAPI " {captive_portal_uri} "; prefix 2002:da8:1:99::/64 {{ AdvOnLink on; AdvAutonomous on; }}; }};' )
5686 captive_portal_uris
= [
5687 "42ěščěškd ěšč ě s" ,
5692 copy_network_unit ( '25-veth-client.netdev' ,
5693 '25-veth-router-captive.netdev' ,
5695 '25-veth-client-captive.network' ,
5696 '25-veth-router-captive.network' ,
5697 '25-veth-bridge-captive.network' ,
5698 '25-bridge99.network' )
5700 self
. wait_online ( 'bridge99:routable' , 'client-p:enslaved' ,
5701 'router-captive:degraded' , 'router-captivep:enslaved' )
5703 for uri
in captive_portal_uris
:
5704 print ( f
"Captive portal: {uri} " )
5705 radvd_write_config ( uri
)
5707 start_radvd ( config_file
= 'bogus-captive-portal.conf' )
5708 networkctl_reconfigure ( 'client' )
5709 self
. wait_online ( 'client:routable' )
5711 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
5712 output
= networkctl_status ( 'client' )
5714 self
. assertNotIn ( 'Captive Portal:' , output
)
5716 class NetworkdDHCPServerTests ( unittest
. TestCase
, Utilities
):
5724 def test_dhcp_server ( self
):
5725 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server.network' )
5727 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
5729 output
= networkctl_status ( 'veth99' )
5731 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
5732 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
5733 self
. assertRegex ( output
, 'DNS: 192.168.5.1 \n *192.168.5.10' )
5734 self
. assertRegex ( output
, 'NTP: 192.168.5.1 \n *192.168.5.11' )
5736 output
= networkctl_status ( 'veth-peer' )
5738 self
. assertRegex ( output
, "Offered DHCP leases: 192.168.5.[0-9]*" )
5740 networkctl_reconfigure ( 'veth-peer' )
5741 self
. wait_online ( 'veth-peer:routable' )
5744 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth-peer' , env
= env
)
5745 if 'Offered DHCP leases: 192.168.5.' in output
:
5751 def test_dhcp_server_null_server_address ( self
):
5752 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-null-server-address.network' )
5754 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
5756 output
= check_output ( 'ip --json address show dev veth-peer' )
5757 server_address
= json
. loads ( output
)[ 0 ][ 'addr_info' ][ 0 ][ 'local' ]
5758 print ( server_address
)
5760 output
= check_output ( 'ip --json address show dev veth99' )
5761 client_address
= json
. loads ( output
)[ 0 ][ 'addr_info' ][ 0 ][ 'local' ]
5762 print ( client_address
)
5764 output
= networkctl_status ( 'veth99' )
5766 self
. assertRegex ( output
, rf
'Address: {client_address} \(DHCP4 via {server_address} \)' )
5767 self
. assertIn ( f
'Gateway: {server_address} ' , output
)
5768 self
. assertIn ( f
'DNS: {server_address} ' , output
)
5769 self
. assertIn ( f
'NTP: {server_address} ' , output
)
5771 output
= networkctl_status ( 'veth-peer' )
5772 self
. assertIn ( f
'Offered DHCP leases: {client_address} ' , output
)
5774 # Check if the same addresses are used even if the service is restarted.
5776 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
5778 output
= check_output ( 'ip -4 address show dev veth-peer' )
5780 self
. assertIn ( f
' {server_address} ' , output
)
5782 output
= check_output ( 'ip -4 address show dev veth99' )
5784 self
. assertIn ( f
' {client_address} ' , output
)
5786 output
= networkctl_status ( 'veth99' )
5788 self
. assertRegex ( output
, rf
'Address: {client_address} \(DHCP4 via {server_address} \)' )
5789 self
. assertIn ( f
'Gateway: {server_address} ' , output
)
5790 self
. assertIn ( f
'DNS: {server_address} ' , output
)
5791 self
. assertIn ( f
'NTP: {server_address} ' , output
)
5793 output
= networkctl_status ( 'veth-peer' )
5794 self
. assertIn ( f
'Offered DHCP leases: {client_address} ' , output
)
5796 def test_dhcp_server_with_uplink ( self
):
5797 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-downstream.network' ,
5798 '12-dummy.netdev' , '25-dhcp-server-uplink.network' )
5800 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
5802 output
= networkctl_status ( 'veth99' )
5804 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
5805 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
5806 self
. assertIn ( 'DNS: 192.168.5.1' , output
)
5807 self
. assertIn ( 'NTP: 192.168.5.1' , output
)
5809 def test_emit_router_timezone ( self
):
5810 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-timezone-router.network' , '25-dhcp-server-timezone-router.network' )
5812 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
5814 output
= networkctl_status ( 'veth99' )
5816 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)' )
5817 self
. assertIn ( 'Gateway: 192.168.5.1' , output
)
5818 self
. assertIn ( 'Time Zone: Europe/Berlin' , output
)
5820 def test_dhcp_server_static_lease ( self
):
5821 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-static-lease.network' , '25-dhcp-server-static-lease.network' )
5823 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
5825 output
= networkctl_status ( 'veth99' )
5827 self
. assertIn ( 'Address: 10.1.1.200 (DHCP4 via 10.1.1.1)' , output
)
5828 self
. assertIn ( 'DHCP4 Client ID: 12:34:56:78:9a:bc' , output
)
5830 def test_dhcp_server_static_lease_default_client_id ( self
):
5831 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-static-lease.network' )
5833 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
5835 output
= networkctl_status ( 'veth99' )
5837 self
. assertIn ( 'Address: 10.1.1.200 (DHCP4 via 10.1.1.1)' , output
)
5838 self
. assertRegex ( output
, 'DHCP4 Client ID: IAID:[0-9a-z]*/DUID' )
5840 class NetworkdDHCPServerRelayAgentTests ( unittest
. TestCase
, Utilities
):
5848 def test_relay_agent ( self
):
5849 copy_network_unit ( '25-agent-veth-client.netdev' ,
5850 '25-agent-veth-server.netdev' ,
5851 '25-agent-client.network' ,
5852 '25-agent-server.network' ,
5853 '25-agent-client-peer.network' ,
5854 '25-agent-server-peer.network' )
5857 self
. wait_online ( 'client:routable' )
5859 output
= networkctl_status ( 'client' )
5861 self
. assertRegex ( output
, r
'Address: 192.168.5.150 \(DHCP4 via 192.168.5.1\)' )
5863 def test_relay_agent_on_bridge ( self
):
5864 copy_network_unit ( '25-agent-bridge.netdev' ,
5865 '25-agent-veth-client.netdev' ,
5866 '25-agent-bridge.network' ,
5867 '25-agent-bridge-port.network' ,
5868 '25-agent-client.network' )
5870 self
. wait_online ( 'bridge-relay:routable' , 'client-peer:enslaved' )
5873 expect
= 'bridge-relay: DHCPv4 server: STARTED'
5875 if expect
in read_networkd_log ():
5881 class NetworkdDHCPClientTests ( unittest
. TestCase
, Utilities
):
5889 def test_dhcp_client_ipv6_only ( self
):
5890 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv6-only.network' )
5893 self
. wait_online ( 'veth-peer:carrier' )
5895 # information request mode
5896 # The name ipv6-only option may not be supported by older dnsmasq
5897 # start_dnsmasq('--dhcp-option=option:ipv6-only,300')
5898 start_dnsmasq ( '--dhcp-option=108,00:00:02:00' ,
5899 '--dhcp-option=option6:dns-server,[2600::ee]' ,
5900 '--dhcp-option=option6:ntp-server,[2600::ff]' ,
5901 ra_mode
= 'ra-stateless' )
5902 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
5904 # DHCPv6 REPLY for INFORMATION-REQUEST may be received after the link entered configured state.
5905 # Let's wait for the expected DNS server being listed in the state file.
5906 for _
in range ( 100 ):
5907 output
= read_link_state_file ( 'veth99' )
5908 if 'DNS=2600::ee' in output
:
5912 # Check link state file
5913 print ( '## link state file' )
5914 output
= read_link_state_file ( 'veth99' )
5916 self
. assertIn ( 'DNS=2600::ee' , output
)
5917 self
. assertIn ( 'NTP=2600::ff' , output
)
5919 # Check manager state file
5920 print ( '## manager state file' )
5921 output
= read_manager_state_file ()
5923 self
. assertRegex ( output
, 'DNS=.*2600::ee' )
5924 self
. assertRegex ( output
, 'NTP=.*2600::ff' )
5926 print ( '## dnsmasq log' )
5927 output
= read_dnsmasq_log_file ()
5929 self
. assertIn ( 'DHCPINFORMATION-REQUEST(veth-peer)' , output
)
5930 self
. assertNotIn ( 'DHCPSOLICIT(veth-peer)' , output
)
5931 self
. assertNotIn ( 'DHCPADVERTISE(veth-peer)' , output
)
5932 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
5933 self
. assertNotIn ( 'DHCPREPLY(veth-peer)' , output
)
5936 check_json ( networkctl_json ( 'veth99' ))
5940 start_dnsmasq ( '--dhcp-option=108,00:00:02:00' ,
5941 '--dhcp-option=option6:dns-server,[2600::ee]' ,
5942 '--dhcp-option=option6:ntp-server,[2600::ff]' )
5943 networkctl_reconfigure ( 'veth99' )
5944 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
5947 output
= check_output ( 'ip address show dev veth99 scope global' )
5949 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
5950 self
. assertNotIn ( '192.168.5' , output
)
5952 # checking semi-static route
5953 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
5955 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
5957 # Confirm that ipv6 token is not set in the kernel
5958 output
= check_output ( 'ip token show dev veth99' )
5960 self
. assertRegex ( output
, 'token :: dev veth99' )
5962 # Make manager and link state file updated
5963 resolvectl ( 'revert' , 'veth99' )
5965 # Check link state file
5966 print ( '## link state file' )
5967 output
= read_link_state_file ( 'veth99' )
5969 self
. assertIn ( 'DNS=2600::ee' , output
)
5970 self
. assertIn ( 'NTP=2600::ff' , output
)
5972 # Check manager state file
5973 print ( '## manager state file' )
5974 output
= read_manager_state_file ()
5976 self
. assertRegex ( output
, 'DNS=.*2600::ee' )
5977 self
. assertRegex ( output
, 'NTP=.*2600::ff' )
5979 print ( '## dnsmasq log' )
5980 output
= read_dnsmasq_log_file ()
5982 self
. assertNotIn ( 'DHCPINFORMATION-REQUEST(veth-peer)' , output
)
5983 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
5984 self
. assertNotIn ( 'DHCPADVERTISE(veth-peer)' , output
)
5985 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
5986 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
5987 self
. assertIn ( 'sent size: 0 option: 14 rapid-commit' , output
)
5990 check_json ( networkctl_json ( 'veth99' ))
5992 # Testing without rapid commit support
5993 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-ipv6-only.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5994 f
. write ( ' \n [DHCPv6] \n RapidCommit=no \n ' )
5997 start_dnsmasq ( '--dhcp-option=108,00:00:02:00' ,
5998 '--dhcp-option=option6:dns-server,[2600::ee]' ,
5999 '--dhcp-option=option6:ntp-server,[2600::ff]' )
6002 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6005 output
= check_output ( 'ip address show dev veth99 scope global' )
6007 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
6008 self
. assertNotIn ( '192.168.5' , output
)
6010 # checking semi-static route
6011 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
6013 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
6015 # Make manager and link state file updated
6016 resolvectl ( 'revert' , 'veth99' )
6018 # Check link state file
6019 print ( '## link state file' )
6020 output
= read_link_state_file ( 'veth99' )
6022 self
. assertIn ( 'DNS=2600::ee' , output
)
6023 self
. assertIn ( 'NTP=2600::ff' , output
)
6025 # Check manager state file
6026 print ( '## manager state file' )
6027 output
= read_manager_state_file ()
6029 self
. assertRegex ( output
, 'DNS=.*2600::ee' )
6030 self
. assertRegex ( output
, 'NTP=.*2600::ff' )
6032 print ( '## dnsmasq log' )
6033 output
= read_dnsmasq_log_file ()
6035 self
. assertNotIn ( 'DHCPINFORMATION-REQUEST(veth-peer)' , output
)
6036 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
6037 self
. assertIn ( 'DHCPADVERTISE(veth-peer)' , output
)
6038 self
. assertIn ( 'DHCPREQUEST(veth-peer)' , output
)
6039 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
6040 self
. assertNotIn ( 'rapid-commit' , output
)
6043 check_json ( networkctl_json ( 'veth99' ))
6045 def test_dhcp_client_ipv6_dbus_status ( self
):
6046 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv6-only.network' )
6048 self
. wait_online ( 'veth-peer:carrier' )
6050 # Note that at this point the DHCPv6 client has not been started because no RA (with managed
6051 # bit set) has yet been received and the configuration does not include WithoutRA=true
6052 state
= get_dhcp6_client_state ( 'veth99' )
6053 print ( f
"DHCPv6 client state = {state} " )
6054 self
. assertEqual ( state
, 'stopped' )
6056 state
= get_dhcp4_client_state ( 'veth99' )
6057 print ( f
"DHCPv4 client state = {state} " )
6058 self
. assertEqual ( state
, 'selecting' )
6060 start_dnsmasq ( '--dhcp-option=108,00:00:02:00' )
6061 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6063 state
= get_dhcp6_client_state ( 'veth99' )
6064 print ( f
"DHCPv6 client state = {state} " )
6065 self
. assertEqual ( state
, 'bound' )
6067 # DHCPv4 client will stop after an DHCPOFFER message received, so we need to wait for a while.
6068 for _
in range ( 100 ):
6069 state
= get_dhcp4_client_state ( 'veth99' )
6070 if state
== 'stopped' :
6074 print ( f
"DHCPv4 client state = {state} " )
6075 self
. assertEqual ( state
, 'stopped' )
6077 # restart dnsmasq to clear log
6079 start_dnsmasq ( '--dhcp-option=108,00:00:02:00' )
6081 # Test renew command
6082 # See https://github.com/systemd/systemd/pull/29472#issuecomment-1759092138
6083 networkctl ( 'renew' , 'veth99' )
6085 for _
in range ( 100 ):
6086 state
= get_dhcp4_client_state ( 'veth99' )
6087 if state
== 'stopped' :
6091 print ( f
"DHCPv4 client state = {state} " )
6092 self
. assertEqual ( state
, 'stopped' )
6094 print ( '## dnsmasq log' )
6095 output
= read_dnsmasq_log_file ()
6097 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc' , output
)
6098 self
. assertIn ( 'DHCPOFFER(veth-peer)' , output
)
6099 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
6100 self
. assertNotIn ( 'DHCPACK(veth-peer)' , output
)
6102 def test_dhcp_client_ipv6_only_with_custom_client_identifier ( self
):
6103 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv6-only-custom-client-identifier.network' )
6106 self
. wait_online ( 'veth-peer:carrier' )
6108 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6111 output
= check_output ( 'ip address show dev veth99 scope global' )
6113 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
6114 self
. assertNotIn ( '192.168.5' , output
)
6116 print ( '## dnsmasq log' )
6117 output
= read_dnsmasq_log_file ()
6119 self
. assertIn ( 'DHCPSOLICIT(veth-peer) 00:42:00:00:ab:11:f9:2a:c2:77:29:f9:5c:00' , output
)
6120 self
. assertNotIn ( 'DHCPADVERTISE(veth-peer)' , output
)
6121 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
6122 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
6123 self
. assertIn ( 'sent size: 0 option: 14 rapid-commit' , output
)
6125 def test_dhcp_client_ipv4_only ( self
):
6126 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv4-only.network' )
6128 self
. setup_nftset ( 'addr4' , 'ipv4_addr' )
6129 self
. setup_nftset ( 'network4' , 'ipv4_addr' , 'flags interval;' )
6130 self
. setup_nftset ( 'ifindex' , 'iface_index' )
6133 self
. wait_online ( 'veth-peer:carrier' )
6134 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7' ,
6135 '--dhcp-option=option:sip-server,192.168.5.21,192.168.5.22' ,
6136 '--dhcp-option=option:domain-search,example.com' ,
6137 '--dhcp-alternate-port=67,5555' ,
6138 ipv4_range
= '192.168.5.110,192.168.5.119' )
6139 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6140 self
. wait_address ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' )
6142 print ( '## ip address show dev veth99 scope global' )
6143 output
= check_output ( 'ip address show dev veth99 scope global' )
6145 self
. assertIn ( 'mtu 1492' , output
)
6146 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
6147 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' )
6148 self
. assertNotIn ( '2600::' , output
)
6150 output
= check_output ( 'ip -4 --json address show dev veth99' )
6151 for i
in json
. loads ( output
)[ 0 ][ 'addr_info' ]:
6152 if i
[ 'label' ] == 'test-label' :
6153 address1
= i
[ 'local' ]
6156 self
. assertFalse ( True )
6158 self
. assertRegex ( address1
, r
'^192.168.5.11[0-9]$' )
6160 print ( '## ip route show table main dev veth99' )
6161 output
= check_output ( 'ip route show table main dev veth99' )
6163 # no DHCP routes assigned to the main table
6164 self
. assertNotIn ( 'proto dhcp' , output
)
6166 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
6167 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
6168 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
6169 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
6171 print ( '## ip route show table 211 dev veth99' )
6172 output
= check_output ( 'ip route show table 211 dev veth99' )
6174 self
. assertRegex ( output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 24' )
6175 self
. assertRegex ( output
, f
'192.168.5.0/24 proto dhcp scope link src {address1} metric 24' )
6176 self
. assertRegex ( output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 24' )
6177 self
. assertRegex ( output
, f
'192.168.5.6 proto dhcp scope link src {address1} metric 24' )
6178 self
. assertRegex ( output
, f
'192.168.5.7 proto dhcp scope link src {address1} metric 24' )
6179 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
6181 print ( '## link state file' )
6182 output
= read_link_state_file ( 'veth99' )
6184 # checking DNS server, SIP server, and Domains
6185 self
. assertIn ( 'DNS=192.168.5.6 192.168.5.7' , output
)
6186 self
. assertIn ( 'SIP=192.168.5.21 192.168.5.22' , output
)
6187 self
. assertIn ( 'DOMAINS=example.com' , output
)
6190 j
= json
. loads ( networkctl_json ( 'veth99' ))
6192 self
. assertEqual ( len ( j
[ 'DNS' ]), 2 )
6195 self
. assertEqual ( i
[ 'Family' ], 2 )
6196 a
= socket
. inet_ntop ( socket
. AF_INET
, bytearray ( i
[ 'Address' ]))
6197 self
. assertRegex ( a
, '^192.168.5.[67]$' )
6198 self
. assertEqual ( i
[ 'ConfigSource' ], 'DHCPv4' )
6199 a
= socket
. inet_ntop ( socket
. AF_INET
, bytearray ( i
[ 'ConfigProvider' ]))
6200 self
. assertEqual ( '192.168.5.1' , a
)
6202 self
. assertEqual ( len ( j
[ 'SIP' ]), 2 )
6205 self
. assertEqual ( i
[ 'Family' ], 2 )
6206 a
= socket
. inet_ntop ( socket
. AF_INET
, bytearray ( i
[ 'Address' ]))
6207 self
. assertRegex ( a
, '^192.168.5.2[12]$' )
6208 self
. assertEqual ( i
[ 'ConfigSource' ], 'DHCPv4' )
6209 a
= socket
. inet_ntop ( socket
. AF_INET
, bytearray ( i
[ 'ConfigProvider' ]))
6210 self
. assertEqual ( '192.168.5.1' , a
)
6212 print ( '## dnsmasq log' )
6213 output
= read_dnsmasq_log_file ()
6215 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
6216 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 192.168.5.110 12:34:56:78:9a:bc' , output
)
6217 self
. assertIn ( 'client provides name: test-hostname' , output
)
6218 self
. assertIn ( '26:mtu' , output
)
6220 # change address range, DNS servers, and Domains
6222 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8' ,
6223 '--dhcp-option=option:sip-server,192.168.5.23,192.168.5.24' ,
6224 '--dhcp-option=option:domain-search,foo.example.com' ,
6225 '--dhcp-alternate-port=67,5555' ,
6226 ipv4_range
= '192.168.5.120,192.168.5.129' ,)
6228 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
6229 print ( 'Wait for the DHCP lease to be expired' )
6230 self
. wait_address_dropped ( 'veth99' , f
'inet {address1} /24' , ipv
= '-4' , timeout_sec
= 120 )
6231 self
. wait_address ( 'veth99' , r
'inet 192.168.5.12[0-9]*/24' , ipv
= '-4' )
6233 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6235 print ( '## ip address show dev veth99 scope global' )
6236 output
= check_output ( 'ip address show dev veth99 scope global' )
6238 self
. assertIn ( 'mtu 1492' , output
)
6239 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
6240 self
. assertNotIn ( f
' {address1} ' , output
)
6241 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' )
6242 self
. assertNotIn ( '2600::' , output
)
6244 output
= check_output ( 'ip -4 --json address show dev veth99' )
6245 for i
in json
. loads ( output
)[ 0 ][ 'addr_info' ]:
6246 if i
[ 'label' ] == 'test-label' :
6247 address2
= i
[ 'local' ]
6250 self
. assertFalse ( True )
6252 self
. assertRegex ( address2
, r
'^192.168.5.12[0-9]$' )
6254 print ( '## ip route show table main dev veth99' )
6255 output
= check_output ( 'ip route show table main dev veth99' )
6257 # no DHCP routes assigned to the main table
6258 self
. assertNotIn ( 'proto dhcp' , output
)
6260 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
6261 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
6262 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
6263 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
6265 print ( '## ip route show table 211 dev veth99' )
6266 output
= check_output ( 'ip route show table 211 dev veth99' )
6268 self
. assertRegex ( output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 24' )
6269 self
. assertRegex ( output
, f
'192.168.5.0/24 proto dhcp scope link src {address2} metric 24' )
6270 self
. assertRegex ( output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 24' )
6271 self
. assertNotIn ( '192.168.5.6' , output
)
6272 self
. assertRegex ( output
, f
'192.168.5.7 proto dhcp scope link src {address2} metric 24' )
6273 self
. assertRegex ( output
, f
'192.168.5.8 proto dhcp scope link src {address2} metric 24' )
6274 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
6276 print ( '## link state file' )
6277 output
= read_link_state_file ( 'veth99' )
6279 # checking DNS server, SIP server, and Domains
6280 self
. assertIn ( 'DNS=192.168.5.1 192.168.5.7 192.168.5.8' , output
)
6281 self
. assertIn ( 'SIP=192.168.5.23 192.168.5.24' , output
)
6282 self
. assertIn ( 'DOMAINS=foo.example.com' , output
)
6285 j
= json
. loads ( networkctl_json ( 'veth99' ))
6287 self
. assertEqual ( len ( j
[ 'DNS' ]), 3 )
6290 self
. assertEqual ( i
[ 'Family' ], 2 )
6291 a
= socket
. inet_ntop ( socket
. AF_INET
, bytearray ( i
[ 'Address' ]))
6292 self
. assertRegex ( a
, '^192.168.5.[178]$' )
6293 self
. assertEqual ( i
[ 'ConfigSource' ], 'DHCPv4' )
6294 a
= socket
. inet_ntop ( socket
. AF_INET
, bytearray ( i
[ 'ConfigProvider' ]))
6295 self
. assertEqual ( '192.168.5.1' , a
)
6297 self
. assertEqual ( len ( j
[ 'SIP' ]), 2 )
6300 self
. assertEqual ( i
[ 'Family' ], 2 )
6301 a
= socket
. inet_ntop ( socket
. AF_INET
, bytearray ( i
[ 'Address' ]))
6302 self
. assertRegex ( a
, '^192.168.5.2[34]$' )
6303 self
. assertEqual ( i
[ 'ConfigSource' ], 'DHCPv4' )
6304 a
= socket
. inet_ntop ( socket
. AF_INET
, bytearray ( i
[ 'ConfigProvider' ]))
6305 self
. assertEqual ( '192.168.5.1' , a
)
6307 print ( '## dnsmasq log' )
6308 output
= read_dnsmasq_log_file ()
6310 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
6311 self
. assertIn ( f
'DHCPDISCOVER(veth-peer) {address1} 12:34:56:78:9a:bc' , output
)
6312 self
. assertIn ( 'client provides name: test-hostname' , output
)
6313 self
. assertIn ( '26:mtu' , output
)
6315 self
. check_netlabel ( 'veth99' , r
'192\.168\.5\.0/24' )
6317 self
. check_nftset ( 'addr4' , r
'192\.168\.5\.1' )
6318 self
. check_nftset ( 'network4' , r
'192\.168\.5\.0/24' )
6319 self
. check_nftset ( 'ifindex' , 'veth99' )
6321 self
. teardown_nftset ( 'addr4' , 'network4' , 'ifindex' )
6323 def test_dhcp_client_ipv4_dbus_status ( self
):
6324 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv4-only.network' )
6326 self
. wait_online ( 'veth-peer:carrier' )
6328 state
= get_dhcp4_client_state ( 'veth99' )
6329 print ( f
"State = {state} " )
6330 self
. assertEqual ( state
, 'rebooting' )
6332 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7' ,
6333 '--dhcp-option=option:domain-search,example.com' ,
6334 '--dhcp-alternate-port=67,5555' ,
6335 ipv4_range
= '192.168.5.110,192.168.5.119' )
6336 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6337 self
. wait_address ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' )
6339 state
= get_dhcp4_client_state ( 'veth99' )
6340 print ( f
"State = {state} " )
6341 self
. assertEqual ( state
, 'bound' )
6343 def test_dhcp_client_allow_list ( self
):
6344 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-allow-list.network' , copy_dropins
= False )
6347 self
. wait_online ( 'veth-peer:carrier' )
6348 since
= datetime
. datetime
. now ()
6351 expect
= 'veth99: DHCPv4 server IP address 192.168.5.1 not found in allow-list, ignoring offer.'
6353 if expect
in read_networkd_log ( since
= since
):
6359 copy_network_unit ( '25-dhcp-client-allow-list.network.d/00-allow-list.conf' )
6360 since
= datetime
. datetime
. now ()
6363 expect
= 'veth99: DHCPv4 server IP address 192.168.5.1 not found in allow-list, ignoring offer.'
6365 if expect
in read_networkd_log ( since
= since
):
6371 copy_network_unit ( '25-dhcp-client-allow-list.network.d/10-deny-list.conf' )
6372 since
= datetime
. datetime
. now ()
6375 expect
= 'veth99: DHCPv4 server IP address 192.168.5.1 found in deny-list, ignoring offer.'
6377 if expect
in read_networkd_log ( since
= since
):
6383 @unittest . skipUnless ( "--dhcp-rapid-commit" in run ( "dnsmasq --help" ). stdout
, reason
= "dnsmasq is missing dhcp-rapid-commit support" )
6384 def test_dhcp_client_rapid_commit ( self
):
6385 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' )
6387 self
. wait_online ( 'veth-peer:carrier' )
6389 start_dnsmasq ( '--dhcp-rapid-commit' )
6390 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6391 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24' , ipv
= '-4' )
6393 state
= get_dhcp4_client_state ( 'veth99' )
6394 print ( f
"DHCPv4 client state = {state} " )
6395 self
. assertEqual ( state
, 'bound' )
6397 output
= read_dnsmasq_log_file ()
6398 self
. assertIn ( 'DHCPDISCOVER(veth-peer)' , output
)
6399 self
. assertNotIn ( 'DHCPOFFER(veth-peer)' , output
)
6400 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
6401 self
. assertIn ( 'DHCPACK(veth-peer)' , output
)
6403 def test_dhcp_client_ipv6_only_mode_without_ipv6_connectivity ( self
):
6404 copy_network_unit ( '25-veth.netdev' ,
6405 '25-dhcp-server-ipv6-only-mode.network' ,
6406 '25-dhcp-client-ipv6-only-mode.network' )
6408 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' , timeout
= '40s' )
6409 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24' , ipv
= '-4' )
6411 state
= get_dhcp4_client_state ( 'veth99' )
6412 print ( f
"State = {state} " )
6413 self
. assertEqual ( state
, 'bound' )
6415 def test_dhcp_client_ipv4_use_routes_gateway ( self
):
6417 for ( routes
, gateway
, dns_and_ntp_routes
, classless
) in itertools
. product ([ True , False ], repeat
= 4 ):
6423 print ( f
'### test_dhcp_client_ipv4_use_routes_gateway(routes= {routes} , gateway= {gateway} , dns_and_ntp_routes= {dns_and_ntp_routes} , classless= {classless} )' )
6424 with self
. subTest ( routes
= routes
, gateway
= gateway
, dns_and_ntp_routes
= dns_and_ntp_routes
, classless
= classless
):
6425 self
._ test
_ dhcp
_ client
_ ipv
4_u se
_ routes
_ gateway
( routes
, gateway
, dns_and_ntp_routes
, classless
)
6427 def _test_dhcp_client_ipv4_use_routes_gateway ( self
, use_routes
, use_gateway
, dns_and_ntp_routes
, classless
):
6428 testunit
= '25-dhcp-client-ipv4-use-routes-use-gateway.network'
6429 testunits
= [ '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , testunit
]
6430 testunits
. append ( f
' {testunit} .d/use-routes- {use_routes} .conf' )
6431 testunits
. append ( f
' {testunit} .d/use-gateway- {use_gateway} .conf' )
6432 testunits
. append ( f
' {testunit} .d/use-dns-and-ntp-routes- {dns_and_ntp_routes} .conf' )
6433 copy_network_unit (* testunits
, copy_dropins
= False )
6436 self
. wait_online ( 'veth-peer:carrier' )
6437 additional_options
= [
6438 '--dhcp-option=option:dns-server,192.168.5.10,8.8.8.8' ,
6439 '--dhcp-option=option:ntp-server,192.168.5.11,9.9.9.9' ,
6440 '--dhcp-option=option:static-route,192.168.6.100,192.168.5.2,8.8.8.8,192.168.5.3'
6443 additional_options
+= [
6444 '--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'
6446 start_dnsmasq (* additional_options
)
6447 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6449 output
= check_output ( 'ip -4 route show dev veth99' )
6455 self
. assertRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6456 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6457 self
. assertRegex ( output
, r
'192.168.5.64/26 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6458 self
. assertRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6459 self
. assertRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6461 self
. assertRegex ( output
, r
'192.168.6.0/24 via 192.168.5.2 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6462 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6463 self
. assertRegex ( output
, r
'192.168.5.2 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6464 self
. assertRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6466 self
. assertNotRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6467 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6468 self
. assertNotRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6469 self
. assertNotRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6470 self
. assertNotRegex ( output
, r
'192.168.6.0/24 via 192.168.5.2 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6471 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6472 self
. assertNotRegex ( output
, r
'192.168.5.2 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6473 self
. assertNotRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6476 if use_gateway
and ( not classless
or not use_routes
):
6477 self
. assertRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6479 self
. assertNotRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6481 # Check route to gateway
6482 if ( use_gateway
or dns_and_ntp_routes
) and ( not classless
or not use_routes
):
6483 self
. assertRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6485 self
. assertNotRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6487 # Check RoutesToDNS= and RoutesToNTP=
6488 if dns_and_ntp_routes
:
6489 self
. assertRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6490 self
. assertRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6493 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6494 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6496 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6497 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6499 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6500 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6502 self
. assertNotRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6503 self
. assertNotRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6504 self
. assertNotRegex ( output
, r
'8.8.8.8 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
6505 self
. assertNotRegex ( output
, r
'9.9.9.9 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
6507 check_json ( networkctl_json ())
6509 def test_dhcp_client_settings_anonymize ( self
):
6510 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-anonymize.network' )
6512 self
. wait_online ( 'veth-peer:carrier' )
6514 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6516 print ( '## dnsmasq log' )
6517 output
= read_dnsmasq_log_file ()
6519 self
. assertNotIn ( 'VendorClassIdentifier=SusantVendorTest' , output
)
6520 self
. assertNotIn ( 'test-hostname' , output
)
6521 self
. assertNotIn ( '26:mtu' , output
)
6523 def test_dhcp_keep_configuration_dhcp ( self
):
6524 copy_network_unit ( '25-veth.netdev' ,
6525 '25-dhcp-server-veth-peer.network' ,
6526 '25-dhcp-client-keep-configuration-dhcp.network' )
6528 self
. wait_online ( 'veth-peer:carrier' )
6530 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6532 output
= check_output ( 'ip address show dev veth99 scope global' )
6534 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
6535 'valid_lft forever preferred_lft forever' )
6537 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
6540 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
6541 print ( 'Wait for the DHCP lease to be expired' )
6544 # The lease address should be kept after the lease expired
6545 output
= check_output ( 'ip address show dev veth99 scope global' )
6547 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
6548 'valid_lft forever preferred_lft forever' )
6552 # The lease address should be kept after networkd stopped
6553 output
= check_output ( 'ip address show dev veth99 scope global' )
6555 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
6556 'valid_lft forever preferred_lft forever' )
6558 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-keep-configuration-dhcp.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
6559 f
. write ( '[Network] \n DHCP=no \n ' )
6562 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6564 # Still the lease address should be kept after networkd restarted
6565 output
= check_output ( 'ip address show dev veth99 scope global' )
6567 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
6568 'valid_lft forever preferred_lft forever' )
6570 def test_dhcp_keep_configuration_dhcp_on_stop ( self
):
6571 copy_network_unit ( '25-veth.netdev' ,
6572 '25-dhcp-server-veth-peer.network' ,
6573 '25-dhcp-client-keep-configuration-dhcp-on-stop.network' )
6575 self
. wait_online ( 'veth-peer:carrier' )
6577 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6579 output
= check_output ( 'ip address show dev veth99 scope global' )
6581 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
6586 output
= check_output ( 'ip address show dev veth99 scope global' )
6588 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
6591 self
. wait_online ( 'veth-peer:routable' )
6593 output
= check_output ( 'ip address show dev veth99 scope global' )
6595 self
. assertNotIn ( '192.168.5.' , output
)
6597 def test_dhcp_client_reuse_address_as_static ( self
):
6598 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' )
6600 self
. wait_online ( 'veth-peer:carrier' )
6602 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6604 # link become 'routable' when at least one protocol provide an valid address.
6605 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
6606 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
6608 output
= check_output ( 'ip address show dev veth99 scope global' )
6609 ipv4_address
= re
. search ( r
'192.168.5.[0-9]*/24' , output
). group ()
6610 ipv6_address
= re
. search ( r
'2600::[0-9a-f:]*/128' , output
). group ()
6611 static_network
= ' \n ' . join ([ '[Match]' , 'Name=veth99' , '[Network]' , 'IPv6AcceptRA=no' , 'Address=' + ipv4_address
, 'Address=' + ipv6_address
])
6612 print ( static_network
)
6614 remove_network_unit ( '25-dhcp-client.network' )
6616 with
open ( os
. path
. join ( network_unit_dir
, '25-static.network' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
6617 f
. write ( static_network
)
6620 self
. wait_online ( 'veth99:routable' )
6622 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
6624 self
. assertRegex ( output
, f
'inet {ipv4_address} brd 192.168.5.255 scope global veth99 \n *'
6625 'valid_lft forever preferred_lft forever' )
6627 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
6629 self
. assertRegex ( output
, f
'inet6 {ipv6_address} scope global * \n *'
6630 'valid_lft forever preferred_lft forever' )
6632 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
6633 def test_dhcp_client_vrf ( self
):
6634 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-vrf.network' ,
6635 '25-vrf.netdev' , '25-vrf.network' )
6637 self
. wait_online ( 'veth-peer:carrier' )
6639 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' , 'vrf99:carrier' )
6641 # link become 'routable' when at least one protocol provide an valid address.
6642 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
6643 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
6645 print ( '## ip -d link show dev vrf99' )
6646 output
= check_output ( 'ip -d link show dev vrf99' )
6648 self
. assertRegex ( output
, 'vrf table 42' )
6650 print ( '## ip address show vrf vrf99' )
6651 output
= check_output ( 'ip address show vrf vrf99' )
6653 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
6654 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
6655 self
. assertRegex ( output
, 'inet6 .* scope link' )
6657 print ( '## ip address show dev veth99' )
6658 output
= check_output ( 'ip address show dev veth99' )
6660 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
6661 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
6662 self
. assertRegex ( output
, 'inet6 .* scope link' )
6664 print ( '## ip route show vrf vrf99' )
6665 output
= check_output ( 'ip route show vrf vrf99' )
6667 self
. assertRegex ( output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.' )
6668 self
. assertRegex ( output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5' )
6669 self
. assertRegex ( output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5' )
6671 print ( '## ip route show table main dev veth99' )
6672 output
= check_output ( 'ip route show table main dev veth99' )
6674 self
. assertEqual ( output
, '' )
6676 def test_dhcp_client_gateway_onlink_implicit ( self
):
6677 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
6678 '25-dhcp-client-gateway-onlink-implicit.network' )
6680 self
. wait_online ( 'veth-peer:carrier' )
6682 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6684 output
= networkctl_status ( 'veth99' )
6686 self
. assertRegex ( output
, '192.168.5' )
6688 output
= check_output ( 'ip route list dev veth99 10.0.0.0/8' )
6690 self
. assertRegex ( output
, 'onlink' )
6691 output
= check_output ( 'ip route list dev veth99 192.168.100.0/24' )
6693 self
. assertRegex ( output
, 'onlink' )
6695 def test_dhcp_client_with_ipv4ll ( self
):
6696 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
6697 '25-dhcp-client-with-ipv4ll.network' )
6699 # we need to increase timeout above default, as this will need to wait for
6700 # systemd-networkd to get the dhcpv4 transient failure event
6701 self
. wait_online ( 'veth99:degraded' , 'veth-peer:routable' , timeout
= '60s' )
6703 output
= check_output ( 'ip -4 address show dev veth99' )
6705 self
. assertNotIn ( '192.168.5.' , output
)
6706 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
6709 print ( 'Wait for a DHCP lease to be acquired and the IPv4LL address to be dropped' )
6710 self
. wait_address ( 'veth99' , r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic' , ipv
= '-4' )
6711 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' )
6712 self
. wait_online ( 'veth99:routable' )
6714 output
= check_output ( 'ip -4 address show dev veth99' )
6716 self
. assertRegex ( output
, r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99' )
6717 self
. assertNotIn ( '169.254.' , output
)
6718 self
. assertNotIn ( 'scope link' , output
)
6721 print ( 'Wait for the DHCP lease to be expired and an IPv4LL address to be acquired' )
6722 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 )
6723 self
. wait_address ( 'veth99' , r
'inet 169\.254\.133\.11/16 metric 2048 brd 169\.254\.255\.255 scope link' , scope
= 'link' , ipv
= '-4' )
6725 output
= check_output ( 'ip -4 address show dev veth99' )
6727 self
. assertNotIn ( '192.168.5.' , output
)
6728 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
6730 def test_dhcp_client_use_dns ( self
):
6731 def check ( self
, ipv4
, ipv6
):
6732 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
6733 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
6734 f
. write ( '[DHCPv4] \n UseDNS=' )
6735 f
. write ( 'yes' if ipv4
else 'no' )
6736 f
. write ( ' \n [DHCPv6] \n UseDNS=' )
6737 f
. write ( 'yes' if ipv6
else 'no' )
6738 f
. write ( ' \n [IPv6AcceptRA] \n UseDNS=no' )
6741 self
. wait_online ( 'veth99:routable' )
6743 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
6744 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
6745 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
6747 # make resolved re-read the link state file
6748 resolvectl ( 'revert' , 'veth99' )
6750 output
= resolvectl ( 'dns' , 'veth99' )
6753 self
. assertIn ( '192.168.5.1' , output
)
6755 self
. assertNotIn ( '192.168.5.1' , output
)
6757 self
. assertIn ( '2600::1' , output
)
6759 self
. assertNotIn ( '2600::1' , output
)
6761 check_json ( networkctl_json ())
6763 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
6766 self
. wait_online ( 'veth-peer:carrier' )
6767 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1' ,
6768 '--dhcp-option=option6:dns-server,[2600::1]' )
6770 check ( self
, True , True )
6771 check ( self
, True , False )
6772 check ( self
, False , True )
6773 check ( self
, False , False )
6775 def test_dhcp_client_use_captive_portal ( self
):
6776 def check ( self
, ipv4
, ipv6
):
6777 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
6778 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
6779 f
. write ( '[DHCPv4] \n UseCaptivePortal=' )
6780 f
. write ( 'yes' if ipv4
else 'no' )
6781 f
. write ( ' \n [DHCPv6] \n UseCaptivePortal=' )
6782 f
. write ( 'yes' if ipv6
else 'no' )
6783 f
. write ( ' \n [IPv6AcceptRA] \n UseCaptivePortal=no' )
6786 self
. wait_online ( 'veth99:routable' )
6788 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
6789 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
6790 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
6792 output
= networkctl_status ( 'veth99' )
6795 self
. assertIn ( 'Captive Portal: http://systemd.io' , output
)
6797 self
. assertNotIn ( 'Captive Portal: http://systemd.io' , output
)
6799 check_json ( networkctl_json ())
6801 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
6804 self
. wait_online ( 'veth-peer:carrier' )
6805 start_dnsmasq ( '--dhcp-option=114,http://systemd.io' ,
6806 '--dhcp-option=option6:103,http://systemd.io' )
6808 check ( self
, True , True )
6809 check ( self
, True , False )
6810 check ( self
, False , True )
6811 check ( self
, False , False )
6813 def test_dhcp_client_reject_captive_portal ( self
):
6814 def check ( self
, ipv4
, ipv6
):
6815 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
6816 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
6817 f
. write ( '[DHCPv4] \n UseCaptivePortal=' )
6818 f
. write ( 'yes' if ipv4
else 'no' )
6819 f
. write ( ' \n [DHCPv6] \n UseCaptivePortal=' )
6820 f
. write ( 'yes' if ipv6
else 'no' )
6821 f
. write ( ' \n [IPv6AcceptRA] \n UseCaptivePortal=no' )
6824 self
. wait_online ( 'veth99:routable' )
6826 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
6827 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
6828 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
6830 output
= networkctl_status ( 'veth99' )
6832 self
. assertNotIn ( 'Captive Portal: ' , output
)
6833 self
. assertNotIn ( 'invalid/url' , output
)
6835 check_json ( networkctl_json ())
6837 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
6840 self
. wait_online ( 'veth-peer:carrier' )
6841 masq
= lambda bs
: ':' . join ( f
'{b:02x}' for b
in bs
)
6842 start_dnsmasq ( '--dhcp-option=114,' + masq ( b
'http:// \x00 invalid/url' ),
6843 '--dhcp-option=option6:103,' + masq ( b
'http:// \x00 /invalid/url' ))
6845 check ( self
, True , True )
6846 check ( self
, True , False )
6847 check ( self
, False , True )
6848 check ( self
, False , False )
6850 class NetworkdDHCPPDTests ( unittest
. TestCase
, Utilities
):
6858 def check_dhcp6_prefix ( self
, link
):
6859 description
= get_link_description ( link
)
6861 self
. assertIn ( 'DHCPv6Client' , description
. keys ())
6862 self
. assertIn ( 'Prefixes' , description
[ 'DHCPv6Client' ])
6864 prefixInfo
= description
[ 'DHCPv6Client' ][ 'Prefixes' ]
6866 self
. assertEqual ( len ( prefixInfo
), 1 )
6868 self
. assertIn ( 'Prefix' , prefixInfo
[ 0 ]. keys ())
6869 self
. assertIn ( 'PrefixLength' , prefixInfo
[ 0 ]. keys ())
6870 self
. assertIn ( 'PreferredLifetimeUSec' , prefixInfo
[ 0 ]. keys ())
6871 self
. assertIn ( 'ValidLifetimeUSec' , prefixInfo
[ 0 ]. keys ())
6873 self
. assertEqual ( prefixInfo
[ 0 ][ 'Prefix' ][ 0 : 6 ], [ 63 , 254 , 5 , 1 , 255 , 255 ])
6874 self
. assertEqual ( prefixInfo
[ 0 ][ 'PrefixLength' ], 56 )
6875 self
. assertGreater ( prefixInfo
[ 0 ][ 'PreferredLifetimeUSec' ], 0 )
6876 self
. assertGreater ( prefixInfo
[ 0 ][ 'ValidLifetimeUSec' ], 0 )
6878 def test_dhcp6pd_no_address ( self
):
6880 copy_network_unit ( '25-veth.netdev' , '25-dhcp6pd-server.network' , '25-dhcp6pd-upstream-no-address.network' )
6883 self
. wait_online ( 'veth-peer:routable' )
6884 start_isc_dhcpd ( conf_file
= 'isc-dhcpd-dhcp6pd.conf' , ipv
= '-6' )
6885 self
. wait_online ( 'veth99:degraded' )
6887 print ( '### ip -6 address show dev veth99 scope global' )
6888 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
6890 self
. assertNotIn ( 'inet6 3ffe:501:ffff' , output
)
6892 self
. check_dhcp6_prefix ( 'veth99' )
6894 def test_dhcp6pd_no_assign ( self
):
6895 # Similar to test_dhcp6pd_no_assign(), but in this case UseAddress=yes (default),
6896 # However, the server does not provide IA_NA. For issue #31349.
6897 copy_network_unit ( '25-veth.netdev' , '25-dhcp6pd-server.network' , '25-dhcp6pd-upstream-no-assign.network' )
6900 self
. wait_online ( 'veth-peer:routable' )
6901 start_isc_dhcpd ( conf_file
= 'isc-dhcpd-dhcp6pd-no-range.conf' , ipv
= '-6' )
6902 self
. wait_online ( 'veth99:degraded' )
6904 print ( '### ip -6 address show dev veth99 scope global' )
6905 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
6907 self
. assertNotIn ( 'inet6 3ffe:501:ffff' , output
)
6909 self
. check_dhcp6_prefix ( 'veth99' )
6911 def test_dhcp6pd ( self
):
6912 copy_network_unit ( '25-veth.netdev' , '25-dhcp6pd-server.network' , '25-dhcp6pd-upstream.network' ,
6913 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
6914 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
6915 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
6916 '25-dhcp-pd-downstream-dummy97.network' ,
6917 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
6918 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' )
6921 self
. wait_online ( 'veth-peer:routable' )
6922 start_isc_dhcpd ( conf_file
= 'isc-dhcpd-dhcp6pd.conf' , ipv
= '-6' )
6923 self
. wait_online ( 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
6924 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' )
6926 self
. setup_nftset ( 'addr6' , 'ipv6_addr' )
6927 self
. setup_nftset ( 'network6' , 'ipv6_addr' , 'flags interval;' )
6928 self
. setup_nftset ( 'ifindex' , 'iface_index' )
6930 # Check DBus assigned prefix information to veth99
6931 self
. check_dhcp6_prefix ( 'veth99' )
6933 print ( '### ip -6 address show dev veth-peer scope global' )
6934 output
= check_output ( 'ip -6 address show dev veth-peer scope global' )
6936 self
. assertIn ( 'inet6 3ffe:501:ffff:100::1/64 scope global' , output
)
6940 # dummy97: 0x01 (The link will appear later)
6942 # dummy99: auto -> 0x02 (No address assignment)
6947 print ( '### ip -6 address show dev veth99 scope global' )
6948 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
6951 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:100::[0-9]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
6952 # address in IA_PD (Token=static)
6953 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic' )
6954 # address in IA_PD (Token=eui64)
6955 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic' )
6956 # address in IA_PD (temporary)
6957 # Note that the temporary addresses may appear after the link enters configured state
6958 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' )
6960 print ( '### ip -6 address show dev test1 scope global' )
6961 output
= check_output ( 'ip -6 address show dev test1 scope global' )
6963 # address in IA_PD (Token=static)
6964 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6965 # address in IA_PD (temporary)
6966 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' )
6968 print ( '### ip -6 address show dev dummy98 scope global' )
6969 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
6971 # address in IA_PD (Token=static)
6972 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6973 # address in IA_PD (temporary)
6974 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' )
6976 print ( '### ip -6 address show dev dummy99 scope global' )
6977 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
6980 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
6982 print ( '### ip -6 address show dev veth97 scope global' )
6983 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
6985 # address in IA_PD (Token=static)
6986 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6987 # address in IA_PD (Token=eui64)
6988 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6989 # address in IA_PD (temporary)
6990 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' )
6992 print ( '### ip -6 address show dev veth97-peer scope global' )
6993 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
6995 # NDisc address (Token=static)
6996 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6997 # NDisc address (Token=eui64)
6998 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
6999 # NDisc address (temporary)
7000 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' )
7002 print ( '### ip -6 address show dev veth98 scope global' )
7003 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
7005 # address in IA_PD (Token=static)
7006 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7007 # address in IA_PD (Token=eui64)
7008 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7009 # address in IA_PD (temporary)
7010 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' )
7012 print ( '### ip -6 address show dev veth98-peer scope global' )
7013 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
7015 # NDisc address (Token=static)
7016 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7017 # NDisc address (Token=eui64)
7018 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7019 # NDisc address (temporary)
7020 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' )
7022 print ( '### ip -6 route show type unreachable' )
7023 output
= check_output ( 'ip -6 route show type unreachable' )
7025 self
. assertRegex ( output
, 'unreachable 3ffe:501:ffff:[2-9a-f]00::/56 dev lo proto dhcp' )
7027 print ( '### ip -6 route show dev veth99' )
7028 output
= check_output ( 'ip -6 route show dev veth99' )
7030 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]10::/64 proto kernel metric [0-9]* expires' )
7032 print ( '### ip -6 route show dev test1' )
7033 output
= check_output ( 'ip -6 route show dev test1' )
7035 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
7037 print ( '### ip -6 route show dev dummy98' )
7038 output
= check_output ( 'ip -6 route show dev dummy98' )
7040 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
7042 print ( '### ip -6 route show dev dummy99' )
7043 output
= check_output ( 'ip -6 route show dev dummy99' )
7045 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
7047 print ( '### ip -6 route show dev veth97' )
7048 output
= check_output ( 'ip -6 route show dev veth97' )
7050 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto kernel metric [0-9]* expires' )
7052 print ( '### ip -6 route show dev veth97-peer' )
7053 output
= check_output ( 'ip -6 route show dev veth97-peer' )
7055 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto ra metric [0-9]* expires' )
7057 print ( '### ip -6 route show dev veth98' )
7058 output
= check_output ( 'ip -6 route show dev veth98' )
7060 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto kernel metric [0-9]* expires' )
7062 print ( '### ip -6 route show dev veth98-peer' )
7063 output
= check_output ( 'ip -6 route show dev veth98-peer' )
7065 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto ra metric [0-9]* expires' )
7067 # Test case for a downstream which appears later
7068 check_output ( 'ip link add dummy97 type dummy' )
7069 self
. wait_online ( 'dummy97:routable' )
7071 print ( '### ip -6 address show dev dummy97 scope global' )
7072 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
7074 # address in IA_PD (Token=static)
7075 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7076 # address in IA_PD (temporary)
7077 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' )
7079 print ( '### ip -6 route show dev dummy97' )
7080 output
= check_output ( 'ip -6 route show dev dummy97' )
7082 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]01::/64 proto kernel metric [0-9]* expires' )
7084 # Test case for reconfigure
7085 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
7086 self
. wait_online ( 'dummy98:routable' , 'dummy99:degraded' )
7088 print ( '### ip -6 address show dev dummy98 scope global' )
7089 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
7091 # address in IA_PD (Token=static)
7092 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7093 # address in IA_PD (temporary)
7094 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' )
7096 print ( '### ip -6 address show dev dummy99 scope global' )
7097 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
7100 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
7102 print ( '### ip -6 route show dev dummy98' )
7103 output
= check_output ( 'ip -6 route show dev dummy98' )
7105 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
7107 print ( '### ip -6 route show dev dummy99' )
7108 output
= check_output ( 'ip -6 route show dev dummy99' )
7110 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
7112 self
. check_netlabel ( 'dummy98' , '3ffe:501:ffff:[2-9a-f]00::/64' )
7114 self
. check_nftset ( 'addr6' , '3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d' )
7115 self
. check_nftset ( 'addr6' , '3ffe:501:ffff:[2-9a-f]00:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*' )
7116 self
. check_nftset ( 'network6' , '3ffe:501:ffff:[2-9a-f]00::/64' )
7117 self
. check_nftset ( 'ifindex' , 'dummy98' )
7119 self
. teardown_nftset ( 'addr6' , 'network6' , 'ifindex' )
7121 def verify_dhcp4_6rd ( self
, tunnel_name
):
7122 print ( '### ip -4 address show dev veth-peer scope global' )
7123 output
= check_output ( 'ip -4 address show dev veth-peer scope global' )
7125 self
. assertIn ( 'inet 10.0.0.1/8 brd 10.255.255.255 scope global veth-peer' , output
)
7129 # dummy97: 0x01 (The link will appear later)
7131 # dummy99: auto -> 0x0[23] (No address assignment)
7132 # 6rd-XXX: auto -> 0x0[23]
7137 print ( '### ip -4 address show dev veth99 scope global' )
7138 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
7140 self
. assertRegex ( output
, 'inet 10.100.100.[0-9]*/8 (metric 1024 |)brd 10.255.255.255 scope global dynamic veth99' )
7142 print ( '### ip -6 address show dev veth99 scope global' )
7143 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
7145 # address in IA_PD (Token=static)
7146 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7147 # address in IA_PD (Token=eui64)
7148 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7149 # address in IA_PD (temporary)
7150 # Note that the temporary addresses may appear after the link enters configured state
7151 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' )
7153 print ( '### ip -6 address show dev test1 scope global' )
7154 output
= check_output ( 'ip -6 address show dev test1 scope global' )
7156 # address in IA_PD (Token=static)
7157 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7158 # address in IA_PD (temporary)
7159 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' )
7161 print ( '### ip -6 address show dev dummy98 scope global' )
7162 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
7164 # address in IA_PD (Token=static)
7165 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7166 # address in IA_PD (temporary)
7167 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' )
7169 print ( '### ip -6 address show dev dummy99 scope global' )
7170 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
7173 self
. assertNotRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+0[23]' )
7175 print ( '### ip -6 address show dev veth97 scope global' )
7176 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
7178 # address in IA_PD (Token=static)
7179 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7180 # address in IA_PD (Token=eui64)
7181 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7182 # address in IA_PD (temporary)
7183 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' )
7185 print ( '### ip -6 address show dev veth97-peer scope global' )
7186 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
7188 # NDisc address (Token=static)
7189 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7190 # NDisc address (Token=eui64)
7191 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7192 # NDisc address (temporary)
7193 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' )
7195 print ( '### ip -6 address show dev veth98 scope global' )
7196 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
7198 # address in IA_PD (Token=static)
7199 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7200 # address in IA_PD (Token=eui64)
7201 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7202 # address in IA_PD (temporary)
7203 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' )
7205 print ( '### ip -6 address show dev veth98-peer scope global' )
7206 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
7208 # NDisc address (Token=static)
7209 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7210 # NDisc address (Token=eui64)
7211 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7212 # NDisc address (temporary)
7213 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' )
7215 print ( '### ip -6 route show type unreachable' )
7216 output
= check_output ( 'ip -6 route show type unreachable' )
7218 self
. assertRegex ( output
, 'unreachable 2001:db8:6464:[0-9a-f]+00::/56 dev lo proto dhcp' )
7220 print ( '### ip -6 route show dev veth99' )
7221 output
= check_output ( 'ip -6 route show dev veth99' )
7223 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+10::/64 proto kernel metric [0-9]* expires' )
7225 print ( '### ip -6 route show dev test1' )
7226 output
= check_output ( 'ip -6 route show dev test1' )
7228 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
7230 print ( '### ip -6 route show dev dummy98' )
7231 output
= check_output ( 'ip -6 route show dev dummy98' )
7233 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
7235 print ( '### ip -6 route show dev dummy99' )
7236 output
= check_output ( 'ip -6 route show dev dummy99' )
7238 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto dhcp metric [0-9]* expires' )
7240 print ( '### ip -6 route show dev veth97' )
7241 output
= check_output ( 'ip -6 route show dev veth97' )
7243 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto kernel metric [0-9]* expires' )
7245 print ( '### ip -6 route show dev veth97-peer' )
7246 output
= check_output ( 'ip -6 route show dev veth97-peer' )
7248 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto ra metric [0-9]* expires' )
7250 print ( '### ip -6 route show dev veth98' )
7251 output
= check_output ( 'ip -6 route show dev veth98' )
7253 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto kernel metric [0-9]* expires' )
7255 print ( '### ip -6 route show dev veth98-peer' )
7256 output
= check_output ( 'ip -6 route show dev veth98-peer' )
7258 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto ra metric [0-9]* expires' )
7260 print ( '### ip -6 address show dev dummy97 scope global' )
7261 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
7263 # address in IA_PD (Token=static)
7264 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7265 # address in IA_PD (temporary)
7266 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' )
7268 print ( '### ip -6 route show dev dummy97' )
7269 output
= check_output ( 'ip -6 route show dev dummy97' )
7271 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+01::/64 proto kernel metric [0-9]* expires' )
7273 print ( f
'### ip -d link show dev {tunnel_name} ' )
7274 output
= check_output ( f
'ip -d link show dev {tunnel_name} ' )
7276 self
. assertIn ( 'link/sit 10.100.100.' , output
)
7277 self
. assertIn ( 'local 10.100.100.' , output
)
7278 self
. assertIn ( 'ttl 64' , output
)
7279 self
. assertIn ( '6rd-prefix 2001:db8::/32' , output
)
7280 self
. assertIn ( '6rd-relay_prefix 10.0.0.0/8' , output
)
7282 print ( f
'### ip -6 address show dev {tunnel_name} ' )
7283 output
= check_output ( f
'ip -6 address show dev {tunnel_name} ' )
7285 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' )
7286 self
. assertRegex ( output
, 'inet6 ::10.100.100.[0-9]+/96 scope global' )
7288 print ( f
'### ip -6 route show dev {tunnel_name} ' )
7289 output
= check_output ( f
'ip -6 route show dev {tunnel_name} ' )
7291 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto kernel metric [0-9]* expires' )
7292 self
. assertRegex ( output
, '::/96 proto kernel metric [0-9]*' )
7294 print ( '### ip -6 route show default' )
7295 output
= check_output ( 'ip -6 route show default' )
7297 self
. assertIn ( 'default' , output
)
7298 self
. assertIn ( f
'via ::10.0.0.1 dev {tunnel_name} ' , output
)
7300 def test_dhcp4_6rd ( self
):
7301 def get_dhcp_6rd_prefix ( link
):
7302 description
= get_link_description ( link
)
7304 self
. assertIn ( 'DHCPv4Client' , description
. keys ())
7305 self
. assertIn ( '6rdPrefix' , description
[ 'DHCPv4Client' ]. keys ())
7307 prefixInfo
= description
[ 'DHCPv4Client' ][ '6rdPrefix' ]
7308 self
. assertIn ( 'Prefix' , prefixInfo
. keys ())
7309 self
. assertIn ( 'PrefixLength' , prefixInfo
. keys ())
7310 self
. assertIn ( 'IPv4MaskLength' , prefixInfo
. keys ())
7311 self
. assertIn ( 'BorderRouters' , prefixInfo
. keys ())
7315 copy_network_unit ( '25-veth.netdev' , '25-dhcp4-6rd-server.network' , '25-dhcp4-6rd-upstream.network' ,
7316 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
7317 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
7318 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
7319 '25-dhcp-pd-downstream-dummy97.network' ,
7320 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
7321 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' ,
7322 '80-6rd-tunnel.network' )
7325 self
. wait_online ( 'veth-peer:routable' )
7328 # 6rd-prefix: 2001:db8::/32
7329 # br-addresss: 10.0.0.1
7331 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' ,
7332 ipv4_range
= '10.100.100.100,10.100.100.200' ,
7333 ipv4_router
= '10.0.0.1' )
7334 self
. wait_online ( 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
7335 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' )
7337 # Check the DBus interface for assigned prefix information
7338 prefixInfo
= get_dhcp_6rd_prefix ( 'veth99' )
7340 self
. assertEqual ( prefixInfo
[ 'Prefix' ], [ 32 , 1 , 13 , 184 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ]) # 2001:db8::
7341 self
. assertEqual ( prefixInfo
[ 'PrefixLength' ], 32 )
7342 self
. assertEqual ( prefixInfo
[ 'IPv4MaskLength' ], 8 )
7343 self
. assertEqual ( prefixInfo
[ 'BorderRouters' ], [[ 10 , 0 , 0 , 1 ]])
7345 # Test case for a downstream which appears later
7346 check_output ( 'ip link add dummy97 type dummy' )
7347 self
. wait_online ( 'dummy97:routable' )
7351 for name
in os
. listdir ( '/sys/class/net/' ):
7352 if name
. startswith ( '6rd-' ):
7356 self
. wait_online ( f
' {tunnel_name} :routable' )
7358 self
. verify_dhcp4_6rd ( tunnel_name
)
7360 # Test case for reconfigure
7361 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
7362 self
. wait_online ( 'dummy98:routable' , 'dummy99:degraded' )
7364 self
. verify_dhcp4_6rd ( tunnel_name
)
7366 print ( 'Wait for the DHCP lease to be renewed/rebind' )
7369 self
. wait_online ( 'veth99:routable' , 'test1:routable' , 'dummy97:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
7370 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' )
7372 self
. verify_dhcp4_6rd ( tunnel_name
)
7374 class NetworkdIPv6PrefixTests ( unittest
. TestCase
, Utilities
):
7382 def test_ipv6_route_prefix ( self
):
7383 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client.network' , '25-ipv6ra-prefix.network' ,
7384 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
7387 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' )
7389 output
= check_output ( 'ip address show dev veth-peer' )
7391 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
7392 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
7393 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
7395 output
= check_output ( 'ip -6 route show dev veth-peer' )
7397 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
7398 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
7399 self
. assertNotIn ( '2001:db8:0:3::/64 proto ra' , output
)
7400 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
7401 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
7402 self
. assertNotIn ( '2001:db2:fff::/64 via ' , output
)
7404 output
= check_output ( 'ip address show dev veth99' )
7406 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
7407 self
. assertIn ( 'inet6 2001:db8:0:2:1a:2b:3c:4d' , output
)
7408 self
. assertIn ( 'inet6 2001:db8:0:2:fa:de:ca:fe' , output
)
7409 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
7411 output
= resolvectl ( 'dns' , 'veth-peer' )
7413 self
. assertRegex ( output
, '2001:db8:1:1::2' )
7415 output
= resolvectl ( 'domain' , 'veth-peer' )
7417 self
. assertIn ( 'example.com' , output
)
7419 check_json ( networkctl_json ())
7421 output
= networkctl_json ( 'veth-peer' )
7425 pref64
= json
. loads ( output
)[ 'NDisc' ][ 'PREF64' ][ 0 ]
7427 prefix
= socket
. inet_ntop ( socket
. AF_INET6
, bytearray ( pref64
[ 'Prefix' ]))
7428 self
. assertEqual ( prefix
, '64:ff9b::' )
7430 prefix_length
= pref64
[ 'PrefixLength' ]
7431 self
. assertEqual ( prefix_length
, 96 )
7433 def test_ipv6_route_prefix_deny_list ( self
):
7434 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client-deny-list.network' , '25-ipv6ra-prefix.network' ,
7435 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
7438 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' )
7440 output
= check_output ( 'ip address show dev veth-peer' )
7442 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
7443 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
7445 output
= check_output ( 'ip -6 route show dev veth-peer' )
7447 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
7448 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
7449 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
7450 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
7452 output
= check_output ( 'ip address show dev veth99' )
7454 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
7455 self
. assertIn ( 'inet6 2001:db8:0:2:' , output
)
7457 output
= resolvectl ( 'dns' , 'veth-peer' )
7459 self
. assertRegex ( output
, '2001:db8:1:1::2' )
7461 output
= resolvectl ( 'domain' , 'veth-peer' )
7463 self
. assertIn ( 'example.com' , output
)
7465 class NetworkdMTUTests ( unittest
. TestCase
, Utilities
):
7473 def check_mtu ( self
, mtu
, ipv6_mtu
= None , reset
= True ):
7479 self
. wait_online ( 'dummy98:routable' )
7480 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
7481 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
7483 # test normal restart
7485 self
. wait_online ( 'dummy98:routable' )
7486 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
7487 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
7490 self
. reset_check_mtu ( mtu
, ipv6_mtu
)
7492 def reset_check_mtu ( self
, mtu
, ipv6_mtu
= None ):
7493 ''' test setting mtu/ipv6_mtu with interface already up '''
7496 # note - changing the device mtu resets the ipv6 mtu
7497 check_output ( 'ip link set up mtu 1501 dev dummy98' )
7498 check_output ( 'ip link set up mtu 1500 dev dummy98' )
7499 self
. check_link_attr ( 'dummy98' , 'mtu' , '1500' )
7500 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , '1500' )
7502 self
. check_mtu ( mtu
, ipv6_mtu
, reset
= False )
7504 def test_mtu_network ( self
):
7505 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' )
7506 self
. check_mtu ( '1600' )
7508 def test_mtu_netdev ( self
):
7509 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network' , copy_dropins
= False )
7510 # note - MTU set by .netdev happens ONLY at device creation!
7511 self
. check_mtu ( '1600' , reset
= False )
7513 def test_mtu_link ( self
):
7514 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network' , copy_dropins
= False )
7515 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
7516 self
. check_mtu ( '1600' , reset
= False )
7518 def test_ipv6_mtu ( self
):
7519 ''' set ipv6 mtu without setting device mtu '''
7520 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1400.conf' )
7521 self
. check_mtu ( '1500' , '1400' )
7523 def test_ipv6_mtu_toolarge ( self
):
7524 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
7525 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
7526 self
. check_mtu ( '1500' , '1500' )
7528 def test_mtu_network_ipv6_mtu ( self
):
7529 ''' set ipv6 mtu and set device mtu via network file '''
7530 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
7531 self
. check_mtu ( '1600' , '1550' )
7533 def test_mtu_netdev_ipv6_mtu ( self
):
7534 ''' set ipv6 mtu and set device mtu via netdev file '''
7535 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
7536 self
. check_mtu ( '1600' , '1550' , reset
= False )
7538 def test_mtu_link_ipv6_mtu ( self
):
7539 ''' set ipv6 mtu and set device mtu via link file '''
7540 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
7541 self
. check_mtu ( '1600' , '1550' , reset
= False )
7544 if __name__
== '__main__' :
7545 parser
= argparse
. ArgumentParser ()
7546 parser
. add_argument ( '--build-dir' , help = 'Path to build dir' , dest
= 'build_dir' )
7547 parser
. add_argument ( '--source-dir' , help = 'Path to source dir/git tree' , dest
= 'source_dir' )
7548 parser
. add_argument ( '--valgrind' , help = 'Enable valgrind' , dest
= 'use_valgrind' , type = bool , nargs
= '?' , const
= True , default
= use_valgrind
)
7549 parser
. add_argument ( '--debug' , help = 'Generate debugging logs' , dest
= 'enable_debug' , type = bool , nargs
= '?' , const
= True , default
= enable_debug
)
7550 parser
. add_argument ( '--asan-options' , help = 'ASAN options' , dest
= 'asan_options' )
7551 parser
. add_argument ( '--lsan-options' , help = 'LSAN options' , dest
= 'lsan_options' )
7552 parser
. add_argument ( '--ubsan-options' , help = 'UBSAN options' , dest
= 'ubsan_options' )
7553 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
)
7554 ns
, unknown_args
= parser
. parse_known_args ( namespace
= unittest
)
7557 networkd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd' )
7558 resolved_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-resolved' )
7559 timesyncd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-timesyncd' )
7560 wait_online_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd-wait-online' )
7561 networkctl_bin
= os
. path
. join ( ns
. build_dir
, 'networkctl' )
7562 resolvectl_bin
= os
. path
. join ( ns
. build_dir
, 'resolvectl' )
7563 timedatectl_bin
= os
. path
. join ( ns
. build_dir
, 'timedatectl' )
7564 udevadm_bin
= os
. path
. join ( ns
. build_dir
, 'udevadm' )
7565 build_dir
= ns
. build_dir
7568 source_dir
= ns
. source_dir
7570 source_dir
= os
. path
. normpath ( os
. path
. join ( os
. path
. dirname ( os
. path
. abspath ( __file__
)), "../../" ))
7571 assert os
. path
. exists ( os
. path
. join ( source_dir
, "meson_options.txt" )), f
" {source_dir} doesn't appear to be a systemd source tree."
7573 use_valgrind
= ns
. use_valgrind
7574 enable_debug
= ns
. enable_debug
7575 asan_options
= ns
. asan_options
7576 lsan_options
= ns
. lsan_options
7577 ubsan_options
= ns
. ubsan_options
7578 with_coverage
= ns
. with_coverage
7581 # Do not forget the trailing space.
7582 valgrind_cmd
= 'valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all '
7584 networkctl_cmd
= valgrind_cmd
. split () + [ networkctl_bin
]
7585 resolvectl_cmd
= valgrind_cmd
. split () + [ resolvectl_bin
]
7586 timedatectl_cmd
= valgrind_cmd
. split () + [ timedatectl_bin
]
7587 udevadm_cmd
= valgrind_cmd
. split () + [ udevadm_bin
]
7588 wait_online_cmd
= valgrind_cmd
. split () + [ wait_online_bin
]
7591 env
. update ({ 'ASAN_OPTIONS' : asan_options
})
7593 env
. update ({ 'LSAN_OPTIONS' : lsan_options
})
7595 env
. update ({ 'UBSAN_OPTIONS' : ubsan_options
})
7597 env
. update ({ 'SYSTEMD_MEMPOOL' : '0' })
7599 wait_online_env
= env
. copy ()
7601 wait_online_env
. update ({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
7603 sys
. argv
[ 1 :] = unknown_args
7604 unittest
. main ( verbosity
= 3 )