]>
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
)
63 test_ndisc_send
= None
76 show_journal
= True # When true, show journal on stopping networkd.
94 saved_ipv4_rules
= None
95 saved_ipv6_rules
= None
99 if os
. path
. exists ( path
):
103 shutil
. rmtree ( path
, ignore_errors
= True )
106 shutil
. copy ( src
, dst
)
109 shutil
. copytree ( src
, dst
, copy_function
= shutil
. copy
, dirs_exist_ok
= True )
112 os
. makedirs ( path
, exist_ok
= True )
115 pathlib
. Path ( path
). touch ()
117 # pylint: disable=R1710
118 def check_output (* command
, ** kwargs
):
119 # This checks the result and returns stdout (and stderr) on success.
120 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
121 ret
= subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. PIPE
, stderr
= subprocess
. STDOUT
, ** kwargs
)
122 if ret
. returncode
== 0 :
123 return ret
. stdout
. rstrip ()
124 # When returncode != 0, print stdout and stderr, then trigger CalledProcessError.
126 ret
. check_returncode ()
128 def call (* command
, ** kwargs
):
129 # This returns returncode. stdout and stderr are merged and shown in console
130 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
131 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stderr
= subprocess
. STDOUT
, ** kwargs
). returncode
133 def call_check (* command
, ** kwargs
):
134 # Same as call() above, but it triggers CalledProcessError if rc != 0
135 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
136 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stderr
= subprocess
. STDOUT
, ** kwargs
). check_returncode ()
138 def call_quiet (* command
, ** kwargs
):
139 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
140 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. DEVNULL
, stderr
= subprocess
. DEVNULL
, ** kwargs
). returncode
142 def run (* command
, ** kwargs
):
143 # This returns CompletedProcess instance.
144 command
= command
[ 0 ]. split () + list ( command
[ 1 :])
145 return subprocess
. run ( command
, check
= False , universal_newlines
= True , stdout
= subprocess
. PIPE
, stderr
= subprocess
. PIPE
, ** kwargs
)
147 def check_json ( string
):
150 except json
. JSONDecodeError
:
151 print ( f
"String is not a valid JSON: ' {string} '" )
154 def is_module_available (* module_names
):
155 for module_name
in module_names
:
156 lsmod_output
= check_output ( 'lsmod' )
157 module_re
= re
. compile ( rf
'^{re.escape(module_name)} \b ' , re
. MULTILINE
)
158 if not module_re
. search ( lsmod_output
) and call_quiet ( 'modprobe' , module_name
) != 0 :
162 def expectedFailureIfModuleIsNotAvailable (* module_names
):
164 return func
if is_module_available (* module_names
) else unittest
. expectedFailure ( func
)
168 def expectedFailureIfERSPANv0IsNotSupported ():
169 # erspan version 0 is supported since f989d546a2d5a9f001f6f8be49d98c10ab9b1897 (v5.8)
171 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' )
172 remove_link ( 'erspan99' )
173 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
177 def expectedFailureIfERSPANv2IsNotSupported ():
178 # erspan version 2 is supported since f551c91de262ba36b20c3ac19538afb4f4507441 (v4.16)
180 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' )
181 remove_link ( 'erspan99' )
182 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
186 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable ():
188 rc
= call_quiet ( 'ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7' )
189 call_quiet ( 'ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7' )
190 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
194 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable ():
196 # IP protocol name is parsed by getprotobyname(), and it requires /etc/protocols.
197 # Hence. here we use explicit number: 6 == tcp.
198 rc
= call_quiet ( 'ip rule add not from 192.168.100.19 ipproto 6 table 7' )
199 call_quiet ( 'ip rule del not from 192.168.100.19 ipproto 6 table 7' )
200 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
204 def expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable ():
207 if call_quiet ( 'ip rule add from 192.168.100.19 table 7 uidrange 200-300' ) == 0 :
208 ret
= run ( 'ip rule list from 192.168.100.19 table 7' )
209 supported
= ret
. returncode
== 0 and 'uidrange 200-300' in ret
. stdout
210 call_quiet ( 'ip rule del from 192.168.100.19 table 7 uidrange 200-300' )
211 return func
if supported
else unittest
. expectedFailure ( func
)
215 def expectedFailureIfRoutingPolicyL3MasterDeviceIsNotAvailable ():
217 rc
= call_quiet ( 'ip rule add not from 192.168.100.19 l3mdev' )
218 call_quiet ( 'ip rule del not from 192.168.100.19 l3mdev' )
219 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
223 def expectedFailureIfNexthopIsNotAvailable ():
225 rc
= call_quiet ( 'ip nexthop list' )
226 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
230 def expectedFailureIfRTA_VIAIsNotSupported ():
232 call_quiet ( 'ip link add dummy98 type dummy' )
233 call_quiet ( 'ip link set up dev dummy98' )
234 call_quiet ( 'ip route add 2001:1234:5:8fff:ff:ff:ff:fe/128 dev dummy98' )
235 rc
= call_quiet ( 'ip route add 10.10.10.10 via inet6 2001:1234:5:8fff:ff:ff:ff:fe dev dummy98' )
236 remove_link ( 'dummy98' )
237 return func
if rc
== 0 else unittest
. expectedFailure ( func
)
241 def expectedFailureIfAlternativeNameIsNotAvailable ():
243 call_quiet ( 'ip link add dummy98 type dummy' )
245 call_quiet ( 'ip link prop add dev dummy98 altname hogehogehogehogehoge' ) == 0 and \
246 call_quiet ( 'ip link show dev hogehogehogehogehoge' ) == 0
247 remove_link ( 'dummy98' )
248 return func
if supported
else unittest
. expectedFailure ( func
)
252 def expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ():
254 def finalize ( func
, supported
):
255 call_quiet ( 'rmmod netdevsim' )
256 return func
if supported
else unittest
. expectedFailure ( func
)
258 call_quiet ( 'rmmod netdevsim' )
259 if call_quiet ( 'modprobe netdevsim' ) != 0 :
260 return finalize ( func
, False )
263 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
266 return finalize ( func
, False )
268 return finalize ( func
, os
. path
. exists ( '/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs' ))
272 def expectedFailureIfKernelReturnsInvalidFlags ():
274 This checks the kernel bug caused by 3ddc2231c8108302a8229d3c5849ee792a63230d (v6.9),
275 fixed by 1af7f88af269c4e06a4dc3bc920ff6cdf7471124 (v6.10, backported to 6.9.3).
278 call_quiet ( 'ip link add dummy98 type dummy' )
279 call_quiet ( 'ip link set up dev dummy98' )
280 call_quiet ( 'ip address add 192.0.2.1/24 dev dummy98 noprefixroute' )
281 output
= check_output ( 'ip address show dev dummy98' )
282 remove_link ( 'dummy98' )
283 return func
if 'noprefixroute' in output
else unittest
. expectedFailure ( func
)
287 # pylint: disable=C0415
288 def compare_kernel_version ( min_kernel_version
):
291 from packaging
import version
293 print ( 'Failed to import either platform or packaging module, assuming the comparison failed' )
296 # Get only the actual kernel version without any build/distro/arch stuff
297 # e.g. '5.18.5-200.fc36.x86_64' -> '5.18.5'
298 kver
= platform
. release (). split ( '-' )[ 0 ]
299 # Get also rid of '+'
300 kver
= kver
. split ( '+' )[ 0 ]
302 return version
. parse ( kver
) >= version
. parse ( min_kernel_version
)
304 def copy_network_unit (* units
, copy_dropins
= True ):
306 Copy networkd unit files into the testbed.
308 Any networkd unit file type can be specified, as well as drop-in files.
310 By default, all drop-ins for a specified unit file are copied in;
311 to avoid that specify dropins=False.
313 When a drop-in file is specified, its unit file is also copied in automatically.
316 mkdir_p ( network_unit_dir
)
318 if copy_dropins
and os
. path
. exists ( os
. path
. join ( networkd_ci_temp_dir
, unit
+ '.d' )):
319 cp_r ( os
. path
. join ( networkd_ci_temp_dir
, unit
+ '.d' ), os
. path
. join ( network_unit_dir
, unit
+ '.d' ))
321 if unit
. endswith ( '.conf' ):
323 unit
= os
. path
. dirname ( dropin
). rstrip ( '.d' )
324 dropindir
= os
. path
. join ( network_unit_dir
, unit
+ '.d' )
326 cp ( os
. path
. join ( networkd_ci_temp_dir
, dropin
), dropindir
)
328 cp ( os
. path
. join ( networkd_ci_temp_dir
, unit
), network_unit_dir
)
330 if unit
. endswith ( '.link' ):
336 def copy_credential ( src
, target
):
337 mkdir_p ( credstore_dir
)
338 cp ( os
. path
. join ( networkd_ci_temp_dir
, src
),
339 os
. path
. join ( credstore_dir
, target
))
341 def remove_network_unit (* units
):
343 Remove previously copied unit files from the testbed.
345 Drop-ins will be removed automatically.
349 rm_f ( os
. path
. join ( network_unit_dir
, unit
))
350 rm_rf ( os
. path
. join ( network_unit_dir
, unit
+ '.d' ))
352 if unit
. endswith ( '.link' ) or unit
. endswith ( '.link.d' ):
358 def clear_network_units ():
360 if os
. path
. exists ( network_unit_dir
):
361 units
= os
. listdir ( network_unit_dir
)
363 if unit
. endswith ( '.link' ) or unit
. endswith ( '.link.d' ):
366 rm_rf ( network_unit_dir
)
371 def copy_networkd_conf_dropin (* dropins
):
372 """Copy networkd.conf dropin files into the testbed."""
373 mkdir_p ( networkd_conf_dropin_dir
)
374 for dropin
in dropins
:
375 cp ( os
. path
. join ( networkd_ci_temp_dir
, dropin
), networkd_conf_dropin_dir
)
377 def remove_networkd_conf_dropin (* dropins
):
378 """Remove previously copied networkd.conf dropin files from the testbed."""
379 for dropin
in dropins
:
380 rm_f ( os
. path
. join ( networkd_conf_dropin_dir
, dropin
))
382 def clear_networkd_conf_dropins ():
383 rm_rf ( networkd_conf_dropin_dir
)
385 def setup_systemd_udev_rules ():
386 if not build_dir
and not source_dir
:
389 mkdir_p ( udev_rules_dir
)
391 for path
in [ build_dir
, source_dir
]:
395 path
= os
. path
. join ( path
, "rules.d" )
396 print ( f
"Copying udev rules from {path} to {udev_rules_dir} " )
398 for rule
in os
. listdir ( path
):
399 if not rule
. endswith ( ".rules" ):
401 cp ( os
. path
. join ( path
, rule
), udev_rules_dir
)
403 def clear_networkd_state_files ():
404 rm_rf ( '/var/lib/systemd/network/' )
406 def copy_udev_rule (* rules
):
407 """Copy udev rules"""
408 mkdir_p ( udev_rules_dir
)
410 cp ( os
. path
. join ( networkd_ci_temp_dir
, rule
), udev_rules_dir
)
412 def remove_udev_rule (* rules
):
413 """Remove previously copied udev rules"""
415 rm_f ( os
. path
. join ( udev_rules_dir
, rule
))
417 def clear_udev_rules ():
418 rm_rf ( udev_rules_dir
)
420 def save_active_units ():
421 for u
in [ 'systemd-networkd.socket' , 'systemd-networkd.service' ,
422 'systemd-resolved.service' , 'systemd-timesyncd.service' ,
423 'firewalld.service' ]:
424 if call ( f
'systemctl is-active --quiet {u} ' ) == 0 :
425 call ( f
'systemctl stop {u} ' )
426 active_units
. append ( u
)
428 def restore_active_units ():
429 if 'systemd-networkd.socket' in active_units
:
430 call ( 'systemctl stop systemd-networkd.socket systemd-networkd.service' )
431 for u
in active_units
:
432 call ( f
'systemctl restart {u} ' )
434 def create_unit_dropin ( unit
, contents
):
435 mkdir_p ( f
'/run/systemd/system/ {unit} .d' )
436 with
open ( f
'/run/systemd/system/ {unit} .d/00-override.conf' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
437 f
. write ( ' \n ' . join ( contents
))
439 def create_service_dropin ( service
, command
, additional_settings
= None ):
440 drop_in
= [ '[Service]' ]
444 f
'ExecStart=!! {valgrind_cmd}{command} ' ,
447 drop_in
+= [ 'Environment=SYSTEMD_LOG_LEVEL=debug' ]
449 drop_in
+= [ f
'Environment=ASAN_OPTIONS=" {asan_options} "' ]
451 drop_in
+= [ f
'Environment=LSAN_OPTIONS=" {lsan_options} "' ]
453 drop_in
+= [ f
'Environment=UBSAN_OPTIONS=" {ubsan_options} "' ]
454 if asan_options
or lsan_options
or ubsan_options
:
455 drop_in
+= [ 'SystemCallFilter=' ]
456 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
457 drop_in
+= [ 'MemoryDenyWriteExecute=no' ]
460 'Environment=SYSTEMD_MEMPOOL=0' ,
468 if additional_settings
:
469 drop_in
+= additional_settings
471 create_unit_dropin ( f
' {service} .service' , drop_in
)
473 def setup_system_units ():
474 if build_dir
or source_dir
:
475 mkdir_p ( '/run/systemd/system/' )
478 'systemd-networkd.service' ,
479 'systemd-networkd.socket' ,
480 'systemd-networkd-persistent-storage.service' ,
481 'systemd-resolved.service' ,
482 'systemd-timesyncd.service' ,
483 'systemd-udevd.service' ,
485 for path
in [ build_dir
, source_dir
]:
489 fullpath
= os
. path
. join ( os
. path
. join ( path
, "units" ), unit
)
490 if os
. path
. exists ( fullpath
):
491 print ( f
"Copying unit file from {fullpath} to /run/systemd/system/" )
492 cp ( fullpath
, '/run/systemd/system/' )
495 create_service_dropin ( 'systemd-networkd' , networkd_bin
,
498 'Environment=SYSTEMD_NETWORK_TEST_MODE=yes' ,
500 'StartLimitIntervalSec=0' ])
501 create_service_dropin ( 'systemd-resolved' , resolved_bin
)
502 create_service_dropin ( 'systemd-timesyncd' , timesyncd_bin
)
504 # TODO: also run udevd with sanitizers, valgrind, or coverage
506 'systemd-udevd.service' ,
510 f
'ExecStart=!!@ {udevadm_bin} systemd-udevd' ,
514 'systemd-networkd.socket' ,
517 'StartLimitIntervalSec=0' ,
521 'systemd-networkd-persistent-storage.service' ,
524 'StartLimitIntervalSec=0' ,
527 f
'ExecStart= {networkctl_bin} persistent-storage yes' ,
529 f
'ExecStop= {networkctl_bin} persistent-storage no' ,
530 'Environment=SYSTEMD_LOG_LEVEL=debug' if enable_debug
else '' ,
534 check_output ( 'systemctl daemon-reload' )
535 print ( check_output ( 'systemctl cat systemd-networkd.service' ))
536 print ( check_output ( 'systemctl cat systemd-networkd-persistent-storage.service' ))
537 print ( check_output ( 'systemctl cat systemd-resolved.service' ))
538 print ( check_output ( 'systemctl cat systemd-timesyncd.service' ))
539 print ( check_output ( 'systemctl cat systemd-udevd.service' ))
540 check_output ( 'systemctl restart systemd-resolved.service' )
541 check_output ( 'systemctl restart systemd-timesyncd.service' )
542 check_output ( 'systemctl restart systemd-udevd.service' )
544 def clear_system_units ():
546 rm_f ( f
'/run/systemd/system/ {name} ' )
547 rm_rf ( f
'/run/systemd/system/ {name} .d' )
549 rm_unit ( 'systemd-networkd.service' )
550 rm_unit ( 'systemd-networkd.socket' )
551 rm_unit ( 'systemd-networkd-persistent-storage.service' )
552 rm_unit ( 'systemd-resolved.service' )
553 rm_unit ( 'systemd-timesyncd.service' )
554 rm_unit ( 'systemd-udevd.service' )
555 check_output ( 'systemctl daemon-reload' )
556 check_output ( 'systemctl restart systemd-udevd.service' )
558 def link_exists (* links
):
560 if call_quiet ( f
'ip link show {link} ' ) != 0 :
564 def link_resolve ( link
):
565 return check_output ( f
'ip link show {link} ' ). split ( ':' )[ 1 ]. strip (). split ( '@' )[ 0 ]
567 def remove_link (* links
, protect
= False ):
569 if protect
and link
in protected_links
:
571 if link_exists ( link
):
572 call ( f
'ip link del dev {link} ' )
574 def save_existing_links ():
575 links
= os
. listdir ( '/sys/class/net' )
577 if link_exists ( link
):
578 protected_links
. add ( link
)
580 print ( '### The following links will be protected:' )
581 print ( ', ' . join ( sorted ( list ( protected_links
))))
583 def unmanage_existing_links ():
584 mkdir_p ( network_unit_dir
)
586 with
open ( os
. path
. join ( network_unit_dir
, '00-unmanaged.network' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
588 for link
in protected_links
:
589 f
. write ( f
'Name= {link} \n ' )
590 f
. write ( ' \n [Link] \n Unmanaged=yes \n ' )
593 links
= os
. listdir ( '/sys/class/net' )
594 remove_link (* links
, protect
= True )
596 def flush_nexthops ():
597 # Currently, the 'ip nexthop' command does not have 'save' and 'restore'.
598 # Hence, we cannot restore nexthops in a simple way.
599 # Let's assume there is no nexthop used in the system
600 call_quiet ( 'ip nexthop flush' )
603 # pylint: disable=global-statement
605 saved_routes
= check_output ( 'ip route show table all' )
606 print ( '### The following routes will be protected:' )
611 output
= check_output ( 'ip route show table all' )
612 for line
in output
. splitlines ():
613 if line
in saved_routes
:
615 if 'proto kernel' in line
:
617 if ' dev ' in line
and not ' dev lo ' in line
:
621 print ( '### Removing routes that did not exist when the test started.' )
623 call ( f
'ip route del {line} ' )
625 def save_routing_policy_rules ():
626 # pylint: disable=global-statement
627 global saved_ipv4_rules
, saved_ipv6_rules
629 output
= check_output ( f
'ip - {ipv} rule show' )
630 print ( f
'### The following IPv {ipv} routing policy rules will be protected:' )
634 saved_ipv4_rules
= save ( 4 )
635 saved_ipv6_rules
= save ( 6 )
637 def flush_routing_policy_rules ():
638 def flush ( ipv
, saved_rules
):
640 output
= check_output ( f
'ip - {ipv} rule show' )
641 for line
in output
. splitlines ():
642 if line
in saved_rules
:
646 print ( f
'### Removing IPv {ipv} routing policy rules that did not exist when the test started.' )
648 words
= line
. replace ( 'lookup [l3mdev-table]' , 'l3mdev' ). split ()
649 priority
= words
[ 0 ]. rstrip ( ':' )
650 call ( f
'ip - {ipv} rule del priority {priority} ' + ' ' . join ( words
[ 1 :]))
652 flush ( 4 , saved_ipv4_rules
)
653 flush ( 6 , saved_ipv6_rules
)
655 def flush_fou_ports ():
656 ret
= run ( 'ip fou show' )
657 if ret
. returncode
!= 0 :
658 return # fou may not be supported
659 for line
in ret
. stdout
. splitlines ():
660 port
= line
. split ()[ 1 ]
661 call ( f
'ip fou del port {port} ' )
663 def flush_l2tp_tunnels ():
665 ret
= run ( 'ip l2tp show tunnel' )
666 if ret
. returncode
!= 0 :
667 return # l2tp may not be supported
668 for line
in ret
. stdout
. splitlines ():
670 if words
[ 0 ] == 'Tunnel' :
671 tid
= words
[ 1 ]. rstrip ( ',' )
672 call ( f
'ip l2tp del tunnel tunnel_id {tid} ' )
675 # Removing L2TP tunnel is asynchronous and slightly takes a time.
678 r
= run ( f
'ip l2tp show tunnel tunnel_id {tid} ' )
679 if r
. returncode
!= 0 or len ( r
. stdout
. rstrip ()) == 0 :
683 print ( f
'Cannot remove L2TP tunnel {tid} , ignoring.' )
686 # pylint: disable=global-statement
687 global saved_timezone
688 r
= run (* timedatectl_cmd
, 'show' , '--value' , '--property' , 'Timezone' , env
= env
)
689 if r
. returncode
== 0 :
690 saved_timezone
= r
. stdout
. rstrip ()
691 print ( f
'### Saved timezone: {saved_timezone} ' )
693 def restore_timezone ():
695 call (* timedatectl_cmd
, 'set-timezone' , f
' {saved_timezone} ' , env
= env
)
697 def read_link_attr (* args
):
698 with
open ( os
. path
. join ( '/sys/class/net' , * args
), encoding
= 'utf-8' ) as f
:
699 return f
. readline (). strip ()
701 def read_manager_state_file ():
702 with
open ( '/run/systemd/netif/state' , encoding
= 'utf-8' ) as f
:
705 def read_link_state_file ( link
):
706 ifindex
= read_link_attr ( link
, 'ifindex' )
707 path
= os
. path
. join ( '/run/systemd/netif/links' , ifindex
)
708 with
open ( path
, encoding
= 'utf-8' ) as f
:
711 def read_ip_sysctl_attr ( link
, attribute
, ipv
):
712 with
open ( os
. path
. join ( '/proc/sys/net' , ipv
, 'conf' , link
, attribute
), encoding
= 'utf-8' ) as f
:
713 return f
. readline (). strip ()
715 def read_ip_neigh_sysctl_attr ( link
, attribute
, ipv
):
716 with
open ( os
. path
. join ( '/proc/sys/net' , ipv
, 'neigh' , link
, attribute
), encoding
= 'utf-8' ) as f
:
717 return f
. readline (). strip ()
719 def read_ipv6_sysctl_attr ( link
, attribute
):
720 return read_ip_sysctl_attr ( link
, attribute
, 'ipv6' )
722 def read_ipv6_neigh_sysctl_attr ( link
, attribute
):
723 return read_ip_neigh_sysctl_attr ( link
, attribute
, 'ipv6' )
725 def read_ipv4_sysctl_attr ( link
, attribute
):
726 return read_ip_sysctl_attr ( link
, attribute
, 'ipv4' )
728 def stop_by_pid_file ( pid_file
):
729 if not os
. path
. exists ( pid_file
):
731 with
open ( pid_file
, 'r' , encoding
= 'utf-8' ) as f
:
732 pid
= f
. read (). rstrip ( ' \t\r\n \0' )
733 os
. kill ( int ( pid
), signal
. SIGTERM
)
737 print ( f
"PID {pid} is still alive, waiting..." )
740 if e
. errno
== errno
. ESRCH
:
742 print ( f
"Unexpected exception when waiting for {pid} to die: {e.errno}" )
745 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' ):
747 ra_mode
= f
', {ra_mode} '
753 f
'--log-facility= {dnsmasq_log_file} ' ,
754 '--log-queries=extra' ,
756 f
'--pid-file= {dnsmasq_pid_file} ' ,
757 '--conf-file=/dev/null' ,
759 f
'--interface= {interface} ' ,
760 f
'--dhcp-leasefile= {dnsmasq_lease_file} ' ,
762 f
'--dhcp-range= {ipv6_range}{ra_mode} ,2m' ,
763 f
'--dhcp-range= {ipv4_range} ,2m' ,
764 '--dhcp-option=option:mtu,1492' ,
765 f
'--dhcp-option=option:router, {ipv4_router} ' ,
768 ) + additional_options
769 check_output (* command
)
772 stop_by_pid_file ( dnsmasq_pid_file
)
773 rm_f ( dnsmasq_lease_file
)
774 rm_f ( dnsmasq_log_file
)
776 def read_dnsmasq_log_file ():
777 with
open ( dnsmasq_log_file
, encoding
= 'utf-8' ) as f
:
780 def start_isc_dhcpd ( conf_file
, ipv
, interface
= 'veth-peer' ):
781 conf_file_path
= os
. path
. join ( networkd_ci_temp_dir
, conf_file
)
782 isc_dhcpd_command
= f
'dhcpd {ipv} -cf {conf_file_path} -lf {isc_dhcpd_lease_file} -pf {isc_dhcpd_pid_file} {interface} '
783 touch ( isc_dhcpd_lease_file
)
784 check_output ( isc_dhcpd_command
)
786 def stop_isc_dhcpd ():
787 stop_by_pid_file ( isc_dhcpd_pid_file
)
788 rm_f ( isc_dhcpd_lease_file
)
790 def get_dbus_link_path ( link
):
791 out
= subprocess
. check_output ([ 'busctl' , 'call' , 'org.freedesktop.network1' ,
792 '/org/freedesktop/network1' , 'org.freedesktop.network1.Manager' ,
793 'GetLinkByName' , 's' , link
])
795 assert out
. startswith ( b
'io ' )
797 assert out
. endswith ( b
'"' )
799 return out
[:- 1 ]. split ( '"' )[ 1 ]
801 def get_dhcp_client_state ( link
, family
):
802 link_path
= get_dbus_link_path ( link
)
804 out
= subprocess
. check_output ([ 'busctl' , 'get-property' , 'org.freedesktop.network1' ,
805 link_path
, f
'org.freedesktop.network1.DHCPv {family} Client' , 'State' ])
806 assert out
. startswith ( b
's "' )
808 assert out
. endswith ( b
'"' )
809 return out
[ 3 :- 1 ]. decode ()
811 def get_dhcp4_client_state ( link
):
812 return get_dhcp_client_state ( link
, '4' )
814 def get_dhcp6_client_state ( link
):
815 return get_dhcp_client_state ( link
, '6' )
817 def get_link_description ( link
):
818 link_path
= get_dbus_link_path ( link
)
820 out
= subprocess
. check_output ([ 'busctl' , 'call' , 'org.freedesktop.network1' ,
821 link_path
, 'org.freedesktop.network1.Link' , 'Describe' ])
822 assert out
. startswith ( b
's "' )
824 assert out
. endswith ( b
'"' )
825 json_raw
= out
[ 2 :]. decode ()
827 description
= json
. loads ( json_raw
) # Convert from escaped sequences to json
828 check_json ( description
)
829 return json
. loads ( description
) # Now parse the json
831 def start_radvd (* additional_options
, config_file
):
832 config_file_path
= os
. path
. join ( networkd_ci_temp_dir
, 'radvd' , config_file
)
835 f
'--pidfile= {radvd_pid_file} ' ,
836 f
'--config= {config_file_path} ' ,
837 '--logmethod=stderr' ,
838 ) + additional_options
839 check_output (* command
)
842 stop_by_pid_file ( radvd_pid_file
)
844 def radvd_check_config ( config_file
):
845 if not shutil
. which ( 'radvd' ):
846 print ( 'radvd is not installed, assuming the config check failed' )
849 # Note: can't use networkd_ci_temp_dir here, as this command may run before that dir is
850 # set up (one instance is @unittest.skipX())
851 config_file_path
= os
. path
. join ( os
. path
. dirname ( os
. path
. abspath ( __file__
)), 'conf/radvd' , config_file
)
852 return call ( f
'radvd --config= {config_file_path} --configtest' ) == 0
854 def networkd_invocation_id ():
855 return check_output ( 'systemctl show --value -p InvocationID systemd-networkd.service' )
858 return check_output ( 'systemctl show --value -p MainPID systemd-networkd.service' )
860 def read_networkd_log ( invocation_id
= None , since
= None ):
861 if not invocation_id
:
862 invocation_id
= networkd_invocation_id ()
866 '--output=short-monotonic' ,
867 f
'_SYSTEMD_INVOCATION_ID= {invocation_id} ' ,
870 command
. append ( f
'--since= {since} ' )
871 check_output ( 'journalctl --sync' )
872 return check_output (* command
)
874 def networkd_is_failed ():
875 return call_quiet ( 'systemctl is-failed -q systemd-networkd.service' ) != 1
877 def stop_networkd ( show_logs
= True ):
879 show_logs
= show_logs
and show_journal
881 invocation_id
= networkd_invocation_id ()
882 check_output ( 'systemctl stop systemd-networkd.socket' )
883 check_output ( 'systemctl stop systemd-networkd.service' )
885 print ( read_networkd_log ( invocation_id
))
886 # Check if networkd exits cleanly.
887 assert not networkd_is_failed ()
889 def start_networkd ():
890 check_output ( 'systemctl start systemd-networkd' )
891 invocation_id
= networkd_invocation_id ()
893 print ( f
'Started systemd-networkd.service: PID= {pid} , Invocation ID= {invocation_id} ' )
895 def restart_networkd ( show_logs
= True ):
897 show_logs
= show_logs
and show_journal
899 invocation_id
= networkd_invocation_id ()
900 check_output ( 'systemctl restart systemd-networkd.service' )
902 print ( read_networkd_log ( invocation_id
))
904 invocation_id
= networkd_invocation_id ()
906 print ( f
'Restarted systemd-networkd.service: PID= {pid} , Invocation ID= {invocation_id} ' )
909 return int ( check_output ( 'systemctl show --value -p MainPID systemd-networkd.service' ))
911 def networkctl (* args
):
912 # Do not call networkctl if networkd is in failed state.
913 # Otherwise, networkd may be restarted and we may get wrong results.
914 assert not networkd_is_failed ()
915 return check_output (*( networkctl_cmd
+ list ( args
)), env
= env
)
917 def networkctl_status (* args
):
918 return networkctl ( '-n' , '0' , 'status' , * args
)
920 def networkctl_json (* args
):
921 return networkctl ( '--json=short' , 'status' , * args
)
923 def networkctl_reconfigure (* links
):
924 networkctl ( 'reconfigure' , * links
)
926 def networkctl_reload ():
929 def resolvectl (* args
):
930 return check_output (*( resolvectl_cmd
+ list ( args
)), env
= env
)
932 def timedatectl (* args
):
933 return check_output (*( timedatectl_cmd
+ list ( args
)), env
= env
)
936 return check_output (*( udevadm_cmd
+ list ( args
)))
938 def udevadm_reload ():
939 udevadm ( 'control' , '--reload' )
941 def udevadm_trigger (* args
, action
= 'add' ):
942 udevadm ( 'trigger' , '--settle' , f
'--action= {action} ' , * args
)
945 # Protect existing links
946 unmanage_existing_links ()
948 # We usually show something in each test. So, let's break line to make the title of a test and output
949 # from the test mixed. Then, flush stream buffer and journals.
952 check_output ( 'journalctl --sync' )
954 def tear_down_common ():
955 # 1. stop DHCP/RA servers
961 call_quiet ( 'rmmod netdevsim' )
962 call_quiet ( 'rmmod sch_teql' )
964 # 3. remove network namespace
965 call_quiet ( 'ip netns del ns99' )
975 clear_network_units ()
976 clear_networkd_conf_dropins ()
977 clear_networkd_state_files ()
982 flush_routing_policy_rules ()
985 # 8. flush stream buffer and journals to make not any output from the test with the next one
987 check_output ( 'journalctl --sync' )
990 rm_rf ( networkd_ci_temp_dir
)
991 cp_r ( os
. path
. join ( os
. path
. dirname ( os
. path
. abspath ( __file__
)), 'conf' ), networkd_ci_temp_dir
)
993 clear_network_units ()
994 clear_networkd_conf_dropins ()
995 clear_networkd_state_files ()
998 setup_systemd_udev_rules ()
999 copy_udev_rule ( '00-debug-net.rules' )
1001 # Save current state
1003 save_existing_links ()
1005 save_routing_policy_rules ()
1008 setup_system_units ()
1010 def tearDownModule ():
1011 rm_rf ( networkd_ci_temp_dir
)
1013 clear_network_units ()
1014 clear_networkd_conf_dropins ()
1015 clear_networkd_state_files ()
1019 clear_system_units ()
1020 restore_active_units ()
1022 # Flush stream buffer and journals before showing the test summary.
1024 check_output ( 'journalctl --sync' )
1027 # pylint: disable=no-member
1029 def check_link_exists ( self
, * link
, expected
= True ):
1031 self
. assertTrue ( link_exists (* link
))
1033 self
. assertFalse ( link_exists (* link
))
1035 def check_link_attr ( self
, * args
):
1036 self
. assertEqual ( read_link_attr (* args
[:- 1 ]), args
[- 1 ])
1038 def check_bridge_port_attr ( self
, master
, port
, attribute
, expected
, allow_enoent
= False ):
1039 path
= os
. path
. join ( '/sys/devices/virtual/net' , master
, 'lower_' + port
, 'brport' , attribute
)
1040 if allow_enoent
and not os
. path
. exists ( path
):
1042 with
open ( path
, encoding
= 'utf-8' ) as f
:
1043 self
. assertEqual ( f
. readline (). strip (), expected
)
1045 def check_ipv4_sysctl_attr ( self
, link
, attribute
, expected
):
1046 self
. assertEqual ( read_ipv4_sysctl_attr ( link
, attribute
), expected
)
1048 def check_ipv6_sysctl_attr ( self
, link
, attribute
, expected
):
1049 self
. assertEqual ( read_ipv6_sysctl_attr ( link
, attribute
), expected
)
1051 def check_ipv6_neigh_sysctl_attr ( self
, link
, attribute
, expected
):
1052 self
. assertEqual ( read_ipv6_neigh_sysctl_attr ( link
, attribute
), expected
)
1054 def wait_links ( self
, * links
, trial
= 40 ):
1055 for _
in range ( trial
):
1056 if link_exists (* links
):
1060 self
. fail ( 'Timed out waiting for all links to be created: ' + ', ' . join ( list ( links
)))
1062 def wait_activated ( self
, link
, state
= 'down' , trial
= 40 ):
1063 # wait for the interface is activated.
1064 needle
= f
' {link} : Bringing link {state} '
1065 flag
= state
. upper ()
1066 self
. wait_links ( link
, trial
= trial
)
1067 self
. check_networkd_log ( needle
, trial
= trial
)
1068 for _
in range ( trial
):
1069 if flag
in check_output ( f
'ip link show {link} ' ):
1073 self
. fail ( f
'Timed out waiting for {link} activated.' )
1075 def wait_operstate ( self
, link
, operstate
= 'degraded' , setup_state
= 'configured' , setup_timeout
= 5 , fail_assert
= True ):
1076 """Wait for the link to reach the specified operstate and/or setup state.
1078 Specify None or '' for either operstate or setup_state to ignore that state.
1079 This will recheck until the state conditions are met or the timeout expires.
1081 If the link successfully matches the requested state, this returns True.
1082 If this times out waiting for the link to match, the behavior depends on the
1083 'fail_assert' parameter; if True, this causes a test assertion failure,
1084 otherwise this returns False. The default is to cause assertion failure.
1086 Note that this function matches on *exactly* the given operstate and setup_state.
1087 To wait for a link to reach *or exceed* a given operstate, use wait_online().
1092 setup_state
= r
'\S+'
1094 for _
in range ( setup_timeout
* 2 ):
1095 if not link_exists ( link
):
1098 output
= networkctl_status ( link
)
1099 if re
. search ( rf
'(?m)^\s*State:\s+ {operstate} \s+\( {setup_state} \)\s*$' , output
):
1104 self
. fail ( f
'Timed out waiting for {link} to reach state {operstate} / {setup_state} ' )
1107 def wait_online ( self
, * links_with_operstate
, timeout
= '20s' , bool_any
= False , ipv4
= False , ipv6
= False , setup_state
= 'configured' , setup_timeout
= 5 ):
1108 """Wait for the links to reach the specified operstate and/or setup state.
1110 This is similar to wait_operstate() but can be used for multiple links,
1111 and it also calls systemd-networkd-wait-online to wait for the given operstate.
1112 The operstate should be specified in the link name, like 'eth0:degraded'.
1113 If just a link name is provided, wait-online's default operstate to wait for is degraded.
1115 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
1116 'setup_timeout' controls the per-link timeout waiting for the setup_state.
1118 Set 'bool_any' to True to wait for any (instead of all) of the given links.
1119 If this is set, no setup_state checks are done.
1121 Set 'ipv4' or 'ipv6' to True to wait for IPv4 address or IPv6 address, respectively, of each of the given links.
1122 This is applied only for the operational state 'degraded' or above.
1124 Note that this function waits for the links to reach *or exceed* the given operstate.
1125 However, the setup_state, if specified, must be matched *exactly*.
1127 This returns if the links reached the requested operstate/setup_state; otherwise it
1128 raises CalledProcessError or fails test assertion.
1130 args
= wait_online_cmd
+ [ f
'--timeout= {timeout} ' ] + [ f
'--interface= {link} ' for link
in links_with_operstate
] + [ f
'--ignore= {link} ' for link
in protected_links
]
1138 check_output (* args
, env
= wait_online_env
)
1139 except subprocess
. CalledProcessError
:
1140 if networkd_is_failed ():
1141 print ( '!!!!! systemd-networkd.service is failed !!!!!' )
1142 call ( 'systemctl status systemd-networkd.service' )
1144 # show detailed status on failure
1145 for link
in links_with_operstate
:
1146 name
= link
. split ( ':' )[ 0 ]
1147 if link_exists ( name
):
1148 print ( networkctl_status ( name
))
1150 print ( f
'Interface {name} not found.' )
1152 if not bool_any
and setup_state
:
1153 for link
in links_with_operstate
:
1154 self
. wait_operstate ( link
. split ( ':' )[ 0 ], None , setup_state
, setup_timeout
)
1156 def wait_address ( self
, link
, address_regex
, scope
= 'global' , ipv
= '' , timeout_sec
= 100 ):
1157 for _
in range ( timeout_sec
* 2 ):
1158 output
= check_output ( f
'ip {ipv} address show dev {link} scope {scope} ' )
1159 if re
. search ( address_regex
, output
) and 'tentative' not in output
:
1163 self
. assertRegex ( output
, address_regex
)
1165 def wait_address_dropped ( self
, link
, address_regex
, scope
= 'global' , ipv
= '' , timeout_sec
= 100 ):
1166 for _
in range ( timeout_sec
* 2 ):
1167 output
= check_output ( f
'ip {ipv} address show dev {link} scope {scope} ' )
1168 if not re
. search ( address_regex
, output
):
1172 self
. assertNotRegex ( output
, address_regex
)
1174 def wait_route ( self
, link
, route_regex
, table
= 'main' , ipv
= '' , timeout_sec
= 100 ):
1175 for _
in range ( timeout_sec
* 2 ):
1176 output
= check_output ( f
'ip {ipv} route show dev {link} table {table} ' )
1177 if re
. search ( route_regex
, output
):
1181 self
. assertRegex ( output
, route_regex
)
1183 def wait_route_dropped ( self
, link
, route_regex
, table
= 'main' , ipv
= '' , timeout_sec
= 100 ):
1184 for _
in range ( timeout_sec
* 2 ):
1185 output
= check_output ( f
'ip {ipv} route show dev {link} table {table} ' )
1186 if not re
. search ( route_regex
, output
):
1190 self
. assertNotRegex ( output
, route_regex
)
1192 def check_netlabel ( self
, interface
, address
, label
= 'system_u:object_r:root_t:s0' ):
1193 if not shutil
. which ( 'selinuxenabled' ):
1194 print ( '## Checking NetLabel skipped: selinuxenabled command not found.' )
1195 elif call_quiet ( 'selinuxenabled' ) != 0 :
1196 print ( '## Checking NetLabel skipped: SELinux disabled.' )
1197 elif not shutil
. which ( 'netlabelctl' ): # not packaged by all distros
1198 print ( '## Checking NetLabel skipped: netlabelctl command not found.' )
1200 output
= check_output ( 'netlabelctl unlbl list' )
1202 self
. assertRegex ( output
, f
'interface: {interface} ,address: {address} ,label:" {label} "' )
1204 def setup_nftset ( self
, filter_name
, filter_type
, flags
= '' ):
1205 if not shutil
. which ( 'nft' ):
1206 print ( '## Setting up NFT sets skipped: nft command not found.' )
1208 if call ( f
'nft add table inet sd_test' ) != 0 :
1209 print ( '## Setting up NFT table failed.' )
1211 if call ( f
'nft add set inet sd_test {filter_name} {{ type {filter_type} ; {flags} }}' ) != 0 :
1212 print ( '## Setting up NFT sets failed.' )
1215 def teardown_nftset ( self
, * filters
):
1216 if not shutil
. which ( 'nft' ):
1217 print ( '## Tearing down NFT sets skipped: nft command not found.' )
1219 for filter_name
in filters
:
1220 if call ( f
'nft delete set inet sd_test {filter_name} ' ) != 0 :
1221 print ( '## Tearing down NFT sets failed.' )
1223 if call ( f
'nft delete table inet sd_test' ) != 0 :
1224 print ( '## Tearing down NFT table failed.' )
1227 def check_nftset ( self
, filter_name
, contents
):
1228 if not shutil
. which ( 'nft' ):
1229 print ( '## Checking NFT sets skipped: nft command not found.' )
1231 output
= check_output ( f
'nft list set inet sd_test {filter_name} ' )
1233 self
. assertRegex ( output
, r
'.*elements = { [^}]*' + contents
+ r
'[^}]* }.*' )
1235 def check_networkd_log ( self
, contents
, since
= None , trial
= 20 ):
1236 for _
in range ( trial
):
1237 if contents
in read_networkd_log ( since
= since
):
1241 self
. fail ( f
'" {contents} " not found in journal.' )
1243 class NetworkctlTests ( unittest
. TestCase
, Utilities
):
1251 @expectedFailureIfAlternativeNameIsNotAvailable ()
1252 def test_altname ( self
):
1253 copy_network_unit ( '26-netdev-link-local-addressing-yes.network' , '12-dummy.netdev' , '12-dummy.link' )
1255 self
. wait_online ( 'dummy98:degraded' )
1257 output
= networkctl_status ( 'dummy98' )
1258 self
. assertRegex ( output
, 'hogehogehogehogehogehoge' )
1260 @expectedFailureIfAlternativeNameIsNotAvailable ()
1261 def test_rename_to_altname ( self
):
1262 copy_network_unit ( '26-netdev-link-local-addressing-yes.network' ,
1263 '12-dummy.netdev' , '12-dummy-rename-to-altname.link' )
1265 self
. wait_online ( 'dummyalt:degraded' )
1267 output
= networkctl_status ( 'dummyalt' )
1268 self
. assertIn ( 'hogehogehogehogehogehoge' , output
)
1269 self
. assertNotIn ( 'dummy98' , output
)
1271 def test_reconfigure ( self
):
1272 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' , copy_dropins
= False )
1274 self
. wait_online ( 'dummy98:routable' )
1276 output
= check_output ( 'ip -4 address show dev dummy98' )
1278 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
1279 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
1280 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
1282 check_output ( 'ip address del 10.1.2.3/16 dev dummy98' )
1283 check_output ( 'ip address del 10.1.2.4/16 dev dummy98' )
1284 check_output ( 'ip address del 10.2.2.4/16 dev dummy98' )
1286 networkctl_reconfigure ( 'dummy98' )
1287 self
. wait_online ( 'dummy98:routable' )
1289 output
= check_output ( 'ip -4 address show dev dummy98' )
1291 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
1292 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
1293 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
1295 remove_network_unit ( '25-address-static.network' )
1298 self
. wait_operstate ( 'dummy98' , 'degraded' , setup_state
= 'unmanaged' )
1300 output
= check_output ( 'ip -4 address show dev dummy98' )
1302 self
. assertNotIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
1303 self
. assertNotIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
1304 self
. assertNotIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
1306 copy_network_unit ( '25-address-static.network' , copy_dropins
= False )
1308 self
. wait_online ( 'dummy98:routable' )
1310 output
= check_output ( 'ip -4 address show dev dummy98' )
1312 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
1313 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
1314 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
1316 def test_renew ( self
):
1318 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
1319 output
= networkctl_status ( 'veth99' )
1321 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCPv4 via 192.168.5.1\)' )
1322 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
1323 self
. assertRegex ( output
, 'DNS: 192.168.5.1 \n *192.168.5.10' )
1324 self
. assertRegex ( output
, 'NTP: 192.168.5.1 \n *192.168.5.11' )
1326 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server.network' )
1329 check_json ( networkctl_json ( '--lines=0' , '--stats' , '--all' , '--full' ))
1331 for verb
in [ 'renew' , 'forcerenew' ]:
1332 networkctl ( verb
, 'veth99' )
1334 networkctl ( verb
, 'veth99' , 'veth99' , 'veth99' )
1337 def test_up_down ( self
):
1338 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' , copy_dropins
= False )
1340 self
. wait_online ( 'dummy98:routable' )
1342 networkctl ( 'down' , 'dummy98' )
1343 self
. wait_online ( 'dummy98:off' )
1344 networkctl ( 'up' , 'dummy98' )
1345 self
. wait_online ( 'dummy98:routable' )
1346 networkctl ( 'down' , 'dummy98' , 'dummy98' , 'dummy98' )
1347 self
. wait_online ( 'dummy98:off' )
1348 networkctl ( 'up' , 'dummy98' , 'dummy98' , 'dummy98' )
1349 self
. wait_online ( 'dummy98:routable' )
1351 def test_reload ( self
):
1354 copy_network_unit ( '11-dummy.netdev' )
1356 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'unmanaged' )
1358 copy_network_unit ( '11-dummy.network' )
1360 self
. wait_online ( 'test1:degraded' )
1362 remove_network_unit ( '11-dummy.network' )
1364 self
. wait_operstate ( 'test1' , 'degraded' , setup_state
= 'unmanaged' )
1366 remove_network_unit ( '11-dummy.netdev' )
1368 self
. wait_operstate ( 'test1' , 'degraded' , setup_state
= 'unmanaged' )
1370 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1372 self
. wait_operstate ( 'test1' , 'degraded' )
1374 def test_glob ( self
):
1375 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1378 self
. wait_online ( 'test1:degraded' )
1380 output
= networkctl ( 'list' )
1381 self
. assertRegex ( output
, '1 lo ' )
1382 self
. assertRegex ( output
, 'test1' )
1384 output
= networkctl ( 'list' , 'test1' )
1385 self
. assertNotRegex ( output
, '1 lo ' )
1386 self
. assertRegex ( output
, 'test1' )
1388 output
= networkctl ( 'list' , 'te*' )
1389 self
. assertNotRegex ( output
, '1 lo ' )
1390 self
. assertRegex ( output
, 'test1' )
1392 output
= networkctl_status ( 'te*' )
1393 self
. assertNotRegex ( output
, '1: lo ' )
1394 self
. assertRegex ( output
, 'test1' )
1396 output
= networkctl_status ( 'tes[a-z][0-9]' )
1397 self
. assertNotRegex ( output
, '1: lo ' )
1398 self
. assertRegex ( output
, 'test1' )
1401 copy_network_unit ( '11-dummy-mtu.netdev' , '11-dummy.network' )
1404 self
. wait_online ( 'test1:degraded' )
1406 output
= networkctl_status ( 'test1' )
1407 self
. assertRegex ( output
, 'MTU: 1600' )
1409 def test_type ( self
):
1410 copy_network_unit ( '11-dummy.netdev' , '11-dummy.network' )
1412 self
. wait_online ( 'test1:degraded' )
1414 output
= networkctl_status ( 'test1' )
1416 self
. assertRegex ( output
, 'Type: ether' )
1418 output
= networkctl_status ( 'lo' )
1420 self
. assertRegex ( output
, 'Type: loopback' )
1422 def test_unit_file ( self
):
1423 copy_network_unit ( '11-test-unit-file.netdev' , '11-test-unit-file.network' , '11-test-unit-file.link' )
1425 self
. wait_online ( 'test1:degraded' )
1427 output
= networkctl_status ( 'test1' )
1429 self
. assertIn ( 'Link File: /run/systemd/network/11-test-unit-file.link' , output
)
1430 self
. assertIn ( '/run/systemd/network/11-test-unit-file.link.d/dropin.conf' , output
)
1431 self
. assertIn ( 'Network File: /run/systemd/network/11-test-unit-file.network' , output
)
1432 self
. assertIn ( '/run/systemd/network/11-test-unit-file.network.d/dropin.conf' , output
)
1434 self
. check_networkd_log ( 'test1: Configuring with /run/systemd/network/11-test-unit-file.network (dropins: /run/systemd/network/11-test-unit-file.network.d/dropin.conf).' )
1436 # This test may be run on the system that has older udevd than 70f32a260b5ebb68c19ecadf5d69b3844896ba55 (v249).
1437 # In that case, the udev DB for the loopback network interface may already have ID_NET_LINK_FILE property.
1438 # Let's reprocess the interface and drop the property.
1439 udevadm_trigger ( '/sys/class/net/lo' )
1440 output
= networkctl_status ( 'lo' )
1442 self
. assertIn ( 'Link File: n/a' , output
)
1443 self
. assertIn ( 'Network File: n/a' , output
)
1445 def test_delete_links ( self
):
1446 copy_network_unit ( '11-dummy.netdev' , '25-veth.netdev' )
1448 self
. wait_links ( 'test1' , 'veth99' , 'veth-peer' )
1449 networkctl ( 'delete' , 'test1' , 'veth99' )
1450 self
. check_link_exists ( 'test1' , 'veth99' , 'veth-peer' , expected
= False )
1452 def test_label ( self
):
1455 class NetworkdMatchTests ( unittest
. TestCase
, Utilities
):
1463 @expectedFailureIfAlternativeNameIsNotAvailable ()
1464 def test_match ( self
):
1465 copy_network_unit ( '12-dummy-mac.netdev' ,
1466 '12-dummy-match-mac-01.network' ,
1467 '12-dummy-match-mac-02.network' ,
1468 '12-dummy-match-renamed.network' ,
1469 '12-dummy-match-altname.network' ,
1470 '12-dummy-altname.link' )
1473 self
. wait_online ( 'dummy98:routable' )
1474 output
= networkctl_status ( 'dummy98' )
1475 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-mac-01.network' , output
)
1476 output
= check_output ( 'ip -4 address show dev dummy98' )
1477 self
. assertIn ( '10.0.0.1/16' , output
)
1479 check_output ( 'ip link set dev dummy98 down' )
1480 check_output ( 'ip link set dev dummy98 address 12:34:56:78:9a:02' )
1482 self
. wait_address ( 'dummy98' , '10.0.0.2/16' , ipv
= '-4' , timeout_sec
= 10 )
1483 self
. wait_online ( 'dummy98:routable' )
1484 output
= networkctl_status ( 'dummy98' )
1485 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-mac-02.network' , output
)
1487 check_output ( 'ip link set dev dummy98 down' )
1488 check_output ( 'ip link set dev dummy98 name dummy98-1' )
1490 self
. wait_address ( 'dummy98-1' , '10.0.1.2/16' , ipv
= '-4' , timeout_sec
= 10 )
1491 self
. wait_online ( 'dummy98-1:routable' )
1492 output
= networkctl_status ( 'dummy98-1' )
1493 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-renamed.network' , output
)
1495 check_output ( 'ip link set dev dummy98-1 down' )
1496 check_output ( 'ip link set dev dummy98-1 name dummy98-2' )
1497 udevadm_trigger ( '/sys/class/net/dummy98-2' )
1499 self
. wait_address ( 'dummy98-2' , '10.0.2.2/16' , ipv
= '-4' , timeout_sec
= 10 )
1500 self
. wait_online ( 'dummy98-2:routable' )
1501 output
= networkctl_status ( 'dummy98-2' )
1502 self
. assertIn ( 'Network File: /run/systemd/network/12-dummy-match-altname.network' , output
)
1504 def test_match_udev_property ( self
):
1505 copy_network_unit ( '12-dummy.netdev' , '13-not-match-udev-property.network' , '14-match-udev-property.network' )
1507 self
. wait_online ( 'dummy98:routable' )
1509 output
= networkctl_status ( 'dummy98' )
1511 self
. assertRegex ( output
, 'Network File: /run/systemd/network/14-match-udev-property' )
1513 class WaitOnlineTests ( unittest
. TestCase
, Utilities
):
1521 def test_wait_online_any ( self
):
1522 copy_network_unit ( '25-bridge.netdev' , '25-bridge.network' , '11-dummy.netdev' , '11-dummy.network' )
1525 self
. wait_online ( 'bridge99' , 'test1:degraded' , bool_any
= True )
1527 self
. wait_operstate ( 'bridge99' , '(off|no-carrier)' , setup_state
= 'configuring' )
1528 self
. wait_operstate ( 'test1' , 'degraded' )
1530 class NetworkdNetDevTests ( unittest
. TestCase
, Utilities
):
1538 def test_dropin_and_name_conflict ( self
):
1539 copy_network_unit ( '10-dropin-test.netdev' , '15-name-conflict-test.netdev' )
1542 self
. wait_online ( 'dropin-test:off' , setup_state
= 'unmanaged' )
1544 output
= check_output ( 'ip link show dropin-test' )
1546 self
. assertRegex ( output
, '00:50:56:c0:00:28' )
1548 @expectedFailureIfModuleIsNotAvailable ( 'bareudp' )
1549 def test_bareudp ( self
):
1550 copy_network_unit ( '25-bareudp.netdev' , '26-netdev-link-local-addressing-yes.network' )
1553 self
. wait_online ( 'bareudp99:degraded' )
1555 output
= check_output ( 'ip -d link show bareudp99' )
1557 self
. assertRegex ( output
, 'dstport 1000 ' )
1558 self
. assertRegex ( output
, 'ethertype ip ' )
1560 @expectedFailureIfModuleIsNotAvailable ( 'batman-adv' )
1561 def test_batadv ( self
):
1562 copy_network_unit ( '25-batadv.netdev' , '26-netdev-link-local-addressing-yes.network' )
1565 self
. wait_online ( 'batadv99:degraded' )
1567 output
= check_output ( 'ip -d link show batadv99' )
1569 self
. assertRegex ( output
, 'batadv' )
1571 def test_bridge ( self
):
1572 copy_network_unit ( '25-bridge.netdev' , '25-bridge-configure-without-carrier.network' )
1575 self
. wait_online ( 'bridge99:no-carrier' )
1577 tick
= os
. sysconf ( 'SC_CLK_TCK' )
1578 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'hello_time' )) / tick
))
1579 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'max_age' )) / tick
))
1580 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'forward_delay' )) / tick
))
1581 self
. assertEqual ( 9 , round ( float ( read_link_attr ( 'bridge99' , 'bridge' , 'ageing_time' )) / tick
))
1582 self
. assertEqual ( 9 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'priority' )))
1583 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_querier' )))
1584 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_snooping' )))
1585 self
. assertEqual ( 1 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'stp_state' )))
1586 self
. assertEqual ( 3 , int ( read_link_attr ( 'bridge99' , 'bridge' , 'multicast_igmp_version' )))
1588 output
= networkctl_status ( 'bridge99' )
1590 self
. assertRegex ( output
, 'Priority: 9' )
1591 self
. assertRegex ( output
, 'STP: yes' )
1592 self
. assertRegex ( output
, 'Multicast IGMP Version: 3' )
1594 output
= check_output ( 'ip -d link show bridge99' )
1596 self
. assertIn ( 'vlan_filtering 1 ' , output
)
1597 self
. assertIn ( 'vlan_protocol 802.1ad ' , output
)
1598 self
. assertIn ( 'vlan_default_pvid 9 ' , output
)
1600 def test_bond ( self
):
1601 copy_network_unit ( '25-bond.netdev' , '25-bond-balanced-tlb.netdev' , '25-bond-property.netdev' )
1604 self
. wait_online ( 'bond99:off' , 'bond98:off' , 'bond97:off' , setup_state
= 'unmanaged' )
1606 self
. check_link_attr ( 'bond99' , 'bonding' , 'mode' , '802.3ad 4' )
1607 self
. check_link_attr ( 'bond99' , 'bonding' , 'xmit_hash_policy' , 'layer3+4 1' )
1608 self
. check_link_attr ( 'bond99' , 'bonding' , 'miimon' , '1000' )
1609 self
. check_link_attr ( 'bond99' , 'bonding' , 'lacp_rate' , 'fast 1' )
1610 self
. check_link_attr ( 'bond99' , 'bonding' , 'updelay' , '2000' )
1611 self
. check_link_attr ( 'bond99' , 'bonding' , 'downdelay' , '2000' )
1612 self
. check_link_attr ( 'bond99' , 'bonding' , 'resend_igmp' , '4' )
1613 self
. check_link_attr ( 'bond99' , 'bonding' , 'min_links' , '1' )
1614 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_actor_sys_prio' , '1218' )
1615 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_user_port_key' , '811' )
1616 self
. check_link_attr ( 'bond99' , 'bonding' , 'ad_actor_system' , '00:11:22:33:44:55' )
1618 self
. check_link_attr ( 'bond98' , 'bonding' , 'mode' , 'balance-tlb 5' )
1619 self
. check_link_attr ( 'bond98' , 'bonding' , 'tlb_dynamic_lb' , '1' )
1621 output
= networkctl_status ( 'bond99' )
1623 self
. assertIn ( 'Mode: 802.3ad' , output
)
1624 self
. assertIn ( 'Miimon: 1s' , output
)
1625 self
. assertIn ( 'Updelay: 2s' , output
)
1626 self
. assertIn ( 'Downdelay: 2s' , output
)
1628 output
= networkctl_status ( 'bond98' )
1630 self
. assertIn ( 'Mode: balance-tlb' , output
)
1632 output
= networkctl_status ( 'bond97' )
1635 self
. check_link_attr ( 'bond97' , 'bonding' , 'arp_missed_max' , '10' )
1636 self
. check_link_attr ( 'bond97' , 'bonding' , 'peer_notif_delay' , '300000' )
1638 def test_vlan ( self
):
1639 copy_network_unit ( '21-vlan.netdev' , '11-dummy.netdev' ,
1640 '21-vlan.network' , '21-vlan-test1.network' )
1643 self
. wait_online ( 'test1:degraded' , 'vlan99:routable' )
1645 output
= check_output ( 'ip -d link show test1' )
1647 self
. assertRegex ( output
, ' mtu 2000 ' )
1649 output
= check_output ( 'ip -d link show vlan99' )
1651 self
. assertIn ( ' mtu 2000 ' , output
)
1652 self
. assertIn ( 'REORDER_HDR' , output
)
1653 self
. assertIn ( 'LOOSE_BINDING' , output
)
1654 self
. assertIn ( 'GVRP' , output
)
1655 self
. assertIn ( 'MVRP' , output
)
1656 self
. assertIn ( ' id 99 ' , output
)
1657 self
. assertIn ( 'ingress-qos-map { 4:100 7:13 }' , output
)
1658 self
. assertIn ( 'egress-qos-map { 0:1 1:3 6:6 7:7 10:3 }' , output
)
1660 output
= check_output ( 'ip -4 address show dev test1' )
1662 self
. assertRegex ( output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1' )
1663 self
. assertRegex ( output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1' )
1665 output
= check_output ( 'ip -4 address show dev vlan99' )
1667 self
. assertRegex ( output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99' )
1669 def test_vlan_on_bond ( self
):
1670 # For issue #24377 (https://github.com/systemd/systemd/issues/24377),
1671 # which is fixed by b05e52000b4eee764b383cc3031da0a3739e996e (PR#24020).
1673 copy_network_unit ( '21-bond-802.3ad.netdev' , '21-bond-802.3ad.network' ,
1674 '21-vlan-on-bond.netdev' , '21-vlan-on-bond.network' )
1676 self
. wait_online ( 'bond99:off' )
1677 self
. wait_operstate ( 'vlan99' , operstate
= 'off' , setup_state
= 'configuring' , setup_timeout
= 10 )
1679 self
. check_networkd_log ( 'vlan99: Could not bring up interface, ignoring: Network is down' )
1681 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '21-dummy-bond-slave.network' )
1683 self
. wait_online ( 'test1:enslaved' , 'dummy98:enslaved' , 'bond99:carrier' , 'vlan99:routable' )
1685 def test_macvtap ( self
):
1687 for mode
in [ 'private' , 'vepa' , 'bridge' , 'passthru' ]:
1693 print ( f
'### test_macvtap(mode= {mode} )' )
1694 with self
. subTest ( mode
= mode
):
1695 copy_network_unit ( '21-macvtap.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1696 '11-dummy.netdev' , '25-macvtap.network' )
1697 with
open ( os
. path
. join ( network_unit_dir
, '21-macvtap.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1698 f
. write ( '[MACVTAP] \n Mode=' + mode
)
1701 self
. wait_online ( 'macvtap99:degraded' ,
1702 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' )
1704 output
= check_output ( 'ip -d link show macvtap99' )
1706 self
. assertRegex ( output
, 'macvtap mode ' + mode
+ ' ' )
1708 @expectedFailureIfModuleIsNotAvailable ( 'macvlan' )
1709 def test_macvlan ( self
):
1711 for mode
in [ 'private' , 'vepa' , 'bridge' , 'passthru' ]:
1717 print ( f
'### test_macvlan(mode= {mode} )' )
1718 with self
. subTest ( mode
= mode
):
1719 copy_network_unit ( '21-macvlan.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1720 '11-dummy.netdev' , '25-macvlan.network' )
1721 with
open ( os
. path
. join ( network_unit_dir
, '21-macvlan.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1722 f
. write ( '[MACVLAN] \n Mode=' + mode
)
1725 self
. wait_online ( 'macvlan99:degraded' ,
1726 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' )
1728 output
= check_output ( 'ip -d link show test1' )
1730 self
. assertIn ( ' mtu 2000 ' , output
)
1732 output
= check_output ( 'ip -d link show macvlan99' )
1734 self
. assertIn ( ' mtu 2000 ' , output
)
1735 self
. assertIn ( f
' macvlan mode {mode} ' , output
)
1737 remove_link ( 'test1' )
1740 check_output ( "ip link add test1 type dummy" )
1741 self
. wait_online ( 'macvlan99:degraded' ,
1742 'test1:carrier' if mode
== 'passthru' else 'test1:degraded' )
1744 output
= check_output ( 'ip -d link show test1' )
1746 self
. assertIn ( ' mtu 2000 ' , output
)
1748 output
= check_output ( 'ip -d link show macvlan99' )
1750 self
. assertIn ( ' mtu 2000 ' , output
)
1751 self
. assertIn ( f
' macvlan mode {mode} ' , output
)
1752 self
. assertIn ( ' bcqueuelen 1234 ' , output
)
1753 if ' bclim ' in output
: # This is new in kernel and iproute2 v6.4
1754 self
. assertIn ( ' bclim 2147483647 ' , output
)
1756 @expectedFailureIfModuleIsNotAvailable ( 'ipvlan' )
1757 def test_ipvlan ( self
):
1759 for mode
, flag
in [[ 'L2' , 'private' ], [ 'L3' , 'vepa' ], [ 'L3S' , 'bridge' ]]:
1765 print ( f
'### test_ipvlan(mode= {mode} , flag= {flag} )' )
1766 with self
. subTest ( mode
= mode
, flag
= flag
):
1767 copy_network_unit ( '25-ipvlan.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1768 '11-dummy.netdev' , '25-ipvlan.network' )
1769 with
open ( os
. path
. join ( network_unit_dir
, '25-ipvlan.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1770 f
. write ( '[IPVLAN] \n Mode=' + mode
+ ' \n Flags=' + flag
)
1773 self
. wait_online ( 'ipvlan99:degraded' , 'test1:degraded' )
1775 output
= check_output ( 'ip -d link show ipvlan99' )
1777 self
. assertRegex ( output
, 'ipvlan *mode ' + mode
. lower () + ' ' + flag
)
1779 @expectedFailureIfModuleIsNotAvailable ( 'ipvtap' )
1780 def test_ipvtap ( self
):
1782 for mode
, flag
in [[ 'L2' , 'private' ], [ 'L3' , 'vepa' ], [ 'L3S' , 'bridge' ]]:
1788 print ( f
'### test_ipvtap(mode= {mode} , flag= {flag} )' )
1789 with self
. subTest ( mode
= mode
, flag
= flag
):
1790 copy_network_unit ( '25-ipvtap.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1791 '11-dummy.netdev' , '25-ipvtap.network' )
1792 with
open ( os
. path
. join ( network_unit_dir
, '25-ipvtap.netdev' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
1793 f
. write ( '[IPVTAP] \n Mode=' + mode
+ ' \n Flags=' + flag
)
1796 self
. wait_online ( 'ipvtap99:degraded' , 'test1:degraded' )
1798 output
= check_output ( 'ip -d link show ipvtap99' )
1800 self
. assertRegex ( output
, 'ipvtap *mode ' + mode
. lower () + ' ' + flag
)
1802 def test_veth ( self
):
1803 copy_network_unit ( '25-veth.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1804 '25-veth-mtu.netdev' )
1807 self
. wait_online ( 'veth99:degraded' , 'veth-peer:degraded' , 'veth-mtu:degraded' , 'veth-mtu-peer:degraded' )
1809 output
= check_output ( 'ip -d link show veth99' )
1811 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bc' )
1812 output
= check_output ( 'ip -d link show veth-peer' )
1814 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bd' )
1816 output
= check_output ( 'ip -d link show veth-mtu' )
1818 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:be' )
1819 self
. assertRegex ( output
, 'mtu 1800' )
1820 output
= check_output ( 'ip -d link show veth-mtu-peer' )
1822 self
. assertRegex ( output
, 'link/ether 12:34:56:78:9a:bf' )
1823 self
. assertRegex ( output
, 'mtu 1800' )
1825 def check_tuntap ( self
, attached
):
1826 pid
= networkd_pid ()
1827 name
= psutil
. Process ( pid
). name ()[: 15 ]
1829 output
= check_output ( 'ip -d -oneline tuntap show' )
1831 self
. assertRegex ( output
, r
'testtap99: tap pi (multi_queue |)vnet_hdr persist filter.*\tAttached to processes:' )
1832 self
. assertRegex ( output
, r
'testtun99: tun pi (multi_queue |)vnet_hdr persist filter.*\tAttached to processes:' )
1835 self
. assertRegex ( output
, fr
'testtap99: .* {name} \( {pid} \)' )
1836 self
. assertRegex ( output
, fr
'testtun99: .* {name} \( {pid} \)' )
1837 self
. assertRegex ( output
, r
'testtap99: .*systemd\(1\)' )
1838 self
. assertRegex ( output
, r
'testtun99: .*systemd\(1\)' )
1840 output
= check_output ( 'ip -d link show testtun99' )
1842 # Old ip command does not support IFF_ flags
1843 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1844 self
. assertIn ( 'UP,LOWER_UP' , output
)
1846 output
= check_output ( 'ip -d link show testtap99' )
1848 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1849 self
. assertIn ( 'UP,LOWER_UP' , output
)
1852 self
. assertNotIn ( f
' {name} ( {pid} )' , output
)
1853 self
. assertNotIn ( 'systemd(1)' , output
)
1856 output
= check_output ( 'ip -d link show testtun99' )
1858 self
. assertRegex ( output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ' )
1859 if 'NO-CARRIER' in output
:
1866 output
= check_output ( 'ip -d link show testtap99' )
1868 self
. assertRegex ( output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ' )
1869 if 'NO-CARRIER' in output
:
1875 def test_tuntap ( self
):
1876 copy_network_unit ( '25-tun.netdev' , '25-tap.netdev' , '26-netdev-link-local-addressing-yes.network' )
1878 self
. wait_online ( 'testtun99:degraded' , 'testtap99:degraded' )
1880 self
. check_tuntap ( True )
1882 remove_network_unit ( '26-netdev-link-local-addressing-yes.network' )
1884 self
. wait_online ( 'testtun99:degraded' , 'testtap99:degraded' , setup_state
= 'unmanaged' )
1886 self
. check_tuntap ( True )
1888 clear_network_units ()
1889 unmanage_existing_links ()
1891 self
. wait_online ( 'testtun99:off' , 'testtap99:off' , setup_state
= 'unmanaged' )
1893 self
. check_tuntap ( False )
1895 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
1897 copy_network_unit ( '25-vrf.netdev' , '26-netdev-link-local-addressing-yes.network' )
1900 self
. wait_online ( 'vrf99:carrier' )
1902 @expectedFailureIfModuleIsNotAvailable ( 'vcan' )
1903 def test_vcan ( self
):
1904 copy_network_unit ( '25-vcan.netdev' , '26-netdev-link-local-addressing-yes.network' ,
1905 '25-vcan98.netdev' , '25-vcan98.network' )
1908 self
. wait_online ( 'vcan99:carrier' , 'vcan98:carrier' )
1909 # For can devices, 'carrier' is the default required operational state.
1910 self
. wait_online ( 'vcan99' , 'vcan98' )
1912 # https://github.com/systemd/systemd/issues/30140
1913 output
= check_output ( 'ip -d link show vcan99' )
1915 self
. assertIn ( 'mtu 16 ' , output
)
1917 output
= check_output ( 'ip -d link show vcan98' )
1919 self
. assertIn ( 'mtu 16 ' , output
)
1921 @expectedFailureIfModuleIsNotAvailable ( 'vxcan' )
1922 def test_vxcan ( self
):
1923 copy_network_unit ( '25-vxcan.netdev' , '26-netdev-link-local-addressing-yes.network' )
1926 self
. wait_online ( 'vxcan99:carrier' , 'vxcan-peer:carrier' )
1927 # For can devices, 'carrier' is the default required operational state.
1928 self
. wait_online ( 'vxcan99' , 'vxcan-peer' )
1930 @expectedFailureIfModuleIsNotAvailable ( 'wireguard' )
1931 def test_wireguard ( self
):
1932 copy_credential ( '25-wireguard-endpoint-peer0-cred.txt' , 'network.wireguard.peer0.endpoint' )
1933 copy_credential ( '25-wireguard-preshared-key-peer2-cred.txt' , 'network.wireguard.peer2.psk' )
1934 copy_credential ( '25-wireguard-no-peer-private-key-cred.txt' , 'network.wireguard.private.25-wireguard-no-peer' )
1936 copy_network_unit ( '25-wireguard.netdev' , '25-wireguard.network' ,
1937 '25-wireguard-23-peers.netdev' , '25-wireguard-23-peers.network' ,
1938 '25-wireguard-preshared-key.txt' , '25-wireguard-private-key.txt' ,
1939 '25-wireguard-no-peer.netdev' , '25-wireguard-no-peer.network' )
1941 self
. wait_online ( 'wg99:routable' , 'wg98:routable' , 'wg97:carrier' )
1943 output
= check_output ( 'ip -4 address show dev wg99' )
1945 self
. assertIn ( 'inet 192.168.124.1/24 scope global wg99' , output
)
1947 output
= check_output ( 'ip -4 address show dev wg99' )
1949 self
. assertIn ( 'inet 169.254.11.1/24 scope link wg99' , output
)
1951 output
= check_output ( 'ip -6 address show dev wg99' )
1953 self
. assertIn ( 'inet6 fe80::1/64 scope link' , output
)
1955 output
= check_output ( 'ip -4 address show dev wg98' )
1957 self
. assertIn ( 'inet 192.168.123.123/24 scope global wg98' , output
)
1959 output
= check_output ( 'ip -6 address show dev wg98' )
1961 self
. assertIn ( 'inet6 fd8d:4d6d:3ccb:500::1/64 scope global' , output
)
1963 output
= check_output ( 'ip -4 route show dev wg99 table 1234' )
1965 self
. assertIn ( '192.168.26.0/24 proto static scope link metric 123' , output
)
1967 output
= check_output ( 'ip -6 route show dev wg99 table 1234' )
1969 self
. assertIn ( 'fd31:bf08:57cb::/48 proto static metric 123 pref medium' , output
)
1971 output
= check_output ( 'ip -6 route show dev wg98 table 1234' )
1973 self
. assertIn ( 'fd8d:4d6d:3ccb:500:c79:2339:edce:ece1 proto static metric 123 pref medium' , output
)
1974 self
. assertIn ( 'fd8d:4d6d:3ccb:500:1dbf:ca8a:32d3:dd81 proto static metric 123 pref medium' , output
)
1975 self
. assertIn ( 'fd8d:4d6d:3ccb:500:1e54:1415:35d0:a47c proto static metric 123 pref medium' , output
)
1976 self
. assertIn ( 'fd8d:4d6d:3ccb:500:270d:b5dd:4a3f:8909 proto static metric 123 pref medium' , output
)
1977 self
. assertIn ( 'fd8d:4d6d:3ccb:500:5660:679d:3532:94d8 proto static metric 123 pref medium' , output
)
1978 self
. assertIn ( 'fd8d:4d6d:3ccb:500:6825:573f:30f3:9472 proto static metric 123 pref medium' , output
)
1979 self
. assertIn ( 'fd8d:4d6d:3ccb:500:6f2e:6888:c6fd:dfb9 proto static metric 123 pref medium' , output
)
1980 self
. assertIn ( 'fd8d:4d6d:3ccb:500:8d4d:bab:7280:a09a proto static metric 123 pref medium' , output
)
1981 self
. assertIn ( 'fd8d:4d6d:3ccb:500:900c:d437:ec27:8822 proto static metric 123 pref medium' , output
)
1982 self
. assertIn ( 'fd8d:4d6d:3ccb:500:9742:9931:5217:18d5 proto static metric 123 pref medium' , output
)
1983 self
. assertIn ( 'fd8d:4d6d:3ccb:500:9c11:d820:2e96:9be0 proto static metric 123 pref medium' , output
)
1984 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a072:80da:de4f:add1 proto static metric 123 pref medium' , output
)
1985 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a3f3:df38:19b0:721 proto static metric 123 pref medium' , output
)
1986 self
. assertIn ( 'fd8d:4d6d:3ccb:500:a94b:cd6a:a32d:90e6 proto static metric 123 pref medium' , output
)
1987 self
. assertIn ( 'fd8d:4d6d:3ccb:500:b39c:9cdc:755a:ead3 proto static metric 123 pref medium' , output
)
1988 self
. assertIn ( 'fd8d:4d6d:3ccb:500:b684:4f81:2e3e:132e proto static metric 123 pref medium' , output
)
1989 self
. assertIn ( 'fd8d:4d6d:3ccb:500:bad5:495d:8e9c:3427 proto static metric 123 pref medium' , output
)
1990 self
. assertIn ( 'fd8d:4d6d:3ccb:500:bfe5:c3c3:5d77:fcb proto static metric 123 pref medium' , output
)
1991 self
. assertIn ( 'fd8d:4d6d:3ccb:500:c624:6bf7:4c09:3b59 proto static metric 123 pref medium' , output
)
1992 self
. assertIn ( 'fd8d:4d6d:3ccb:500:d4f9:5dc:9296:a1a proto static metric 123 pref medium' , output
)
1993 self
. assertIn ( 'fd8d:4d6d:3ccb:500:dcdd:d33b:90c9:6088 proto static metric 123 pref medium' , output
)
1994 self
. assertIn ( 'fd8d:4d6d:3ccb:500:e2e1:ae15:103f:f376 proto static metric 123 pref medium' , output
)
1995 self
. assertIn ( 'fd8d:4d6d:3ccb:500:f349:c4f0:10c1:6b4 proto static metric 123 pref medium' , output
)
1996 self
. assertIn ( 'fd8d:4d6d:3ccb:c79:2339:edce::/96 proto static metric 123 pref medium' , output
)
1997 self
. assertIn ( 'fd8d:4d6d:3ccb:1dbf:ca8a:32d3::/96 proto static metric 123 pref medium' , output
)
1998 self
. assertIn ( 'fd8d:4d6d:3ccb:1e54:1415:35d0::/96 proto static metric 123 pref medium' , output
)
1999 self
. assertIn ( 'fd8d:4d6d:3ccb:270d:b5dd:4a3f::/96 proto static metric 123 pref medium' , output
)
2000 self
. assertIn ( 'fd8d:4d6d:3ccb:5660:679d:3532::/96 proto static metric 123 pref medium' , output
)
2001 self
. assertIn ( 'fd8d:4d6d:3ccb:6825:573f:30f3::/96 proto static metric 123 pref medium' , output
)
2002 self
. assertIn ( 'fd8d:4d6d:3ccb:6f2e:6888:c6fd::/96 proto static metric 123 pref medium' , output
)
2003 self
. assertIn ( 'fd8d:4d6d:3ccb:8d4d:bab:7280::/96 proto static metric 123 pref medium' , output
)
2004 self
. assertIn ( 'fd8d:4d6d:3ccb:900c:d437:ec27::/96 proto static metric 123 pref medium' , output
)
2005 self
. assertIn ( 'fd8d:4d6d:3ccb:9742:9931:5217::/96 proto static metric 123 pref medium' , output
)
2006 self
. assertIn ( 'fd8d:4d6d:3ccb:9c11:d820:2e96::/96 proto static metric 123 pref medium' , output
)
2007 self
. assertIn ( 'fd8d:4d6d:3ccb:a072:80da:de4f::/96 proto static metric 123 pref medium' , output
)
2008 self
. assertIn ( 'fd8d:4d6d:3ccb:a3f3:df38:19b0::/96 proto static metric 123 pref medium' , output
)
2009 self
. assertIn ( 'fd8d:4d6d:3ccb:a94b:cd6a:a32d::/96 proto static metric 123 pref medium' , output
)
2010 self
. assertIn ( 'fd8d:4d6d:3ccb:b39c:9cdc:755a::/96 proto static metric 123 pref medium' , output
)
2011 self
. assertIn ( 'fd8d:4d6d:3ccb:b684:4f81:2e3e::/96 proto static metric 123 pref medium' , output
)
2012 self
. assertIn ( 'fd8d:4d6d:3ccb:bad5:495d:8e9c::/96 proto static metric 123 pref medium' , output
)
2013 self
. assertIn ( 'fd8d:4d6d:3ccb:bfe5:c3c3:5d77::/96 proto static metric 123 pref medium' , output
)
2014 self
. assertIn ( 'fd8d:4d6d:3ccb:c624:6bf7:4c09::/96 proto static metric 123 pref medium' , output
)
2015 self
. assertIn ( 'fd8d:4d6d:3ccb:d4f9:5dc:9296::/96 proto static metric 123 pref medium' , output
)
2016 self
. assertIn ( 'fd8d:4d6d:3ccb:dcdd:d33b:90c9::/96 proto static metric 123 pref medium' , output
)
2017 self
. assertIn ( 'fd8d:4d6d:3ccb:e2e1:ae15:103f::/96 proto static metric 123 pref medium' , output
)
2018 self
. assertIn ( 'fd8d:4d6d:3ccb:f349:c4f0:10c1::/96 proto static metric 123 pref medium' , output
)
2020 if shutil
. which ( 'wg' ):
2023 output
= check_output ( 'wg show wg99 listen-port' )
2024 self
. assertEqual ( output
, '51820' )
2025 output
= check_output ( 'wg show wg99 fwmark' )
2026 self
. assertEqual ( output
, '0x4d2' )
2027 output
= check_output ( 'wg show wg99 private-key' )
2028 self
. assertEqual ( output
, 'EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=' )
2029 output
= check_output ( 'wg show wg99 allowed-ips' )
2030 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t 192.168.124.3/32' , output
)
2031 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t 192.168.124.2/32' , output
)
2032 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t fdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128' , output
)
2033 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 192.168.26.0/24 fd31:bf08:57cb::/48' , output
)
2034 output
= check_output ( 'wg show wg99 persistent-keepalive' )
2035 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t off' , output
)
2036 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t off' , output
)
2037 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t off' , output
)
2038 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 20' , output
)
2039 output
= check_output ( 'wg show wg99 endpoints' )
2040 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t (none)' , output
)
2041 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t (none)' , output
)
2042 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t (none)' , output
)
2043 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t 192.168.27.3:51820' , output
)
2044 output
= check_output ( 'wg show wg99 preshared-keys' )
2045 self
. assertIn ( '9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= \t 6Fsg8XN0DE6aPQgAX4r2oazEYJOGqyHUz3QRH/jCB+I=' , output
)
2046 self
. assertIn ( 'TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= \t it7nd33chCT/tKT2ZZWfYyp43Zs+6oif72hexnSNMqA=' , output
)
2047 self
. assertIn ( 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= \t cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=' , output
)
2048 self
. assertIn ( 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= \t IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=' , output
)
2050 output
= check_output ( 'wg show wg98 private-key' )
2051 self
. assertEqual ( output
, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr+WHtZLZ90FU=' )
2053 output
= check_output ( 'wg show wg97 listen-port' )
2054 self
. assertEqual ( output
, '51821' )
2055 output
= check_output ( 'wg show wg97 fwmark' )
2056 self
. assertEqual ( output
, '0x4d3' )
2058 def test_geneve ( self
):
2059 copy_network_unit ( '25-geneve.netdev' , '26-netdev-link-local-addressing-yes.network' )
2062 self
. wait_online ( 'geneve99:degraded' )
2064 output
= check_output ( 'ip -d link show geneve99' )
2066 self
. assertRegex ( output
, '192.168.22.1' )
2067 self
. assertRegex ( output
, '6082' )
2068 self
. assertRegex ( output
, 'udpcsum' )
2069 self
. assertRegex ( output
, 'udp6zerocsumrx' )
2071 def test_ipip_tunnel ( self
):
2072 copy_network_unit ( '12-dummy.netdev' , '25-ipip.network' ,
2073 '25-ipip-tunnel.netdev' , '25-tunnel.network' ,
2074 '25-ipip-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
2075 '25-ipip-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
2076 '25-ipip-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
2078 self
. wait_online ( 'ipiptun99:routable' , 'ipiptun98:routable' , 'ipiptun97:routable' , 'ipiptun96:routable' , 'dummy98:degraded' )
2080 output
= check_output ( 'ip -d link show ipiptun99' )
2082 self
. assertRegex ( output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98' )
2083 output
= check_output ( 'ip -d link show ipiptun98' )
2085 self
. assertRegex ( output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98' )
2086 output
= check_output ( 'ip -d link show ipiptun97' )
2088 self
. assertRegex ( output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98' )
2089 output
= check_output ( 'ip -d link show ipiptun96' )
2091 self
. assertRegex ( output
, 'ipip (ipip )?remote any local any dev dummy98' )
2093 def test_gre_tunnel ( self
):
2094 copy_network_unit ( '12-dummy.netdev' , '25-gretun.network' ,
2095 '25-gre-tunnel.netdev' , '25-tunnel.network' ,
2096 '25-gre-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
2097 '25-gre-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
2098 '25-gre-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
2100 self
. wait_online ( 'gretun99:routable' , 'gretun98:routable' , 'gretun97:routable' , 'gretun96:routable' , 'dummy98:degraded' )
2102 output
= check_output ( 'ip -d link show gretun99' )
2104 self
. assertRegex ( output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
2105 self
. assertRegex ( output
, 'ikey 1.2.3.103' )
2106 self
. assertRegex ( output
, 'okey 1.2.4.103' )
2107 self
. assertRegex ( output
, 'iseq' )
2108 self
. assertRegex ( output
, 'oseq' )
2109 output
= check_output ( 'ip -d link show gretun98' )
2111 self
. assertRegex ( output
, 'gre remote 10.65.223.239 local any dev dummy98' )
2112 self
. assertRegex ( output
, 'ikey 0.0.0.104' )
2113 self
. assertRegex ( output
, 'okey 0.0.0.104' )
2114 self
. assertNotRegex ( output
, 'iseq' )
2115 self
. assertNotRegex ( output
, 'oseq' )
2116 output
= check_output ( 'ip -d link show gretun97' )
2118 self
. assertRegex ( output
, 'gre remote any local 10.65.223.238 dev dummy98' )
2119 self
. assertRegex ( output
, 'ikey 0.0.0.105' )
2120 self
. assertRegex ( output
, 'okey 0.0.0.105' )
2121 self
. assertNotRegex ( output
, 'iseq' )
2122 self
. assertNotRegex ( output
, 'oseq' )
2123 output
= check_output ( 'ip -d link show gretun96' )
2125 self
. assertRegex ( output
, 'gre remote any local any dev dummy98' )
2126 self
. assertRegex ( output
, 'ikey 0.0.0.106' )
2127 self
. assertRegex ( output
, 'okey 0.0.0.106' )
2128 self
. assertNotRegex ( output
, 'iseq' )
2129 self
. assertNotRegex ( output
, 'oseq' )
2131 def test_ip6gre_tunnel ( self
):
2132 copy_network_unit ( '12-dummy.netdev' , '25-ip6gretun.network' ,
2133 '25-ip6gre-tunnel.netdev' , '25-tunnel.network' ,
2134 '25-ip6gre-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
2135 '25-ip6gre-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
2136 '25-ip6gre-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
2139 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
2141 self
. wait_links ( 'dummy98' , 'ip6gretun99' , 'ip6gretun98' , 'ip6gretun97' , 'ip6gretun96' )
2143 output
= check_output ( 'ip -d link show ip6gretun99' )
2145 self
. assertRegex ( output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
2146 output
= check_output ( 'ip -d link show ip6gretun98' )
2148 self
. assertRegex ( output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98' )
2149 output
= check_output ( 'ip -d link show ip6gretun97' )
2151 self
. assertRegex ( output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98' )
2152 output
= check_output ( 'ip -d link show ip6gretun96' )
2154 self
. assertRegex ( output
, 'ip6gre remote any local any dev dummy98' )
2156 def test_gretap_tunnel ( self
):
2157 copy_network_unit ( '12-dummy.netdev' , '25-gretap.network' ,
2158 '25-gretap-tunnel.netdev' , '25-tunnel.network' ,
2159 '25-gretap-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
2161 self
. wait_online ( 'gretap99:routable' , 'gretap98:routable' , 'dummy98:degraded' )
2163 output
= check_output ( 'ip -d link show gretap99' )
2165 self
. assertRegex ( output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
2166 self
. assertRegex ( output
, 'ikey 0.0.0.106' )
2167 self
. assertRegex ( output
, 'okey 0.0.0.106' )
2168 self
. assertRegex ( output
, 'iseq' )
2169 self
. assertRegex ( output
, 'oseq' )
2170 self
. assertIn ( 'nopmtudisc' , output
)
2171 self
. assertIn ( 'ignore-df' , output
)
2172 output
= check_output ( 'ip -d link show gretap98' )
2174 self
. assertRegex ( output
, 'gretap remote 10.65.223.239 local any dev dummy98' )
2175 self
. assertRegex ( output
, 'ikey 0.0.0.107' )
2176 self
. assertRegex ( output
, 'okey 0.0.0.107' )
2177 self
. assertRegex ( output
, 'iseq' )
2178 self
. assertRegex ( output
, 'oseq' )
2180 def test_ip6gretap_tunnel ( self
):
2181 copy_network_unit ( '12-dummy.netdev' , '25-ip6gretap.network' ,
2182 '25-ip6gretap-tunnel.netdev' , '25-tunnel.network' ,
2183 '25-ip6gretap-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
2185 self
. wait_online ( 'ip6gretap99:routable' , 'ip6gretap98:routable' , 'dummy98:degraded' )
2187 output
= check_output ( 'ip -d link show ip6gretap99' )
2189 self
. assertRegex ( output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
2190 output
= check_output ( 'ip -d link show ip6gretap98' )
2192 self
. assertRegex ( output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98' )
2194 def test_vti_tunnel ( self
):
2195 copy_network_unit ( '12-dummy.netdev' , '25-vti.network' ,
2196 '25-vti-tunnel.netdev' , '25-tunnel.network' ,
2197 '25-vti-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
2198 '25-vti-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
2199 '25-vti-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
2201 self
. wait_online ( 'vtitun99:routable' , 'vtitun98:routable' , 'vtitun97:routable' , 'vtitun96:routable' , 'dummy98:degraded' )
2203 output
= check_output ( 'ip -d link show vtitun99' )
2205 self
. assertRegex ( output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98' )
2206 output
= check_output ( 'ip -d link show vtitun98' )
2208 self
. assertRegex ( output
, 'vti remote 10.65.223.239 local any dev dummy98' )
2209 output
= check_output ( 'ip -d link show vtitun97' )
2211 self
. assertRegex ( output
, 'vti remote any local 10.65.223.238 dev dummy98' )
2212 output
= check_output ( 'ip -d link show vtitun96' )
2214 self
. assertRegex ( output
, 'vti remote any local any dev dummy98' )
2216 def test_vti6_tunnel ( self
):
2217 copy_network_unit ( '12-dummy.netdev' , '25-vti6.network' ,
2218 '25-vti6-tunnel.netdev' , '25-tunnel.network' ,
2219 '25-vti6-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
2220 '25-vti6-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' )
2222 self
. wait_online ( 'vti6tun99:routable' , 'vti6tun98:routable' , 'vti6tun97:routable' , 'dummy98:degraded' )
2224 output
= check_output ( 'ip -d link show vti6tun99' )
2226 self
. assertRegex ( output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' )
2227 output
= check_output ( 'ip -d link show vti6tun98' )
2229 self
. assertRegex ( output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98' )
2230 output
= check_output ( 'ip -d link show vti6tun97' )
2232 self
. assertRegex ( output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98' )
2234 def test_ip6tnl_tunnel ( self
):
2235 copy_network_unit ( '12-dummy.netdev' , '25-ip6tnl.network' ,
2236 '25-ip6tnl-tunnel.netdev' , '25-tunnel.network' ,
2237 '25-ip6tnl-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
2238 '25-ip6tnl-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
2239 '25-veth.netdev' , '25-ip6tnl-slaac.network' , '25-ipv6-prefix.network' ,
2240 '25-ip6tnl-tunnel-local-slaac.netdev' , '25-ip6tnl-tunnel-local-slaac.network' ,
2241 '25-ip6tnl-tunnel-external.netdev' , '26-netdev-link-local-addressing-yes.network' )
2243 self
. wait_online ( 'ip6tnl99:routable' , 'ip6tnl98:routable' , 'ip6tnl97:routable' ,
2244 'ip6tnl-slaac:degraded' , 'ip6tnl-external:degraded' ,
2245 'dummy98:degraded' , 'veth99:routable' , 'veth-peer:degraded' )
2247 output
= check_output ( 'ip -d link show ip6tnl99' )
2249 self
. assertIn ( 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98' , output
)
2250 output
= check_output ( 'ip -d link show ip6tnl98' )
2252 self
. assertRegex ( output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98' )
2253 output
= check_output ( 'ip -d link show ip6tnl97' )
2255 self
. assertRegex ( output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98' )
2256 output
= check_output ( 'ip -d link show ip6tnl-external' )
2258 self
. assertIn ( 'ip6tnl-external@NONE:' , output
)
2259 self
. assertIn ( 'ip6tnl external ' , output
)
2260 output
= check_output ( 'ip -d link show ip6tnl-slaac' )
2262 self
. assertIn ( 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99' , output
)
2264 output
= check_output ( 'ip -6 address show veth99' )
2266 self
. assertIn ( 'inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic' , output
)
2268 output
= check_output ( 'ip -4 route show default' )
2270 self
. assertIn ( 'default dev ip6tnl-slaac proto static' , output
)
2272 def test_sit_tunnel ( self
):
2273 copy_network_unit ( '12-dummy.netdev' , '25-sit.network' ,
2274 '25-sit-tunnel.netdev' , '25-tunnel.network' ,
2275 '25-sit-tunnel-local-any.netdev' , '25-tunnel-local-any.network' ,
2276 '25-sit-tunnel-remote-any.netdev' , '25-tunnel-remote-any.network' ,
2277 '25-sit-tunnel-any-any.netdev' , '25-tunnel-any-any.network' )
2279 self
. wait_online ( 'sittun99:routable' , 'sittun98:routable' , 'sittun97:routable' , 'sittun96:routable' , 'dummy98:degraded' )
2281 output
= check_output ( 'ip -d link show sittun99' )
2283 self
. assertRegex ( output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98" )
2284 output
= check_output ( 'ip -d link show sittun98' )
2286 self
. assertRegex ( output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98" )
2287 output
= check_output ( 'ip -d link show sittun97' )
2289 self
. assertRegex ( output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98" )
2290 output
= check_output ( 'ip -d link show sittun96' )
2292 self
. assertRegex ( output
, "sit (ip6ip )?remote any local any dev dummy98" )
2294 def test_isatap_tunnel ( self
):
2295 copy_network_unit ( '12-dummy.netdev' , '25-isatap.network' ,
2296 '25-isatap-tunnel.netdev' , '25-tunnel.network' )
2298 self
. wait_online ( 'isataptun99:routable' , 'dummy98:degraded' )
2300 output
= check_output ( 'ip -d link show isataptun99' )
2302 self
. assertRegex ( output
, "isatap " )
2304 def test_6rd_tunnel ( self
):
2305 copy_network_unit ( '12-dummy.netdev' , '25-6rd.network' ,
2306 '25-6rd-tunnel.netdev' , '25-tunnel.network' )
2308 self
. wait_online ( 'sittun99:routable' , 'dummy98:degraded' )
2310 output
= check_output ( 'ip -d link show sittun99' )
2312 self
. assertRegex ( output
, '6rd-prefix 2602::/24' )
2314 @expectedFailureIfERSPANv0IsNotSupported ()
2315 def test_erspan_tunnel_v0 ( self
):
2316 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
2317 '25-erspan0-tunnel.netdev' , '25-tunnel.network' ,
2318 '25-erspan0-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
2320 self
. wait_online ( 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' )
2322 output
= check_output ( 'ip -d link show erspan99' )
2324 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
2325 self
. assertIn ( 'erspan_ver 0' , output
)
2326 self
. assertNotIn ( 'erspan_index 123' , output
)
2327 self
. assertNotIn ( 'erspan_dir ingress' , output
)
2328 self
. assertNotIn ( 'erspan_hwid 1f' , output
)
2329 self
. assertIn ( 'ikey 0.0.0.101' , output
)
2330 self
. assertIn ( 'iseq' , output
)
2331 self
. assertIn ( 'nopmtudisc' , output
)
2332 self
. assertIn ( 'ignore-df' , output
)
2333 output
= check_output ( 'ip -d link show erspan98' )
2335 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
2336 self
. assertIn ( 'erspan_ver 0' , output
)
2337 self
. assertNotIn ( 'erspan_index 124' , output
)
2338 self
. assertNotIn ( 'erspan_dir egress' , output
)
2339 self
. assertNotIn ( 'erspan_hwid 2f' , output
)
2340 self
. assertIn ( 'ikey 0.0.0.102' , output
)
2341 self
. assertIn ( 'iseq' , output
)
2343 def test_erspan_tunnel_v1 ( self
):
2344 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
2345 '25-erspan1-tunnel.netdev' , '25-tunnel.network' ,
2346 '25-erspan1-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
2348 self
. wait_online ( 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' )
2350 output
= check_output ( 'ip -d link show erspan99' )
2352 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
2353 self
. assertIn ( 'erspan_ver 1' , output
)
2354 self
. assertIn ( 'erspan_index 123' , output
)
2355 self
. assertNotIn ( 'erspan_dir ingress' , output
)
2356 self
. assertNotIn ( 'erspan_hwid 1f' , output
)
2357 self
. assertIn ( 'ikey 0.0.0.101' , output
)
2358 self
. assertIn ( 'okey 0.0.0.101' , output
)
2359 self
. assertIn ( 'iseq' , output
)
2360 self
. assertIn ( 'oseq' , output
)
2361 output
= check_output ( 'ip -d link show erspan98' )
2363 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
2364 self
. assertIn ( 'erspan_ver 1' , output
)
2365 self
. assertIn ( 'erspan_index 124' , output
)
2366 self
. assertNotIn ( 'erspan_dir egress' , output
)
2367 self
. assertNotIn ( 'erspan_hwid 2f' , output
)
2368 self
. assertIn ( 'ikey 0.0.0.102' , output
)
2369 self
. assertIn ( 'okey 0.0.0.102' , output
)
2370 self
. assertIn ( 'iseq' , output
)
2371 self
. assertIn ( 'oseq' , output
)
2373 @expectedFailureIfERSPANv2IsNotSupported ()
2374 def test_erspan_tunnel_v2 ( self
):
2375 copy_network_unit ( '12-dummy.netdev' , '25-erspan.network' ,
2376 '25-erspan2-tunnel.netdev' , '25-tunnel.network' ,
2377 '25-erspan2-tunnel-local-any.netdev' , '25-tunnel-local-any.network' )
2379 self
. wait_online ( 'erspan99:routable' , 'erspan98:routable' , 'dummy98:degraded' )
2381 output
= check_output ( 'ip -d link show erspan99' )
2383 self
. assertIn ( 'erspan remote 172.16.1.100 local 172.16.1.200' , output
)
2384 self
. assertIn ( 'erspan_ver 2' , output
)
2385 self
. assertNotIn ( 'erspan_index 123' , output
)
2386 self
. assertIn ( 'erspan_dir ingress' , output
)
2387 self
. assertIn ( 'erspan_hwid 0x1f' , output
)
2388 self
. assertIn ( 'ikey 0.0.0.101' , output
)
2389 self
. assertIn ( 'okey 0.0.0.101' , output
)
2390 self
. assertIn ( 'iseq' , output
)
2391 self
. assertIn ( 'oseq' , output
)
2392 output
= check_output ( 'ip -d link show erspan98' )
2394 self
. assertIn ( 'erspan remote 172.16.1.100 local any' , output
)
2395 self
. assertIn ( 'erspan_ver 2' , output
)
2396 self
. assertNotIn ( 'erspan_index 124' , output
)
2397 self
. assertIn ( 'erspan_dir egress' , output
)
2398 self
. assertIn ( 'erspan_hwid 0x2f' , output
)
2399 self
. assertIn ( 'ikey 0.0.0.102' , output
)
2400 self
. assertIn ( 'okey 0.0.0.102' , output
)
2401 self
. assertIn ( 'iseq' , output
)
2402 self
. assertIn ( 'oseq' , output
)
2404 def test_tunnel_independent ( self
):
2405 copy_network_unit ( '25-ipip-tunnel-independent.netdev' , '26-netdev-link-local-addressing-yes.network' )
2408 self
. wait_online ( 'ipiptun99:carrier' )
2410 def test_tunnel_independent_loopback ( self
):
2411 copy_network_unit ( '25-ipip-tunnel-independent-loopback.netdev' , '26-netdev-link-local-addressing-yes.network' )
2414 self
. wait_online ( 'ipiptun99:carrier' )
2416 @expectedFailureIfModuleIsNotAvailable ( 'xfrm_interface' )
2417 def test_xfrm ( self
):
2418 copy_network_unit ( '12-dummy.netdev' , '25-xfrm.network' ,
2419 '25-xfrm.netdev' , '25-xfrm-independent.netdev' ,
2420 '26-netdev-link-local-addressing-yes.network' )
2423 self
. wait_online ( 'dummy98:degraded' , 'xfrm98:degraded' , 'xfrm99:degraded' )
2425 output
= check_output ( 'ip -d link show dev xfrm98' )
2427 self
. assertIn ( 'xfrm98@dummy98:' , output
)
2428 self
. assertIn ( 'xfrm if_id 0x98 ' , output
)
2430 output
= check_output ( 'ip -d link show dev xfrm99' )
2432 self
. assertIn ( 'xfrm99@lo:' , output
)
2433 self
. assertIn ( 'xfrm if_id 0x99 ' , output
)
2435 @expectedFailureIfModuleIsNotAvailable ( 'fou' )
2437 # The following redundant check is necessary for CentOS CI.
2438 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
2439 self
. assertTrue ( is_module_available ( 'fou' ))
2441 copy_network_unit ( '25-fou-ipproto-ipip.netdev' , '25-fou-ipproto-gre.netdev' ,
2442 '25-fou-ipip.netdev' , '25-fou-sit.netdev' ,
2443 '25-fou-gre.netdev' , '25-fou-gretap.netdev' )
2446 self
. wait_online ( 'ipiptun96:off' , 'sittun96:off' , 'gretun96:off' , 'gretap96:off' , setup_state
= 'unmanaged' )
2448 output
= check_output ( 'ip fou show' )
2450 self
. assertRegex ( output
, 'port 55555 ipproto 4' )
2451 self
. assertRegex ( output
, 'port 55556 ipproto 47' )
2453 output
= check_output ( 'ip -d link show ipiptun96' )
2455 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55555' )
2456 output
= check_output ( 'ip -d link show sittun96' )
2458 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55555' )
2459 output
= check_output ( 'ip -d link show gretun96' )
2461 self
. assertRegex ( output
, 'encap fou encap-sport 1001 encap-dport 55556' )
2462 output
= check_output ( 'ip -d link show gretap96' )
2464 self
. assertRegex ( output
, 'encap fou encap-sport auto encap-dport 55556' )
2466 def test_vxlan ( self
):
2467 copy_network_unit ( '11-dummy.netdev' , '25-vxlan-test1.network' ,
2468 '25-vxlan.netdev' , '25-vxlan.network' ,
2469 '25-vxlan-ipv6.netdev' , '25-vxlan-ipv6.network' ,
2470 '25-vxlan-independent.netdev' , '26-netdev-link-local-addressing-yes.network' ,
2471 '25-veth.netdev' , '25-vxlan-veth99.network' , '25-ipv6-prefix.network' ,
2472 '25-vxlan-local-slaac.netdev' , '25-vxlan-local-slaac.network' )
2475 self
. wait_online ( 'test1:degraded' , 'veth99:routable' , 'veth-peer:degraded' ,
2476 'vxlan99:degraded' , 'vxlan98:degraded' , 'vxlan97:degraded' , 'vxlan-slaac:degraded' )
2478 output
= check_output ( 'ip -d -d link show vxlan99' )
2480 self
. assertIn ( '999' , output
)
2481 self
. assertIn ( '5555' , output
)
2482 self
. assertIn ( 'l2miss' , output
)
2483 self
. assertIn ( 'l3miss' , output
)
2484 self
. assertIn ( 'gbp' , output
)
2485 # Since [0] some of the options use slightly different names and some
2486 # options with default values are shown only if the -d(etails) setting
2488 # [0] https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit/?id=1215e9d3862387353d8672296cb4c6c16e8cbb72
2489 self
. assertRegex ( output
, '(udpcsum|udp_csum)' )
2490 self
. assertRegex ( output
, '(udp6zerocsumtx|udp_zero_csum6_tx)' )
2491 self
. assertRegex ( output
, '(udp6zerocsumrx|udp_zero_csum6_rx)' )
2492 self
. assertRegex ( output
, '(remcsumtx|remcsum_tx)' )
2493 self
. assertRegex ( output
, '(remcsumrx|remcsum_rx)' )
2495 output
= check_output ( 'bridge fdb show dev vxlan99' )
2497 self
. assertIn ( '00:11:22:33:44:55 dst 10.0.0.5 self permanent' , output
)
2498 self
. assertIn ( '00:11:22:33:44:66 dst 10.0.0.6 self permanent' , output
)
2499 self
. assertIn ( '00:11:22:33:44:77 dst 10.0.0.7 via test1 self permanent' , output
)
2501 output
= networkctl_status ( 'vxlan99' )
2503 self
. assertIn ( 'VNI: 999' , output
)
2504 self
. assertIn ( 'Destination Port: 5555' , output
)
2505 self
. assertIn ( 'Underlying Device: test1' , output
)
2507 output
= check_output ( 'bridge fdb show dev vxlan97' )
2509 self
. assertIn ( '00:00:00:00:00:00 dst fe80::23b:d2ff:fe95:967f via test1 self permanent' , output
)
2510 self
. assertIn ( '00:00:00:00:00:00 dst fe80::27c:16ff:fec0:6c74 via test1 self permanent' , output
)
2511 self
. assertIn ( '00:00:00:00:00:00 dst fe80::2a2:e4ff:fef9:2269 via test1 self permanent' , output
)
2513 output
= check_output ( 'ip -d link show vxlan-slaac' )
2515 self
. assertIn ( 'vxlan id 4831584 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99' , output
)
2517 output
= check_output ( 'ip -6 address show veth99' )
2519 self
. assertIn ( 'inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic' , output
)
2521 @unittest . skipUnless ( compare_kernel_version ( "6" ), reason
= "Causes kernel panic on unpatched kernels: https://bugzilla.kernel.org/show_bug.cgi?id=208315" )
2522 def test_macsec ( self
):
2523 copy_network_unit ( '25-macsec.netdev' , '25-macsec.network' , '25-macsec.key' ,
2524 '26-macsec.network' , '12-dummy.netdev' )
2527 self
. wait_online ( 'dummy98:degraded' , 'macsec99:routable' )
2529 output
= check_output ( 'ip -d link show macsec99' )
2531 self
. assertRegex ( output
, 'macsec99@dummy98' )
2532 self
. assertRegex ( output
, 'macsec sci [0-9a-f]*000b' )
2533 self
. assertRegex ( output
, 'encrypt on' )
2535 output
= check_output ( 'ip macsec show macsec99' )
2537 self
. assertRegex ( output
, 'encrypt on' )
2538 self
. assertRegex ( output
, 'TXSC: [0-9a-f]*000b on SA 1' )
2539 self
. assertRegex ( output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000' )
2540 self
. assertRegex ( output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000' )
2541 self
. assertRegex ( output
, 'RXSC: c619528fe6a00100, state on' )
2542 self
. assertRegex ( output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000' )
2543 self
. assertRegex ( output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000' )
2544 self
. assertRegex ( output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000' )
2545 self
. assertRegex ( output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000' )
2546 self
. assertNotRegex ( output
, 'key 02030405067080900000000000000000' )
2547 self
. assertRegex ( output
, 'RXSC: 8c16456c83a90002, state on' )
2548 self
. assertRegex ( output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000' )
2550 def test_nlmon ( self
):
2551 copy_network_unit ( '25-nlmon.netdev' , '26-netdev-link-local-addressing-yes.network' )
2554 self
. wait_online ( 'nlmon99:carrier' )
2556 @expectedFailureIfModuleIsNotAvailable ( 'ifb' )
2558 copy_network_unit ( '25-ifb.netdev' , '26-netdev-link-local-addressing-yes.network' )
2561 self
. wait_online ( 'ifb99:degraded' )
2563 @unittest . skipUnless ( os
. cpu_count () >= 2 , reason
= "CPU count should be >= 2 to pass this test" )
2564 def test_rps_cpu_1 ( self
):
2565 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network' , '25-rps-cpu-1.link' )
2568 self
. wait_online ( 'dummy98:carrier' )
2570 output
= check_output ( 'cat /sys/class/net/dummy98/queues/rx-0/rps_cpus' )
2572 self
. assertEqual ( int ( output
. replace ( ',' , '' ), base
= 16 ), 2 )
2574 @unittest . skipUnless ( os
. cpu_count () >= 2 , reason
= "CPU count should be >= 2 to pass this test" )
2575 def test_rps_cpu_0_1 ( self
):
2576 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network' , '25-rps-cpu-0-1.link' )
2579 self
. wait_online ( 'dummy98:carrier' )
2581 output
= check_output ( 'cat /sys/class/net/dummy98/queues/rx-0/rps_cpus' )
2583 self
. assertEqual ( int ( output
. replace ( ',' , '' ), base
= 16 ), 3 )
2585 @unittest . skipUnless ( os
. cpu_count () >= 4 , reason
= "CPU count should be >= 4 to pass this test" )
2586 def test_rps_cpu_multi ( self
):
2587 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network' , '25-rps-cpu-multi.link' )
2590 self
. wait_online ( 'dummy98:carrier' )
2592 output
= check_output ( 'cat /sys/class/net/dummy98/queues/rx-0/rps_cpus' )
2594 self
. assertEqual ( int ( output
. replace ( ',' , '' ), base
= 16 ), 15 )
2596 def test_rps_cpu ( self
):
2597 cpu_count
= os
. cpu_count ()
2599 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network' )
2602 self
. wait_online ( 'dummy98:carrier' )
2605 copy_network_unit ( '25-rps-cpu-0.link' )
2606 udevadm_trigger ( '/sys/class/net/dummy98' )
2607 output
= check_output ( 'cat /sys/class/net/dummy98/queues/rx-0/rps_cpus' )
2609 self
. assertEqual ( int ( output
. replace ( ',' , '' ), base
= 16 ), 1 )
2610 remove_network_unit ( '25-rps-cpu-0.link' )
2613 copy_network_unit ( '25-rps-cpu-all.link' )
2614 udevadm_trigger ( '/sys/class/net/dummy98' )
2615 output
= check_output ( 'cat /sys/class/net/dummy98/queues/rx-0/rps_cpus' )
2617 self
. assertEqual ( f
"{int(output.replace(',', ''), base=16):x}" , f
'{(1 << cpu_count) - 1:x}' )
2618 remove_network_unit ( '25-rps-cpu-all.link' )
2621 copy_network_unit ( '24-rps-cpu-disable.link' )
2622 udevadm_trigger ( '/sys/class/net/dummy98' )
2623 output
= check_output ( 'cat /sys/class/net/dummy98/queues/rx-0/rps_cpus' )
2625 self
. assertEqual ( int ( output
. replace ( ',' , '' ), base
= 16 ), 0 )
2626 remove_network_unit ( '24-rps-cpu-disable.link' )
2629 copy_network_unit ( '25-rps-cpu-all.link' )
2630 udevadm_trigger ( '/sys/class/net/dummy98' )
2631 output
= check_output ( 'cat /sys/class/net/dummy98/queues/rx-0/rps_cpus' )
2633 self
. assertEqual ( f
"{int(output.replace(',', ''), base=16):x}" , f
'{(1 << cpu_count) - 1:x}' )
2634 remove_network_unit ( '25-rps-cpu-all.link' )
2636 # empty -> unchanged
2637 copy_network_unit ( '24-rps-cpu-empty.link' )
2638 udevadm_trigger ( '/sys/class/net/dummy98' )
2639 output
= check_output ( 'cat /sys/class/net/dummy98/queues/rx-0/rps_cpus' )
2641 self
. assertEqual ( f
"{int(output.replace(',', ''), base=16):x}" , f
'{(1 << cpu_count) - 1:x}' )
2642 remove_network_unit ( '24-rps-cpu-empty.link' )
2644 # 0, then empty -> unchanged
2645 copy_network_unit ( '25-rps-cpu-0-empty.link' )
2646 udevadm_trigger ( '/sys/class/net/dummy98' )
2647 output
= check_output ( 'cat /sys/class/net/dummy98/queues/rx-0/rps_cpus' )
2649 self
. assertEqual ( f
"{int(output.replace(',', ''), base=16):x}" , f
'{(1 << cpu_count) - 1:x}' )
2650 remove_network_unit ( '25-rps-cpu-0-empty.link' )
2652 # 0, then invalid -> 0
2653 copy_network_unit ( '25-rps-cpu-0-invalid.link' )
2654 udevadm_trigger ( '/sys/class/net/dummy98' )
2655 output
= check_output ( 'cat /sys/class/net/dummy98/queues/rx-0/rps_cpus' )
2657 self
. assertEqual ( int ( output
. replace ( ',' , '' ), base
= 16 ), 1 )
2658 remove_network_unit ( '25-rps-cpu-0-invalid.link' )
2660 # invalid -> unchanged
2661 copy_network_unit ( '24-rps-cpu-invalid.link' )
2662 udevadm_trigger ( '/sys/class/net/dummy98' )
2663 output
= check_output ( 'cat /sys/class/net/dummy98/queues/rx-0/rps_cpus' )
2665 self
. assertEqual ( int ( output
. replace ( ',' , '' ), base
= 16 ), 1 )
2666 remove_network_unit ( '24-rps-cpu-invalid.link' )
2668 class NetworkdL2TPTests ( unittest
. TestCase
, Utilities
):
2676 @expectedFailureIfModuleIsNotAvailable ( 'l2tp_eth' , 'l2tp_netlink' )
2677 def test_l2tp_udp ( self
):
2678 copy_network_unit ( '11-dummy.netdev' , '25-l2tp-dummy.network' ,
2679 '25-l2tp-udp.netdev' , '25-l2tp.network' )
2682 self
. wait_online ( 'test1:routable' , 'l2tp-ses1:degraded' , 'l2tp-ses2:degraded' )
2684 output
= check_output ( 'ip l2tp show tunnel tunnel_id 10' )
2686 self
. assertRegex ( output
, "Tunnel 10, encap UDP" )
2687 self
. assertRegex ( output
, "From 192.168.30.100 to 192.168.30.101" )
2688 self
. assertRegex ( output
, "Peer tunnel 11" )
2689 self
. assertRegex ( output
, "UDP source / dest ports: 3000/4000" )
2690 self
. assertRegex ( output
, "UDP checksum: enabled" )
2692 output
= check_output ( 'ip l2tp show session tid 10 session_id 15' )
2694 self
. assertRegex ( output
, "Session 15 in tunnel 10" )
2695 self
. assertRegex ( output
, "Peer session 16, tunnel 11" )
2696 self
. assertRegex ( output
, "interface name: l2tp-ses1" )
2698 output
= check_output ( 'ip l2tp show session tid 10 session_id 17' )
2700 self
. assertRegex ( output
, "Session 17 in tunnel 10" )
2701 self
. assertRegex ( output
, "Peer session 18, tunnel 11" )
2702 self
. assertRegex ( output
, "interface name: l2tp-ses2" )
2704 @expectedFailureIfModuleIsNotAvailable ( 'l2tp_eth' , 'l2tp_ip' , 'l2tp_netlink' )
2705 def test_l2tp_ip ( self
):
2706 copy_network_unit ( '11-dummy.netdev' , '25-l2tp-dummy.network' ,
2707 '25-l2tp-ip.netdev' , '25-l2tp.network' )
2710 self
. wait_online ( 'test1:routable' , 'l2tp-ses3:degraded' , 'l2tp-ses4:degraded' )
2712 output
= check_output ( 'ip l2tp show tunnel tunnel_id 10' )
2714 self
. assertRegex ( output
, "Tunnel 10, encap IP" )
2715 self
. assertRegex ( output
, "From 192.168.30.100 to 192.168.30.101" )
2716 self
. assertRegex ( output
, "Peer tunnel 12" )
2718 output
= check_output ( 'ip l2tp show session tid 10 session_id 25' )
2720 self
. assertRegex ( output
, "Session 25 in tunnel 10" )
2721 self
. assertRegex ( output
, "Peer session 26, tunnel 12" )
2722 self
. assertRegex ( output
, "interface name: l2tp-ses3" )
2724 output
= check_output ( 'ip l2tp show session tid 10 session_id 27' )
2726 self
. assertRegex ( output
, "Session 27 in tunnel 10" )
2727 self
. assertRegex ( output
, "Peer session 28, tunnel 12" )
2728 self
. assertRegex ( output
, "interface name: l2tp-ses4" )
2730 class NetworkdNetworkTests ( unittest
. TestCase
, Utilities
):
2738 def verify_address_static (
2768 output
= check_output ( 'ip address show dev dummy98' )
2772 self
. assertIn ( 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98' , output
)
2773 self
. assertIn ( 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98' , output
)
2774 self
. assertIn ( 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98' , output
)
2775 self
. assertIn ( 'inet6 2001:db8:0:f101::15/64 scope global' , output
)
2776 self
. assertIn ( 'inet6 2001:db8:0:f101::16/64 scope global' , output
)
2777 self
. assertIn ( 'inet6 2001:db8:0:f102::15/64 scope global' , output
)
2780 self
. assertIn ( f
'inet 10.3.1.1/24 brd 10.3.1.255 scope global {label1} ' , output
)
2781 self
. assertIn ( f
'inet 10.3.2.1/24 brd 10.3.2.255 scope global {label2} ' , output
)
2782 self
. assertIn ( f
'inet 10.3.3.1/24 brd 10.3.3.255 scope global {label3} ' , output
)
2785 self
. assertIn ( f
'inet 10.4.1.1/24 {broadcast1} scope global dummy98' , output
)
2786 self
. assertIn ( f
'inet 10.4.2.1/24 {broadcast2} scope global dummy98' , output
)
2787 self
. assertIn ( f
'inet 10.4.3.1/24 {broadcast3} scope global dummy98' , output
)
2790 self
. assertIn ( f
'inet 10.5.1.1 {peer1} scope global dummy98' , output
)
2791 self
. assertIn ( f
'inet 10.5.2.1 {peer2} scope global dummy98' , output
)
2792 self
. assertIn ( f
'inet 10.5.3.1 {peer3} scope global dummy98' , output
)
2793 self
. assertIn ( f
'inet6 2001:db8:0:f103::1 {peer4} scope global' , output
)
2794 self
. assertIn ( f
'inet6 2001:db8:0:f103::2 {peer5} scope global' , output
)
2795 self
. assertIn ( f
'inet6 2001:db8:0:f103::3 {peer6} scope global' , output
)
2798 self
. assertIn ( f
'inet 10.6.1.1/24 brd 10.6.1.255 scope {scope1} dummy98' , output
)
2799 self
. assertIn ( f
'inet 10.6.2.1/24 brd 10.6.2.255 scope {scope2} dummy98' , output
)
2802 self
. assertIn ( f
'inet 10.7.1.1/24 brd 10.7.1.255 scope global {deprecated1} dummy98' , output
)
2803 self
. assertIn ( f
'inet 10.7.2.1/24 brd 10.7.2.255 scope global {deprecated2} dummy98' , output
)
2804 self
. assertIn ( f
'inet6 2001:db8:0:f104::1/64 scope global {deprecated3} ' , output
)
2805 self
. assertIn ( f
'inet6 2001:db8:0:f104::2/64 scope global {deprecated4} ' , output
)
2808 self
. assertRegex ( output
, rf
'inet 10.8.1.1/24 (metric {route_metric} |)brd 10.8.1.255 scope global dummy98' )
2809 self
. assertRegex ( output
, rf
'inet6 2001:db8:0:f105::1/64 (metric {route_metric} |)scope global' )
2811 output_route
= check_output ( 'ip -4 route show dev dummy98 10.8.1.0/24' )
2813 self
. assertIn ( f
'10.8.1.0/24 proto kernel scope link src 10.8.1.1 metric {route_metric} ' , output_route
)
2815 output_route
= check_output ( 'ip -6 route show dev dummy98 2001:db8:0:f105::/64' )
2817 self
. assertIn ( f
'2001:db8:0:f105::/64 proto kernel metric {route_metric} ' , output_route
)
2820 self
. assertIn ( f
'inet 10.9.1.1/24 brd 10.9.1.255 scope global {flag1} dummy98' , output
)
2821 self
. assertIn ( f
'inet 10.9.2.1/24 brd 10.9.2.255 scope global {flag2} dummy98' , output
)
2822 self
. assertIn ( f
'inet6 2001:db8:0:f106::1/64 scope global {flag3} ' , output
)
2823 self
. assertIn ( f
'inet6 2001:db8:0:f106::2/64 scope global {flag4} ' , output
)
2826 self
. assertTrue ( ip4_null_16
. endswith ( '.0.1' ))
2827 prefix16
= ip4_null_16
[:- len ( '.0.1' )]
2828 self
. assertTrue ( ip4_null_24
. endswith ( '.1' ))
2829 prefix24
= ip4_null_24
[:- len ( '.1' )]
2830 self
. assertIn ( f
'inet {ip4_null_16} /16 brd {prefix16} .255.255 scope global subnet16' , output
)
2831 self
. assertIn ( f
'inet {ip4_null_24} /24 brd {prefix24} .255 scope global subnet24' , output
)
2832 self
. assertIn ( f
'inet6 {ip6_null_73} /73 scope global' , output
)
2833 self
. assertIn ( f
'inet6 {ip6_null_74} /74 scope global' , output
)
2836 self
. assertNotIn ( '10.4.4.1' , output
)
2837 self
. assertNotIn ( '10.5.4.1' , output
)
2838 self
. assertNotIn ( '10.5.5.1' , output
)
2839 self
. assertNotIn ( '10.8.2.1' , output
)
2840 self
. assertNotIn ( '10.9.3.1' , output
)
2841 self
. assertNotIn ( '2001:db8:0:f101::2' , output
)
2842 self
. assertNotIn ( '2001:db8:0:f103::4' , output
)
2845 self
. check_netlabel ( 'dummy98' , r
'10\.10\.1\.0/24' )
2847 check_json ( networkctl_json ())
2849 @expectedFailureIfKernelReturnsInvalidFlags ()
2850 def test_address_static ( self
):
2851 copy_network_unit ( '25-address-static.network' , '12-dummy.netdev' , copy_dropins
= False )
2852 self
. setup_nftset ( 'addr4' , 'ipv4_addr' )
2853 self
. setup_nftset ( 'network4' , 'ipv4_addr' , 'flags interval;' )
2854 self
. setup_nftset ( 'ifindex' , 'iface_index' )
2857 self
. wait_online ( 'dummy98:routable' )
2861 output
= check_output ( 'ip -4 --json address show dev dummy98' )
2862 for i
in json
. loads ( output
)[ 0 ][ 'addr_info' ]:
2863 if i
[ 'label' ] == 'subnet16' :
2864 ip4_null_16
= i
[ 'local' ]
2865 elif i
[ 'label' ] == 'subnet24' :
2866 ip4_null_24
= i
[ 'local' ]
2867 self
. assertTrue ( ip4_null_16
. endswith ( '.0.1' ))
2868 self
. assertTrue ( ip4_null_24
. endswith ( '.1' ))
2872 output
= check_output ( 'ip -6 --json address show dev dummy98' )
2873 for i
in json
. loads ( output
)[ 0 ][ 'addr_info' ]:
2874 if i
[ 'prefixlen' ] == 73 :
2875 ip6_null_73
= i
[ 'local' ]
2876 elif i
[ 'prefixlen' ] == 74 :
2877 ip6_null_74
= i
[ 'local' ]
2878 self
. assertTrue ( ip6_null_73
. endswith ( ':1' ))
2879 self
. assertTrue ( ip6_null_74
. endswith ( ':1' ))
2881 self
. verify_address_static (
2886 broadcast2
= ' brd 10.4.2.255' ,
2887 broadcast3
= ' brd 10.4.3.63' ,
2888 peer1
= ' peer 10.5.1.101/24' ,
2889 peer2
= ' peer 10.5.2.101/24' ,
2890 peer3
= '/24 brd 10.5.3.255' ,
2891 peer4
= ' peer 2001:db8:0:f103::101/128' ,
2892 peer5
= ' peer 2001:db8:0:f103::102/128' ,
2897 deprecated2
= ' deprecated' ,
2899 deprecated4
= ' deprecated' ,
2901 flag1
= ' noprefixroute' ,
2903 flag3
= ' noprefixroute' ,
2904 flag4
= ' home mngtmpaddr' ,
2905 ip4_null_16
= ip4_null_16
,
2906 ip4_null_24
= ip4_null_24
,
2907 ip6_null_73
= ip6_null_73
,
2908 ip6_null_74
= ip6_null_74
,
2911 self
. check_nftset ( 'addr4' , r
'10\.10\.1\.1' )
2912 self
. check_nftset ( 'network4' , r
'10\.10\.1\.0/24' )
2913 self
. check_nftset ( 'ifindex' , 'dummy98' )
2915 self
. teardown_nftset ( 'addr4' , 'network4' , 'ifindex' )
2917 copy_network_unit ( '25-address-static.network.d/10-override.conf' )
2919 self
. wait_online ( 'dummy98:routable' )
2920 self
. verify_address_static (
2921 label1
= 'new-label1' ,
2923 label3
= 'new-label3' ,
2924 broadcast1
= ' brd 10.4.1.255' ,
2926 broadcast3
= ' brd 10.4.3.31' ,
2927 peer1
= ' peer 10.5.1.102/24' ,
2928 peer2
= '/24 brd 10.5.2.255' ,
2929 peer3
= ' peer 10.5.3.102/24' ,
2930 peer4
= ' peer 2001:db8:0:f103::201/128' ,
2932 peer6
= ' peer 2001:db8:0:f103::203/128' ,
2935 deprecated1
= ' deprecated' ,
2937 deprecated3
= ' deprecated' ,
2941 flag2
= ' noprefixroute' ,
2942 flag3
= ' home mngtmpaddr' ,
2943 flag4
= ' noprefixroute' ,
2944 ip4_null_16
= ip4_null_16
,
2945 ip4_null_24
= ip4_null_24
,
2946 ip6_null_73
= ip6_null_73
,
2947 ip6_null_74
= ip6_null_74
,
2950 networkctl_reconfigure ( 'dummy98' )
2951 self
. wait_online ( 'dummy98:routable' )
2952 self
. verify_address_static (
2953 label1
= 'new-label1' ,
2955 label3
= 'new-label3' ,
2956 broadcast1
= ' brd 10.4.1.255' ,
2958 broadcast3
= ' brd 10.4.3.31' ,
2959 peer1
= ' peer 10.5.1.102/24' ,
2960 peer2
= '/24 brd 10.5.2.255' ,
2961 peer3
= ' peer 10.5.3.102/24' ,
2962 peer4
= ' peer 2001:db8:0:f103::201/128' ,
2964 peer6
= ' peer 2001:db8:0:f103::203/128' ,
2967 deprecated1
= ' deprecated' ,
2969 deprecated3
= ' deprecated' ,
2973 flag2
= ' noprefixroute' ,
2974 flag3
= ' home mngtmpaddr' ,
2975 flag4
= ' noprefixroute' ,
2976 ip4_null_16
= ip4_null_16
,
2977 ip4_null_24
= ip4_null_24
,
2978 ip6_null_73
= ip6_null_73
,
2979 ip6_null_74
= ip6_null_74
,
2983 # 1. set preferred lifetime forever to drop the deprecated flag for testing #20891.
2984 check_output ( 'ip address change 10.7.1.1/24 dev dummy98 preferred_lft forever' )
2985 check_output ( 'ip address change 2001:db8:0:f104::1/64 dev dummy98 preferred_lft forever' )
2986 output
= check_output ( 'ip address show dev dummy98' )
2988 self
. assertNotRegex ( output
, '10.7.1.1/24 .* deprecated' )
2989 self
. assertNotRegex ( output
, '2001:db8:0:f104::1/64 .* deprecated' )
2991 # 2. reconfigure the interface, and check the deprecated flag is set again
2992 networkctl_reconfigure ( 'dummy98' )
2993 self
. wait_online ( 'dummy98:routable' )
2994 self
. verify_address_static (
2995 label1
= 'new-label1' ,
2997 label3
= 'new-label3' ,
2998 broadcast1
= ' brd 10.4.1.255' ,
3000 broadcast3
= ' brd 10.4.3.31' ,
3001 peer1
= ' peer 10.5.1.102/24' ,
3002 peer2
= '/24 brd 10.5.2.255' ,
3003 peer3
= ' peer 10.5.3.102/24' ,
3004 peer4
= ' peer 2001:db8:0:f103::201/128' ,
3006 peer6
= ' peer 2001:db8:0:f103::203/128' ,
3009 deprecated1
= ' deprecated' ,
3011 deprecated3
= ' deprecated' ,
3015 flag2
= ' noprefixroute' ,
3016 flag3
= ' home mngtmpaddr' ,
3017 flag4
= ' noprefixroute' ,
3018 ip4_null_16
= ip4_null_16
,
3019 ip4_null_24
= ip4_null_24
,
3020 ip6_null_73
= ip6_null_73
,
3021 ip6_null_74
= ip6_null_74
,
3024 # test for ENOBUFS issue #17012 (with reload)
3025 copy_network_unit ( '25-address-static.network.d/10-many-address.conf' )
3027 self
. wait_online ( 'dummy98:routable' )
3028 output
= check_output ( 'ip -4 address show dev dummy98' )
3029 for i
in range ( 1 , 254 ):
3030 self
. assertIn ( f
'inet 10.3.3. {i} /16 brd 10.3.255.255' , output
)
3032 # (with reconfigure)
3033 networkctl_reconfigure ( 'dummy98' )
3034 self
. wait_online ( 'dummy98:routable' )
3035 output
= check_output ( 'ip -4 address show dev dummy98' )
3036 for i
in range ( 1 , 254 ):
3037 self
. assertIn ( f
'inet 10.3.3. {i} /16 brd 10.3.255.255' , output
)
3039 # test for an empty string assignment for Address= in [Network]
3040 copy_network_unit ( '25-address-static.network.d/20-clear-addresses.conf' )
3042 self
. wait_online ( 'dummy98:routable' )
3043 output
= check_output ( 'ip -4 address show dev dummy98' )
3044 for i
in range ( 1 , 254 ):
3045 self
. assertNotIn ( f
'inet 10.3.3. {i} /16 brd 10.3.255.255' , output
)
3046 self
. assertIn ( 'inet 10.4.0.1/16 brd 10.4.255.255' , output
)
3048 def test_address_ipv4acd ( self
):
3049 check_output ( 'ip netns add ns99' )
3050 check_output ( 'ip link add veth99 type veth peer veth-peer' )
3051 check_output ( 'ip link set veth-peer netns ns99' )
3052 check_output ( 'ip link set veth99 up' )
3053 check_output ( 'ip netns exec ns99 ip link set veth-peer up' )
3054 check_output ( 'ip netns exec ns99 ip address add 192.168.100.10/24 dev veth-peer' )
3056 copy_network_unit ( '25-address-ipv4acd-veth99.network' , copy_dropins
= False )
3058 self
. wait_online ( 'veth99:routable' )
3060 output
= check_output ( 'ip -4 address show dev veth99' )
3062 self
. assertNotIn ( '192.168.100.10/24' , output
)
3063 self
. assertIn ( '192.168.100.11/24' , output
)
3065 copy_network_unit ( '25-address-ipv4acd-veth99.network.d/conflict-address.conf' )
3067 self
. wait_operstate ( 'veth99' , operstate
= 'routable' , setup_state
= 'configuring' , setup_timeout
= 10 )
3069 output
= check_output ( 'ip -4 address show dev veth99' )
3071 self
. assertNotIn ( '192.168.100.10/24' , output
)
3072 self
. assertIn ( '192.168.100.11/24' , output
)
3074 def test_address_peer_ipv4 ( self
):
3075 # test for issue #17304
3076 copy_network_unit ( '25-address-peer-ipv4.network' , '12-dummy.netdev' )
3078 for trial
in range ( 2 ):
3084 self
. wait_online ( 'dummy98:routable' )
3086 output
= check_output ( 'ip -4 address show dev dummy98' )
3087 self
. assertIn ( 'inet 100.64.0.1 peer 100.64.0.2/32 scope global' , output
)
3089 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
3090 def test_prefix_route ( self
):
3091 copy_network_unit ( '25-prefix-route-with-vrf.network' , '12-dummy.netdev' ,
3092 '25-prefix-route-without-vrf.network' , '11-dummy.netdev' ,
3093 '25-vrf.netdev' , '25-vrf.network' )
3094 for trial
in range ( 2 ):
3100 self
. wait_online ( 'dummy98:routable' , 'test1:routable' , 'vrf99:carrier' )
3102 output
= check_output ( 'ip route show table 42 dev dummy98' )
3103 print ( '### ip route show table 42 dev dummy98' )
3105 self
. assertRegex ( output
, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1' )
3106 self
. assertRegex ( output
, '10.20.33.0/24 proto kernel scope link src 10.20.33.1' )
3107 self
. assertRegex ( output
, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1' )
3108 self
. assertRegex ( output
, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1' )
3109 self
. assertRegex ( output
, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1' )
3110 self
. assertRegex ( output
, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1' )
3111 self
. assertRegex ( output
, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1' )
3112 output
= check_output ( 'ip -6 route show table 42 dev dummy98' )
3113 print ( '### ip -6 route show table 42 dev dummy98' )
3117 self
. assertRegex ( output
, 'local fdde:11:22::1 proto kernel metric 0 pref medium' )
3118 #self.assertRegex(output, 'fdde:11:22::1 proto kernel metric 256 pref medium')
3119 self
. assertRegex ( output
, 'local fdde:11:33::1 proto kernel metric 0 pref medium' )
3120 self
. assertRegex ( output
, 'fdde:11:33::/64 proto kernel metric 256 pref medium' )
3121 self
. assertRegex ( output
, 'local fdde:11:44::1 proto kernel metric 0 pref medium' )
3122 self
. assertRegex ( output
, 'local fdde:11:55::1 proto kernel metric 0 pref medium' )
3123 self
. assertRegex ( output
, 'fe80::/64 proto kernel metric 256 pref medium' )
3124 self
. assertRegex ( output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium' )
3128 output
= check_output ( 'ip route show dev test1' )
3129 print ( '### ip route show dev test1' )
3131 self
. assertRegex ( output
, '10.21.33.0/24 proto kernel scope link src 10.21.33.1' )
3132 output
= check_output ( 'ip route show table local dev test1' )
3133 print ( '### ip route show table local dev test1' )
3135 self
. assertRegex ( output
, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1' )
3136 self
. assertRegex ( output
, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1' )
3137 self
. assertRegex ( output
, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1' )
3138 self
. assertRegex ( output
, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1' )
3139 self
. assertRegex ( output
, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1' )
3140 self
. assertRegex ( output
, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1' )
3141 output
= check_output ( 'ip -6 route show dev test1' )
3142 print ( '### ip -6 route show dev test1' )
3144 self
. assertRegex ( output
, 'fdde:12:22::1 proto kernel metric 256 pref medium' )
3145 self
. assertRegex ( output
, 'fdde:12:33::/64 proto kernel metric 256 pref medium' )
3146 self
. assertRegex ( output
, 'fe80::/64 proto kernel metric 256 pref medium' )
3147 output
= check_output ( 'ip -6 route show table local dev test1' )
3148 print ( '### ip -6 route show table local dev test1' )
3150 self
. assertRegex ( output
, 'local fdde:12:22::1 proto kernel metric 0 pref medium' )
3151 self
. assertRegex ( output
, 'local fdde:12:33::1 proto kernel metric 0 pref medium' )
3152 self
. assertRegex ( output
, 'local fdde:12:44::1 proto kernel metric 0 pref medium' )
3153 self
. assertRegex ( output
, 'local fdde:12:55::1 proto kernel metric 0 pref medium' )
3154 self
. assertRegex ( output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium' )
3156 def test_configure_without_carrier ( self
):
3157 copy_network_unit ( '11-dummy.netdev' )
3159 self
. wait_operstate ( 'test1' , 'off' , '' )
3160 check_output ( 'ip link set dev test1 up carrier off' )
3162 copy_network_unit ( '25-test1.network.d/configure-without-carrier.conf' , copy_dropins
= False )
3164 self
. wait_online ( 'test1:no-carrier' )
3166 carrier_map
= { 'on' : '1' , 'off' : '0' }
3167 routable_map
= { 'on' : 'routable' , 'off' : 'no-carrier' }
3168 for carrier
in [ 'off' , 'on' , 'off' ]:
3169 with self
. subTest ( carrier
= carrier
):
3170 if carrier_map
[ carrier
] != read_link_attr ( 'test1' , 'carrier' ):
3171 check_output ( f
'ip link set dev test1 carrier {carrier} ' )
3172 self
. wait_online ( f
'test1:{routable_map[carrier]}:{routable_map[carrier]}' )
3174 output
= networkctl_status ( 'test1' )
3176 self
. assertRegex ( output
, '192.168.0.15' )
3177 self
. assertRegex ( output
, '192.168.0.1' )
3178 self
. assertRegex ( output
, routable_map
[ carrier
])
3180 def test_configure_without_carrier_yes_ignore_carrier_loss_no ( self
):
3181 copy_network_unit ( '11-dummy.netdev' )
3183 self
. wait_operstate ( 'test1' , 'off' , '' )
3184 check_output ( 'ip link set dev test1 up carrier off' )
3186 copy_network_unit ( '25-test1.network' )
3188 self
. wait_online ( 'test1:no-carrier' )
3190 carrier_map
= { 'on' : '1' , 'off' : '0' }
3191 routable_map
= { 'on' : 'routable' , 'off' : 'no-carrier' }
3192 for ( carrier
, have_config
) in [( 'off' , True ), ( 'on' , True ), ( 'off' , False )]:
3193 with self
. subTest ( carrier
= carrier
, have_config
= have_config
):
3194 if carrier_map
[ carrier
] != read_link_attr ( 'test1' , 'carrier' ):
3195 check_output ( f
'ip link set dev test1 carrier {carrier} ' )
3196 self
. wait_online ( f
'test1:{routable_map[carrier]}:{routable_map[carrier]}' )
3198 output
= networkctl_status ( 'test1' )
3201 self
. assertRegex ( output
, '192.168.0.15' )
3202 self
. assertRegex ( output
, '192.168.0.1' )
3204 self
. assertNotRegex ( output
, '192.168.0.15' )
3205 self
. assertNotRegex ( output
, '192.168.0.1' )
3206 self
. assertRegex ( output
, routable_map
[ carrier
])
3208 def test_routing_policy_rule ( self
):
3209 copy_network_unit ( '25-routing-policy-rule-test1.network' , '11-dummy.netdev' )
3211 self
. wait_online ( 'test1:degraded' )
3213 output
= check_output ( 'ip rule list iif test1 priority 111' )
3215 self
. assertRegex ( output
, '111:' )
3216 self
. assertRegex ( output
, 'from 192.168.100.18' )
3217 self
. assertRegex ( output
, r
'tos (0x08|throughput)\s' )
3218 self
. assertRegex ( output
, 'iif test1' )
3219 self
. assertRegex ( output
, 'oif test1' )
3220 self
. assertRegex ( output
, 'lookup 7' )
3222 output
= check_output ( 'ip rule list iif test1 priority 101' )
3224 self
. assertRegex ( output
, '101:' )
3225 self
. assertRegex ( output
, 'from all' )
3226 self
. assertRegex ( output
, 'iif test1' )
3227 self
. assertRegex ( output
, 'lookup 9' )
3229 output
= check_output ( 'ip -6 rule list iif test1 priority 100' )
3231 self
. assertRegex ( output
, '100:' )
3232 self
. assertRegex ( output
, 'from all' )
3233 self
. assertRegex ( output
, 'iif test1' )
3234 self
. assertRegex ( output
, 'lookup 8' )
3236 output
= check_output ( 'ip rule list iif test1 priority 102' )
3238 self
. assertRegex ( output
, '102:' )
3239 self
. assertRegex ( output
, 'from 0.0.0.0/8' )
3240 self
. assertRegex ( output
, 'iif test1' )
3241 self
. assertRegex ( output
, 'lookup 10' )
3243 check_json ( networkctl_json ())
3245 def test_routing_policy_rule_issue_11280 ( self
):
3246 copy_network_unit ( '25-routing-policy-rule-test1.network' , '11-dummy.netdev' ,
3247 '25-routing-policy-rule-dummy98.network' , '12-dummy.netdev' )
3249 for trial
in range ( 3 ):
3250 restart_networkd ( show_logs
=( trial
> 0 ))
3251 self
. wait_online ( 'test1:degraded' , 'dummy98:degraded' )
3253 output
= check_output ( 'ip rule list table 7' )
3255 self
. assertRegex ( output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7' )
3257 output
= check_output ( 'ip rule list table 8' )
3259 self
. assertRegex ( output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8' )
3261 def test_routing_policy_rule_reconfigure ( self
):
3262 copy_network_unit ( '25-routing-policy-rule-reconfigure2.network' , '11-dummy.netdev' )
3264 self
. wait_online ( 'test1:degraded' )
3266 output
= check_output ( 'ip rule list table 1011' )
3268 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
3269 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
3270 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
3271 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
3273 output
= check_output ( 'ip -6 rule list table 1011' )
3275 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
3277 copy_network_unit ( '25-routing-policy-rule-reconfigure1.network' , '11-dummy.netdev' )
3279 self
. wait_online ( 'test1:degraded' )
3281 output
= check_output ( 'ip rule list table 1011' )
3283 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
3284 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
3285 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
3286 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
3288 output
= check_output ( 'ip -6 rule list table 1011' )
3290 self
. assertNotIn ( '10112: from all oif test1 lookup 1011' , output
)
3291 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
3293 call ( 'ip rule delete priority 10111' )
3294 call ( 'ip rule delete priority 10112' )
3295 call ( 'ip rule delete priority 10113' )
3296 call ( 'ip rule delete priority 10114' )
3297 call ( 'ip -6 rule delete priority 10113' )
3299 output
= check_output ( 'ip rule list table 1011' )
3301 self
. assertEqual ( output
, '' )
3303 output
= check_output ( 'ip -6 rule list table 1011' )
3305 self
. assertEqual ( output
, '' )
3307 networkctl_reconfigure ( 'test1' )
3308 self
. wait_online ( 'test1:degraded' )
3310 output
= check_output ( 'ip rule list table 1011' )
3312 self
. assertIn ( '10111: from all fwmark 0x3f3 lookup 1011' , output
)
3313 self
. assertIn ( '10112: from all oif test1 lookup 1011' , output
)
3314 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
3315 self
. assertIn ( '10114: from 192.168.8.254 lookup 1011' , output
)
3317 output
= check_output ( 'ip -6 rule list table 1011' )
3319 self
. assertIn ( '10113: from all iif test1 lookup 1011' , output
)
3321 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable ()
3322 def test_routing_policy_rule_port_range ( self
):
3323 copy_network_unit ( '25-fibrule-port-range.network' , '11-dummy.netdev' )
3325 self
. wait_online ( 'test1:degraded' )
3327 output
= check_output ( 'ip rule' )
3329 self
. assertIn ( '111:' , output
)
3330 self
. assertIn ( 'from 192.168.100.18 ' , output
)
3331 self
. assertIn ( 'sport 1123-1150 ' , output
)
3332 self
. assertIn ( 'dport 3224-3290 ' , output
)
3333 self
. assertRegex ( output
, 'ipproto (tcp|ipproto-6) ' )
3334 self
. assertIn ( 'lookup 7 ' , output
)
3336 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable ()
3337 def test_routing_policy_rule_invert ( self
):
3338 copy_network_unit ( '25-fibrule-invert.network' , '11-dummy.netdev' )
3340 self
. wait_online ( 'test1:degraded' )
3342 output
= check_output ( 'ip rule' )
3344 self
. assertIn ( '111:' , output
)
3345 self
. assertIn ( 'not ' , output
)
3346 self
. assertIn ( 'from 192.168.100.18 ' , output
)
3347 self
. assertRegex ( output
, 'ipproto (tcp|ipproto-6) ' )
3348 self
. assertIn ( 'lookup 7 ' , output
)
3350 @expectedFailureIfRoutingPolicyL3MasterDeviceIsNotAvailable ()
3351 def test_routing_policy_rule_l3mdev ( self
):
3352 copy_network_unit ( '25-fibrule-l3mdev.network' , '11-dummy.netdev' )
3354 self
. wait_online ( 'test1:degraded' )
3356 output
= check_output ( 'ip rule' )
3358 self
. assertIn ( '1500: from all lookup [l3mdev-table]' , output
)
3359 self
. assertIn ( '2000: from all lookup [l3mdev-table] unreachable' , output
)
3361 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable ()
3362 def test_routing_policy_rule_uidrange ( self
):
3363 copy_network_unit ( '25-fibrule-uidrange.network' , '11-dummy.netdev' )
3365 self
. wait_online ( 'test1:degraded' )
3367 output
= check_output ( 'ip rule' )
3369 self
. assertIn ( '111:' , output
)
3370 self
. assertIn ( 'from 192.168.100.18 ' , output
)
3371 self
. assertIn ( 'lookup 7 ' , output
)
3372 self
. assertIn ( 'uidrange 100-200 ' , output
)
3374 def _test_route_static ( self
, manage_foreign_routes
):
3375 if not manage_foreign_routes
:
3376 copy_networkd_conf_dropin ( 'networkd-manage-foreign-routes-no.conf' )
3378 copy_network_unit ( '25-route-static.network' , '12-dummy.netdev' ,
3379 '25-route-static-test1.network' , '11-dummy.netdev' )
3381 self
. wait_online ( 'dummy98:routable' )
3383 output
= networkctl_status ( 'dummy98' )
3386 print ( '### ip -6 route show dev dummy98' )
3387 output
= check_output ( 'ip -6 route show dev dummy98' )
3389 self
. assertIn ( '2001:1234:5:8fff:ff:ff:ff:ff proto static' , output
)
3390 self
. assertIn ( '2001:1234:5:8f63::1 proto kernel' , output
)
3391 self
. assertIn ( '2001:1234:5:afff:ff:ff:ff:ff via fe80:0:222:4dff:ff:ff:ff:ff proto static' , output
)
3393 print ( '### ip -6 route show default' )
3394 output
= check_output ( 'ip -6 route show default' )
3396 self
. assertIn ( 'default' , output
)
3397 self
. assertIn ( 'via 2001:1234:5:8fff:ff:ff:ff:ff' , output
)
3399 print ( '### ip -4 route show dev dummy98' )
3400 output
= check_output ( 'ip -4 route show dev dummy98' )
3402 self
. assertIn ( '149.10.124.48/28 proto kernel scope link src 149.10.124.58' , output
)
3403 self
. assertIn ( '149.10.124.64 proto static scope link' , output
)
3404 self
. assertIn ( '169.254.0.0/16 proto static scope link metric 2048' , output
)
3405 self
. assertIn ( '192.168.1.1 proto static scope link initcwnd 20' , output
)
3406 self
. assertIn ( '192.168.1.2 proto static scope link initrwnd 30' , output
)
3407 self
. assertIn ( '192.168.1.3 proto static scope link advmss 30' , output
)
3408 self
. assertIn ( '192.168.1.4 proto static scope link hoplimit 122' , output
)
3409 self
. assertIn ( 'multicast 149.10.123.4 proto static' , output
)
3411 print ( '### ip -4 route show dev dummy98 default' )
3412 output
= check_output ( 'ip -4 route show dev dummy98 default' )
3414 self
. assertIn ( 'default via 149.10.125.65 proto static onlink' , output
)
3415 self
. assertIn ( 'default via 149.10.124.64 proto static' , output
)
3416 self
. assertIn ( 'default proto static' , output
)
3417 self
. assertIn ( 'default via 1.1.8.104 proto static' , output
)
3419 print ( '### ip -4 route show table local dev dummy98' )
3420 output
= check_output ( 'ip -4 route show table local dev dummy98' )
3422 self
. assertIn ( 'local 149.10.123.1 proto static scope host' , output
)
3423 self
. assertIn ( 'anycast 149.10.123.2 proto static scope link' , output
)
3424 self
. assertIn ( 'broadcast 149.10.123.3 proto static scope link' , output
)
3426 print ( '### ip -4 route show type blackhole' )
3427 output
= check_output ( 'ip -4 route show type blackhole' )
3429 self
. assertIn ( 'blackhole 202.54.1.2 proto static' , output
)
3431 print ( '### ip -4 route show type unreachable' )
3432 output
= check_output ( 'ip -4 route show type unreachable' )
3434 self
. assertIn ( 'unreachable 202.54.1.3 proto static' , output
)
3436 print ( '### ip -4 route show type prohibit' )
3437 output
= check_output ( 'ip -4 route show type prohibit' )
3439 self
. assertIn ( 'prohibit 202.54.1.4 proto static' , output
)
3441 print ( '### ip -6 route show type blackhole' )
3442 output
= check_output ( 'ip -6 route show type blackhole' )
3444 self
. assertIn ( 'blackhole 2001:1234:5678::2 dev lo proto static' , output
)
3446 print ( '### ip -6 route show type unreachable' )
3447 output
= check_output ( 'ip -6 route show type unreachable' )
3449 self
. assertIn ( 'unreachable 2001:1234:5678::3 dev lo proto static' , output
)
3451 print ( '### ip -6 route show type prohibit' )
3452 output
= check_output ( 'ip -6 route show type prohibit' )
3454 self
. assertIn ( 'prohibit 2001:1234:5678::4 dev lo proto static' , output
)
3456 print ( '### ip route show 192.168.10.1' )
3457 output
= check_output ( 'ip route show 192.168.10.1' )
3459 self
. assertIn ( '192.168.10.1 proto static' , output
)
3460 self
. assertIn ( 'nexthop via 149.10.123.59 dev test1 weight 20' , output
)
3461 self
. assertIn ( 'nexthop via 149.10.123.60 dev test1 weight 30' , output
)
3462 self
. assertIn ( 'nexthop via 149.10.124.59 dev dummy98 weight 10' , output
)
3463 self
. assertIn ( 'nexthop via 149.10.124.60 dev dummy98 weight 5' , output
)
3465 print ( '### ip route show 192.168.10.2' )
3466 output
= check_output ( 'ip route show 192.168.10.2' )
3468 # old ip command does not show IPv6 gateways...
3469 self
. assertIn ( '192.168.10.2 proto static' , output
)
3470 self
. assertIn ( 'nexthop' , output
)
3471 self
. assertIn ( 'dev test1 weight 20' , output
)
3472 self
. assertIn ( 'dev test1 weight 30' , output
)
3473 self
. assertIn ( 'dev dummy98 weight 10' , output
)
3474 self
. assertIn ( 'dev dummy98 weight 5' , output
)
3476 print ( '### ip -6 route show 2001:1234:5:bfff:ff:ff:ff:ff' )
3477 output
= check_output ( 'ip -6 route show 2001:1234:5:bfff:ff:ff:ff:ff' )
3479 # old ip command does not show 'nexthop' keyword and weight...
3480 self
. assertIn ( '2001:1234:5:bfff:ff:ff:ff:ff' , output
)
3481 self
. assertIn ( 'via 2001:1234:5:6fff:ff:ff:ff:ff dev test1' , output
)
3482 self
. assertIn ( 'via 2001:1234:5:7fff:ff:ff:ff:ff dev test1' , output
)
3483 self
. assertIn ( 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98' , output
)
3484 self
. assertIn ( 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98' , output
)
3486 check_json ( networkctl_json ())
3488 copy_network_unit ( '25-address-static.network' , copy_dropins
= False )
3490 self
. wait_online ( 'dummy98:routable' )
3492 # check all routes managed by Manager are removed
3493 print ( '### ip -4 route show type blackhole' )
3494 output
= check_output ( 'ip -4 route show type blackhole' )
3496 self
. assertEqual ( output
, '' )
3498 print ( '### ip -4 route show type unreachable' )
3499 output
= check_output ( 'ip -4 route show type unreachable' )
3501 self
. assertEqual ( output
, '' )
3503 print ( '### ip -4 route show type prohibit' )
3504 output
= check_output ( 'ip -4 route show type prohibit' )
3506 self
. assertEqual ( output
, '' )
3508 print ( '### ip -6 route show type blackhole' )
3509 output
= check_output ( 'ip -6 route show type blackhole' )
3511 self
. assertEqual ( output
, '' )
3513 print ( '### ip -6 route show type unreachable' )
3514 output
= check_output ( 'ip -6 route show type unreachable' )
3516 self
. assertEqual ( output
, '' )
3518 print ( '### ip -6 route show type prohibit' )
3519 output
= check_output ( 'ip -6 route show type prohibit' )
3521 self
. assertEqual ( output
, '' )
3523 remove_network_unit ( '25-address-static.network' )
3525 self
. wait_online ( 'dummy98:routable' )
3527 # check all routes managed by Manager are reconfigured
3528 print ( '### ip -4 route show type blackhole' )
3529 output
= check_output ( 'ip -4 route show type blackhole' )
3531 self
. assertIn ( 'blackhole 202.54.1.2 proto static' , output
)
3533 print ( '### ip -4 route show type unreachable' )
3534 output
= check_output ( 'ip -4 route show type unreachable' )
3536 self
. assertIn ( 'unreachable 202.54.1.3 proto static' , output
)
3538 print ( '### ip -4 route show type prohibit' )
3539 output
= check_output ( 'ip -4 route show type prohibit' )
3541 self
. assertIn ( 'prohibit 202.54.1.4 proto static' , output
)
3543 print ( '### ip -6 route show type blackhole' )
3544 output
= check_output ( 'ip -6 route show type blackhole' )
3546 self
. assertIn ( 'blackhole 2001:1234:5678::2 dev lo proto static' , output
)
3548 print ( '### ip -6 route show type unreachable' )
3549 output
= check_output ( 'ip -6 route show type unreachable' )
3551 self
. assertIn ( 'unreachable 2001:1234:5678::3 dev lo proto static' , output
)
3553 print ( '### ip -6 route show type prohibit' )
3554 output
= check_output ( 'ip -6 route show type prohibit' )
3556 self
. assertIn ( 'prohibit 2001:1234:5678::4 dev lo proto static' , output
)
3558 remove_link ( 'dummy98' )
3561 # check all routes managed by Manager are removed
3562 print ( '### ip -4 route show type blackhole' )
3563 output
= check_output ( 'ip -4 route show type blackhole' )
3565 self
. assertEqual ( output
, '' )
3567 print ( '### ip -4 route show type unreachable' )
3568 output
= check_output ( 'ip -4 route show type unreachable' )
3570 self
. assertEqual ( output
, '' )
3572 print ( '### ip -4 route show type prohibit' )
3573 output
= check_output ( 'ip -4 route show type prohibit' )
3575 self
. assertEqual ( output
, '' )
3577 print ( '### ip -6 route show type blackhole' )
3578 output
= check_output ( 'ip -6 route show type blackhole' )
3580 self
. assertEqual ( output
, '' )
3582 print ( '### ip -6 route show type unreachable' )
3583 output
= check_output ( 'ip -6 route show type unreachable' )
3585 self
. assertEqual ( output
, '' )
3587 print ( '### ip -6 route show type prohibit' )
3588 output
= check_output ( 'ip -6 route show type prohibit' )
3590 self
. assertEqual ( output
, '' )
3592 def test_route_static ( self
):
3594 for manage_foreign_routes
in [ True , False ]:
3600 print ( f
'### test_route_static(manage_foreign_routes= {manage_foreign_routes} )' )
3601 with self
. subTest ( manage_foreign_routes
= manage_foreign_routes
):
3602 self
._ test
_ route
_ static
( manage_foreign_routes
)
3604 @expectedFailureIfRTA_VIAIsNotSupported ()
3605 def test_route_via_ipv6 ( self
):
3606 copy_network_unit ( '25-route-via-ipv6.network' , '12-dummy.netdev' )
3608 self
. wait_online ( 'dummy98:routable' )
3610 output
= networkctl_status ( 'dummy98' )
3613 print ( '### ip -6 route show dev dummy98' )
3614 output
= check_output ( 'ip -6 route show dev dummy98' )
3616 self
. assertRegex ( output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static' )
3617 self
. assertRegex ( output
, '2001:1234:5:8f63::1 proto kernel' )
3619 print ( '### ip -4 route show dev dummy98' )
3620 output
= check_output ( 'ip -4 route show dev dummy98' )
3622 self
. assertRegex ( output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58' )
3623 self
. assertRegex ( output
, '149.10.124.66 via inet6 2001:1234:5:8fff:ff:ff:ff:ff proto static' )
3625 @expectedFailureIfModuleIsNotAvailable ( 'tcp_dctcp' )
3626 def test_route_congctl ( self
):
3627 copy_network_unit ( '25-route-congctl.network' , '12-dummy.netdev' )
3629 self
. wait_online ( 'dummy98:routable' )
3631 print ( '### ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff' )
3632 output
= check_output ( 'ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff' )
3634 self
. assertIn ( '2001:1234:5:8fff:ff:ff:ff:ff proto static' , output
)
3635 self
. assertIn ( 'congctl dctcp' , output
)
3637 print ( '### ip -4 route show dev dummy98 149.10.124.66' )
3638 output
= check_output ( 'ip -4 route show dev dummy98 149.10.124.66' )
3640 self
. assertIn ( '149.10.124.66 proto static' , output
)
3641 self
. assertIn ( 'congctl dctcp' , output
)
3642 self
. assertIn ( 'rto_min 300s' , output
)
3644 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
3645 def test_route_vrf ( self
):
3646 copy_network_unit ( '25-route-vrf.network' , '12-dummy.netdev' ,
3647 '25-vrf.netdev' , '25-vrf.network' )
3649 self
. wait_online ( 'dummy98:routable' , 'vrf99:carrier' )
3651 output
= check_output ( 'ip route show vrf vrf99' )
3653 self
. assertRegex ( output
, 'default via 192.168.100.1' )
3655 output
= check_output ( 'ip route show' )
3657 self
. assertNotRegex ( output
, 'default via 192.168.100.1' )
3659 def test_gateway_reconfigure ( self
):
3660 copy_network_unit ( '25-gateway-static.network' , '12-dummy.netdev' )
3662 self
. wait_online ( 'dummy98:routable' )
3663 print ( '### ip -4 route show dev dummy98 default' )
3664 output
= check_output ( 'ip -4 route show dev dummy98 default' )
3666 self
. assertIn ( 'default via 149.10.124.59 proto static' , output
)
3667 self
. assertNotIn ( '149.10.124.60' , output
)
3669 remove_network_unit ( '25-gateway-static.network' )
3670 copy_network_unit ( '25-gateway-next-static.network' )
3672 self
. wait_online ( 'dummy98:routable' )
3673 print ( '### ip -4 route show dev dummy98 default' )
3674 output
= check_output ( 'ip -4 route show dev dummy98 default' )
3676 self
. assertNotIn ( '149.10.124.59' , output
)
3677 self
. assertIn ( 'default via 149.10.124.60 proto static' , output
)
3679 def test_ip_route_ipv6_src_route ( self
):
3680 # a dummy device does not make the addresses go through tentative state, so we
3681 # reuse a bond from an earlier test, which does make the addresses go through
3682 # tentative state, and do our test on that
3683 copy_network_unit ( '23-active-slave.network' , '25-route-ipv6-src.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
3685 self
. wait_online ( 'dummy98:enslaved' , 'bond199:routable' )
3687 output
= check_output ( 'ip -6 route list dev bond199' )
3689 self
. assertIn ( 'abcd::/16 via 2001:1234:56:8f63::1:1 proto static src 2001:1234:56:8f63::2' , output
)
3691 def test_route_preferred_source_with_existing_address ( self
):
3693 copy_network_unit ( '25-route-preferred-source.network' , '12-dummy.netdev' )
3698 networkctl_reconfigure ( 'dummy98' )
3700 self
. wait_online ( 'dummy98:routable' )
3702 output
= check_output ( 'ip -6 route list dev dummy98' )
3704 self
. assertIn ( 'abcd::/16 via 2001:1234:56:8f63::1:1 proto static src 2001:1234:56:8f63::1' , output
)
3706 def test_ip_link_mac_address ( self
):
3707 copy_network_unit ( '25-address-link-section.network' , '12-dummy.netdev' )
3709 self
. wait_online ( 'dummy98:degraded' )
3711 output
= check_output ( 'ip link show dummy98' )
3713 self
. assertRegex ( output
, '00:01:02:aa:bb:cc' )
3715 def test_ip_link_unmanaged ( self
):
3716 copy_network_unit ( '25-link-section-unmanaged.network' , '12-dummy.netdev' )
3719 self
. wait_operstate ( 'dummy98' , 'off' , setup_state
= 'unmanaged' )
3721 def test_ipv6_address_label ( self
):
3722 copy_network_unit ( '25-ipv6-address-label-section.network' , '12-dummy.netdev' )
3724 self
. wait_online ( 'dummy98:degraded' )
3726 output
= check_output ( 'ip addrlabel list' )
3728 self
. assertRegex ( output
, '2004:da8:1::/64' )
3730 def test_ipv6_proxy_ndp ( self
):
3731 copy_network_unit ( '25-ipv6-proxy-ndp.network' , '12-dummy.netdev' )
3734 self
. wait_online ( 'dummy98:routable' )
3736 output
= check_output ( 'ip neighbor show proxy dev dummy98' )
3738 for i
in range ( 1 , 5 ):
3739 self
. assertRegex ( output
, f
'2607:5300:203:5215: {i} ::1 *proxy' )
3741 def test_ipv6_neigh_retrans_time ( self
):
3743 copy_network_unit ( '25-dummy.netdev' , '25-dummy.network' )
3746 self
. wait_online ( f
' {link} :degraded' )
3747 remove_network_unit ( '25-dummy.network' )
3749 # expect retrans_time_ms updated
3750 copy_network_unit ( '25-ipv6-neigh-retrans-time-3s.network' )
3752 self
. wait_online ( f
' {link} :degraded' )
3753 self
. check_ipv6_neigh_sysctl_attr ( link
, 'retrans_time_ms' , '3000' )
3754 remove_network_unit ( '25-ipv6-neigh-retrans-time-3s.network' )
3756 # expect retrans_time_ms unchanged
3757 copy_network_unit ( '25-ipv6-neigh-retrans-time-0s.network' )
3759 self
. wait_online ( f
' {link} :degraded' )
3760 self
. check_ipv6_neigh_sysctl_attr ( link
, 'retrans_time_ms' , '3000' )
3761 remove_network_unit ( '25-ipv6-neigh-retrans-time-0s.network' )
3763 # expect retrans_time_ms unchanged
3764 copy_network_unit ( '25-ipv6-neigh-retrans-time-toobig.network' )
3766 self
. wait_online ( f
' {link} :degraded' )
3767 self
. check_ipv6_neigh_sysctl_attr ( link
, 'retrans_time_ms' , '3000' )
3768 remove_network_unit ( '25-ipv6-neigh-retrans-time-toobig.network' )
3770 # expect retrans_time_ms unchanged
3771 copy_network_unit ( '25-ipv6-neigh-retrans-time-infinity.network' )
3773 self
. wait_online ( f
' {link} :degraded' )
3774 self
. check_ipv6_neigh_sysctl_attr ( link
, 'retrans_time_ms' , '3000' )
3775 remove_network_unit ( '25-ipv6-neigh-retrans-time-infinity.network' )
3777 # expect retrans_time_ms unchanged
3778 copy_network_unit ( '25-ipv6-neigh-retrans-time-invalid.network' )
3780 self
. wait_online ( f
' {link} :degraded' )
3781 self
. check_ipv6_neigh_sysctl_attr ( link
, 'retrans_time_ms' , '3000' )
3782 remove_network_unit ( '25-ipv6-neigh-retrans-time-invalid.network' )
3784 # expect retrans_time_ms updated
3785 copy_network_unit ( '25-ipv6-neigh-retrans-time-4s.network' )
3787 self
. wait_online ( f
' {link} :degraded' )
3788 self
. check_ipv6_neigh_sysctl_attr ( link
, 'retrans_time_ms' , '4000' )
3789 remove_network_unit ( '25-ipv6-neigh-retrans-time-4s.network' )
3791 def test_neighbor ( self
):
3792 copy_network_unit ( '12-dummy.netdev' , '25-neighbor-dummy.network' , '25-neighbor-dummy.network.d/10-step1.conf' ,
3793 '25-gre-tunnel-remote-any.netdev' , '25-neighbor-ip.network' ,
3794 '25-ip6gre-tunnel-remote-any.netdev' , '25-neighbor-ipv6.network' ,
3797 self
. wait_online ( 'dummy98:degraded' , 'gretun97:routable' , 'ip6gretun97:routable' )
3799 print ( '### ip neigh list dev gretun97' )
3800 output
= check_output ( 'ip neigh list dev gretun97' )
3802 self
. assertIn ( '10.0.0.22 lladdr 10.65.223.239 PERMANENT' , output
)
3803 self
. assertNotIn ( '10.0.0.23' , output
)
3805 print ( '### ip neigh list dev ip6gretun97' )
3806 output
= check_output ( 'ip neigh list dev ip6gretun97' )
3808 self
. assertRegex ( output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT' )
3809 self
. assertNotIn ( '2001:db8:0:f102::18' , output
)
3811 print ( '### ip neigh list dev dummy98' )
3812 output
= check_output ( 'ip neigh list dev dummy98' )
3814 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:02:65 PERMANENT' , output
)
3815 self
. assertIn ( '2004:da8:1::1 lladdr 00:00:5e:00:02:66 PERMANENT' , output
)
3816 self
. assertNotIn ( '2004:da8:1:0::2' , output
)
3817 self
. assertNotIn ( '192.168.10.2' , output
)
3818 self
. assertNotIn ( '00:00:5e:00:02:67' , output
)
3820 check_json ( networkctl_json ())
3822 # Here, 10-step1.conf is intendedly kept, to verify that 10-step2.conf overrides
3823 # the valid configurations in 10-step1.conf.
3824 copy_network_unit ( '25-neighbor-dummy.network.d/10-step2.conf' )
3826 self
. wait_online ( 'dummy98:degraded' )
3828 print ( '### ip neigh list dev dummy98' )
3829 output
= check_output ( 'ip neigh list dev dummy98' )
3831 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:03:65 PERMANENT' , output
)
3832 self
. assertIn ( '2004:da8:1::1 lladdr 00:00:5e:00:03:66 PERMANENT' , output
)
3833 self
. assertNotIn ( '2004:da8:1:0::2' , output
)
3834 self
. assertNotIn ( '192.168.10.2' , output
)
3835 self
. assertNotIn ( '00:00:5e:00:02:67' , output
)
3837 check_json ( networkctl_json ())
3839 remove_network_unit ( '25-neighbor-dummy.network.d/10-step1.conf' ,
3840 '25-neighbor-dummy.network.d/10-step2.conf' )
3841 copy_network_unit ( '25-neighbor-dummy.network.d/10-step3.conf' )
3843 self
. wait_online ( 'dummy98:degraded' )
3845 print ( '### ip neigh list dev dummy98' )
3846 output
= check_output ( 'ip neigh list dev dummy98' )
3848 self
. assertIn ( '192.168.10.1 lladdr 00:00:5e:00:03:66 PERMANENT' , output
)
3849 self
. assertNotIn ( '00:00:5e:00:02:65' , output
)
3850 self
. assertNotIn ( '00:00:5e:00:02:66' , output
)
3851 self
. assertNotIn ( '00:00:5e:00:03:65' , output
)
3852 self
. assertNotIn ( '2004:da8:1::1' , output
)
3854 def test_link_local_addressing ( self
):
3855 copy_network_unit ( '25-link-local-addressing-yes.network' , '11-dummy.netdev' ,
3856 '25-link-local-addressing-no.network' , '12-dummy.netdev' )
3858 self
. wait_online ( 'test1:degraded' , 'dummy98:carrier' )
3860 output
= check_output ( 'ip address show dev test1' )
3862 self
. assertRegex ( output
, 'inet .* scope link' )
3863 self
. assertRegex ( output
, 'inet6 .* scope link' )
3865 output
= check_output ( 'ip address show dev dummy98' )
3867 self
. assertNotRegex ( output
, 'inet6* .* scope link' )
3869 # Documentation/networking/ip-sysctl.txt
3871 # addr_gen_mode - INTEGER
3872 # Defines how link-local and autoconf addresses are generated.
3874 # 0: generate address based on EUI64 (default)
3875 # 1: do no generate a link-local address, use EUI64 for addresses generated
3877 # 2: generate stable privacy addresses, using the secret from
3878 # stable_secret (RFC7217)
3879 # 3: generate stable privacy addresses, using a random secret if unset
3881 self
. check_ipv6_sysctl_attr ( 'test1' , 'stable_secret' , '0123:4567:89ab:cdef:0123:4567:89ab:cdef' )
3882 self
. check_ipv6_sysctl_attr ( 'test1' , 'addr_gen_mode' , '2' )
3883 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'addr_gen_mode' , '1' )
3885 def test_link_local_addressing_ipv6ll ( self
):
3886 copy_network_unit ( '26-link-local-addressing-ipv6.network' , '12-dummy.netdev' )
3888 self
. wait_online ( 'dummy98:degraded' )
3890 # An IPv6LL address exists by default.
3891 output
= check_output ( 'ip address show dev dummy98' )
3893 self
. assertRegex ( output
, 'inet6 .* scope link' )
3895 copy_network_unit ( '25-link-local-addressing-no.network' )
3897 self
. wait_online ( 'dummy98:carrier' )
3899 # Check if the IPv6LL address is removed.
3900 output
= check_output ( 'ip address show dev dummy98' )
3902 self
. assertNotRegex ( output
, 'inet6 .* scope link' )
3904 remove_network_unit ( '25-link-local-addressing-no.network' )
3906 self
. wait_online ( 'dummy98:degraded' )
3908 # Check if a new IPv6LL address is assigned.
3909 output
= check_output ( 'ip address show dev dummy98' )
3911 self
. assertRegex ( output
, 'inet6 .* scope link' )
3913 def test_sysctl ( self
):
3914 copy_networkd_conf_dropin ( '25-global-ipv6-privacy-extensions.conf' )
3915 copy_network_unit ( '25-sysctl.network' , '12-dummy.netdev' , copy_dropins
= False )
3917 self
. wait_online ( 'dummy98:degraded' )
3919 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
3920 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'use_tempaddr' , '1' )
3921 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'dad_transmits' , '3' )
3922 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'hop_limit' , '5' )
3923 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'proxy_ndp' , '1' )
3924 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'forwarding' , '1' )
3925 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'proxy_arp' , '1' )
3926 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'proxy_arp_pvlan' , '1' )
3927 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'accept_local' , '1' )
3928 self
. check_ipv4_sysctl_attr ( 'dummy98' , 'rp_filter' , '0' )
3930 copy_network_unit ( '25-sysctl.network.d/25-ipv6-privacy-extensions.conf' )
3932 self
. wait_online ( 'dummy98:degraded' )
3934 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'use_tempaddr' , '2' )
3936 def test_sysctl_disable_ipv6 ( self
):
3937 copy_network_unit ( '25-sysctl-disable-ipv6.network' , '12-dummy.netdev' )
3939 print ( '## Disable ipv6' )
3940 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=1' )
3941 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=1' )
3944 self
. wait_online ( 'dummy98:routable' )
3946 output
= check_output ( 'ip -4 address show dummy98' )
3948 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3949 output
= check_output ( 'ip -6 address show dummy98' )
3951 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3952 self
. assertRegex ( output
, 'inet6 .* scope link' )
3953 output
= check_output ( 'ip -4 route show dev dummy98' )
3955 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3956 output
= check_output ( 'ip -6 route show default' )
3958 self
. assertRegex ( output
, 'default' )
3959 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3961 remove_link ( 'dummy98' )
3963 print ( '## Enable ipv6' )
3964 check_output ( 'sysctl net.ipv6.conf.all.disable_ipv6=0' )
3965 check_output ( 'sysctl net.ipv6.conf.default.disable_ipv6=0' )
3968 self
. wait_online ( 'dummy98:routable' )
3970 output
= check_output ( 'ip -4 address show dummy98' )
3972 self
. assertRegex ( output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98' )
3973 output
= check_output ( 'ip -6 address show dummy98' )
3975 self
. assertRegex ( output
, 'inet6 2607:5300:203:3906::/64 scope global' )
3976 self
. assertRegex ( output
, 'inet6 .* scope link' )
3977 output
= check_output ( 'ip -4 route show dev dummy98' )
3979 self
. assertRegex ( output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4' )
3980 output
= check_output ( 'ip -6 route show default' )
3982 self
. assertRegex ( output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff' )
3984 def test_bind_carrier ( self
):
3985 copy_network_unit ( '25-bind-carrier.network' , '11-dummy.netdev' )
3988 # no bound interface.
3989 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
3990 output
= check_output ( 'ip address show test1' )
3992 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
3993 self
. assertIn ( 'DOWN' , output
)
3994 self
. assertNotIn ( '192.168.10' , output
)
3996 # add one bound interface. The interface will be up.
3997 check_output ( 'ip link add dummy98 type dummy' )
3998 check_output ( 'ip link set dummy98 up' )
3999 self
. wait_online ( 'test1:routable' )
4000 output
= check_output ( 'ip address show test1' )
4002 self
. assertIn ( 'UP,LOWER_UP' , output
)
4003 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
4005 # add another bound interface. The interface is still up.
4006 check_output ( 'ip link add dummy99 type dummy' )
4007 check_output ( 'ip link set dummy99 up' )
4008 self
. wait_operstate ( 'dummy99' , 'degraded' , setup_state
= 'unmanaged' )
4009 output
= check_output ( 'ip address show test1' )
4011 self
. assertIn ( 'UP,LOWER_UP' , output
)
4012 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
4014 # remove one of the bound interfaces. The interface is still up
4015 remove_link ( 'dummy98' )
4016 output
= check_output ( 'ip address show test1' )
4018 self
. assertIn ( 'UP,LOWER_UP' , output
)
4019 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
4021 # bring down the remaining bound interface. The interface will be down.
4022 check_output ( 'ip link set dummy99 down' )
4023 self
. wait_operstate ( 'test1' , 'off' )
4024 self
. wait_address_dropped ( 'test1' , r
'192.168.10' , ipv
= '-4' , timeout_sec
= 10 )
4025 output
= check_output ( 'ip address show test1' )
4027 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
4028 self
. assertIn ( 'DOWN' , output
)
4029 self
. assertNotIn ( '192.168.10' , output
)
4031 # bring up the bound interface. The interface will be up.
4032 check_output ( 'ip link set dummy99 up' )
4033 self
. wait_online ( 'test1:routable' )
4034 output
= check_output ( 'ip address show test1' )
4036 self
. assertIn ( 'UP,LOWER_UP' , output
)
4037 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
4039 # remove the remaining bound interface. The interface will be down.
4040 remove_link ( 'dummy99' )
4041 self
. wait_operstate ( 'test1' , 'off' )
4042 self
. wait_address_dropped ( 'test1' , r
'192.168.10' , ipv
= '-4' , timeout_sec
= 10 )
4043 output
= check_output ( 'ip address show test1' )
4045 self
. assertNotIn ( 'UP,LOWER_UP' , output
)
4046 self
. assertIn ( 'DOWN' , output
)
4047 self
. assertNotIn ( '192.168.10' , output
)
4049 # re-add one bound interface. The interface will be up.
4050 check_output ( 'ip link add dummy98 type dummy' )
4051 check_output ( 'ip link set dummy98 up' )
4052 self
. wait_online ( 'test1:routable' )
4053 output
= check_output ( 'ip address show test1' )
4055 self
. assertIn ( 'UP,LOWER_UP' , output
)
4056 self
. assertIn ( 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1' , output
)
4058 def _test_activation_policy ( self
, interface
, test
):
4059 conffile
= '25-activation-policy.network'
4061 conffile
= f
' {conffile} .d/ {test} .conf'
4062 if interface
== 'vlan99' :
4063 copy_network_unit ( '21-vlan.netdev' , '21-vlan-test1.network' )
4064 copy_network_unit ( '11-dummy.netdev' , conffile
, copy_dropins
= False )
4067 always
= test
. startswith ( 'always' )
4068 initial_up
= test
!= 'manual' and not test
. endswith ( 'down' ) # note: default is up
4069 expect_up
= initial_up
4070 next_up
= not expect_up
4072 if test
. endswith ( 'down' ):
4073 self
. wait_activated ( interface
)
4075 for iteration
in range ( 4 ):
4076 with self
. subTest ( iteration
= iteration
, expect_up
= expect_up
):
4077 operstate
= 'routable' if expect_up
else 'off'
4078 setup_state
= 'configured' if expect_up
else ( 'configuring' if iteration
== 0 else None )
4079 self
. wait_operstate ( interface
, operstate
, setup_state
= setup_state
, setup_timeout
= 20 )
4082 self
. assertIn ( 'UP' , check_output ( f
'ip link show {interface} ' ))
4083 self
. assertIn ( '192.168.10.30/24' , check_output ( f
'ip address show {interface} ' ))
4084 self
. assertIn ( 'default via 192.168.10.1' , check_output ( f
'ip route show dev {interface} ' ))
4086 self
. assertIn ( 'DOWN' , check_output ( f
'ip link show {interface} ' ))
4089 check_output ( f
'ip link set dev {interface} up' )
4091 check_output ( f
'ip link set dev {interface} down' )
4092 expect_up
= initial_up
if always
else next_up
4093 next_up
= not next_up
4097 def test_activation_policy ( self
):
4099 for interface
in [ 'test1' , 'vlan99' ]:
4100 for test
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , '' ]:
4106 print ( f
'### test_activation_policy(interface= {interface} , test= {test} )' )
4107 with self
. subTest ( interface
= interface
, test
= test
):
4108 self
._ test
_ activation
_ policy
( interface
, test
)
4110 def _test_activation_policy_required_for_online ( self
, policy
, required
):
4111 conffile
= '25-activation-policy.network'
4112 units
= [ '11-dummy.netdev' , '12-dummy.netdev' , '12-dummy.network' , conffile
]
4114 units
+= [ f
' {conffile} .d/ {policy} .conf' ]
4116 units
+= [ f
' {conffile} .d/required- {required} .conf' ]
4117 copy_network_unit (* units
, copy_dropins
= False )
4120 if policy
. endswith ( 'down' ):
4121 self
. wait_activated ( 'test1' )
4123 if policy
. endswith ( 'down' ) or policy
== 'manual' :
4124 self
. wait_operstate ( 'test1' , 'off' , setup_state
= 'configuring' )
4126 self
. wait_online ( 'test1' )
4128 if policy
== 'always-down' :
4129 # if always-down, required for online is forced to no
4132 # otherwise if required for online is specified, it should match that
4133 expected
= required
== 'yes'
4135 # otherwise if only policy specified, required for online defaults to
4136 # true if policy is up, always-up, or bound
4137 expected
= policy
. endswith ( 'up' ) or policy
== 'bound'
4139 # default is true, if neither are specified
4142 output
= networkctl_status ( 'test1' )
4145 yesno
= 'yes' if expected
else 'no'
4146 self
. assertRegex ( output
, f
'Required For Online: {yesno} ' )
4148 def test_activation_policy_required_for_online ( self
):
4150 for policy
in [ 'up' , 'always-up' , 'manual' , 'always-down' , 'down' , 'bound' , '' ]:
4151 for required
in [ 'yes' , 'no' , '' ]:
4157 print ( f
'### test_activation_policy_required_for_online(policy= {policy} , required= {required} )' )
4158 with self
. subTest ( policy
= policy
, required
= required
):
4159 self
._ test
_ activation
_ policy
_ required
_ for
_ online
( policy
, required
)
4161 def test_domain ( self
):
4162 copy_network_unit ( '12-dummy.netdev' , '24-search-domain.network' )
4164 self
. wait_online ( 'dummy98:routable' )
4166 output
= networkctl_status ( 'dummy98' )
4168 self
. assertRegex ( output
, 'Address: 192.168.42.100' )
4169 self
. assertRegex ( output
, 'DNS: 192.168.42.1' )
4170 self
. assertRegex ( output
, 'Search Domains: one' )
4172 def test_keep_configuration_static ( self
):
4173 check_output ( 'ip link add name dummy98 type dummy' )
4174 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
4175 check_output ( 'ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500' )
4176 output
= check_output ( 'ip address show dummy98' )
4178 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
4179 self
. assertRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
4180 output
= check_output ( 'ip route show dev dummy98' )
4183 copy_network_unit ( '24-keep-configuration-static.network' )
4185 self
. wait_online ( 'dummy98:routable' )
4187 output
= check_output ( 'ip address show dummy98' )
4189 self
. assertRegex ( output
, 'inet 10.1.2.3/16 scope global dummy98' )
4190 self
. assertNotRegex ( output
, 'inet 10.2.3.4/16 scope global dynamic dummy98' )
4192 def check_nexthop ( self
, manage_foreign_nexthops
, first
):
4193 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' )
4195 output
= check_output ( 'ip nexthop list dev veth99' )
4198 self
. assertIn ( 'id 1 via 192.168.5.1 dev veth99' , output
)
4199 self
. assertIn ( 'id 2 via 2001:1234:5:8f63::2 dev veth99' , output
)
4201 self
. assertIn ( 'id 6 via 192.168.5.1 dev veth99' , output
)
4202 self
. assertIn ( 'id 7 via 2001:1234:5:8f63::2 dev veth99' , output
)
4203 self
. assertIn ( 'id 3 dev veth99' , output
)
4204 self
. assertIn ( 'id 4 dev veth99' , output
)
4206 self
. assertRegex ( output
, 'id 5 via 192.168.10.1 dev veth99 .*onlink' )
4208 self
. assertIn ( 'id 5 via 192.168.5.3 dev veth99' , output
)
4209 self
. assertNotRegex ( output
, 'id 5 via 192.168.5.3 dev veth99 .*onlink' )
4210 self
. assertIn ( 'id 8 via fe80:0:222:4dff:ff:ff:ff:ff dev veth99' , output
)
4211 if manage_foreign_nexthops
:
4212 self
. assertRegex ( output
, r
'id [0-9]* via 192.168.5.2 dev veth99' )
4214 output
= check_output ( 'ip nexthop list dev dummy98' )
4217 self
. assertIn ( 'id 20 via 192.168.20.1 dev dummy98' , output
)
4219 self
. assertIn ( 'id 21 via 192.168.20.1 dev dummy98' , output
)
4220 if manage_foreign_nexthops
:
4221 self
. assertNotIn ( 'id 42 via 192.168.20.2 dev dummy98' , output
)
4223 self
. assertIn ( 'id 42 via 192.168.20.2 dev dummy98' , output
)
4225 # kernel manages blackhole nexthops on lo
4226 output
= check_output ( 'ip nexthop list dev lo' )
4229 self
. assertIn ( 'id 6 blackhole' , output
)
4230 self
. assertIn ( 'id 7 blackhole' , output
)
4232 self
. assertIn ( 'id 1 blackhole' , output
)
4233 self
. assertIn ( 'id 2 blackhole' , output
)
4235 # group nexthops are shown with -0 option
4237 output
= check_output ( 'ip -0 nexthop list id 21' )
4239 self
. assertRegex ( output
, r
'id 21 group (1,3/20|20/1,3)' )
4241 output
= check_output ( 'ip -0 nexthop list id 20' )
4243 self
. assertRegex ( output
, r
'id 20 group (5,3/21|21/5,3)' )
4245 output
= check_output ( 'ip route show dev veth99 10.10.10.10' )
4248 self
. assertEqual ( '10.10.10.10 nhid 1 via 192.168.5.1 proto static' , output
)
4250 self
. assertEqual ( '10.10.10.10 nhid 6 via 192.168.5.1 proto static' , output
)
4252 output
= check_output ( 'ip route show dev veth99 10.10.10.11' )
4255 self
. assertEqual ( '10.10.10.11 nhid 2 via inet6 2001:1234:5:8f63::2 proto static' , output
)
4257 self
. assertEqual ( '10.10.10.11 nhid 7 via inet6 2001:1234:5:8f63::2 proto static' , output
)
4259 output
= check_output ( 'ip route show dev veth99 10.10.10.12' )
4262 self
. assertEqual ( '10.10.10.12 nhid 5 via 192.168.10.1 proto static onlink' , output
)
4264 self
. assertEqual ( '10.10.10.12 nhid 5 via 192.168.5.3 proto static' , output
)
4266 output
= check_output ( 'ip -6 route show dev veth99 2001:1234:5:8f62::1' )
4269 self
. assertEqual ( '2001:1234:5:8f62::1 nhid 2 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium' , output
)
4271 self
. assertEqual ( '2001:1234:5:8f62::1 nhid 7 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium' , output
)
4273 output
= check_output ( 'ip route show 10.10.10.13' )
4276 self
. assertEqual ( 'blackhole 10.10.10.13 nhid 6 dev lo proto static' , output
)
4278 self
. assertEqual ( 'blackhole 10.10.10.13 nhid 1 dev lo proto static' , output
)
4280 output
= check_output ( 'ip -6 route show 2001:1234:5:8f62::2' )
4283 self
. assertEqual ( 'blackhole 2001:1234:5:8f62::2 nhid 7 dev lo proto static metric 1024 pref medium' , output
)
4285 self
. assertEqual ( 'blackhole 2001:1234:5:8f62::2 nhid 2 dev lo proto static metric 1024 pref medium' , output
)
4287 output
= check_output ( 'ip route show 10.10.10.14' )
4290 self
. assertIn ( '10.10.10.14 nhid 21 proto static' , output
)
4291 self
. assertIn ( 'nexthop via 192.168.5.1 dev veth99 weight 3' , output
)
4293 self
. assertIn ( '10.10.10.14 nhid 20 proto static' , output
)
4294 self
. assertIn ( 'nexthop via 192.168.5.3 dev veth99 weight 3' , output
)
4295 self
. assertIn ( 'nexthop via 192.168.20.1 dev dummy98 weight 1' , output
)
4297 output
= networkctl_json ()
4299 self
. assertNotIn ( '"Destination":[10.10.10.14]' , output
)
4301 def _test_nexthop ( self
, manage_foreign_nexthops
):
4302 if not manage_foreign_nexthops
:
4303 copy_networkd_conf_dropin ( 'networkd-manage-foreign-nexthops-no.conf' )
4305 check_output ( 'ip link add dummy98 type dummy' )
4306 check_output ( 'ip link set dummy98 up' )
4307 check_output ( 'ip address add 192.168.20.20/24 dev dummy98' )
4308 check_output ( 'ip nexthop add id 42 via 192.168.20.2 dev dummy98' )
4310 copy_network_unit ( '25-nexthop-1.network' , '25-veth.netdev' , '25-veth-peer.network' ,
4311 '12-dummy.netdev' , '25-nexthop-dummy-1.network' )
4314 self
. check_nexthop ( manage_foreign_nexthops
, first
= True )
4316 remove_network_unit ( '25-nexthop-1.network' , '25-nexthop-dummy-1.network' )
4317 copy_network_unit ( '25-nexthop-2.network' , '25-nexthop-dummy-2.network' )
4319 self
. check_nexthop ( manage_foreign_nexthops
, first
= False )
4321 remove_network_unit ( '25-nexthop-2.network' )
4322 copy_network_unit ( '25-nexthop-nothing.network' )
4324 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
4326 output
= check_output ( 'ip nexthop list dev veth99' )
4328 self
. assertEqual ( output
, '' )
4329 output
= check_output ( 'ip nexthop list dev lo' )
4331 self
. assertEqual ( output
, '' )
4333 remove_network_unit ( '25-nexthop-nothing.network' , '25-nexthop-dummy-2.network' )
4334 copy_network_unit ( '25-nexthop-1.network' , '25-nexthop-dummy-1.network' )
4335 # Of course, networkctl_reconfigure() below is unnecessary in normal operation, but it is intentional
4336 # here to test reconfiguring with different .network files does not trigger race.
4337 # See also comments in link_drop_requests().
4338 networkctl_reconfigure ( 'dummy98' ) # reconfigured with 25-nexthop-dummy-2.network
4339 networkctl_reload () # reconfigured with 25-nexthop-dummy-1.network
4341 self
. check_nexthop ( manage_foreign_nexthops
, first
= True )
4343 # Remove nexthop with ID 20
4344 check_output ( 'ip nexthop del id 20' )
4345 copy_network_unit ( '11-dummy.netdev' , '25-nexthop-test1.network' )
4348 # 25-nexthop-test1.network requests a route with nexthop ID 21,
4349 # which is silently removed by the kernel when nexthop with ID 20 is removed in the above,
4350 # hence test1 should be stuck in the configuring state.
4351 self
. wait_operstate ( 'test1' , operstate
= 'routable' , setup_state
= 'configuring' )
4353 # Wait for a while, and check if the interface is still in the configuring state.
4355 output
= networkctl_status ( 'test1' )
4356 self
. assertIn ( 'State: routable (configuring)' , output
)
4358 # Check if the route which needs nexthop 20 and 21 are forgotten.
4359 output
= networkctl_json ()
4361 self
. assertNotIn ( '"Destination":[10.10.10.14]' , output
)
4363 # Reconfigure the interface that has nexthop with ID 20 and 21,
4364 # then the route requested by test1 can be configured.
4365 networkctl_reconfigure ( 'dummy98' )
4366 self
. wait_online ( 'test1:routable' )
4368 # Check if the requested route actually configured.
4369 output
= check_output ( 'ip route show 10.10.11.10' )
4371 self
. assertIn ( '10.10.11.10 nhid 21 proto static' , output
)
4372 self
. assertIn ( 'nexthop via 192.168.5.1 dev veth99 weight 3' , output
)
4373 self
. assertIn ( 'nexthop via 192.168.20.1 dev dummy98 weight 1' , output
)
4375 remove_link ( 'veth99' )
4378 output
= check_output ( 'ip nexthop list dev lo' )
4380 self
. assertEqual ( output
, '' )
4382 @expectedFailureIfNexthopIsNotAvailable ()
4383 def test_nexthop ( self
):
4385 for manage_foreign_nexthops
in [ True , False ]:
4391 print ( f
'### test_nexthop(manage_foreign_nexthops= {manage_foreign_nexthops} )' )
4392 with self
. subTest ( manage_foreign_nexthops
= manage_foreign_nexthops
):
4393 self
._ test
_ nexthop
( manage_foreign_nexthops
)
4395 class NetworkdTCTests ( unittest
. TestCase
, Utilities
):
4403 @expectedFailureIfModuleIsNotAvailable ( 'sch_cake' )
4404 def test_qdisc_cake ( self
):
4405 copy_network_unit ( '25-qdisc-cake.network' , '12-dummy.netdev' )
4407 self
. wait_online ( 'dummy98:routable' )
4409 output
= check_output ( 'tc qdisc show dev dummy98' )
4411 self
. assertIn ( 'qdisc cake 3a: root' , output
)
4412 self
. assertIn ( 'bandwidth 500Mbit' , output
)
4413 self
. assertIn ( 'autorate-ingress' , output
)
4414 self
. assertIn ( 'diffserv8' , output
)
4415 self
. assertIn ( 'dual-dsthost' , output
)
4416 self
. assertIn ( ' nat' , output
)
4417 self
. assertIn ( ' wash' , output
)
4418 self
. assertIn ( ' split-gso' , output
)
4419 self
. assertIn ( ' raw' , output
)
4420 self
. assertIn ( ' atm' , output
)
4421 self
. assertIn ( 'overhead 128' , output
)
4422 self
. assertIn ( 'mpu 20' , output
)
4423 self
. assertIn ( 'fwmark 0xff00' , output
)
4424 self
. assertIn ( 'rtt 1s' , output
)
4425 self
. assertIn ( 'ack-filter-aggressive' , output
)
4427 @expectedFailureIfModuleIsNotAvailable ( 'sch_codel' )
4428 def test_qdisc_codel ( self
):
4429 copy_network_unit ( '25-qdisc-codel.network' , '12-dummy.netdev' )
4431 self
. wait_online ( 'dummy98:routable' )
4433 output
= check_output ( 'tc qdisc show dev dummy98' )
4435 self
. assertRegex ( output
, 'qdisc codel 33: root' )
4436 self
. assertRegex ( output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn' )
4438 @expectedFailureIfModuleIsNotAvailable ( 'sch_drr' )
4439 def test_qdisc_drr ( self
):
4440 copy_network_unit ( '25-qdisc-drr.network' , '12-dummy.netdev' )
4442 self
. wait_online ( 'dummy98:routable' )
4444 output
= check_output ( 'tc qdisc show dev dummy98' )
4446 self
. assertRegex ( output
, 'qdisc drr 2: root' )
4447 output
= check_output ( 'tc class show dev dummy98' )
4449 self
. assertRegex ( output
, 'class drr 2:30 root quantum 2000b' )
4451 @expectedFailureIfModuleIsNotAvailable ( 'sch_ets' )
4452 def test_qdisc_ets ( self
):
4453 copy_network_unit ( '25-qdisc-ets.network' , '12-dummy.netdev' )
4455 self
. wait_online ( 'dummy98:routable' )
4457 output
= check_output ( 'tc qdisc show dev dummy98' )
4460 self
. assertRegex ( output
, 'qdisc ets 3a: root' )
4461 self
. assertRegex ( output
, 'bands 10 strict 3' )
4462 self
. assertRegex ( output
, 'quanta 1 2 3 4 5' )
4463 self
. assertRegex ( output
, 'priomap 3 4 5 6 7' )
4465 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq' )
4466 def test_qdisc_fq ( self
):
4467 copy_network_unit ( '25-qdisc-fq.network' , '12-dummy.netdev' )
4469 self
. wait_online ( 'dummy98:routable' )
4471 output
= check_output ( 'tc qdisc show dev dummy98' )
4473 self
. assertRegex ( output
, 'qdisc fq 32: root' )
4474 self
. assertRegex ( output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511' )
4475 self
. assertRegex ( output
, 'quantum 1500' )
4476 self
. assertRegex ( output
, 'initial_quantum 13000' )
4477 self
. assertRegex ( output
, 'maxrate 1Mbit' )
4479 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_codel' )
4480 def test_qdisc_fq_codel ( self
):
4481 copy_network_unit ( '25-qdisc-fq_codel.network' , '12-dummy.netdev' )
4483 self
. wait_online ( 'dummy98:routable' )
4485 output
= check_output ( 'tc qdisc show dev dummy98' )
4487 self
. assertRegex ( output
, 'qdisc fq_codel 34: root' )
4488 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' )
4490 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq_pie' )
4491 def test_qdisc_fq_pie ( self
):
4492 copy_network_unit ( '25-qdisc-fq_pie.network' , '12-dummy.netdev' )
4494 self
. wait_online ( 'dummy98:routable' )
4496 output
= check_output ( 'tc qdisc show dev dummy98' )
4499 self
. assertRegex ( output
, 'qdisc fq_pie 3a: root' )
4500 self
. assertRegex ( output
, 'limit 200000p' )
4502 @expectedFailureIfModuleIsNotAvailable ( 'sch_gred' )
4503 def test_qdisc_gred ( self
):
4504 copy_network_unit ( '25-qdisc-gred.network' , '12-dummy.netdev' )
4506 self
. wait_online ( 'dummy98:routable' )
4508 output
= check_output ( 'tc qdisc show dev dummy98' )
4510 self
. assertRegex ( output
, 'qdisc gred 38: root' )
4511 self
. assertRegex ( output
, 'vqs 12 default 10 grio' )
4513 @expectedFailureIfModuleIsNotAvailable ( 'sch_hhf' )
4514 def test_qdisc_hhf ( self
):
4515 copy_network_unit ( '25-qdisc-hhf.network' , '12-dummy.netdev' )
4517 self
. wait_online ( 'dummy98:routable' )
4519 output
= check_output ( 'tc qdisc show dev dummy98' )
4521 self
. assertRegex ( output
, 'qdisc hhf 3a: root' )
4522 self
. assertRegex ( output
, 'limit 1022p' )
4524 @expectedFailureIfModuleIsNotAvailable ( 'sch_htb' )
4525 def test_qdisc_htb_fifo ( self
):
4526 copy_network_unit ( '25-qdisc-htb-fifo.network' , '12-dummy.netdev' )
4528 self
. wait_online ( 'dummy98:routable' )
4530 output
= check_output ( 'tc qdisc show dev dummy98' )
4532 self
. assertRegex ( output
, 'qdisc htb 2: root' )
4533 self
. assertRegex ( output
, r
'default (0x30|30)' )
4535 self
. assertRegex ( output
, 'qdisc pfifo 37: parent 2:37' )
4536 self
. assertRegex ( output
, 'limit 100000p' )
4538 self
. assertRegex ( output
, 'qdisc bfifo 3a: parent 2:3a' )
4539 self
. assertRegex ( output
, 'limit 1000000' )
4541 self
. assertRegex ( output
, 'qdisc pfifo_head_drop 3b: parent 2:3b' )
4542 self
. assertRegex ( output
, 'limit 1023p' )
4544 self
. assertRegex ( output
, 'qdisc pfifo_fast 3c: parent 2:3c' )
4546 output
= check_output ( 'tc -d class show dev dummy98' )
4548 # Here (:|prio) is a workaround for a bug in iproute2 v6.2.0 caused by
4549 # https://github.com/shemminger/iproute2/commit/010a8388aea11e767ba3a2506728b9ad9760df0e
4550 # which is fixed in v6.3.0 by
4551 # https://github.com/shemminger/iproute2/commit/4e0e56e0ef05387f7f5d8ab41fe6ec6a1897b26d
4552 self
. assertRegex ( output
, 'class htb 2:37 root leaf 37(:|prio) ' )
4553 self
. assertRegex ( output
, 'class htb 2:3a root leaf 3a(:|prio) ' )
4554 self
. assertRegex ( output
, 'class htb 2:3b root leaf 3b(:|prio) ' )
4555 self
. assertRegex ( output
, 'class htb 2:3c root leaf 3c(:|prio) ' )
4556 self
. assertRegex ( output
, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit' )
4557 self
. assertRegex ( output
, 'burst 123456' )
4558 self
. assertRegex ( output
, 'cburst 123457' )
4560 @expectedFailureIfModuleIsNotAvailable ( 'sch_ingress' )
4561 def test_qdisc_ingress ( self
):
4562 copy_network_unit ( '25-qdisc-clsact.network' , '12-dummy.netdev' ,
4563 '25-qdisc-ingress.network' , '11-dummy.netdev' )
4565 self
. wait_online ( 'dummy98:routable' , 'test1:routable' )
4567 output
= check_output ( 'tc qdisc show dev dummy98' )
4569 self
. assertRegex ( output
, 'qdisc clsact' )
4571 output
= check_output ( 'tc qdisc show dev test1' )
4573 self
. assertRegex ( output
, 'qdisc ingress' )
4575 @expectedFailureIfModuleIsNotAvailable ( 'sch_netem' )
4576 def test_qdisc_netem ( self
):
4577 copy_network_unit ( '25-qdisc-netem.network' , '12-dummy.netdev' ,
4578 '25-qdisc-netem-compat.network' , '11-dummy.netdev' )
4580 self
. wait_online ( 'dummy98:routable' , 'test1:routable' )
4582 output
= check_output ( 'tc qdisc show dev dummy98' )
4584 self
. assertRegex ( output
, 'qdisc netem 30: root' )
4585 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
4587 output
= check_output ( 'tc qdisc show dev test1' )
4589 self
. assertRegex ( output
, 'qdisc netem [0-9a-f]*: root' )
4590 self
. assertRegex ( output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%' )
4592 @expectedFailureIfModuleIsNotAvailable ( 'sch_pie' )
4593 def test_qdisc_pie ( self
):
4594 copy_network_unit ( '25-qdisc-pie.network' , '12-dummy.netdev' )
4596 self
. wait_online ( 'dummy98:routable' )
4598 output
= check_output ( 'tc qdisc show dev dummy98' )
4600 self
. assertRegex ( output
, 'qdisc pie 3a: root' )
4601 self
. assertRegex ( output
, 'limit 200000' )
4603 @expectedFailureIfModuleIsNotAvailable ( 'sch_qfq' )
4604 def test_qdisc_qfq ( self
):
4605 copy_network_unit ( '25-qdisc-qfq.network' , '12-dummy.netdev' )
4607 self
. wait_online ( 'dummy98:routable' )
4609 output
= check_output ( 'tc qdisc show dev dummy98' )
4611 self
. assertRegex ( output
, 'qdisc qfq 2: root' )
4612 output
= check_output ( 'tc class show dev dummy98' )
4614 self
. assertRegex ( output
, 'class qfq 2:30 root weight 2 maxpkt 16000' )
4615 self
. assertRegex ( output
, 'class qfq 2:31 root weight 10 maxpkt 8000' )
4617 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfb' )
4618 def test_qdisc_sfb ( self
):
4619 copy_network_unit ( '25-qdisc-sfb.network' , '12-dummy.netdev' )
4621 self
. wait_online ( 'dummy98:routable' )
4623 output
= check_output ( 'tc qdisc show dev dummy98' )
4625 self
. assertRegex ( output
, 'qdisc sfb 39: root' )
4626 self
. assertRegex ( output
, 'limit 200000' )
4628 @expectedFailureIfModuleIsNotAvailable ( 'sch_sfq' )
4629 def test_qdisc_sfq ( self
):
4630 copy_network_unit ( '25-qdisc-sfq.network' , '12-dummy.netdev' )
4632 self
. wait_online ( 'dummy98:routable' )
4634 output
= check_output ( 'tc qdisc show dev dummy98' )
4636 self
. assertRegex ( output
, 'qdisc sfq 36: root' )
4637 self
. assertRegex ( output
, 'perturb 5sec' )
4639 @expectedFailureIfModuleIsNotAvailable ( 'sch_tbf' )
4640 def test_qdisc_tbf ( self
):
4641 copy_network_unit ( '25-qdisc-tbf.network' , '12-dummy.netdev' )
4643 self
. wait_online ( 'dummy98:routable' )
4645 output
= check_output ( 'tc qdisc show dev dummy98' )
4647 self
. assertRegex ( output
, 'qdisc tbf 35: root' )
4648 self
. assertRegex ( output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms' )
4650 @expectedFailureIfModuleIsNotAvailable ( 'sch_teql' )
4651 def test_qdisc_teql ( self
):
4652 call_quiet ( 'rmmod sch_teql' )
4654 copy_network_unit ( '25-qdisc-teql.network' , '12-dummy.netdev' )
4656 self
. wait_links ( 'dummy98' )
4657 check_output ( 'modprobe sch_teql max_equalizers=2' )
4658 self
. wait_online ( 'dummy98:routable' )
4660 output
= check_output ( 'tc qdisc show dev dummy98' )
4662 self
. assertRegex ( output
, 'qdisc teql1 31: root' )
4664 @expectedFailureIfModuleIsNotAvailable ( 'sch_fq' , 'sch_sfq' , 'sch_tbf' )
4665 def test_qdisc_drop ( self
):
4666 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network' )
4668 self
. wait_online ( 'dummy98:routable' )
4670 # Test case for issue #32247 and #32254.
4672 check_output ( 'tc qdisc replace dev dummy98 root fq' )
4673 self
. assertFalse ( networkd_is_failed ())
4674 check_output ( 'tc qdisc replace dev dummy98 root fq pacing' )
4675 self
. assertFalse ( networkd_is_failed ())
4676 check_output ( 'tc qdisc replace dev dummy98 handle 10: root tbf rate 0.5mbit burst 5kb latency 70ms peakrate 1mbit minburst 1540' )
4677 self
. assertFalse ( networkd_is_failed ())
4678 check_output ( 'tc qdisc add dev dummy98 parent 10:1 handle 100: sfq' )
4679 self
. assertFalse ( networkd_is_failed ())
4681 class NetworkdStateFileTests ( unittest
. TestCase
, Utilities
):
4689 def test_state_file ( self
):
4690 copy_network_unit ( '12-dummy.netdev' , '25-state-file-tests.network' )
4692 self
. wait_online ( 'dummy98:routable' )
4694 # make link state file updated
4695 resolvectl ( 'revert' , 'dummy98' )
4697 check_json ( networkctl_json ())
4699 output
= read_link_state_file ( 'dummy98' )
4701 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
4702 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
4703 self
. assertIn ( 'ADMIN_STATE=configured' , output
)
4704 self
. assertIn ( 'OPER_STATE=routable' , output
)
4705 self
. assertIn ( 'REQUIRED_FOR_ONLINE=yes' , output
)
4706 self
. assertIn ( 'REQUIRED_OPER_STATE_FOR_ONLINE=routable' , output
)
4707 self
. assertIn ( 'REQUIRED_FAMILY_FOR_ONLINE=both' , output
)
4708 self
. assertIn ( 'ACTIVATION_POLICY=up' , output
)
4709 self
. assertIn ( 'NETWORK_FILE=/run/systemd/network/25-state-file-tests.network' , output
)
4710 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
4711 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
4712 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
4713 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
4714 self
. assertIn ( 'LLMNR=no' , output
)
4715 self
. assertIn ( 'MDNS=yes' , output
)
4716 self
. assertIn ( 'DNSSEC=no' , output
)
4718 resolvectl ( 'dns' , 'dummy98' , '10.10.10.12#ccc.com' , '10.10.10.13' , '1111:2222::3333' )
4719 resolvectl ( 'domain' , 'dummy98' , 'hogehogehoge' , '~foofoofoo' )
4720 resolvectl ( 'llmnr' , 'dummy98' , 'yes' )
4721 resolvectl ( 'mdns' , 'dummy98' , 'no' )
4722 resolvectl ( 'dnssec' , 'dummy98' , 'yes' )
4723 timedatectl ( 'ntp-servers' , 'dummy98' , '2.fedora.pool.ntp.org' , '3.fedora.pool.ntp.org' )
4725 check_json ( networkctl_json ())
4727 output
= read_link_state_file ( 'dummy98' )
4729 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
4730 self
. assertIn ( 'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org' , output
)
4731 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
4732 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
4733 self
. assertIn ( 'LLMNR=yes' , output
)
4734 self
. assertIn ( 'MDNS=no' , output
)
4735 self
. assertIn ( 'DNSSEC=yes' , output
)
4737 timedatectl ( 'revert' , 'dummy98' )
4739 check_json ( networkctl_json ())
4741 output
= read_link_state_file ( 'dummy98' )
4743 self
. assertIn ( 'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333' , output
)
4744 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
4745 self
. assertIn ( 'DOMAINS=hogehogehoge' , output
)
4746 self
. assertIn ( 'ROUTE_DOMAINS=foofoofoo' , output
)
4747 self
. assertIn ( 'LLMNR=yes' , output
)
4748 self
. assertIn ( 'MDNS=no' , output
)
4749 self
. assertIn ( 'DNSSEC=yes' , output
)
4751 resolvectl ( 'revert' , 'dummy98' )
4753 check_json ( networkctl_json ())
4755 output
= read_link_state_file ( 'dummy98' )
4757 self
. assertIn ( 'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com' , output
)
4758 self
. assertIn ( 'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org' , output
)
4759 self
. assertIn ( 'DOMAINS=hogehoge' , output
)
4760 self
. assertIn ( 'ROUTE_DOMAINS=foofoo' , output
)
4761 self
. assertIn ( 'LLMNR=no' , output
)
4762 self
. assertIn ( 'MDNS=yes' , output
)
4763 self
. assertIn ( 'DNSSEC=no' , output
)
4765 def test_address_state ( self
):
4766 copy_network_unit ( '12-dummy.netdev' , '12-dummy-no-address.network' )
4769 self
. wait_online ( 'dummy98:degraded' )
4771 output
= read_link_state_file ( 'dummy98' )
4772 self
. assertIn ( 'IPV4_ADDRESS_STATE=off' , output
)
4773 self
. assertIn ( 'IPV6_ADDRESS_STATE=degraded' , output
)
4775 # with a routable IPv4 address
4776 check_output ( 'ip address add 10.1.2.3/16 dev dummy98' )
4777 self
. wait_online ( 'dummy98:routable' , ipv4
= True )
4778 self
. wait_online ( 'dummy98:routable' )
4780 output
= read_link_state_file ( 'dummy98' )
4781 self
. assertIn ( 'IPV4_ADDRESS_STATE=routable' , output
)
4782 self
. assertIn ( 'IPV6_ADDRESS_STATE=degraded' , output
)
4784 check_output ( 'ip address del 10.1.2.3/16 dev dummy98' )
4786 # with a routable IPv6 address
4787 check_output ( 'ip address add 2002:da8:1:0:1034:56ff:fe78:9abc/64 dev dummy98' )
4788 self
. wait_online ( 'dummy98:routable' , ipv6
= True )
4789 self
. wait_online ( 'dummy98:routable' )
4791 output
= read_link_state_file ( 'dummy98' )
4792 self
. assertIn ( 'IPV4_ADDRESS_STATE=off' , output
)
4793 self
. assertIn ( 'IPV6_ADDRESS_STATE=routable' , output
)
4795 class NetworkdBondTests ( unittest
. TestCase
, Utilities
):
4803 def test_bond_keep_master ( self
):
4804 check_output ( 'ip link add bond199 type bond mode active-backup' )
4805 check_output ( 'ip link add dummy98 type dummy' )
4806 check_output ( 'ip link set dummy98 master bond199' )
4808 copy_network_unit ( '23-keep-master.network' )
4810 self
. wait_online ( 'dummy98:enslaved' )
4812 output
= check_output ( 'ip -d link show bond199' )
4814 self
. assertRegex ( output
, 'active_slave dummy98' )
4816 output
= check_output ( 'ip -d link show dummy98' )
4818 self
. assertRegex ( output
, 'master bond199' )
4820 def test_bond_active_slave ( self
):
4821 copy_network_unit ( '23-active-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
4823 self
. wait_online ( 'dummy98:enslaved' , 'bond199:degraded' )
4825 output
= check_output ( 'ip -d link show bond199' )
4827 self
. assertIn ( 'active_slave dummy98' , output
)
4829 # test case for issue #31165.
4830 since
= datetime
. datetime
. now ()
4831 networkctl_reconfigure ( 'dummy98' )
4832 self
. wait_online ( 'dummy98:enslaved' , 'bond199:degraded' )
4833 self
. assertNotIn ( 'dummy98: Bringing link down' , read_networkd_log ( since
= since
))
4835 def test_bond_primary_slave ( self
):
4836 copy_network_unit ( '23-primary-slave.network' , '23-bond199.network' , '25-bond-active-backup-slave.netdev' , '12-dummy.netdev' )
4838 self
. wait_online ( 'dummy98:enslaved' , 'bond199:degraded' )
4840 output
= check_output ( 'ip -d link show bond199' )
4842 self
. assertIn ( 'primary dummy98' , output
)
4845 mkdir_p ( os
. path
. join ( network_unit_dir
, '23-bond199.network.d' ))
4846 for mac
in [ '00:11:22:33:44:55' , '00:11:22:33:44:56' ]:
4847 with
open ( os
. path
. join ( network_unit_dir
, '23-bond199.network.d/mac.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
4848 f
. write ( f
'[Link] \n MACAddress= {mac} \n ' )
4851 self
. wait_online ( 'dummy98:enslaved' , 'bond199:degraded' )
4853 output
= check_output ( 'ip -d link show bond199' )
4855 self
. assertIn ( f
'link/ether {mac} ' , output
)
4857 def test_bond_operstate ( self
):
4858 copy_network_unit ( '25-bond.netdev' , '11-dummy.netdev' , '12-dummy.netdev' ,
4859 '25-bond99.network' , '25-bond-slave.network' )
4861 self
. wait_online ( 'dummy98:enslaved' , 'test1:enslaved' , 'bond99:routable' )
4863 output
= check_output ( 'ip -d link show dummy98' )
4865 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
4867 output
= check_output ( 'ip -d link show test1' )
4869 self
. assertRegex ( output
, 'SLAVE,UP,LOWER_UP' )
4871 output
= check_output ( 'ip -d link show bond99' )
4873 self
. assertRegex ( output
, 'MASTER,UP,LOWER_UP' )
4875 self
. wait_operstate ( 'dummy98' , 'enslaved' )
4876 self
. wait_operstate ( 'test1' , 'enslaved' )
4877 self
. wait_operstate ( 'bond99' , 'routable' )
4879 check_output ( 'ip link set dummy98 down' )
4881 self
. wait_operstate ( 'dummy98' , 'off' )
4882 self
. wait_operstate ( 'test1' , 'enslaved' )
4883 self
. wait_operstate ( 'bond99' , 'routable' )
4885 check_output ( 'ip link set dummy98 up' )
4887 self
. wait_operstate ( 'dummy98' , 'enslaved' )
4888 self
. wait_operstate ( 'test1' , 'enslaved' )
4889 self
. wait_operstate ( 'bond99' , 'routable' )
4891 check_output ( 'ip link set dummy98 down' )
4892 check_output ( 'ip link set test1 down' )
4894 self
. wait_operstate ( 'dummy98' , 'off' )
4895 self
. wait_operstate ( 'test1' , 'off' )
4897 if not self
. wait_operstate ( 'bond99' , 'no-carrier' , setup_timeout
= 30 , fail_assert
= False ):
4898 # Huh? Kernel does not recognize that all slave interfaces are down?
4899 # Let's confirm that networkd's operstate is consistent with ip's result.
4900 self
. assertNotRegex ( output
, 'NO-CARRIER' )
4902 class NetworkdBridgeTests ( unittest
. TestCase
, Utilities
):
4910 def test_bridge_mac_none ( self
):
4911 copy_network_unit ( '12-dummy-mac.netdev' , '26-bridge-mac-slave.network' ,
4912 '26-bridge-mac.netdev' , '26-bridge-mac-master.network' , '26-bridge-mac.link' )
4914 self
. wait_online ( 'dummy98:enslaved' , 'bridge99:degraded' )
4916 output
= check_output ( 'ip link show dev dummy98' )
4918 self
. assertIn ( 'link/ether 12:34:56:78:9a:01' , output
)
4920 output
= check_output ( 'ip link show dev bridge99' )
4922 self
. assertIn ( 'link/ether 12:34:56:78:9a:01' , output
)
4924 def test_bridge_vlan ( self
):
4925 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave.network' ,
4926 '26-bridge.netdev' , '26-bridge-vlan-master.network' ,
4929 self
. wait_online ( 'test1:enslaved' , 'bridge99:degraded' )
4931 output
= check_output ( 'bridge vlan show dev test1' )
4933 # check if the default VID is removed
4934 self
. assertNotIn ( '1 Egress Untagged' , output
)
4935 for i
in range ( 1000 , 3000 ):
4937 self
. assertIn ( f
' {i} PVID' , output
)
4938 elif i
in range ( 1012 , 1016 ) or i
in range ( 1103 , 1109 ):
4939 self
. assertIn ( f
' {i} Egress Untagged' , output
)
4940 elif i
in range ( 1008 , 1014 ) or i
in range ( 1100 , 1111 ):
4941 self
. assertIn ( f
' {i} ' , output
)
4943 self
. assertNotIn ( f
' {i} ' , output
)
4945 output
= check_output ( 'bridge vlan show dev bridge99' )
4947 # check if the default VID is removed
4948 self
. assertNotIn ( '1 Egress Untagged' , output
)
4949 for i
in range ( 1000 , 3000 ):
4951 self
. assertIn ( f
' {i} PVID' , output
)
4952 elif i
in range ( 1022 , 1026 ) or i
in range ( 1203 , 1209 ):
4953 self
. assertIn ( f
' {i} Egress Untagged' , output
)
4954 elif i
in range ( 1018 , 1024 ) or i
in range ( 1200 , 1211 ):
4955 self
. assertIn ( f
' {i} ' , output
)
4957 self
. assertNotIn ( f
' {i} ' , output
)
4960 copy_network_unit ( '26-bridge-vlan-slave.network.d/10-override.conf' ,
4961 '26-bridge-vlan-master.network.d/10-override.conf' )
4963 self
. wait_online ( 'test1:enslaved' , 'bridge99:degraded' )
4965 output
= check_output ( 'bridge vlan show dev test1' )
4967 for i
in range ( 1000 , 3000 ):
4969 self
. assertIn ( f
' {i} PVID' , output
)
4970 elif i
in range ( 2012 , 2016 ) or i
in range ( 2103 , 2109 ):
4971 self
. assertIn ( f
' {i} Egress Untagged' , output
)
4972 elif i
in range ( 2008 , 2014 ) or i
in range ( 2100 , 2111 ):
4973 self
. assertIn ( f
' {i} ' , output
)
4975 self
. assertNotIn ( f
' {i} ' , output
)
4977 output
= check_output ( 'bridge vlan show dev bridge99' )
4979 for i
in range ( 1000 , 3000 ):
4981 self
. assertIn ( f
' {i} PVID' , output
)
4982 elif i
in range ( 2022 , 2026 ) or i
in range ( 2203 , 2209 ):
4983 self
. assertIn ( f
' {i} Egress Untagged' , output
)
4984 elif i
in range ( 2018 , 2024 ) or i
in range ( 2200 , 2211 ):
4985 self
. assertIn ( f
' {i} ' , output
)
4987 self
. assertNotIn ( f
' {i} ' , output
)
4989 # Remove several vlan IDs
4990 copy_network_unit ( '26-bridge-vlan-slave.network.d/20-override.conf' ,
4991 '26-bridge-vlan-master.network.d/20-override.conf' )
4993 self
. wait_online ( 'test1:enslaved' , 'bridge99:degraded' )
4995 output
= check_output ( 'bridge vlan show dev test1' )
4997 for i
in range ( 1000 , 3000 ):
4999 self
. assertIn ( f
' {i} PVID' , output
)
5000 elif i
in range ( 2012 , 2016 ):
5001 self
. assertIn ( f
' {i} Egress Untagged' , output
)
5002 elif i
in range ( 2008 , 2014 ):
5003 self
. assertIn ( f
' {i} ' , output
)
5005 self
. assertNotIn ( f
' {i} ' , output
)
5007 output
= check_output ( 'bridge vlan show dev bridge99' )
5009 for i
in range ( 1000 , 3000 ):
5011 self
. assertIn ( f
' {i} PVID' , output
)
5012 elif i
in range ( 2022 , 2026 ):
5013 self
. assertIn ( f
' {i} Egress Untagged' , output
)
5014 elif i
in range ( 2018 , 2024 ):
5015 self
. assertIn ( f
' {i} ' , output
)
5017 self
. assertNotIn ( f
' {i} ' , output
)
5019 # Remove all vlan IDs
5020 copy_network_unit ( '26-bridge-vlan-slave.network.d/30-override.conf' ,
5021 '26-bridge-vlan-master.network.d/30-override.conf' )
5023 self
. wait_online ( 'test1:enslaved' , 'bridge99:degraded' )
5025 output
= check_output ( 'bridge vlan show dev test1' )
5027 self
. assertNotIn ( 'PVID' , output
)
5028 for i
in range ( 1000 , 3000 ):
5029 self
. assertNotIn ( f
' {i} ' , output
)
5031 output
= check_output ( 'bridge vlan show dev bridge99' )
5033 self
. assertNotIn ( 'PVID' , output
)
5034 for i
in range ( 1000 , 3000 ):
5035 self
. assertNotIn ( f
' {i} ' , output
)
5037 def test_bridge_vlan_issue_20373 ( self
):
5038 copy_network_unit ( '11-dummy.netdev' , '26-bridge-vlan-slave-issue-20373.network' ,
5039 '26-bridge-issue-20373.netdev' , '26-bridge-vlan-master-issue-20373.network' ,
5040 '21-vlan.netdev' , '21-vlan.network' )
5042 self
. wait_online ( 'test1:enslaved' , 'bridge99:degraded' , 'vlan99:routable' )
5044 output
= check_output ( 'bridge vlan show dev test1' )
5046 self
. assertIn ( '100 PVID Egress Untagged' , output
)
5047 self
. assertIn ( '560' , output
)
5048 self
. assertIn ( '600' , output
)
5050 output
= check_output ( 'bridge vlan show dev bridge99' )
5052 self
. assertIn ( '1 PVID Egress Untagged' , output
)
5053 self
. assertIn ( '100' , output
)
5054 self
. assertIn ( '600' , output
)
5056 def test_bridge_mdb ( self
):
5057 copy_network_unit ( '11-dummy.netdev' , '26-bridge-mdb-slave.network' ,
5058 '26-bridge.netdev' , '26-bridge-mdb-master.network' )
5060 self
. wait_online ( 'test1:enslaved' , 'bridge99:degraded' )
5062 output
= check_output ( 'bridge mdb show dev bridge99' )
5064 self
. assertRegex ( output
, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064' )
5065 self
. assertRegex ( output
, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065' )
5067 # Old kernel may not support bridge MDB entries on bridge master
5068 if call_quiet ( 'bridge mdb add dev bridge99 port bridge99 grp 224.0.1.3 temp vid 4068' ) == 0 :
5069 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp ff02:aaaa:fee5::1:4 temp *vid 4066' )
5070 self
. assertRegex ( output
, 'dev bridge99 port bridge99 grp 224.0.1.2 temp *vid 4067' )
5072 def test_bridge_keep_master ( self
):
5073 check_output ( 'ip link add bridge99 type bridge' )
5074 check_output ( 'ip link set bridge99 up' )
5075 check_output ( 'ip link add dummy98 type dummy' )
5076 check_output ( 'ip link set dummy98 master bridge99' )
5078 copy_network_unit ( '23-keep-master.network' )
5080 self
. wait_online ( 'dummy98:enslaved' )
5082 output
= check_output ( 'ip -d link show dummy98' )
5084 self
. assertRegex ( output
, 'master bridge99' )
5085 self
. assertRegex ( output
, 'bridge' )
5087 output
= check_output ( 'bridge -d link show dummy98' )
5089 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
5090 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
5091 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
5092 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
5093 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
5094 # CONFIG_BRIDGE_IGMP_SNOOPING=y
5095 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
5096 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
5097 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
5098 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
5099 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
5100 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
5102 def test_bridge_property ( self
):
5103 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
5104 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
5105 '25-bridge99.network' )
5107 self
. wait_online ( 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' )
5109 output
= check_output ( 'ip -d link show bridge99' )
5111 self
. assertIn ( 'mtu 9000 ' , output
)
5113 output
= check_output ( 'ip -d link show test1' )
5115 self
. assertIn ( 'master bridge99 ' , output
)
5116 self
. assertIn ( 'bridge_slave' , output
)
5117 self
. assertIn ( 'mtu 9000 ' , output
)
5119 output
= check_output ( 'ip -d link show dummy98' )
5121 self
. assertIn ( 'master bridge99 ' , output
)
5122 self
. assertIn ( 'bridge_slave' , output
)
5123 self
. assertIn ( 'mtu 9000 ' , output
)
5125 output
= check_output ( 'ip addr show bridge99' )
5127 self
. assertIn ( '192.168.0.15/24' , output
)
5129 output
= check_output ( 'bridge -d link show dummy98' )
5131 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'path_cost' , '400' )
5132 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'hairpin_mode' , '1' )
5133 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'isolated' , '1' )
5134 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_fast_leave' , '1' )
5135 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'unicast_flood' , '1' )
5136 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_flood' , '0' )
5137 # CONFIG_BRIDGE_IGMP_SNOOPING=y
5138 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'multicast_to_unicast' , '1' , allow_enoent
= True )
5139 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'neigh_suppress' , '1' , allow_enoent
= True )
5140 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'learning' , '0' )
5141 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'priority' , '23' )
5142 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'bpdu_guard' , '0' )
5143 self
. check_bridge_port_attr ( 'bridge99' , 'dummy98' , 'root_block' , '0' )
5145 output
= check_output ( 'bridge -d link show test1' )
5147 self
. check_bridge_port_attr ( 'bridge99' , 'test1' , 'priority' , '0' )
5149 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
5150 output
= check_output ( 'ip addr show bridge99' )
5152 self
. assertIn ( '192.168.0.16/24' , output
)
5155 print ( '### ip -6 route list table all dev bridge99' )
5156 output
= check_output ( 'ip -6 route list table all dev bridge99' )
5158 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
5160 remove_link ( 'test1' )
5161 self
. wait_operstate ( 'bridge99' , 'routable' )
5163 output
= check_output ( 'ip -d link show bridge99' )
5165 self
. assertIn ( 'mtu 9000 ' , output
)
5167 output
= check_output ( 'ip -d link show dummy98' )
5169 self
. assertIn ( 'master bridge99 ' , output
)
5170 self
. assertIn ( 'bridge_slave' , output
)
5171 self
. assertIn ( 'mtu 9000 ' , output
)
5173 remove_link ( 'dummy98' )
5174 self
. wait_operstate ( 'bridge99' , 'no-carrier' )
5176 output
= check_output ( 'ip -d link show bridge99' )
5178 # When no carrier, the kernel may reset the MTU
5179 self
. assertIn ( 'NO-CARRIER' , output
)
5181 output
= check_output ( 'ip address show bridge99' )
5183 self
. assertNotIn ( '192.168.0.15/24' , output
)
5184 self
. assertIn ( '192.168.0.16/24' , output
) # foreign address is kept
5186 print ( '### ip -6 route list table all dev bridge99' )
5187 output
= check_output ( 'ip -6 route list table all dev bridge99' )
5189 self
. assertRegex ( output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium' )
5191 check_output ( 'ip link add dummy98 type dummy' )
5192 self
. wait_online ( 'dummy98:enslaved' , 'bridge99:routable' )
5194 output
= check_output ( 'ip -d link show bridge99' )
5196 self
. assertIn ( 'mtu 9000 ' , output
)
5198 output
= check_output ( 'ip -d link show dummy98' )
5200 self
. assertIn ( 'master bridge99 ' , output
)
5201 self
. assertIn ( 'bridge_slave' , output
)
5202 self
. assertIn ( 'mtu 9000 ' , output
)
5204 def test_bridge_configure_without_carrier ( self
):
5205 copy_network_unit ( '26-bridge.netdev' , '26-bridge-configure-without-carrier.network' ,
5209 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
5210 for test
in [ 'no-slave' , 'add-slave' , 'slave-up' , 'slave-no-carrier' , 'slave-carrier' , 'slave-down' ]:
5211 with self
. subTest ( test
= test
):
5212 if test
== 'no-slave' :
5213 # bridge has no slaves; it's up but *might* not have carrier
5214 self
. wait_operstate ( 'bridge99' , operstate
= r
'(no-carrier|routable)' , setup_state
= None , setup_timeout
= 30 )
5215 # due to a bug in the kernel, newly-created bridges are brought up
5216 # *with* carrier, unless they have had any setting changed; e.g.
5217 # their mac set, priority set, etc. Then, they will lose carrier
5218 # as soon as a (down) slave interface is added, and regain carrier
5219 # again once the slave interface is brought up.
5220 #self.check_link_attr('bridge99', 'carrier', '0')
5221 elif test
== 'add-slave' :
5222 # add slave to bridge, but leave it down; bridge is definitely no-carrier
5223 self
. check_link_attr ( 'test1' , 'operstate' , 'down' )
5224 check_output ( 'ip link set dev test1 master bridge99' )
5225 self
. wait_operstate ( 'bridge99' , operstate
= 'no-carrier' , setup_state
= None )
5226 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
5227 elif test
== 'slave-up' :
5228 # bring up slave, which will have carrier; bridge gains carrier
5229 check_output ( 'ip link set dev test1 up' )
5230 self
. wait_online ( 'bridge99:routable' )
5231 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
5232 elif test
== 'slave-no-carrier' :
5233 # drop slave carrier; bridge loses carrier
5234 check_output ( 'ip link set dev test1 carrier off' )
5235 self
. wait_online ( 'bridge99:no-carrier:no-carrier' )
5236 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
5237 elif test
== 'slave-carrier' :
5238 # restore slave carrier; bridge gains carrier
5239 check_output ( 'ip link set dev test1 carrier on' )
5240 self
. wait_online ( 'bridge99:routable' )
5241 self
. check_link_attr ( 'bridge99' , 'carrier' , '1' )
5242 elif test
== 'slave-down' :
5243 # bring down slave; bridge loses carrier
5244 check_output ( 'ip link set dev test1 down' )
5245 self
. wait_online ( 'bridge99:no-carrier:no-carrier' )
5246 self
. check_link_attr ( 'bridge99' , 'carrier' , '0' )
5248 output
= networkctl_status ( 'bridge99' )
5249 self
. assertRegex ( output
, '10.1.2.3' )
5250 self
. assertRegex ( output
, '10.1.2.1' )
5252 def test_bridge_ignore_carrier_loss ( self
):
5253 copy_network_unit ( '11-dummy.netdev' , '12-dummy.netdev' , '26-bridge.netdev' ,
5254 '26-bridge-slave-interface-1.network' , '26-bridge-slave-interface-2.network' ,
5255 '25-bridge99-ignore-carrier-loss.network' )
5257 self
. wait_online ( 'dummy98:enslaved' , 'test1:enslaved' , 'bridge99:routable' )
5259 check_output ( 'ip address add 192.168.0.16/24 dev bridge99' )
5260 remove_link ( 'test1' , 'dummy98' )
5263 output
= check_output ( 'ip address show bridge99' )
5265 self
. assertRegex ( output
, 'NO-CARRIER' )
5266 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
5267 self
. assertRegex ( output
, 'inet 192.168.0.16/24 scope global secondary bridge99' )
5269 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain ( self
):
5270 copy_network_unit ( '26-bridge.netdev' , '26-bridge-slave-interface-1.network' ,
5271 '25-bridge99-ignore-carrier-loss.network' )
5273 self
. wait_online ( 'bridge99:no-carrier' )
5275 for trial
in range ( 4 ):
5276 check_output ( 'ip link add dummy98 type dummy' )
5277 check_output ( 'ip link set dummy98 up' )
5279 remove_link ( 'dummy98' )
5281 self
. wait_online ( 'bridge99:routable' , 'dummy98:enslaved' )
5283 output
= check_output ( 'ip address show bridge99' )
5285 self
. assertRegex ( output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99' )
5287 output
= check_output ( 'ip rule list table 100' )
5289 self
. assertIn ( 'from all to 8.8.8.8 lookup 100' , output
)
5291 class NetworkdSRIOVTests ( unittest
. TestCase
, Utilities
):
5299 def setup_netdevsim ( self
, id = 99 , num_ports
= 1 , num_vfs
= 0 ):
5300 call ( 'modprobe netdevsim' )
5302 # Create netdevsim device.
5303 with
open ( '/sys/bus/netdevsim/new_device' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
5304 f
. write ( f
' {id} {num_ports} ' )
5308 with
open ( f
'/sys/bus/netdevsim/devices/netdevsim {id} /sriov_numvfs' , mode
= 'w' , encoding
= 'utf-8' ) as f
:
5309 f
. write ( f
' {num_vfs} ' )
5311 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
5312 def test_sriov ( self
):
5313 copy_network_unit ( '25-netdevsim.link' , '25-sriov.network' )
5315 self
. setup_netdevsim ( num_vfs
= 3 )
5318 self
. wait_online ( 'sim99:routable' )
5320 output
= check_output ( 'ip link show dev sim99' )
5322 self
. assertRegex ( output
,
5323 '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 *'
5324 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
5325 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
5328 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable ()
5329 def test_sriov_udev ( self
):
5330 copy_network_unit ( '25-sriov.link' , '25-sriov-udev.network' )
5332 self
. setup_netdevsim ()
5335 self
. wait_online ( 'sim99:routable' )
5337 # The name sim99 is an alternative name, and cannot be used by udevadm below.
5338 ifname
= link_resolve ( 'sim99' )
5340 output
= check_output ( 'ip link show dev sim99' )
5342 self
. assertRegex ( output
,
5343 '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 *'
5344 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
5345 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
5347 self
. assertNotIn ( 'vf 3' , output
)
5348 self
. assertNotIn ( 'vf 4' , output
)
5350 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5351 f
. write ( '[Link] \n SR-IOVVirtualFunctions=4 \n ' )
5354 udevadm_trigger ( f
'/sys/devices/netdevsim99/net/ {ifname} ' )
5356 output
= check_output ( 'ip link show dev sim99' )
5358 self
. assertRegex ( output
,
5359 '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 *'
5360 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
5361 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
5364 self
. assertNotIn ( 'vf 4' , output
)
5366 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5367 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
5370 udevadm_trigger ( f
'/sys/devices/netdevsim99/net/ {ifname} ' )
5372 output
= check_output ( 'ip link show dev sim99' )
5374 self
. assertRegex ( output
,
5375 '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 *'
5376 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
5377 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off \n *'
5380 self
. assertNotIn ( 'vf 4' , output
)
5382 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5383 f
. write ( '[Link] \n SR-IOVVirtualFunctions=2 \n ' )
5386 udevadm_trigger ( f
'/sys/devices/netdevsim99/net/ {ifname} ' )
5388 output
= check_output ( 'ip link show dev sim99' )
5390 self
. assertRegex ( output
,
5391 '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 *'
5392 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off'
5394 self
. assertNotIn ( 'vf 2' , output
)
5395 self
. assertNotIn ( 'vf 3' , output
)
5396 self
. assertNotIn ( 'vf 4' , output
)
5398 with
open ( os
. path
. join ( network_unit_dir
, '25-sriov.link' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5399 f
. write ( '[Link] \n SR-IOVVirtualFunctions= \n ' )
5402 udevadm_trigger ( f
'/sys/devices/netdevsim99/net/ {ifname} ' )
5404 output
= check_output ( 'ip link show dev sim99' )
5406 self
. assertRegex ( output
,
5407 '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 *'
5408 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off \n *'
5409 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
5411 self
. assertNotIn ( 'vf 3' , output
)
5412 self
. assertNotIn ( 'vf 4' , output
)
5414 class NetworkdLLDPTests ( unittest
. TestCase
, Utilities
):
5422 def test_lldp ( self
):
5423 copy_network_unit ( '23-emit-lldp.network' , '24-lldp.network' , '25-veth.netdev' )
5425 self
. wait_online ( 'veth99:degraded' , 'veth-peer:degraded' )
5428 output
= networkctl ( 'lldp' )
5430 if re
. search ( r
'veth99 .* veth-peer .* .......a...' , output
):
5436 # With interface name
5437 output
= networkctl ( 'lldp' , 'veth99' );
5439 self
. assertRegex ( output
, r
'veth99 .* veth-peer .* .......a...' )
5441 # With interface name pattern
5442 output
= networkctl ( 'lldp' , 've*9' );
5444 self
. assertRegex ( output
, r
'veth99 .* veth-peer .* .......a...' )
5447 output
= networkctl ( '--json=short' , 'lldp' )
5449 self
. assertIn ( '"InterfaceName":"veth99"' , output
)
5450 self
. assertIn ( '"PortID":"veth-peer"' , output
)
5451 self
. assertIn ( '"EnabledCapabilities":128' , output
)
5453 # json format with interface name
5454 output
= networkctl ( '--json=short' , 'lldp' , 'veth99' )
5456 self
. assertIn ( '"InterfaceName":"veth99"' , output
)
5457 self
. assertIn ( '"PortID":"veth-peer"' , output
)
5458 self
. assertIn ( '"EnabledCapabilities":128' , output
)
5460 # json format with interface name pattern
5461 output
= networkctl ( '--json=short' , 'lldp' , 've*9' )
5463 self
. assertIn ( '"InterfaceName":"veth99"' , output
)
5464 self
. assertIn ( '"PortID":"veth-peer"' , output
)
5465 self
. assertIn ( '"EnabledCapabilities":128' , output
)
5467 # LLDP neighbors in status
5468 output
= networkctl_status ( 'veth99' )
5470 self
. assertRegex ( output
, r
'Connected To: .* on port veth-peer' )
5472 # enable forwarding, to enable the Router flag
5473 with
open ( os
. path
. join ( network_unit_dir
, '23-emit-lldp.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5474 f
. write ( '[Network] \n IPv4Forwarding=yes \n ' )
5477 self
. wait_online ( 'veth-peer:degraded' )
5480 output
= networkctl ( 'lldp' )
5482 if re
. search ( r
'veth99 .* veth-peer .* ....r......' , output
):
5488 # With interface name
5489 output
= networkctl ( 'lldp' , 'veth99' );
5491 self
. assertRegex ( output
, r
'veth99 .* veth-peer .* ....r......' )
5493 # With interface name pattern
5494 output
= networkctl ( 'lldp' , 've*9' );
5496 self
. assertRegex ( output
, r
'veth99 .* veth-peer .* ....r......' )
5499 output
= networkctl ( '--json=short' , 'lldp' )
5501 self
. assertIn ( '"InterfaceName":"veth99"' , output
)
5502 self
. assertIn ( '"PortID":"veth-peer"' , output
)
5503 self
. assertIn ( '"EnabledCapabilities":16' , output
)
5505 # json format with interface name
5506 output
= networkctl ( '--json=short' , 'lldp' , 'veth99' )
5508 self
. assertIn ( '"InterfaceName":"veth99"' , output
)
5509 self
. assertIn ( '"PortID":"veth-peer"' , output
)
5510 self
. assertIn ( '"EnabledCapabilities":16' , output
)
5512 # json format with interface name pattern
5513 output
= networkctl ( '--json=short' , 'lldp' , 've*9' )
5515 self
. assertIn ( '"InterfaceName":"veth99"' , output
)
5516 self
. assertIn ( '"PortID":"veth-peer"' , output
)
5517 self
. assertIn ( '"EnabledCapabilities":16' , output
)
5519 # LLDP neighbors in status
5520 output
= networkctl_status ( 'veth99' )
5522 self
. assertRegex ( output
, r
'Connected To: .* on port veth-peer' )
5524 class NetworkdRATests ( unittest
. TestCase
, Utilities
):
5532 def test_ipv6_prefix_delegation ( self
):
5533 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth.network' )
5534 self
. setup_nftset ( 'addr6' , 'ipv6_addr' )
5535 self
. setup_nftset ( 'network6' , 'ipv6_addr' , 'flags interval;' )
5536 self
. setup_nftset ( 'ifindex' , 'iface_index' )
5538 self
. wait_online ( 'veth99:routable' , 'veth-peer:degraded' )
5540 # IPv6SendRA=yes implies IPv6Forwarding.
5541 self
. check_ipv6_sysctl_attr ( 'veth-peer' , 'forwarding' , '1' )
5543 output
= resolvectl ( 'dns' , 'veth99' )
5545 self
. assertRegex ( output
, 'fe80::' )
5546 self
. assertRegex ( output
, '2002:da8:1::1' )
5548 output
= resolvectl ( 'domain' , 'veth99' )
5550 self
. assertIn ( 'hogehoge.test' , output
)
5552 output
= networkctl_status ( 'veth99' )
5554 self
. assertRegex ( output
, '2002:da8:1:0' )
5556 self
. check_ipv6_neigh_sysctl_attr ( 'veth99' , 'base_reachable_time_ms' , '42000' )
5557 self
. check_ipv6_neigh_sysctl_attr ( 'veth99' , 'retrans_time_ms' , '500' )
5559 self
. check_netlabel ( 'veth99' , '2002:da8:1::/64' )
5560 self
. check_netlabel ( 'veth99' , '2002:da8:2::/64' )
5562 self
. check_nftset ( 'addr6' , '2002:da8:1:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*' )
5563 self
. check_nftset ( 'addr6' , '2002:da8:2:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*' )
5564 self
. check_nftset ( 'network6' , '2002:da8:1::/64' )
5565 self
. check_nftset ( 'network6' , '2002:da8:2::/64' )
5566 self
. check_nftset ( 'ifindex' , 'veth99' )
5568 self
. teardown_nftset ( 'addr6' , 'network6' , 'ifindex' )
5570 def check_ipv6_token_static ( self
):
5571 self
. wait_online ( 'veth99:routable' , 'veth-peer:degraded' )
5573 output
= networkctl_status ( 'veth99' )
5575 self
. assertRegex ( output
, '2002:da8:1:0:1a:2b:3c:4d' )
5576 self
. assertRegex ( output
, '2002:da8:1:0:fa:de:ca:fe' )
5577 self
. assertRegex ( output
, '2002:da8:2:0:1a:2b:3c:4d' )
5578 self
. assertRegex ( output
, '2002:da8:2:0:fa:de:ca:fe' )
5580 def test_ipv6_token_static ( self
):
5581 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-static.network' )
5584 self
. check_ipv6_token_static ()
5587 check_output ( 'ip link set veth99 down' )
5588 check_output ( 'ip link set veth99 up' )
5590 self
. check_ipv6_token_static ()
5593 check_output ( 'ip link set veth99 down' )
5594 time
. sleep ( random
. uniform ( 0 , 0.1 ))
5595 check_output ( 'ip link set veth99 up' )
5596 time
. sleep ( random
. uniform ( 0 , 0.1 ))
5598 self
. check_ipv6_token_static ()
5600 def test_ndisc_redirect ( self
):
5601 if not os
. path
. exists ( test_ndisc_send
):
5602 self
. skipTest ( f
" {test_ndisc_send} does not exist." )
5604 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-static.network' )
5607 self
. check_ipv6_token_static ()
5609 # Introduce three redirect routes.
5610 check_output ( f
' {test_ndisc_send} --interface veth-peer --type redirect --target-address 2002:da8:1:1:1a:2b:3c:4d --redirect-destination 2002:da8:1:1:1a:2b:3c:4d' )
5611 check_output ( f
' {test_ndisc_send} --interface veth-peer --type redirect --target-address 2002:da8:1:2:1a:2b:3c:4d --redirect-destination 2002:da8:1:2:1a:2b:3c:4d' )
5612 check_output ( f
' {test_ndisc_send} --interface veth-peer --type redirect --target-address 2002:da8:1:3:1a:2b:3c:4d --redirect-destination 2002:da8:1:3:1a:2b:3c:4d' )
5613 self
. wait_route ( 'veth99' , '2002:da8:1:1:1a:2b:3c:4d proto redirect' , ipv
= '-6' , timeout_sec
= 10 )
5614 self
. wait_route ( 'veth99' , '2002:da8:1:2:1a:2b:3c:4d proto redirect' , ipv
= '-6' , timeout_sec
= 10 )
5615 self
. wait_route ( 'veth99' , '2002:da8:1:3:1a:2b:3c:4d proto redirect' , ipv
= '-6' , timeout_sec
= 10 )
5617 # Change the target address of the redirects.
5618 check_output ( f
' {test_ndisc_send} --interface veth-peer --type redirect --target-address fe80::1 --redirect-destination 2002:da8:1:1:1a:2b:3c:4d' )
5619 check_output ( f
' {test_ndisc_send} --interface veth-peer --type redirect --target-address fe80::2 --redirect-destination 2002:da8:1:2:1a:2b:3c:4d' )
5620 self
. wait_route_dropped ( 'veth99' , '2002:da8:1:1:1a:2b:3c:4d proto redirect' , ipv
= '-6' , timeout_sec
= 10 )
5621 self
. wait_route_dropped ( 'veth99' , '2002:da8:1:2:1a:2b:3c:4d proto redirect' , ipv
= '-6' , timeout_sec
= 10 )
5622 self
. wait_route ( 'veth99' , '2002:da8:1:1:1a:2b:3c:4d via fe80::1 proto redirect' , ipv
= '-6' , timeout_sec
= 10 )
5623 self
. wait_route ( 'veth99' , '2002:da8:1:2:1a:2b:3c:4d via fe80::2 proto redirect' , ipv
= '-6' , timeout_sec
= 10 )
5625 # Send Neighbor Advertisement without the router flag to announce the default router is not available anymore.
5626 # Then, verify that all redirect routes and the default route are dropped.
5627 output
= check_output ( 'ip -6 address show dev veth-peer scope link' )
5628 veth_peer_ipv6ll
= re
. search ( 'fe80:[:0-9a-f]*' , output
). group ()
5629 print ( f
'veth-peer IPv6LL address: {veth_peer_ipv6ll} ' )
5630 check_output ( f
' {test_ndisc_send} --interface veth-peer --type neighbor-advertisement --target-address {veth_peer_ipv6ll} --is-router no' )
5631 self
. wait_route_dropped ( 'veth99' , 'proto ra' , ipv
= '-6' , timeout_sec
= 10 )
5632 self
. wait_route_dropped ( 'veth99' , 'proto redirect' , ipv
= '-6' , timeout_sec
= 10 )
5634 # Check if sd-radv refuses RS from the same interface.
5635 # See https://github.com/systemd/systemd/pull/32267#discussion_r1566721306
5636 since
= datetime
. datetime
. now ()
5637 check_output ( f
' {test_ndisc_send} --interface veth-peer --type rs --dest {veth_peer_ipv6ll} ' )
5638 self
. check_networkd_log ( 'veth-peer: RADV: Received RS from the same interface, ignoring.' , since
= since
)
5640 def check_ndisc_mtu ( self
, mtu
):
5642 output
= read_ipv6_sysctl_attr ( 'veth99' , 'mtu' )
5643 if output
== f
' {mtu} ' :
5647 self
. fail ( f
'IPv6 MTU does not matches: value= {output} , expected= {mtu} ' )
5649 def test_ndisc_mtu ( self
):
5650 if not os
. path
. exists ( test_ndisc_send
):
5651 self
. skipTest ( f
" {test_ndisc_send} does not exist." )
5653 copy_network_unit ( '25-veth.netdev' ,
5654 '25-veth-peer-no-address.network' ,
5655 '25-ipv6-prefix-veth-token-static.network' )
5657 self
. wait_online ( 'veth-peer:degraded' )
5659 self
. check_networkd_log ( 'veth99: NDISC: Started IPv6 Router Solicitation client' )
5661 check_output ( f
' {test_ndisc_send} --interface veth-peer --type ra --lifetime 1hour --mtu 1400' )
5662 self
. check_ndisc_mtu ( 1400 )
5664 check_output ( f
' {test_ndisc_send} --interface veth-peer --type ra --lifetime 1hour --mtu 1410' )
5665 self
. check_ndisc_mtu ( 1410 )
5667 check_output ( 'ip link set dev veth99 mtu 1600' )
5668 self
. check_ndisc_mtu ( 1410 )
5670 check_output ( f
' {test_ndisc_send} --interface veth-peer --type ra --lifetime 1hour --mtu 1700' )
5671 self
. check_ndisc_mtu ( 1600 )
5673 check_output ( 'ip link set dev veth99 mtu 1800' )
5674 self
. check_ndisc_mtu ( 1700 )
5676 def test_ipv6_token_prefixstable ( self
):
5677 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable.network' )
5679 self
. wait_online ( 'veth99:routable' , 'veth-peer:degraded' )
5681 output
= check_output ( 'ip -6 address show dev veth99' )
5683 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e/64' , output
) # the 1st prefixstable
5684 self
. assertIn ( '2002:da8:2:0:1034:56ff:fe78:9abc/64' , output
) # EUI64
5686 with
open ( os
. path
. join ( network_unit_dir
, '25-ipv6-prefix-veth-token-prefixstable.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5687 f
. write ( ' \n [IPv6AcceptRA] \n PrefixAllowList=2002:da8:1:0::/64 \n ' )
5690 self
. wait_online ( 'veth99:routable' )
5692 output
= check_output ( 'ip -6 address show dev veth99' )
5694 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e/64' , output
) # the 1st prefixstable
5695 self
. assertNotIn ( '2002:da8:2:0:1034:56ff:fe78:9abc/64' , output
) # EUI64
5697 check_output ( 'ip address del 2002:da8:1:0:b47e:7975:fc7a:7d6e/64 dev veth99' )
5698 check_output ( 'ip address add 2002:da8:1:0:b47e:7975:fc7a:7d6e/64 dev veth-peer nodad' )
5700 networkctl_reconfigure ( 'veth99' )
5701 self
. wait_online ( 'veth99:routable' )
5702 self
. wait_address ( 'veth99' , '2002:da8:1:0:da5d:e50a:43fd:5d0f/64' , ipv
= '-6' , timeout_sec
= 10 ) # the 2nd prefixstable
5703 self
. wait_address_dropped ( 'veth99' , '2002:da8:1:0:b47e:7975:fc7a:7d6e/64' , ipv
= '-6' , timeout_sec
= 10 ) # the 1st prefixstable
5705 check_output ( 'ip address del 2002:da8:1:0:da5d:e50a:43fd:5d0f/64 dev veth99' )
5706 check_output ( 'ip address add 2002:da8:1:0:da5d:e50a:43fd:5d0f/64 dev veth-peer nodad' )
5708 networkctl_reconfigure ( 'veth99' )
5709 self
. wait_online ( 'veth99:routable' )
5710 self
. wait_address ( 'veth99' , '2002:da8:1:0:c7e4:77ec:eb31:1b0d/64' , ipv
= '-6' , timeout_sec
= 10 ) # the 3rd prefixstable
5711 self
. wait_address_dropped ( 'veth99' , '2002:da8:1:0:da5d:e50a:43fd:5d0f/64' , ipv
= '-6' , timeout_sec
= 10 ) # the 2nd prefixstable
5712 self
. wait_address_dropped ( 'veth99' , '2002:da8:1:0:b47e:7975:fc7a:7d6e/64' , ipv
= '-6' , timeout_sec
= 10 ) # the 1st prefixstable
5714 def test_ipv6_token_prefixstable_without_address ( self
):
5715 copy_network_unit ( '25-veth.netdev' , '25-ipv6-prefix.network' , '25-ipv6-prefix-veth-token-prefixstable-without-address.network' )
5717 self
. wait_online ( 'veth99:routable' , 'veth-peer:degraded' )
5719 output
= networkctl_status ( 'veth99' )
5721 self
. assertIn ( '2002:da8:1:0:b47e:7975:fc7a:7d6e' , output
)
5722 self
. assertIn ( '2002:da8:2:0:f689:561a:8eda:7443' , output
)
5724 def test_router_hop_limit ( self
):
5725 copy_network_unit ( '25-veth-client.netdev' ,
5726 '25-veth-router.netdev' ,
5728 '25-veth-bridge.network' ,
5729 '25-veth-client.network' ,
5730 '25-veth-router-hop-limit.network' ,
5731 '25-bridge99.network' )
5733 self
. wait_online ( 'client:routable' , 'client-p:enslaved' ,
5734 'router:degraded' , 'router-p:enslaved' ,
5735 'bridge99:routable' )
5737 self
. check_ipv6_sysctl_attr ( 'client' , 'hop_limit' , '42' )
5739 with
open ( os
. path
. join ( network_unit_dir
, '25-veth-router-hop-limit.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5740 f
. write ( ' \n [IPv6SendRA] \n HopLimit=43 \n ' )
5745 output
= read_ipv6_sysctl_attr ( 'client' , 'hop_limit' )
5750 self
. check_ipv6_sysctl_attr ( 'client' , 'hop_limit' , '43' )
5752 def test_router_preference ( self
):
5753 copy_network_unit ( '25-veth-client.netdev' ,
5754 '25-veth-router-high.netdev' ,
5755 '25-veth-router-low.netdev' ,
5757 '25-veth-bridge.network' ,
5758 '25-veth-client.network' ,
5759 '25-veth-router-high.network' ,
5760 '25-veth-router-low.network' ,
5761 '25-bridge99.network' )
5763 self
. wait_online ( 'client-p:enslaved' ,
5764 'router-high:degraded' , 'router-high-p:enslaved' ,
5765 'router-low:degraded' , 'router-low-p:enslaved' ,
5766 'bridge99:routable' )
5768 networkctl_reconfigure ( 'client' )
5769 self
. wait_online ( 'client:routable' )
5771 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
5772 self
. wait_address ( 'client' , '2002:da8:1:98:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
5773 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 512' , ipv
= '-6' , timeout_sec
= 10 )
5774 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 2048' , ipv
= '-6' , timeout_sec
= 10 )
5776 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
5778 self
. assertIn ( 'metric 512' , output
)
5779 self
. assertIn ( 'pref high' , output
)
5780 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
5782 self
. assertIn ( 'metric 2048' , output
)
5783 self
. assertIn ( 'pref low' , output
)
5785 with
open ( os
. path
. join ( network_unit_dir
, '25-veth-client.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5786 f
. write ( ' \n [Link] \n MACAddress=12:34:56:78:9a:01 \n [IPv6AcceptRA] \n RouteMetric=100:200:300 \n ' )
5789 self
. wait_online ( 'client:routable' )
5791 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a01/64' , ipv
= '-6' , timeout_sec
= 10 )
5792 self
. wait_address ( 'client' , '2002:da8:1:98:1034:56ff:fe78:9a01/64' , ipv
= '-6' , timeout_sec
= 10 )
5793 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 100' , ipv
= '-6' , timeout_sec
= 10 )
5794 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 300' , ipv
= '-6' , timeout_sec
= 10 )
5796 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
5798 self
. assertIn ( 'metric 100' , output
)
5799 self
. assertNotIn ( 'metric 512' , output
)
5800 self
. assertIn ( 'pref high' , output
)
5801 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
5803 self
. assertIn ( 'metric 300' , output
)
5804 self
. assertNotIn ( 'metric 2048' , output
)
5805 self
. assertIn ( 'pref low' , output
)
5807 # swap the preference (for issue #28439)
5808 remove_network_unit ( '25-veth-router-high.network' , '25-veth-router-low.network' )
5809 copy_network_unit ( '25-veth-router-high2.network' , '25-veth-router-low2.network' )
5811 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 300' , ipv
= '-6' , timeout_sec
= 10 )
5812 self
. wait_route ( 'client' , 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 100' , ipv
= '-6' , timeout_sec
= 10 )
5814 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99' )
5816 self
. assertIn ( 'metric 300' , output
)
5817 self
. assertNotIn ( 'metric 100' , output
)
5818 self
. assertIn ( 'pref low' , output
)
5819 self
. assertNotIn ( 'pref high' , output
)
5820 output
= check_output ( 'ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98' )
5822 self
. assertIn ( 'metric 100' , output
)
5823 self
. assertNotIn ( 'metric 300' , output
)
5824 self
. assertIn ( 'pref high' , output
)
5825 self
. assertNotIn ( 'pref low' , output
)
5827 @unittest . skipUnless ( radvd_check_config ( 'captive-portal.conf' ), "Installed radvd doesn't support captive portals" )
5828 def test_captive_portal ( self
):
5829 copy_network_unit ( '25-veth-client.netdev' ,
5830 '25-veth-router-captive.netdev' ,
5832 '25-veth-client-captive.network' ,
5833 '25-veth-router-captive.network' ,
5834 '25-veth-bridge-captive.network' ,
5835 '25-bridge99.network' )
5837 self
. wait_online ( 'bridge99:routable' , 'client-p:enslaved' ,
5838 'router-captive:degraded' , 'router-captivep:enslaved' )
5840 start_radvd ( config_file
= 'captive-portal.conf' )
5841 networkctl_reconfigure ( 'client' )
5842 self
. wait_online ( 'client:routable' )
5844 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
5845 output
= networkctl_status ( 'client' )
5847 self
. assertIn ( 'Captive Portal: http://systemd.io' , output
)
5849 @unittest . skipUnless ( radvd_check_config ( 'captive-portal.conf' ), "Installed radvd doesn't support captive portals" )
5850 def test_invalid_captive_portal ( self
):
5851 def radvd_write_config ( captive_portal_uri
):
5852 with
open ( os
. path
. join ( networkd_ci_temp_dir
, 'radvd/bogus-captive-portal.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
5853 f
. write ( f
'interface router-captive {{ AdvSendAdvert on; AdvCaptivePortalAPI " {captive_portal_uri} "; prefix 2002:da8:1:99::/64 {{ AdvOnLink on; AdvAutonomous on; }}; }};' )
5855 captive_portal_uris
= [
5856 "42ěščěškd ěšč ě s" ,
5861 copy_network_unit ( '25-veth-client.netdev' ,
5862 '25-veth-router-captive.netdev' ,
5864 '25-veth-client-captive.network' ,
5865 '25-veth-router-captive.network' ,
5866 '25-veth-bridge-captive.network' ,
5867 '25-bridge99.network' )
5869 self
. wait_online ( 'bridge99:routable' , 'client-p:enslaved' ,
5870 'router-captive:degraded' , 'router-captivep:enslaved' )
5872 for uri
in captive_portal_uris
:
5873 print ( f
"Captive portal: {uri} " )
5874 radvd_write_config ( uri
)
5876 start_radvd ( config_file
= 'bogus-captive-portal.conf' )
5877 networkctl_reconfigure ( 'client' )
5878 self
. wait_online ( 'client:routable' )
5880 self
. wait_address ( 'client' , '2002:da8:1:99:1034:56ff:fe78:9a00/64' , ipv
= '-6' , timeout_sec
= 10 )
5881 output
= networkctl_status ( 'client' )
5883 self
. assertNotIn ( 'Captive Portal:' , output
)
5885 class NetworkdDHCPServerTests ( unittest
. TestCase
, Utilities
):
5893 def check_dhcp_server ( self
, persist_leases
= True ):
5894 output
= networkctl_status ( 'veth99' )
5896 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCPv4 via 192.168.5.1\)' )
5897 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
5898 self
. assertRegex ( output
, 'DNS: 192.168.5.1 \n *192.168.5.10' )
5899 self
. assertRegex ( output
, 'NTP: 192.168.5.1 \n *192.168.5.11' )
5901 output
= networkctl_status ( 'veth-peer' )
5903 self
. assertRegex ( output
, "Offered DHCP leases: 192.168.5.[0-9]*" )
5906 with
open ( '/var/lib/systemd/network/dhcp-server-lease/veth-peer' , encoding
= 'utf-8' ) as f
:
5907 check_json ( f
. read ())
5909 self
. assertFalse ( os
. path
. exists ( '/var/lib/systemd/network/dhcp-server-lease/veth-peer' ))
5911 def test_dhcp_server ( self
):
5912 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server.network' )
5914 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
5916 self
. check_dhcp_server ()
5918 networkctl_reconfigure ( 'veth-peer' )
5919 self
. wait_online ( 'veth-peer:routable' )
5922 output
= check_output (* networkctl_cmd
, '-n' , '0' , 'status' , 'veth-peer' , env
= env
)
5923 if 'Offered DHCP leases: 192.168.5.' in output
:
5929 def test_dhcp_server_persist_leases_no ( self
):
5930 copy_networkd_conf_dropin ( 'persist-leases-no.conf' )
5931 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server.network' )
5933 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
5935 self
. check_dhcp_server ( persist_leases
= False )
5937 remove_networkd_conf_dropin ( 'persist-leases-no.conf' )
5938 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-server.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
5939 f
. write ( '[DHCPServer] \n PersistLeases=no' )
5941 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
5943 self
. check_dhcp_server ( persist_leases
= False )
5945 def test_dhcp_server_null_server_address ( self
):
5946 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-null-server-address.network' )
5948 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
5950 output
= check_output ( 'ip --json address show dev veth-peer' )
5951 server_address
= json
. loads ( output
)[ 0 ][ 'addr_info' ][ 0 ][ 'local' ]
5952 print ( server_address
)
5954 output
= check_output ( 'ip --json address show dev veth99' )
5955 client_address
= json
. loads ( output
)[ 0 ][ 'addr_info' ][ 0 ][ 'local' ]
5956 print ( client_address
)
5958 output
= networkctl_status ( 'veth99' )
5960 self
. assertRegex ( output
, rf
'Address: {client_address} \(DHCPv4 via {server_address} \)' )
5961 self
. assertIn ( f
'Gateway: {server_address} ' , output
)
5962 self
. assertIn ( f
'DNS: {server_address} ' , output
)
5963 self
. assertIn ( f
'NTP: {server_address} ' , output
)
5965 output
= networkctl_status ( 'veth-peer' )
5966 self
. assertIn ( f
'Offered DHCP leases: {client_address} ' , output
)
5968 # Check if the same addresses are used even if the service is restarted.
5970 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
5972 output
= check_output ( 'ip -4 address show dev veth-peer' )
5974 self
. assertIn ( f
' {server_address} ' , output
)
5976 output
= check_output ( 'ip -4 address show dev veth99' )
5978 self
. assertIn ( f
' {client_address} ' , output
)
5980 output
= networkctl_status ( 'veth99' )
5982 self
. assertRegex ( output
, rf
'Address: {client_address} \(DHCPv4 via {server_address} \)' )
5983 self
. assertIn ( f
'Gateway: {server_address} ' , output
)
5984 self
. assertIn ( f
'DNS: {server_address} ' , output
)
5985 self
. assertIn ( f
'NTP: {server_address} ' , output
)
5987 output
= networkctl_status ( 'veth-peer' )
5988 self
. assertIn ( f
'Offered DHCP leases: {client_address} ' , output
)
5990 def test_dhcp_server_with_uplink ( self
):
5991 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-downstream.network' ,
5992 '12-dummy.netdev' , '25-dhcp-server-uplink.network' )
5994 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
5996 output
= networkctl_status ( 'veth99' )
5998 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCPv4 via 192.168.5.1\)' )
5999 self
. assertIn ( 'Gateway: 192.168.5.3' , output
)
6000 self
. assertIn ( 'DNS: 192.168.5.1' , output
)
6001 self
. assertIn ( 'NTP: 192.168.5.1' , output
)
6003 def test_emit_router_timezone ( self
):
6004 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-timezone-router.network' , '25-dhcp-server-timezone-router.network' )
6006 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6008 output
= networkctl_status ( 'veth99' )
6010 self
. assertRegex ( output
, r
'Address: 192.168.5.[0-9]* \(DHCPv4 via 192.168.5.1\)' )
6011 self
. assertIn ( 'Gateway: 192.168.5.1' , output
)
6012 self
. assertIn ( 'Time Zone: Europe/Berlin' , output
)
6014 def test_dhcp_server_static_lease ( self
):
6015 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client-static-lease.network' , '25-dhcp-server-static-lease.network' )
6017 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6019 output
= networkctl_status ( 'veth99' )
6021 self
. assertIn ( 'Address: 10.1.1.200 (DHCPv4 via 10.1.1.1)' , output
)
6022 self
. assertIn ( 'DHCPv4 Client ID: 12:34:56:78:9a:bc' , output
)
6024 def test_dhcp_server_static_lease_default_client_id ( self
):
6025 copy_network_unit ( '25-veth.netdev' , '25-dhcp-client.network' , '25-dhcp-server-static-lease.network' )
6027 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6029 output
= networkctl_status ( 'veth99' )
6031 self
. assertIn ( 'Address: 10.1.1.200 (DHCPv4 via 10.1.1.1)' , output
)
6032 self
. assertRegex ( output
, 'DHCPv4 Client ID: IAID:[0-9a-z]*/DUID' )
6034 class NetworkdDHCPServerRelayAgentTests ( unittest
. TestCase
, Utilities
):
6042 def test_relay_agent ( self
):
6043 copy_network_unit ( '25-agent-veth-client.netdev' ,
6044 '25-agent-veth-server.netdev' ,
6045 '25-agent-client.network' ,
6046 '25-agent-server.network' ,
6047 '25-agent-client-peer.network' ,
6048 '25-agent-server-peer.network' )
6051 self
. wait_online ( 'client:routable' )
6053 output
= networkctl_status ( 'client' )
6055 self
. assertRegex ( output
, r
'Address: 192.168.5.150 \(DHCPv4 via 192.168.5.1\)' )
6057 def test_relay_agent_on_bridge ( self
):
6058 copy_network_unit ( '25-agent-bridge.netdev' ,
6059 '25-agent-veth-client.netdev' ,
6060 '25-agent-bridge.network' ,
6061 '25-agent-bridge-port.network' ,
6062 '25-agent-client.network' )
6064 self
. wait_online ( 'bridge-relay:routable' , 'client-peer:enslaved' )
6067 self
. check_networkd_log ( 'bridge-relay: DHCPv4 server: STARTED' )
6069 class NetworkdDHCPClientTests ( unittest
. TestCase
, Utilities
):
6077 def test_dhcp_client_ipv6_only ( self
):
6078 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv6-only.network' )
6081 self
. wait_online ( 'veth-peer:carrier' )
6083 # information request mode
6084 # The name ipv6-only option may not be supported by older dnsmasq
6085 # start_dnsmasq('--dhcp-option=option:ipv6-only,300')
6086 start_dnsmasq ( '--dhcp-option=108,00:00:02:00' ,
6087 '--dhcp-option=option6:dns-server,[2600::ee]' ,
6088 '--dhcp-option=option6:ntp-server,[2600::ff]' ,
6089 ra_mode
= 'ra-stateless' )
6090 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6092 # DHCPv6 REPLY for INFORMATION-REQUEST may be received after the link entered configured state.
6093 # Let's wait for the expected DNS server being listed in the state file.
6094 for _
in range ( 100 ):
6095 output
= read_link_state_file ( 'veth99' )
6096 if 'DNS=2600::ee' in output
:
6100 # Check link state file
6101 print ( '## link state file' )
6102 output
= read_link_state_file ( 'veth99' )
6104 self
. assertIn ( 'DNS=2600::ee' , output
)
6105 self
. assertIn ( 'NTP=2600::ff' , output
)
6107 # Check manager state file
6108 print ( '## manager state file' )
6109 output
= read_manager_state_file ()
6111 self
. assertRegex ( output
, 'DNS=.*2600::ee' )
6112 self
. assertRegex ( output
, 'NTP=.*2600::ff' )
6114 print ( '## dnsmasq log' )
6115 output
= read_dnsmasq_log_file ()
6117 self
. assertIn ( 'DHCPINFORMATION-REQUEST(veth-peer)' , output
)
6118 self
. assertNotIn ( 'DHCPSOLICIT(veth-peer)' , output
)
6119 self
. assertNotIn ( 'DHCPADVERTISE(veth-peer)' , output
)
6120 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
6121 self
. assertNotIn ( 'DHCPREPLY(veth-peer)' , output
)
6124 check_json ( networkctl_json ( 'veth99' ))
6128 start_dnsmasq ( '--dhcp-option=108,00:00:02:00' ,
6129 '--dhcp-option=option6:dns-server,[2600::ee]' ,
6130 '--dhcp-option=option6:ntp-server,[2600::ff]' )
6131 networkctl_reconfigure ( 'veth99' )
6132 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6135 output
= check_output ( 'ip address show dev veth99 scope global' )
6137 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
6138 self
. assertNotIn ( '192.168.5' , output
)
6140 # checking semi-static route
6141 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
6143 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
6145 # Confirm that ipv6 token is not set in the kernel
6146 output
= check_output ( 'ip token show dev veth99' )
6148 self
. assertRegex ( output
, 'token :: dev veth99' )
6150 # Make manager and link state file updated
6151 resolvectl ( 'revert' , 'veth99' )
6153 # Check link state file
6154 print ( '## link state file' )
6155 output
= read_link_state_file ( 'veth99' )
6157 self
. assertIn ( 'DNS=2600::ee' , output
)
6158 self
. assertIn ( 'NTP=2600::ff' , output
)
6160 # Check manager state file
6161 print ( '## manager state file' )
6162 output
= read_manager_state_file ()
6164 self
. assertRegex ( output
, 'DNS=.*2600::ee' )
6165 self
. assertRegex ( output
, 'NTP=.*2600::ff' )
6167 print ( '## dnsmasq log' )
6168 output
= read_dnsmasq_log_file ()
6170 self
. assertNotIn ( 'DHCPINFORMATION-REQUEST(veth-peer)' , output
)
6171 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
6172 self
. assertNotIn ( 'DHCPADVERTISE(veth-peer)' , output
)
6173 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
6174 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
6175 self
. assertIn ( 'sent size: 0 option: 14 rapid-commit' , output
)
6178 check_json ( networkctl_json ( 'veth99' ))
6180 # Testing without rapid commit support
6181 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-ipv6-only.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
6182 f
. write ( ' \n [DHCPv6] \n RapidCommit=no \n ' )
6185 start_dnsmasq ( '--dhcp-option=108,00:00:02:00' ,
6186 '--dhcp-option=option6:dns-server,[2600::ee]' ,
6187 '--dhcp-option=option6:ntp-server,[2600::ff]' )
6190 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6193 output
= check_output ( 'ip address show dev veth99 scope global' )
6195 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
6196 self
. assertNotIn ( '192.168.5' , output
)
6198 # checking semi-static route
6199 output
= check_output ( 'ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff' )
6201 self
. assertRegex ( output
, 'via fe80::1034:56ff:fe78:9abd' )
6203 # Make manager and link state file updated
6204 resolvectl ( 'revert' , 'veth99' )
6206 # Check link state file
6207 print ( '## link state file' )
6208 output
= read_link_state_file ( 'veth99' )
6210 self
. assertIn ( 'DNS=2600::ee' , output
)
6211 self
. assertIn ( 'NTP=2600::ff' , output
)
6213 # Check manager state file
6214 print ( '## manager state file' )
6215 output
= read_manager_state_file ()
6217 self
. assertRegex ( output
, 'DNS=.*2600::ee' )
6218 self
. assertRegex ( output
, 'NTP=.*2600::ff' )
6220 print ( '## dnsmasq log' )
6221 output
= read_dnsmasq_log_file ()
6223 self
. assertNotIn ( 'DHCPINFORMATION-REQUEST(veth-peer)' , output
)
6224 self
. assertIn ( 'DHCPSOLICIT(veth-peer)' , output
)
6225 self
. assertIn ( 'DHCPADVERTISE(veth-peer)' , output
)
6226 self
. assertIn ( 'DHCPREQUEST(veth-peer)' , output
)
6227 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
6228 self
. assertNotIn ( 'rapid-commit' , output
)
6231 check_json ( networkctl_json ( 'veth99' ))
6233 def test_dhcp_client_ipv6_dbus_status ( self
):
6234 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv6-only.network' )
6236 self
. wait_online ( 'veth-peer:carrier' )
6238 # Note that at this point the DHCPv6 client has not been started because no RA (with managed
6239 # bit set) has yet been received and the configuration does not include WithoutRA=true
6240 state
= get_dhcp6_client_state ( 'veth99' )
6241 print ( f
"DHCPv6 client state = {state} " )
6242 self
. assertEqual ( state
, 'stopped' )
6244 state
= get_dhcp4_client_state ( 'veth99' )
6245 print ( f
"DHCPv4 client state = {state} " )
6246 self
. assertEqual ( state
, 'selecting' )
6248 start_dnsmasq ( '--dhcp-option=108,00:00:02:00' )
6249 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6251 state
= get_dhcp6_client_state ( 'veth99' )
6252 print ( f
"DHCPv6 client state = {state} " )
6253 self
. assertEqual ( state
, 'bound' )
6255 # DHCPv4 client will stop after an DHCPOFFER message received, so we need to wait for a while.
6256 for _
in range ( 100 ):
6257 state
= get_dhcp4_client_state ( 'veth99' )
6258 if state
== 'stopped' :
6262 print ( f
"DHCPv4 client state = {state} " )
6263 self
. assertEqual ( state
, 'stopped' )
6265 # restart dnsmasq to clear log
6267 start_dnsmasq ( '--dhcp-option=108,00:00:02:00' )
6269 # Test renew command
6270 # See https://github.com/systemd/systemd/pull/29472#issuecomment-1759092138
6271 networkctl ( 'renew' , 'veth99' )
6273 for _
in range ( 100 ):
6274 state
= get_dhcp4_client_state ( 'veth99' )
6275 if state
== 'stopped' :
6279 print ( f
"DHCPv4 client state = {state} " )
6280 self
. assertEqual ( state
, 'stopped' )
6282 print ( '## dnsmasq log' )
6283 output
= read_dnsmasq_log_file ()
6285 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc' , output
)
6286 self
. assertIn ( 'DHCPOFFER(veth-peer)' , output
)
6287 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
6288 self
. assertNotIn ( 'DHCPACK(veth-peer)' , output
)
6290 def test_dhcp_client_ipv6_only_with_custom_client_identifier ( self
):
6291 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv6-only-custom-client-identifier.network' )
6294 self
. wait_online ( 'veth-peer:carrier' )
6296 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6299 output
= check_output ( 'ip address show dev veth99 scope global' )
6301 self
. assertRegex ( output
, r
'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute' )
6302 self
. assertNotIn ( '192.168.5' , output
)
6304 print ( '## dnsmasq log' )
6305 output
= read_dnsmasq_log_file ()
6307 self
. assertIn ( 'DHCPSOLICIT(veth-peer) 00:42:00:00:ab:11:f9:2a:c2:77:29:f9:5c:00' , output
)
6308 self
. assertNotIn ( 'DHCPADVERTISE(veth-peer)' , output
)
6309 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
6310 self
. assertIn ( 'DHCPREPLY(veth-peer)' , output
)
6311 self
. assertIn ( 'sent size: 0 option: 14 rapid-commit' , output
)
6313 @expectedFailureIfKernelReturnsInvalidFlags ()
6314 def test_dhcp_client_ipv4_only ( self
):
6315 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv4-only.network' )
6317 self
. setup_nftset ( 'addr4' , 'ipv4_addr' )
6318 self
. setup_nftset ( 'network4' , 'ipv4_addr' , 'flags interval;' )
6319 self
. setup_nftset ( 'ifindex' , 'iface_index' )
6322 self
. wait_online ( 'veth-peer:carrier' )
6323 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7' ,
6324 '--dhcp-option=option:sip-server,192.168.5.21,192.168.5.22' ,
6325 '--dhcp-option=option:domain-search,example.com' ,
6326 '--dhcp-alternate-port=67,5555' ,
6327 ipv4_range
= '192.168.5.110,192.168.5.119' )
6328 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6329 self
. wait_address ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' )
6331 print ( '## ip address show dev veth99 scope global' )
6332 output
= check_output ( 'ip address show dev veth99 scope global' )
6334 self
. assertIn ( 'mtu 1492' , output
)
6335 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
6336 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' )
6337 self
. assertNotIn ( '2600::' , output
)
6339 output
= check_output ( 'ip -4 --json address show dev veth99' )
6340 for i
in json
. loads ( output
)[ 0 ][ 'addr_info' ]:
6341 if i
[ 'label' ] == 'test-label' :
6342 address1
= i
[ 'local' ]
6345 self
. assertFalse ( True )
6347 self
. assertRegex ( address1
, r
'^192.168.5.11[0-9]$' )
6349 print ( '## ip route show table main dev veth99' )
6350 output
= check_output ( 'ip route show table main dev veth99' )
6352 # no DHCP routes assigned to the main table
6353 self
. assertNotIn ( 'proto dhcp' , output
)
6355 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
6356 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
6357 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
6358 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
6360 print ( '## ip route show table 211 dev veth99' )
6361 output
= check_output ( 'ip route show table 211 dev veth99' )
6363 self
. assertRegex ( output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 24' )
6364 self
. assertRegex ( output
, f
'192.168.5.0/24 proto dhcp scope link src {address1} metric 24' )
6365 self
. assertRegex ( output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 24' )
6366 self
. assertRegex ( output
, f
'192.168.5.6 proto dhcp scope link src {address1} metric 24' )
6367 self
. assertRegex ( output
, f
'192.168.5.7 proto dhcp scope link src {address1} metric 24' )
6368 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
6370 print ( '## link state file' )
6371 output
= read_link_state_file ( 'veth99' )
6373 # checking DNS server, SIP server, and Domains
6374 self
. assertIn ( 'DNS=192.168.5.6 192.168.5.7' , output
)
6375 self
. assertIn ( 'SIP=192.168.5.21 192.168.5.22' , output
)
6376 self
. assertIn ( 'DOMAINS=example.com' , output
)
6379 j
= json
. loads ( networkctl_json ( 'veth99' ))
6381 self
. assertEqual ( len ( j
[ 'DNS' ]), 2 )
6384 self
. assertEqual ( i
[ 'Family' ], 2 )
6385 a
= socket
. inet_ntop ( socket
. AF_INET
, bytearray ( i
[ 'Address' ]))
6386 self
. assertRegex ( a
, '^192.168.5.[67]$' )
6387 self
. assertEqual ( i
[ 'ConfigSource' ], 'DHCPv4' )
6388 a
= socket
. inet_ntop ( socket
. AF_INET
, bytearray ( i
[ 'ConfigProvider' ]))
6389 self
. assertEqual ( '192.168.5.1' , a
)
6391 self
. assertEqual ( len ( j
[ 'SIP' ]), 2 )
6394 self
. assertEqual ( i
[ 'Family' ], 2 )
6395 a
= socket
. inet_ntop ( socket
. AF_INET
, bytearray ( i
[ 'Address' ]))
6396 self
. assertRegex ( a
, '^192.168.5.2[12]$' )
6397 self
. assertEqual ( i
[ 'ConfigSource' ], 'DHCPv4' )
6398 a
= socket
. inet_ntop ( socket
. AF_INET
, bytearray ( i
[ 'ConfigProvider' ]))
6399 self
. assertEqual ( '192.168.5.1' , a
)
6401 print ( '## dnsmasq log' )
6402 output
= read_dnsmasq_log_file ()
6404 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
6405 self
. assertIn ( 'DHCPDISCOVER(veth-peer) 192.168.5.110 12:34:56:78:9a:bc' , output
)
6406 self
. assertIn ( 'client provides name: test-hostname' , output
)
6407 self
. assertIn ( '26:mtu' , output
)
6409 # change address range, DNS servers, and Domains
6411 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8' ,
6412 '--dhcp-option=option:sip-server,192.168.5.23,192.168.5.24' ,
6413 '--dhcp-option=option:domain-search,foo.example.com' ,
6414 '--dhcp-alternate-port=67,5555' ,
6415 ipv4_range
= '192.168.5.120,192.168.5.129' ,)
6417 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
6418 print ( 'Wait for the DHCP lease to be expired' )
6419 self
. wait_address_dropped ( 'veth99' , f
'inet {address1} /24' , ipv
= '-4' , timeout_sec
= 120 )
6420 self
. wait_address ( 'veth99' , r
'inet 192.168.5.12[0-9]*/24' , ipv
= '-4' )
6422 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6424 print ( '## ip address show dev veth99 scope global' )
6425 output
= check_output ( 'ip address show dev veth99 scope global' )
6427 self
. assertIn ( 'mtu 1492' , output
)
6428 self
. assertIn ( 'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99' , output
)
6429 self
. assertNotIn ( f
' {address1} ' , output
)
6430 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' )
6431 self
. assertNotIn ( '2600::' , output
)
6433 output
= check_output ( 'ip -4 --json address show dev veth99' )
6434 for i
in json
. loads ( output
)[ 0 ][ 'addr_info' ]:
6435 if i
[ 'label' ] == 'test-label' :
6436 address2
= i
[ 'local' ]
6439 self
. assertFalse ( True )
6441 self
. assertRegex ( address2
, r
'^192.168.5.12[0-9]$' )
6443 print ( '## ip route show table main dev veth99' )
6444 output
= check_output ( 'ip route show table main dev veth99' )
6446 # no DHCP routes assigned to the main table
6447 self
. assertNotIn ( 'proto dhcp' , output
)
6449 self
. assertIn ( '192.168.5.0/24 proto kernel scope link src 192.168.5.250' , output
)
6450 self
. assertIn ( '192.168.5.0/24 proto static scope link' , output
)
6451 self
. assertIn ( '192.168.6.0/24 proto static scope link' , output
)
6452 self
. assertIn ( '192.168.7.0/24 proto static scope link' , output
)
6454 print ( '## ip route show table 211 dev veth99' )
6455 output
= check_output ( 'ip route show table 211 dev veth99' )
6457 self
. assertRegex ( output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 24' )
6458 self
. assertRegex ( output
, f
'192.168.5.0/24 proto dhcp scope link src {address2} metric 24' )
6459 self
. assertRegex ( output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 24' )
6460 self
. assertNotIn ( '192.168.5.6' , output
)
6461 self
. assertRegex ( output
, f
'192.168.5.7 proto dhcp scope link src {address2} metric 24' )
6462 self
. assertRegex ( output
, f
'192.168.5.8 proto dhcp scope link src {address2} metric 24' )
6463 self
. assertIn ( '10.0.0.0/8 via 192.168.5.1 proto dhcp' , output
)
6465 print ( '## link state file' )
6466 output
= read_link_state_file ( 'veth99' )
6468 # checking DNS server, SIP server, and Domains
6469 self
. assertIn ( 'DNS=192.168.5.1 192.168.5.7 192.168.5.8' , output
)
6470 self
. assertIn ( 'SIP=192.168.5.23 192.168.5.24' , output
)
6471 self
. assertIn ( 'DOMAINS=foo.example.com' , output
)
6474 j
= json
. loads ( networkctl_json ( 'veth99' ))
6476 self
. assertEqual ( len ( j
[ 'DNS' ]), 3 )
6479 self
. assertEqual ( i
[ 'Family' ], 2 )
6480 a
= socket
. inet_ntop ( socket
. AF_INET
, bytearray ( i
[ 'Address' ]))
6481 self
. assertRegex ( a
, '^192.168.5.[178]$' )
6482 self
. assertEqual ( i
[ 'ConfigSource' ], 'DHCPv4' )
6483 a
= socket
. inet_ntop ( socket
. AF_INET
, bytearray ( i
[ 'ConfigProvider' ]))
6484 self
. assertEqual ( '192.168.5.1' , a
)
6486 self
. assertEqual ( len ( j
[ 'SIP' ]), 2 )
6489 self
. assertEqual ( i
[ 'Family' ], 2 )
6490 a
= socket
. inet_ntop ( socket
. AF_INET
, bytearray ( i
[ 'Address' ]))
6491 self
. assertRegex ( a
, '^192.168.5.2[34]$' )
6492 self
. assertEqual ( i
[ 'ConfigSource' ], 'DHCPv4' )
6493 a
= socket
. inet_ntop ( socket
. AF_INET
, bytearray ( i
[ 'ConfigProvider' ]))
6494 self
. assertEqual ( '192.168.5.1' , a
)
6496 print ( '## dnsmasq log' )
6497 output
= read_dnsmasq_log_file ()
6499 self
. assertIn ( 'vendor class: FooBarVendorTest' , output
)
6500 self
. assertIn ( f
'DHCPDISCOVER(veth-peer) {address1} 12:34:56:78:9a:bc' , output
)
6501 self
. assertIn ( 'client provides name: test-hostname' , output
)
6502 self
. assertIn ( '26:mtu' , output
)
6504 self
. check_netlabel ( 'veth99' , r
'192\.168\.5\.0/24' )
6506 self
. check_nftset ( 'addr4' , r
'192\.168\.5\.1' )
6507 self
. check_nftset ( 'network4' , r
'192\.168\.5\.0/24' )
6508 self
. check_nftset ( 'ifindex' , 'veth99' )
6510 self
. teardown_nftset ( 'addr4' , 'network4' , 'ifindex' )
6512 def test_dhcp_client_ipv4_dbus_status ( self
):
6513 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-ipv4-only.network' )
6515 self
. wait_online ( 'veth-peer:carrier' )
6517 state
= get_dhcp4_client_state ( 'veth99' )
6518 print ( f
"State = {state} " )
6519 self
. assertEqual ( state
, 'rebooting' )
6521 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7' ,
6522 '--dhcp-option=option:domain-search,example.com' ,
6523 '--dhcp-alternate-port=67,5555' ,
6524 ipv4_range
= '192.168.5.110,192.168.5.119' )
6525 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6526 self
. wait_address ( 'veth99' , r
'inet 192.168.5.11[0-9]*/24' , ipv
= '-4' )
6528 state
= get_dhcp4_client_state ( 'veth99' )
6529 print ( f
"State = {state} " )
6530 self
. assertEqual ( state
, 'bound' )
6532 def test_dhcp_client_allow_list ( self
):
6533 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-allow-list.network' , copy_dropins
= False )
6536 self
. wait_online ( 'veth-peer:carrier' )
6537 since
= datetime
. datetime
. now ()
6540 self
. check_networkd_log ( 'veth99: DHCPv4 server IP address 192.168.5.1 not found in allow-list, ignoring offer.' , since
= since
)
6542 copy_network_unit ( '25-dhcp-client-allow-list.network.d/00-allow-list.conf' )
6543 since
= datetime
. datetime
. now ()
6546 self
. check_networkd_log ( 'veth99: DHCPv4 server IP address 192.168.5.1 not found in allow-list, ignoring offer.' , since
= since
)
6548 copy_network_unit ( '25-dhcp-client-allow-list.network.d/10-deny-list.conf' )
6549 since
= datetime
. datetime
. now ()
6552 self
. check_networkd_log ( 'veth99: DHCPv4 server IP address 192.168.5.1 found in deny-list, ignoring offer.' , since
= since
)
6554 @unittest . skipUnless ( "--dhcp-rapid-commit" in run ( "dnsmasq --help" ). stdout
, reason
= "dnsmasq is missing dhcp-rapid-commit support" )
6555 def test_dhcp_client_rapid_commit ( self
):
6556 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' )
6558 self
. wait_online ( 'veth-peer:carrier' )
6560 start_dnsmasq ( '--dhcp-rapid-commit' )
6561 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6562 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24' , ipv
= '-4' )
6564 state
= get_dhcp4_client_state ( 'veth99' )
6565 print ( f
"DHCPv4 client state = {state} " )
6566 self
. assertEqual ( state
, 'bound' )
6568 output
= read_dnsmasq_log_file ()
6569 self
. assertIn ( 'DHCPDISCOVER(veth-peer)' , output
)
6570 self
. assertNotIn ( 'DHCPOFFER(veth-peer)' , output
)
6571 self
. assertNotIn ( 'DHCPREQUEST(veth-peer)' , output
)
6572 self
. assertIn ( 'DHCPACK(veth-peer)' , output
)
6574 def test_dhcp_client_ipv6_only_mode_without_ipv6_connectivity ( self
):
6575 copy_network_unit ( '25-veth.netdev' ,
6576 '25-dhcp-server-ipv6-only-mode.network' ,
6577 '25-dhcp-client-ipv6-only-mode.network' )
6579 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' , timeout
= '40s' )
6580 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24' , ipv
= '-4' )
6582 state
= get_dhcp4_client_state ( 'veth99' )
6583 print ( f
"State = {state} " )
6584 self
. assertEqual ( state
, 'bound' )
6586 def test_dhcp_client_ipv4_use_routes_gateway ( self
):
6588 for ( routes
, gateway
, dns_and_ntp_routes
, classless
) in itertools
. product ([ True , False ], repeat
= 4 ):
6594 print ( f
'### test_dhcp_client_ipv4_use_routes_gateway(routes= {routes} , gateway= {gateway} , dns_and_ntp_routes= {dns_and_ntp_routes} , classless= {classless} )' )
6595 with self
. subTest ( routes
= routes
, gateway
= gateway
, dns_and_ntp_routes
= dns_and_ntp_routes
, classless
= classless
):
6596 self
._ test
_ dhcp
_ client
_ ipv
4_u se
_ routes
_ gateway
( routes
, gateway
, dns_and_ntp_routes
, classless
)
6598 def _test_dhcp_client_ipv4_use_routes_gateway ( self
, use_routes
, use_gateway
, dns_and_ntp_routes
, classless
):
6599 testunit
= '25-dhcp-client-ipv4-use-routes-use-gateway.network'
6600 testunits
= [ '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , testunit
]
6601 testunits
. append ( f
' {testunit} .d/use-routes- {use_routes} .conf' )
6602 testunits
. append ( f
' {testunit} .d/use-gateway- {use_gateway} .conf' )
6603 testunits
. append ( f
' {testunit} .d/use-dns-and-ntp-routes- {dns_and_ntp_routes} .conf' )
6604 copy_network_unit (* testunits
, copy_dropins
= False )
6607 self
. wait_online ( 'veth-peer:carrier' )
6608 additional_options
= [
6609 '--dhcp-option=option:dns-server,192.168.5.10,8.8.8.8' ,
6610 '--dhcp-option=option:ntp-server,192.168.5.11,9.9.9.9' ,
6611 '--dhcp-option=option:static-route,192.168.6.100,192.168.5.2,8.8.8.8,192.168.5.3'
6614 additional_options
+= [
6615 '--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'
6617 start_dnsmasq (* additional_options
)
6618 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6620 output
= check_output ( 'ip -4 route show dev veth99' )
6626 self
. assertRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6627 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6628 self
. assertRegex ( output
, r
'192.168.5.64/26 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6629 self
. assertRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6630 self
. assertRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6632 self
. assertRegex ( output
, r
'192.168.6.0/24 via 192.168.5.2 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6633 self
. assertRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6634 self
. assertRegex ( output
, r
'192.168.5.2 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6635 self
. assertRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6637 self
. assertNotRegex ( output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6638 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6639 self
. assertNotRegex ( output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6640 self
. assertNotRegex ( output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6641 self
. assertNotRegex ( output
, r
'192.168.6.0/24 via 192.168.5.2 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6642 self
. assertNotRegex ( output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6643 self
. assertNotRegex ( output
, r
'192.168.5.2 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6644 self
. assertNotRegex ( output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6647 if use_gateway
and ( not classless
or not use_routes
):
6648 self
. assertRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6650 self
. assertNotRegex ( output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6652 # Check route to gateway
6653 if ( use_gateway
or dns_and_ntp_routes
) and ( not classless
or not use_routes
):
6654 self
. assertRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6656 self
. assertNotRegex ( output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6658 # Check RoutesToDNS= and RoutesToNTP=
6659 if dns_and_ntp_routes
:
6660 self
. assertRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6661 self
. assertRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6664 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6665 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6667 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6668 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6670 self
. assertRegex ( output
, r
'8.8.8.8 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6671 self
. assertRegex ( output
, r
'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024' )
6673 self
. assertNotRegex ( output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6674 self
. assertNotRegex ( output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024' )
6675 self
. assertNotRegex ( output
, r
'8.8.8.8 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
6676 self
. assertNotRegex ( output
, r
'9.9.9.9 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024' )
6678 check_json ( networkctl_json ())
6680 def test_dhcp_client_settings_anonymize ( self
):
6681 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-anonymize.network' )
6683 self
. wait_online ( 'veth-peer:carrier' )
6685 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6687 print ( '## dnsmasq log' )
6688 output
= read_dnsmasq_log_file ()
6690 self
. assertNotIn ( 'VendorClassIdentifier=SusantVendorTest' , output
)
6691 self
. assertNotIn ( 'test-hostname' , output
)
6692 self
. assertNotIn ( '26:mtu' , output
)
6694 def test_dhcp_keep_configuration_dhcp ( self
):
6695 copy_network_unit ( '25-veth.netdev' ,
6696 '25-dhcp-server-veth-peer.network' ,
6697 '25-dhcp-client-keep-configuration-dhcp.network' )
6699 self
. wait_online ( 'veth-peer:carrier' )
6701 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6703 output
= check_output ( 'ip address show dev veth99 scope global' )
6705 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
6706 'valid_lft forever preferred_lft forever' )
6708 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
6711 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
6712 print ( 'Wait for the DHCP lease to be expired' )
6715 # The lease address should be kept after the lease expired
6716 output
= check_output ( 'ip address show dev veth99 scope global' )
6718 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
6719 'valid_lft forever preferred_lft forever' )
6723 # The lease address should be kept after networkd stopped
6724 output
= check_output ( 'ip address show dev veth99 scope global' )
6726 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
6727 'valid_lft forever preferred_lft forever' )
6729 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client-keep-configuration-dhcp.network' ), mode
= 'a' , encoding
= 'utf-8' ) as f
:
6730 f
. write ( '[Network] \n DHCP=no \n ' )
6733 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6735 # Still the lease address should be kept after networkd restarted
6736 output
= check_output ( 'ip address show dev veth99 scope global' )
6738 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
6739 'valid_lft forever preferred_lft forever' )
6741 def test_dhcp_keep_configuration_dhcp_on_stop ( self
):
6742 copy_network_unit ( '25-veth.netdev' ,
6743 '25-dhcp-server-veth-peer.network' ,
6744 '25-dhcp-client-keep-configuration-dhcp-on-stop.network' )
6746 self
. wait_online ( 'veth-peer:carrier' )
6748 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6750 output
= check_output ( 'ip address show dev veth99 scope global' )
6752 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
6757 output
= check_output ( 'ip address show dev veth99 scope global' )
6759 self
. assertRegex ( output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
6762 self
. wait_online ( 'veth-peer:routable' )
6764 output
= check_output ( 'ip address show dev veth99 scope global' )
6766 self
. assertNotIn ( '192.168.5.' , output
)
6768 def test_dhcp_client_reuse_address_as_static ( self
):
6769 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' )
6771 self
. wait_online ( 'veth-peer:carrier' )
6773 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6775 # link become 'routable' when at least one protocol provide an valid address.
6776 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
6777 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
6779 output
= check_output ( 'ip address show dev veth99 scope global' )
6780 ipv4_address
= re
. search ( r
'192.168.5.[0-9]*/24' , output
). group ()
6781 ipv6_address
= re
. search ( r
'2600::[0-9a-f:]*/128' , output
). group ()
6782 static_network
= ' \n ' . join ([ '[Match]' , 'Name=veth99' , '[Network]' , 'IPv6AcceptRA=no' , 'Address=' + ipv4_address
, 'Address=' + ipv6_address
])
6783 print ( static_network
)
6785 remove_network_unit ( '25-dhcp-client.network' )
6787 with
open ( os
. path
. join ( network_unit_dir
, '25-static.network' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
6788 f
. write ( static_network
)
6791 self
. wait_online ( 'veth99:routable' )
6793 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
6795 self
. assertRegex ( output
, f
'inet {ipv4_address} brd 192.168.5.255 scope global veth99 \n *'
6796 'valid_lft forever preferred_lft forever' )
6798 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
6800 self
. assertRegex ( output
, f
'inet6 {ipv6_address} scope global * \n *'
6801 'valid_lft forever preferred_lft forever' )
6803 @expectedFailureIfModuleIsNotAvailable ( 'vrf' )
6804 def test_dhcp_client_vrf ( self
):
6805 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client-vrf.network' ,
6806 '25-vrf.netdev' , '25-vrf.network' )
6808 self
. wait_online ( 'veth-peer:carrier' )
6810 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' , 'vrf99:carrier' )
6812 # link become 'routable' when at least one protocol provide an valid address.
6813 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
6814 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
6816 print ( '## ip -d link show dev vrf99' )
6817 output
= check_output ( 'ip -d link show dev vrf99' )
6819 self
. assertRegex ( output
, 'vrf table 42' )
6821 print ( '## ip address show vrf vrf99' )
6822 output
= check_output ( 'ip address show vrf vrf99' )
6824 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
6825 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
6826 self
. assertRegex ( output
, 'inet6 .* scope link' )
6828 print ( '## ip address show dev veth99' )
6829 output
= check_output ( 'ip address show dev veth99' )
6831 self
. assertRegex ( output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99' )
6832 self
. assertRegex ( output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
6833 self
. assertRegex ( output
, 'inet6 .* scope link' )
6835 print ( '## ip route show vrf vrf99' )
6836 output
= check_output ( 'ip route show vrf vrf99' )
6838 self
. assertRegex ( output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.' )
6839 self
. assertRegex ( output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5' )
6840 self
. assertRegex ( output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5' )
6842 print ( '## ip route show table main dev veth99' )
6843 output
= check_output ( 'ip route show table main dev veth99' )
6845 self
. assertEqual ( output
, '' )
6847 def test_dhcp_client_gateway_onlink_implicit ( self
):
6848 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
6849 '25-dhcp-client-gateway-onlink-implicit.network' )
6851 self
. wait_online ( 'veth-peer:carrier' )
6853 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' )
6855 output
= networkctl_status ( 'veth99' )
6857 self
. assertRegex ( output
, '192.168.5' )
6859 output
= check_output ( 'ip route list dev veth99 10.0.0.0/8' )
6861 self
. assertRegex ( output
, 'onlink' )
6862 output
= check_output ( 'ip route list dev veth99 192.168.100.0/24' )
6864 self
. assertRegex ( output
, 'onlink' )
6866 def test_dhcp_client_with_ipv4ll ( self
):
6867 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' ,
6868 '25-dhcp-client-with-ipv4ll.network' )
6870 # we need to increase timeout above default, as this will need to wait for
6871 # systemd-networkd to get the dhcpv4 transient failure event
6872 self
. wait_online ( 'veth99:degraded' , 'veth-peer:routable' , timeout
= '60s' )
6874 output
= check_output ( 'ip -4 address show dev veth99' )
6876 self
. assertNotIn ( '192.168.5.' , output
)
6877 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
6880 print ( 'Wait for a DHCP lease to be acquired and the IPv4LL address to be dropped' )
6881 self
. wait_address ( 'veth99' , r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic' , ipv
= '-4' )
6882 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' )
6883 self
. wait_online ( 'veth99:routable' )
6885 output
= check_output ( 'ip -4 address show dev veth99' )
6887 self
. assertRegex ( output
, r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99' )
6888 self
. assertNotIn ( '169.254.' , output
)
6889 self
. assertNotIn ( 'scope link' , output
)
6892 print ( 'Wait for the DHCP lease to be expired and an IPv4LL address to be acquired' )
6893 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 )
6894 self
. wait_address ( 'veth99' , r
'inet 169\.254\.133\.11/16 metric 2048 brd 169\.254\.255\.255 scope link' , scope
= 'link' , ipv
= '-4' )
6896 output
= check_output ( 'ip -4 address show dev veth99' )
6898 self
. assertNotIn ( '192.168.5.' , output
)
6899 self
. assertIn ( 'inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link' , output
)
6901 def test_dhcp_client_use_dns ( self
):
6902 def check ( self
, ipv4
, ipv6
):
6903 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
6904 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
6905 f
. write ( '[DHCPv4] \n UseDNS=' )
6906 f
. write ( 'yes' if ipv4
else 'no' )
6907 f
. write ( ' \n [DHCPv6] \n UseDNS=' )
6908 f
. write ( 'yes' if ipv6
else 'no' )
6909 f
. write ( ' \n [IPv6AcceptRA] \n UseDNS=no' )
6912 self
. wait_online ( 'veth99:routable' )
6914 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
6915 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
6916 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
6918 # make resolved re-read the link state file
6919 resolvectl ( 'revert' , 'veth99' )
6921 output
= resolvectl ( 'dns' , 'veth99' )
6924 self
. assertIn ( '192.168.5.1' , output
)
6926 self
. assertNotIn ( '192.168.5.1' , output
)
6928 self
. assertIn ( '2600::1' , output
)
6930 self
. assertNotIn ( '2600::1' , output
)
6932 check_json ( networkctl_json ())
6934 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
6937 self
. wait_online ( 'veth-peer:carrier' )
6938 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1' ,
6939 '--dhcp-option=option6:dns-server,[2600::1]' )
6941 check ( self
, True , True )
6942 check ( self
, True , False )
6943 check ( self
, False , True )
6944 check ( self
, False , False )
6946 def test_dhcp_client_default_use_domains ( self
):
6947 def check ( self
, common
, ipv4
, ipv6
):
6948 mkdir_p ( networkd_conf_dropin_dir
)
6949 with
open ( os
. path
. join ( networkd_conf_dropin_dir
, 'default_use_domains.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
6950 f
. write ( '[Network] \n UseDomains=' )
6951 f
. write ( 'yes \n ' if common
else 'no \n ' )
6952 f
. write ( '[DHCPv4] \n UseDomains=' )
6953 f
. write ( 'yes \n ' if ipv4
else 'no \n ' )
6954 f
. write ( '[DHCPv6] \n UseDomains=' )
6955 f
. write ( 'yes \n ' if ipv6
else 'no \n ' )
6958 self
. wait_online ( 'veth-peer:carrier' )
6959 start_dnsmasq ( '--dhcp-option=option:dns-server,192.168.5.1' ,
6960 '--dhcp-option=option6:dns-server,[2600::1]' ,
6961 '--dhcp-option=option:domain-search,example.com' ,
6962 '--dhcp-option=option6:domain-search,example.com' )
6964 self
. wait_online ( 'veth99:routable' )
6966 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
6967 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
6968 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
6971 output
= resolvectl ( 'domain' , 'veth99' )
6972 if common
or ipv4
or ipv6
:
6973 if 'example.com' in output
:
6976 if 'example.com' not in output
:
6981 print ( read_link_state_file ( 'veth99' ))
6982 self
. fail ( 'unexpected domain setting in resolved...' )
6985 remove_networkd_conf_dropin ( 'default_use_domains.conf' )
6987 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
6988 check ( self
, True , False , False )
6989 check ( self
, False , True , True )
6990 check ( self
, False , True , False )
6991 check ( self
, False , False , True )
6992 check ( self
, False , False , False )
6994 def test_dhcp_client_use_captive_portal ( self
):
6995 def check ( self
, ipv4
, ipv6
):
6996 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
6997 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
6998 f
. write ( '[DHCPv4] \n UseCaptivePortal=' )
6999 f
. write ( 'yes' if ipv4
else 'no' )
7000 f
. write ( ' \n [DHCPv6] \n UseCaptivePortal=' )
7001 f
. write ( 'yes' if ipv6
else 'no' )
7002 f
. write ( ' \n [IPv6AcceptRA] \n UseCaptivePortal=no' )
7005 self
. wait_online ( 'veth99:routable' )
7007 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
7008 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
7009 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
7011 output
= networkctl_status ( 'veth99' )
7014 self
. assertIn ( 'Captive Portal: http://systemd.io' , output
)
7016 self
. assertNotIn ( 'Captive Portal: http://systemd.io' , output
)
7018 check_json ( networkctl_json ())
7020 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
7023 self
. wait_online ( 'veth-peer:carrier' )
7024 start_dnsmasq ( '--dhcp-option=114,http://systemd.io' ,
7025 '--dhcp-option=option6:103,http://systemd.io' )
7027 check ( self
, True , True )
7028 check ( self
, True , False )
7029 check ( self
, False , True )
7030 check ( self
, False , False )
7032 def test_dhcp_client_reject_captive_portal ( self
):
7033 def check ( self
, ipv4
, ipv6
):
7034 os
. makedirs ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d' ), exist_ok
= True )
7035 with
open ( os
. path
. join ( network_unit_dir
, '25-dhcp-client.network.d/override.conf' ), mode
= 'w' , encoding
= 'utf-8' ) as f
:
7036 f
. write ( '[DHCPv4] \n UseCaptivePortal=' )
7037 f
. write ( 'yes' if ipv4
else 'no' )
7038 f
. write ( ' \n [DHCPv6] \n UseCaptivePortal=' )
7039 f
. write ( 'yes' if ipv6
else 'no' )
7040 f
. write ( ' \n [IPv6AcceptRA] \n UseCaptivePortal=no' )
7043 self
. wait_online ( 'veth99:routable' )
7045 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
7046 self
. wait_address ( 'veth99' , r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic' , ipv
= '-4' )
7047 self
. wait_address ( 'veth99' , r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' , ipv
= '-6' )
7049 output
= networkctl_status ( 'veth99' )
7051 self
. assertNotIn ( 'Captive Portal: ' , output
)
7052 self
. assertNotIn ( 'invalid/url' , output
)
7054 check_json ( networkctl_json ())
7056 copy_network_unit ( '25-veth.netdev' , '25-dhcp-server-veth-peer.network' , '25-dhcp-client.network' , copy_dropins
= False )
7059 self
. wait_online ( 'veth-peer:carrier' )
7060 masq
= lambda bs
: ':' . join ( f
'{b:02x}' for b
in bs
)
7061 start_dnsmasq ( '--dhcp-option=114,' + masq ( b
'http:// \x00 invalid/url' ),
7062 '--dhcp-option=option6:103,' + masq ( b
'http:// \x00 /invalid/url' ))
7064 check ( self
, True , True )
7065 check ( self
, True , False )
7066 check ( self
, False , True )
7067 check ( self
, False , False )
7069 class NetworkdDHCPPDTests ( unittest
. TestCase
, Utilities
):
7077 def check_dhcp6_prefix ( self
, link
):
7078 description
= get_link_description ( link
)
7080 self
. assertIn ( 'DHCPv6Client' , description
. keys ())
7081 self
. assertIn ( 'Prefixes' , description
[ 'DHCPv6Client' ])
7083 prefixInfo
= description
[ 'DHCPv6Client' ][ 'Prefixes' ]
7085 self
. assertEqual ( len ( prefixInfo
), 1 )
7087 self
. assertIn ( 'Prefix' , prefixInfo
[ 0 ]. keys ())
7088 self
. assertIn ( 'PrefixLength' , prefixInfo
[ 0 ]. keys ())
7089 self
. assertIn ( 'PreferredLifetimeUSec' , prefixInfo
[ 0 ]. keys ())
7090 self
. assertIn ( 'ValidLifetimeUSec' , prefixInfo
[ 0 ]. keys ())
7092 self
. assertEqual ( prefixInfo
[ 0 ][ 'Prefix' ][ 0 : 6 ], [ 63 , 254 , 5 , 1 , 255 , 255 ])
7093 self
. assertEqual ( prefixInfo
[ 0 ][ 'PrefixLength' ], 56 )
7094 self
. assertGreater ( prefixInfo
[ 0 ][ 'PreferredLifetimeUSec' ], 0 )
7095 self
. assertGreater ( prefixInfo
[ 0 ][ 'ValidLifetimeUSec' ], 0 )
7097 def test_dhcp6pd_no_address ( self
):
7099 copy_network_unit ( '25-veth.netdev' , '25-dhcp6pd-server.network' , '25-dhcp6pd-upstream-no-address.network' )
7102 self
. wait_online ( 'veth-peer:routable' )
7103 start_isc_dhcpd ( conf_file
= 'isc-dhcpd-dhcp6pd.conf' , ipv
= '-6' )
7104 self
. wait_online ( 'veth99:degraded' )
7106 print ( '### ip -6 address show dev veth99 scope global' )
7107 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
7109 self
. assertNotIn ( 'inet6 3ffe:501:ffff' , output
)
7111 self
. check_dhcp6_prefix ( 'veth99' )
7113 def test_dhcp6pd_no_assign ( self
):
7114 # Similar to test_dhcp6pd_no_assign(), but in this case UseAddress=yes (default),
7115 # However, the server does not provide IA_NA. For issue #31349.
7116 copy_network_unit ( '25-veth.netdev' , '25-dhcp6pd-server.network' , '25-dhcp6pd-upstream-no-assign.network' )
7119 self
. wait_online ( 'veth-peer:routable' )
7120 start_isc_dhcpd ( conf_file
= 'isc-dhcpd-dhcp6pd-no-range.conf' , ipv
= '-6' )
7121 self
. wait_online ( 'veth99:degraded' )
7123 print ( '### ip -6 address show dev veth99 scope global' )
7124 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
7126 self
. assertNotIn ( 'inet6 3ffe:501:ffff' , output
)
7128 self
. check_dhcp6_prefix ( 'veth99' )
7130 def test_dhcp6pd ( self
):
7131 copy_network_unit ( '25-veth.netdev' , '25-dhcp6pd-server.network' , '25-dhcp6pd-upstream.network' ,
7132 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
7133 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
7134 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
7135 '25-dhcp-pd-downstream-dummy97.network' ,
7136 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
7137 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' )
7140 self
. wait_online ( 'veth-peer:routable' )
7141 start_isc_dhcpd ( conf_file
= 'isc-dhcpd-dhcp6pd.conf' , ipv
= '-6' )
7142 self
. wait_online ( 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
7143 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' )
7145 self
. setup_nftset ( 'addr6' , 'ipv6_addr' )
7146 self
. setup_nftset ( 'network6' , 'ipv6_addr' , 'flags interval;' )
7147 self
. setup_nftset ( 'ifindex' , 'iface_index' )
7149 # Check DBus assigned prefix information to veth99
7150 self
. check_dhcp6_prefix ( 'veth99' )
7152 print ( '### ip -6 address show dev veth-peer scope global' )
7153 output
= check_output ( 'ip -6 address show dev veth-peer scope global' )
7155 self
. assertIn ( 'inet6 3ffe:501:ffff:100::1/64 scope global' , output
)
7159 # dummy97: 0x01 (The link will appear later)
7161 # dummy99: auto -> 0x02 (No address assignment)
7166 print ( '### ip -6 address show dev veth99 scope global' )
7167 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
7170 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:100::[0-9]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)' )
7171 # address in IA_PD (Token=static)
7172 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic' )
7173 # address in IA_PD (Token=eui64)
7174 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic' )
7175 # address in IA_PD (temporary)
7176 # Note that the temporary addresses may appear after the link enters configured state
7177 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' )
7179 print ( '### ip -6 address show dev test1 scope global' )
7180 output
= check_output ( 'ip -6 address show dev test1 scope global' )
7182 # address in IA_PD (Token=static)
7183 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7184 # address in IA_PD (temporary)
7185 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' )
7187 print ( '### ip -6 address show dev dummy98 scope global' )
7188 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
7190 # address in IA_PD (Token=static)
7191 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7192 # address in IA_PD (temporary)
7193 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' )
7195 print ( '### ip -6 address show dev dummy99 scope global' )
7196 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
7199 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
7201 print ( '### ip -6 address show dev veth97 scope global' )
7202 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
7204 # address in IA_PD (Token=static)
7205 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7206 # address in IA_PD (Token=eui64)
7207 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7208 # address in IA_PD (temporary)
7209 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' )
7211 print ( '### ip -6 address show dev veth97-peer scope global' )
7212 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
7214 # NDisc address (Token=static)
7215 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7216 # NDisc address (Token=eui64)
7217 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7218 # NDisc address (temporary)
7219 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' )
7221 print ( '### ip -6 address show dev veth98 scope global' )
7222 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
7224 # address in IA_PD (Token=static)
7225 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7226 # address in IA_PD (Token=eui64)
7227 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7228 # address in IA_PD (temporary)
7229 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' )
7231 print ( '### ip -6 address show dev veth98-peer scope global' )
7232 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
7234 # NDisc address (Token=static)
7235 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7236 # NDisc address (Token=eui64)
7237 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7238 # NDisc address (temporary)
7239 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' )
7241 print ( '### ip -6 route show type unreachable' )
7242 output
= check_output ( 'ip -6 route show type unreachable' )
7244 self
. assertRegex ( output
, 'unreachable 3ffe:501:ffff:[2-9a-f]00::/56 dev lo proto dhcp' )
7246 print ( '### ip -6 route show dev veth99' )
7247 output
= check_output ( 'ip -6 route show dev veth99' )
7249 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]10::/64 proto kernel metric [0-9]* expires' )
7251 print ( '### ip -6 route show dev test1' )
7252 output
= check_output ( 'ip -6 route show dev test1' )
7254 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
7256 print ( '### ip -6 route show dev dummy98' )
7257 output
= check_output ( 'ip -6 route show dev dummy98' )
7259 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
7261 print ( '### ip -6 route show dev dummy99' )
7262 output
= check_output ( 'ip -6 route show dev dummy99' )
7264 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
7266 print ( '### ip -6 route show dev veth97' )
7267 output
= check_output ( 'ip -6 route show dev veth97' )
7269 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto kernel metric [0-9]* expires' )
7271 print ( '### ip -6 route show dev veth97-peer' )
7272 output
= check_output ( 'ip -6 route show dev veth97-peer' )
7274 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]08::/64 proto ra metric [0-9]* expires' )
7276 print ( '### ip -6 route show dev veth98' )
7277 output
= check_output ( 'ip -6 route show dev veth98' )
7279 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto kernel metric [0-9]* expires' )
7281 print ( '### ip -6 route show dev veth98-peer' )
7282 output
= check_output ( 'ip -6 route show dev veth98-peer' )
7284 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]09::/64 proto ra metric [0-9]* expires' )
7286 # Test case for a downstream which appears later
7287 check_output ( 'ip link add dummy97 type dummy' )
7288 self
. wait_online ( 'dummy97:routable' )
7290 print ( '### ip -6 address show dev dummy97 scope global' )
7291 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
7293 # address in IA_PD (Token=static)
7294 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7295 # address in IA_PD (temporary)
7296 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' )
7298 print ( '### ip -6 route show dev dummy97' )
7299 output
= check_output ( 'ip -6 route show dev dummy97' )
7301 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]01::/64 proto kernel metric [0-9]* expires' )
7303 # Test case for reconfigure
7304 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
7305 self
. wait_online ( 'dummy98:routable' , 'dummy99:degraded' )
7307 print ( '### ip -6 address show dev dummy98 scope global' )
7308 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
7310 # address in IA_PD (Token=static)
7311 self
. assertRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7312 # address in IA_PD (temporary)
7313 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' )
7315 print ( '### ip -6 address show dev dummy99 scope global' )
7316 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
7319 self
. assertNotRegex ( output
, 'inet6 3ffe:501:ffff:[2-9a-f]02' )
7321 print ( '### ip -6 route show dev dummy98' )
7322 output
= check_output ( 'ip -6 route show dev dummy98' )
7324 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires' )
7326 print ( '### ip -6 route show dev dummy99' )
7327 output
= check_output ( 'ip -6 route show dev dummy99' )
7329 self
. assertRegex ( output
, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires' )
7331 self
. check_netlabel ( 'dummy98' , '3ffe:501:ffff:[2-9a-f]00::/64' )
7333 self
. check_nftset ( 'addr6' , '3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d' )
7334 self
. check_nftset ( 'addr6' , '3ffe:501:ffff:[2-9a-f]00:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*' )
7335 self
. check_nftset ( 'network6' , '3ffe:501:ffff:[2-9a-f]00::/64' )
7336 self
. check_nftset ( 'ifindex' , 'dummy98' )
7338 self
. teardown_nftset ( 'addr6' , 'network6' , 'ifindex' )
7340 def verify_dhcp4_6rd ( self
, tunnel_name
):
7341 print ( '### ip -4 address show dev veth-peer scope global' )
7342 output
= check_output ( 'ip -4 address show dev veth-peer scope global' )
7344 self
. assertIn ( 'inet 10.0.0.1/8 brd 10.255.255.255 scope global veth-peer' , output
)
7348 # dummy97: 0x01 (The link will appear later)
7350 # dummy99: auto -> 0x0[23] (No address assignment)
7351 # 6rd-XXX: auto -> 0x0[23]
7356 print ( '### ip -4 address show dev veth99 scope global' )
7357 output
= check_output ( 'ip -4 address show dev veth99 scope global' )
7359 self
. assertRegex ( output
, 'inet 10.100.100.[0-9]*/8 (metric 1024 |)brd 10.255.255.255 scope global dynamic veth99' )
7361 print ( '### ip -6 address show dev veth99 scope global' )
7362 output
= check_output ( 'ip -6 address show dev veth99 scope global' )
7364 # address in IA_PD (Token=static)
7365 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7366 # address in IA_PD (Token=eui64)
7367 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7368 # address in IA_PD (temporary)
7369 # Note that the temporary addresses may appear after the link enters configured state
7370 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' )
7372 print ( '### ip -6 address show dev test1 scope global' )
7373 output
= check_output ( 'ip -6 address show dev test1 scope global' )
7375 # address in IA_PD (Token=static)
7376 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7377 # address in IA_PD (temporary)
7378 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' )
7380 print ( '### ip -6 address show dev dummy98 scope global' )
7381 output
= check_output ( 'ip -6 address show dev dummy98 scope global' )
7383 # address in IA_PD (Token=static)
7384 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7385 # address in IA_PD (temporary)
7386 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' )
7388 print ( '### ip -6 address show dev dummy99 scope global' )
7389 output
= check_output ( 'ip -6 address show dev dummy99 scope global' )
7392 self
. assertNotRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+0[23]' )
7394 print ( '### ip -6 address show dev veth97 scope global' )
7395 output
= check_output ( 'ip -6 address show dev veth97 scope global' )
7397 # address in IA_PD (Token=static)
7398 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7399 # address in IA_PD (Token=eui64)
7400 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7401 # address in IA_PD (temporary)
7402 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' )
7404 print ( '### ip -6 address show dev veth97-peer scope global' )
7405 output
= check_output ( 'ip -6 address show dev veth97-peer scope global' )
7407 # NDisc address (Token=static)
7408 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7409 # NDisc address (Token=eui64)
7410 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7411 # NDisc address (temporary)
7412 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' )
7414 print ( '### ip -6 address show dev veth98 scope global' )
7415 output
= check_output ( 'ip -6 address show dev veth98 scope global' )
7417 # address in IA_PD (Token=static)
7418 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7419 # address in IA_PD (Token=eui64)
7420 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7421 # address in IA_PD (temporary)
7422 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' )
7424 print ( '### ip -6 address show dev veth98-peer scope global' )
7425 output
= check_output ( 'ip -6 address show dev veth98-peer scope global' )
7427 # NDisc address (Token=static)
7428 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7429 # NDisc address (Token=eui64)
7430 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7431 # NDisc address (temporary)
7432 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' )
7434 print ( '### ip -6 route show type unreachable' )
7435 output
= check_output ( 'ip -6 route show type unreachable' )
7437 self
. assertRegex ( output
, 'unreachable 2001:db8:6464:[0-9a-f]+00::/56 dev lo proto dhcp' )
7439 print ( '### ip -6 route show dev veth99' )
7440 output
= check_output ( 'ip -6 route show dev veth99' )
7442 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+10::/64 proto kernel metric [0-9]* expires' )
7444 print ( '### ip -6 route show dev test1' )
7445 output
= check_output ( 'ip -6 route show dev test1' )
7447 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
7449 print ( '### ip -6 route show dev dummy98' )
7450 output
= check_output ( 'ip -6 route show dev dummy98' )
7452 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires' )
7454 print ( '### ip -6 route show dev dummy99' )
7455 output
= check_output ( 'ip -6 route show dev dummy99' )
7457 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto dhcp metric [0-9]* expires' )
7459 print ( '### ip -6 route show dev veth97' )
7460 output
= check_output ( 'ip -6 route show dev veth97' )
7462 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto kernel metric [0-9]* expires' )
7464 print ( '### ip -6 route show dev veth97-peer' )
7465 output
= check_output ( 'ip -6 route show dev veth97-peer' )
7467 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+08::/64 proto ra metric [0-9]* expires' )
7469 print ( '### ip -6 route show dev veth98' )
7470 output
= check_output ( 'ip -6 route show dev veth98' )
7472 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto kernel metric [0-9]* expires' )
7474 print ( '### ip -6 route show dev veth98-peer' )
7475 output
= check_output ( 'ip -6 route show dev veth98-peer' )
7477 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+09::/64 proto ra metric [0-9]* expires' )
7479 print ( '### ip -6 address show dev dummy97 scope global' )
7480 output
= check_output ( 'ip -6 address show dev dummy97 scope global' )
7482 # address in IA_PD (Token=static)
7483 self
. assertRegex ( output
, 'inet6 2001:db8:6464:[0-9a-f]+01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr' )
7484 # address in IA_PD (temporary)
7485 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' )
7487 print ( '### ip -6 route show dev dummy97' )
7488 output
= check_output ( 'ip -6 route show dev dummy97' )
7490 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+01::/64 proto kernel metric [0-9]* expires' )
7492 print ( f
'### ip -d link show dev {tunnel_name} ' )
7493 output
= check_output ( f
'ip -d link show dev {tunnel_name} ' )
7495 self
. assertIn ( 'link/sit 10.100.100.' , output
)
7496 self
. assertIn ( 'local 10.100.100.' , output
)
7497 self
. assertIn ( 'ttl 64' , output
)
7498 self
. assertIn ( '6rd-prefix 2001:db8::/32' , output
)
7499 self
. assertIn ( '6rd-relay_prefix 10.0.0.0/8' , output
)
7501 print ( f
'### ip -6 address show dev {tunnel_name} ' )
7502 output
= check_output ( f
'ip -6 address show dev {tunnel_name} ' )
7504 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' )
7505 self
. assertRegex ( output
, 'inet6 ::10.100.100.[0-9]+/96 scope global' )
7507 print ( f
'### ip -6 route show dev {tunnel_name} ' )
7508 output
= check_output ( f
'ip -6 route show dev {tunnel_name} ' )
7510 self
. assertRegex ( output
, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto kernel metric [0-9]* expires' )
7511 self
. assertRegex ( output
, '::/96 proto kernel metric [0-9]*' )
7513 print ( '### ip -6 route show default' )
7514 output
= check_output ( 'ip -6 route show default' )
7516 self
. assertIn ( 'default' , output
)
7517 self
. assertIn ( f
'via ::10.0.0.1 dev {tunnel_name} ' , output
)
7519 def test_dhcp4_6rd ( self
):
7520 def get_dhcp_6rd_prefix ( link
):
7521 description
= get_link_description ( link
)
7523 self
. assertIn ( 'DHCPv4Client' , description
. keys ())
7524 self
. assertIn ( '6rdPrefix' , description
[ 'DHCPv4Client' ]. keys ())
7526 prefixInfo
= description
[ 'DHCPv4Client' ][ '6rdPrefix' ]
7527 self
. assertIn ( 'Prefix' , prefixInfo
. keys ())
7528 self
. assertIn ( 'PrefixLength' , prefixInfo
. keys ())
7529 self
. assertIn ( 'IPv4MaskLength' , prefixInfo
. keys ())
7530 self
. assertIn ( 'BorderRouters' , prefixInfo
. keys ())
7534 copy_network_unit ( '25-veth.netdev' , '25-dhcp4-6rd-server.network' , '25-dhcp4-6rd-upstream.network' ,
7535 '25-veth-downstream-veth97.netdev' , '25-dhcp-pd-downstream-veth97.network' , '25-dhcp-pd-downstream-veth97-peer.network' ,
7536 '25-veth-downstream-veth98.netdev' , '25-dhcp-pd-downstream-veth98.network' , '25-dhcp-pd-downstream-veth98-peer.network' ,
7537 '11-dummy.netdev' , '25-dhcp-pd-downstream-test1.network' ,
7538 '25-dhcp-pd-downstream-dummy97.network' ,
7539 '12-dummy.netdev' , '25-dhcp-pd-downstream-dummy98.network' ,
7540 '13-dummy.netdev' , '25-dhcp-pd-downstream-dummy99.network' ,
7541 '80-6rd-tunnel.network' )
7544 self
. wait_online ( 'veth-peer:routable' )
7547 # 6rd-prefix: 2001:db8::/32
7548 # br-addresss: 10.0.0.1
7550 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' ,
7551 ipv4_range
= '10.100.100.100,10.100.100.200' ,
7552 ipv4_router
= '10.0.0.1' )
7553 self
. wait_online ( 'veth99:routable' , 'test1:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
7554 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' )
7556 # Check the DBus interface for assigned prefix information
7557 prefixInfo
= get_dhcp_6rd_prefix ( 'veth99' )
7559 self
. assertEqual ( prefixInfo
[ 'Prefix' ], [ 32 , 1 , 13 , 184 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ]) # 2001:db8::
7560 self
. assertEqual ( prefixInfo
[ 'PrefixLength' ], 32 )
7561 self
. assertEqual ( prefixInfo
[ 'IPv4MaskLength' ], 8 )
7562 self
. assertEqual ( prefixInfo
[ 'BorderRouters' ], [[ 10 , 0 , 0 , 1 ]])
7564 # Test case for a downstream which appears later
7565 check_output ( 'ip link add dummy97 type dummy' )
7566 self
. wait_online ( 'dummy97:routable' )
7570 for name
in os
. listdir ( '/sys/class/net/' ):
7571 if name
. startswith ( '6rd-' ):
7575 self
. wait_online ( f
' {tunnel_name} :routable' )
7577 self
. verify_dhcp4_6rd ( tunnel_name
)
7579 # Test case for reconfigure
7580 networkctl_reconfigure ( 'dummy98' , 'dummy99' )
7581 self
. wait_online ( 'dummy98:routable' , 'dummy99:degraded' )
7583 self
. verify_dhcp4_6rd ( tunnel_name
)
7585 print ( 'Wait for the DHCP lease to be renewed/rebind' )
7588 self
. wait_online ( 'veth99:routable' , 'test1:routable' , 'dummy97:routable' , 'dummy98:routable' , 'dummy99:degraded' ,
7589 'veth97:routable' , 'veth97-peer:routable' , 'veth98:routable' , 'veth98-peer:routable' )
7591 self
. verify_dhcp4_6rd ( tunnel_name
)
7593 class NetworkdIPv6PrefixTests ( unittest
. TestCase
, Utilities
):
7601 def test_ipv6_route_prefix ( self
):
7602 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client.network' , '25-ipv6ra-prefix.network' ,
7603 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
7606 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' )
7608 output
= check_output ( 'ip address show dev veth-peer' )
7610 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
7611 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
7612 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
7614 output
= check_output ( 'ip -6 route show dev veth-peer' )
7616 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
7617 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
7618 self
. assertNotIn ( '2001:db8:0:3::/64 proto ra' , output
)
7619 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
7620 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
7621 self
. assertNotIn ( '2001:db2:fff::/64 via ' , output
)
7623 output
= check_output ( 'ip address show dev veth99' )
7625 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
7626 self
. assertIn ( 'inet6 2001:db8:0:2:1a:2b:3c:4d' , output
)
7627 self
. assertIn ( 'inet6 2001:db8:0:2:fa:de:ca:fe' , output
)
7628 self
. assertNotIn ( 'inet6 2001:db8:0:3:' , output
)
7630 output
= resolvectl ( 'dns' , 'veth-peer' )
7632 self
. assertRegex ( output
, '2001:db8:1:1::2' )
7634 output
= resolvectl ( 'domain' , 'veth-peer' )
7636 self
. assertIn ( 'example.com' , output
)
7638 check_json ( networkctl_json ())
7640 output
= networkctl_json ( 'veth-peer' )
7644 pref64
= json
. loads ( output
)[ 'NDisc' ][ 'PREF64' ][ 0 ]
7646 prefix
= socket
. inet_ntop ( socket
. AF_INET6
, bytearray ( pref64
[ 'Prefix' ]))
7647 self
. assertEqual ( prefix
, '64:ff9b::' )
7649 prefix_length
= pref64
[ 'PrefixLength' ]
7650 self
. assertEqual ( prefix_length
, 96 )
7652 def test_ipv6_route_prefix_deny_list ( self
):
7653 copy_network_unit ( '25-veth.netdev' , '25-ipv6ra-prefix-client-deny-list.network' , '25-ipv6ra-prefix.network' ,
7654 '12-dummy.netdev' , '25-ipv6ra-uplink.network' )
7657 self
. wait_online ( 'veth99:routable' , 'veth-peer:routable' , 'dummy98:routable' )
7659 output
= check_output ( 'ip address show dev veth-peer' )
7661 self
. assertIn ( 'inet6 2001:db8:0:1:' , output
)
7662 self
. assertNotIn ( 'inet6 2001:db8:0:2:' , output
)
7664 output
= check_output ( 'ip -6 route show dev veth-peer' )
7666 self
. assertIn ( '2001:db8:0:1::/64 proto ra' , output
)
7667 self
. assertNotIn ( '2001:db8:0:2::/64 proto ra' , output
)
7668 self
. assertIn ( '2001:db0:fff::/64 via ' , output
)
7669 self
. assertNotIn ( '2001:db1:fff::/64 via ' , output
)
7671 output
= check_output ( 'ip address show dev veth99' )
7673 self
. assertNotIn ( 'inet6 2001:db8:0:1:' , output
)
7674 self
. assertIn ( 'inet6 2001:db8:0:2:' , output
)
7676 output
= resolvectl ( 'dns' , 'veth-peer' )
7678 self
. assertRegex ( output
, '2001:db8:1:1::2' )
7680 output
= resolvectl ( 'domain' , 'veth-peer' )
7682 self
. assertIn ( 'example.com' , output
)
7684 class NetworkdMTUTests ( unittest
. TestCase
, Utilities
):
7692 def check_mtu ( self
, mtu
, ipv6_mtu
= None , reset
= True ):
7698 self
. wait_online ( 'dummy98:routable' )
7699 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
7700 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
7702 # test normal restart
7704 self
. wait_online ( 'dummy98:routable' )
7705 self
. check_link_attr ( 'dummy98' , 'mtu' , mtu
)
7706 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , ipv6_mtu
)
7709 self
. reset_check_mtu ( mtu
, ipv6_mtu
)
7711 def reset_check_mtu ( self
, mtu
, ipv6_mtu
= None ):
7712 ''' test setting mtu/ipv6_mtu with interface already up '''
7715 # note - changing the device mtu resets the ipv6 mtu
7716 check_output ( 'ip link set up mtu 1501 dev dummy98' )
7717 check_output ( 'ip link set up mtu 1500 dev dummy98' )
7718 self
. check_link_attr ( 'dummy98' , 'mtu' , '1500' )
7719 self
. check_ipv6_sysctl_attr ( 'dummy98' , 'mtu' , '1500' )
7721 self
. check_mtu ( mtu
, ipv6_mtu
, reset
= False )
7723 def test_mtu_network ( self
):
7724 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' )
7725 self
. check_mtu ( '1600' )
7727 def test_mtu_netdev ( self
):
7728 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network' , copy_dropins
= False )
7729 # note - MTU set by .netdev happens ONLY at device creation!
7730 self
. check_mtu ( '1600' , reset
= False )
7732 def test_mtu_link ( self
):
7733 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network' , copy_dropins
= False )
7734 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
7735 self
. check_mtu ( '1600' , reset
= False )
7737 def test_ipv6_mtu ( self
):
7738 ''' set ipv6 mtu without setting device mtu '''
7739 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1400.conf' )
7740 self
. check_mtu ( '1500' , '1400' )
7742 def test_ipv6_mtu_toolarge ( self
):
7743 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
7744 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
7745 self
. check_mtu ( '1500' , '1500' )
7747 def test_mtu_network_ipv6_mtu ( self
):
7748 ''' set ipv6 mtu and set device mtu via network file '''
7749 copy_network_unit ( '12-dummy.netdev' , '12-dummy.network.d/mtu.conf' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
7750 self
. check_mtu ( '1600' , '1550' )
7752 def test_mtu_netdev_ipv6_mtu ( self
):
7753 ''' set ipv6 mtu and set device mtu via netdev file '''
7754 copy_network_unit ( '12-dummy-mtu.netdev' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
7755 self
. check_mtu ( '1600' , '1550' , reset
= False )
7757 def test_mtu_link_ipv6_mtu ( self
):
7758 ''' set ipv6 mtu and set device mtu via link file '''
7759 copy_network_unit ( '12-dummy.netdev' , '12-dummy-mtu.link' , '12-dummy.network.d/ipv6-mtu-1550.conf' )
7760 self
. check_mtu ( '1600' , '1550' , reset
= False )
7763 if __name__
== '__main__' :
7764 parser
= argparse
. ArgumentParser ()
7765 parser
. add_argument ( '--build-dir' , help = 'Path to build dir' , dest
= 'build_dir' )
7766 parser
. add_argument ( '--source-dir' , help = 'Path to source dir/git tree' , dest
= 'source_dir' )
7767 parser
. add_argument ( '--valgrind' , help = 'Enable valgrind' , dest
= 'use_valgrind' , type = bool , nargs
= '?' , const
= True , default
= use_valgrind
)
7768 parser
. add_argument ( '--debug' , help = 'Generate debugging logs' , dest
= 'enable_debug' , type = bool , nargs
= '?' , const
= True , default
= enable_debug
)
7769 parser
. add_argument ( '--asan-options' , help = 'ASAN options' , dest
= 'asan_options' )
7770 parser
. add_argument ( '--lsan-options' , help = 'LSAN options' , dest
= 'lsan_options' )
7771 parser
. add_argument ( '--ubsan-options' , help = 'UBSAN options' , dest
= 'ubsan_options' )
7772 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
)
7773 parser
. add_argument ( '--no-journal' , help = 'Do not show journal of systemd-networkd on stop' , dest
= 'show_journal' , action
= 'store_false' )
7774 ns
, unknown_args
= parser
. parse_known_args ( namespace
= unittest
)
7777 networkd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd' )
7778 resolved_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-resolved' )
7779 timesyncd_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-timesyncd' )
7780 wait_online_bin
= os
. path
. join ( ns
. build_dir
, 'systemd-networkd-wait-online' )
7781 networkctl_bin
= os
. path
. join ( ns
. build_dir
, 'networkctl' )
7782 resolvectl_bin
= os
. path
. join ( ns
. build_dir
, 'resolvectl' )
7783 timedatectl_bin
= os
. path
. join ( ns
. build_dir
, 'timedatectl' )
7784 udevadm_bin
= os
. path
. join ( ns
. build_dir
, 'udevadm' )
7785 build_dir
= ns
. build_dir
7788 source_dir
= ns
. source_dir
7789 assert os
. path
. exists ( os
. path
. join ( source_dir
, "meson_options.txt" )), f
" {source_dir} doesn't appear to be a systemd source tree."
7790 elif os
. path
. exists ( os
. path
. normpath ( os
. path
. join ( os
. path
. dirname ( os
. path
. abspath ( __file__
)), "../../meson_options.txt" ))):
7791 source_dir
= os
. path
. normpath ( os
. path
. join ( os
. path
. dirname ( os
. path
. abspath ( __file__
)), "../../" ))
7795 use_valgrind
= ns
. use_valgrind
7796 enable_debug
= ns
. enable_debug
7797 asan_options
= ns
. asan_options
7798 lsan_options
= ns
. lsan_options
7799 ubsan_options
= ns
. ubsan_options
7800 with_coverage
= ns
. with_coverage
7801 show_journal
= ns
. show_journal
7804 # Do not forget the trailing space.
7805 valgrind_cmd
= 'valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all '
7807 networkctl_cmd
= valgrind_cmd
. split () + [ networkctl_bin
]
7808 resolvectl_cmd
= valgrind_cmd
. split () + [ resolvectl_bin
]
7809 timedatectl_cmd
= valgrind_cmd
. split () + [ timedatectl_bin
]
7810 udevadm_cmd
= valgrind_cmd
. split () + [ udevadm_bin
]
7811 wait_online_cmd
= valgrind_cmd
. split () + [ wait_online_bin
]
7814 test_ndisc_send
= os
. path
. normpath ( os
. path
. join ( build_dir
, 'test-ndisc-send' ))
7816 test_ndisc_send
= '/usr/lib/tests/test-ndisc-send'
7819 env
. update ({ 'ASAN_OPTIONS' : asan_options
})
7821 env
. update ({ 'LSAN_OPTIONS' : lsan_options
})
7823 env
. update ({ 'UBSAN_OPTIONS' : ubsan_options
})
7825 env
. update ({ 'SYSTEMD_MEMPOOL' : '0' })
7827 wait_online_env
= env
. copy ()
7829 wait_online_env
. update ({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
7836 *([ "-k" , match
] if ( match
:= os
. getenv ( "TEST_MATCH_TESTCASE" )) else [])