2 # SPDX-License-Identifier: LGPL-2.1+
3 # systemd-networkd tests
15 from shutil
import copytree
17 network_unit_file_path
='/run/systemd/network'
18 networkd_runtime_directory
='/run/systemd/netif'
19 networkd_ci_path
='/run/networkd-ci'
20 network_sysctl_ipv6_path
='/proc/sys/net/ipv6/conf'
21 network_sysctl_ipv4_path
='/proc/sys/net/ipv4/conf'
23 dnsmasq_pid_file
='/run/networkd-ci/test-test-dnsmasq.pid'
24 dnsmasq_log_file
='/run/networkd-ci/test-dnsmasq-log-file'
26 systemd_lib_paths
=['/usr/lib/systemd', '/lib/systemd']
27 which_paths
=':'.join(systemd_lib_paths
+ os
.getenv('PATH', os
.defpath
).lstrip(':').split(':'))
29 networkd_bin
=shutil
.which('systemd-networkd', path
=which_paths
)
30 resolved_bin
=shutil
.which('systemd-resolved', path
=which_paths
)
31 udevd_bin
=shutil
.which('systemd-udevd', path
=which_paths
)
32 wait_online_bin
=shutil
.which('systemd-networkd-wait-online', path
=which_paths
)
33 networkctl_bin
=shutil
.which('networkctl', path
=which_paths
)
34 resolvectl_bin
=shutil
.which('resolvectl', path
=which_paths
)
35 timedatectl_bin
=shutil
.which('timedatectl', path
=which_paths
)
46 def check_output(*command
, **kwargs
):
47 # This replaces both check_output and check_call (output can be ignored)
48 command
= command
[0].split() + list(command
[1:])
49 return subprocess
.check_output(command
, universal_newlines
=True, **kwargs
).rstrip()
51 def call(*command
, **kwargs
):
52 command
= command
[0].split() + list(command
[1:])
53 return subprocess
.call(command
, universal_newlines
=True, **kwargs
)
55 def run(*command
, **kwargs
):
56 command
= command
[0].split() + list(command
[1:])
57 return subprocess
.run(command
, universal_newlines
=True, **kwargs
)
59 def is_module_available(module_name
):
60 lsmod_output
= check_output('lsmod')
61 module_re
= re
.compile(rf
'^{re.escape(module_name)}\b', re
.MULTILINE
)
62 return module_re
.search(lsmod_output
) or not call('modprobe', module_name
, stderr
=subprocess
.DEVNULL
)
64 def expectedFailureIfModuleIsNotAvailable(module_name
):
66 if not is_module_available(module_name
):
67 return unittest
.expectedFailure(func
)
72 def expectedFailureIfERSPANModuleIsNotAvailable():
74 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
)
76 call('ip link del erspan99')
79 return unittest
.expectedFailure(func
)
83 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable():
85 rc
= call('ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7', stderr
=subprocess
.DEVNULL
)
87 call('ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
90 return unittest
.expectedFailure(func
)
94 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
96 rc
= call('ip rule add not from 192.168.100.19 ipproto tcp table 7', stderr
=subprocess
.DEVNULL
)
98 call('ip rule del not from 192.168.100.19 ipproto tcp table 7')
101 return unittest
.expectedFailure(func
)
105 def expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable():
108 rc
= call('ip rule add from 192.168.100.19 table 7 uidrange 200-300', stderr
=subprocess
.DEVNULL
)
110 ret
= run('ip rule list from 192.168.100.19 table 7', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
111 if ret
.returncode
== 0 and 'uidrange 200-300' in ret
.stdout
.rstrip():
113 call('ip rule del from 192.168.100.19 table 7 uidrange 200-300')
118 return unittest
.expectedFailure(func
)
122 def expectedFailureIfLinkFileFieldIsNotSet():
125 rc
= call('ip link add name dummy99 type dummy', stderr
=subprocess
.DEVNULL
)
127 ret
= run('udevadm info -w10s /sys/class/net/dummy99', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
128 if ret
.returncode
== 0 and 'E: ID_NET_LINK_FILE=' in ret
.stdout
.rstrip():
130 call('ip link del dummy99')
135 return unittest
.expectedFailure(func
)
139 def expectedFailureIfNexthopIsNotAvailable():
141 rc
= call('ip nexthop list', stderr
=subprocess
.DEVNULL
)
145 return unittest
.expectedFailure(func
)
149 def expectedFailureIfAlternativeNameIsNotAvailable():
151 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
152 rc
= call('ip link prop add dev dummy98 altname hogehogehogehogehoge', stderr
=subprocess
.DEVNULL
)
153 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
157 return unittest
.expectedFailure(func
)
161 def expectedFailureIfCAKEIsNotAvailable():
163 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
164 rc
= call('tc qdisc add dev dummy98 parent root cake', stderr
=subprocess
.DEVNULL
)
165 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
169 return unittest
.expectedFailure(func
)
173 def expectedFailureIfPIEIsNotAvailable():
175 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
176 rc
= call('tc qdisc add dev dummy98 parent root pie', stderr
=subprocess
.DEVNULL
)
177 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
181 return unittest
.expectedFailure(func
)
185 def expectedFailureIfHHFIsNotAvailable():
187 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
188 rc
= call('tc qdisc add dev dummy98 parent root hhf', stderr
=subprocess
.DEVNULL
)
189 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
193 return unittest
.expectedFailure(func
)
200 os
.makedirs(network_unit_file_path
, exist_ok
=True)
201 os
.makedirs(networkd_ci_path
, exist_ok
=True)
203 shutil
.rmtree(networkd_ci_path
)
204 copytree(os
.path
.join(os
.path
.dirname(os
.path
.abspath(__file__
)), 'conf'), networkd_ci_path
)
206 for u
in ['systemd-networkd.socket', 'systemd-networkd.service', 'systemd-resolved.service',
207 'systemd-udevd-kernel.socket', 'systemd-udevd-control.socket', 'systemd-udevd.service',
208 'firewalld.service']:
209 if call(f
'systemctl is-active --quiet {u}') == 0:
210 check_output(f
'systemctl stop {u}')
211 running_units
.append(u
)
215 'StartLimitIntervalSec=0',
222 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin
,
226 drop_in
+= ['ExecStart=!!' + networkd_bin
]
228 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
230 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
232 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
234 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
235 if asan_options
or lsan_options
or ubsan_options
:
236 drop_in
+= ['SystemCallFilter=']
237 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
238 drop_in
+= ['MemoryDenyWriteExecute=no']
240 os
.makedirs('/run/systemd/system/systemd-networkd.service.d', exist_ok
=True)
241 with
open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode
='w') as f
:
242 f
.write('\n'.join(drop_in
))
250 drop_in
+= ['ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + resolved_bin
]
252 drop_in
+= ['ExecStart=!!' + resolved_bin
]
254 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
256 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
258 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
260 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
261 if asan_options
or lsan_options
or ubsan_options
:
262 drop_in
+= ['SystemCallFilter=']
263 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
264 drop_in
+= ['MemoryDenyWriteExecute=no']
266 os
.makedirs('/run/systemd/system/systemd-resolved.service.d', exist_ok
=True)
267 with
open('/run/systemd/system/systemd-resolved.service.d/00-override.conf', mode
='w') as f
:
268 f
.write('\n'.join(drop_in
))
273 'ExecStart=!!' + udevd_bin
,
276 os
.makedirs('/run/systemd/system/systemd-udevd.service.d', exist_ok
=True)
277 with
open('/run/systemd/system/systemd-udevd.service.d/00-override.conf', mode
='w') as f
:
278 f
.write('\n'.join(drop_in
))
280 check_output('systemctl daemon-reload')
281 print(check_output('systemctl cat systemd-networkd.service'))
282 print(check_output('systemctl cat systemd-resolved.service'))
283 print(check_output('systemctl cat systemd-udevd.service'))
284 check_output('systemctl restart systemd-resolved')
285 check_output('systemctl restart systemd-udevd')
287 def tearDownModule():
290 shutil
.rmtree(networkd_ci_path
)
292 for u
in ['systemd-networkd.service', 'systemd-resolved.service']:
293 check_output(f
'systemctl stop {u}')
295 shutil
.rmtree('/run/systemd/system/systemd-networkd.service.d')
296 shutil
.rmtree('/run/systemd/system/systemd-resolved.service.d')
297 shutil
.rmtree('/run/systemd/system/systemd-udevd.service.d')
298 check_output('systemctl daemon-reload')
299 check_output('systemctl restart systemd-udevd.service')
301 for u
in running_units
:
302 check_output(f
'systemctl start {u}')
304 def read_link_attr(*args
):
305 with
open(os
.path
.join('/sys/class/net/', *args
)) as f
:
306 return f
.readline().strip()
308 def read_bridge_port_attr(bridge
, link
, attribute
):
309 path_bridge
= os
.path
.join('/sys/devices/virtual/net', bridge
)
310 path_port
= 'lower_' + link
+ '/brport'
311 path
= os
.path
.join(path_bridge
, path_port
)
313 with
open(os
.path
.join(path
, attribute
)) as f
:
314 return f
.readline().strip()
316 def link_exists(link
):
317 return os
.path
.exists(os
.path
.join('/sys/class/net', link
))
319 def remove_links(links
):
321 if link_exists(link
):
322 call('ip link del dev', link
)
325 def remove_fou_ports(ports
):
327 call('ip fou del port', port
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
329 def remove_routing_policy_rule_tables(tables
):
333 rc
= call('ip rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
335 def remove_routes(routes
):
336 for route_type
, addr
in routes
:
337 call('ip route del', route_type
, addr
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
339 def remove_l2tp_tunnels(tunnel_ids
):
340 output
= check_output('ip l2tp show tunnel')
341 for tid
in tunnel_ids
:
342 words
='Tunnel ' + tid
+ ', encap'
344 call('ip l2tp del tunnel tid', tid
)
347 def read_ipv6_sysctl_attr(link
, attribute
):
348 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, link
), attribute
)) as f
:
349 return f
.readline().strip()
351 def read_ipv4_sysctl_attr(link
, attribute
):
352 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv4_path
, link
), attribute
)) as f
:
353 return f
.readline().strip()
355 def copy_unit_to_networkd_unit_path(*units
, dropins
=True):
356 """Copy networkd unit files into the testbed.
358 Any networkd unit file type can be specified, as well as drop-in files.
360 By default, all drop-ins for a specified unit file are copied in;
361 to avoid that specify dropins=False.
363 When a drop-in file is specified, its unit file is also copied in automatically.
367 if dropins
and os
.path
.exists(os
.path
.join(networkd_ci_path
, unit
+ '.d')):
368 copytree(os
.path
.join(networkd_ci_path
, unit
+ '.d'), os
.path
.join(network_unit_file_path
, unit
+ '.d'))
369 if unit
.endswith('.conf'):
371 dropindir
= os
.path
.join(network_unit_file_path
, os
.path
.dirname(dropin
))
372 os
.makedirs(dropindir
, exist_ok
=True)
373 shutil
.copy(os
.path
.join(networkd_ci_path
, dropin
), dropindir
)
374 unit
= os
.path
.dirname(dropin
).rstrip('.d')
375 shutil
.copy(os
.path
.join(networkd_ci_path
, unit
), network_unit_file_path
)
377 def remove_unit_from_networkd_path(units
):
378 """Remove previously copied unit files from the testbed.
380 Drop-ins will be removed automatically.
383 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
))):
384 os
.remove(os
.path
.join(network_unit_file_path
, unit
))
385 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
+ '.d'))):
386 shutil
.rmtree(os
.path
.join(network_unit_file_path
, unit
+ '.d'))
388 def start_dnsmasq(additional_options
='', ipv4_range
='192.168.5.10,192.168.5.200', ipv6_range
='2600::10,2600::20', lease_time
='1h'):
389 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
390 check_output(dnsmasq_command
)
392 def stop_dnsmasq(pid_file
):
393 if os
.path
.exists(pid_file
):
394 with
open(pid_file
, 'r') as f
:
395 pid
= f
.read().rstrip(' \t\r\n\0')
396 os
.kill(int(pid
), signal
.SIGTERM
)
400 def search_words_in_dnsmasq_log(words
, show_all
=False):
401 if os
.path
.exists(dnsmasq_log_file
):
402 with
open (dnsmasq_log_file
) as in_file
:
403 contents
= in_file
.read()
406 for line
in contents
.splitlines():
409 print("%s, %s" % (words
, line
))
413 def remove_lease_file():
414 if os
.path
.exists(os
.path
.join(networkd_ci_path
, 'lease')):
415 os
.remove(os
.path
.join(networkd_ci_path
, 'lease'))
417 def remove_log_file():
418 if os
.path
.exists(dnsmasq_log_file
):
419 os
.remove(dnsmasq_log_file
)
421 def remove_networkd_state_files():
422 if os
.path
.exists(os
.path
.join(networkd_runtime_directory
, 'state')):
423 os
.remove(os
.path
.join(networkd_runtime_directory
, 'state'))
425 def stop_networkd(show_logs
=True, remove_state_files
=True):
427 invocation_id
= check_output('systemctl show systemd-networkd -p InvocationID --value')
428 check_output('systemctl stop systemd-networkd')
430 print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
))
431 if remove_state_files
:
432 remove_networkd_state_files()
434 def start_networkd(sleep_sec
=0):
435 check_output('systemctl start systemd-networkd')
437 time
.sleep(sleep_sec
)
439 def restart_networkd(sleep_sec
=0, show_logs
=True, remove_state_files
=True):
440 stop_networkd(show_logs
, remove_state_files
)
441 start_networkd(sleep_sec
)
445 def check_link_exists(self
, link
):
446 self
.assertTrue(link_exists(link
))
448 def check_link_attr(self
, *args
):
449 self
.assertEqual(read_link_attr(*args
[:-1]), args
[-1]);
451 def wait_operstate(self
, link
, operstate
='degraded', setup_state
='configured', setup_timeout
=5, fail_assert
=True):
452 """Wait for the link to reach the specified operstate and/or setup state.
454 Specify None or '' for either operstate or setup_state to ignore that state.
455 This will recheck until the state conditions are met or the timeout expires.
457 If the link successfully matches the requested state, this returns True.
458 If this times out waiting for the link to match, the behavior depends on the
459 'fail_assert' parameter; if True, this causes a test assertion failure,
460 otherwise this returns False. The default is to cause assertion failure.
462 Note that this function matches on *exactly* the given operstate and setup_state.
463 To wait for a link to reach *or exceed* a given operstate, use wait_online().
470 for secs
in range(setup_timeout
+ 1):
471 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
, env
=env
)
473 if re
.search(rf
'(?m)^\s*State:\s+{operstate}\s+\({setup_state}\)\s*$', output
):
475 # don't bother sleeping if time is up
476 if secs
< setup_timeout
:
479 self
.fail(f
'Timed out waiting for {link} to reach state {operstate}/{setup_state}')
482 def wait_online(self
, links_with_operstate
, timeout
='20s', bool_any
=False, setup_state
='configured', setup_timeout
=5):
483 """Wait for the link(s) to reach the specified operstate and/or setup state.
485 This is similar to wait_operstate() but can be used for multiple links,
486 and it also calls systemd-networkd-wait-online to wait for the given operstate.
487 The operstate should be specified in the link name, like 'eth0:degraded'.
488 If just a link name is provided, wait-online's default operstate to wait for is degraded.
490 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
491 'setup_timeout' controls the per-link timeout waiting for the setup_state.
493 Set 'bool_any' to True to wait for any (instead of all) of the given links.
494 If this is set, no setup_state checks are done.
496 Note that this function waits for the link(s) to reach *or exceed* the given operstate.
497 However, the setup_state, if specified, must be matched *exactly*.
499 This returns if the link(s) reached the requested operstate/setup_state; otherwise it
500 raises CalledProcessError or fails test assertion.
502 args
= wait_online_cmd
+ [f
'--timeout={timeout}'] + [f
'--interface={link}' for link
in links_with_operstate
]
506 check_output(*args
, env
=env
)
507 except subprocess
.CalledProcessError
:
508 for link
in links_with_operstate
:
509 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
.split(':')[0], env
=env
)
512 if not bool_any
and setup_state
:
513 for link
in links_with_operstate
:
514 self
.wait_operstate(link
.split(':')[0], None, setup_state
, setup_timeout
)
516 def wait_address(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
517 for i
in range(timeout_sec
):
520 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
521 if re
.search(address_regex
, output
):
524 self
.assertRegex(output
, address_regex
)
526 class NetworkctlTests(unittest
.TestCase
, Utilities
):
536 '11-dummy-mtu.netdev',
540 '25-address-static.network',
542 'netdev-link-local-addressing-yes.network',
546 remove_links(self
.links
)
547 stop_networkd(show_logs
=False)
550 remove_links(self
.links
)
551 remove_unit_from_networkd_path(self
.units
)
552 stop_networkd(show_logs
=True)
554 @expectedFailureIfAlternativeNameIsNotAvailable()
555 def test_altname(self
):
556 copy_unit_to_networkd_unit_path('netdev-link-local-addressing-yes.network', '12-dummy.netdev', '12-dummy.link')
557 check_output('udevadm control --reload')
559 self
.wait_online(['dummy98:degraded'])
561 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
562 self
.assertRegex(output
, 'hogehogehogehogehogehoge')
564 def test_reconfigure(self
):
565 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
567 self
.wait_online(['dummy98:routable'])
569 output
= check_output('ip -4 address show dev dummy98')
571 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
572 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
573 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
575 check_output('ip address del 10.1.2.3/16 dev dummy98')
576 check_output('ip address del 10.1.2.4/16 dev dummy98')
577 check_output('ip address del 10.2.2.4/16 dev dummy98')
579 check_output(*networkctl_cmd
, 'reconfigure', 'dummy98', env
=env
)
580 self
.wait_online(['dummy98:routable'])
582 output
= check_output('ip -4 address show dev dummy98')
584 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
585 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
586 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
588 def test_reload(self
):
591 copy_unit_to_networkd_unit_path('11-dummy.netdev')
592 check_output(*networkctl_cmd
, 'reload', env
=env
)
593 self
.wait_operstate('test1', 'off', setup_state
='unmanaged')
595 copy_unit_to_networkd_unit_path('11-dummy.network')
596 check_output(*networkctl_cmd
, 'reload', env
=env
)
597 self
.wait_online(['test1:degraded'])
599 remove_unit_from_networkd_path(['11-dummy.network'])
600 check_output(*networkctl_cmd
, 'reload', env
=env
)
601 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
603 remove_unit_from_networkd_path(['11-dummy.netdev'])
604 check_output(*networkctl_cmd
, 'reload', env
=env
)
605 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
607 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
608 check_output(*networkctl_cmd
, 'reload', env
=env
)
609 self
.wait_operstate('test1', 'degraded')
612 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
615 self
.wait_online(['test1:degraded'])
617 output
= check_output(*networkctl_cmd
, 'list', env
=env
)
618 self
.assertRegex(output
, '1 lo ')
619 self
.assertRegex(output
, 'test1')
621 output
= check_output(*networkctl_cmd
, 'list', 'test1', env
=env
)
622 self
.assertNotRegex(output
, '1 lo ')
623 self
.assertRegex(output
, 'test1')
625 output
= check_output(*networkctl_cmd
, 'list', 'te*', env
=env
)
626 self
.assertNotRegex(output
, '1 lo ')
627 self
.assertRegex(output
, 'test1')
629 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'te*', env
=env
)
630 self
.assertNotRegex(output
, '1: lo ')
631 self
.assertRegex(output
, 'test1')
633 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'tes[a-z][0-9]', env
=env
)
634 self
.assertNotRegex(output
, '1: lo ')
635 self
.assertRegex(output
, 'test1')
638 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
641 self
.wait_online(['test1:degraded'])
643 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
644 self
.assertRegex(output
, 'MTU: 1600')
647 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
649 self
.wait_online(['test1:degraded'])
651 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
653 self
.assertRegex(output
, 'Type: ether')
655 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
657 self
.assertRegex(output
, 'Type: loopback')
659 @expectedFailureIfLinkFileFieldIsNotSet()
660 def test_udev_link_file(self
):
661 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
663 self
.wait_online(['test1:degraded'])
665 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
667 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
668 self
.assertRegex(output
, r
'Network File: /run/systemd/network/11-dummy.network')
670 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
672 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
673 self
.assertRegex(output
, r
'Network File: n/a')
675 def test_delete_links(self
):
676 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
677 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
680 self
.wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
682 check_output(*networkctl_cmd
, 'delete', 'test1', 'veth99', env
=env
)
683 self
.assertFalse(link_exists('test1'))
684 self
.assertFalse(link_exists('veth99'))
685 self
.assertFalse(link_exists('veth-peer'))
687 class NetworkdNetDevTests(unittest
.TestCase
, Utilities
):
689 links_remove_earlier
= [
755 '10-dropin-test.netdev',
759 '13-not-match-udev-property.network',
760 '14-match-udev-property.network',
761 '15-name-conflict-test.netdev',
764 '21-vlan-test1.network',
767 '25-6rd-tunnel.netdev',
769 '25-bond-balanced-tlb.netdev',
771 '25-bridge-configure-without-carrier.network',
773 '25-erspan-tunnel-local-any.netdev',
774 '25-erspan-tunnel.netdev',
775 '25-fou-gretap.netdev',
777 '25-fou-ipip.netdev',
778 '25-fou-ipproto-gre.netdev',
779 '25-fou-ipproto-ipip.netdev',
782 '25-gretap-tunnel-local-any.netdev',
783 '25-gretap-tunnel.netdev',
784 '25-gre-tunnel-any-any.netdev',
785 '25-gre-tunnel-local-any.netdev',
786 '25-gre-tunnel-remote-any.netdev',
787 '25-gre-tunnel.netdev',
789 '25-ip6gretap-tunnel-local-any.netdev',
790 '25-ip6gretap-tunnel.netdev',
791 '25-ip6gre-tunnel-any-any.netdev',
792 '25-ip6gre-tunnel-local-any.netdev',
793 '25-ip6gre-tunnel-remote-any.netdev',
794 '25-ip6gre-tunnel.netdev',
795 '25-ip6tnl-tunnel-any-any.netdev',
796 '25-ip6tnl-tunnel-local-any.netdev',
797 '25-ip6tnl-tunnel-remote-any.netdev',
798 '25-ip6tnl-tunnel.netdev',
799 '25-ipip-tunnel-any-any.netdev',
800 '25-ipip-tunnel-independent.netdev',
801 '25-ipip-tunnel-independent-loopback.netdev',
802 '25-ipip-tunnel-local-any.netdev',
803 '25-ipip-tunnel-remote-any.netdev',
804 '25-ipip-tunnel.netdev',
807 '25-isatap-tunnel.netdev',
812 '25-sit-tunnel-any-any.netdev',
813 '25-sit-tunnel-local-any.netdev',
814 '25-sit-tunnel-remote-any.netdev',
815 '25-sit-tunnel.netdev',
818 '25-tunnel-local-any.network',
819 '25-tunnel-remote-any.network',
824 '25-vti6-tunnel-any-any.netdev',
825 '25-vti6-tunnel-local-any.netdev',
826 '25-vti6-tunnel-remote-any.netdev',
827 '25-vti6-tunnel.netdev',
828 '25-vti-tunnel-any-any.netdev',
829 '25-vti-tunnel-local-any.netdev',
830 '25-vti-tunnel-remote-any.netdev',
831 '25-vti-tunnel.netdev',
834 '25-wireguard-23-peers.netdev',
835 '25-wireguard-23-peers.network',
836 '25-wireguard-no-peer.netdev',
837 '25-wireguard-no-peer.network',
838 '25-wireguard-preshared-key.txt',
839 '25-wireguard-private-key.txt',
840 '25-wireguard.netdev',
841 '25-wireguard.network',
843 '25-xfrm-independent.netdev',
859 'netdev-link-local-addressing-yes.network',
863 'vxlan-test1.network',
873 remove_fou_ports(self
.fou_ports
)
874 remove_links(self
.links_remove_earlier
)
875 remove_links(self
.links
)
876 stop_networkd(show_logs
=False)
879 remove_fou_ports(self
.fou_ports
)
880 remove_links(self
.links_remove_earlier
)
881 remove_links(self
.links
)
882 remove_unit_from_networkd_path(self
.units
)
883 stop_networkd(show_logs
=True)
885 def test_dropin_and_name_conflict(self
):
886 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
889 self
.wait_online(['dropin-test:off'], setup_state
='unmanaged')
891 output
= check_output('ip link show dropin-test')
893 self
.assertRegex(output
, '00:50:56:c0:00:28')
895 def test_match_udev_property(self
):
896 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
898 self
.wait_online(['dummy98:routable'])
900 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
902 self
.assertRegex(output
, 'Network File: /run/systemd/network/14-match-udev-property')
904 def test_wait_online_any(self
):
905 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
908 self
.wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
910 self
.wait_operstate('bridge99', '(off|no-carrier)', setup_state
='configuring')
911 self
.wait_operstate('test1', 'degraded')
913 def test_bridge(self
):
914 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
917 self
.wait_online(['bridge99:no-carrier'])
919 tick
= os
.sysconf('SC_CLK_TCK')
920 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
921 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
922 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'forward_delay')) / tick
))
923 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'ageing_time')) / tick
))
924 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge', 'priority')))
925 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_querier')))
926 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_snooping')))
927 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'stp_state')))
928 self
.assertEqual(3, int(read_link_attr('bridge99', 'bridge', 'multicast_igmp_version')))
930 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
932 self
.assertRegex(output
, 'Priority: 9')
933 self
.assertRegex(output
, 'STP: yes')
934 self
.assertRegex(output
, 'Multicast IGMP Version: 3')
937 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
940 self
.wait_online(['bond99:off', 'bond98:off'], setup_state
='unmanaged')
942 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
943 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
944 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
945 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
946 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
947 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
948 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
949 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
950 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
951 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
952 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
954 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
955 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
958 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
959 '21-vlan.network', '21-vlan-test1.network')
962 self
.wait_online(['test1:degraded', 'vlan99:routable'])
964 output
= check_output('ip -d link show test1')
966 self
.assertRegex(output
, ' mtu 2000 ')
968 output
= check_output('ip -d link show vlan99')
970 self
.assertRegex(output
, ' mtu 2000 ')
971 self
.assertRegex(output
, 'REORDER_HDR')
972 self
.assertRegex(output
, 'LOOSE_BINDING')
973 self
.assertRegex(output
, 'GVRP')
974 self
.assertRegex(output
, 'MVRP')
975 self
.assertRegex(output
, ' id 99 ')
977 output
= check_output('ip -4 address show dev test1')
979 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
980 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
982 output
= check_output('ip -4 address show dev vlan99')
984 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
986 def test_macvtap(self
):
987 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
988 with self
.subTest(mode
=mode
):
989 if mode
!= 'private':
991 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
992 '11-dummy.netdev', 'macvtap.network')
993 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
994 f
.write('[MACVTAP]\nMode=' + mode
)
997 self
.wait_online(['macvtap99:degraded', 'test1:degraded'])
999 output
= check_output('ip -d link show macvtap99')
1001 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
1003 def test_macvlan(self
):
1004 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
1005 with self
.subTest(mode
=mode
):
1006 if mode
!= 'private':
1008 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
1009 '11-dummy.netdev', 'macvlan.network')
1010 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
1011 f
.write('[MACVLAN]\nMode=' + mode
)
1014 self
.wait_online(['macvlan99:degraded', 'test1:degraded'])
1016 output
= check_output('ip -d link show test1')
1018 self
.assertRegex(output
, ' mtu 2000 ')
1020 output
= check_output('ip -d link show macvlan99')
1022 self
.assertRegex(output
, ' mtu 2000 ')
1023 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
1025 @expectedFailureIfModuleIsNotAvailable('ipvlan')
1026 def test_ipvlan(self
):
1027 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1028 with self
.subTest(mode
=mode
, flag
=flag
):
1031 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
1032 '11-dummy.netdev', 'ipvlan.network')
1033 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
1034 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
1037 self
.wait_online(['ipvlan99:degraded', 'test1:degraded'])
1039 output
= check_output('ip -d link show ipvlan99')
1041 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
1043 @expectedFailureIfModuleIsNotAvailable('ipvtap')
1044 def test_ipvtap(self
):
1045 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1046 with self
.subTest(mode
=mode
, flag
=flag
):
1049 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
1050 '11-dummy.netdev', 'ipvtap.network')
1051 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
1052 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
1055 self
.wait_online(['ipvtap99:degraded', 'test1:degraded'])
1057 output
= check_output('ip -d link show ipvtap99')
1059 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
1061 def test_veth(self
):
1062 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
1065 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
1067 output
= check_output('ip -d link show veth99')
1069 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
1070 output
= check_output('ip -d link show veth-peer')
1072 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
1075 copy_unit_to_networkd_unit_path('25-tun.netdev')
1078 self
.wait_online(['tun99:off'], setup_state
='unmanaged')
1080 output
= check_output('ip -d link show tun99')
1082 # Old ip command does not support IFF_ flags
1083 self
.assertRegex(output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
1086 copy_unit_to_networkd_unit_path('25-tap.netdev')
1089 self
.wait_online(['tap99:off'], setup_state
='unmanaged')
1091 output
= check_output('ip -d link show tap99')
1093 # Old ip command does not support IFF_ flags
1094 self
.assertRegex(output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
1096 @expectedFailureIfModuleIsNotAvailable('vrf')
1098 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
1101 self
.wait_online(['vrf99:carrier'])
1103 @expectedFailureIfModuleIsNotAvailable('vcan')
1104 def test_vcan(self
):
1105 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
1108 self
.wait_online(['vcan99:carrier'])
1110 @expectedFailureIfModuleIsNotAvailable('vxcan')
1111 def test_vxcan(self
):
1112 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
1115 self
.wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
1117 @expectedFailureIfModuleIsNotAvailable('wireguard')
1118 def test_wireguard(self
):
1119 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
1120 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
1121 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt',
1122 '25-wireguard-no-peer.netdev', '25-wireguard-no-peer.network')
1124 self
.wait_online(['wg99:carrier', 'wg98:routable', 'wg97:carrier'])
1126 if shutil
.which('wg'):
1129 output
= check_output('wg show wg99 listen-port')
1130 self
.assertRegex(output
, '51820')
1131 output
= check_output('wg show wg99 fwmark')
1132 self
.assertRegex(output
, '0x4d2')
1133 output
= check_output('wg show wg99 allowed-ips')
1134 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
1135 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
1136 output
= check_output('wg show wg99 persistent-keepalive')
1137 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
1138 output
= check_output('wg show wg99 endpoints')
1139 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
1140 output
= check_output('wg show wg99 private-key')
1141 self
.assertRegex(output
, r
'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
1142 output
= check_output('wg show wg99 preshared-keys')
1143 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
1144 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
1146 output
= check_output('wg show wg98 private-key')
1147 self
.assertRegex(output
, r
'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
1149 output
= check_output('wg show wg97 listen-port')
1150 self
.assertRegex(output
, '51821')
1151 output
= check_output('wg show wg97 fwmark')
1152 self
.assertRegex(output
, '0x4d3')
1154 def test_geneve(self
):
1155 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
1158 self
.wait_online(['geneve99:degraded'])
1160 output
= check_output('ip -d link show geneve99')
1162 self
.assertRegex(output
, '192.168.22.1')
1163 self
.assertRegex(output
, '6082')
1164 self
.assertRegex(output
, 'udpcsum')
1165 self
.assertRegex(output
, 'udp6zerocsumrx')
1167 def test_ipip_tunnel(self
):
1168 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
1169 '25-ipip-tunnel.netdev', '25-tunnel.network',
1170 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1171 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1172 '25-ipip-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1174 self
.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'ipiptun96:routable', 'dummy98:degraded'])
1176 output
= check_output('ip -d link show ipiptun99')
1178 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98')
1179 output
= check_output('ip -d link show ipiptun98')
1181 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98')
1182 output
= check_output('ip -d link show ipiptun97')
1184 self
.assertRegex(output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98')
1185 output
= check_output('ip -d link show ipiptun96')
1187 self
.assertRegex(output
, 'ipip (ipip )?remote any local any dev dummy98')
1189 def test_gre_tunnel(self
):
1190 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
1191 '25-gre-tunnel.netdev', '25-tunnel.network',
1192 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1193 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1194 '25-gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1196 self
.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'gretun96:routable', 'dummy98:degraded'])
1198 output
= check_output('ip -d link show gretun99')
1200 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1201 self
.assertRegex(output
, 'ikey 1.2.3.103')
1202 self
.assertRegex(output
, 'okey 1.2.4.103')
1203 self
.assertRegex(output
, 'iseq')
1204 self
.assertRegex(output
, 'oseq')
1205 output
= check_output('ip -d link show gretun98')
1207 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
1208 self
.assertRegex(output
, 'ikey 0.0.0.104')
1209 self
.assertRegex(output
, 'okey 0.0.0.104')
1210 self
.assertNotRegex(output
, 'iseq')
1211 self
.assertNotRegex(output
, 'oseq')
1212 output
= check_output('ip -d link show gretun97')
1214 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
1215 self
.assertRegex(output
, 'ikey 0.0.0.105')
1216 self
.assertRegex(output
, 'okey 0.0.0.105')
1217 self
.assertNotRegex(output
, 'iseq')
1218 self
.assertNotRegex(output
, 'oseq')
1219 output
= check_output('ip -d link show gretun96')
1221 self
.assertRegex(output
, 'gre remote any local any dev dummy98')
1222 self
.assertRegex(output
, 'ikey 0.0.0.106')
1223 self
.assertRegex(output
, 'okey 0.0.0.106')
1224 self
.assertNotRegex(output
, 'iseq')
1225 self
.assertNotRegex(output
, 'oseq')
1227 def test_ip6gre_tunnel(self
):
1228 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
1229 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
1230 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1231 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1232 '25-ip6gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1235 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1237 self
.check_link_exists('dummy98')
1238 self
.check_link_exists('ip6gretun99')
1239 self
.check_link_exists('ip6gretun98')
1240 self
.check_link_exists('ip6gretun97')
1241 self
.check_link_exists('ip6gretun96')
1243 output
= check_output('ip -d link show ip6gretun99')
1245 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1246 output
= check_output('ip -d link show ip6gretun98')
1248 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
1249 output
= check_output('ip -d link show ip6gretun97')
1251 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
1252 output
= check_output('ip -d link show ip6gretun96')
1254 self
.assertRegex(output
, 'ip6gre remote any local any dev dummy98')
1256 def test_gretap_tunnel(self
):
1257 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
1258 '25-gretap-tunnel.netdev', '25-tunnel.network',
1259 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1261 self
.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
1263 output
= check_output('ip -d link show gretap99')
1265 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1266 self
.assertRegex(output
, 'ikey 0.0.0.106')
1267 self
.assertRegex(output
, 'okey 0.0.0.106')
1268 self
.assertRegex(output
, 'iseq')
1269 self
.assertRegex(output
, 'oseq')
1270 output
= check_output('ip -d link show gretap98')
1272 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
1273 self
.assertRegex(output
, 'ikey 0.0.0.107')
1274 self
.assertRegex(output
, 'okey 0.0.0.107')
1275 self
.assertRegex(output
, 'iseq')
1276 self
.assertRegex(output
, 'oseq')
1278 def test_ip6gretap_tunnel(self
):
1279 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
1280 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1281 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1283 self
.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
1285 output
= check_output('ip -d link show ip6gretap99')
1287 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1288 output
= check_output('ip -d link show ip6gretap98')
1290 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1292 def test_vti_tunnel(self
):
1293 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
1294 '25-vti-tunnel.netdev', '25-tunnel.network',
1295 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1296 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1297 '25-vti-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1299 self
.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'vtitun96:routable', 'dummy98:degraded'])
1301 output
= check_output('ip -d link show vtitun99')
1303 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1304 output
= check_output('ip -d link show vtitun98')
1306 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
1307 output
= check_output('ip -d link show vtitun97')
1309 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
1310 output
= check_output('ip -d link show vtitun96')
1312 self
.assertRegex(output
, 'vti remote any local any dev dummy98')
1314 def test_vti6_tunnel(self
):
1315 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
1316 '25-vti6-tunnel.netdev', '25-tunnel.network',
1317 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1318 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1320 self
.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
1322 output
= check_output('ip -d link show vti6tun99')
1324 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1325 output
= check_output('ip -d link show vti6tun98')
1327 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1328 output
= check_output('ip -d link show vti6tun97')
1330 self
.assertRegex(output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1332 def test_ip6tnl_tunnel(self
):
1333 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
1334 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1335 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1336 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1338 self
.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
1340 output
= check_output('ip -d link show ip6tnl99')
1342 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1343 output
= check_output('ip -d link show ip6tnl98')
1345 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1346 output
= check_output('ip -d link show ip6tnl97')
1348 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1350 def test_sit_tunnel(self
):
1351 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1352 '25-sit-tunnel.netdev', '25-tunnel.network',
1353 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1354 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1355 '25-sit-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1357 self
.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'sittun96:routable', 'dummy98:degraded'])
1359 output
= check_output('ip -d link show sittun99')
1361 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1362 output
= check_output('ip -d link show sittun98')
1364 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98")
1365 output
= check_output('ip -d link show sittun97')
1367 self
.assertRegex(output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98")
1368 output
= check_output('ip -d link show sittun96')
1370 self
.assertRegex(output
, "sit (ip6ip )?remote any local any dev dummy98")
1372 def test_isatap_tunnel(self
):
1373 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1374 '25-isatap-tunnel.netdev', '25-tunnel.network')
1376 self
.wait_online(['isataptun99:routable', 'dummy98:degraded'])
1378 output
= check_output('ip -d link show isataptun99')
1380 self
.assertRegex(output
, "isatap ")
1382 def test_6rd_tunnel(self
):
1383 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1384 '25-6rd-tunnel.netdev', '25-tunnel.network')
1386 self
.wait_online(['sittun99:routable', 'dummy98:degraded'])
1388 output
= check_output('ip -d link show sittun99')
1390 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1392 @expectedFailureIfERSPANModuleIsNotAvailable()
1393 def test_erspan_tunnel(self
):
1394 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1395 '25-erspan-tunnel.netdev', '25-tunnel.network',
1396 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1398 self
.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1400 output
= check_output('ip -d link show erspan99')
1402 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1403 self
.assertRegex(output
, 'ikey 0.0.0.101')
1404 self
.assertRegex(output
, 'okey 0.0.0.101')
1405 self
.assertRegex(output
, 'iseq')
1406 self
.assertRegex(output
, 'oseq')
1407 output
= check_output('ip -d link show erspan98')
1409 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1410 self
.assertRegex(output
, '102')
1411 self
.assertRegex(output
, 'ikey 0.0.0.102')
1412 self
.assertRegex(output
, 'okey 0.0.0.102')
1413 self
.assertRegex(output
, 'iseq')
1414 self
.assertRegex(output
, 'oseq')
1416 def test_tunnel_independent(self
):
1417 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1420 self
.wait_online(['ipiptun99:carrier'])
1422 def test_tunnel_independent_loopback(self
):
1423 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent-loopback.netdev', 'netdev-link-local-addressing-yes.network')
1426 self
.wait_online(['ipiptun99:carrier'])
1428 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1429 def test_xfrm(self
):
1430 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'xfrm.network',
1431 '25-xfrm.netdev', 'netdev-link-local-addressing-yes.network')
1434 self
.wait_online(['xfrm99:degraded', 'dummy98:degraded'])
1436 output
= check_output('ip link show dev xfrm99')
1439 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1440 def test_xfrm_independent(self
):
1441 copy_unit_to_networkd_unit_path('25-xfrm-independent.netdev', 'netdev-link-local-addressing-yes.network')
1444 self
.wait_online(['xfrm99:degraded'])
1446 @expectedFailureIfModuleIsNotAvailable('fou')
1448 # The following redundant check is necessary for CentOS CI.
1449 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1450 self
.assertTrue(is_module_available('fou'))
1452 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1453 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1454 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1457 self
.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'], setup_state
='unmanaged')
1459 output
= check_output('ip fou show')
1461 self
.assertRegex(output
, 'port 55555 ipproto 4')
1462 self
.assertRegex(output
, 'port 55556 ipproto 47')
1464 output
= check_output('ip -d link show ipiptun96')
1466 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1467 output
= check_output('ip -d link show sittun96')
1469 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1470 output
= check_output('ip -d link show gretun96')
1472 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1473 output
= check_output('ip -d link show gretap96')
1475 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1477 def test_vxlan(self
):
1478 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1479 '11-dummy.netdev', 'vxlan-test1.network')
1482 self
.wait_online(['test1:degraded', 'vxlan99:degraded'])
1484 output
= check_output('ip -d link show vxlan99')
1486 self
.assertRegex(output
, '999')
1487 self
.assertRegex(output
, '5555')
1488 self
.assertRegex(output
, 'l2miss')
1489 self
.assertRegex(output
, 'l3miss')
1490 self
.assertRegex(output
, 'udpcsum')
1491 self
.assertRegex(output
, 'udp6zerocsumtx')
1492 self
.assertRegex(output
, 'udp6zerocsumrx')
1493 self
.assertRegex(output
, 'remcsumtx')
1494 self
.assertRegex(output
, 'remcsumrx')
1495 self
.assertRegex(output
, 'gbp')
1497 output
= check_output('bridge fdb show dev vxlan99')
1499 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1500 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1501 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1503 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'vxlan99', env
=env
)
1505 self
.assertRegex(output
, 'VNI: 999')
1506 self
.assertRegex(output
, 'Destination Port: 5555')
1507 self
.assertRegex(output
, 'Underlying Device: test1')
1509 def test_macsec(self
):
1510 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1511 'macsec.network', '12-dummy.netdev')
1514 self
.wait_online(['dummy98:degraded', 'macsec99:routable'])
1516 output
= check_output('ip -d link show macsec99')
1518 self
.assertRegex(output
, 'macsec99@dummy98')
1519 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1520 self
.assertRegex(output
, 'encrypt on')
1522 output
= check_output('ip macsec show macsec99')
1524 self
.assertRegex(output
, 'encrypt on')
1525 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1526 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1527 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1528 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1529 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1530 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1531 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1532 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1533 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1534 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1535 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1537 def test_nlmon(self
):
1538 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1541 self
.wait_online(['nlmon99:carrier'])
1543 @expectedFailureIfModuleIsNotAvailable('ifb')
1545 copy_unit_to_networkd_unit_path('25-ifb.netdev', 'netdev-link-local-addressing-yes.network')
1548 self
.wait_online(['ifb99:degraded'])
1550 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1561 '25-l2tp-dummy.network',
1563 '25-l2tp-ip.netdev',
1564 '25-l2tp-udp.netdev']
1566 l2tp_tunnel_ids
= [ '10' ]
1569 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1570 remove_links(self
.links
)
1571 stop_networkd(show_logs
=False)
1574 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1575 remove_links(self
.links
)
1576 remove_unit_from_networkd_path(self
.units
)
1577 stop_networkd(show_logs
=True)
1579 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1580 def test_l2tp_udp(self
):
1581 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1582 '25-l2tp-udp.netdev', '25-l2tp.network')
1585 self
.wait_online(['test1:routable', 'l2tp-ses1:degraded', 'l2tp-ses2:degraded'])
1587 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1589 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1590 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1591 self
.assertRegex(output
, "Peer tunnel 11")
1592 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1593 self
.assertRegex(output
, "UDP checksum: enabled")
1595 output
= check_output('ip l2tp show session tid 10 session_id 15')
1597 self
.assertRegex(output
, "Session 15 in tunnel 10")
1598 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1599 self
.assertRegex(output
, "interface name: l2tp-ses1")
1601 output
= check_output('ip l2tp show session tid 10 session_id 17')
1603 self
.assertRegex(output
, "Session 17 in tunnel 10")
1604 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1605 self
.assertRegex(output
, "interface name: l2tp-ses2")
1607 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1608 def test_l2tp_ip(self
):
1609 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1610 '25-l2tp-ip.netdev', '25-l2tp.network')
1613 self
.wait_online(['test1:routable', 'l2tp-ses3:degraded', 'l2tp-ses4:degraded'])
1615 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1617 self
.assertRegex(output
, "Tunnel 10, encap IP")
1618 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1619 self
.assertRegex(output
, "Peer tunnel 12")
1621 output
= check_output('ip l2tp show session tid 10 session_id 25')
1623 self
.assertRegex(output
, "Session 25 in tunnel 10")
1624 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1625 self
.assertRegex(output
, "interface name: l2tp-ses3")
1627 output
= check_output('ip l2tp show session tid 10 session_id 27')
1629 self
.assertRegex(output
, "Session 27 in tunnel 10")
1630 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1631 self
.assertRegex(output
, "interface name: l2tp-ses4")
1633 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1648 '23-active-slave.network',
1649 '24-keep-configuration-static.network',
1650 '24-search-domain.network',
1651 '25-address-dad-veth-peer.network',
1652 '25-address-dad-veth99.network',
1653 '25-address-link-section.network',
1654 '25-address-preferred-lifetime-zero.network',
1655 '25-address-static.network',
1656 '25-bind-carrier.network',
1657 '25-bond-active-backup-slave.netdev',
1658 '25-fibrule-invert.network',
1659 '25-fibrule-port-range.network',
1660 '25-fibrule-uidrange.network',
1661 '25-gre-tunnel-remote-any.netdev',
1662 '25-ip6gre-tunnel-remote-any.netdev',
1663 '25-ipv6-address-label-section.network',
1664 '25-link-local-addressing-no.network',
1665 '25-link-local-addressing-yes.network',
1666 '25-link-section-unmanaged.network',
1667 '25-neighbor-section.network',
1668 '25-neighbor-next.network',
1669 '25-neighbor-ipv6.network',
1670 '25-neighbor-ip-dummy.network',
1671 '25-neighbor-ip.network',
1672 '25-nexthop.network',
1673 '25-qdisc-cake.network',
1674 '25-qdisc-clsact-and-htb.network',
1675 '25-qdisc-drr.network',
1676 '25-qdisc-hhf.network',
1677 '25-qdisc-ingress-netem-compat.network',
1678 '25-qdisc-pie.network',
1679 '25-qdisc-qfq.network',
1680 '25-route-ipv6-src.network',
1681 '25-route-static.network',
1682 '25-route-vrf.network',
1683 '25-gateway-static.network',
1684 '25-gateway-next-static.network',
1685 '25-sysctl-disable-ipv6.network',
1686 '25-sysctl.network',
1688 '25-veth-peer.network',
1691 '26-link-local-addressing-ipv6.network',
1692 'routing-policy-rule-dummy98.network',
1693 'routing-policy-rule-test1.network']
1695 routing_policy_rule_tables
= ['7', '8', '9']
1696 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1699 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1700 remove_routes(self
.routes
)
1701 remove_links(self
.links
)
1702 stop_networkd(show_logs
=False)
1705 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1706 remove_routes(self
.routes
)
1707 remove_links(self
.links
)
1708 remove_unit_from_networkd_path(self
.units
)
1709 stop_networkd(show_logs
=True)
1711 def test_address_static(self
):
1712 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1715 self
.wait_online(['dummy98:routable'])
1717 output
= check_output('ip -4 address show dev dummy98')
1719 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1720 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1721 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1724 self
.assertNotRegex(output
, '10.10.0.1/16')
1725 self
.assertNotRegex(output
, '10.10.0.2/16')
1727 output
= check_output('ip -4 address show dev dummy98 label 32')
1728 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1730 output
= check_output('ip -4 address show dev dummy98 label 33')
1731 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1733 output
= check_output('ip -4 address show dev dummy98 label 34')
1734 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1736 output
= check_output('ip -4 address show dev dummy98 label 35')
1737 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1739 output
= check_output('ip -6 address show dev dummy98')
1741 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1742 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1743 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1744 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1745 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1746 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1748 def test_address_preferred_lifetime_zero_ipv6(self
):
1749 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero.network', '12-dummy.netdev')
1752 self
.wait_online(['dummy98:routable'])
1754 output
= check_output('ip address show dummy98')
1756 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1757 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1759 output
= check_output('ip route show dev dummy98')
1761 self
.assertRegex(output
, 'default via 20.20.20.1 proto static')
1763 def test_address_dad(self
):
1764 copy_unit_to_networkd_unit_path('25-address-dad-veth99.network', '25-address-dad-veth-peer.network',
1767 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
1769 output
= check_output('ip -4 address show dev veth99')
1771 self
.assertRegex(output
, '192.168.100.10/24')
1773 output
= check_output('ip -4 address show dev veth-peer')
1775 self
.assertNotRegex(output
, '192.168.100.10/24')
1777 def test_configure_without_carrier(self
):
1778 copy_unit_to_networkd_unit_path('11-dummy.netdev')
1780 self
.wait_operstate('test1', 'off', '')
1781 check_output('ip link set dev test1 up carrier off')
1783 copy_unit_to_networkd_unit_path('25-test1.network.d/configure-without-carrier.conf', dropins
=False)
1785 self
.wait_online(['test1:no-carrier'])
1787 carrier_map
= {'on': '1', 'off': '0'}
1788 routable_map
= {'on': 'routable', 'off': 'no-carrier'}
1789 for carrier
in ['off', 'on', 'off']:
1790 with self
.subTest(carrier
=carrier
):
1791 if carrier_map
[carrier
] != read_link_attr('test1', 'carrier'):
1792 check_output(f
'ip link set dev test1 carrier {carrier}')
1793 self
.wait_online([f
'test1:{routable_map[carrier]}'])
1795 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
1797 self
.assertRegex(output
, '192.168.0.15')
1798 self
.assertRegex(output
, '192.168.0.1')
1799 self
.assertRegex(output
, routable_map
[carrier
])
1801 def test_configure_without_carrier_yes_ignore_carrier_loss_no(self
):
1802 copy_unit_to_networkd_unit_path('11-dummy.netdev')
1804 self
.wait_operstate('test1', 'off', '')
1805 check_output('ip link set dev test1 up carrier off')
1807 copy_unit_to_networkd_unit_path('25-test1.network')
1809 self
.wait_online(['test1:no-carrier'])
1811 carrier_map
= {'on': '1', 'off': '0'}
1812 routable_map
= {'on': 'routable', 'off': 'no-carrier'}
1813 for (carrier
, have_config
) in [('off', True), ('on', True), ('off', False)]:
1814 with self
.subTest(carrier
=carrier
, have_config
=have_config
):
1815 if carrier_map
[carrier
] != read_link_attr('test1', 'carrier'):
1816 check_output(f
'ip link set dev test1 carrier {carrier}')
1817 self
.wait_online([f
'test1:{routable_map[carrier]}'])
1819 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
1822 self
.assertRegex(output
, '192.168.0.15')
1823 self
.assertRegex(output
, '192.168.0.1')
1825 self
.assertNotRegex(output
, '192.168.0.15')
1826 self
.assertNotRegex(output
, '192.168.0.1')
1827 self
.assertRegex(output
, routable_map
[carrier
])
1829 def test_routing_policy_rule(self
):
1830 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1832 self
.wait_online(['test1:degraded'])
1834 output
= check_output('ip rule list iif test1 priority 111')
1836 self
.assertRegex(output
, '111:')
1837 self
.assertRegex(output
, 'from 192.168.100.18')
1838 self
.assertRegex(output
, r
'tos (0x08|throughput)\s')
1839 self
.assertRegex(output
, 'iif test1')
1840 self
.assertRegex(output
, 'oif test1')
1841 self
.assertRegex(output
, 'lookup 7')
1843 output
= check_output('ip rule list iif test1 priority 101')
1845 self
.assertRegex(output
, '101:')
1846 self
.assertRegex(output
, 'from all')
1847 self
.assertRegex(output
, 'iif test1')
1848 self
.assertRegex(output
, 'lookup 9')
1850 output
= check_output('ip -6 rule list iif test1 priority 100')
1852 self
.assertRegex(output
, '100:')
1853 self
.assertRegex(output
, 'from all')
1854 self
.assertRegex(output
, 'iif test1')
1855 self
.assertRegex(output
, 'lookup 8')
1857 output
= check_output('ip -6 rule list iif test1 priority 101')
1859 self
.assertRegex(output
, '101:')
1860 self
.assertRegex(output
, 'from all')
1861 self
.assertRegex(output
, 'iif test1')
1862 self
.assertRegex(output
, 'lookup 9')
1864 def test_routing_policy_rule_issue_11280(self
):
1865 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1866 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1868 for trial
in range(3):
1869 # Remove state files only first time
1871 self
.wait_online(['test1:degraded', 'dummy98:degraded'])
1874 output
= check_output('ip rule list table 7')
1876 self
.assertRegex(output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
1878 output
= check_output('ip rule list table 8')
1880 self
.assertRegex(output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1882 stop_networkd(remove_state_files
=False)
1884 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1885 def test_routing_policy_rule_port_range(self
):
1886 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1888 self
.wait_online(['test1:degraded'])
1890 output
= check_output('ip rule')
1892 self
.assertRegex(output
, '111')
1893 self
.assertRegex(output
, 'from 192.168.100.18')
1894 self
.assertRegex(output
, '1123-1150')
1895 self
.assertRegex(output
, '3224-3290')
1896 self
.assertRegex(output
, 'tcp')
1897 self
.assertRegex(output
, 'lookup 7')
1899 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1900 def test_routing_policy_rule_invert(self
):
1901 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1903 self
.wait_online(['test1:degraded'])
1905 output
= check_output('ip rule')
1907 self
.assertRegex(output
, '111')
1908 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
1909 self
.assertRegex(output
, 'tcp')
1910 self
.assertRegex(output
, 'lookup 7')
1912 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable()
1913 def test_routing_policy_rule_uidrange(self
):
1914 copy_unit_to_networkd_unit_path('25-fibrule-uidrange.network', '11-dummy.netdev')
1916 self
.wait_online(['test1:degraded'])
1918 output
= check_output('ip rule')
1920 self
.assertRegex(output
, '111')
1921 self
.assertRegex(output
, 'from 192.168.100.18')
1922 self
.assertRegex(output
, 'lookup 7')
1923 self
.assertRegex(output
, 'uidrange 100-200')
1925 def test_route_static(self
):
1926 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1928 self
.wait_online(['dummy98:routable'])
1930 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
1933 print('### ip -6 route show dev dummy98')
1934 output
= check_output('ip -6 route show dev dummy98')
1936 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1937 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
1939 print('### ip -6 route show dev dummy98 default')
1940 output
= check_output('ip -6 route show dev dummy98 default')
1942 self
.assertRegex(output
, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1944 print('### ip -4 route show dev dummy98')
1945 output
= check_output('ip -4 route show dev dummy98')
1947 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1948 self
.assertRegex(output
, '149.10.124.64 proto static scope link')
1949 self
.assertRegex(output
, '169.254.0.0/16 proto static scope link metric 2048')
1950 self
.assertRegex(output
, '192.168.1.1 proto static initcwnd 20')
1951 self
.assertRegex(output
, '192.168.1.2 proto static initrwnd 30')
1952 self
.assertRegex(output
, 'multicast 149.10.123.4 proto static')
1954 print('### ip -4 route show dev dummy98 default')
1955 output
= check_output('ip -4 route show dev dummy98 default')
1957 self
.assertRegex(output
, 'default via 149.10.125.65 proto static onlink')
1958 self
.assertRegex(output
, 'default via 149.10.124.64 proto static')
1959 self
.assertRegex(output
, 'default proto static')
1961 print('### ip -4 route show table local dev dummy98')
1962 output
= check_output('ip -4 route show table local dev dummy98')
1964 self
.assertRegex(output
, 'local 149.10.123.1 proto static scope host')
1965 self
.assertRegex(output
, 'anycast 149.10.123.2 proto static scope link')
1966 self
.assertRegex(output
, 'broadcast 149.10.123.3 proto static scope link')
1968 print('### ip route show type blackhole')
1969 output
= check_output('ip route show type blackhole')
1971 self
.assertRegex(output
, 'blackhole 202.54.1.2 proto static')
1973 print('### ip route show type unreachable')
1974 output
= check_output('ip route show type unreachable')
1976 self
.assertRegex(output
, 'unreachable 202.54.1.3 proto static')
1978 print('### ip route show type prohibit')
1979 output
= check_output('ip route show type prohibit')
1981 self
.assertRegex(output
, 'prohibit 202.54.1.4 proto static')
1983 print('### ip route show 192.168.10.1')
1984 output
= check_output('ip route show 192.168.10.1')
1986 self
.assertRegex(output
, '192.168.10.1 proto static')
1987 self
.assertRegex(output
, 'nexthop via 149.10.124.59 dev dummy98 weight 10')
1988 self
.assertRegex(output
, 'nexthop via 149.10.124.60 dev dummy98 weight 5')
1990 print('### ip route show 192.168.10.2')
1991 output
= check_output('ip route show 192.168.10.2')
1993 # old ip command does not show IPv6 gateways...
1994 self
.assertRegex(output
, '192.168.10.2 proto static')
1995 self
.assertRegex(output
, 'nexthop')
1996 self
.assertRegex(output
, 'dev dummy98 weight 10')
1997 self
.assertRegex(output
, 'dev dummy98 weight 5')
1999 print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2000 output
= check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2002 # old ip command does not show 'nexthop' keyword and weight...
2003 self
.assertRegex(output
, '2001:1234:5:7fff:ff:ff:ff:ff')
2004 self
.assertRegex(output
, 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98')
2005 self
.assertRegex(output
, 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98')
2007 @expectedFailureIfModuleIsNotAvailable('vrf')
2008 def test_route_vrf(self
):
2009 copy_unit_to_networkd_unit_path('25-route-vrf.network', '12-dummy.netdev',
2010 '25-vrf.netdev', '25-vrf.network')
2012 self
.wait_online(['dummy98:routable', 'vrf99:carrier'])
2014 output
= check_output('ip route show vrf vrf99')
2016 self
.assertRegex(output
, 'default via 192.168.100.1')
2018 output
= check_output('ip route show')
2020 self
.assertNotRegex(output
, 'default via 192.168.100.1')
2022 def test_gateway_reconfigure(self
):
2023 copy_unit_to_networkd_unit_path('25-gateway-static.network', '12-dummy.netdev')
2025 self
.wait_online(['dummy98:routable'])
2026 print('### ip -4 route show dev dummy98 default')
2027 output
= check_output('ip -4 route show dev dummy98 default')
2029 self
.assertRegex(output
, 'default via 149.10.124.59 proto static')
2030 self
.assertNotRegex(output
, '149.10.124.60')
2032 remove_unit_from_networkd_path(['25-gateway-static.network'])
2033 copy_unit_to_networkd_unit_path('25-gateway-next-static.network')
2035 self
.wait_online(['dummy98:routable'])
2036 print('### ip -4 route show dev dummy98 default')
2037 output
= check_output('ip -4 route show dev dummy98 default')
2039 self
.assertNotRegex(output
, '149.10.124.59')
2040 self
.assertRegex(output
, 'default via 149.10.124.60 proto static')
2042 def test_ip_route_ipv6_src_route(self
):
2043 # a dummy device does not make the addresses go through tentative state, so we
2044 # reuse a bond from an earlier test, which does make the addresses go through
2045 # tentative state, and do our test on that
2046 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2048 self
.wait_online(['dummy98:enslaved', 'bond199:routable'])
2050 output
= check_output('ip -6 route list dev bond199')
2052 self
.assertRegex(output
, 'abcd::/16')
2053 self
.assertRegex(output
, 'src')
2054 self
.assertRegex(output
, '2001:1234:56:8f63::2')
2056 def test_ip_link_mac_address(self
):
2057 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
2059 self
.wait_online(['dummy98:degraded'])
2061 output
= check_output('ip link show dummy98')
2063 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
2065 def test_ip_link_unmanaged(self
):
2066 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
2069 self
.check_link_exists('dummy98')
2071 self
.wait_operstate('dummy98', 'off', setup_state
='unmanaged')
2073 def test_ipv6_address_label(self
):
2074 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
2076 self
.wait_online(['dummy98:degraded'])
2078 output
= check_output('ip addrlabel list')
2080 self
.assertRegex(output
, '2004:da8:1::/64')
2082 def test_neighbor_section(self
):
2083 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2085 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2087 print('### ip neigh list dev dummy98')
2088 output
= check_output('ip neigh list dev dummy98')
2090 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2091 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2093 def test_neighbor_reconfigure(self
):
2094 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2096 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2098 print('### ip neigh list dev dummy98')
2099 output
= check_output('ip neigh list dev dummy98')
2101 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2102 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2104 remove_unit_from_networkd_path(['25-neighbor-section.network'])
2105 copy_unit_to_networkd_unit_path('25-neighbor-next.network')
2107 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2108 print('### ip neigh list dev dummy98')
2109 output
= check_output('ip neigh list dev dummy98')
2111 self
.assertNotRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2112 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT')
2113 self
.assertNotRegex(output
, '2004:da8:1::1.*PERMANENT')
2115 def test_neighbor_gre(self
):
2116 copy_unit_to_networkd_unit_path('25-neighbor-ip.network', '25-neighbor-ipv6.network', '25-neighbor-ip-dummy.network',
2117 '12-dummy.netdev', '25-gre-tunnel-remote-any.netdev', '25-ip6gre-tunnel-remote-any.netdev')
2119 self
.wait_online(['dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable'], timeout
='40s')
2121 output
= check_output('ip neigh list dev gretun97')
2123 self
.assertRegex(output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT')
2125 output
= check_output('ip neigh list dev ip6gretun97')
2127 self
.assertRegex(output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
2129 def test_link_local_addressing(self
):
2130 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
2131 '25-link-local-addressing-no.network', '12-dummy.netdev')
2133 self
.wait_online(['test1:degraded', 'dummy98:carrier'])
2135 output
= check_output('ip address show dev test1')
2137 self
.assertRegex(output
, 'inet .* scope link')
2138 self
.assertRegex(output
, 'inet6 .* scope link')
2140 output
= check_output('ip address show dev dummy98')
2142 self
.assertNotRegex(output
, 'inet6* .* scope link')
2145 Documentation/networking/ip-sysctl.txt
2147 addr_gen_mode - INTEGER
2148 Defines how link-local and autoconf addresses are generated.
2150 0: generate address based on EUI64 (default)
2151 1: do no generate a link-local address, use EUI64 for addresses generated
2153 2: generate stable privacy addresses, using the secret from
2154 stable_secret (RFC7217)
2155 3: generate stable privacy addresses, using a random secret if unset
2158 test1_addr_gen_mode
= ''
2159 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
2160 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
2164 # if stable_secret is unset, then EIO is returned
2165 test1_addr_gen_mode
= '0'
2167 test1_addr_gen_mode
= '2'
2169 test1_addr_gen_mode
= '0'
2171 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
2172 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
2174 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
2175 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
2177 def test_link_local_addressing_remove_ipv6ll(self
):
2178 copy_unit_to_networkd_unit_path('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
2180 self
.wait_online(['dummy98:degraded'])
2182 output
= check_output('ip address show dev dummy98')
2184 self
.assertRegex(output
, 'inet6 .* scope link')
2186 copy_unit_to_networkd_unit_path('25-link-local-addressing-no.network')
2188 self
.wait_online(['dummy98:carrier'])
2190 output
= check_output('ip address show dev dummy98')
2192 self
.assertNotRegex(output
, 'inet6* .* scope link')
2194 def test_sysctl(self
):
2195 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
2197 self
.wait_online(['dummy98:degraded'])
2199 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
2200 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
2201 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
2202 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
2203 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
2204 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
2205 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
2206 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'accept_local'), '1')
2208 def test_sysctl_disable_ipv6(self
):
2209 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
2211 print('## Disable ipv6')
2212 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
2213 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
2216 self
.wait_online(['dummy98:routable'])
2218 output
= check_output('ip -4 address show dummy98')
2220 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2221 output
= check_output('ip -6 address show dummy98')
2223 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2224 self
.assertRegex(output
, 'inet6 .* scope link')
2225 output
= check_output('ip -4 route show dev dummy98')
2227 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2228 output
= check_output('ip -6 route show dev dummy98')
2230 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2232 check_output('ip link del dummy98')
2234 print('## Enable ipv6')
2235 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
2236 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
2239 self
.wait_online(['dummy98:routable'])
2241 output
= check_output('ip -4 address show dummy98')
2243 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2244 output
= check_output('ip -6 address show dummy98')
2246 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2247 self
.assertRegex(output
, 'inet6 .* scope link')
2248 output
= check_output('ip -4 route show dev dummy98')
2250 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2251 output
= check_output('ip -6 route show dev dummy98')
2253 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2255 def test_bind_carrier(self
):
2256 check_output('ip link add dummy98 type dummy')
2257 check_output('ip link set dummy98 up')
2260 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
2262 self
.wait_online(['test1:routable'])
2264 output
= check_output('ip address show test1')
2266 self
.assertRegex(output
, 'UP,LOWER_UP')
2267 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2268 self
.wait_operstate('test1', 'routable')
2270 check_output('ip link add dummy99 type dummy')
2271 check_output('ip link set dummy99 up')
2273 output
= check_output('ip address show test1')
2275 self
.assertRegex(output
, 'UP,LOWER_UP')
2276 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2277 self
.wait_operstate('test1', 'routable')
2279 check_output('ip link del dummy98')
2281 output
= check_output('ip address show test1')
2283 self
.assertRegex(output
, 'UP,LOWER_UP')
2284 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2285 self
.wait_operstate('test1', 'routable')
2287 check_output('ip link set dummy99 down')
2289 output
= check_output('ip address show test1')
2291 self
.assertNotRegex(output
, 'UP,LOWER_UP')
2292 self
.assertRegex(output
, 'DOWN')
2293 self
.assertNotRegex(output
, '192.168.10')
2294 self
.wait_operstate('test1', 'off')
2296 check_output('ip link set dummy99 up')
2298 output
= check_output('ip address show test1')
2300 self
.assertRegex(output
, 'UP,LOWER_UP')
2301 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2302 self
.wait_operstate('test1', 'routable')
2304 def test_domain(self
):
2305 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
2307 self
.wait_online(['dummy98:routable'])
2309 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2311 self
.assertRegex(output
, 'Address: 192.168.42.100')
2312 self
.assertRegex(output
, 'DNS: 192.168.42.1')
2313 self
.assertRegex(output
, 'Search Domains: one')
2315 def test_keep_configuration_static(self
):
2316 check_output('systemctl stop systemd-networkd')
2318 check_output('ip link add name dummy98 type dummy')
2319 check_output('ip address add 10.1.2.3/16 dev dummy98')
2320 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
2321 output
= check_output('ip address show dummy98')
2323 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2324 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2325 output
= check_output('ip route show dev dummy98')
2328 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
2330 self
.wait_online(['dummy98:routable'])
2332 output
= check_output('ip address show dummy98')
2334 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2335 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2337 @expectedFailureIfNexthopIsNotAvailable()
2338 def test_nexthop(self
):
2339 copy_unit_to_networkd_unit_path('25-nexthop.network', '25-veth.netdev', '25-veth-peer.network')
2341 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2343 output
= check_output('ip nexthop list dev veth99')
2345 self
.assertRegex(output
, '192.168.5.1')
2347 def test_qdisc(self
):
2348 copy_unit_to_networkd_unit_path('25-qdisc-clsact-and-htb.network', '12-dummy.netdev',
2349 '25-qdisc-ingress-netem-compat.network', '11-dummy.netdev')
2350 check_output('modprobe sch_teql max_equalizers=2')
2353 self
.wait_online(['dummy98:routable', 'test1:routable'])
2355 output
= check_output('tc qdisc show dev test1')
2357 self
.assertRegex(output
, 'qdisc netem')
2358 self
.assertRegex(output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
2359 self
.assertRegex(output
, 'qdisc ingress')
2361 output
= check_output('tc qdisc show dev dummy98')
2363 self
.assertRegex(output
, 'qdisc clsact')
2365 self
.assertRegex(output
, 'qdisc htb 2: root')
2366 self
.assertRegex(output
, r
'default (0x30|30)')
2368 self
.assertRegex(output
, 'qdisc netem 30: parent 2:30')
2369 self
.assertRegex(output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
2370 self
.assertRegex(output
, 'qdisc fq_codel')
2371 self
.assertRegex(output
, 'limit 20480p flows 2048 quantum 1400 target 10(.0)?ms ce_threshold 100(.0)?ms interval 200(.0)?ms memory_limit 64Mb ecn')
2373 self
.assertRegex(output
, 'qdisc teql1 31: parent 2:31')
2375 self
.assertRegex(output
, 'qdisc fq 32: parent 2:32')
2376 self
.assertRegex(output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
2377 self
.assertRegex(output
, 'quantum 1500')
2378 self
.assertRegex(output
, 'initial_quantum 13000')
2379 self
.assertRegex(output
, 'maxrate 1Mbit')
2381 self
.assertRegex(output
, 'qdisc codel 33: parent 2:33')
2382 self
.assertRegex(output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn')
2384 self
.assertRegex(output
, 'qdisc fq_codel 34: parent 2:34')
2385 self
.assertRegex(output
, 'limit 20480p flows 2048 quantum 1400 target 10(.0)?ms ce_threshold 100(.0)?ms interval 200(.0)?ms memory_limit 64Mb ecn')
2387 self
.assertRegex(output
, 'qdisc tbf 35: parent 2:35')
2388 self
.assertRegex(output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms')
2390 self
.assertRegex(output
, 'qdisc sfq 36: parent 2:36')
2391 self
.assertRegex(output
, 'perturb 5sec')
2393 self
.assertRegex(output
, 'qdisc pfifo 37: parent 2:37')
2394 self
.assertRegex(output
, 'limit 100000p')
2396 self
.assertRegex(output
, 'qdisc gred 38: parent 2:38')
2397 self
.assertRegex(output
, 'vqs 12 default 10 grio')
2399 self
.assertRegex(output
, 'qdisc sfb 39: parent 2:39')
2400 self
.assertRegex(output
, 'limit 200000')
2402 self
.assertRegex(output
, 'qdisc bfifo 3a: parent 2:3a')
2403 self
.assertRegex(output
, 'limit 1000000')
2405 self
.assertRegex(output
, 'qdisc pfifo_head_drop 3b: parent 2:3b')
2406 self
.assertRegex(output
, 'limit 1023p')
2408 self
.assertRegex(output
, 'qdisc pfifo_fast 3c: parent 2:3c')
2410 output
= check_output('tc class show dev dummy98')
2412 self
.assertRegex(output
, 'class htb 2:30 root leaf 30:')
2413 self
.assertRegex(output
, 'class htb 2:31 root leaf 31:')
2414 self
.assertRegex(output
, 'class htb 2:32 root leaf 32:')
2415 self
.assertRegex(output
, 'class htb 2:33 root leaf 33:')
2416 self
.assertRegex(output
, 'class htb 2:34 root leaf 34:')
2417 self
.assertRegex(output
, 'class htb 2:35 root leaf 35:')
2418 self
.assertRegex(output
, 'class htb 2:36 root leaf 36:')
2419 self
.assertRegex(output
, 'class htb 2:37 root leaf 37:')
2420 self
.assertRegex(output
, 'class htb 2:38 root leaf 38:')
2421 self
.assertRegex(output
, 'class htb 2:39 root leaf 39:')
2422 self
.assertRegex(output
, 'class htb 2:3a root leaf 3a:')
2423 self
.assertRegex(output
, 'class htb 2:3b root leaf 3b:')
2424 self
.assertRegex(output
, 'class htb 2:3c root leaf 3c:')
2425 self
.assertRegex(output
, 'prio 1 rate 1Mbit ceil 500Kbit')
2427 def test_qdisc2(self
):
2428 copy_unit_to_networkd_unit_path('25-qdisc-drr.network', '12-dummy.netdev',
2429 '25-qdisc-qfq.network', '11-dummy.netdev')
2432 self
.wait_online(['dummy98:routable', 'test1:routable'])
2434 output
= check_output('tc qdisc show dev dummy98')
2436 self
.assertRegex(output
, 'qdisc drr 2: root')
2437 output
= check_output('tc class show dev dummy98')
2439 self
.assertRegex(output
, 'class drr 2:30 root quantum 2000b')
2441 output
= check_output('tc qdisc show dev test1')
2443 self
.assertRegex(output
, 'qdisc qfq 2: root')
2444 output
= check_output('tc class show dev test1')
2446 self
.assertRegex(output
, 'class qfq 2:30 root weight 2 maxpkt 16000')
2447 self
.assertRegex(output
, 'class qfq 2:31 root weight 10 maxpkt 8000')
2449 @expectedFailureIfCAKEIsNotAvailable()
2450 def test_qdisc_cake(self
):
2451 copy_unit_to_networkd_unit_path('25-qdisc-cake.network', '12-dummy.netdev')
2453 self
.wait_online(['dummy98:routable'])
2455 output
= check_output('tc qdisc show dev dummy98')
2457 self
.assertRegex(output
, 'qdisc cake 3a: root')
2458 self
.assertRegex(output
, 'bandwidth 500Mbit')
2459 self
.assertRegex(output
, 'overhead 128')
2461 @expectedFailureIfPIEIsNotAvailable()
2462 def test_qdisc_pie(self
):
2463 copy_unit_to_networkd_unit_path('25-qdisc-pie.network', '12-dummy.netdev')
2465 self
.wait_online(['dummy98:routable'])
2467 output
= check_output('tc qdisc show dev dummy98')
2469 self
.assertRegex(output
, 'qdisc pie 3a: root')
2470 self
.assertRegex(output
, 'limit 200000')
2472 @expectedFailureIfHHFIsNotAvailable()
2473 def test_qdisc_hhf(self
):
2474 copy_unit_to_networkd_unit_path('25-qdisc-hhf.network', '12-dummy.netdev')
2476 self
.wait_online(['dummy98:routable'])
2478 output
= check_output('tc qdisc show dev dummy98')
2480 self
.assertRegex(output
, 'qdisc hhf 3a: root')
2481 self
.assertRegex(output
, 'limit 1022p')
2483 class NetworkdStateFileTests(unittest
.TestCase
, Utilities
):
2490 'state-file-tests.network',
2494 remove_links(self
.links
)
2495 stop_networkd(show_logs
=False)
2498 remove_links(self
.links
)
2499 remove_unit_from_networkd_path(self
.units
)
2500 stop_networkd(show_logs
=True)
2502 def test_state_file(self
):
2503 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'state-file-tests.network')
2505 self
.wait_online(['dummy98:routable'])
2507 output
= check_output(*networkctl_cmd
, '--no-legend', 'list', 'dummy98', env
=env
)
2509 ifindex
= output
.split()[0]
2511 path
= os
.path
.join('/run/systemd/netif/links/', ifindex
)
2512 self
.assertTrue(os
.path
.exists(path
))
2515 with
open(path
) as f
:
2517 self
.assertRegex(data
, r
'ADMIN_STATE=configured')
2518 self
.assertRegex(data
, r
'OPER_STATE=routable')
2519 self
.assertRegex(data
, r
'REQUIRED_FOR_ONLINE=yes')
2520 self
.assertRegex(data
, r
'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
2521 self
.assertRegex(data
, r
'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
2522 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
2523 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2524 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2525 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2526 self
.assertRegex(data
, r
'LLMNR=no')
2527 self
.assertRegex(data
, r
'MDNS=yes')
2528 self
.assertRegex(data
, r
'DNSSEC=no')
2529 self
.assertRegex(data
, r
'ADDRESSES=192.168.(10.10|12.12)/24 192.168.(12.12|10.10)/24')
2531 check_output(*resolvectl_cmd
, 'dns', 'dummy98', '10.10.10.12', '10.10.10.13', env
=env
)
2532 check_output(*resolvectl_cmd
, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env
=env
)
2533 check_output(*resolvectl_cmd
, 'llmnr', 'dummy98', 'yes', env
=env
)
2534 check_output(*resolvectl_cmd
, 'mdns', 'dummy98', 'no', env
=env
)
2535 check_output(*resolvectl_cmd
, 'dnssec', 'dummy98', 'yes', env
=env
)
2536 check_output(*timedatectl_cmd
, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env
=env
)
2539 with
open(path
) as f
:
2541 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
2542 self
.assertRegex(data
, r
'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org')
2543 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2544 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2545 self
.assertRegex(data
, r
'LLMNR=yes')
2546 self
.assertRegex(data
, r
'MDNS=no')
2547 self
.assertRegex(data
, r
'DNSSEC=yes')
2549 check_output(*timedatectl_cmd
, 'revert', 'dummy98', env
=env
)
2552 with
open(path
) as f
:
2554 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
2555 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2556 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2557 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2558 self
.assertRegex(data
, r
'LLMNR=yes')
2559 self
.assertRegex(data
, r
'MDNS=no')
2560 self
.assertRegex(data
, r
'DNSSEC=yes')
2562 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
2565 with
open(path
) as f
:
2567 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
2568 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2569 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2570 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2571 self
.assertRegex(data
, r
'LLMNR=no')
2572 self
.assertRegex(data
, r
'MDNS=yes')
2573 self
.assertRegex(data
, r
'DNSSEC=no')
2575 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
2585 '23-active-slave.network',
2586 '23-bond199.network',
2587 '23-primary-slave.network',
2588 '25-bond-active-backup-slave.netdev',
2591 'bond-slave.network']
2594 remove_links(self
.links
)
2595 stop_networkd(show_logs
=False)
2598 remove_links(self
.links
)
2599 remove_unit_from_networkd_path(self
.units
)
2600 stop_networkd(show_logs
=True)
2602 def test_bond_active_slave(self
):
2603 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2605 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2607 output
= check_output('ip -d link show bond199')
2609 self
.assertRegex(output
, 'active_slave dummy98')
2611 def test_bond_primary_slave(self
):
2612 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2614 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2616 output
= check_output('ip -d link show bond199')
2618 self
.assertRegex(output
, 'primary dummy98')
2620 def test_bond_operstate(self
):
2621 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
2622 'bond99.network','bond-slave.network')
2624 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
2626 output
= check_output('ip -d link show dummy98')
2628 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2630 output
= check_output('ip -d link show test1')
2632 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2634 output
= check_output('ip -d link show bond99')
2636 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
2638 self
.wait_operstate('dummy98', 'enslaved')
2639 self
.wait_operstate('test1', 'enslaved')
2640 self
.wait_operstate('bond99', 'routable')
2642 check_output('ip link set dummy98 down')
2644 self
.wait_operstate('dummy98', 'off')
2645 self
.wait_operstate('test1', 'enslaved')
2646 self
.wait_operstate('bond99', 'degraded-carrier')
2648 check_output('ip link set dummy98 up')
2650 self
.wait_operstate('dummy98', 'enslaved')
2651 self
.wait_operstate('test1', 'enslaved')
2652 self
.wait_operstate('bond99', 'routable')
2654 check_output('ip link set dummy98 down')
2655 check_output('ip link set test1 down')
2657 self
.wait_operstate('dummy98', 'off')
2658 self
.wait_operstate('test1', 'off')
2660 if not self
.wait_operstate('bond99', 'no-carrier', setup_timeout
=30, fail_assert
=False):
2661 # Huh? Kernel does not recognize that all slave interfaces are down?
2662 # Let's confirm that networkd's operstate is consistent with ip's result.
2663 self
.assertNotRegex(output
, 'NO-CARRIER')
2665 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
2675 '26-bridge-configure-without-carrier.network',
2676 '26-bridge-slave-interface-1.network',
2677 '26-bridge-slave-interface-2.network',
2678 '26-bridge-vlan-master.network',
2679 '26-bridge-vlan-slave.network',
2680 'bridge99-ignore-carrier-loss.network',
2683 routing_policy_rule_tables
= ['100']
2686 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2687 remove_links(self
.links
)
2688 stop_networkd(show_logs
=False)
2691 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2692 remove_links(self
.links
)
2693 remove_unit_from_networkd_path(self
.units
)
2694 stop_networkd(show_logs
=True)
2696 def test_bridge_vlan(self
):
2697 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
2698 '26-bridge.netdev', '26-bridge-vlan-master.network')
2700 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
2702 output
= check_output('bridge vlan show dev test1')
2704 self
.assertNotRegex(output
, '4063')
2705 for i
in range(4064, 4095):
2706 self
.assertRegex(output
, f
'{i}')
2707 self
.assertNotRegex(output
, '4095')
2709 output
= check_output('bridge vlan show dev bridge99')
2711 self
.assertNotRegex(output
, '4059')
2712 for i
in range(4060, 4095):
2713 self
.assertRegex(output
, f
'{i}')
2714 self
.assertNotRegex(output
, '4095')
2716 def test_bridge_property(self
):
2717 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2718 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2721 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2723 output
= check_output('ip -d link show test1')
2725 self
.assertRegex(output
, 'master')
2726 self
.assertRegex(output
, 'bridge')
2728 output
= check_output('ip -d link show dummy98')
2730 self
.assertRegex(output
, 'master')
2731 self
.assertRegex(output
, 'bridge')
2733 output
= check_output('ip addr show bridge99')
2735 self
.assertRegex(output
, '192.168.0.15/24')
2737 output
= check_output('bridge -d link show dummy98')
2739 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
2740 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
2741 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
2742 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
2743 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
2744 # CONFIG_BRIDGE_IGMP_SNOOPING=y
2745 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
2746 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
2747 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
2748 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
2749 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
2750 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'priority'), '23')
2751 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard'), '1')
2752 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'root_block'), '1')
2754 output
= check_output('bridge -d link show test1')
2756 self
.assertEqual(read_bridge_port_attr('bridge99', 'test1', 'priority'), '0')
2758 check_output('ip address add 192.168.0.16/24 dev bridge99')
2761 output
= check_output('ip addr show bridge99')
2763 self
.assertRegex(output
, '192.168.0.16/24')
2766 print('### ip -6 route list table all dev bridge99')
2767 output
= check_output('ip -6 route list table all dev bridge99')
2769 self
.assertRegex(output
, 'ff00::/8 table local metric 256 pref medium')
2771 self
.assertEqual(call('ip link del test1'), 0)
2773 self
.wait_operstate('bridge99', 'degraded-carrier')
2775 check_output('ip link del dummy98')
2777 self
.wait_operstate('bridge99', 'no-carrier')
2779 output
= check_output('ip address show bridge99')
2781 self
.assertRegex(output
, 'NO-CARRIER')
2782 self
.assertNotRegex(output
, '192.168.0.15/24')
2783 self
.assertNotRegex(output
, '192.168.0.16/24')
2785 print('### ip -6 route list table all dev bridge99')
2786 output
= check_output('ip -6 route list table all dev bridge99')
2788 self
.assertRegex(output
, 'ff00::/8 table local metric 256 (linkdown )?pref medium')
2790 def test_bridge_configure_without_carrier(self
):
2791 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-configure-without-carrier.network',
2795 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
2796 for test
in ['no-slave', 'add-slave', 'slave-up', 'slave-no-carrier', 'slave-carrier', 'slave-down']:
2797 with self
.subTest(test
=test
):
2798 if test
== 'no-slave':
2799 # bridge has no slaves; it's up but *might* not have carrier
2800 # It may take very long time that the interface become configured state.
2801 self
.wait_online(['bridge99:no-carrier'], timeout
='2m')
2802 # due to a bug in the kernel, newly-created bridges are brought up
2803 # *with* carrier, unless they have had any setting changed; e.g.
2804 # their mac set, priority set, etc. Then, they will lose carrier
2805 # as soon as a (down) slave interface is added, and regain carrier
2806 # again once the slave interface is brought up.
2807 #self.check_link_attr('bridge99', 'carrier', '0')
2808 elif test
== 'add-slave':
2809 # add slave to bridge, but leave it down; bridge is definitely no-carrier
2810 self
.check_link_attr('test1', 'operstate', 'down')
2811 check_output('ip link set dev test1 master bridge99')
2812 self
.wait_online(['bridge99:no-carrier:no-carrier'])
2813 self
.check_link_attr('bridge99', 'carrier', '0')
2814 elif test
== 'slave-up':
2815 # bring up slave, which will have carrier; bridge gains carrier
2816 check_output('ip link set dev test1 up')
2817 self
.wait_online(['bridge99:routable'])
2818 self
.check_link_attr('bridge99', 'carrier', '1')
2819 elif test
== 'slave-no-carrier':
2820 # drop slave carrier; bridge loses carrier
2821 check_output('ip link set dev test1 carrier off')
2822 self
.wait_online(['bridge99:no-carrier:no-carrier'])
2823 self
.check_link_attr('bridge99', 'carrier', '0')
2824 elif test
== 'slave-carrier':
2825 # restore slave carrier; bridge gains carrier
2826 check_output('ip link set dev test1 carrier on')
2827 self
.wait_online(['bridge99:routable'])
2828 self
.check_link_attr('bridge99', 'carrier', '1')
2829 elif test
== 'slave-down':
2830 # bring down slave; bridge loses carrier
2831 check_output('ip link set dev test1 down')
2832 self
.wait_online(['bridge99:no-carrier:no-carrier'])
2833 self
.check_link_attr('bridge99', 'carrier', '0')
2835 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
2837 self
.assertRegex(output
, '10.1.2.3')
2838 self
.assertRegex(output
, '10.1.2.1')
2840 def test_bridge_ignore_carrier_loss(self
):
2841 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2842 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2843 'bridge99-ignore-carrier-loss.network')
2845 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2847 check_output('ip address add 192.168.0.16/24 dev bridge99')
2850 check_output('ip link del test1')
2851 check_output('ip link del dummy98')
2854 output
= check_output('ip address show bridge99')
2856 self
.assertRegex(output
, 'NO-CARRIER')
2857 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2858 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
2860 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
2861 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
2862 'bridge99-ignore-carrier-loss.network')
2864 self
.wait_online(['bridge99:no-carrier'])
2866 for trial
in range(4):
2867 check_output('ip link add dummy98 type dummy')
2868 check_output('ip link set dummy98 up')
2870 check_output('ip link del dummy98')
2872 self
.wait_online(['bridge99:routable', 'dummy98:enslaved'])
2874 output
= check_output('ip address show bridge99')
2876 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2878 output
= check_output('ip rule list table 100')
2880 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
2882 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
2886 '23-emit-lldp.network',
2891 remove_links(self
.links
)
2892 stop_networkd(show_logs
=False)
2895 remove_links(self
.links
)
2896 remove_unit_from_networkd_path(self
.units
)
2897 stop_networkd(show_logs
=True)
2899 def test_lldp(self
):
2900 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
2902 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
2904 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
2906 self
.assertRegex(output
, 'veth-peer')
2907 self
.assertRegex(output
, 'veth99')
2909 class NetworkdRATests(unittest
.TestCase
, Utilities
):
2914 'ipv6-prefix.network',
2915 'ipv6-prefix-veth.network',
2916 'ipv6-prefix-veth-token-static.network',
2917 'ipv6-prefix-veth-token-static-explicit.network',
2918 'ipv6-prefix-veth-token-static-multiple.network',
2919 'ipv6-prefix-veth-token-prefixstable.network']
2922 remove_links(self
.links
)
2923 stop_networkd(show_logs
=False)
2926 remove_links(self
.links
)
2927 remove_unit_from_networkd_path(self
.units
)
2928 stop_networkd(show_logs
=True)
2930 def test_ipv6_prefix_delegation(self
):
2931 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
2933 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2935 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
2937 self
.assertRegex(output
, 'fe80::')
2938 self
.assertRegex(output
, '2002:da8:1::1')
2940 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2942 self
.assertRegex(output
, '2002:da8:1:0')
2944 def test_ipv6_token_static(self
):
2945 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static.network')
2947 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2949 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2951 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
2953 def test_ipv6_token_static_explicit(self
):
2954 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static-explicit.network')
2956 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2958 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2960 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
2962 def test_ipv6_token_static_multiple(self
):
2963 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static-multiple.network')
2965 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2967 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2969 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
2970 self
.assertRegex(output
, '2002:da8:1:0:fa:de:ca:fe')
2972 def test_ipv6_token_prefixstable(self
):
2973 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable.network')
2975 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2977 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2979 self
.assertRegex(output
, '2002:da8:1:0')
2981 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
2986 'dhcp-client.network',
2987 'dhcp-client-timezone-router.network',
2988 'dhcp-server.network',
2989 'dhcp-server-timezone-router.network']
2992 remove_links(self
.links
)
2993 stop_networkd(show_logs
=False)
2996 remove_links(self
.links
)
2997 remove_unit_from_networkd_path(self
.units
)
2998 stop_networkd(show_logs
=True)
3000 def test_dhcp_server(self
):
3001 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
3003 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3005 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3007 self
.assertRegex(output
, '192.168.5.*')
3008 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
3009 self
.assertRegex(output
, 'DNS: 192.168.5.1')
3010 self
.assertRegex(output
, 'NTP: 192.168.5.1')
3012 def test_emit_router_timezone(self
):
3013 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
3015 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3017 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3019 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
3020 self
.assertRegex(output
, '192.168.5.*')
3021 self
.assertRegex(output
, 'Europe/Berlin')
3023 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
3032 'dhcp-client-anonymize.network',
3033 'dhcp-client-decline.network',
3034 'dhcp-client-gateway-ipv4.network',
3035 'dhcp-client-gateway-ipv6.network',
3036 'dhcp-client-gateway-onlink-implicit.network',
3037 'dhcp-client-ipv4-dhcp-settings.network',
3038 'dhcp-client-ipv4-only-ipv6-disabled.network',
3039 'dhcp-client-ipv4-only.network',
3040 'dhcp-client-ipv4-use-routes-use-gateway.network',
3041 'dhcp-client-ipv6-only.network',
3042 'dhcp-client-ipv6-rapid-commit.network',
3043 'dhcp-client-keep-configuration-dhcp-on-stop.network',
3044 'dhcp-client-keep-configuration-dhcp.network',
3045 'dhcp-client-listen-port.network',
3046 'dhcp-client-reassign-static-routes-ipv4.network',
3047 'dhcp-client-reassign-static-routes-ipv6.network',
3048 'dhcp-client-route-metric.network',
3049 'dhcp-client-route-table.network',
3050 'dhcp-client-use-dns-ipv4-and-ra.network',
3051 'dhcp-client-use-dns-ipv4.network',
3052 'dhcp-client-use-dns-no.network',
3053 'dhcp-client-use-dns-yes.network',
3054 'dhcp-client-use-domains.network',
3055 'dhcp-client-vrf.network',
3056 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
3057 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
3058 'dhcp-client-with-static-address.network',
3059 'dhcp-client.network',
3060 'dhcp-server-decline.network',
3061 'dhcp-server-veth-peer.network',
3062 'dhcp-v4-server-veth-peer.network',
3066 stop_dnsmasq(dnsmasq_pid_file
)
3067 remove_links(self
.links
)
3068 stop_networkd(show_logs
=False)
3071 stop_dnsmasq(dnsmasq_pid_file
)
3074 remove_links(self
.links
)
3075 remove_unit_from_networkd_path(self
.units
)
3076 stop_networkd(show_logs
=True)
3078 def test_dhcp_client_ipv6_only(self
):
3079 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3082 self
.wait_online(['veth-peer:carrier'])
3084 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3086 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3088 self
.assertRegex(output
, '2600::')
3089 self
.assertNotRegex(output
, '192.168.5')
3091 # Confirm that ipv6 token is not set in the kernel
3092 output
= check_output('ip token show dev veth99')
3094 self
.assertRegex(output
, 'token :: dev veth99')
3096 def test_dhcp_client_ipv4_only(self
):
3097 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
3100 self
.wait_online(['veth-peer:carrier'])
3101 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
3102 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3104 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3106 self
.assertNotRegex(output
, '2600::')
3107 self
.assertRegex(output
, '192.168.5')
3108 self
.assertRegex(output
, '192.168.5.6')
3109 self
.assertRegex(output
, '192.168.5.7')
3111 # checking routes to DNS servers
3112 output
= check_output('ip route show dev veth99')
3114 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3115 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3116 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3118 stop_dnsmasq(dnsmasq_pid_file
)
3119 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8', lease_time
='2m')
3121 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3122 print('Wait for the dynamic address to be renewed')
3125 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3127 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3129 self
.assertNotRegex(output
, '2600::')
3130 self
.assertRegex(output
, '192.168.5')
3131 self
.assertNotRegex(output
, '192.168.5.6')
3132 self
.assertRegex(output
, '192.168.5.7')
3133 self
.assertRegex(output
, '192.168.5.8')
3135 # checking routes to DNS servers
3136 output
= check_output('ip route show dev veth99')
3138 self
.assertNotRegex(output
, r
'192.168.5.6')
3139 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3140 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3141 self
.assertRegex(output
, r
'192.168.5.8 proto dhcp scope link src 192.168.5.181 metric 1024')
3143 def test_dhcp_client_ipv4_use_routes_gateway(self
):
3144 for (routes
, gateway
, dnsroutes
) in itertools
.product([True, False, None], repeat
=3):
3146 with self
.subTest(routes
=routes
, gateway
=gateway
, dnsroutes
=dnsroutes
):
3147 self
._test
_dhcp
_client
_ipv
4_use
_routes
_gateway
(routes
, gateway
, dnsroutes
)
3150 def _test_dhcp_client_ipv4_use_routes_gateway(self
, routes
, gateway
, dnsroutes
):
3151 testunit
= 'dhcp-client-ipv4-use-routes-use-gateway.network'
3152 testunits
= ['25-veth.netdev', 'dhcp-server-veth-peer.network', testunit
]
3154 testunits
.append(f
'{testunit}.d/use-routes-{routes}.conf');
3156 testunits
.append(f
'{testunit}.d/use-gateway-{gateway}.conf');
3157 if dnsroutes
!= None:
3158 testunits
.append(f
'{testunit}.d/use-dns-routes-{dnsroutes}.conf');
3159 copy_unit_to_networkd_unit_path(*testunits
, dropins
=False)
3162 self
.wait_online(['veth-peer:carrier'])
3163 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
3164 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3166 output
= check_output('ip route show dev veth99')
3169 # UseRoutes= defaults to true
3170 useroutes
= routes
in [True, None]
3171 # UseGateway= defaults to useroutes
3172 usegateway
= useroutes
if gateway
== None else gateway
3176 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.181 metric 1024')
3178 self
.assertNotRegex(output
, r
'192.168.5.5')
3182 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.181 metric 1024')
3184 self
.assertNotRegex(output
, r
'default via 192.168.5.1')
3186 # Check RoutesToDNS=, which defaults to false
3188 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3189 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3191 self
.assertNotRegex(output
, r
'192.168.5.6')
3192 self
.assertNotRegex(output
, r
'192.168.5.7')
3194 def test_dhcp_client_ipv4_ipv6(self
):
3195 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
3196 'dhcp-client-ipv4-only.network')
3198 self
.wait_online(['veth-peer:carrier'])
3200 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3202 # link become 'routable' when at least one protocol provide an valid address.
3203 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3204 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3206 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3208 self
.assertRegex(output
, '2600::')
3209 self
.assertRegex(output
, '192.168.5')
3211 def test_dhcp_client_settings(self
):
3212 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
3215 self
.wait_online(['veth-peer:carrier'])
3217 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3219 print('## ip address show dev veth99')
3220 output
= check_output('ip address show dev veth99')
3222 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3223 self
.assertRegex(output
, '192.168.5')
3224 self
.assertRegex(output
, '1492')
3226 print('## ip route show table main dev veth99')
3227 output
= check_output('ip route show table main dev veth99')
3230 main_table_is_empty
= output
== ''
3231 if not main_table_is_empty
:
3232 self
.assertNotRegex(output
, 'proto dhcp')
3234 print('## ip route show table 211 dev veth99')
3235 output
= check_output('ip route show table 211 dev veth99')
3237 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
3238 if main_table_is_empty
:
3239 self
.assertRegex(output
, '192.168.5.0/24 proto dhcp')
3240 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
3241 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
3243 print('## dnsmasq log')
3244 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
3245 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
3246 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
3247 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
3249 def test_dhcp6_client_settings_rapidcommit_true(self
):
3250 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3252 self
.wait_online(['veth-peer:carrier'])
3254 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3256 output
= check_output('ip address show dev veth99')
3258 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3259 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
3261 def test_dhcp6_client_settings_rapidcommit_false(self
):
3262 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
3264 self
.wait_online(['veth-peer:carrier'])
3266 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3268 output
= check_output('ip address show dev veth99')
3270 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3271 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
3273 def test_dhcp_client_settings_anonymize(self
):
3274 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
3276 self
.wait_online(['veth-peer:carrier'])
3278 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3280 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
3281 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
3282 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
3284 def test_dhcp_client_listen_port(self
):
3285 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
3287 self
.wait_online(['veth-peer:carrier'])
3288 start_dnsmasq('--dhcp-alternate-port=67,5555')
3289 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3291 output
= check_output('ip -4 address show dev veth99')
3293 self
.assertRegex(output
, '192.168.5.* dynamic')
3295 def test_dhcp_client_with_static_address(self
):
3296 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
3297 'dhcp-client-with-static-address.network')
3299 self
.wait_online(['veth-peer:carrier'])
3301 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3303 output
= check_output('ip address show dev veth99 scope global')
3305 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
3306 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
3308 output
= check_output('ip route show dev veth99')
3310 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
3311 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
3312 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
3313 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
3315 def test_dhcp_route_table_id(self
):
3316 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
3318 self
.wait_online(['veth-peer:carrier'])
3320 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3322 output
= check_output('ip route show table 12')
3324 self
.assertRegex(output
, 'veth99 proto dhcp')
3325 self
.assertRegex(output
, '192.168.5.1')
3327 def test_dhcp_route_metric(self
):
3328 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
3330 self
.wait_online(['veth-peer:carrier'])
3332 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3334 output
= check_output('ip route show dev veth99')
3336 self
.assertRegex(output
, 'metric 24')
3338 def test_dhcp_client_reassign_static_routes_ipv4(self
):
3339 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3340 'dhcp-client-reassign-static-routes-ipv4.network')
3342 self
.wait_online(['veth-peer:carrier'])
3343 start_dnsmasq(lease_time
='2m')
3344 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3346 output
= check_output('ip address show dev veth99 scope global')
3348 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3350 output
= check_output('ip route show dev veth99')
3352 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3353 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3354 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3355 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3357 stop_dnsmasq(dnsmasq_pid_file
)
3358 start_dnsmasq(ipv4_range
='192.168.5.210,192.168.5.220', lease_time
='2m')
3360 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3361 print('Wait for the dynamic address to be renewed')
3364 self
.wait_online(['veth99:routable'])
3366 output
= check_output('ip route show dev veth99')
3368 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3369 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3370 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3371 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3373 def test_dhcp_client_reassign_static_routes_ipv6(self
):
3374 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3375 'dhcp-client-reassign-static-routes-ipv6.network')
3377 self
.wait_online(['veth-peer:carrier'])
3378 start_dnsmasq(lease_time
='2m')
3379 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3381 output
= check_output('ip address show dev veth99 scope global')
3383 self
.assertRegex(output
, r
'inet6 2600::[0-9a-f]*/128 scope global (noprefixroute dynamic|dynamic noprefixroute)')
3385 output
= check_output('ip -6 route show dev veth99')
3387 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3388 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3390 stop_dnsmasq(dnsmasq_pid_file
)
3391 start_dnsmasq(ipv6_range
='2600::30,2600::40', lease_time
='2m')
3393 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3394 print('Wait for the dynamic address to be renewed')
3397 self
.wait_online(['veth99:routable'])
3399 output
= check_output('ip -6 route show dev veth99')
3401 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3402 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3404 def test_dhcp_keep_configuration_dhcp(self
):
3405 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
3407 self
.wait_online(['veth-peer:carrier'])
3408 start_dnsmasq(lease_time
='2m')
3409 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3411 output
= check_output('ip address show dev veth99 scope global')
3413 self
.assertRegex(output
, r
'192.168.5.*')
3415 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3417 self
.assertRegex(output
, r
'192.168.5.*')
3419 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
3420 stop_dnsmasq(dnsmasq_pid_file
)
3422 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3423 print('Wait for the dynamic address to be expired')
3426 print('The lease address should be kept after lease expired')
3427 output
= check_output('ip address show dev veth99 scope global')
3429 self
.assertRegex(output
, r
'192.168.5.*')
3431 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3433 self
.assertRegex(output
, r
'192.168.5.*')
3435 check_output('systemctl stop systemd-networkd')
3437 print('The lease address should be kept after networkd stopped')
3438 output
= check_output('ip address show dev veth99 scope global')
3440 self
.assertRegex(output
, r
'192.168.5.*')
3442 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3444 self
.assertRegex(output
, r
'192.168.5.*')
3447 self
.wait_online(['veth-peer:routable'])
3449 print('Still the lease address should be kept after networkd restarted')
3450 output
= check_output('ip address show dev veth99 scope global')
3452 self
.assertRegex(output
, r
'192.168.5.*')
3454 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3456 self
.assertRegex(output
, r
'192.168.5.*')
3458 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
3459 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
3461 self
.wait_online(['veth-peer:carrier'])
3462 start_dnsmasq(lease_time
='2m')
3463 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3465 output
= check_output('ip address show dev veth99 scope global')
3467 self
.assertRegex(output
, r
'192.168.5.*')
3469 stop_dnsmasq(dnsmasq_pid_file
)
3470 check_output('systemctl stop systemd-networkd')
3472 output
= check_output('ip address show dev veth99 scope global')
3474 self
.assertRegex(output
, r
'192.168.5.*')
3477 self
.wait_online(['veth-peer:routable'])
3479 output
= check_output('ip address show dev veth99 scope global')
3481 self
.assertNotRegex(output
, r
'192.168.5.*')
3483 def test_dhcp_client_reuse_address_as_static(self
):
3484 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
3486 self
.wait_online(['veth-peer:carrier'])
3488 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3490 # link become 'routable' when at least one protocol provide an valid address.
3491 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3492 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3494 output
= check_output('ip address show dev veth99 scope global')
3496 self
.assertRegex(output
, '192.168.5')
3497 self
.assertRegex(output
, '2600::')
3499 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
3500 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
3501 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
3502 print(static_network
)
3504 remove_unit_from_networkd_path(['dhcp-client.network'])
3506 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
3507 f
.write(static_network
)
3509 # When networkd started, the links are already configured, so let's wait for 5 seconds
3510 # the links to be re-configured.
3512 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3514 output
= check_output('ip -4 address show dev veth99 scope global')
3516 self
.assertRegex(output
, '192.168.5')
3517 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3519 output
= check_output('ip -6 address show dev veth99 scope global')
3521 self
.assertRegex(output
, '2600::')
3522 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3524 @expectedFailureIfModuleIsNotAvailable('vrf')
3525 def test_dhcp_client_vrf(self
):
3526 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
3527 '25-vrf.netdev', '25-vrf.network')
3529 self
.wait_online(['veth-peer:carrier'])
3531 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
3533 # link become 'routable' when at least one protocol provide an valid address.
3534 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3535 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3537 print('## ip -d link show dev vrf99')
3538 output
= check_output('ip -d link show dev vrf99')
3540 self
.assertRegex(output
, 'vrf table 42')
3542 print('## ip address show vrf vrf99')
3543 output
= check_output('ip address show vrf vrf99')
3545 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3546 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3547 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3548 self
.assertRegex(output
, 'inet6 .* scope link')
3550 print('## ip address show dev veth99')
3551 output
= check_output('ip address show dev veth99')
3553 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3554 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3555 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3556 self
.assertRegex(output
, 'inet6 .* scope link')
3558 print('## ip route show vrf vrf99')
3559 output
= check_output('ip route show vrf vrf99')
3561 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
3562 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
3563 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
3564 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
3565 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
3567 print('## ip route show table main dev veth99')
3568 output
= check_output('ip route show table main dev veth99')
3570 self
.assertEqual(output
, '')
3572 def test_dhcp_client_gateway_ipv4(self
):
3573 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3574 'dhcp-client-gateway-ipv4.network')
3576 self
.wait_online(['veth-peer:carrier'])
3578 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3580 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3582 self
.assertRegex(output
, '10.0.0.0/8 via 192.168.5.1 proto static')
3584 def test_dhcp_client_gateway_ipv6(self
):
3585 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3586 'dhcp-client-gateway-ipv6.network')
3588 self
.wait_online(['veth-peer:carrier'])
3590 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3592 output
= check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
3594 self
.assertRegex(output
, 'via fe80::1034:56ff:fe78:9abd')
3596 def test_dhcp_client_gateway_onlink_implicit(self
):
3597 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3598 'dhcp-client-gateway-onlink-implicit.network')
3600 self
.wait_online(['veth-peer:carrier'])
3602 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3604 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3606 self
.assertRegex(output
, '192.168.5')
3608 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3610 self
.assertRegex(output
, 'onlink')
3611 output
= check_output('ip route list dev veth99 192.168.100.0/24')
3613 self
.assertRegex(output
, 'onlink')
3615 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
3616 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3617 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
3619 self
.wait_online(['veth-peer:carrier'])
3620 start_dnsmasq(lease_time
='2m')
3621 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3623 output
= check_output('ip address show dev veth99')
3626 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3627 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3628 output
= check_output('ip -6 address show dev veth99 scope link')
3629 self
.assertRegex(output
, 'inet6 .* scope link')
3630 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3631 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3632 output
= check_output('ip -4 address show dev veth99 scope link')
3633 self
.assertNotRegex(output
, 'inet .* scope link')
3635 print('Wait for the dynamic address to be expired')
3638 output
= check_output('ip address show dev veth99')
3641 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3642 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3643 output
= check_output('ip -6 address show dev veth99 scope link')
3644 self
.assertRegex(output
, 'inet6 .* scope link')
3645 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3646 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3647 output
= check_output('ip -4 address show dev veth99 scope link')
3648 self
.assertNotRegex(output
, 'inet .* scope link')
3650 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
3652 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
3653 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3654 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
3656 self
.wait_online(['veth99:degraded', 'veth-peer:routable'])
3658 output
= check_output('ip address show dev veth99')
3661 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3662 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3663 output
= check_output('ip -6 address show dev veth99 scope link')
3664 self
.assertRegex(output
, 'inet6 .* scope link')
3665 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3666 self
.assertNotRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3667 output
= check_output('ip -4 address show dev veth99 scope link')
3668 self
.assertRegex(output
, 'inet .* scope link')
3670 def test_dhcp_client_route_remove_on_renew(self
):
3671 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3672 'dhcp-client-ipv4-only-ipv6-disabled.network')
3674 self
.wait_online(['veth-peer:carrier'])
3675 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
3676 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3678 # test for issue #12490
3680 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3682 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3684 for line
in output
.splitlines():
3685 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3686 address1
= line
.split()[1].split('/')[0]
3689 output
= check_output('ip -4 route show dev veth99')
3691 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3692 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3694 stop_dnsmasq(dnsmasq_pid_file
)
3695 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
3697 print('Wait for the dynamic address to be expired')
3700 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3702 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3704 for line
in output
.splitlines():
3705 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3706 address2
= line
.split()[1].split('/')[0]
3709 self
.assertNotEqual(address1
, address2
)
3711 output
= check_output('ip -4 route show dev veth99')
3713 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3714 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3715 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
3716 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
3718 def test_dhcp_client_use_dns_yes(self
):
3719 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-yes.network')
3722 self
.wait_online(['veth-peer:carrier'])
3723 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3724 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3726 # link become 'routable' when at least one protocol provide an valid address.
3727 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3728 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3731 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3733 self
.assertRegex(output
, '192.168.5.1')
3734 self
.assertRegex(output
, '2600::1')
3736 def test_dhcp_client_use_dns_no(self
):
3737 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-no.network')
3740 self
.wait_online(['veth-peer:carrier'])
3741 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3742 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3744 # link become 'routable' when at least one protocol provide an valid address.
3745 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3746 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3749 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3751 self
.assertNotRegex(output
, '192.168.5.1')
3752 self
.assertNotRegex(output
, '2600::1')
3754 def test_dhcp_client_use_dns_ipv4(self
):
3755 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4.network')
3758 self
.wait_online(['veth-peer:carrier'])
3759 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3760 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3762 # link become 'routable' when at least one protocol provide an valid address.
3763 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3764 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3767 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3769 self
.assertRegex(output
, '192.168.5.1')
3770 self
.assertNotRegex(output
, '2600::1')
3772 def test_dhcp_client_use_dns_ipv4_and_ra(self
):
3773 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4-and-ra.network')
3776 self
.wait_online(['veth-peer:carrier'])
3777 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3778 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3780 # link become 'routable' when at least one protocol provide an valid address.
3781 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3782 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3785 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3787 self
.assertRegex(output
, '192.168.5.1')
3788 self
.assertRegex(output
, '2600::1')
3790 def test_dhcp_client_use_domains(self
):
3791 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-domains.network')
3794 self
.wait_online(['veth-peer:carrier'])
3795 start_dnsmasq('--dhcp-option=option:domain-search,example.com')
3796 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3798 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3800 self
.assertRegex(output
, 'Search Domains: example.com')
3803 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
3805 self
.assertRegex(output
, 'example.com')
3807 def test_dhcp_client_decline(self
):
3808 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-decline.network', 'dhcp-client-decline.network')
3811 self
.wait_online(['veth-peer:carrier'])
3812 rc
= call(*wait_online_cmd
, '--timeout=10s', '--interface=veth99:routable', env
=env
)
3813 self
.assertTrue(rc
== 1)
3815 class NetworkdIPv6PrefixTests(unittest
.TestCase
, Utilities
):
3820 'ipv6ra-prefix-client.network',
3821 'ipv6ra-prefix.network'
3825 remove_links(self
.links
)
3826 stop_networkd(show_logs
=False)
3830 remove_links(self
.links
)
3831 remove_unit_from_networkd_path(self
.units
)
3832 stop_networkd(show_logs
=True)
3834 def test_ipv6_route_prefix(self
):
3835 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client.network', 'ipv6ra-prefix.network')
3838 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3840 output
= check_output('ip -6 route show dev veth-peer')
3842 self
.assertRegex(output
, '2001:db8:0:1::/64 proto ra')
3844 output
= check_output('ip addr show dev veth99')
3846 self
.assertNotRegex(output
, '2001:db8:0:1')
3847 self
.assertRegex(output
, '2001:db8:0:2')
3849 class NetworkdMTUTests(unittest
.TestCase
, Utilities
):
3854 '12-dummy-mtu.netdev',
3855 '12-dummy-mtu.link',
3860 remove_links(self
.links
)
3861 stop_networkd(show_logs
=False)
3865 remove_links(self
.links
)
3866 remove_unit_from_networkd_path(self
.units
)
3867 stop_networkd(show_logs
=True)
3869 def check_mtu(self
, mtu
, ipv6_mtu
=None, reset
=True):
3875 self
.wait_online(['dummy98:routable'])
3876 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
3877 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
3879 # test normal restart
3881 self
.wait_online(['dummy98:routable'])
3882 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
3883 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
3886 self
.reset_check_mtu(mtu
, ipv6_mtu
)
3888 def reset_check_mtu(self
, mtu
, ipv6_mtu
=None):
3889 ''' test setting mtu/ipv6_mtu with interface already up '''
3892 # note - changing the device mtu resets the ipv6 mtu
3893 run('ip link set up mtu 1501 dev dummy98')
3894 run('ip link set up mtu 1500 dev dummy98')
3895 self
.assertEqual(read_link_attr('dummy98', 'mtu'), '1500')
3896 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), '1500')
3898 self
.check_mtu(mtu
, ipv6_mtu
, reset
=False)
3900 def test_mtu_network(self
):
3901 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
3902 self
.check_mtu('1600')
3904 def test_mtu_netdev(self
):
3905 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network', dropins
=False)
3906 # note - MTU set by .netdev happens ONLY at device creation!
3907 self
.check_mtu('1600', reset
=False)
3909 def test_mtu_link(self
):
3910 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', dropins
=False)
3911 # must reload udev because it only picks up new files after 3 second delay
3912 call('udevadm control --reload')
3913 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
3914 self
.check_mtu('1600', reset
=False)
3916 def test_ipv6_mtu(self
):
3917 ''' set ipv6 mtu without setting device mtu '''
3918 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
3919 self
.check_mtu('1500', '1400')
3921 def test_ipv6_mtu_toolarge(self
):
3922 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
3923 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
3924 self
.check_mtu('1500', '1500')
3926 def test_mtu_network_ipv6_mtu(self
):
3927 ''' set ipv6 mtu and set device mtu via network file '''
3928 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
3929 self
.check_mtu('1600', '1550')
3931 def test_mtu_netdev_ipv6_mtu(self
):
3932 ''' set ipv6 mtu and set device mtu via netdev file '''
3933 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
3934 self
.check_mtu('1600', '1550', reset
=False)
3936 def test_mtu_link_ipv6_mtu(self
):
3937 ''' set ipv6 mtu and set device mtu via link file '''
3938 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
3939 # must reload udev because it only picks up new files after 3 second delay
3940 call('udevadm control --reload')
3941 self
.check_mtu('1600', '1550', reset
=False)
3944 if __name__
== '__main__':
3945 parser
= argparse
.ArgumentParser()
3946 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
3947 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
3948 parser
.add_argument('--resolved', help='Path to systemd-resolved', dest
='resolved_bin')
3949 parser
.add_argument('--udevd', help='Path to systemd-udevd', dest
='udevd_bin')
3950 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
3951 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
3952 parser
.add_argument('--resolvectl', help='Path to resolvectl', dest
='resolvectl_bin')
3953 parser
.add_argument('--timedatectl', help='Path to timedatectl', dest
='timedatectl_bin')
3954 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
3955 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
3956 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
3957 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
3958 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
3959 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
3962 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
:
3963 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
3964 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
3965 resolved_bin
= os
.path
.join(ns
.build_dir
, 'systemd-resolved')
3966 udevd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-udevd')
3967 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
3968 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
3969 resolvectl_bin
= os
.path
.join(ns
.build_dir
, 'resolvectl')
3970 timedatectl_bin
= os
.path
.join(ns
.build_dir
, 'timedatectl')
3973 networkd_bin
= ns
.networkd_bin
3975 resolved_bin
= ns
.resolved_bin
3977 udevd_bin
= ns
.udevd_bin
3978 if ns
.wait_online_bin
:
3979 wait_online_bin
= ns
.wait_online_bin
3980 if ns
.networkctl_bin
:
3981 networkctl_bin
= ns
.networkctl_bin
3982 if ns
.resolvectl_bin
:
3983 resolvectl_bin
= ns
.resolvectl_bin
3984 if ns
.timedatectl_bin
:
3985 timedatectl_bin
= ns
.timedatectl_bin
3987 use_valgrind
= ns
.use_valgrind
3988 enable_debug
= ns
.enable_debug
3989 asan_options
= ns
.asan_options
3990 lsan_options
= ns
.lsan_options
3991 ubsan_options
= ns
.ubsan_options
3994 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
3995 resolvectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin
]
3996 timedatectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin
]
3997 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
3999 networkctl_cmd
= [networkctl_bin
]
4000 resolvectl_cmd
= [resolvectl_bin
]
4001 timedatectl_cmd
= [timedatectl_bin
]
4002 wait_online_cmd
= [wait_online_bin
]
4005 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
4007 env
.update({ 'ASAN_OPTIONS' : asan_options
})
4009 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
4011 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
4014 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,