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
)
172 def expectedFailureIfPIEIsNotAvailable():
174 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
175 rc
= call('tc qdisc add dev dummy98 parent root pie', stderr
=subprocess
.DEVNULL
)
176 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
180 return unittest
.expectedFailure(func
)
184 def expectedFailureIfHHFIsNotAvailable():
186 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
187 rc
= call('tc qdisc add dev dummy98 parent root hhf', stderr
=subprocess
.DEVNULL
)
188 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
192 return unittest
.expectedFailure(func
)
199 os
.makedirs(network_unit_file_path
, exist_ok
=True)
200 os
.makedirs(networkd_ci_path
, exist_ok
=True)
202 shutil
.rmtree(networkd_ci_path
)
203 copytree(os
.path
.join(os
.path
.dirname(os
.path
.abspath(__file__
)), 'conf'), networkd_ci_path
)
205 for u
in ['systemd-networkd.socket', 'systemd-networkd.service', 'systemd-resolved.service',
206 'systemd-udevd-kernel.socket', 'systemd-udevd-control.socket', 'systemd-udevd.service',
207 'firewalld.service']:
208 if call(f
'systemctl is-active --quiet {u}') == 0:
209 check_output(f
'systemctl stop {u}')
210 running_units
.append(u
)
214 'StartLimitIntervalSec=0',
221 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin
,
225 drop_in
+= ['ExecStart=!!' + networkd_bin
]
227 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
229 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
231 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
233 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
234 if asan_options
or lsan_options
or ubsan_options
:
235 drop_in
+= ['SystemCallFilter=']
236 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
237 drop_in
+= ['MemoryDenyWriteExecute=no']
239 os
.makedirs('/run/systemd/system/systemd-networkd.service.d', exist_ok
=True)
240 with
open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode
='w') as f
:
241 f
.write('\n'.join(drop_in
))
249 drop_in
+= ['ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + resolved_bin
]
251 drop_in
+= ['ExecStart=!!' + resolved_bin
]
253 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
255 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
257 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
259 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
260 if asan_options
or lsan_options
or ubsan_options
:
261 drop_in
+= ['SystemCallFilter=']
262 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
263 drop_in
+= ['MemoryDenyWriteExecute=no']
265 os
.makedirs('/run/systemd/system/systemd-resolved.service.d', exist_ok
=True)
266 with
open('/run/systemd/system/systemd-resolved.service.d/00-override.conf', mode
='w') as f
:
267 f
.write('\n'.join(drop_in
))
272 'ExecStart=!!' + udevd_bin
,
275 os
.makedirs('/run/systemd/system/systemd-udevd.service.d', exist_ok
=True)
276 with
open('/run/systemd/system/systemd-udevd.service.d/00-override.conf', mode
='w') as f
:
277 f
.write('\n'.join(drop_in
))
279 check_output('systemctl daemon-reload')
280 print(check_output('systemctl cat systemd-networkd.service'))
281 print(check_output('systemctl cat systemd-resolved.service'))
282 print(check_output('systemctl cat systemd-udevd.service'))
283 check_output('systemctl restart systemd-resolved')
284 check_output('systemctl restart systemd-udevd')
286 def tearDownModule():
289 shutil
.rmtree(networkd_ci_path
)
291 for u
in ['systemd-networkd.service', 'systemd-resolved.service']:
292 check_output(f
'systemctl stop {u}')
294 shutil
.rmtree('/run/systemd/system/systemd-networkd.service.d')
295 shutil
.rmtree('/run/systemd/system/systemd-resolved.service.d')
296 shutil
.rmtree('/run/systemd/system/systemd-udevd.service.d')
297 check_output('systemctl daemon-reload')
298 check_output('systemctl restart systemd-udevd.service')
300 for u
in running_units
:
301 check_output(f
'systemctl start {u}')
303 def read_link_attr(*args
):
304 with
open(os
.path
.join('/sys/class/net/', *args
)) as f
:
305 return f
.readline().strip()
307 def read_bridge_port_attr(bridge
, link
, attribute
):
308 path_bridge
= os
.path
.join('/sys/devices/virtual/net', bridge
)
309 path_port
= 'lower_' + link
+ '/brport'
310 path
= os
.path
.join(path_bridge
, path_port
)
312 with
open(os
.path
.join(path
, attribute
)) as f
:
313 return f
.readline().strip()
315 def link_exists(link
):
316 return os
.path
.exists(os
.path
.join('/sys/class/net', link
))
318 def remove_links(links
):
320 if link_exists(link
):
321 call('ip link del dev', link
)
324 def remove_fou_ports(ports
):
326 call('ip fou del port', port
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
328 def remove_routing_policy_rule_tables(tables
):
332 rc
= call('ip rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
334 def remove_routes(routes
):
335 for route_type
, addr
in routes
:
336 call('ip route del', route_type
, addr
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
338 def remove_l2tp_tunnels(tunnel_ids
):
339 output
= check_output('ip l2tp show tunnel')
340 for tid
in tunnel_ids
:
341 words
='Tunnel ' + tid
+ ', encap'
343 call('ip l2tp del tunnel tid', tid
)
346 def read_ipv6_sysctl_attr(link
, attribute
):
347 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, link
), attribute
)) as f
:
348 return f
.readline().strip()
350 def read_ipv4_sysctl_attr(link
, attribute
):
351 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv4_path
, link
), attribute
)) as f
:
352 return f
.readline().strip()
354 def copy_unit_to_networkd_unit_path(*units
, dropins
=True):
355 """Copy networkd unit files into the testbed.
357 Any networkd unit file type can be specified, as well as drop-in files.
359 By default, all drop-ins for a specified unit file are copied in;
360 to avoid that specify dropins=False.
362 When a drop-in file is specified, its unit file is also copied in automatically.
366 if dropins
and os
.path
.exists(os
.path
.join(networkd_ci_path
, unit
+ '.d')):
367 copytree(os
.path
.join(networkd_ci_path
, unit
+ '.d'), os
.path
.join(network_unit_file_path
, unit
+ '.d'))
368 if unit
.endswith('.conf'):
370 dropindir
= os
.path
.join(network_unit_file_path
, os
.path
.dirname(dropin
))
371 os
.makedirs(dropindir
, exist_ok
=True)
372 shutil
.copy(os
.path
.join(networkd_ci_path
, dropin
), dropindir
)
373 unit
= os
.path
.dirname(dropin
).rstrip('.d')
374 shutil
.copy(os
.path
.join(networkd_ci_path
, unit
), network_unit_file_path
)
376 def remove_unit_from_networkd_path(units
):
377 """Remove previously copied unit files from the testbed.
379 Drop-ins will be removed automatically.
382 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
))):
383 os
.remove(os
.path
.join(network_unit_file_path
, unit
))
384 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
+ '.d'))):
385 shutil
.rmtree(os
.path
.join(network_unit_file_path
, unit
+ '.d'))
387 def start_dnsmasq(additional_options
='', ipv4_range
='192.168.5.10,192.168.5.200', ipv6_range
='2600::10,2600::20', lease_time
='1h'):
388 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
389 check_output(dnsmasq_command
)
391 def stop_dnsmasq(pid_file
):
392 if os
.path
.exists(pid_file
):
393 with
open(pid_file
, 'r') as f
:
394 pid
= f
.read().rstrip(' \t\r\n\0')
395 os
.kill(int(pid
), signal
.SIGTERM
)
399 def search_words_in_dnsmasq_log(words
, show_all
=False):
400 if os
.path
.exists(dnsmasq_log_file
):
401 with
open (dnsmasq_log_file
) as in_file
:
402 contents
= in_file
.read()
405 for line
in contents
.splitlines():
408 print("%s, %s" % (words
, line
))
412 def remove_lease_file():
413 if os
.path
.exists(os
.path
.join(networkd_ci_path
, 'lease')):
414 os
.remove(os
.path
.join(networkd_ci_path
, 'lease'))
416 def remove_log_file():
417 if os
.path
.exists(dnsmasq_log_file
):
418 os
.remove(dnsmasq_log_file
)
420 def remove_networkd_state_files():
421 if os
.path
.exists(os
.path
.join(networkd_runtime_directory
, 'state')):
422 os
.remove(os
.path
.join(networkd_runtime_directory
, 'state'))
424 def stop_networkd(show_logs
=True, remove_state_files
=True):
426 invocation_id
= check_output('systemctl show systemd-networkd -p InvocationID --value')
427 check_output('systemctl stop systemd-networkd')
429 print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
))
430 if remove_state_files
:
431 remove_networkd_state_files()
433 def start_networkd(sleep_sec
=0):
434 check_output('systemctl start systemd-networkd')
436 time
.sleep(sleep_sec
)
438 def restart_networkd(sleep_sec
=0, show_logs
=True, remove_state_files
=True):
439 stop_networkd(show_logs
, remove_state_files
)
440 start_networkd(sleep_sec
)
444 def check_link_exists(self
, link
):
445 self
.assertTrue(link_exists(link
))
447 def wait_operstate(self
, link
, operstate
='degraded', setup_state
='configured', setup_timeout
=5, fail_assert
=True):
448 """Wait for the link to reach the specified operstate and/or setup state.
450 Specify None or '' for either operstate or setup_state to ignore that state.
451 This will recheck until the state conditions are met or the timeout expires.
453 If the link successfully matches the requested state, this returns True.
454 If this times out waiting for the link to match, the behavior depends on the
455 'fail_assert' parameter; if True, this causes a test assertion failure,
456 otherwise this returns False. The default is to cause assertion failure.
458 Note that this function matches on *exactly* the given operstate and setup_state.
459 To wait for a link to reach *or exceed* a given operstate, use wait_online().
466 for secs
in range(setup_timeout
+ 1):
467 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
, env
=env
)
469 if re
.search(rf
'(?m)^\s*State:\s+{operstate}\s+\({setup_state}\)\s*$', output
):
471 # don't bother sleeping if time is up
472 if secs
< setup_timeout
:
475 self
.fail(f
'Timed out waiting for {link} to reach state {operstate}/{setup_state}')
478 def wait_online(self
, links_with_operstate
, timeout
='20s', bool_any
=False, setup_state
='configured', setup_timeout
=5):
479 """Wait for the link(s) to reach the specified operstate and/or setup state.
481 This is similar to wait_operstate() but can be used for multiple links,
482 and it also calls systemd-networkd-wait-online to wait for the given operstate.
483 The operstate should be specified in the link name, like 'eth0:degraded'.
484 If just a link name is provided, wait-online's default operstate to wait for is degraded.
486 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
487 'setup_timeout' controls the per-link timeout waiting for the setup_state.
489 Set 'bool_any' to True to wait for any (instead of all) of the given links.
490 If this is set, no setup_state checks are done.
492 Note that this function waits for the link(s) to reach *or exceed* the given operstate.
493 However, the setup_state, if specified, must be matched *exactly*.
495 This returns if the link(s) reached the requested operstate/setup_state; otherwise it
496 raises CalledProcessError or fails test assertion.
498 args
= wait_online_cmd
+ [f
'--timeout={timeout}'] + [f
'--interface={link}' for link
in links_with_operstate
]
502 check_output(*args
, env
=env
)
503 except subprocess
.CalledProcessError
:
504 for link
in links_with_operstate
:
505 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
.split(':')[0], env
=env
)
508 if not bool_any
and setup_state
:
509 for link
in links_with_operstate
:
510 self
.wait_operstate(link
.split(':')[0], None, setup_state
, setup_timeout
)
512 def wait_address(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
513 for i
in range(timeout_sec
):
516 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
517 if re
.search(address_regex
, output
):
520 self
.assertRegex(output
, address_regex
)
522 class NetworkctlTests(unittest
.TestCase
, Utilities
):
532 '11-dummy-mtu.netdev',
536 '25-address-static.network',
538 'netdev-link-local-addressing-yes.network',
542 remove_links(self
.links
)
543 stop_networkd(show_logs
=False)
546 remove_links(self
.links
)
547 remove_unit_from_networkd_path(self
.units
)
548 stop_networkd(show_logs
=True)
550 @expectedFailureIfAlternativeNameIsNotAvailable()
551 def test_altname(self
):
552 copy_unit_to_networkd_unit_path('netdev-link-local-addressing-yes.network', '12-dummy.netdev', '12-dummy.link')
553 check_output('udevadm control --reload')
555 self
.wait_online(['dummy98:degraded'])
557 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
558 self
.assertRegex(output
, 'hogehogehogehogehogehoge')
560 def test_reconfigure(self
):
561 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
563 self
.wait_online(['dummy98:routable'])
565 output
= check_output('ip -4 address show dev dummy98')
567 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
568 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
569 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
571 check_output('ip address del 10.1.2.3/16 dev dummy98')
572 check_output('ip address del 10.1.2.4/16 dev dummy98')
573 check_output('ip address del 10.2.2.4/16 dev dummy98')
575 check_output(*networkctl_cmd
, 'reconfigure', 'dummy98', env
=env
)
576 self
.wait_online(['dummy98:routable'])
578 output
= check_output('ip -4 address show dev dummy98')
580 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
581 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
582 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
584 def test_reload(self
):
587 copy_unit_to_networkd_unit_path('11-dummy.netdev')
588 check_output(*networkctl_cmd
, 'reload', env
=env
)
589 self
.wait_operstate('test1', 'off', setup_state
='unmanaged')
591 copy_unit_to_networkd_unit_path('11-dummy.network')
592 check_output(*networkctl_cmd
, 'reload', env
=env
)
593 self
.wait_online(['test1:degraded'])
595 remove_unit_from_networkd_path(['11-dummy.network'])
596 check_output(*networkctl_cmd
, 'reload', env
=env
)
597 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
599 remove_unit_from_networkd_path(['11-dummy.netdev'])
600 check_output(*networkctl_cmd
, 'reload', env
=env
)
601 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
603 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
604 check_output(*networkctl_cmd
, 'reload', env
=env
)
605 self
.wait_operstate('test1', 'degraded')
608 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
611 self
.wait_online(['test1:degraded'])
613 output
= check_output(*networkctl_cmd
, 'list', env
=env
)
614 self
.assertRegex(output
, '1 lo ')
615 self
.assertRegex(output
, 'test1')
617 output
= check_output(*networkctl_cmd
, 'list', 'test1', env
=env
)
618 self
.assertNotRegex(output
, '1 lo ')
619 self
.assertRegex(output
, 'test1')
621 output
= check_output(*networkctl_cmd
, 'list', 'te*', env
=env
)
622 self
.assertNotRegex(output
, '1 lo ')
623 self
.assertRegex(output
, 'test1')
625 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'te*', env
=env
)
626 self
.assertNotRegex(output
, '1: lo ')
627 self
.assertRegex(output
, 'test1')
629 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'tes[a-z][0-9]', env
=env
)
630 self
.assertNotRegex(output
, '1: lo ')
631 self
.assertRegex(output
, 'test1')
634 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
637 self
.wait_online(['test1:degraded'])
639 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
640 self
.assertRegex(output
, 'MTU: 1600')
643 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
645 self
.wait_online(['test1:degraded'])
647 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
649 self
.assertRegex(output
, 'Type: ether')
651 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
653 self
.assertRegex(output
, 'Type: loopback')
655 @expectedFailureIfLinkFileFieldIsNotSet()
656 def test_udev_link_file(self
):
657 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
659 self
.wait_online(['test1:degraded'])
661 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
663 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
664 self
.assertRegex(output
, r
'Network File: /run/systemd/network/11-dummy.network')
666 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
668 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
669 self
.assertRegex(output
, r
'Network File: n/a')
671 def test_delete_links(self
):
672 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
673 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
676 self
.wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
678 check_output(*networkctl_cmd
, 'delete', 'test1', 'veth99', env
=env
)
679 self
.assertFalse(link_exists('test1'))
680 self
.assertFalse(link_exists('veth99'))
681 self
.assertFalse(link_exists('veth-peer'))
683 class NetworkdNetDevTests(unittest
.TestCase
, Utilities
):
685 links_remove_earlier
= [
750 '10-dropin-test.netdev',
754 '13-not-match-udev-property.network',
755 '14-match-udev-property.network',
756 '15-name-conflict-test.netdev',
759 '21-vlan-test1.network',
762 '25-6rd-tunnel.netdev',
764 '25-bond-balanced-tlb.netdev',
766 '25-bridge-configure-without-carrier.network',
768 '25-erspan-tunnel-local-any.netdev',
769 '25-erspan-tunnel.netdev',
770 '25-fou-gretap.netdev',
772 '25-fou-ipip.netdev',
773 '25-fou-ipproto-gre.netdev',
774 '25-fou-ipproto-ipip.netdev',
777 '25-gretap-tunnel-local-any.netdev',
778 '25-gretap-tunnel.netdev',
779 '25-gre-tunnel-any-any.netdev',
780 '25-gre-tunnel-local-any.netdev',
781 '25-gre-tunnel-remote-any.netdev',
782 '25-gre-tunnel.netdev',
784 '25-ip6gretap-tunnel-local-any.netdev',
785 '25-ip6gretap-tunnel.netdev',
786 '25-ip6gre-tunnel-any-any.netdev',
787 '25-ip6gre-tunnel-local-any.netdev',
788 '25-ip6gre-tunnel-remote-any.netdev',
789 '25-ip6gre-tunnel.netdev',
790 '25-ip6tnl-tunnel-any-any.netdev',
791 '25-ip6tnl-tunnel-local-any.netdev',
792 '25-ip6tnl-tunnel-remote-any.netdev',
793 '25-ip6tnl-tunnel.netdev',
794 '25-ipip-tunnel-any-any.netdev',
795 '25-ipip-tunnel-independent.netdev',
796 '25-ipip-tunnel-independent-loopback.netdev',
797 '25-ipip-tunnel-local-any.netdev',
798 '25-ipip-tunnel-remote-any.netdev',
799 '25-ipip-tunnel.netdev',
802 '25-isatap-tunnel.netdev',
807 '25-sit-tunnel-any-any.netdev',
808 '25-sit-tunnel-local-any.netdev',
809 '25-sit-tunnel-remote-any.netdev',
810 '25-sit-tunnel.netdev',
813 '25-tunnel-local-any.network',
814 '25-tunnel-remote-any.network',
819 '25-vti6-tunnel-any-any.netdev',
820 '25-vti6-tunnel-local-any.netdev',
821 '25-vti6-tunnel-remote-any.netdev',
822 '25-vti6-tunnel.netdev',
823 '25-vti-tunnel-any-any.netdev',
824 '25-vti-tunnel-local-any.netdev',
825 '25-vti-tunnel-remote-any.netdev',
826 '25-vti-tunnel.netdev',
829 '25-wireguard-23-peers.netdev',
830 '25-wireguard-23-peers.network',
831 '25-wireguard-preshared-key.txt',
832 '25-wireguard-private-key.txt',
833 '25-wireguard.netdev',
834 '25-wireguard.network',
836 '25-xfrm-independent.netdev',
852 'netdev-link-local-addressing-yes.network',
856 'vxlan-test1.network',
866 remove_fou_ports(self
.fou_ports
)
867 remove_links(self
.links_remove_earlier
)
868 remove_links(self
.links
)
869 stop_networkd(show_logs
=False)
872 remove_fou_ports(self
.fou_ports
)
873 remove_links(self
.links_remove_earlier
)
874 remove_links(self
.links
)
875 remove_unit_from_networkd_path(self
.units
)
876 stop_networkd(show_logs
=True)
878 def test_dropin_and_name_conflict(self
):
879 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
882 self
.wait_online(['dropin-test:off'], setup_state
='unmanaged')
884 output
= check_output('ip link show dropin-test')
886 self
.assertRegex(output
, '00:50:56:c0:00:28')
888 def test_match_udev_property(self
):
889 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
891 self
.wait_online(['dummy98:routable'])
893 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
895 self
.assertRegex(output
, 'Network File: /run/systemd/network/14-match-udev-property')
897 def test_wait_online_any(self
):
898 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
901 self
.wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
903 self
.wait_operstate('bridge99', '(off|no-carrier)', setup_state
='configuring')
904 self
.wait_operstate('test1', 'degraded')
906 def test_bridge(self
):
907 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
910 self
.wait_online(['bridge99:no-carrier'])
912 tick
= os
.sysconf('SC_CLK_TCK')
913 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
914 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
915 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'forward_delay')) / tick
))
916 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'ageing_time')) / tick
))
917 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge', 'priority')))
918 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_querier')))
919 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_snooping')))
920 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'stp_state')))
921 self
.assertEqual(3, int(read_link_attr('bridge99', 'bridge', 'multicast_igmp_version')))
923 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
925 self
.assertRegex(output
, 'Priority: 9')
926 self
.assertRegex(output
, 'STP: yes')
927 self
.assertRegex(output
, 'Multicast IGMP Version: 3')
930 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
933 self
.wait_online(['bond99:off', 'bond98:off'], setup_state
='unmanaged')
935 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
936 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
937 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
938 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
939 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
940 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
941 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
942 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
943 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
944 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
945 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
947 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
948 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
951 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
952 '21-vlan.network', '21-vlan-test1.network')
955 self
.wait_online(['test1:degraded', 'vlan99:routable'])
957 output
= check_output('ip -d link show test1')
959 self
.assertRegex(output
, ' mtu 2000 ')
961 output
= check_output('ip -d link show vlan99')
963 self
.assertRegex(output
, ' mtu 2000 ')
964 self
.assertRegex(output
, 'REORDER_HDR')
965 self
.assertRegex(output
, 'LOOSE_BINDING')
966 self
.assertRegex(output
, 'GVRP')
967 self
.assertRegex(output
, 'MVRP')
968 self
.assertRegex(output
, ' id 99 ')
970 output
= check_output('ip -4 address show dev test1')
972 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
973 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
975 output
= check_output('ip -4 address show dev vlan99')
977 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
979 def test_macvtap(self
):
980 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
981 with self
.subTest(mode
=mode
):
982 if mode
!= 'private':
984 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
985 '11-dummy.netdev', 'macvtap.network')
986 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
987 f
.write('[MACVTAP]\nMode=' + mode
)
990 self
.wait_online(['macvtap99:degraded', 'test1:degraded'])
992 output
= check_output('ip -d link show macvtap99')
994 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
996 def test_macvlan(self
):
997 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
998 with self
.subTest(mode
=mode
):
999 if mode
!= 'private':
1001 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
1002 '11-dummy.netdev', 'macvlan.network')
1003 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
1004 f
.write('[MACVLAN]\nMode=' + mode
)
1007 self
.wait_online(['macvlan99:degraded', 'test1:degraded'])
1009 output
= check_output('ip -d link show test1')
1011 self
.assertRegex(output
, ' mtu 2000 ')
1013 output
= check_output('ip -d link show macvlan99')
1015 self
.assertRegex(output
, ' mtu 2000 ')
1016 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
1018 @expectedFailureIfModuleIsNotAvailable('ipvlan')
1019 def test_ipvlan(self
):
1020 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1021 with self
.subTest(mode
=mode
, flag
=flag
):
1024 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
1025 '11-dummy.netdev', 'ipvlan.network')
1026 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
1027 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
1030 self
.wait_online(['ipvlan99:degraded', 'test1:degraded'])
1032 output
= check_output('ip -d link show ipvlan99')
1034 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
1036 @expectedFailureIfModuleIsNotAvailable('ipvtap')
1037 def test_ipvtap(self
):
1038 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1039 with self
.subTest(mode
=mode
, flag
=flag
):
1042 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
1043 '11-dummy.netdev', 'ipvtap.network')
1044 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
1045 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
1048 self
.wait_online(['ipvtap99:degraded', 'test1:degraded'])
1050 output
= check_output('ip -d link show ipvtap99')
1052 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
1054 def test_veth(self
):
1055 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
1058 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
1060 output
= check_output('ip -d link show veth99')
1062 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
1063 output
= check_output('ip -d link show veth-peer')
1065 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
1068 copy_unit_to_networkd_unit_path('25-tun.netdev')
1071 self
.wait_online(['tun99:off'], setup_state
='unmanaged')
1073 output
= check_output('ip -d link show tun99')
1075 # Old ip command does not support IFF_ flags
1076 self
.assertRegex(output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
1079 copy_unit_to_networkd_unit_path('25-tap.netdev')
1082 self
.wait_online(['tap99:off'], setup_state
='unmanaged')
1084 output
= check_output('ip -d link show tap99')
1086 # Old ip command does not support IFF_ flags
1087 self
.assertRegex(output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
1089 @expectedFailureIfModuleIsNotAvailable('vrf')
1091 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
1094 self
.wait_online(['vrf99:carrier'])
1096 @expectedFailureIfModuleIsNotAvailable('vcan')
1097 def test_vcan(self
):
1098 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
1101 self
.wait_online(['vcan99:carrier'])
1103 @expectedFailureIfModuleIsNotAvailable('vxcan')
1104 def test_vxcan(self
):
1105 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
1108 self
.wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
1110 @expectedFailureIfModuleIsNotAvailable('wireguard')
1111 def test_wireguard(self
):
1112 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
1113 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
1114 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt')
1116 self
.wait_online(['wg99:carrier', 'wg98:routable'])
1118 if shutil
.which('wg'):
1121 output
= check_output('wg show wg99 listen-port')
1122 self
.assertRegex(output
, '51820')
1123 output
= check_output('wg show wg99 fwmark')
1124 self
.assertRegex(output
, '0x4d2')
1125 output
= check_output('wg show wg99 allowed-ips')
1126 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
1127 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
1128 output
= check_output('wg show wg99 persistent-keepalive')
1129 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
1130 output
= check_output('wg show wg99 endpoints')
1131 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
1132 output
= check_output('wg show wg99 private-key')
1133 self
.assertRegex(output
, r
'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
1134 output
= check_output('wg show wg99 preshared-keys')
1135 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
1136 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
1138 output
= check_output('wg show wg98 private-key')
1139 self
.assertRegex(output
, r
'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
1141 def test_geneve(self
):
1142 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
1145 self
.wait_online(['geneve99:degraded'])
1147 output
= check_output('ip -d link show geneve99')
1149 self
.assertRegex(output
, '192.168.22.1')
1150 self
.assertRegex(output
, '6082')
1151 self
.assertRegex(output
, 'udpcsum')
1152 self
.assertRegex(output
, 'udp6zerocsumrx')
1154 def test_ipip_tunnel(self
):
1155 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
1156 '25-ipip-tunnel.netdev', '25-tunnel.network',
1157 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1158 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1159 '25-ipip-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1161 self
.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'ipiptun96:routable', 'dummy98:degraded'])
1163 output
= check_output('ip -d link show ipiptun99')
1165 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98')
1166 output
= check_output('ip -d link show ipiptun98')
1168 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98')
1169 output
= check_output('ip -d link show ipiptun97')
1171 self
.assertRegex(output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98')
1172 output
= check_output('ip -d link show ipiptun96')
1174 self
.assertRegex(output
, 'ipip (ipip )?remote any local any dev dummy98')
1176 def test_gre_tunnel(self
):
1177 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
1178 '25-gre-tunnel.netdev', '25-tunnel.network',
1179 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1180 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1181 '25-gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1183 self
.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'gretun96:routable', 'dummy98:degraded'])
1185 output
= check_output('ip -d link show gretun99')
1187 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1188 self
.assertRegex(output
, 'ikey 1.2.3.103')
1189 self
.assertRegex(output
, 'okey 1.2.4.103')
1190 self
.assertRegex(output
, 'iseq')
1191 self
.assertRegex(output
, 'oseq')
1192 output
= check_output('ip -d link show gretun98')
1194 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
1195 self
.assertRegex(output
, 'ikey 0.0.0.104')
1196 self
.assertRegex(output
, 'okey 0.0.0.104')
1197 self
.assertNotRegex(output
, 'iseq')
1198 self
.assertNotRegex(output
, 'oseq')
1199 output
= check_output('ip -d link show gretun97')
1201 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
1202 self
.assertRegex(output
, 'ikey 0.0.0.105')
1203 self
.assertRegex(output
, 'okey 0.0.0.105')
1204 self
.assertNotRegex(output
, 'iseq')
1205 self
.assertNotRegex(output
, 'oseq')
1206 output
= check_output('ip -d link show gretun96')
1208 self
.assertRegex(output
, 'gre remote any local any dev dummy98')
1209 self
.assertRegex(output
, 'ikey 0.0.0.106')
1210 self
.assertRegex(output
, 'okey 0.0.0.106')
1211 self
.assertNotRegex(output
, 'iseq')
1212 self
.assertNotRegex(output
, 'oseq')
1214 def test_ip6gre_tunnel(self
):
1215 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
1216 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
1217 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1218 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1219 '25-ip6gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1222 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1224 self
.check_link_exists('dummy98')
1225 self
.check_link_exists('ip6gretun99')
1226 self
.check_link_exists('ip6gretun98')
1227 self
.check_link_exists('ip6gretun97')
1228 self
.check_link_exists('ip6gretun96')
1230 output
= check_output('ip -d link show ip6gretun99')
1232 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1233 output
= check_output('ip -d link show ip6gretun98')
1235 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
1236 output
= check_output('ip -d link show ip6gretun97')
1238 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
1239 output
= check_output('ip -d link show ip6gretun96')
1241 self
.assertRegex(output
, 'ip6gre remote any local any dev dummy98')
1243 def test_gretap_tunnel(self
):
1244 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
1245 '25-gretap-tunnel.netdev', '25-tunnel.network',
1246 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1248 self
.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
1250 output
= check_output('ip -d link show gretap99')
1252 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1253 self
.assertRegex(output
, 'ikey 0.0.0.106')
1254 self
.assertRegex(output
, 'okey 0.0.0.106')
1255 self
.assertRegex(output
, 'iseq')
1256 self
.assertRegex(output
, 'oseq')
1257 output
= check_output('ip -d link show gretap98')
1259 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
1260 self
.assertRegex(output
, 'ikey 0.0.0.107')
1261 self
.assertRegex(output
, 'okey 0.0.0.107')
1262 self
.assertRegex(output
, 'iseq')
1263 self
.assertRegex(output
, 'oseq')
1265 def test_ip6gretap_tunnel(self
):
1266 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
1267 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1268 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1270 self
.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
1272 output
= check_output('ip -d link show ip6gretap99')
1274 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1275 output
= check_output('ip -d link show ip6gretap98')
1277 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1279 def test_vti_tunnel(self
):
1280 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
1281 '25-vti-tunnel.netdev', '25-tunnel.network',
1282 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1283 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1284 '25-vti-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1286 self
.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'vtitun96:routable', 'dummy98:degraded'])
1288 output
= check_output('ip -d link show vtitun99')
1290 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1291 output
= check_output('ip -d link show vtitun98')
1293 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
1294 output
= check_output('ip -d link show vtitun97')
1296 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
1297 output
= check_output('ip -d link show vtitun96')
1299 self
.assertRegex(output
, 'vti remote any local any dev dummy98')
1301 def test_vti6_tunnel(self
):
1302 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
1303 '25-vti6-tunnel.netdev', '25-tunnel.network',
1304 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1305 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1307 self
.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
1309 output
= check_output('ip -d link show vti6tun99')
1311 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1312 output
= check_output('ip -d link show vti6tun98')
1314 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1315 output
= check_output('ip -d link show vti6tun97')
1317 self
.assertRegex(output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1319 def test_ip6tnl_tunnel(self
):
1320 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
1321 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1322 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1323 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1325 self
.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
1327 output
= check_output('ip -d link show ip6tnl99')
1329 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1330 output
= check_output('ip -d link show ip6tnl98')
1332 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1333 output
= check_output('ip -d link show ip6tnl97')
1335 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1337 def test_sit_tunnel(self
):
1338 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1339 '25-sit-tunnel.netdev', '25-tunnel.network',
1340 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1341 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1342 '25-sit-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1344 self
.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'sittun96:routable', 'dummy98:degraded'])
1346 output
= check_output('ip -d link show sittun99')
1348 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1349 output
= check_output('ip -d link show sittun98')
1351 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98")
1352 output
= check_output('ip -d link show sittun97')
1354 self
.assertRegex(output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98")
1355 output
= check_output('ip -d link show sittun96')
1357 self
.assertRegex(output
, "sit (ip6ip )?remote any local any dev dummy98")
1359 def test_isatap_tunnel(self
):
1360 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1361 '25-isatap-tunnel.netdev', '25-tunnel.network')
1363 self
.wait_online(['isataptun99:routable', 'dummy98:degraded'])
1365 output
= check_output('ip -d link show isataptun99')
1367 self
.assertRegex(output
, "isatap ")
1369 def test_6rd_tunnel(self
):
1370 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1371 '25-6rd-tunnel.netdev', '25-tunnel.network')
1373 self
.wait_online(['sittun99:routable', 'dummy98:degraded'])
1375 output
= check_output('ip -d link show sittun99')
1377 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1379 @expectedFailureIfERSPANModuleIsNotAvailable()
1380 def test_erspan_tunnel(self
):
1381 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1382 '25-erspan-tunnel.netdev', '25-tunnel.network',
1383 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1385 self
.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1387 output
= check_output('ip -d link show erspan99')
1389 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1390 self
.assertRegex(output
, 'ikey 0.0.0.101')
1391 self
.assertRegex(output
, 'okey 0.0.0.101')
1392 self
.assertRegex(output
, 'iseq')
1393 self
.assertRegex(output
, 'oseq')
1394 output
= check_output('ip -d link show erspan98')
1396 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1397 self
.assertRegex(output
, '102')
1398 self
.assertRegex(output
, 'ikey 0.0.0.102')
1399 self
.assertRegex(output
, 'okey 0.0.0.102')
1400 self
.assertRegex(output
, 'iseq')
1401 self
.assertRegex(output
, 'oseq')
1403 def test_tunnel_independent(self
):
1404 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1407 self
.wait_online(['ipiptun99:carrier'])
1409 def test_tunnel_independent_loopback(self
):
1410 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent-loopback.netdev', 'netdev-link-local-addressing-yes.network')
1413 self
.wait_online(['ipiptun99:carrier'])
1415 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1416 def test_xfrm(self
):
1417 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'xfrm.network',
1418 '25-xfrm.netdev', 'netdev-link-local-addressing-yes.network')
1421 self
.wait_online(['xfrm99:degraded', 'dummy98:degraded'])
1423 output
= check_output('ip link show dev xfrm99')
1426 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1427 def test_xfrm_independent(self
):
1428 copy_unit_to_networkd_unit_path('25-xfrm-independent.netdev', 'netdev-link-local-addressing-yes.network')
1431 self
.wait_online(['xfrm99:degraded'])
1433 @expectedFailureIfModuleIsNotAvailable('fou')
1435 # The following redundant check is necessary for CentOS CI.
1436 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1437 self
.assertTrue(is_module_available('fou'))
1439 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1440 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1441 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1444 self
.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'], setup_state
='unmanaged')
1446 output
= check_output('ip fou show')
1448 self
.assertRegex(output
, 'port 55555 ipproto 4')
1449 self
.assertRegex(output
, 'port 55556 ipproto 47')
1451 output
= check_output('ip -d link show ipiptun96')
1453 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1454 output
= check_output('ip -d link show sittun96')
1456 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1457 output
= check_output('ip -d link show gretun96')
1459 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1460 output
= check_output('ip -d link show gretap96')
1462 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1464 def test_vxlan(self
):
1465 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1466 '11-dummy.netdev', 'vxlan-test1.network')
1469 self
.wait_online(['test1:degraded', 'vxlan99:degraded'])
1471 output
= check_output('ip -d link show vxlan99')
1473 self
.assertRegex(output
, '999')
1474 self
.assertRegex(output
, '5555')
1475 self
.assertRegex(output
, 'l2miss')
1476 self
.assertRegex(output
, 'l3miss')
1477 self
.assertRegex(output
, 'udpcsum')
1478 self
.assertRegex(output
, 'udp6zerocsumtx')
1479 self
.assertRegex(output
, 'udp6zerocsumrx')
1480 self
.assertRegex(output
, 'remcsumtx')
1481 self
.assertRegex(output
, 'remcsumrx')
1482 self
.assertRegex(output
, 'gbp')
1484 output
= check_output('bridge fdb show dev vxlan99')
1486 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1487 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1488 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1490 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'vxlan99', env
=env
)
1492 self
.assertRegex(output
, 'VNI: 999')
1493 self
.assertRegex(output
, 'Destination Port: 5555')
1494 self
.assertRegex(output
, 'Underlying Device: test1')
1496 def test_macsec(self
):
1497 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1498 'macsec.network', '12-dummy.netdev')
1501 self
.wait_online(['dummy98:degraded', 'macsec99:routable'])
1503 output
= check_output('ip -d link show macsec99')
1505 self
.assertRegex(output
, 'macsec99@dummy98')
1506 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1507 self
.assertRegex(output
, 'encrypt on')
1509 output
= check_output('ip macsec show macsec99')
1511 self
.assertRegex(output
, 'encrypt on')
1512 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1513 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1514 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1515 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1516 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1517 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1518 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1519 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1520 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1521 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1522 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1524 def test_nlmon(self
):
1525 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1528 self
.wait_online(['nlmon99:carrier'])
1530 @expectedFailureIfModuleIsNotAvailable('ifb')
1532 copy_unit_to_networkd_unit_path('25-ifb.netdev', 'netdev-link-local-addressing-yes.network')
1535 self
.wait_online(['ifb99:degraded'])
1537 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1548 '25-l2tp-dummy.network',
1550 '25-l2tp-ip.netdev',
1551 '25-l2tp-udp.netdev']
1553 l2tp_tunnel_ids
= [ '10' ]
1556 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1557 remove_links(self
.links
)
1558 stop_networkd(show_logs
=False)
1561 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1562 remove_links(self
.links
)
1563 remove_unit_from_networkd_path(self
.units
)
1564 stop_networkd(show_logs
=True)
1566 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1567 def test_l2tp_udp(self
):
1568 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1569 '25-l2tp-udp.netdev', '25-l2tp.network')
1572 self
.wait_online(['test1:routable', 'l2tp-ses1:degraded', 'l2tp-ses2:degraded'])
1574 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1576 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1577 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1578 self
.assertRegex(output
, "Peer tunnel 11")
1579 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1580 self
.assertRegex(output
, "UDP checksum: enabled")
1582 output
= check_output('ip l2tp show session tid 10 session_id 15')
1584 self
.assertRegex(output
, "Session 15 in tunnel 10")
1585 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1586 self
.assertRegex(output
, "interface name: l2tp-ses1")
1588 output
= check_output('ip l2tp show session tid 10 session_id 17')
1590 self
.assertRegex(output
, "Session 17 in tunnel 10")
1591 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1592 self
.assertRegex(output
, "interface name: l2tp-ses2")
1594 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1595 def test_l2tp_ip(self
):
1596 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1597 '25-l2tp-ip.netdev', '25-l2tp.network')
1600 self
.wait_online(['test1:routable', 'l2tp-ses3:degraded', 'l2tp-ses4:degraded'])
1602 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1604 self
.assertRegex(output
, "Tunnel 10, encap IP")
1605 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1606 self
.assertRegex(output
, "Peer tunnel 12")
1608 output
= check_output('ip l2tp show session tid 10 session_id 25')
1610 self
.assertRegex(output
, "Session 25 in tunnel 10")
1611 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1612 self
.assertRegex(output
, "interface name: l2tp-ses3")
1614 output
= check_output('ip l2tp show session tid 10 session_id 27')
1616 self
.assertRegex(output
, "Session 27 in tunnel 10")
1617 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1618 self
.assertRegex(output
, "interface name: l2tp-ses4")
1620 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1635 '23-active-slave.network',
1636 '24-keep-configuration-static.network',
1637 '24-search-domain.network',
1638 '25-address-dad-veth-peer.network',
1639 '25-address-dad-veth99.network',
1640 '25-address-link-section.network',
1641 '25-address-preferred-lifetime-zero.network',
1642 '25-address-static.network',
1643 '25-bind-carrier.network',
1644 '25-bond-active-backup-slave.netdev',
1645 '25-fibrule-invert.network',
1646 '25-fibrule-port-range.network',
1647 '25-fibrule-uidrange.network',
1648 '25-gre-tunnel-remote-any.netdev',
1649 '25-ip6gre-tunnel-remote-any.netdev',
1650 '25-ipv6-address-label-section.network',
1651 '25-link-local-addressing-no.network',
1652 '25-link-local-addressing-yes.network',
1653 '25-link-section-unmanaged.network',
1654 '25-neighbor-section.network',
1655 '25-neighbor-next.network',
1656 '25-neighbor-ipv6.network',
1657 '25-neighbor-ip-dummy.network',
1658 '25-neighbor-ip.network',
1659 '25-nexthop.network',
1660 '25-qdisc-cake.network',
1661 '25-qdisc-clsact-and-htb.network',
1662 '25-qdisc-drr.network',
1663 '25-qdisc-hhf.network',
1664 '25-qdisc-ingress-netem-compat.network',
1665 '25-qdisc-pie.network',
1666 '25-route-ipv6-src.network',
1667 '25-route-static.network',
1668 '25-route-vrf.network',
1669 '25-gateway-static.network',
1670 '25-gateway-next-static.network',
1671 '25-sysctl-disable-ipv6.network',
1672 '25-sysctl.network',
1673 '25-veth-peer.network',
1676 '26-link-local-addressing-ipv6.network',
1677 'configure-without-carrier.network',
1678 'routing-policy-rule-dummy98.network',
1679 'routing-policy-rule-test1.network']
1681 routing_policy_rule_tables
= ['7', '8', '9']
1682 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1685 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1686 remove_routes(self
.routes
)
1687 remove_links(self
.links
)
1688 stop_networkd(show_logs
=False)
1691 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1692 remove_routes(self
.routes
)
1693 remove_links(self
.links
)
1694 remove_unit_from_networkd_path(self
.units
)
1695 stop_networkd(show_logs
=True)
1697 def test_address_static(self
):
1698 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1701 self
.wait_online(['dummy98:routable'])
1703 output
= check_output('ip -4 address show dev dummy98')
1705 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1706 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1707 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1710 self
.assertNotRegex(output
, '10.10.0.1/16')
1711 self
.assertNotRegex(output
, '10.10.0.2/16')
1713 output
= check_output('ip -4 address show dev dummy98 label 32')
1714 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1716 output
= check_output('ip -4 address show dev dummy98 label 33')
1717 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1719 output
= check_output('ip -4 address show dev dummy98 label 34')
1720 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1722 output
= check_output('ip -4 address show dev dummy98 label 35')
1723 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1725 output
= check_output('ip -6 address show dev dummy98')
1727 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1728 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1729 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1730 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1731 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1732 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1734 def test_address_preferred_lifetime_zero_ipv6(self
):
1735 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero.network', '12-dummy.netdev')
1738 self
.wait_online(['dummy98:routable'])
1740 output
= check_output('ip address show dummy98')
1742 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1743 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1745 output
= check_output('ip route show dev dummy98')
1747 self
.assertRegex(output
, 'default via 20.20.20.1 proto static')
1749 def test_address_dad(self
):
1750 copy_unit_to_networkd_unit_path('25-address-dad-veth99.network', '25-address-dad-veth-peer.network',
1753 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
1755 output
= check_output('ip -4 address show dev veth99')
1757 self
.assertRegex(output
, '192.168.100.10/24')
1759 output
= check_output('ip -4 address show dev veth-peer')
1761 self
.assertNotRegex(output
, '192.168.100.10/24')
1763 def test_configure_without_carrier(self
):
1764 copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
1766 self
.wait_online(['test1:routable'])
1768 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
1770 self
.assertRegex(output
, '192.168.0.15')
1771 self
.assertRegex(output
, '192.168.0.1')
1772 self
.assertRegex(output
, 'routable')
1774 def test_routing_policy_rule(self
):
1775 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1777 self
.wait_online(['test1:degraded'])
1779 output
= check_output('ip rule list iif test1 priority 111')
1781 self
.assertRegex(output
, '111:')
1782 self
.assertRegex(output
, 'from 192.168.100.18')
1783 self
.assertRegex(output
, r
'tos (0x08|throughput)\s')
1784 self
.assertRegex(output
, 'iif test1')
1785 self
.assertRegex(output
, 'oif test1')
1786 self
.assertRegex(output
, 'lookup 7')
1788 output
= check_output('ip rule list iif test1 priority 101')
1790 self
.assertRegex(output
, '101:')
1791 self
.assertRegex(output
, 'from all')
1792 self
.assertRegex(output
, 'iif test1')
1793 self
.assertRegex(output
, 'lookup 9')
1795 output
= check_output('ip -6 rule list iif test1 priority 100')
1797 self
.assertRegex(output
, '100:')
1798 self
.assertRegex(output
, 'from all')
1799 self
.assertRegex(output
, 'iif test1')
1800 self
.assertRegex(output
, 'lookup 8')
1802 output
= check_output('ip -6 rule list iif test1 priority 101')
1804 self
.assertRegex(output
, '101:')
1805 self
.assertRegex(output
, 'from all')
1806 self
.assertRegex(output
, 'iif test1')
1807 self
.assertRegex(output
, 'lookup 9')
1809 def test_routing_policy_rule_issue_11280(self
):
1810 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1811 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1813 for trial
in range(3):
1814 # Remove state files only first time
1816 self
.wait_online(['test1:degraded', 'dummy98:degraded'])
1819 output
= check_output('ip rule list table 7')
1821 self
.assertRegex(output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
1823 output
= check_output('ip rule list table 8')
1825 self
.assertRegex(output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1827 stop_networkd(remove_state_files
=False)
1829 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1830 def test_routing_policy_rule_port_range(self
):
1831 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1833 self
.wait_online(['test1:degraded'])
1835 output
= check_output('ip rule')
1837 self
.assertRegex(output
, '111')
1838 self
.assertRegex(output
, 'from 192.168.100.18')
1839 self
.assertRegex(output
, '1123-1150')
1840 self
.assertRegex(output
, '3224-3290')
1841 self
.assertRegex(output
, 'tcp')
1842 self
.assertRegex(output
, 'lookup 7')
1844 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1845 def test_routing_policy_rule_invert(self
):
1846 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1848 self
.wait_online(['test1:degraded'])
1850 output
= check_output('ip rule')
1852 self
.assertRegex(output
, '111')
1853 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
1854 self
.assertRegex(output
, 'tcp')
1855 self
.assertRegex(output
, 'lookup 7')
1857 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable()
1858 def test_routing_policy_rule_uidrange(self
):
1859 copy_unit_to_networkd_unit_path('25-fibrule-uidrange.network', '11-dummy.netdev')
1861 self
.wait_online(['test1:degraded'])
1863 output
= check_output('ip rule')
1865 self
.assertRegex(output
, '111')
1866 self
.assertRegex(output
, 'from 192.168.100.18')
1867 self
.assertRegex(output
, 'lookup 7')
1868 self
.assertRegex(output
, 'uidrange 100-200')
1870 def test_route_static(self
):
1871 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1873 self
.wait_online(['dummy98:routable'])
1875 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
1878 print('### ip -6 route show dev dummy98')
1879 output
= check_output('ip -6 route show dev dummy98')
1881 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1882 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
1884 print('### ip -6 route show dev dummy98 default')
1885 output
= check_output('ip -6 route show dev dummy98 default')
1887 self
.assertRegex(output
, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1889 print('### ip -4 route show dev dummy98')
1890 output
= check_output('ip -4 route show dev dummy98')
1892 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1893 self
.assertRegex(output
, '149.10.124.64 proto static scope link')
1894 self
.assertRegex(output
, '169.254.0.0/16 proto static scope link metric 2048')
1895 self
.assertRegex(output
, '192.168.1.1 proto static initcwnd 20')
1896 self
.assertRegex(output
, '192.168.1.2 proto static initrwnd 30')
1897 self
.assertRegex(output
, 'multicast 149.10.123.4 proto static')
1899 print('### ip -4 route show dev dummy98 default')
1900 output
= check_output('ip -4 route show dev dummy98 default')
1902 self
.assertRegex(output
, 'default via 149.10.125.65 proto static onlink')
1903 self
.assertRegex(output
, 'default via 149.10.124.64 proto static')
1904 self
.assertRegex(output
, 'default proto static')
1906 print('### ip -4 route show table local dev dummy98')
1907 output
= check_output('ip -4 route show table local dev dummy98')
1909 self
.assertRegex(output
, 'local 149.10.123.1 proto static scope host')
1910 self
.assertRegex(output
, 'anycast 149.10.123.2 proto static scope link')
1911 self
.assertRegex(output
, 'broadcast 149.10.123.3 proto static scope link')
1913 print('### ip route show type blackhole')
1914 output
= check_output('ip route show type blackhole')
1916 self
.assertRegex(output
, 'blackhole 202.54.1.2 proto static')
1918 print('### ip route show type unreachable')
1919 output
= check_output('ip route show type unreachable')
1921 self
.assertRegex(output
, 'unreachable 202.54.1.3 proto static')
1923 print('### ip route show type prohibit')
1924 output
= check_output('ip route show type prohibit')
1926 self
.assertRegex(output
, 'prohibit 202.54.1.4 proto static')
1928 print('### ip route show 192.168.10.1')
1929 output
= check_output('ip route show 192.168.10.1')
1931 self
.assertRegex(output
, '192.168.10.1 proto static')
1932 self
.assertRegex(output
, 'nexthop via 149.10.124.59 dev dummy98 weight 10')
1933 self
.assertRegex(output
, 'nexthop via 149.10.124.60 dev dummy98 weight 5')
1935 print('### ip route show 192.168.10.2')
1936 output
= check_output('ip route show 192.168.10.2')
1938 # old ip command does not show IPv6 gateways...
1939 self
.assertRegex(output
, '192.168.10.2 proto static')
1940 self
.assertRegex(output
, 'nexthop')
1941 self
.assertRegex(output
, 'dev dummy98 weight 10')
1942 self
.assertRegex(output
, 'dev dummy98 weight 5')
1944 print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
1945 output
= check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
1947 # old ip command does not show 'nexthop' keyword and weight...
1948 self
.assertRegex(output
, '2001:1234:5:7fff:ff:ff:ff:ff')
1949 self
.assertRegex(output
, 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98')
1950 self
.assertRegex(output
, 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98')
1952 @expectedFailureIfModuleIsNotAvailable('vrf')
1953 def test_route_vrf(self
):
1954 copy_unit_to_networkd_unit_path('25-route-vrf.network', '12-dummy.netdev',
1955 '25-vrf.netdev', '25-vrf.network')
1957 self
.wait_online(['dummy98:routable', 'vrf99:carrier'])
1959 output
= check_output('ip route show vrf vrf99')
1961 self
.assertRegex(output
, 'default via 192.168.100.1')
1963 output
= check_output('ip route show')
1965 self
.assertNotRegex(output
, 'default via 192.168.100.1')
1967 def test_gateway_reconfigure(self
):
1968 copy_unit_to_networkd_unit_path('25-gateway-static.network', '12-dummy.netdev')
1970 self
.wait_online(['dummy98:routable'])
1971 print('### ip -4 route show dev dummy98 default')
1972 output
= check_output('ip -4 route show dev dummy98 default')
1974 self
.assertRegex(output
, 'default via 149.10.124.59 proto static')
1975 self
.assertNotRegex(output
, '149.10.124.60')
1977 remove_unit_from_networkd_path(['25-gateway-static.network'])
1978 copy_unit_to_networkd_unit_path('25-gateway-next-static.network')
1980 self
.wait_online(['dummy98:routable'])
1981 print('### ip -4 route show dev dummy98 default')
1982 output
= check_output('ip -4 route show dev dummy98 default')
1984 self
.assertNotRegex(output
, '149.10.124.59')
1985 self
.assertRegex(output
, 'default via 149.10.124.60 proto static')
1987 def test_ip_route_ipv6_src_route(self
):
1988 # a dummy device does not make the addresses go through tentative state, so we
1989 # reuse a bond from an earlier test, which does make the addresses go through
1990 # tentative state, and do our test on that
1991 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1993 self
.wait_online(['dummy98:enslaved', 'bond199:routable'])
1995 output
= check_output('ip -6 route list dev bond199')
1997 self
.assertRegex(output
, 'abcd::/16')
1998 self
.assertRegex(output
, 'src')
1999 self
.assertRegex(output
, '2001:1234:56:8f63::2')
2001 def test_ip_link_mac_address(self
):
2002 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
2004 self
.wait_online(['dummy98:degraded'])
2006 output
= check_output('ip link show dummy98')
2008 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
2010 def test_ip_link_unmanaged(self
):
2011 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
2014 self
.check_link_exists('dummy98')
2016 self
.wait_operstate('dummy98', 'off', setup_state
='unmanaged')
2018 def test_ipv6_address_label(self
):
2019 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
2021 self
.wait_online(['dummy98:degraded'])
2023 output
= check_output('ip addrlabel list')
2025 self
.assertRegex(output
, '2004:da8:1::/64')
2027 def test_neighbor_section(self
):
2028 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2030 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2032 print('### ip neigh list dev dummy98')
2033 output
= check_output('ip neigh list dev dummy98')
2035 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2036 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2038 def test_neighbor_reconfigure(self
):
2039 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2041 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2043 print('### ip neigh list dev dummy98')
2044 output
= check_output('ip neigh list dev dummy98')
2046 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2047 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2049 remove_unit_from_networkd_path(['25-neighbor-section.network'])
2050 copy_unit_to_networkd_unit_path('25-neighbor-next.network')
2052 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2053 print('### ip neigh list dev dummy98')
2054 output
= check_output('ip neigh list dev dummy98')
2056 self
.assertNotRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2057 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT')
2058 self
.assertNotRegex(output
, '2004:da8:1::1.*PERMANENT')
2060 def test_neighbor_gre(self
):
2061 copy_unit_to_networkd_unit_path('25-neighbor-ip.network', '25-neighbor-ipv6.network', '25-neighbor-ip-dummy.network',
2062 '12-dummy.netdev', '25-gre-tunnel-remote-any.netdev', '25-ip6gre-tunnel-remote-any.netdev')
2064 self
.wait_online(['dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable'], timeout
='40s')
2066 output
= check_output('ip neigh list dev gretun97')
2068 self
.assertRegex(output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT')
2070 output
= check_output('ip neigh list dev ip6gretun97')
2072 self
.assertRegex(output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
2074 def test_link_local_addressing(self
):
2075 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
2076 '25-link-local-addressing-no.network', '12-dummy.netdev')
2078 self
.wait_online(['test1:degraded', 'dummy98:carrier'])
2080 output
= check_output('ip address show dev test1')
2082 self
.assertRegex(output
, 'inet .* scope link')
2083 self
.assertRegex(output
, 'inet6 .* scope link')
2085 output
= check_output('ip address show dev dummy98')
2087 self
.assertNotRegex(output
, 'inet6* .* scope link')
2090 Documentation/networking/ip-sysctl.txt
2092 addr_gen_mode - INTEGER
2093 Defines how link-local and autoconf addresses are generated.
2095 0: generate address based on EUI64 (default)
2096 1: do no generate a link-local address, use EUI64 for addresses generated
2098 2: generate stable privacy addresses, using the secret from
2099 stable_secret (RFC7217)
2100 3: generate stable privacy addresses, using a random secret if unset
2103 test1_addr_gen_mode
= ''
2104 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
2105 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
2109 # if stable_secret is unset, then EIO is returned
2110 test1_addr_gen_mode
= '0'
2112 test1_addr_gen_mode
= '2'
2114 test1_addr_gen_mode
= '0'
2116 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
2117 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
2119 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
2120 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
2122 def test_link_local_addressing_remove_ipv6ll(self
):
2123 copy_unit_to_networkd_unit_path('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
2125 self
.wait_online(['dummy98:degraded'])
2127 output
= check_output('ip address show dev dummy98')
2129 self
.assertRegex(output
, 'inet6 .* scope link')
2131 copy_unit_to_networkd_unit_path('25-link-local-addressing-no.network')
2133 self
.wait_online(['dummy98:carrier'])
2135 output
= check_output('ip address show dev dummy98')
2137 self
.assertNotRegex(output
, 'inet6* .* scope link')
2139 def test_sysctl(self
):
2140 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
2142 self
.wait_online(['dummy98:degraded'])
2144 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
2145 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
2146 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
2147 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
2148 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
2149 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
2150 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
2152 def test_sysctl_disable_ipv6(self
):
2153 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
2155 print('## Disable ipv6')
2156 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
2157 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
2160 self
.wait_online(['dummy98:routable'])
2162 output
= check_output('ip -4 address show dummy98')
2164 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2165 output
= check_output('ip -6 address show dummy98')
2167 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2168 self
.assertRegex(output
, 'inet6 .* scope link')
2169 output
= check_output('ip -4 route show dev dummy98')
2171 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2172 output
= check_output('ip -6 route show dev dummy98')
2174 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2176 check_output('ip link del dummy98')
2178 print('## Enable ipv6')
2179 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
2180 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
2183 self
.wait_online(['dummy98:routable'])
2185 output
= check_output('ip -4 address show dummy98')
2187 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2188 output
= check_output('ip -6 address show dummy98')
2190 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2191 self
.assertRegex(output
, 'inet6 .* scope link')
2192 output
= check_output('ip -4 route show dev dummy98')
2194 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2195 output
= check_output('ip -6 route show dev dummy98')
2197 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2199 def test_bind_carrier(self
):
2200 check_output('ip link add dummy98 type dummy')
2201 check_output('ip link set dummy98 up')
2204 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
2206 self
.wait_online(['test1:routable'])
2208 output
= check_output('ip address show test1')
2210 self
.assertRegex(output
, 'UP,LOWER_UP')
2211 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2212 self
.wait_operstate('test1', 'routable')
2214 check_output('ip link add dummy99 type dummy')
2215 check_output('ip link set dummy99 up')
2217 output
= check_output('ip address show test1')
2219 self
.assertRegex(output
, 'UP,LOWER_UP')
2220 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2221 self
.wait_operstate('test1', 'routable')
2223 check_output('ip link del dummy98')
2225 output
= check_output('ip address show test1')
2227 self
.assertRegex(output
, 'UP,LOWER_UP')
2228 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2229 self
.wait_operstate('test1', 'routable')
2231 check_output('ip link set dummy99 down')
2233 output
= check_output('ip address show test1')
2235 self
.assertNotRegex(output
, 'UP,LOWER_UP')
2236 self
.assertRegex(output
, 'DOWN')
2237 self
.assertNotRegex(output
, '192.168.10')
2238 self
.wait_operstate('test1', 'off')
2240 check_output('ip link set dummy99 up')
2242 output
= check_output('ip address show test1')
2244 self
.assertRegex(output
, 'UP,LOWER_UP')
2245 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2246 self
.wait_operstate('test1', 'routable')
2248 def test_domain(self
):
2249 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
2251 self
.wait_online(['dummy98:routable'])
2253 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2255 self
.assertRegex(output
, 'Address: 192.168.42.100')
2256 self
.assertRegex(output
, 'DNS: 192.168.42.1')
2257 self
.assertRegex(output
, 'Search Domains: one')
2259 def test_keep_configuration_static(self
):
2260 check_output('systemctl stop systemd-networkd')
2262 check_output('ip link add name dummy98 type dummy')
2263 check_output('ip address add 10.1.2.3/16 dev dummy98')
2264 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
2265 output
= check_output('ip address show dummy98')
2267 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2268 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2269 output
= check_output('ip route show dev dummy98')
2272 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
2274 self
.wait_online(['dummy98:routable'])
2276 output
= check_output('ip address show dummy98')
2278 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2279 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2281 @expectedFailureIfNexthopIsNotAvailable()
2282 def test_nexthop(self
):
2283 copy_unit_to_networkd_unit_path('25-nexthop.network', '25-veth.netdev', '25-veth-peer.network')
2285 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2287 output
= check_output('ip nexthop list dev veth99')
2289 self
.assertRegex(output
, '192.168.5.1')
2291 def test_qdisc(self
):
2292 copy_unit_to_networkd_unit_path('25-qdisc-clsact-and-htb.network', '12-dummy.netdev',
2293 '25-qdisc-ingress-netem-compat.network', '11-dummy.netdev')
2294 check_output('modprobe sch_teql max_equalizers=2')
2297 self
.wait_online(['dummy98:routable', 'test1:routable'])
2299 output
= check_output('tc qdisc show dev test1')
2301 self
.assertRegex(output
, 'qdisc netem')
2302 self
.assertRegex(output
, 'limit 100 delay 50.0ms 10.0ms loss 20%')
2303 self
.assertRegex(output
, 'qdisc ingress')
2305 output
= check_output('tc qdisc show dev dummy98')
2307 self
.assertRegex(output
, 'qdisc clsact')
2309 self
.assertRegex(output
, 'qdisc htb 2: root')
2310 self
.assertRegex(output
, r
'default (0x30|30)')
2312 self
.assertRegex(output
, 'qdisc netem 30: parent 2:30')
2313 self
.assertRegex(output
, 'limit 100 delay 50.0ms 10.0ms loss 20%')
2314 self
.assertRegex(output
, 'qdisc fq_codel')
2315 self
.assertRegex(output
, 'limit 20480p flows 2048 quantum 1400 target 10.0ms ce_threshold 100.0ms interval 200.0ms memory_limit 64Mb ecn')
2317 self
.assertRegex(output
, 'qdisc teql1 31: parent 2:31')
2319 self
.assertRegex(output
, 'qdisc fq 32: parent 2:32')
2320 self
.assertRegex(output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
2321 self
.assertRegex(output
, 'quantum 1500')
2322 self
.assertRegex(output
, 'initial_quantum 13000')
2323 self
.assertRegex(output
, 'maxrate 1Mbit')
2325 self
.assertRegex(output
, 'qdisc codel 33: parent 2:33')
2326 self
.assertRegex(output
, 'limit 2000p target 10.0ms ce_threshold 100.0ms interval 50.0ms ecn')
2328 self
.assertRegex(output
, 'qdisc fq_codel 34: parent 2:34')
2329 self
.assertRegex(output
, 'limit 20480p flows 2048 quantum 1400 target 10.0ms ce_threshold 100.0ms interval 200.0ms memory_limit 64Mb ecn')
2331 self
.assertRegex(output
, 'qdisc tbf 35: parent 2:35')
2332 self
.assertRegex(output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70.0ms')
2334 self
.assertRegex(output
, 'qdisc sfq 36: parent 2:36')
2335 self
.assertRegex(output
, 'perturb 5sec')
2337 self
.assertRegex(output
, 'qdisc pfifo 37: parent 2:37')
2338 self
.assertRegex(output
, 'limit 100000p')
2340 self
.assertRegex(output
, 'qdisc gred 38: parent 2:38')
2341 self
.assertRegex(output
, 'vqs 12 default 10 grio')
2343 self
.assertRegex(output
, 'qdisc sfb 39: parent 2:39')
2344 self
.assertRegex(output
, 'limit 200000')
2346 self
.assertRegex(output
, 'qdisc bfifo 3a: parent 2:3a')
2347 self
.assertRegex(output
, 'limit 1000000')
2349 self
.assertRegex(output
, 'qdisc pfifo_head_drop 3b: parent 2:3b')
2350 self
.assertRegex(output
, 'limit 1023p')
2352 self
.assertRegex(output
, 'qdisc pfifo_fast 3c: parent 2:3c')
2354 output
= check_output('tc class show dev dummy98')
2356 self
.assertRegex(output
, 'class htb 2:30 root leaf 30:')
2357 self
.assertRegex(output
, 'class htb 2:31 root leaf 31:')
2358 self
.assertRegex(output
, 'class htb 2:32 root leaf 32:')
2359 self
.assertRegex(output
, 'class htb 2:33 root leaf 33:')
2360 self
.assertRegex(output
, 'class htb 2:34 root leaf 34:')
2361 self
.assertRegex(output
, 'class htb 2:35 root leaf 35:')
2362 self
.assertRegex(output
, 'class htb 2:36 root leaf 36:')
2363 self
.assertRegex(output
, 'class htb 2:37 root leaf 37:')
2364 self
.assertRegex(output
, 'class htb 2:38 root leaf 38:')
2365 self
.assertRegex(output
, 'class htb 2:39 root leaf 39:')
2366 self
.assertRegex(output
, 'class htb 2:3a root leaf 3a:')
2367 self
.assertRegex(output
, 'class htb 2:3b root leaf 3b:')
2368 self
.assertRegex(output
, 'class htb 2:3c root leaf 3c:')
2369 self
.assertRegex(output
, 'prio 1 rate 1Mbit ceil 500Kbit')
2371 def test_qdisc2(self
):
2372 copy_unit_to_networkd_unit_path('25-qdisc-drr.network', '12-dummy.netdev')
2375 self
.wait_online(['dummy98:routable'])
2377 output
= check_output('tc qdisc show dev dummy98')
2379 self
.assertRegex(output
, 'qdisc drr 2: root')
2380 output
= check_output('tc class show dev dummy98')
2382 self
.assertRegex(output
, 'class drr 2:30 root quantum 2000b')
2384 @expectedFailureIfCAKEIsNotAvailable()
2385 def test_qdisc_cake(self
):
2386 copy_unit_to_networkd_unit_path('25-qdisc-cake.network', '12-dummy.netdev')
2388 self
.wait_online(['dummy98:routable'])
2390 output
= check_output('tc qdisc show dev dummy98')
2392 self
.assertRegex(output
, 'qdisc cake 3a: root')
2393 self
.assertRegex(output
, 'bandwidth 500Mbit')
2394 self
.assertRegex(output
, 'overhead 128')
2396 @expectedFailureIfPIEIsNotAvailable()
2397 def test_qdisc_pie(self
):
2398 copy_unit_to_networkd_unit_path('25-qdisc-pie.network', '12-dummy.netdev')
2400 self
.wait_online(['dummy98:routable'])
2402 output
= check_output('tc qdisc show dev dummy98')
2404 self
.assertRegex(output
, 'qdisc pie 3a: root')
2405 self
.assertRegex(output
, 'limit 200000')
2407 @expectedFailureIfHHFIsNotAvailable()
2408 def test_qdisc_hhf(self
):
2409 copy_unit_to_networkd_unit_path('25-qdisc-hhf.network', '12-dummy.netdev')
2411 self
.wait_online(['dummy98:routable'])
2413 output
= check_output('tc qdisc show dev dummy98')
2415 self
.assertRegex(output
, 'qdisc hhf 3a: root')
2416 self
.assertRegex(output
, 'limit 1022p')
2418 class NetworkdStateFileTests(unittest
.TestCase
, Utilities
):
2425 'state-file-tests.network',
2429 remove_links(self
.links
)
2430 stop_networkd(show_logs
=False)
2433 remove_links(self
.links
)
2434 remove_unit_from_networkd_path(self
.units
)
2435 stop_networkd(show_logs
=True)
2437 def test_state_file(self
):
2438 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'state-file-tests.network')
2440 self
.wait_online(['dummy98:routable'])
2442 output
= check_output(*networkctl_cmd
, '--no-legend', 'list', 'dummy98', env
=env
)
2444 ifindex
= output
.split()[0]
2446 path
= os
.path
.join('/run/systemd/netif/links/', ifindex
)
2447 self
.assertTrue(os
.path
.exists(path
))
2450 with
open(path
) as f
:
2452 self
.assertRegex(data
, r
'ADMIN_STATE=configured')
2453 self
.assertRegex(data
, r
'OPER_STATE=routable')
2454 self
.assertRegex(data
, r
'REQUIRED_FOR_ONLINE=yes')
2455 self
.assertRegex(data
, r
'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
2456 self
.assertRegex(data
, r
'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
2457 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
2458 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2459 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2460 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2461 self
.assertRegex(data
, r
'LLMNR=no')
2462 self
.assertRegex(data
, r
'MDNS=yes')
2463 self
.assertRegex(data
, r
'DNSSEC=no')
2464 self
.assertRegex(data
, r
'ADDRESSES=192.168.(10.10|12.12)/24 192.168.(12.12|10.10)/24')
2466 check_output(*resolvectl_cmd
, 'dns', 'dummy98', '10.10.10.12', '10.10.10.13', env
=env
)
2467 check_output(*resolvectl_cmd
, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env
=env
)
2468 check_output(*resolvectl_cmd
, 'llmnr', 'dummy98', 'yes', env
=env
)
2469 check_output(*resolvectl_cmd
, 'mdns', 'dummy98', 'no', env
=env
)
2470 check_output(*resolvectl_cmd
, 'dnssec', 'dummy98', 'yes', env
=env
)
2471 check_output(*timedatectl_cmd
, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env
=env
)
2474 with
open(path
) as f
:
2476 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
2477 self
.assertRegex(data
, r
'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org')
2478 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2479 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2480 self
.assertRegex(data
, r
'LLMNR=yes')
2481 self
.assertRegex(data
, r
'MDNS=no')
2482 self
.assertRegex(data
, r
'DNSSEC=yes')
2484 check_output(*timedatectl_cmd
, 'revert', 'dummy98', env
=env
)
2487 with
open(path
) as f
:
2489 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
2490 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2491 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2492 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2493 self
.assertRegex(data
, r
'LLMNR=yes')
2494 self
.assertRegex(data
, r
'MDNS=no')
2495 self
.assertRegex(data
, r
'DNSSEC=yes')
2497 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
2500 with
open(path
) as f
:
2502 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
2503 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2504 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2505 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2506 self
.assertRegex(data
, r
'LLMNR=no')
2507 self
.assertRegex(data
, r
'MDNS=yes')
2508 self
.assertRegex(data
, r
'DNSSEC=no')
2510 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
2520 '23-active-slave.network',
2521 '23-bond199.network',
2522 '23-primary-slave.network',
2523 '25-bond-active-backup-slave.netdev',
2526 'bond-slave.network']
2529 remove_links(self
.links
)
2530 stop_networkd(show_logs
=False)
2533 remove_links(self
.links
)
2534 remove_unit_from_networkd_path(self
.units
)
2535 stop_networkd(show_logs
=True)
2537 def test_bond_active_slave(self
):
2538 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2540 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2542 output
= check_output('ip -d link show bond199')
2544 self
.assertRegex(output
, 'active_slave dummy98')
2546 def test_bond_primary_slave(self
):
2547 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2549 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2551 output
= check_output('ip -d link show bond199')
2553 self
.assertRegex(output
, 'primary dummy98')
2555 def test_bond_operstate(self
):
2556 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
2557 'bond99.network','bond-slave.network')
2559 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
2561 output
= check_output('ip -d link show dummy98')
2563 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2565 output
= check_output('ip -d link show test1')
2567 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2569 output
= check_output('ip -d link show bond99')
2571 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
2573 self
.wait_operstate('dummy98', 'enslaved')
2574 self
.wait_operstate('test1', 'enslaved')
2575 self
.wait_operstate('bond99', 'routable')
2577 check_output('ip link set dummy98 down')
2579 self
.wait_operstate('dummy98', 'off')
2580 self
.wait_operstate('test1', 'enslaved')
2581 self
.wait_operstate('bond99', 'degraded-carrier')
2583 check_output('ip link set dummy98 up')
2585 self
.wait_operstate('dummy98', 'enslaved')
2586 self
.wait_operstate('test1', 'enslaved')
2587 self
.wait_operstate('bond99', 'routable')
2589 check_output('ip link set dummy98 down')
2590 check_output('ip link set test1 down')
2592 self
.wait_operstate('dummy98', 'off')
2593 self
.wait_operstate('test1', 'off')
2595 if not self
.wait_operstate('bond99', 'no-carrier', setup_timeout
=30, fail_assert
=False):
2596 # Huh? Kernel does not recognize that all slave interfaces are down?
2597 # Let's confirm that networkd's operstate is consistent with ip's result.
2598 self
.assertNotRegex(output
, 'NO-CARRIER')
2600 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
2610 '26-bridge-slave-interface-1.network',
2611 '26-bridge-slave-interface-2.network',
2612 '26-bridge-vlan-master.network',
2613 '26-bridge-vlan-slave.network',
2614 'bridge99-ignore-carrier-loss.network',
2617 routing_policy_rule_tables
= ['100']
2620 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2621 remove_links(self
.links
)
2622 stop_networkd(show_logs
=False)
2625 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2626 remove_links(self
.links
)
2627 remove_unit_from_networkd_path(self
.units
)
2628 stop_networkd(show_logs
=True)
2630 def test_bridge_vlan(self
):
2631 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
2632 '26-bridge.netdev', '26-bridge-vlan-master.network')
2634 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
2636 output
= check_output('bridge vlan show dev test1')
2638 self
.assertNotRegex(output
, '4063')
2639 for i
in range(4064, 4095):
2640 self
.assertRegex(output
, f
'{i}')
2641 self
.assertNotRegex(output
, '4095')
2643 output
= check_output('bridge vlan show dev bridge99')
2645 self
.assertNotRegex(output
, '4059')
2646 for i
in range(4060, 4095):
2647 self
.assertRegex(output
, f
'{i}')
2648 self
.assertNotRegex(output
, '4095')
2650 def test_bridge_property(self
):
2651 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2652 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2655 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2657 output
= check_output('ip -d link show test1')
2659 self
.assertRegex(output
, 'master')
2660 self
.assertRegex(output
, 'bridge')
2662 output
= check_output('ip -d link show dummy98')
2664 self
.assertRegex(output
, 'master')
2665 self
.assertRegex(output
, 'bridge')
2667 output
= check_output('ip addr show bridge99')
2669 self
.assertRegex(output
, '192.168.0.15/24')
2671 output
= check_output('bridge -d link show dummy98')
2673 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
2674 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
2675 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
2676 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
2677 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
2678 # CONFIG_BRIDGE_IGMP_SNOOPING=y
2679 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
2680 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
2681 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
2682 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
2683 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
2684 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'priority'), '23')
2685 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard'), '1')
2686 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'root_block'), '1')
2688 output
= check_output('bridge -d link show test1')
2690 self
.assertEqual(read_bridge_port_attr('bridge99', 'test1', 'priority'), '0')
2692 check_output('ip address add 192.168.0.16/24 dev bridge99')
2695 output
= check_output('ip addr show bridge99')
2697 self
.assertRegex(output
, '192.168.0.16/24')
2700 print('### ip -6 route list table all dev bridge99')
2701 output
= check_output('ip -6 route list table all dev bridge99')
2703 self
.assertRegex(output
, 'ff00::/8 table local metric 256 pref medium')
2705 self
.assertEqual(call('ip link del test1'), 0)
2707 self
.wait_operstate('bridge99', 'degraded-carrier')
2709 check_output('ip link del dummy98')
2711 self
.wait_operstate('bridge99', 'no-carrier')
2713 output
= check_output('ip address show bridge99')
2715 self
.assertRegex(output
, 'NO-CARRIER')
2716 self
.assertNotRegex(output
, '192.168.0.15/24')
2717 self
.assertNotRegex(output
, '192.168.0.16/24')
2719 print('### ip -6 route list table all dev bridge99')
2720 output
= check_output('ip -6 route list table all dev bridge99')
2722 self
.assertRegex(output
, 'ff00::/8 table local metric 256 (linkdown )?pref medium')
2724 def test_bridge_ignore_carrier_loss(self
):
2725 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2726 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2727 'bridge99-ignore-carrier-loss.network')
2729 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2731 check_output('ip address add 192.168.0.16/24 dev bridge99')
2734 check_output('ip link del test1')
2735 check_output('ip link del dummy98')
2738 output
= check_output('ip address show bridge99')
2740 self
.assertRegex(output
, 'NO-CARRIER')
2741 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2742 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
2744 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
2745 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
2746 'bridge99-ignore-carrier-loss.network')
2748 self
.wait_online(['bridge99:no-carrier'])
2750 for trial
in range(4):
2751 check_output('ip link add dummy98 type dummy')
2752 check_output('ip link set dummy98 up')
2754 check_output('ip link del dummy98')
2756 self
.wait_online(['bridge99:routable', 'dummy98:enslaved'])
2758 output
= check_output('ip address show bridge99')
2760 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2762 output
= check_output('ip rule list table 100')
2764 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
2766 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
2770 '23-emit-lldp.network',
2775 remove_links(self
.links
)
2776 stop_networkd(show_logs
=False)
2779 remove_links(self
.links
)
2780 remove_unit_from_networkd_path(self
.units
)
2781 stop_networkd(show_logs
=True)
2783 def test_lldp(self
):
2784 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
2786 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
2788 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
2790 self
.assertRegex(output
, 'veth-peer')
2791 self
.assertRegex(output
, 'veth99')
2793 class NetworkdRATests(unittest
.TestCase
, Utilities
):
2798 'ipv6-prefix.network',
2799 'ipv6-prefix-veth.network',
2800 'ipv6-prefix-veth-token-static.network',
2801 'ipv6-prefix-veth-token-static-explicit.network',
2802 'ipv6-prefix-veth-token-static-multiple.network',
2803 'ipv6-prefix-veth-token-prefixstable.network']
2806 remove_links(self
.links
)
2807 stop_networkd(show_logs
=False)
2810 remove_links(self
.links
)
2811 remove_unit_from_networkd_path(self
.units
)
2812 stop_networkd(show_logs
=True)
2814 def test_ipv6_prefix_delegation(self
):
2815 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
2817 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2819 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
2821 self
.assertRegex(output
, 'fe80::')
2822 self
.assertRegex(output
, '2002:da8:1::1')
2824 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2826 self
.assertRegex(output
, '2002:da8:1:0')
2828 def test_ipv6_token_static(self
):
2829 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static.network')
2831 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2833 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2835 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
2837 def test_ipv6_token_static_explicit(self
):
2838 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static-explicit.network')
2840 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2842 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2844 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
2846 def test_ipv6_token_static_multiple(self
):
2847 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static-multiple.network')
2849 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2851 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2853 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
2854 self
.assertRegex(output
, '2002:da8:1:0:fa:de:ca:fe')
2856 def test_ipv6_token_prefixstable(self
):
2857 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable.network')
2859 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2861 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2863 self
.assertRegex(output
, '2002:da8:1:0')
2865 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
2870 'dhcp-client.network',
2871 'dhcp-client-timezone-router.network',
2872 'dhcp-server.network',
2873 'dhcp-server-timezone-router.network']
2876 remove_links(self
.links
)
2877 stop_networkd(show_logs
=False)
2880 remove_links(self
.links
)
2881 remove_unit_from_networkd_path(self
.units
)
2882 stop_networkd(show_logs
=True)
2884 def test_dhcp_server(self
):
2885 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
2887 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2889 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2891 self
.assertRegex(output
, '192.168.5.*')
2892 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
2893 self
.assertRegex(output
, 'DNS: 192.168.5.1')
2894 self
.assertRegex(output
, 'NTP: 192.168.5.1')
2896 def test_emit_router_timezone(self
):
2897 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
2899 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2901 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2903 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
2904 self
.assertRegex(output
, '192.168.5.*')
2905 self
.assertRegex(output
, 'Europe/Berlin')
2907 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
2916 'dhcp-client-anonymize.network',
2917 'dhcp-client-decline.network',
2918 'dhcp-client-gateway-ipv4.network',
2919 'dhcp-client-gateway-ipv6.network',
2920 'dhcp-client-gateway-onlink-implicit.network',
2921 'dhcp-client-ipv4-dhcp-settings.network',
2922 'dhcp-client-ipv4-only-ipv6-disabled.network',
2923 'dhcp-client-ipv4-only.network',
2924 'dhcp-client-ipv4-use-gateway-no.network',
2925 'dhcp-client-ipv4-use-routes-no.network',
2926 'dhcp-client-ipv6-only.network',
2927 'dhcp-client-ipv6-rapid-commit.network',
2928 'dhcp-client-keep-configuration-dhcp-on-stop.network',
2929 'dhcp-client-keep-configuration-dhcp.network',
2930 'dhcp-client-listen-port.network',
2931 'dhcp-client-reassign-static-routes-ipv4.network',
2932 'dhcp-client-reassign-static-routes-ipv6.network',
2933 'dhcp-client-route-metric.network',
2934 'dhcp-client-route-table.network',
2935 'dhcp-client-use-dns-ipv4-and-ra.network',
2936 'dhcp-client-use-dns-ipv4.network',
2937 'dhcp-client-use-dns-no.network',
2938 'dhcp-client-use-dns-yes.network',
2939 'dhcp-client-use-domains.network',
2940 'dhcp-client-use-routes-no.network',
2941 'dhcp-client-vrf.network',
2942 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
2943 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
2944 'dhcp-client-with-static-address.network',
2945 'dhcp-client.network',
2946 'dhcp-server-decline.network',
2947 'dhcp-server-veth-peer.network',
2948 'dhcp-v4-server-veth-peer.network',
2949 'dhcp-client-use-domains.network',
2953 stop_dnsmasq(dnsmasq_pid_file
)
2954 remove_links(self
.links
)
2955 stop_networkd(show_logs
=False)
2958 stop_dnsmasq(dnsmasq_pid_file
)
2961 remove_links(self
.links
)
2962 remove_unit_from_networkd_path(self
.units
)
2963 stop_networkd(show_logs
=True)
2965 def test_dhcp_client_ipv6_only(self
):
2966 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2969 self
.wait_online(['veth-peer:carrier'])
2971 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2973 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2975 self
.assertRegex(output
, '2600::')
2976 self
.assertNotRegex(output
, '192.168.5')
2978 # Confirm that ipv6 token is not set in the kernel
2979 output
= check_output('ip token show dev veth99')
2981 self
.assertRegex(output
, 'token :: dev veth99')
2983 def test_dhcp_client_ipv4_only(self
):
2984 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
2987 self
.wait_online(['veth-peer:carrier'])
2988 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
2989 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2991 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2993 self
.assertNotRegex(output
, '2600::')
2994 self
.assertRegex(output
, '192.168.5')
2995 self
.assertRegex(output
, '192.168.5.6')
2996 self
.assertRegex(output
, '192.168.5.7')
2998 # checking routes to DNS servers
2999 output
= check_output('ip route show dev veth99')
3001 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3002 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3003 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3005 stop_dnsmasq(dnsmasq_pid_file
)
3006 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8', lease_time
='2m')
3008 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3009 print('Wait for the dynamic address to be renewed')
3012 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3014 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3016 self
.assertNotRegex(output
, '2600::')
3017 self
.assertRegex(output
, '192.168.5')
3018 self
.assertNotRegex(output
, '192.168.5.6')
3019 self
.assertRegex(output
, '192.168.5.7')
3020 self
.assertRegex(output
, '192.168.5.8')
3022 # checking routes to DNS servers
3023 output
= check_output('ip route show dev veth99')
3025 self
.assertNotRegex(output
, r
'192.168.5.6')
3026 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3027 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3028 self
.assertRegex(output
, r
'192.168.5.8 proto dhcp scope link src 192.168.5.181 metric 1024')
3030 def test_dhcp_client_ipv4_use_routes_no(self
):
3031 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-use-routes-no.network')
3034 self
.wait_online(['veth-peer:carrier'])
3035 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
3036 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3038 output
= check_output('ip route show dev veth99')
3040 self
.assertNotRegex(output
, r
'192.168.5.5')
3041 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.181 metric 1024')
3042 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3044 def test_dhcp_client_ipv4_use_gateway_no(self
):
3045 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-use-gateway-no.network')
3048 self
.wait_online(['veth-peer:carrier'])
3049 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
3050 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3052 output
= check_output('ip route show dev veth99')
3054 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.181 metric 1024')
3055 self
.assertNotRegex(output
, r
'default via 192.168.5.1')
3057 def test_dhcp_client_ipv4_ipv6(self
):
3058 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
3059 'dhcp-client-ipv4-only.network')
3061 self
.wait_online(['veth-peer:carrier'])
3063 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3065 # link become 'routable' when at least one protocol provide an valid address.
3066 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3067 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3069 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3071 self
.assertRegex(output
, '2600::')
3072 self
.assertRegex(output
, '192.168.5')
3074 def test_dhcp_client_settings(self
):
3075 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
3078 self
.wait_online(['veth-peer:carrier'])
3080 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3082 print('## ip address show dev veth99')
3083 output
= check_output('ip address show dev veth99')
3085 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3086 self
.assertRegex(output
, '192.168.5')
3087 self
.assertRegex(output
, '1492')
3089 print('## ip route show table main dev veth99')
3090 output
= check_output('ip route show table main dev veth99')
3093 main_table_is_empty
= output
== ''
3094 if not main_table_is_empty
:
3095 self
.assertNotRegex(output
, 'proto dhcp')
3097 print('## ip route show table 211 dev veth99')
3098 output
= check_output('ip route show table 211 dev veth99')
3100 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
3101 if main_table_is_empty
:
3102 self
.assertRegex(output
, '192.168.5.0/24 proto dhcp')
3103 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
3104 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
3106 print('## dnsmasq log')
3107 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
3108 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
3109 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
3110 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
3112 def test_dhcp6_client_settings_rapidcommit_true(self
):
3113 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3115 self
.wait_online(['veth-peer:carrier'])
3117 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3119 output
= check_output('ip address show dev veth99')
3121 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3122 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
3124 def test_dhcp6_client_settings_rapidcommit_false(self
):
3125 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
3127 self
.wait_online(['veth-peer:carrier'])
3129 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3131 output
= check_output('ip address show dev veth99')
3133 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3134 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
3136 def test_dhcp_client_settings_anonymize(self
):
3137 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
3139 self
.wait_online(['veth-peer:carrier'])
3141 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3143 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
3144 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
3145 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
3147 def test_dhcp_client_listen_port(self
):
3148 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
3150 self
.wait_online(['veth-peer:carrier'])
3151 start_dnsmasq('--dhcp-alternate-port=67,5555')
3152 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3154 output
= check_output('ip -4 address show dev veth99')
3156 self
.assertRegex(output
, '192.168.5.* dynamic')
3158 def test_dhcp_client_with_static_address(self
):
3159 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
3160 'dhcp-client-with-static-address.network')
3162 self
.wait_online(['veth-peer:carrier'])
3164 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3166 output
= check_output('ip address show dev veth99 scope global')
3168 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
3169 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
3171 output
= check_output('ip route show dev veth99')
3173 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
3174 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
3175 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
3176 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
3178 def test_dhcp_route_table_id(self
):
3179 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
3181 self
.wait_online(['veth-peer:carrier'])
3183 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3185 output
= check_output('ip route show table 12')
3187 self
.assertRegex(output
, 'veth99 proto dhcp')
3188 self
.assertRegex(output
, '192.168.5.1')
3190 def test_dhcp_route_metric(self
):
3191 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
3193 self
.wait_online(['veth-peer:carrier'])
3195 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3197 output
= check_output('ip route show dev veth99')
3199 self
.assertRegex(output
, 'metric 24')
3201 def test_dhcp_client_reassign_static_routes_ipv4(self
):
3202 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3203 'dhcp-client-reassign-static-routes-ipv4.network')
3205 self
.wait_online(['veth-peer:carrier'])
3206 start_dnsmasq(lease_time
='2m')
3207 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3209 output
= check_output('ip address show dev veth99 scope global')
3211 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3213 output
= check_output('ip route show dev veth99')
3215 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3216 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3217 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3218 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3220 stop_dnsmasq(dnsmasq_pid_file
)
3221 start_dnsmasq(ipv4_range
='192.168.5.210,192.168.5.220', lease_time
='2m')
3223 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3224 print('Wait for the dynamic address to be renewed')
3227 self
.wait_online(['veth99:routable'])
3229 output
= check_output('ip route show dev veth99')
3231 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3232 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3233 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3234 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3236 def test_dhcp_client_reassign_static_routes_ipv6(self
):
3237 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3238 'dhcp-client-reassign-static-routes-ipv6.network')
3240 self
.wait_online(['veth-peer:carrier'])
3241 start_dnsmasq(lease_time
='2m')
3242 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3244 output
= check_output('ip address show dev veth99 scope global')
3246 self
.assertRegex(output
, r
'inet6 2600::[0-9a-f]*/128 scope global (noprefixroute dynamic|dynamic noprefixroute)')
3248 output
= check_output('ip -6 route show dev veth99')
3250 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3251 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3253 stop_dnsmasq(dnsmasq_pid_file
)
3254 start_dnsmasq(ipv6_range
='2600::30,2600::40', lease_time
='2m')
3256 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3257 print('Wait for the dynamic address to be renewed')
3260 self
.wait_online(['veth99:routable'])
3262 output
= check_output('ip -6 route show dev veth99')
3264 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3265 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3267 def test_dhcp_keep_configuration_dhcp(self
):
3268 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
3270 self
.wait_online(['veth-peer:carrier'])
3271 start_dnsmasq(lease_time
='2m')
3272 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3274 output
= check_output('ip address show dev veth99 scope global')
3276 self
.assertRegex(output
, r
'192.168.5.*')
3278 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3280 self
.assertRegex(output
, r
'192.168.5.*')
3282 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
3283 stop_dnsmasq(dnsmasq_pid_file
)
3285 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3286 print('Wait for the dynamic address to be expired')
3289 print('The lease address should be kept after lease expired')
3290 output
= check_output('ip address show dev veth99 scope global')
3292 self
.assertRegex(output
, r
'192.168.5.*')
3294 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3296 self
.assertRegex(output
, r
'192.168.5.*')
3298 check_output('systemctl stop systemd-networkd')
3300 print('The lease address should be kept after networkd stopped')
3301 output
= check_output('ip address show dev veth99 scope global')
3303 self
.assertRegex(output
, r
'192.168.5.*')
3305 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3307 self
.assertRegex(output
, r
'192.168.5.*')
3310 self
.wait_online(['veth-peer:routable'])
3312 print('Still the lease address should be kept after networkd restarted')
3313 output
= check_output('ip address show dev veth99 scope global')
3315 self
.assertRegex(output
, r
'192.168.5.*')
3317 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3319 self
.assertRegex(output
, r
'192.168.5.*')
3321 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
3322 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
3324 self
.wait_online(['veth-peer:carrier'])
3325 start_dnsmasq(lease_time
='2m')
3326 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3328 output
= check_output('ip address show dev veth99 scope global')
3330 self
.assertRegex(output
, r
'192.168.5.*')
3332 stop_dnsmasq(dnsmasq_pid_file
)
3333 check_output('systemctl stop systemd-networkd')
3335 output
= check_output('ip address show dev veth99 scope global')
3337 self
.assertRegex(output
, r
'192.168.5.*')
3340 self
.wait_online(['veth-peer:routable'])
3342 output
= check_output('ip address show dev veth99 scope global')
3344 self
.assertNotRegex(output
, r
'192.168.5.*')
3346 def test_dhcp_client_reuse_address_as_static(self
):
3347 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
3349 self
.wait_online(['veth-peer:carrier'])
3351 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3353 # link become 'routable' when at least one protocol provide an valid address.
3354 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3355 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3357 output
= check_output('ip address show dev veth99 scope global')
3359 self
.assertRegex(output
, '192.168.5')
3360 self
.assertRegex(output
, '2600::')
3362 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
3363 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
3364 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
3365 print(static_network
)
3367 remove_unit_from_networkd_path(['dhcp-client.network'])
3369 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
3370 f
.write(static_network
)
3372 # When networkd started, the links are already configured, so let's wait for 5 seconds
3373 # the links to be re-configured.
3375 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3377 output
= check_output('ip -4 address show dev veth99 scope global')
3379 self
.assertRegex(output
, '192.168.5')
3380 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3382 output
= check_output('ip -6 address show dev veth99 scope global')
3384 self
.assertRegex(output
, '2600::')
3385 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3387 @expectedFailureIfModuleIsNotAvailable('vrf')
3388 def test_dhcp_client_vrf(self
):
3389 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
3390 '25-vrf.netdev', '25-vrf.network')
3392 self
.wait_online(['veth-peer:carrier'])
3394 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
3396 # link become 'routable' when at least one protocol provide an valid address.
3397 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3398 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3400 print('## ip -d link show dev vrf99')
3401 output
= check_output('ip -d link show dev vrf99')
3403 self
.assertRegex(output
, 'vrf table 42')
3405 print('## ip address show vrf vrf99')
3406 output
= check_output('ip address show vrf vrf99')
3408 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3409 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3410 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3411 self
.assertRegex(output
, 'inet6 .* scope link')
3413 print('## ip address show dev veth99')
3414 output
= check_output('ip address show dev veth99')
3416 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3417 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3418 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3419 self
.assertRegex(output
, 'inet6 .* scope link')
3421 print('## ip route show vrf vrf99')
3422 output
= check_output('ip route show vrf vrf99')
3424 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
3425 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
3426 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
3427 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
3428 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
3430 print('## ip route show table main dev veth99')
3431 output
= check_output('ip route show table main dev veth99')
3433 self
.assertEqual(output
, '')
3435 def test_dhcp_client_gateway_ipv4(self
):
3436 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3437 'dhcp-client-gateway-ipv4.network')
3439 self
.wait_online(['veth-peer:carrier'])
3441 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3443 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3445 self
.assertRegex(output
, '10.0.0.0/8 via 192.168.5.1 proto static')
3447 def test_dhcp_client_gateway_ipv6(self
):
3448 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3449 'dhcp-client-gateway-ipv6.network')
3451 self
.wait_online(['veth-peer:carrier'])
3453 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3455 output
= check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
3457 self
.assertRegex(output
, 'via fe80::1034:56ff:fe78:9abd')
3459 def test_dhcp_client_gateway_onlink_implicit(self
):
3460 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3461 'dhcp-client-gateway-onlink-implicit.network')
3463 self
.wait_online(['veth-peer:carrier'])
3465 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3467 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3469 self
.assertRegex(output
, '192.168.5')
3471 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3473 self
.assertRegex(output
, 'onlink')
3474 output
= check_output('ip route list dev veth99 192.168.100.0/24')
3476 self
.assertRegex(output
, 'onlink')
3478 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
3479 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3480 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
3482 self
.wait_online(['veth-peer:carrier'])
3483 start_dnsmasq(lease_time
='2m')
3484 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3486 output
= check_output('ip address show dev veth99')
3489 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3490 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3491 output
= check_output('ip -6 address show dev veth99 scope link')
3492 self
.assertRegex(output
, 'inet6 .* scope link')
3493 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3494 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3495 output
= check_output('ip -4 address show dev veth99 scope link')
3496 self
.assertNotRegex(output
, 'inet .* scope link')
3498 print('Wait for the dynamic address to be expired')
3501 output
= check_output('ip address show dev veth99')
3504 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3505 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3506 output
= check_output('ip -6 address show dev veth99 scope link')
3507 self
.assertRegex(output
, 'inet6 .* scope link')
3508 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3509 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3510 output
= check_output('ip -4 address show dev veth99 scope link')
3511 self
.assertNotRegex(output
, 'inet .* scope link')
3513 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
3515 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
3516 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3517 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
3519 self
.wait_online(['veth99:degraded', 'veth-peer:routable'])
3521 output
= check_output('ip address show dev veth99')
3524 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3525 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3526 output
= check_output('ip -6 address show dev veth99 scope link')
3527 self
.assertRegex(output
, 'inet6 .* scope link')
3528 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3529 self
.assertNotRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3530 output
= check_output('ip -4 address show dev veth99 scope link')
3531 self
.assertRegex(output
, 'inet .* scope link')
3533 def test_dhcp_client_route_remove_on_renew(self
):
3534 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3535 'dhcp-client-ipv4-only-ipv6-disabled.network')
3537 self
.wait_online(['veth-peer:carrier'])
3538 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
3539 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3541 # test for issue #12490
3543 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3545 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3547 for line
in output
.splitlines():
3548 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3549 address1
= line
.split()[1].split('/')[0]
3552 output
= check_output('ip -4 route show dev veth99')
3554 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3555 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3557 stop_dnsmasq(dnsmasq_pid_file
)
3558 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
3560 print('Wait for the dynamic address to be expired')
3563 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3565 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3567 for line
in output
.splitlines():
3568 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3569 address2
= line
.split()[1].split('/')[0]
3572 self
.assertNotEqual(address1
, address2
)
3574 output
= check_output('ip -4 route show dev veth99')
3576 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3577 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3578 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
3579 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
3581 def test_dhcp_client_use_dns_yes(self
):
3582 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-yes.network')
3585 self
.wait_online(['veth-peer:carrier'])
3586 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3587 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3589 # link become 'routable' when at least one protocol provide an valid address.
3590 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3591 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3594 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3596 self
.assertRegex(output
, '192.168.5.1')
3597 self
.assertRegex(output
, '2600::1')
3599 def test_dhcp_client_use_dns_no(self
):
3600 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-no.network')
3603 self
.wait_online(['veth-peer:carrier'])
3604 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3605 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3607 # link become 'routable' when at least one protocol provide an valid address.
3608 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3609 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3612 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3614 self
.assertNotRegex(output
, '192.168.5.1')
3615 self
.assertNotRegex(output
, '2600::1')
3617 def test_dhcp_client_use_dns_ipv4(self
):
3618 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4.network')
3621 self
.wait_online(['veth-peer:carrier'])
3622 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3623 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3625 # link become 'routable' when at least one protocol provide an valid address.
3626 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3627 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3630 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3632 self
.assertRegex(output
, '192.168.5.1')
3633 self
.assertNotRegex(output
, '2600::1')
3635 def test_dhcp_client_use_dns_ipv4_and_ra(self
):
3636 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4-and-ra.network')
3639 self
.wait_online(['veth-peer:carrier'])
3640 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3641 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3643 # link become 'routable' when at least one protocol provide an valid address.
3644 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3645 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3648 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3650 self
.assertRegex(output
, '192.168.5.1')
3651 self
.assertRegex(output
, '2600::1')
3653 def test_dhcp_client_use_domains(self
):
3654 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-domains.network')
3657 self
.wait_online(['veth-peer:carrier'])
3658 start_dnsmasq('--dhcp-option=option:domain-search,example.com')
3659 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3661 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3663 self
.assertRegex(output
, 'Search Domains: example.com')
3666 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
3668 self
.assertRegex(output
, 'example.com')
3670 def test_dhcp_client_decline(self
):
3671 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-decline.network', 'dhcp-client-decline.network')
3674 self
.wait_online(['veth-peer:carrier'])
3675 rc
= call(*wait_online_cmd
, '--timeout=10s', '--interface=veth99:routable', env
=env
)
3676 self
.assertTrue(rc
== 1)
3678 class NetworkdIPv6PrefixTests(unittest
.TestCase
, Utilities
):
3683 'ipv6ra-prefix-client.network',
3684 'ipv6ra-prefix.network'
3688 remove_links(self
.links
)
3689 stop_networkd(show_logs
=False)
3693 remove_links(self
.links
)
3694 remove_unit_from_networkd_path(self
.units
)
3695 stop_networkd(show_logs
=True)
3697 def test_ipv6_route_prefix(self
):
3698 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client.network', 'ipv6ra-prefix.network')
3701 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3703 output
= check_output('ip -6 route show dev veth-peer')
3705 self
.assertRegex(output
, '2001:db8:0:1::/64 proto ra')
3707 output
= check_output('ip addr show dev veth99')
3709 self
.assertNotRegex(output
, '2001:db8:0:1')
3710 self
.assertRegex(output
, '2001:db8:0:2')
3712 class NetworkdMTUTests(unittest
.TestCase
, Utilities
):
3717 '12-dummy-mtu.netdev',
3718 '12-dummy-mtu.link',
3723 remove_links(self
.links
)
3724 stop_networkd(show_logs
=False)
3728 remove_links(self
.links
)
3729 remove_unit_from_networkd_path(self
.units
)
3730 stop_networkd(show_logs
=True)
3732 def check_mtu(self
, mtu
, ipv6_mtu
=None, reset
=True):
3738 self
.wait_online(['dummy98:routable'])
3739 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
3740 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
3742 # test normal restart
3744 self
.wait_online(['dummy98:routable'])
3745 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
3746 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
3749 self
.reset_check_mtu(mtu
, ipv6_mtu
)
3751 def reset_check_mtu(self
, mtu
, ipv6_mtu
=None):
3752 ''' test setting mtu/ipv6_mtu with interface already up '''
3755 # note - changing the device mtu resets the ipv6 mtu
3756 run('ip link set up mtu 1501 dev dummy98')
3757 run('ip link set up mtu 1500 dev dummy98')
3758 self
.assertEqual(read_link_attr('dummy98', 'mtu'), '1500')
3759 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), '1500')
3761 self
.check_mtu(mtu
, ipv6_mtu
, reset
=False)
3763 def test_mtu_network(self
):
3764 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
3765 self
.check_mtu('1600')
3767 def test_mtu_netdev(self
):
3768 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network', dropins
=False)
3769 # note - MTU set by .netdev happens ONLY at device creation!
3770 self
.check_mtu('1600', reset
=False)
3772 def test_mtu_link(self
):
3773 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', dropins
=False)
3774 # must reload udev because it only picks up new files after 3 second delay
3775 call('udevadm control --reload')
3776 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
3777 self
.check_mtu('1600', reset
=False)
3779 def test_ipv6_mtu(self
):
3780 ''' set ipv6 mtu without setting device mtu '''
3781 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
3782 self
.check_mtu('1500', '1400')
3784 def test_ipv6_mtu_toolarge(self
):
3785 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
3786 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
3787 self
.check_mtu('1500', '1500')
3789 def test_mtu_network_ipv6_mtu(self
):
3790 ''' set ipv6 mtu and set device mtu via network file '''
3791 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
3792 self
.check_mtu('1600', '1550')
3794 def test_mtu_netdev_ipv6_mtu(self
):
3795 ''' set ipv6 mtu and set device mtu via netdev file '''
3796 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
3797 self
.check_mtu('1600', '1550', reset
=False)
3799 def test_mtu_link_ipv6_mtu(self
):
3800 ''' set ipv6 mtu and set device mtu via link file '''
3801 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
3802 # must reload udev because it only picks up new files after 3 second delay
3803 call('udevadm control --reload')
3804 self
.check_mtu('1600', '1550', reset
=False)
3807 if __name__
== '__main__':
3808 parser
= argparse
.ArgumentParser()
3809 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
3810 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
3811 parser
.add_argument('--resolved', help='Path to systemd-resolved', dest
='resolved_bin')
3812 parser
.add_argument('--udevd', help='Path to systemd-udevd', dest
='udevd_bin')
3813 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
3814 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
3815 parser
.add_argument('--resolvectl', help='Path to resolvectl', dest
='resolvectl_bin')
3816 parser
.add_argument('--timedatectl', help='Path to timedatectl', dest
='timedatectl_bin')
3817 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
3818 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
3819 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
3820 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
3821 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
3822 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
3825 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
:
3826 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
3827 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
3828 resolved_bin
= os
.path
.join(ns
.build_dir
, 'systemd-resolved')
3829 udevd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-udevd')
3830 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
3831 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
3832 resolvectl_bin
= os
.path
.join(ns
.build_dir
, 'resolvectl')
3833 timedatectl_bin
= os
.path
.join(ns
.build_dir
, 'timedatectl')
3836 networkd_bin
= ns
.networkd_bin
3838 resolved_bin
= ns
.resolved_bin
3840 udevd_bin
= ns
.udevd_bin
3841 if ns
.wait_online_bin
:
3842 wait_online_bin
= ns
.wait_online_bin
3843 if ns
.networkctl_bin
:
3844 networkctl_bin
= ns
.networkctl_bin
3845 if ns
.resolvectl_bin
:
3846 resolvectl_bin
= ns
.resolvectl_bin
3847 if ns
.timedatectl_bin
:
3848 timedatectl_bin
= ns
.timedatectl_bin
3850 use_valgrind
= ns
.use_valgrind
3851 enable_debug
= ns
.enable_debug
3852 asan_options
= ns
.asan_options
3853 lsan_options
= ns
.lsan_options
3854 ubsan_options
= ns
.ubsan_options
3857 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
3858 resolvectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin
]
3859 timedatectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin
]
3860 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
3862 networkctl_cmd
= [networkctl_bin
]
3863 resolvectl_cmd
= [resolvectl_bin
]
3864 timedatectl_cmd
= [timedatectl_bin
]
3865 wait_online_cmd
= [wait_online_bin
]
3868 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
3870 env
.update({ 'ASAN_OPTIONS' : asan_options
})
3872 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
3874 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
3877 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,