2 # SPDX-License-Identifier: LGPL-2.1+
3 # systemd-networkd tests
14 from shutil
import copytree
16 network_unit_file_path
='/run/systemd/network'
17 networkd_runtime_directory
='/run/systemd/netif'
18 networkd_ci_path
='/run/networkd-ci'
19 network_sysctl_ipv6_path
='/proc/sys/net/ipv6/conf'
20 network_sysctl_ipv4_path
='/proc/sys/net/ipv4/conf'
22 dnsmasq_pid_file
='/run/networkd-ci/test-test-dnsmasq.pid'
23 dnsmasq_log_file
='/run/networkd-ci/test-dnsmasq-log-file'
25 systemd_lib_paths
=['/usr/lib/systemd', '/lib/systemd']
26 which_paths
=':'.join(systemd_lib_paths
+ os
.getenv('PATH', os
.defpath
).lstrip(':').split(':'))
28 networkd_bin
=shutil
.which('systemd-networkd', path
=which_paths
)
29 resolved_bin
=shutil
.which('systemd-resolved', path
=which_paths
)
30 udevd_bin
=shutil
.which('systemd-udevd', path
=which_paths
)
31 wait_online_bin
=shutil
.which('systemd-networkd-wait-online', path
=which_paths
)
32 networkctl_bin
=shutil
.which('networkctl', path
=which_paths
)
33 resolvectl_bin
=shutil
.which('resolvectl', path
=which_paths
)
34 timedatectl_bin
=shutil
.which('timedatectl', path
=which_paths
)
45 def check_output(*command
, **kwargs
):
46 # This replaces both check_output and check_call (output can be ignored)
47 command
= command
[0].split() + list(command
[1:])
48 return subprocess
.check_output(command
, universal_newlines
=True, **kwargs
).rstrip()
50 def call(*command
, **kwargs
):
51 command
= command
[0].split() + list(command
[1:])
52 return subprocess
.call(command
, universal_newlines
=True, **kwargs
)
54 def run(*command
, **kwargs
):
55 command
= command
[0].split() + list(command
[1:])
56 return subprocess
.run(command
, universal_newlines
=True, **kwargs
)
58 def is_module_available(module_name
):
59 lsmod_output
= check_output('lsmod')
60 module_re
= re
.compile(rf
'^{re.escape(module_name)}\b', re
.MULTILINE
)
61 return module_re
.search(lsmod_output
) or not call('modprobe', module_name
, stderr
=subprocess
.DEVNULL
)
63 def expectedFailureIfModuleIsNotAvailable(module_name
):
65 if not is_module_available(module_name
):
66 return unittest
.expectedFailure(func
)
71 def expectedFailureIfERSPANModuleIsNotAvailable():
73 rc
= call('ip link add dev erspan99 type erspan seq key 30 local 192.168.1.4 remote 192.168.1.1 erspan_ver 1 erspan 123', stderr
=subprocess
.DEVNULL
)
75 call('ip link del erspan99')
78 return unittest
.expectedFailure(func
)
82 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable():
84 rc
= call('ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7', stderr
=subprocess
.DEVNULL
)
86 call('ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
89 return unittest
.expectedFailure(func
)
93 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
95 rc
= call('ip rule add not from 192.168.100.19 ipproto tcp table 7', stderr
=subprocess
.DEVNULL
)
97 call('ip rule del not from 192.168.100.19 ipproto tcp table 7')
100 return unittest
.expectedFailure(func
)
104 def expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable():
107 rc
= call('ip rule add from 192.168.100.19 table 7 uidrange 200-300', stderr
=subprocess
.DEVNULL
)
109 ret
= run('ip rule list from 192.168.100.19 table 7', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
110 if ret
.returncode
== 0 and 'uidrange 200-300' in ret
.stdout
.rstrip():
112 call('ip rule del from 192.168.100.19 table 7 uidrange 200-300')
117 return unittest
.expectedFailure(func
)
121 def expectedFailureIfLinkFileFieldIsNotSet():
124 rc
= call('ip link add name dummy99 type dummy', stderr
=subprocess
.DEVNULL
)
126 ret
= run('udevadm info -w10s /sys/class/net/dummy99', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
127 if ret
.returncode
== 0 and 'E: ID_NET_LINK_FILE=' in ret
.stdout
.rstrip():
129 call('ip link del dummy99')
134 return unittest
.expectedFailure(func
)
138 def expectedFailureIfNexthopIsNotAvailable():
140 rc
= call('ip nexthop list', stderr
=subprocess
.DEVNULL
)
144 return unittest
.expectedFailure(func
)
148 def expectedFailureIfAlternativeNameIsNotAvailable():
150 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
151 rc
= call('ip link prop add dev dummy98 altname hogehogehogehogehoge', stderr
=subprocess
.DEVNULL
)
152 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
156 return unittest
.expectedFailure(func
)
160 def expectedFailureIfCAKEIsNotAvailable():
162 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
163 rc
= call('tc qdisc add dev dummy98 parent root cake', stderr
=subprocess
.DEVNULL
)
164 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
168 return unittest
.expectedFailure(func
)
175 os
.makedirs(network_unit_file_path
, exist_ok
=True)
176 os
.makedirs(networkd_ci_path
, exist_ok
=True)
178 shutil
.rmtree(networkd_ci_path
)
179 copytree(os
.path
.join(os
.path
.dirname(os
.path
.abspath(__file__
)), 'conf'), networkd_ci_path
)
181 for u
in ['systemd-networkd.socket', 'systemd-networkd.service', 'systemd-resolved.service',
182 'systemd-udevd-kernel.socket', 'systemd-udevd-control.socket', 'systemd-udevd.service',
183 'firewalld.service']:
184 if call(f
'systemctl is-active --quiet {u}') == 0:
185 check_output(f
'systemctl stop {u}')
186 running_units
.append(u
)
190 'StartLimitIntervalSec=0',
197 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin
,
201 drop_in
+= ['ExecStart=!!' + networkd_bin
]
203 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
205 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
207 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
209 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
210 if asan_options
or lsan_options
or ubsan_options
:
211 drop_in
+= ['SystemCallFilter=']
212 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
213 drop_in
+= ['MemoryDenyWriteExecute=no']
215 os
.makedirs('/run/systemd/system/systemd-networkd.service.d', exist_ok
=True)
216 with
open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode
='w') as f
:
217 f
.write('\n'.join(drop_in
))
225 drop_in
+= ['ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + resolved_bin
]
227 drop_in
+= ['ExecStart=!!' + resolved_bin
]
229 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
231 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
233 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
235 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
236 if asan_options
or lsan_options
or ubsan_options
:
237 drop_in
+= ['SystemCallFilter=']
238 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
239 drop_in
+= ['MemoryDenyWriteExecute=no']
241 os
.makedirs('/run/systemd/system/systemd-resolved.service.d', exist_ok
=True)
242 with
open('/run/systemd/system/systemd-resolved.service.d/00-override.conf', mode
='w') as f
:
243 f
.write('\n'.join(drop_in
))
248 'ExecStart=!!' + udevd_bin
,
251 os
.makedirs('/run/systemd/system/systemd-udevd.service.d', exist_ok
=True)
252 with
open('/run/systemd/system/systemd-udevd.service.d/00-override.conf', mode
='w') as f
:
253 f
.write('\n'.join(drop_in
))
255 check_output('systemctl daemon-reload')
256 print(check_output('systemctl cat systemd-networkd.service'))
257 print(check_output('systemctl cat systemd-resolved.service'))
258 print(check_output('systemctl cat systemd-udevd.service'))
259 check_output('systemctl restart systemd-resolved')
260 check_output('systemctl restart systemd-udevd')
262 def tearDownModule():
265 shutil
.rmtree(networkd_ci_path
)
267 for u
in ['systemd-networkd.service', 'systemd-resolved.service']:
268 check_output(f
'systemctl stop {u}')
270 shutil
.rmtree('/run/systemd/system/systemd-networkd.service.d')
271 shutil
.rmtree('/run/systemd/system/systemd-resolved.service.d')
272 shutil
.rmtree('/run/systemd/system/systemd-udevd.service.d')
273 check_output('systemctl daemon-reload')
274 check_output('systemctl restart systemd-udevd.service')
276 for u
in running_units
:
277 check_output(f
'systemctl start {u}')
279 def read_link_attr(*args
):
280 with
open(os
.path
.join('/sys/class/net/', *args
)) as f
:
281 return f
.readline().strip()
283 def read_bridge_port_attr(bridge
, link
, attribute
):
284 path_bridge
= os
.path
.join('/sys/devices/virtual/net', bridge
)
285 path_port
= 'lower_' + link
+ '/brport'
286 path
= os
.path
.join(path_bridge
, path_port
)
288 with
open(os
.path
.join(path
, attribute
)) as f
:
289 return f
.readline().strip()
291 def link_exists(link
):
292 return os
.path
.exists(os
.path
.join('/sys/class/net', link
))
294 def remove_links(links
):
296 if link_exists(link
):
297 call('ip link del dev', link
)
300 def remove_fou_ports(ports
):
302 call('ip fou del port', port
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
304 def remove_routing_policy_rule_tables(tables
):
308 rc
= call('ip rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
310 def remove_routes(routes
):
311 for route_type
, addr
in routes
:
312 call('ip route del', route_type
, addr
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
314 def remove_l2tp_tunnels(tunnel_ids
):
315 output
= check_output('ip l2tp show tunnel')
316 for tid
in tunnel_ids
:
317 words
='Tunnel ' + tid
+ ', encap'
319 call('ip l2tp del tunnel tid', tid
)
322 def read_ipv6_sysctl_attr(link
, attribute
):
323 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, link
), attribute
)) as f
:
324 return f
.readline().strip()
326 def read_ipv4_sysctl_attr(link
, attribute
):
327 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv4_path
, link
), attribute
)) as f
:
328 return f
.readline().strip()
330 def copy_unit_to_networkd_unit_path(*units
, dropins
=True):
331 """Copy networkd unit files into the testbed.
333 Any networkd unit file type can be specified, as well as drop-in files.
335 By default, all drop-ins for a specified unit file are copied in;
336 to avoid that specify dropins=False.
338 When a drop-in file is specified, its unit file is also copied in automatically.
342 if dropins
and os
.path
.exists(os
.path
.join(networkd_ci_path
, unit
+ '.d')):
343 copytree(os
.path
.join(networkd_ci_path
, unit
+ '.d'), os
.path
.join(network_unit_file_path
, unit
+ '.d'))
344 if unit
.endswith('.conf'):
346 dropindir
= os
.path
.join(network_unit_file_path
, os
.path
.dirname(dropin
))
347 os
.makedirs(dropindir
, exist_ok
=True)
348 shutil
.copy(os
.path
.join(networkd_ci_path
, dropin
), dropindir
)
349 unit
= os
.path
.dirname(dropin
).rstrip('.d')
350 shutil
.copy(os
.path
.join(networkd_ci_path
, unit
), network_unit_file_path
)
352 def remove_unit_from_networkd_path(units
):
353 """Remove previously copied unit files from the testbed.
355 Drop-ins will be removed automatically.
358 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
))):
359 os
.remove(os
.path
.join(network_unit_file_path
, unit
))
360 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
+ '.d'))):
361 shutil
.rmtree(os
.path
.join(network_unit_file_path
, unit
+ '.d'))
363 def start_dnsmasq(additional_options
='', ipv4_range
='192.168.5.10,192.168.5.200', ipv6_range
='2600::10,2600::20', lease_time
='1h'):
364 dnsmasq_command
= f
'dnsmasq -8 /var/run/networkd-ci/test-dnsmasq-log-file --log-queries=extra --log-dhcp --pid-file=/var/run/networkd-ci/test-test-dnsmasq.pid --conf-file=/dev/null --interface=veth-peer --enable-ra --dhcp-range={ipv6_range},{lease_time} --dhcp-range={ipv4_range},{lease_time} -R --dhcp-leasefile=/var/run/networkd-ci/lease --dhcp-option=26,1492 --dhcp-option=option:router,192.168.5.1 --dhcp-option=33,192.168.5.4,192.168.5.5 --port=0 ' + additional_options
365 check_output(dnsmasq_command
)
367 def stop_dnsmasq(pid_file
):
368 if os
.path
.exists(pid_file
):
369 with
open(pid_file
, 'r') as f
:
370 pid
= f
.read().rstrip(' \t\r\n\0')
371 os
.kill(int(pid
), signal
.SIGTERM
)
375 def search_words_in_dnsmasq_log(words
, show_all
=False):
376 if os
.path
.exists(dnsmasq_log_file
):
377 with
open (dnsmasq_log_file
) as in_file
:
378 contents
= in_file
.read()
381 for line
in contents
.splitlines():
384 print("%s, %s" % (words
, line
))
388 def remove_lease_file():
389 if os
.path
.exists(os
.path
.join(networkd_ci_path
, 'lease')):
390 os
.remove(os
.path
.join(networkd_ci_path
, 'lease'))
392 def remove_log_file():
393 if os
.path
.exists(dnsmasq_log_file
):
394 os
.remove(dnsmasq_log_file
)
396 def remove_networkd_state_files():
397 if os
.path
.exists(os
.path
.join(networkd_runtime_directory
, 'state')):
398 os
.remove(os
.path
.join(networkd_runtime_directory
, 'state'))
400 def stop_networkd(show_logs
=True, remove_state_files
=True):
402 invocation_id
= check_output('systemctl show systemd-networkd -p InvocationID --value')
403 check_output('systemctl stop systemd-networkd')
405 print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
))
406 if remove_state_files
:
407 remove_networkd_state_files()
409 def start_networkd(sleep_sec
=0):
410 check_output('systemctl start systemd-networkd')
412 time
.sleep(sleep_sec
)
414 def restart_networkd(sleep_sec
=0, show_logs
=True, remove_state_files
=True):
415 stop_networkd(show_logs
, remove_state_files
)
416 start_networkd(sleep_sec
)
420 def check_link_exists(self
, link
):
421 self
.assertTrue(link_exists(link
))
423 def wait_operstate(self
, link
, operstate
='degraded', setup_state
='configured', setup_timeout
=5, fail_assert
=True):
424 """Wait for the link to reach the specified operstate and/or setup state.
426 Specify None or '' for either operstate or setup_state to ignore that state.
427 This will recheck until the state conditions are met or the timeout expires.
429 If the link successfully matches the requested state, this returns True.
430 If this times out waiting for the link to match, the behavior depends on the
431 'fail_assert' parameter; if True, this causes a test assertion failure,
432 otherwise this returns False. The default is to cause assertion failure.
434 Note that this function matches on *exactly* the given operstate and setup_state.
435 To wait for a link to reach *or exceed* a given operstate, use wait_online().
442 for secs
in range(setup_timeout
+ 1):
443 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
, env
=env
)
445 if re
.search(rf
'(?m)^\s*State:\s+{operstate}\s+\({setup_state}\)\s*$', output
):
447 # don't bother sleeping if time is up
448 if secs
< setup_timeout
:
451 self
.fail(f
'Timed out waiting for {link} to reach state {operstate}/{setup_state}')
454 def wait_online(self
, links_with_operstate
, timeout
='20s', bool_any
=False, setup_state
='configured', setup_timeout
=5):
455 """Wait for the link(s) to reach the specified operstate and/or setup state.
457 This is similar to wait_operstate() but can be used for multiple links,
458 and it also calls systemd-networkd-wait-online to wait for the given operstate.
459 The operstate should be specified in the link name, like 'eth0:degraded'.
460 If just a link name is provided, wait-online's default operstate to wait for is degraded.
462 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
463 'setup_timeout' controls the per-link timeout waiting for the setup_state.
465 Set 'bool_any' to True to wait for any (instead of all) of the given links.
466 If this is set, no setup_state checks are done.
468 Note that this function waits for the link(s) to reach *or exceed* the given operstate.
469 However, the setup_state, if specified, must be matched *exactly*.
471 This returns if the link(s) reached the requested operstate/setup_state; otherwise it
472 raises CalledProcessError or fails test assertion.
474 args
= wait_online_cmd
+ [f
'--timeout={timeout}'] + [f
'--interface={link}' for link
in links_with_operstate
]
478 check_output(*args
, env
=env
)
479 except subprocess
.CalledProcessError
:
480 for link
in links_with_operstate
:
481 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
.split(':')[0], env
=env
)
484 if not bool_any
and setup_state
:
485 for link
in links_with_operstate
:
486 self
.wait_operstate(link
.split(':')[0], None, setup_state
, setup_timeout
)
488 def wait_address(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
489 for i
in range(timeout_sec
):
492 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
493 if re
.search(address_regex
, output
):
496 self
.assertRegex(output
, address_regex
)
498 class NetworkctlTests(unittest
.TestCase
, Utilities
):
508 '11-dummy-mtu.netdev',
512 '25-address-static.network',
514 'netdev-link-local-addressing-yes.network',
518 remove_links(self
.links
)
519 stop_networkd(show_logs
=False)
522 remove_links(self
.links
)
523 remove_unit_from_networkd_path(self
.units
)
524 stop_networkd(show_logs
=True)
526 @expectedFailureIfAlternativeNameIsNotAvailable()
527 def test_altname(self
):
528 copy_unit_to_networkd_unit_path('netdev-link-local-addressing-yes.network', '12-dummy.netdev', '12-dummy.link')
529 check_output('udevadm control --reload')
531 self
.wait_online(['dummy98:degraded'])
533 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
534 self
.assertRegex(output
, 'hogehogehogehogehogehoge')
536 def test_reconfigure(self
):
537 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
539 self
.wait_online(['dummy98:routable'])
541 output
= check_output('ip -4 address show dev dummy98')
543 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
544 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
545 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
547 check_output('ip address del 10.1.2.3/16 dev dummy98')
548 check_output('ip address del 10.1.2.4/16 dev dummy98')
549 check_output('ip address del 10.2.2.4/16 dev dummy98')
551 check_output(*networkctl_cmd
, 'reconfigure', 'dummy98', env
=env
)
552 self
.wait_online(['dummy98:routable'])
554 output
= check_output('ip -4 address show dev dummy98')
556 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
557 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
558 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
560 def test_reload(self
):
563 copy_unit_to_networkd_unit_path('11-dummy.netdev')
564 check_output(*networkctl_cmd
, 'reload', env
=env
)
565 self
.wait_operstate('test1', 'off', setup_state
='unmanaged')
567 copy_unit_to_networkd_unit_path('11-dummy.network')
568 check_output(*networkctl_cmd
, 'reload', env
=env
)
569 self
.wait_online(['test1:degraded'])
571 remove_unit_from_networkd_path(['11-dummy.network'])
572 check_output(*networkctl_cmd
, 'reload', env
=env
)
573 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
575 remove_unit_from_networkd_path(['11-dummy.netdev'])
576 check_output(*networkctl_cmd
, 'reload', env
=env
)
577 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
579 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
580 check_output(*networkctl_cmd
, 'reload', env
=env
)
581 self
.wait_operstate('test1', 'degraded')
584 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
587 self
.wait_online(['test1:degraded'])
589 output
= check_output(*networkctl_cmd
, 'list', env
=env
)
590 self
.assertRegex(output
, '1 lo ')
591 self
.assertRegex(output
, 'test1')
593 output
= check_output(*networkctl_cmd
, 'list', 'test1', env
=env
)
594 self
.assertNotRegex(output
, '1 lo ')
595 self
.assertRegex(output
, 'test1')
597 output
= check_output(*networkctl_cmd
, 'list', 'te*', env
=env
)
598 self
.assertNotRegex(output
, '1 lo ')
599 self
.assertRegex(output
, 'test1')
601 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'te*', env
=env
)
602 self
.assertNotRegex(output
, '1: lo ')
603 self
.assertRegex(output
, 'test1')
605 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'tes[a-z][0-9]', env
=env
)
606 self
.assertNotRegex(output
, '1: lo ')
607 self
.assertRegex(output
, 'test1')
610 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
613 self
.wait_online(['test1:degraded'])
615 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
616 self
.assertRegex(output
, 'MTU: 1600')
619 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
621 self
.wait_online(['test1:degraded'])
623 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
625 self
.assertRegex(output
, 'Type: ether')
627 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
629 self
.assertRegex(output
, 'Type: loopback')
631 @expectedFailureIfLinkFileFieldIsNotSet()
632 def test_udev_link_file(self
):
633 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
635 self
.wait_online(['test1:degraded'])
637 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
639 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
640 self
.assertRegex(output
, r
'Network File: /run/systemd/network/11-dummy.network')
642 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
644 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
645 self
.assertRegex(output
, r
'Network File: n/a')
647 def test_delete_links(self
):
648 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
649 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
652 self
.wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
654 check_output(*networkctl_cmd
, 'delete', 'test1', 'veth99', env
=env
)
655 self
.assertFalse(link_exists('test1'))
656 self
.assertFalse(link_exists('veth99'))
657 self
.assertFalse(link_exists('veth-peer'))
659 class NetworkdNetDevTests(unittest
.TestCase
, Utilities
):
661 links_remove_earlier
= [
726 '10-dropin-test.netdev',
730 '13-not-match-udev-property.network',
731 '14-match-udev-property.network',
732 '15-name-conflict-test.netdev',
735 '21-vlan-test1.network',
738 '25-6rd-tunnel.netdev',
740 '25-bond-balanced-tlb.netdev',
742 '25-bridge-configure-without-carrier.network',
744 '25-erspan-tunnel-local-any.netdev',
745 '25-erspan-tunnel.netdev',
746 '25-fou-gretap.netdev',
748 '25-fou-ipip.netdev',
749 '25-fou-ipproto-gre.netdev',
750 '25-fou-ipproto-ipip.netdev',
753 '25-gretap-tunnel-local-any.netdev',
754 '25-gretap-tunnel.netdev',
755 '25-gre-tunnel-any-any.netdev',
756 '25-gre-tunnel-local-any.netdev',
757 '25-gre-tunnel-remote-any.netdev',
758 '25-gre-tunnel.netdev',
760 '25-ip6gretap-tunnel-local-any.netdev',
761 '25-ip6gretap-tunnel.netdev',
762 '25-ip6gre-tunnel-any-any.netdev',
763 '25-ip6gre-tunnel-local-any.netdev',
764 '25-ip6gre-tunnel-remote-any.netdev',
765 '25-ip6gre-tunnel.netdev',
766 '25-ip6tnl-tunnel-any-any.netdev',
767 '25-ip6tnl-tunnel-local-any.netdev',
768 '25-ip6tnl-tunnel-remote-any.netdev',
769 '25-ip6tnl-tunnel.netdev',
770 '25-ipip-tunnel-any-any.netdev',
771 '25-ipip-tunnel-independent.netdev',
772 '25-ipip-tunnel-independent-loopback.netdev',
773 '25-ipip-tunnel-local-any.netdev',
774 '25-ipip-tunnel-remote-any.netdev',
775 '25-ipip-tunnel.netdev',
778 '25-isatap-tunnel.netdev',
783 '25-sit-tunnel-any-any.netdev',
784 '25-sit-tunnel-local-any.netdev',
785 '25-sit-tunnel-remote-any.netdev',
786 '25-sit-tunnel.netdev',
789 '25-tunnel-local-any.network',
790 '25-tunnel-remote-any.network',
795 '25-vti6-tunnel-any-any.netdev',
796 '25-vti6-tunnel-local-any.netdev',
797 '25-vti6-tunnel-remote-any.netdev',
798 '25-vti6-tunnel.netdev',
799 '25-vti-tunnel-any-any.netdev',
800 '25-vti-tunnel-local-any.netdev',
801 '25-vti-tunnel-remote-any.netdev',
802 '25-vti-tunnel.netdev',
805 '25-wireguard-23-peers.netdev',
806 '25-wireguard-23-peers.network',
807 '25-wireguard-preshared-key.txt',
808 '25-wireguard-private-key.txt',
809 '25-wireguard.netdev',
810 '25-wireguard.network',
812 '25-xfrm-independent.netdev',
828 'netdev-link-local-addressing-yes.network',
832 'vxlan-test1.network',
842 remove_fou_ports(self
.fou_ports
)
843 remove_links(self
.links_remove_earlier
)
844 remove_links(self
.links
)
845 stop_networkd(show_logs
=False)
848 remove_fou_ports(self
.fou_ports
)
849 remove_links(self
.links_remove_earlier
)
850 remove_links(self
.links
)
851 remove_unit_from_networkd_path(self
.units
)
852 stop_networkd(show_logs
=True)
854 def test_dropin_and_name_conflict(self
):
855 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
858 self
.wait_online(['dropin-test:off'], setup_state
='unmanaged')
860 output
= check_output('ip link show dropin-test')
862 self
.assertRegex(output
, '00:50:56:c0:00:28')
864 def test_match_udev_property(self
):
865 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
867 self
.wait_online(['dummy98:routable'])
869 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
871 self
.assertRegex(output
, 'Network File: /run/systemd/network/14-match-udev-property')
873 def test_wait_online_any(self
):
874 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
877 self
.wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
879 self
.wait_operstate('bridge99', '(off|no-carrier)', setup_state
='configuring')
880 self
.wait_operstate('test1', 'degraded')
882 def test_bridge(self
):
883 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
886 self
.wait_online(['bridge99:no-carrier'])
888 tick
= os
.sysconf('SC_CLK_TCK')
889 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
890 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
891 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'forward_delay')) / tick
))
892 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'ageing_time')) / tick
))
893 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge', 'priority')))
894 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_querier')))
895 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_snooping')))
896 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'stp_state')))
897 self
.assertEqual(3, int(read_link_attr('bridge99', 'bridge', 'multicast_igmp_version')))
899 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
901 self
.assertRegex(output
, 'Priority: 9')
902 self
.assertRegex(output
, 'STP: yes')
903 self
.assertRegex(output
, 'Multicast IGMP Version: 3')
906 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
909 self
.wait_online(['bond99:off', 'bond98:off'], setup_state
='unmanaged')
911 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
912 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
913 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
914 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
915 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
916 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
917 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
918 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
919 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
920 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
921 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
923 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
924 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
927 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
928 '21-vlan.network', '21-vlan-test1.network')
931 self
.wait_online(['test1:degraded', 'vlan99:routable'])
933 output
= check_output('ip -d link show test1')
935 self
.assertRegex(output
, ' mtu 2000 ')
937 output
= check_output('ip -d link show vlan99')
939 self
.assertRegex(output
, ' mtu 2000 ')
940 self
.assertRegex(output
, 'REORDER_HDR')
941 self
.assertRegex(output
, 'LOOSE_BINDING')
942 self
.assertRegex(output
, 'GVRP')
943 self
.assertRegex(output
, 'MVRP')
944 self
.assertRegex(output
, ' id 99 ')
946 output
= check_output('ip -4 address show dev test1')
948 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
949 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
951 output
= check_output('ip -4 address show dev vlan99')
953 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
955 def test_macvtap(self
):
956 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
957 with self
.subTest(mode
=mode
):
958 if mode
!= 'private':
960 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
961 '11-dummy.netdev', 'macvtap.network')
962 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
963 f
.write('[MACVTAP]\nMode=' + mode
)
966 self
.wait_online(['macvtap99:degraded', 'test1:degraded'])
968 output
= check_output('ip -d link show macvtap99')
970 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
972 def test_macvlan(self
):
973 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
974 with self
.subTest(mode
=mode
):
975 if mode
!= 'private':
977 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
978 '11-dummy.netdev', 'macvlan.network')
979 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
980 f
.write('[MACVLAN]\nMode=' + mode
)
983 self
.wait_online(['macvlan99:degraded', 'test1:degraded'])
985 output
= check_output('ip -d link show test1')
987 self
.assertRegex(output
, ' mtu 2000 ')
989 output
= check_output('ip -d link show macvlan99')
991 self
.assertRegex(output
, ' mtu 2000 ')
992 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
994 @expectedFailureIfModuleIsNotAvailable('ipvlan')
995 def test_ipvlan(self
):
996 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
997 with self
.subTest(mode
=mode
, flag
=flag
):
1000 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
1001 '11-dummy.netdev', 'ipvlan.network')
1002 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
1003 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
1006 self
.wait_online(['ipvlan99:degraded', 'test1:degraded'])
1008 output
= check_output('ip -d link show ipvlan99')
1010 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
1012 @expectedFailureIfModuleIsNotAvailable('ipvtap')
1013 def test_ipvtap(self
):
1014 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1015 with self
.subTest(mode
=mode
, flag
=flag
):
1018 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
1019 '11-dummy.netdev', 'ipvtap.network')
1020 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
1021 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
1024 self
.wait_online(['ipvtap99:degraded', 'test1:degraded'])
1026 output
= check_output('ip -d link show ipvtap99')
1028 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
1030 def test_veth(self
):
1031 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
1034 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
1036 output
= check_output('ip -d link show veth99')
1038 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
1039 output
= check_output('ip -d link show veth-peer')
1041 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
1044 copy_unit_to_networkd_unit_path('25-tun.netdev')
1047 self
.wait_online(['tun99:off'], setup_state
='unmanaged')
1049 output
= check_output('ip -d link show tun99')
1051 # Old ip command does not support IFF_ flags
1052 self
.assertRegex(output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
1055 copy_unit_to_networkd_unit_path('25-tap.netdev')
1058 self
.wait_online(['tap99:off'], setup_state
='unmanaged')
1060 output
= check_output('ip -d link show tap99')
1062 # Old ip command does not support IFF_ flags
1063 self
.assertRegex(output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
1065 @expectedFailureIfModuleIsNotAvailable('vrf')
1067 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
1070 self
.wait_online(['vrf99:carrier'])
1072 @expectedFailureIfModuleIsNotAvailable('vcan')
1073 def test_vcan(self
):
1074 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
1077 self
.wait_online(['vcan99:carrier'])
1079 @expectedFailureIfModuleIsNotAvailable('vxcan')
1080 def test_vxcan(self
):
1081 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
1084 self
.wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
1086 @expectedFailureIfModuleIsNotAvailable('wireguard')
1087 def test_wireguard(self
):
1088 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
1089 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
1090 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt')
1092 self
.wait_online(['wg99:carrier', 'wg98:routable'])
1094 if shutil
.which('wg'):
1097 output
= check_output('wg show wg99 listen-port')
1098 self
.assertRegex(output
, '51820')
1099 output
= check_output('wg show wg99 fwmark')
1100 self
.assertRegex(output
, '0x4d2')
1101 output
= check_output('wg show wg99 allowed-ips')
1102 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
1103 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
1104 output
= check_output('wg show wg99 persistent-keepalive')
1105 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
1106 output
= check_output('wg show wg99 endpoints')
1107 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
1108 output
= check_output('wg show wg99 private-key')
1109 self
.assertRegex(output
, r
'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
1110 output
= check_output('wg show wg99 preshared-keys')
1111 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
1112 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
1114 output
= check_output('wg show wg98 private-key')
1115 self
.assertRegex(output
, r
'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
1117 def test_geneve(self
):
1118 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
1121 self
.wait_online(['geneve99:degraded'])
1123 output
= check_output('ip -d link show geneve99')
1125 self
.assertRegex(output
, '192.168.22.1')
1126 self
.assertRegex(output
, '6082')
1127 self
.assertRegex(output
, 'udpcsum')
1128 self
.assertRegex(output
, 'udp6zerocsumrx')
1130 def test_ipip_tunnel(self
):
1131 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
1132 '25-ipip-tunnel.netdev', '25-tunnel.network',
1133 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1134 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1135 '25-ipip-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1137 self
.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'ipiptun96:routable', 'dummy98:degraded'])
1139 output
= check_output('ip -d link show ipiptun99')
1141 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98')
1142 output
= check_output('ip -d link show ipiptun98')
1144 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98')
1145 output
= check_output('ip -d link show ipiptun97')
1147 self
.assertRegex(output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98')
1148 output
= check_output('ip -d link show ipiptun96')
1150 self
.assertRegex(output
, 'ipip (ipip )?remote any local any dev dummy98')
1152 def test_gre_tunnel(self
):
1153 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
1154 '25-gre-tunnel.netdev', '25-tunnel.network',
1155 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1156 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1157 '25-gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1159 self
.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'gretun96:routable', 'dummy98:degraded'])
1161 output
= check_output('ip -d link show gretun99')
1163 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1164 self
.assertRegex(output
, 'ikey 1.2.3.103')
1165 self
.assertRegex(output
, 'okey 1.2.4.103')
1166 self
.assertRegex(output
, 'iseq')
1167 self
.assertRegex(output
, 'oseq')
1168 output
= check_output('ip -d link show gretun98')
1170 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
1171 self
.assertRegex(output
, 'ikey 0.0.0.104')
1172 self
.assertRegex(output
, 'okey 0.0.0.104')
1173 self
.assertNotRegex(output
, 'iseq')
1174 self
.assertNotRegex(output
, 'oseq')
1175 output
= check_output('ip -d link show gretun97')
1177 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
1178 self
.assertRegex(output
, 'ikey 0.0.0.105')
1179 self
.assertRegex(output
, 'okey 0.0.0.105')
1180 self
.assertNotRegex(output
, 'iseq')
1181 self
.assertNotRegex(output
, 'oseq')
1182 output
= check_output('ip -d link show gretun96')
1184 self
.assertRegex(output
, 'gre remote any local any dev dummy98')
1185 self
.assertRegex(output
, 'ikey 0.0.0.106')
1186 self
.assertRegex(output
, 'okey 0.0.0.106')
1187 self
.assertNotRegex(output
, 'iseq')
1188 self
.assertNotRegex(output
, 'oseq')
1190 def test_ip6gre_tunnel(self
):
1191 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
1192 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
1193 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1194 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1195 '25-ip6gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1198 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1200 self
.check_link_exists('dummy98')
1201 self
.check_link_exists('ip6gretun99')
1202 self
.check_link_exists('ip6gretun98')
1203 self
.check_link_exists('ip6gretun97')
1204 self
.check_link_exists('ip6gretun96')
1206 output
= check_output('ip -d link show ip6gretun99')
1208 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1209 output
= check_output('ip -d link show ip6gretun98')
1211 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
1212 output
= check_output('ip -d link show ip6gretun97')
1214 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
1215 output
= check_output('ip -d link show ip6gretun96')
1217 self
.assertRegex(output
, 'ip6gre remote any local any dev dummy98')
1219 def test_gretap_tunnel(self
):
1220 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
1221 '25-gretap-tunnel.netdev', '25-tunnel.network',
1222 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1224 self
.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
1226 output
= check_output('ip -d link show gretap99')
1228 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1229 self
.assertRegex(output
, 'ikey 0.0.0.106')
1230 self
.assertRegex(output
, 'okey 0.0.0.106')
1231 self
.assertRegex(output
, 'iseq')
1232 self
.assertRegex(output
, 'oseq')
1233 output
= check_output('ip -d link show gretap98')
1235 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
1236 self
.assertRegex(output
, 'ikey 0.0.0.107')
1237 self
.assertRegex(output
, 'okey 0.0.0.107')
1238 self
.assertRegex(output
, 'iseq')
1239 self
.assertRegex(output
, 'oseq')
1241 def test_ip6gretap_tunnel(self
):
1242 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
1243 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1244 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1246 self
.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
1248 output
= check_output('ip -d link show ip6gretap99')
1250 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1251 output
= check_output('ip -d link show ip6gretap98')
1253 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1255 def test_vti_tunnel(self
):
1256 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
1257 '25-vti-tunnel.netdev', '25-tunnel.network',
1258 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1259 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1260 '25-vti-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1262 self
.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'vtitun96:routable', 'dummy98:degraded'])
1264 output
= check_output('ip -d link show vtitun99')
1266 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1267 output
= check_output('ip -d link show vtitun98')
1269 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
1270 output
= check_output('ip -d link show vtitun97')
1272 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
1273 output
= check_output('ip -d link show vtitun96')
1275 self
.assertRegex(output
, 'vti remote any local any dev dummy98')
1277 def test_vti6_tunnel(self
):
1278 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
1279 '25-vti6-tunnel.netdev', '25-tunnel.network',
1280 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1281 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1283 self
.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
1285 output
= check_output('ip -d link show vti6tun99')
1287 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1288 output
= check_output('ip -d link show vti6tun98')
1290 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1291 output
= check_output('ip -d link show vti6tun97')
1293 self
.assertRegex(output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1295 def test_ip6tnl_tunnel(self
):
1296 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
1297 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1298 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1299 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1301 self
.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
1303 output
= check_output('ip -d link show ip6tnl99')
1305 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1306 output
= check_output('ip -d link show ip6tnl98')
1308 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1309 output
= check_output('ip -d link show ip6tnl97')
1311 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1313 def test_sit_tunnel(self
):
1314 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1315 '25-sit-tunnel.netdev', '25-tunnel.network',
1316 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1317 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1318 '25-sit-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1320 self
.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'sittun96:routable', 'dummy98:degraded'])
1322 output
= check_output('ip -d link show sittun99')
1324 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1325 output
= check_output('ip -d link show sittun98')
1327 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98")
1328 output
= check_output('ip -d link show sittun97')
1330 self
.assertRegex(output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98")
1331 output
= check_output('ip -d link show sittun96')
1333 self
.assertRegex(output
, "sit (ip6ip )?remote any local any dev dummy98")
1335 def test_isatap_tunnel(self
):
1336 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1337 '25-isatap-tunnel.netdev', '25-tunnel.network')
1339 self
.wait_online(['isataptun99:routable', 'dummy98:degraded'])
1341 output
= check_output('ip -d link show isataptun99')
1343 self
.assertRegex(output
, "isatap ")
1345 def test_6rd_tunnel(self
):
1346 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1347 '25-6rd-tunnel.netdev', '25-tunnel.network')
1349 self
.wait_online(['sittun99:routable', 'dummy98:degraded'])
1351 output
= check_output('ip -d link show sittun99')
1353 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1355 @expectedFailureIfERSPANModuleIsNotAvailable()
1356 def test_erspan_tunnel(self
):
1357 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1358 '25-erspan-tunnel.netdev', '25-tunnel.network',
1359 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1361 self
.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1363 output
= check_output('ip -d link show erspan99')
1365 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1366 self
.assertRegex(output
, 'ikey 0.0.0.101')
1367 self
.assertRegex(output
, 'okey 0.0.0.101')
1368 self
.assertRegex(output
, 'iseq')
1369 self
.assertRegex(output
, 'oseq')
1370 output
= check_output('ip -d link show erspan98')
1372 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1373 self
.assertRegex(output
, '102')
1374 self
.assertRegex(output
, 'ikey 0.0.0.102')
1375 self
.assertRegex(output
, 'okey 0.0.0.102')
1376 self
.assertRegex(output
, 'iseq')
1377 self
.assertRegex(output
, 'oseq')
1379 def test_tunnel_independent(self
):
1380 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1383 self
.wait_online(['ipiptun99:carrier'])
1385 def test_tunnel_independent_loopback(self
):
1386 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent-loopback.netdev', 'netdev-link-local-addressing-yes.network')
1389 self
.wait_online(['ipiptun99:carrier'])
1391 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1392 def test_xfrm(self
):
1393 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'xfrm.network',
1394 '25-xfrm.netdev', 'netdev-link-local-addressing-yes.network')
1397 self
.wait_online(['xfrm99:degraded', 'dummy98:degraded'])
1399 output
= check_output('ip link show dev xfrm99')
1402 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1403 def test_xfrm_independent(self
):
1404 copy_unit_to_networkd_unit_path('25-xfrm-independent.netdev', 'netdev-link-local-addressing-yes.network')
1407 self
.wait_online(['xfrm99:degraded'])
1409 @expectedFailureIfModuleIsNotAvailable('fou')
1411 # The following redundant check is necessary for CentOS CI.
1412 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1413 self
.assertTrue(is_module_available('fou'))
1415 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1416 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1417 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1420 self
.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'], setup_state
='unmanaged')
1422 output
= check_output('ip fou show')
1424 self
.assertRegex(output
, 'port 55555 ipproto 4')
1425 self
.assertRegex(output
, 'port 55556 ipproto 47')
1427 output
= check_output('ip -d link show ipiptun96')
1429 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1430 output
= check_output('ip -d link show sittun96')
1432 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1433 output
= check_output('ip -d link show gretun96')
1435 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1436 output
= check_output('ip -d link show gretap96')
1438 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1440 def test_vxlan(self
):
1441 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1442 '11-dummy.netdev', 'vxlan-test1.network')
1445 self
.wait_online(['test1:degraded', 'vxlan99:degraded'])
1447 output
= check_output('ip -d link show vxlan99')
1449 self
.assertRegex(output
, '999')
1450 self
.assertRegex(output
, '5555')
1451 self
.assertRegex(output
, 'l2miss')
1452 self
.assertRegex(output
, 'l3miss')
1453 self
.assertRegex(output
, 'udpcsum')
1454 self
.assertRegex(output
, 'udp6zerocsumtx')
1455 self
.assertRegex(output
, 'udp6zerocsumrx')
1456 self
.assertRegex(output
, 'remcsumtx')
1457 self
.assertRegex(output
, 'remcsumrx')
1458 self
.assertRegex(output
, 'gbp')
1460 output
= check_output('bridge fdb show dev vxlan99')
1462 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1463 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1464 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1466 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'vxlan99', env
=env
)
1468 self
.assertRegex(output
, 'VNI: 999')
1469 self
.assertRegex(output
, 'Destination Port: 5555')
1470 self
.assertRegex(output
, 'Underlying Device: test1')
1472 def test_macsec(self
):
1473 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1474 'macsec.network', '12-dummy.netdev')
1477 self
.wait_online(['dummy98:degraded', 'macsec99:routable'])
1479 output
= check_output('ip -d link show macsec99')
1481 self
.assertRegex(output
, 'macsec99@dummy98')
1482 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1483 self
.assertRegex(output
, 'encrypt on')
1485 output
= check_output('ip macsec show macsec99')
1487 self
.assertRegex(output
, 'encrypt on')
1488 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1489 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1490 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1491 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1492 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1493 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1494 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1495 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1496 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1497 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1498 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1500 def test_nlmon(self
):
1501 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1504 self
.wait_online(['nlmon99:carrier'])
1506 @expectedFailureIfModuleIsNotAvailable('ifb')
1508 copy_unit_to_networkd_unit_path('25-ifb.netdev', 'netdev-link-local-addressing-yes.network')
1511 self
.wait_online(['ifb99:degraded'])
1513 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1524 '25-l2tp-dummy.network',
1526 '25-l2tp-ip.netdev',
1527 '25-l2tp-udp.netdev']
1529 l2tp_tunnel_ids
= [ '10' ]
1532 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1533 remove_links(self
.links
)
1534 stop_networkd(show_logs
=False)
1537 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1538 remove_links(self
.links
)
1539 remove_unit_from_networkd_path(self
.units
)
1540 stop_networkd(show_logs
=True)
1542 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1543 def test_l2tp_udp(self
):
1544 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1545 '25-l2tp-udp.netdev', '25-l2tp.network')
1548 self
.wait_online(['test1:routable', 'l2tp-ses1:degraded', 'l2tp-ses2:degraded'])
1550 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1552 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1553 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1554 self
.assertRegex(output
, "Peer tunnel 11")
1555 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1556 self
.assertRegex(output
, "UDP checksum: enabled")
1558 output
= check_output('ip l2tp show session tid 10 session_id 15')
1560 self
.assertRegex(output
, "Session 15 in tunnel 10")
1561 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1562 self
.assertRegex(output
, "interface name: l2tp-ses1")
1564 output
= check_output('ip l2tp show session tid 10 session_id 17')
1566 self
.assertRegex(output
, "Session 17 in tunnel 10")
1567 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1568 self
.assertRegex(output
, "interface name: l2tp-ses2")
1570 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1571 def test_l2tp_ip(self
):
1572 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1573 '25-l2tp-ip.netdev', '25-l2tp.network')
1576 self
.wait_online(['test1:routable', 'l2tp-ses3:degraded', 'l2tp-ses4:degraded'])
1578 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1580 self
.assertRegex(output
, "Tunnel 10, encap IP")
1581 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1582 self
.assertRegex(output
, "Peer tunnel 12")
1584 output
= check_output('ip l2tp show session tid 10 session_id 25')
1586 self
.assertRegex(output
, "Session 25 in tunnel 10")
1587 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1588 self
.assertRegex(output
, "interface name: l2tp-ses3")
1590 output
= check_output('ip l2tp show session tid 10 session_id 27')
1592 self
.assertRegex(output
, "Session 27 in tunnel 10")
1593 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1594 self
.assertRegex(output
, "interface name: l2tp-ses4")
1596 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1611 '23-active-slave.network',
1612 '24-keep-configuration-static.network',
1613 '24-search-domain.network',
1614 '25-address-dad-veth-peer.network',
1615 '25-address-dad-veth99.network',
1616 '25-address-link-section.network',
1617 '25-address-preferred-lifetime-zero.network',
1618 '25-address-static.network',
1619 '25-bind-carrier.network',
1620 '25-bond-active-backup-slave.netdev',
1621 '25-fibrule-invert.network',
1622 '25-fibrule-port-range.network',
1623 '25-fibrule-uidrange.network',
1624 '25-gre-tunnel-remote-any.netdev',
1625 '25-ip6gre-tunnel-remote-any.netdev',
1626 '25-ipv6-address-label-section.network',
1627 '25-link-local-addressing-no.network',
1628 '25-link-local-addressing-yes.network',
1629 '25-link-section-unmanaged.network',
1630 '25-neighbor-section.network',
1631 '25-neighbor-next.network',
1632 '25-neighbor-ipv6.network',
1633 '25-neighbor-ip-dummy.network',
1634 '25-neighbor-ip.network',
1635 '25-nexthop.network',
1636 '25-qdisc-cake.network',
1637 '25-qdisc-clsact-and-htb.network',
1638 '25-qdisc-ingress-netem-compat.network',
1639 '25-route-ipv6-src.network',
1640 '25-route-static.network',
1641 '25-route-vrf.network',
1642 '25-gateway-static.network',
1643 '25-gateway-next-static.network',
1644 '25-sysctl-disable-ipv6.network',
1645 '25-sysctl.network',
1646 '25-veth-peer.network',
1649 '26-link-local-addressing-ipv6.network',
1650 'configure-without-carrier.network',
1651 'routing-policy-rule-dummy98.network',
1652 'routing-policy-rule-test1.network']
1654 routing_policy_rule_tables
= ['7', '8', '9']
1655 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1658 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1659 remove_routes(self
.routes
)
1660 remove_links(self
.links
)
1661 stop_networkd(show_logs
=False)
1664 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1665 remove_routes(self
.routes
)
1666 remove_links(self
.links
)
1667 remove_unit_from_networkd_path(self
.units
)
1668 stop_networkd(show_logs
=True)
1670 def test_address_static(self
):
1671 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1674 self
.wait_online(['dummy98:routable'])
1676 output
= check_output('ip -4 address show dev dummy98')
1678 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1679 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1680 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1683 self
.assertNotRegex(output
, '10.10.0.1/16')
1684 self
.assertNotRegex(output
, '10.10.0.2/16')
1686 output
= check_output('ip -4 address show dev dummy98 label 32')
1687 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1689 output
= check_output('ip -4 address show dev dummy98 label 33')
1690 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1692 output
= check_output('ip -4 address show dev dummy98 label 34')
1693 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1695 output
= check_output('ip -4 address show dev dummy98 label 35')
1696 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1698 output
= check_output('ip -6 address show dev dummy98')
1700 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1701 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1702 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1703 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1704 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1705 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1707 def test_address_preferred_lifetime_zero_ipv6(self
):
1708 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero.network', '12-dummy.netdev')
1711 self
.wait_online(['dummy98:routable'])
1713 output
= check_output('ip address show dummy98')
1715 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1716 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1718 output
= check_output('ip route show dev dummy98')
1720 self
.assertRegex(output
, 'default via 20.20.20.1 proto static')
1722 def test_address_dad(self
):
1723 copy_unit_to_networkd_unit_path('25-address-dad-veth99.network', '25-address-dad-veth-peer.network',
1726 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
1728 output
= check_output('ip -4 address show dev veth99')
1730 self
.assertRegex(output
, '192.168.100.10/24')
1732 output
= check_output('ip -4 address show dev veth-peer')
1734 self
.assertNotRegex(output
, '192.168.100.10/24')
1736 def test_configure_without_carrier(self
):
1737 copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
1739 self
.wait_online(['test1:routable'])
1741 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
1743 self
.assertRegex(output
, '192.168.0.15')
1744 self
.assertRegex(output
, '192.168.0.1')
1745 self
.assertRegex(output
, 'routable')
1747 def test_routing_policy_rule(self
):
1748 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1750 self
.wait_online(['test1:degraded'])
1752 output
= check_output('ip rule list iif test1 priority 111')
1754 self
.assertRegex(output
, '111:')
1755 self
.assertRegex(output
, 'from 192.168.100.18')
1756 self
.assertRegex(output
, r
'tos (0x08|throughput)\s')
1757 self
.assertRegex(output
, 'iif test1')
1758 self
.assertRegex(output
, 'oif test1')
1759 self
.assertRegex(output
, 'lookup 7')
1761 output
= check_output('ip rule list iif test1 priority 101')
1763 self
.assertRegex(output
, '101:')
1764 self
.assertRegex(output
, 'from all')
1765 self
.assertRegex(output
, 'iif test1')
1766 self
.assertRegex(output
, 'lookup 9')
1768 output
= check_output('ip -6 rule list iif test1 priority 100')
1770 self
.assertRegex(output
, '100:')
1771 self
.assertRegex(output
, 'from all')
1772 self
.assertRegex(output
, 'iif test1')
1773 self
.assertRegex(output
, 'lookup 8')
1775 output
= check_output('ip -6 rule list iif test1 priority 101')
1777 self
.assertRegex(output
, '101:')
1778 self
.assertRegex(output
, 'from all')
1779 self
.assertRegex(output
, 'iif test1')
1780 self
.assertRegex(output
, 'lookup 9')
1782 def test_routing_policy_rule_issue_11280(self
):
1783 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1784 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1786 for trial
in range(3):
1787 # Remove state files only first time
1789 self
.wait_online(['test1:degraded', 'dummy98:degraded'])
1792 output
= check_output('ip rule list table 7')
1794 self
.assertRegex(output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
1796 output
= check_output('ip rule list table 8')
1798 self
.assertRegex(output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1800 stop_networkd(remove_state_files
=False)
1802 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1803 def test_routing_policy_rule_port_range(self
):
1804 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1806 self
.wait_online(['test1:degraded'])
1808 output
= check_output('ip rule')
1810 self
.assertRegex(output
, '111')
1811 self
.assertRegex(output
, 'from 192.168.100.18')
1812 self
.assertRegex(output
, '1123-1150')
1813 self
.assertRegex(output
, '3224-3290')
1814 self
.assertRegex(output
, 'tcp')
1815 self
.assertRegex(output
, 'lookup 7')
1817 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1818 def test_routing_policy_rule_invert(self
):
1819 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1821 self
.wait_online(['test1:degraded'])
1823 output
= check_output('ip rule')
1825 self
.assertRegex(output
, '111')
1826 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
1827 self
.assertRegex(output
, 'tcp')
1828 self
.assertRegex(output
, 'lookup 7')
1830 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable()
1831 def test_routing_policy_rule_uidrange(self
):
1832 copy_unit_to_networkd_unit_path('25-fibrule-uidrange.network', '11-dummy.netdev')
1834 self
.wait_online(['test1:degraded'])
1836 output
= check_output('ip rule')
1838 self
.assertRegex(output
, '111')
1839 self
.assertRegex(output
, 'from 192.168.100.18')
1840 self
.assertRegex(output
, 'lookup 7')
1841 self
.assertRegex(output
, 'uidrange 100-200')
1843 def test_route_static(self
):
1844 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1846 self
.wait_online(['dummy98:routable'])
1848 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
1851 print('### ip -6 route show dev dummy98')
1852 output
= check_output('ip -6 route show dev dummy98')
1854 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1855 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
1857 print('### ip -6 route show dev dummy98 default')
1858 output
= check_output('ip -6 route show dev dummy98 default')
1860 self
.assertRegex(output
, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1862 print('### ip -4 route show dev dummy98')
1863 output
= check_output('ip -4 route show dev dummy98')
1865 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1866 self
.assertRegex(output
, '149.10.124.64 proto static scope link')
1867 self
.assertRegex(output
, '169.254.0.0/16 proto static scope link metric 2048')
1868 self
.assertRegex(output
, '192.168.1.1 proto static initcwnd 20')
1869 self
.assertRegex(output
, '192.168.1.2 proto static initrwnd 30')
1870 self
.assertRegex(output
, 'multicast 149.10.123.4 proto static')
1872 print('### ip -4 route show dev dummy98 default')
1873 output
= check_output('ip -4 route show dev dummy98 default')
1875 self
.assertRegex(output
, 'default via 149.10.125.65 proto static onlink')
1876 self
.assertRegex(output
, 'default via 149.10.124.64 proto static')
1877 self
.assertRegex(output
, 'default proto static')
1879 print('### ip -4 route show table local dev dummy98')
1880 output
= check_output('ip -4 route show table local dev dummy98')
1882 self
.assertRegex(output
, 'local 149.10.123.1 proto static scope host')
1883 self
.assertRegex(output
, 'anycast 149.10.123.2 proto static scope link')
1884 self
.assertRegex(output
, 'broadcast 149.10.123.3 proto static scope link')
1886 print('### ip route show type blackhole')
1887 output
= check_output('ip route show type blackhole')
1889 self
.assertRegex(output
, 'blackhole 202.54.1.2 proto static')
1891 print('### ip route show type unreachable')
1892 output
= check_output('ip route show type unreachable')
1894 self
.assertRegex(output
, 'unreachable 202.54.1.3 proto static')
1896 print('### ip route show type prohibit')
1897 output
= check_output('ip route show type prohibit')
1899 self
.assertRegex(output
, 'prohibit 202.54.1.4 proto static')
1901 print('### ip route show 192.168.10.1')
1902 output
= check_output('ip route show 192.168.10.1')
1904 self
.assertRegex(output
, '192.168.10.1 proto static')
1905 self
.assertRegex(output
, 'nexthop via 149.10.124.59 dev dummy98 weight 10')
1906 self
.assertRegex(output
, 'nexthop via 149.10.124.60 dev dummy98 weight 5')
1908 print('### ip route show 192.168.10.2')
1909 output
= check_output('ip route show 192.168.10.2')
1911 # old ip command does not show IPv6 gateways...
1912 self
.assertRegex(output
, '192.168.10.2 proto static')
1913 self
.assertRegex(output
, 'nexthop')
1914 self
.assertRegex(output
, 'dev dummy98 weight 10')
1915 self
.assertRegex(output
, 'dev dummy98 weight 5')
1917 print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
1918 output
= check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
1920 # old ip command does not show 'nexthop' keyword and weight...
1921 self
.assertRegex(output
, '2001:1234:5:7fff:ff:ff:ff:ff')
1922 self
.assertRegex(output
, 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98')
1923 self
.assertRegex(output
, 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98')
1925 @expectedFailureIfModuleIsNotAvailable('vrf')
1926 def test_route_vrf(self
):
1927 copy_unit_to_networkd_unit_path('25-route-vrf.network', '12-dummy.netdev',
1928 '25-vrf.netdev', '25-vrf.network')
1930 self
.wait_online(['dummy98:routable', 'vrf99:carrier'])
1932 output
= check_output('ip route show vrf vrf99')
1934 self
.assertRegex(output
, 'default via 192.168.100.1')
1936 output
= check_output('ip route show')
1938 self
.assertNotRegex(output
, 'default via 192.168.100.1')
1940 def test_gateway_reconfigure(self
):
1941 copy_unit_to_networkd_unit_path('25-gateway-static.network', '12-dummy.netdev')
1943 self
.wait_online(['dummy98:routable'])
1944 print('### ip -4 route show dev dummy98 default')
1945 output
= check_output('ip -4 route show dev dummy98 default')
1947 self
.assertRegex(output
, 'default via 149.10.124.59 proto static')
1948 self
.assertNotRegex(output
, '149.10.124.60')
1950 remove_unit_from_networkd_path(['25-gateway-static.network'])
1951 copy_unit_to_networkd_unit_path('25-gateway-next-static.network')
1953 self
.wait_online(['dummy98:routable'])
1954 print('### ip -4 route show dev dummy98 default')
1955 output
= check_output('ip -4 route show dev dummy98 default')
1957 self
.assertNotRegex(output
, '149.10.124.59')
1958 self
.assertRegex(output
, 'default via 149.10.124.60 proto static')
1960 def test_ip_route_ipv6_src_route(self
):
1961 # a dummy device does not make the addresses go through tentative state, so we
1962 # reuse a bond from an earlier test, which does make the addresses go through
1963 # tentative state, and do our test on that
1964 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1966 self
.wait_online(['dummy98:enslaved', 'bond199:routable'])
1968 output
= check_output('ip -6 route list dev bond199')
1970 self
.assertRegex(output
, 'abcd::/16')
1971 self
.assertRegex(output
, 'src')
1972 self
.assertRegex(output
, '2001:1234:56:8f63::2')
1974 def test_ip_link_mac_address(self
):
1975 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
1977 self
.wait_online(['dummy98:degraded'])
1979 output
= check_output('ip link show dummy98')
1981 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
1983 def test_ip_link_unmanaged(self
):
1984 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
1987 self
.check_link_exists('dummy98')
1989 self
.wait_operstate('dummy98', 'off', setup_state
='unmanaged')
1991 def test_ipv6_address_label(self
):
1992 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
1994 self
.wait_online(['dummy98:degraded'])
1996 output
= check_output('ip addrlabel list')
1998 self
.assertRegex(output
, '2004:da8:1::/64')
2000 def test_neighbor_section(self
):
2001 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2003 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2005 print('### ip neigh list dev dummy98')
2006 output
= check_output('ip neigh list dev dummy98')
2008 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2009 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2011 def test_neighbor_reconfigure(self
):
2012 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2014 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2016 print('### ip neigh list dev dummy98')
2017 output
= check_output('ip neigh list dev dummy98')
2019 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2020 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2022 remove_unit_from_networkd_path(['25-neighbor-section.network'])
2023 copy_unit_to_networkd_unit_path('25-neighbor-next.network')
2025 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2026 print('### ip neigh list dev dummy98')
2027 output
= check_output('ip neigh list dev dummy98')
2029 self
.assertNotRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2030 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT')
2031 self
.assertNotRegex(output
, '2004:da8:1::1.*PERMANENT')
2033 def test_neighbor_gre(self
):
2034 copy_unit_to_networkd_unit_path('25-neighbor-ip.network', '25-neighbor-ipv6.network', '25-neighbor-ip-dummy.network',
2035 '12-dummy.netdev', '25-gre-tunnel-remote-any.netdev', '25-ip6gre-tunnel-remote-any.netdev')
2037 self
.wait_online(['dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable'], timeout
='40s')
2039 output
= check_output('ip neigh list dev gretun97')
2041 self
.assertRegex(output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT')
2043 output
= check_output('ip neigh list dev ip6gretun97')
2045 self
.assertRegex(output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
2047 def test_link_local_addressing(self
):
2048 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
2049 '25-link-local-addressing-no.network', '12-dummy.netdev')
2051 self
.wait_online(['test1:degraded', 'dummy98:carrier'])
2053 output
= check_output('ip address show dev test1')
2055 self
.assertRegex(output
, 'inet .* scope link')
2056 self
.assertRegex(output
, 'inet6 .* scope link')
2058 output
= check_output('ip address show dev dummy98')
2060 self
.assertNotRegex(output
, 'inet6* .* scope link')
2063 Documentation/networking/ip-sysctl.txt
2065 addr_gen_mode - INTEGER
2066 Defines how link-local and autoconf addresses are generated.
2068 0: generate address based on EUI64 (default)
2069 1: do no generate a link-local address, use EUI64 for addresses generated
2071 2: generate stable privacy addresses, using the secret from
2072 stable_secret (RFC7217)
2073 3: generate stable privacy addresses, using a random secret if unset
2076 test1_addr_gen_mode
= ''
2077 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
2078 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
2082 # if stable_secret is unset, then EIO is returned
2083 test1_addr_gen_mode
= '0'
2085 test1_addr_gen_mode
= '2'
2087 test1_addr_gen_mode
= '0'
2089 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
2090 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
2092 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
2093 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
2095 def test_link_local_addressing_remove_ipv6ll(self
):
2096 copy_unit_to_networkd_unit_path('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
2098 self
.wait_online(['dummy98:degraded'])
2100 output
= check_output('ip address show dev dummy98')
2102 self
.assertRegex(output
, 'inet6 .* scope link')
2104 copy_unit_to_networkd_unit_path('25-link-local-addressing-no.network')
2106 self
.wait_online(['dummy98:carrier'])
2108 output
= check_output('ip address show dev dummy98')
2110 self
.assertNotRegex(output
, 'inet6* .* scope link')
2112 def test_sysctl(self
):
2113 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
2115 self
.wait_online(['dummy98:degraded'])
2117 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
2118 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
2119 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
2120 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
2121 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
2122 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
2123 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
2125 def test_sysctl_disable_ipv6(self
):
2126 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
2128 print('## Disable ipv6')
2129 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
2130 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
2133 self
.wait_online(['dummy98:routable'])
2135 output
= check_output('ip -4 address show dummy98')
2137 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2138 output
= check_output('ip -6 address show dummy98')
2140 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2141 self
.assertRegex(output
, 'inet6 .* scope link')
2142 output
= check_output('ip -4 route show dev dummy98')
2144 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2145 output
= check_output('ip -6 route show dev dummy98')
2147 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2149 check_output('ip link del dummy98')
2151 print('## Enable ipv6')
2152 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
2153 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
2156 self
.wait_online(['dummy98:routable'])
2158 output
= check_output('ip -4 address show dummy98')
2160 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2161 output
= check_output('ip -6 address show dummy98')
2163 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2164 self
.assertRegex(output
, 'inet6 .* scope link')
2165 output
= check_output('ip -4 route show dev dummy98')
2167 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2168 output
= check_output('ip -6 route show dev dummy98')
2170 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2172 def test_bind_carrier(self
):
2173 check_output('ip link add dummy98 type dummy')
2174 check_output('ip link set dummy98 up')
2177 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
2179 self
.wait_online(['test1:routable'])
2181 output
= check_output('ip address show test1')
2183 self
.assertRegex(output
, 'UP,LOWER_UP')
2184 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2185 self
.wait_operstate('test1', 'routable')
2187 check_output('ip link add dummy99 type dummy')
2188 check_output('ip link set dummy99 up')
2190 output
= check_output('ip address show test1')
2192 self
.assertRegex(output
, 'UP,LOWER_UP')
2193 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2194 self
.wait_operstate('test1', 'routable')
2196 check_output('ip link del dummy98')
2198 output
= check_output('ip address show test1')
2200 self
.assertRegex(output
, 'UP,LOWER_UP')
2201 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2202 self
.wait_operstate('test1', 'routable')
2204 check_output('ip link set dummy99 down')
2206 output
= check_output('ip address show test1')
2208 self
.assertNotRegex(output
, 'UP,LOWER_UP')
2209 self
.assertRegex(output
, 'DOWN')
2210 self
.assertNotRegex(output
, '192.168.10')
2211 self
.wait_operstate('test1', 'off')
2213 check_output('ip link set dummy99 up')
2215 output
= check_output('ip address show test1')
2217 self
.assertRegex(output
, 'UP,LOWER_UP')
2218 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2219 self
.wait_operstate('test1', 'routable')
2221 def test_domain(self
):
2222 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
2224 self
.wait_online(['dummy98:routable'])
2226 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2228 self
.assertRegex(output
, 'Address: 192.168.42.100')
2229 self
.assertRegex(output
, 'DNS: 192.168.42.1')
2230 self
.assertRegex(output
, 'Search Domains: one')
2232 def test_keep_configuration_static(self
):
2233 check_output('systemctl stop systemd-networkd')
2235 check_output('ip link add name dummy98 type dummy')
2236 check_output('ip address add 10.1.2.3/16 dev dummy98')
2237 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
2238 output
= check_output('ip address show dummy98')
2240 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2241 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2242 output
= check_output('ip route show dev dummy98')
2245 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
2247 self
.wait_online(['dummy98:routable'])
2249 output
= check_output('ip address show dummy98')
2251 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2252 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2254 @expectedFailureIfNexthopIsNotAvailable()
2255 def test_nexthop(self
):
2256 copy_unit_to_networkd_unit_path('25-nexthop.network', '25-veth.netdev', '25-veth-peer.network')
2258 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2260 output
= check_output('ip nexthop list dev veth99')
2262 self
.assertRegex(output
, '192.168.5.1')
2264 def test_qdisc(self
):
2265 copy_unit_to_networkd_unit_path('25-qdisc-clsact-and-htb.network', '12-dummy.netdev',
2266 '25-qdisc-ingress-netem-compat.network', '11-dummy.netdev')
2267 check_output('modprobe sch_teql max_equalizers=2')
2270 self
.wait_online(['dummy98:routable', 'test1:routable'])
2272 output
= check_output('tc qdisc show dev test1')
2274 self
.assertRegex(output
, 'qdisc netem')
2275 self
.assertRegex(output
, 'limit 100 delay 50.0ms 10.0ms loss 20%')
2276 self
.assertRegex(output
, 'qdisc ingress')
2278 output
= check_output('tc qdisc show dev dummy98')
2280 self
.assertRegex(output
, 'qdisc clsact')
2282 self
.assertRegex(output
, 'qdisc htb 2: root')
2283 self
.assertRegex(output
, r
'default (0x30|30)')
2285 self
.assertRegex(output
, 'qdisc netem 30: parent 2:30')
2286 self
.assertRegex(output
, 'limit 100 delay 50.0ms 10.0ms loss 20%')
2287 self
.assertRegex(output
, 'qdisc fq_codel')
2288 self
.assertRegex(output
, 'limit 20480p flows 2048 quantum 1400 target 10.0ms ce_threshold 100.0ms interval 200.0ms memory_limit 64Mb ecn')
2290 self
.assertRegex(output
, 'qdisc teql1 31: parent 2:31')
2292 self
.assertRegex(output
, 'qdisc fq 32: parent 2:32')
2293 self
.assertRegex(output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
2294 self
.assertRegex(output
, 'quantum 1500')
2295 self
.assertRegex(output
, 'initial_quantum 13000')
2296 self
.assertRegex(output
, 'maxrate 1Mbit')
2298 self
.assertRegex(output
, 'qdisc codel 33: parent 2:33')
2299 self
.assertRegex(output
, 'limit 2000p target 10.0ms ce_threshold 100.0ms interval 50.0ms ecn')
2301 self
.assertRegex(output
, 'qdisc fq_codel 34: parent 2:34')
2302 self
.assertRegex(output
, 'limit 20480p flows 2048 quantum 1400 target 10.0ms ce_threshold 100.0ms interval 200.0ms memory_limit 64Mb ecn')
2304 self
.assertRegex(output
, 'qdisc tbf 35: parent 2:35')
2305 self
.assertRegex(output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70.0ms')
2307 self
.assertRegex(output
, 'qdisc sfq 36: parent 2:36')
2308 self
.assertRegex(output
, 'perturb 5sec')
2310 self
.assertRegex(output
, 'qdisc pfifo 37: parent 2:37')
2311 self
.assertRegex(output
, 'limit 100000p')
2313 self
.assertRegex(output
, 'qdisc gred 38: parent 2:38')
2314 self
.assertRegex(output
, 'vqs 12 default 10 grio')
2316 self
.assertRegex(output
, 'qdisc sfb 39: parent 2:39')
2317 self
.assertRegex(output
, 'limit 200000')
2319 output
= check_output('tc class show dev dummy98')
2321 self
.assertRegex(output
, 'class htb 2:30 root leaf 30:')
2322 self
.assertRegex(output
, 'class htb 2:31 root leaf 31:')
2323 self
.assertRegex(output
, 'class htb 2:32 root leaf 32:')
2324 self
.assertRegex(output
, 'class htb 2:33 root leaf 33:')
2325 self
.assertRegex(output
, 'class htb 2:34 root leaf 34:')
2326 self
.assertRegex(output
, 'class htb 2:35 root leaf 35:')
2327 self
.assertRegex(output
, 'class htb 2:36 root leaf 36:')
2328 self
.assertRegex(output
, 'class htb 2:37 root leaf 37:')
2329 self
.assertRegex(output
, 'class htb 2:38 root leaf 38:')
2330 self
.assertRegex(output
, 'class htb 2:39 root leaf 39:')
2331 self
.assertRegex(output
, 'prio 1 rate 1Mbit ceil 500Kbit')
2333 @expectedFailureIfCAKEIsNotAvailable()
2334 def test_qdisc_cake(self
):
2335 copy_unit_to_networkd_unit_path('25-qdisc-cake.network', '12-dummy.netdev')
2337 self
.wait_online(['dummy98:routable'])
2339 output
= check_output('tc qdisc show dev dummy98')
2341 self
.assertRegex(output
, 'qdisc cake 3a: root')
2342 self
.assertRegex(output
, 'bandwidth 500Mbit')
2343 self
.assertRegex(output
, 'overhead 128')
2345 class NetworkdStateFileTests(unittest
.TestCase
, Utilities
):
2352 'state-file-tests.network',
2356 remove_links(self
.links
)
2357 stop_networkd(show_logs
=False)
2360 remove_links(self
.links
)
2361 remove_unit_from_networkd_path(self
.units
)
2362 stop_networkd(show_logs
=True)
2364 def test_state_file(self
):
2365 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'state-file-tests.network')
2367 self
.wait_online(['dummy98:routable'])
2369 output
= check_output(*networkctl_cmd
, '--no-legend', 'list', 'dummy98', env
=env
)
2371 ifindex
= output
.split()[0]
2373 path
= os
.path
.join('/run/systemd/netif/links/', ifindex
)
2374 self
.assertTrue(os
.path
.exists(path
))
2377 with
open(path
) as f
:
2379 self
.assertRegex(data
, r
'ADMIN_STATE=configured')
2380 self
.assertRegex(data
, r
'OPER_STATE=routable')
2381 self
.assertRegex(data
, r
'REQUIRED_FOR_ONLINE=yes')
2382 self
.assertRegex(data
, r
'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
2383 self
.assertRegex(data
, r
'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
2384 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
2385 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2386 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2387 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2388 self
.assertRegex(data
, r
'LLMNR=no')
2389 self
.assertRegex(data
, r
'MDNS=yes')
2390 self
.assertRegex(data
, r
'DNSSEC=no')
2391 self
.assertRegex(data
, r
'ADDRESSES=192.168.(10.10|12.12)/24 192.168.(12.12|10.10)/24')
2393 check_output(*resolvectl_cmd
, 'dns', 'dummy98', '10.10.10.12', '10.10.10.13', env
=env
)
2394 check_output(*resolvectl_cmd
, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env
=env
)
2395 check_output(*resolvectl_cmd
, 'llmnr', 'dummy98', 'yes', env
=env
)
2396 check_output(*resolvectl_cmd
, 'mdns', 'dummy98', 'no', env
=env
)
2397 check_output(*resolvectl_cmd
, 'dnssec', 'dummy98', 'yes', env
=env
)
2398 check_output(*timedatectl_cmd
, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env
=env
)
2401 with
open(path
) as f
:
2403 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
2404 self
.assertRegex(data
, r
'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org')
2405 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2406 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2407 self
.assertRegex(data
, r
'LLMNR=yes')
2408 self
.assertRegex(data
, r
'MDNS=no')
2409 self
.assertRegex(data
, r
'DNSSEC=yes')
2411 check_output(*timedatectl_cmd
, 'revert', 'dummy98', env
=env
)
2414 with
open(path
) as f
:
2416 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
2417 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2418 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2419 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2420 self
.assertRegex(data
, r
'LLMNR=yes')
2421 self
.assertRegex(data
, r
'MDNS=no')
2422 self
.assertRegex(data
, r
'DNSSEC=yes')
2424 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
2427 with
open(path
) as f
:
2429 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
2430 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2431 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2432 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2433 self
.assertRegex(data
, r
'LLMNR=no')
2434 self
.assertRegex(data
, r
'MDNS=yes')
2435 self
.assertRegex(data
, r
'DNSSEC=no')
2437 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
2447 '23-active-slave.network',
2448 '23-bond199.network',
2449 '23-primary-slave.network',
2450 '25-bond-active-backup-slave.netdev',
2453 'bond-slave.network']
2456 remove_links(self
.links
)
2457 stop_networkd(show_logs
=False)
2460 remove_links(self
.links
)
2461 remove_unit_from_networkd_path(self
.units
)
2462 stop_networkd(show_logs
=True)
2464 def test_bond_active_slave(self
):
2465 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2467 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2469 output
= check_output('ip -d link show bond199')
2471 self
.assertRegex(output
, 'active_slave dummy98')
2473 def test_bond_primary_slave(self
):
2474 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2476 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2478 output
= check_output('ip -d link show bond199')
2480 self
.assertRegex(output
, 'primary dummy98')
2482 def test_bond_operstate(self
):
2483 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
2484 'bond99.network','bond-slave.network')
2486 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
2488 output
= check_output('ip -d link show dummy98')
2490 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2492 output
= check_output('ip -d link show test1')
2494 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2496 output
= check_output('ip -d link show bond99')
2498 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
2500 self
.wait_operstate('dummy98', 'enslaved')
2501 self
.wait_operstate('test1', 'enslaved')
2502 self
.wait_operstate('bond99', 'routable')
2504 check_output('ip link set dummy98 down')
2506 self
.wait_operstate('dummy98', 'off')
2507 self
.wait_operstate('test1', 'enslaved')
2508 self
.wait_operstate('bond99', 'degraded-carrier')
2510 check_output('ip link set dummy98 up')
2512 self
.wait_operstate('dummy98', 'enslaved')
2513 self
.wait_operstate('test1', 'enslaved')
2514 self
.wait_operstate('bond99', 'routable')
2516 check_output('ip link set dummy98 down')
2517 check_output('ip link set test1 down')
2519 self
.wait_operstate('dummy98', 'off')
2520 self
.wait_operstate('test1', 'off')
2522 if not self
.wait_operstate('bond99', 'no-carrier', setup_timeout
=30, fail_assert
=False):
2523 # Huh? Kernel does not recognize that all slave interfaces are down?
2524 # Let's confirm that networkd's operstate is consistent with ip's result.
2525 self
.assertNotRegex(output
, 'NO-CARRIER')
2527 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
2537 '26-bridge-slave-interface-1.network',
2538 '26-bridge-slave-interface-2.network',
2539 '26-bridge-vlan-master.network',
2540 '26-bridge-vlan-slave.network',
2541 'bridge99-ignore-carrier-loss.network',
2544 routing_policy_rule_tables
= ['100']
2547 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2548 remove_links(self
.links
)
2549 stop_networkd(show_logs
=False)
2552 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2553 remove_links(self
.links
)
2554 remove_unit_from_networkd_path(self
.units
)
2555 stop_networkd(show_logs
=True)
2557 def test_bridge_vlan(self
):
2558 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
2559 '26-bridge.netdev', '26-bridge-vlan-master.network')
2561 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
2563 output
= check_output('bridge vlan show dev test1')
2565 self
.assertNotRegex(output
, '4063')
2566 for i
in range(4064, 4095):
2567 self
.assertRegex(output
, f
'{i}')
2568 self
.assertNotRegex(output
, '4095')
2570 output
= check_output('bridge vlan show dev bridge99')
2572 self
.assertNotRegex(output
, '4059')
2573 for i
in range(4060, 4095):
2574 self
.assertRegex(output
, f
'{i}')
2575 self
.assertNotRegex(output
, '4095')
2577 def test_bridge_property(self
):
2578 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2579 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2582 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2584 output
= check_output('ip -d link show test1')
2586 self
.assertRegex(output
, 'master')
2587 self
.assertRegex(output
, 'bridge')
2589 output
= check_output('ip -d link show dummy98')
2591 self
.assertRegex(output
, 'master')
2592 self
.assertRegex(output
, 'bridge')
2594 output
= check_output('ip addr show bridge99')
2596 self
.assertRegex(output
, '192.168.0.15/24')
2598 output
= check_output('bridge -d link show dummy98')
2600 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
2601 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
2602 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
2603 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
2604 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
2605 # CONFIG_BRIDGE_IGMP_SNOOPING=y
2606 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
2607 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
2608 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
2609 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
2610 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
2611 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'priority'), '23')
2612 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard'), '1')
2613 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'root_block'), '1')
2615 output
= check_output('bridge -d link show test1')
2617 self
.assertEqual(read_bridge_port_attr('bridge99', 'test1', 'priority'), '0')
2619 check_output('ip address add 192.168.0.16/24 dev bridge99')
2622 output
= check_output('ip addr show bridge99')
2624 self
.assertRegex(output
, '192.168.0.16/24')
2627 print('### ip -6 route list table all dev bridge99')
2628 output
= check_output('ip -6 route list table all dev bridge99')
2630 self
.assertRegex(output
, 'ff00::/8 table local metric 256 pref medium')
2632 self
.assertEqual(call('ip link del test1'), 0)
2634 self
.wait_operstate('bridge99', 'degraded-carrier')
2636 check_output('ip link del dummy98')
2638 self
.wait_operstate('bridge99', 'no-carrier')
2640 output
= check_output('ip address show bridge99')
2642 self
.assertRegex(output
, 'NO-CARRIER')
2643 self
.assertNotRegex(output
, '192.168.0.15/24')
2644 self
.assertNotRegex(output
, '192.168.0.16/24')
2646 print('### ip -6 route list table all dev bridge99')
2647 output
= check_output('ip -6 route list table all dev bridge99')
2649 self
.assertRegex(output
, 'ff00::/8 table local metric 256 (linkdown )?pref medium')
2651 def test_bridge_ignore_carrier_loss(self
):
2652 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2653 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2654 'bridge99-ignore-carrier-loss.network')
2656 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2658 check_output('ip address add 192.168.0.16/24 dev bridge99')
2661 check_output('ip link del test1')
2662 check_output('ip link del dummy98')
2665 output
= check_output('ip address show bridge99')
2667 self
.assertRegex(output
, 'NO-CARRIER')
2668 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2669 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
2671 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
2672 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
2673 'bridge99-ignore-carrier-loss.network')
2675 self
.wait_online(['bridge99:no-carrier'])
2677 for trial
in range(4):
2678 check_output('ip link add dummy98 type dummy')
2679 check_output('ip link set dummy98 up')
2681 check_output('ip link del dummy98')
2683 self
.wait_online(['bridge99:routable', 'dummy98:enslaved'])
2685 output
= check_output('ip address show bridge99')
2687 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2689 output
= check_output('ip rule list table 100')
2691 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
2693 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
2697 '23-emit-lldp.network',
2702 remove_links(self
.links
)
2703 stop_networkd(show_logs
=False)
2706 remove_links(self
.links
)
2707 remove_unit_from_networkd_path(self
.units
)
2708 stop_networkd(show_logs
=True)
2710 def test_lldp(self
):
2711 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
2713 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
2715 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
2717 self
.assertRegex(output
, 'veth-peer')
2718 self
.assertRegex(output
, 'veth99')
2720 class NetworkdRATests(unittest
.TestCase
, Utilities
):
2725 'ipv6-prefix.network',
2726 'ipv6-prefix-veth.network',
2727 'ipv6-prefix-veth-token-static.network',
2728 'ipv6-prefix-veth-token-static-explicit.network',
2729 'ipv6-prefix-veth-token-static-multiple.network',
2730 'ipv6-prefix-veth-token-prefixstable.network']
2733 remove_links(self
.links
)
2734 stop_networkd(show_logs
=False)
2737 remove_links(self
.links
)
2738 remove_unit_from_networkd_path(self
.units
)
2739 stop_networkd(show_logs
=True)
2741 def test_ipv6_prefix_delegation(self
):
2742 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
2744 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2746 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
2748 self
.assertRegex(output
, 'fe80::')
2749 self
.assertRegex(output
, '2002:da8:1::1')
2751 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2753 self
.assertRegex(output
, '2002:da8:1:0')
2755 def test_ipv6_token_static(self
):
2756 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static.network')
2758 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2760 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2762 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
2764 def test_ipv6_token_static_explicit(self
):
2765 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static-explicit.network')
2767 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2769 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2771 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
2773 def test_ipv6_token_static_multiple(self
):
2774 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static-multiple.network')
2776 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2778 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2780 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
2781 self
.assertRegex(output
, '2002:da8:1:0:fa:de:ca:fe')
2783 def test_ipv6_token_prefixstable(self
):
2784 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable.network')
2786 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2788 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2790 self
.assertRegex(output
, '2002:da8:1:0')
2792 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
2797 'dhcp-client.network',
2798 'dhcp-client-timezone-router.network',
2799 'dhcp-server.network',
2800 'dhcp-server-timezone-router.network']
2803 remove_links(self
.links
)
2804 stop_networkd(show_logs
=False)
2807 remove_links(self
.links
)
2808 remove_unit_from_networkd_path(self
.units
)
2809 stop_networkd(show_logs
=True)
2811 def test_dhcp_server(self
):
2812 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
2814 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2816 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2818 self
.assertRegex(output
, '192.168.5.*')
2819 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
2820 self
.assertRegex(output
, 'DNS: 192.168.5.1')
2821 self
.assertRegex(output
, 'NTP: 192.168.5.1')
2823 def test_emit_router_timezone(self
):
2824 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
2826 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2828 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2830 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
2831 self
.assertRegex(output
, '192.168.5.*')
2832 self
.assertRegex(output
, 'Europe/Berlin')
2834 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
2843 'dhcp-client-anonymize.network',
2844 'dhcp-client-decline.network',
2845 'dhcp-client-gateway-ipv4.network',
2846 'dhcp-client-gateway-ipv6.network',
2847 'dhcp-client-gateway-onlink-implicit.network',
2848 'dhcp-client-ipv4-dhcp-settings.network',
2849 'dhcp-client-ipv4-only-ipv6-disabled.network',
2850 'dhcp-client-ipv4-only.network',
2851 'dhcp-client-ipv4-use-routes-no.network',
2852 'dhcp-client-ipv6-only.network',
2853 'dhcp-client-ipv6-rapid-commit.network',
2854 'dhcp-client-keep-configuration-dhcp-on-stop.network',
2855 'dhcp-client-keep-configuration-dhcp.network',
2856 'dhcp-client-listen-port.network',
2857 'dhcp-client-reassign-static-routes-ipv4.network',
2858 'dhcp-client-reassign-static-routes-ipv6.network',
2859 'dhcp-client-route-metric.network',
2860 'dhcp-client-route-table.network',
2861 'dhcp-client-use-dns-ipv4-and-ra.network',
2862 'dhcp-client-use-dns-ipv4.network',
2863 'dhcp-client-use-dns-no.network',
2864 'dhcp-client-use-dns-yes.network',
2865 'dhcp-client-use-domains.network',
2866 'dhcp-client-use-routes-no.network',
2867 'dhcp-client-vrf.network',
2868 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
2869 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
2870 'dhcp-client-with-static-address.network',
2871 'dhcp-client.network',
2872 'dhcp-server-decline.network',
2873 'dhcp-server-veth-peer.network',
2874 'dhcp-v4-server-veth-peer.network',
2875 'dhcp-client-use-domains.network',
2879 stop_dnsmasq(dnsmasq_pid_file
)
2880 remove_links(self
.links
)
2881 stop_networkd(show_logs
=False)
2884 stop_dnsmasq(dnsmasq_pid_file
)
2887 remove_links(self
.links
)
2888 remove_unit_from_networkd_path(self
.units
)
2889 stop_networkd(show_logs
=True)
2891 def test_dhcp_client_ipv6_only(self
):
2892 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2895 self
.wait_online(['veth-peer:carrier'])
2897 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2899 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2901 self
.assertRegex(output
, '2600::')
2902 self
.assertNotRegex(output
, '192.168.5')
2904 # Confirm that ipv6 token is not set in the kernel
2905 output
= check_output('ip token show dev veth99')
2907 self
.assertRegex(output
, 'token :: dev veth99')
2909 def test_dhcp_client_ipv4_only(self
):
2910 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
2913 self
.wait_online(['veth-peer:carrier'])
2914 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
2915 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2917 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2919 self
.assertNotRegex(output
, '2600::')
2920 self
.assertRegex(output
, '192.168.5')
2921 self
.assertRegex(output
, '192.168.5.6')
2922 self
.assertRegex(output
, '192.168.5.7')
2924 # checking routes to DNS servers
2925 output
= check_output('ip route show dev veth99')
2927 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
2928 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
2929 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
2931 stop_dnsmasq(dnsmasq_pid_file
)
2932 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8', lease_time
='2m')
2934 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2935 print('Wait for the dynamic address to be renewed')
2938 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2940 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2942 self
.assertNotRegex(output
, '2600::')
2943 self
.assertRegex(output
, '192.168.5')
2944 self
.assertNotRegex(output
, '192.168.5.6')
2945 self
.assertRegex(output
, '192.168.5.7')
2946 self
.assertRegex(output
, '192.168.5.8')
2948 # checking routes to DNS servers
2949 output
= check_output('ip route show dev veth99')
2951 self
.assertNotRegex(output
, r
'192.168.5.6')
2952 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
2953 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
2954 self
.assertRegex(output
, r
'192.168.5.8 proto dhcp scope link src 192.168.5.181 metric 1024')
2956 def test_dhcp_client_ipv4_use_routes_no(self
):
2957 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-use-routes-no.network')
2960 self
.wait_online(['veth-peer:carrier'])
2961 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
2962 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2964 output
= check_output('ip route show dev veth99')
2966 self
.assertNotRegex(output
, r
'192.168.5.5')
2967 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.181 metric 1024')
2968 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
2970 def test_dhcp_client_ipv4_ipv6(self
):
2971 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
2972 'dhcp-client-ipv4-only.network')
2974 self
.wait_online(['veth-peer:carrier'])
2976 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2978 # link become 'routable' when at least one protocol provide an valid address.
2979 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2980 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2982 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2984 self
.assertRegex(output
, '2600::')
2985 self
.assertRegex(output
, '192.168.5')
2987 def test_dhcp_client_settings(self
):
2988 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
2991 self
.wait_online(['veth-peer:carrier'])
2993 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2995 print('## ip address show dev veth99')
2996 output
= check_output('ip address show dev veth99')
2998 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2999 self
.assertRegex(output
, '192.168.5')
3000 self
.assertRegex(output
, '1492')
3002 print('## ip route show table main dev veth99')
3003 output
= check_output('ip route show table main dev veth99')
3006 main_table_is_empty
= output
== ''
3007 if not main_table_is_empty
:
3008 self
.assertNotRegex(output
, 'proto dhcp')
3010 print('## ip route show table 211 dev veth99')
3011 output
= check_output('ip route show table 211 dev veth99')
3013 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
3014 if main_table_is_empty
:
3015 self
.assertRegex(output
, '192.168.5.0/24 proto dhcp')
3016 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
3017 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
3019 print('## dnsmasq log')
3020 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
3021 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
3022 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
3023 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
3025 def test_dhcp6_client_settings_rapidcommit_true(self
):
3026 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3028 self
.wait_online(['veth-peer:carrier'])
3030 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3032 output
= check_output('ip address show dev veth99')
3034 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3035 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
3037 def test_dhcp6_client_settings_rapidcommit_false(self
):
3038 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
3040 self
.wait_online(['veth-peer:carrier'])
3042 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3044 output
= check_output('ip address show dev veth99')
3046 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3047 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
3049 def test_dhcp_client_settings_anonymize(self
):
3050 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
3052 self
.wait_online(['veth-peer:carrier'])
3054 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3056 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
3057 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
3058 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
3060 def test_dhcp_client_listen_port(self
):
3061 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
3063 self
.wait_online(['veth-peer:carrier'])
3064 start_dnsmasq('--dhcp-alternate-port=67,5555')
3065 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3067 output
= check_output('ip -4 address show dev veth99')
3069 self
.assertRegex(output
, '192.168.5.* dynamic')
3071 def test_dhcp_client_with_static_address(self
):
3072 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
3073 'dhcp-client-with-static-address.network')
3075 self
.wait_online(['veth-peer:carrier'])
3077 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3079 output
= check_output('ip address show dev veth99 scope global')
3081 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
3082 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
3084 output
= check_output('ip route show dev veth99')
3086 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
3087 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
3088 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
3089 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
3091 def test_dhcp_route_table_id(self
):
3092 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
3094 self
.wait_online(['veth-peer:carrier'])
3096 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3098 output
= check_output('ip route show table 12')
3100 self
.assertRegex(output
, 'veth99 proto dhcp')
3101 self
.assertRegex(output
, '192.168.5.1')
3103 def test_dhcp_route_metric(self
):
3104 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
3106 self
.wait_online(['veth-peer:carrier'])
3108 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3110 output
= check_output('ip route show dev veth99')
3112 self
.assertRegex(output
, 'metric 24')
3114 def test_dhcp_client_reassign_static_routes_ipv4(self
):
3115 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3116 'dhcp-client-reassign-static-routes-ipv4.network')
3118 self
.wait_online(['veth-peer:carrier'])
3119 start_dnsmasq(lease_time
='2m')
3120 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3122 output
= check_output('ip address show dev veth99 scope global')
3124 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3126 output
= check_output('ip route show dev veth99')
3128 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3129 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3130 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3131 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3133 stop_dnsmasq(dnsmasq_pid_file
)
3134 start_dnsmasq(ipv4_range
='192.168.5.210,192.168.5.220', lease_time
='2m')
3136 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3137 print('Wait for the dynamic address to be renewed')
3140 self
.wait_online(['veth99:routable'])
3142 output
= check_output('ip route show dev veth99')
3144 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3145 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3146 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3147 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3149 def test_dhcp_client_reassign_static_routes_ipv6(self
):
3150 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3151 'dhcp-client-reassign-static-routes-ipv6.network')
3153 self
.wait_online(['veth-peer:carrier'])
3154 start_dnsmasq(lease_time
='2m')
3155 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3157 output
= check_output('ip address show dev veth99 scope global')
3159 self
.assertRegex(output
, r
'inet6 2600::[0-9a-f]*/128 scope global (noprefixroute dynamic|dynamic noprefixroute)')
3161 output
= check_output('ip -6 route show dev veth99')
3163 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3164 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3166 stop_dnsmasq(dnsmasq_pid_file
)
3167 start_dnsmasq(ipv6_range
='2600::30,2600::40', lease_time
='2m')
3169 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3170 print('Wait for the dynamic address to be renewed')
3173 self
.wait_online(['veth99:routable'])
3175 output
= check_output('ip -6 route show dev veth99')
3177 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3178 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3180 def test_dhcp_keep_configuration_dhcp(self
):
3181 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
3183 self
.wait_online(['veth-peer:carrier'])
3184 start_dnsmasq(lease_time
='2m')
3185 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3187 output
= check_output('ip address show dev veth99 scope global')
3189 self
.assertRegex(output
, r
'192.168.5.*')
3191 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3193 self
.assertRegex(output
, r
'192.168.5.*')
3195 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
3196 stop_dnsmasq(dnsmasq_pid_file
)
3198 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3199 print('Wait for the dynamic address to be expired')
3202 print('The lease address should be kept after lease expired')
3203 output
= check_output('ip address show dev veth99 scope global')
3205 self
.assertRegex(output
, r
'192.168.5.*')
3207 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3209 self
.assertRegex(output
, r
'192.168.5.*')
3211 check_output('systemctl stop systemd-networkd')
3213 print('The lease address should be kept after networkd stopped')
3214 output
= check_output('ip address show dev veth99 scope global')
3216 self
.assertRegex(output
, r
'192.168.5.*')
3218 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3220 self
.assertRegex(output
, r
'192.168.5.*')
3223 self
.wait_online(['veth-peer:routable'])
3225 print('Still the lease address should be kept after networkd restarted')
3226 output
= check_output('ip address show dev veth99 scope global')
3228 self
.assertRegex(output
, r
'192.168.5.*')
3230 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3232 self
.assertRegex(output
, r
'192.168.5.*')
3234 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
3235 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
3237 self
.wait_online(['veth-peer:carrier'])
3238 start_dnsmasq(lease_time
='2m')
3239 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3241 output
= check_output('ip address show dev veth99 scope global')
3243 self
.assertRegex(output
, r
'192.168.5.*')
3245 stop_dnsmasq(dnsmasq_pid_file
)
3246 check_output('systemctl stop systemd-networkd')
3248 output
= check_output('ip address show dev veth99 scope global')
3250 self
.assertRegex(output
, r
'192.168.5.*')
3253 self
.wait_online(['veth-peer:routable'])
3255 output
= check_output('ip address show dev veth99 scope global')
3257 self
.assertNotRegex(output
, r
'192.168.5.*')
3259 def test_dhcp_client_reuse_address_as_static(self
):
3260 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
3262 self
.wait_online(['veth-peer:carrier'])
3264 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3266 # link become 'routable' when at least one protocol provide an valid address.
3267 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3268 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3270 output
= check_output('ip address show dev veth99 scope global')
3272 self
.assertRegex(output
, '192.168.5')
3273 self
.assertRegex(output
, '2600::')
3275 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
3276 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
3277 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
3278 print(static_network
)
3280 remove_unit_from_networkd_path(['dhcp-client.network'])
3282 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
3283 f
.write(static_network
)
3285 # When networkd started, the links are already configured, so let's wait for 5 seconds
3286 # the links to be re-configured.
3288 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3290 output
= check_output('ip -4 address show dev veth99 scope global')
3292 self
.assertRegex(output
, '192.168.5')
3293 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3295 output
= check_output('ip -6 address show dev veth99 scope global')
3297 self
.assertRegex(output
, '2600::')
3298 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3300 @expectedFailureIfModuleIsNotAvailable('vrf')
3301 def test_dhcp_client_vrf(self
):
3302 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
3303 '25-vrf.netdev', '25-vrf.network')
3305 self
.wait_online(['veth-peer:carrier'])
3307 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
3309 # link become 'routable' when at least one protocol provide an valid address.
3310 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3311 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3313 print('## ip -d link show dev vrf99')
3314 output
= check_output('ip -d link show dev vrf99')
3316 self
.assertRegex(output
, 'vrf table 42')
3318 print('## ip address show vrf vrf99')
3319 output
= check_output('ip address show vrf vrf99')
3321 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3322 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3323 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3324 self
.assertRegex(output
, 'inet6 .* scope link')
3326 print('## ip address show dev veth99')
3327 output
= check_output('ip address show dev veth99')
3329 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3330 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3331 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3332 self
.assertRegex(output
, 'inet6 .* scope link')
3334 print('## ip route show vrf vrf99')
3335 output
= check_output('ip route show vrf vrf99')
3337 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
3338 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
3339 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
3340 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
3341 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
3343 print('## ip route show table main dev veth99')
3344 output
= check_output('ip route show table main dev veth99')
3346 self
.assertEqual(output
, '')
3348 def test_dhcp_client_gateway_ipv4(self
):
3349 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3350 'dhcp-client-gateway-ipv4.network')
3352 self
.wait_online(['veth-peer:carrier'])
3354 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3356 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3358 self
.assertRegex(output
, '10.0.0.0/8 via 192.168.5.1 proto static')
3360 def test_dhcp_client_gateway_ipv6(self
):
3361 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3362 'dhcp-client-gateway-ipv6.network')
3364 self
.wait_online(['veth-peer:carrier'])
3366 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3368 output
= check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
3370 self
.assertRegex(output
, 'via fe80::1034:56ff:fe78:9abd')
3372 def test_dhcp_client_gateway_onlink_implicit(self
):
3373 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3374 'dhcp-client-gateway-onlink-implicit.network')
3376 self
.wait_online(['veth-peer:carrier'])
3378 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3380 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3382 self
.assertRegex(output
, '192.168.5')
3384 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3386 self
.assertRegex(output
, 'onlink')
3387 output
= check_output('ip route list dev veth99 192.168.100.0/24')
3389 self
.assertRegex(output
, 'onlink')
3391 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
3392 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3393 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
3395 self
.wait_online(['veth-peer:carrier'])
3396 start_dnsmasq(lease_time
='2m')
3397 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3399 output
= check_output('ip address show dev veth99')
3402 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3403 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3404 output
= check_output('ip -6 address show dev veth99 scope link')
3405 self
.assertRegex(output
, 'inet6 .* scope link')
3406 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3407 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3408 output
= check_output('ip -4 address show dev veth99 scope link')
3409 self
.assertNotRegex(output
, 'inet .* scope link')
3411 print('Wait for the dynamic address to be expired')
3414 output
= check_output('ip address show dev veth99')
3417 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3418 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3419 output
= check_output('ip -6 address show dev veth99 scope link')
3420 self
.assertRegex(output
, 'inet6 .* scope link')
3421 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3422 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3423 output
= check_output('ip -4 address show dev veth99 scope link')
3424 self
.assertNotRegex(output
, 'inet .* scope link')
3426 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
3428 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
3429 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3430 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
3432 self
.wait_online(['veth99:degraded', 'veth-peer:routable'])
3434 output
= check_output('ip address show dev veth99')
3437 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3438 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3439 output
= check_output('ip -6 address show dev veth99 scope link')
3440 self
.assertRegex(output
, 'inet6 .* scope link')
3441 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3442 self
.assertNotRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3443 output
= check_output('ip -4 address show dev veth99 scope link')
3444 self
.assertRegex(output
, 'inet .* scope link')
3446 def test_dhcp_client_route_remove_on_renew(self
):
3447 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3448 'dhcp-client-ipv4-only-ipv6-disabled.network')
3450 self
.wait_online(['veth-peer:carrier'])
3451 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
3452 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3454 # test for issue #12490
3456 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3458 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3460 for line
in output
.splitlines():
3461 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3462 address1
= line
.split()[1].split('/')[0]
3465 output
= check_output('ip -4 route show dev veth99')
3467 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3468 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3470 stop_dnsmasq(dnsmasq_pid_file
)
3471 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
3473 print('Wait for the dynamic address to be expired')
3476 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3478 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3480 for line
in output
.splitlines():
3481 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3482 address2
= line
.split()[1].split('/')[0]
3485 self
.assertNotEqual(address1
, address2
)
3487 output
= check_output('ip -4 route show dev veth99')
3489 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3490 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3491 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
3492 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
3494 def test_dhcp_client_use_dns_yes(self
):
3495 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-yes.network')
3498 self
.wait_online(['veth-peer:carrier'])
3499 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3500 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3502 # link become 'routable' when at least one protocol provide an valid address.
3503 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3504 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3507 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3509 self
.assertRegex(output
, '192.168.5.1')
3510 self
.assertRegex(output
, '2600::1')
3512 def test_dhcp_client_use_dns_no(self
):
3513 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-no.network')
3516 self
.wait_online(['veth-peer:carrier'])
3517 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3518 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3520 # link become 'routable' when at least one protocol provide an valid address.
3521 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3522 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3525 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3527 self
.assertNotRegex(output
, '192.168.5.1')
3528 self
.assertNotRegex(output
, '2600::1')
3530 def test_dhcp_client_use_dns_ipv4(self
):
3531 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4.network')
3534 self
.wait_online(['veth-peer:carrier'])
3535 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3536 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3538 # link become 'routable' when at least one protocol provide an valid address.
3539 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3540 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3543 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3545 self
.assertRegex(output
, '192.168.5.1')
3546 self
.assertNotRegex(output
, '2600::1')
3548 def test_dhcp_client_use_dns_ipv4_and_ra(self
):
3549 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4-and-ra.network')
3552 self
.wait_online(['veth-peer:carrier'])
3553 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3554 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3556 # link become 'routable' when at least one protocol provide an valid address.
3557 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3558 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3561 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3563 self
.assertRegex(output
, '192.168.5.1')
3564 self
.assertRegex(output
, '2600::1')
3566 def test_dhcp_client_use_domains(self
):
3567 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-domains.network')
3570 self
.wait_online(['veth-peer:carrier'])
3571 start_dnsmasq('--dhcp-option=option:domain-search,example.com')
3572 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3574 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3576 self
.assertRegex(output
, 'Search Domains: example.com')
3579 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
3581 self
.assertRegex(output
, 'example.com')
3583 def test_dhcp_client_decline(self
):
3584 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-decline.network', 'dhcp-client-decline.network')
3587 self
.wait_online(['veth-peer:carrier'])
3588 rc
= call(*wait_online_cmd
, '--timeout=10s', '--interface=veth99:routable', env
=env
)
3589 self
.assertTrue(rc
== 1)
3591 class NetworkdIPv6PrefixTests(unittest
.TestCase
, Utilities
):
3596 'ipv6ra-prefix-client.network',
3597 'ipv6ra-prefix.network'
3601 remove_links(self
.links
)
3602 stop_networkd(show_logs
=False)
3606 remove_links(self
.links
)
3607 remove_unit_from_networkd_path(self
.units
)
3608 stop_networkd(show_logs
=True)
3610 def test_ipv6_route_prefix(self
):
3611 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client.network', 'ipv6ra-prefix.network')
3614 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3616 output
= check_output('ip -6 route show dev veth-peer')
3618 self
.assertRegex(output
, '2001:db8:0:1::/64 proto ra')
3620 output
= check_output('ip addr show dev veth99')
3622 self
.assertNotRegex(output
, '2001:db8:0:1')
3623 self
.assertRegex(output
, '2001:db8:0:2')
3625 class NetworkdMTUTests(unittest
.TestCase
, Utilities
):
3630 '12-dummy-mtu.netdev',
3631 '12-dummy-mtu.link',
3636 remove_links(self
.links
)
3637 stop_networkd(show_logs
=False)
3641 remove_links(self
.links
)
3642 remove_unit_from_networkd_path(self
.units
)
3643 stop_networkd(show_logs
=True)
3645 def check_mtu(self
, mtu
, ipv6_mtu
=None, reset
=True):
3651 self
.wait_online(['dummy98:routable'])
3652 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
3653 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
3655 # test normal restart
3657 self
.wait_online(['dummy98:routable'])
3658 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
3659 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
3662 self
.reset_check_mtu(mtu
, ipv6_mtu
)
3664 def reset_check_mtu(self
, mtu
, ipv6_mtu
=None):
3665 ''' test setting mtu/ipv6_mtu with interface already up '''
3668 # note - changing the device mtu resets the ipv6 mtu
3669 run('ip link set up mtu 1501 dev dummy98')
3670 run('ip link set up mtu 1500 dev dummy98')
3671 self
.assertEqual(read_link_attr('dummy98', 'mtu'), '1500')
3672 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), '1500')
3674 self
.check_mtu(mtu
, ipv6_mtu
, reset
=False)
3676 def test_mtu_network(self
):
3677 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
3678 self
.check_mtu('1600')
3680 def test_mtu_netdev(self
):
3681 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network', dropins
=False)
3682 # note - MTU set by .netdev happens ONLY at device creation!
3683 self
.check_mtu('1600', reset
=False)
3685 def test_mtu_link(self
):
3686 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', dropins
=False)
3687 # must reload udev because it only picks up new files after 3 second delay
3688 call('udevadm control --reload')
3689 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
3690 self
.check_mtu('1600', reset
=False)
3692 def test_ipv6_mtu(self
):
3693 ''' set ipv6 mtu without setting device mtu '''
3694 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
3695 self
.check_mtu('1500', '1400')
3697 def test_ipv6_mtu_toolarge(self
):
3698 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
3699 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
3700 self
.check_mtu('1500', '1500')
3702 def test_mtu_network_ipv6_mtu(self
):
3703 ''' set ipv6 mtu and set device mtu via network file '''
3704 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
3705 self
.check_mtu('1600', '1550')
3707 def test_mtu_netdev_ipv6_mtu(self
):
3708 ''' set ipv6 mtu and set device mtu via netdev file '''
3709 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
3710 self
.check_mtu('1600', '1550', reset
=False)
3712 def test_mtu_link_ipv6_mtu(self
):
3713 ''' set ipv6 mtu and set device mtu via link file '''
3714 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
3715 # must reload udev because it only picks up new files after 3 second delay
3716 call('udevadm control --reload')
3717 self
.check_mtu('1600', '1550', reset
=False)
3720 if __name__
== '__main__':
3721 parser
= argparse
.ArgumentParser()
3722 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
3723 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
3724 parser
.add_argument('--resolved', help='Path to systemd-resolved', dest
='resolved_bin')
3725 parser
.add_argument('--udevd', help='Path to systemd-udevd', dest
='udevd_bin')
3726 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
3727 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
3728 parser
.add_argument('--resolvectl', help='Path to resolvectl', dest
='resolvectl_bin')
3729 parser
.add_argument('--timedatectl', help='Path to timedatectl', dest
='timedatectl_bin')
3730 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
3731 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
3732 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
3733 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
3734 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
3735 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
3738 if ns
.networkd_bin
or ns
.resolved_bin
or ns
.udevd_bin
or ns
.wait_online_bin
or ns
.networkctl_bin
or ns
.resolvectl_bin
or ns
.timedatectl_bin
:
3739 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
3740 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
3741 resolved_bin
= os
.path
.join(ns
.build_dir
, 'systemd-resolved')
3742 udevd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-udevd')
3743 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
3744 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
3745 resolvectl_bin
= os
.path
.join(ns
.build_dir
, 'resolvectl')
3746 timedatectl_bin
= os
.path
.join(ns
.build_dir
, 'timedatectl')
3749 networkd_bin
= ns
.networkd_bin
3751 resolved_bin
= ns
.resolved_bin
3753 udevd_bin
= ns
.udevd_bin
3754 if ns
.wait_online_bin
:
3755 wait_online_bin
= ns
.wait_online_bin
3756 if ns
.networkctl_bin
:
3757 networkctl_bin
= ns
.networkctl_bin
3758 if ns
.resolvectl_bin
:
3759 resolvectl_bin
= ns
.resolvectl_bin
3760 if ns
.timedatectl_bin
:
3761 timedatectl_bin
= ns
.timedatectl_bin
3763 use_valgrind
= ns
.use_valgrind
3764 enable_debug
= ns
.enable_debug
3765 asan_options
= ns
.asan_options
3766 lsan_options
= ns
.lsan_options
3767 ubsan_options
= ns
.ubsan_options
3770 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
3771 resolvectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin
]
3772 timedatectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin
]
3773 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
3775 networkctl_cmd
= [networkctl_bin
]
3776 resolvectl_cmd
= [resolvectl_bin
]
3777 timedatectl_cmd
= [timedatectl_bin
]
3778 wait_online_cmd
= [wait_online_bin
]
3781 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
3783 env
.update({ 'ASAN_OPTIONS' : asan_options
})
3785 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
3787 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
3790 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,