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
= [
754 '10-dropin-test.netdev',
758 '13-not-match-udev-property.network',
759 '14-match-udev-property.network',
760 '15-name-conflict-test.netdev',
763 '21-vlan-test1.network',
766 '25-6rd-tunnel.netdev',
768 '25-bond-balanced-tlb.netdev',
770 '25-bridge-configure-without-carrier.network',
772 '25-erspan-tunnel-local-any.netdev',
773 '25-erspan-tunnel.netdev',
774 '25-fou-gretap.netdev',
776 '25-fou-ipip.netdev',
777 '25-fou-ipproto-gre.netdev',
778 '25-fou-ipproto-ipip.netdev',
781 '25-gretap-tunnel-local-any.netdev',
782 '25-gretap-tunnel.netdev',
783 '25-gre-tunnel-any-any.netdev',
784 '25-gre-tunnel-local-any.netdev',
785 '25-gre-tunnel-remote-any.netdev',
786 '25-gre-tunnel.netdev',
788 '25-ip6gretap-tunnel-local-any.netdev',
789 '25-ip6gretap-tunnel.netdev',
790 '25-ip6gre-tunnel-any-any.netdev',
791 '25-ip6gre-tunnel-local-any.netdev',
792 '25-ip6gre-tunnel-remote-any.netdev',
793 '25-ip6gre-tunnel.netdev',
794 '25-ip6tnl-tunnel-any-any.netdev',
795 '25-ip6tnl-tunnel-local-any.netdev',
796 '25-ip6tnl-tunnel-remote-any.netdev',
797 '25-ip6tnl-tunnel.netdev',
798 '25-ipip-tunnel-any-any.netdev',
799 '25-ipip-tunnel-independent.netdev',
800 '25-ipip-tunnel-independent-loopback.netdev',
801 '25-ipip-tunnel-local-any.netdev',
802 '25-ipip-tunnel-remote-any.netdev',
803 '25-ipip-tunnel.netdev',
806 '25-isatap-tunnel.netdev',
811 '25-sit-tunnel-any-any.netdev',
812 '25-sit-tunnel-local-any.netdev',
813 '25-sit-tunnel-remote-any.netdev',
814 '25-sit-tunnel.netdev',
817 '25-tunnel-local-any.network',
818 '25-tunnel-remote-any.network',
823 '25-vti6-tunnel-any-any.netdev',
824 '25-vti6-tunnel-local-any.netdev',
825 '25-vti6-tunnel-remote-any.netdev',
826 '25-vti6-tunnel.netdev',
827 '25-vti-tunnel-any-any.netdev',
828 '25-vti-tunnel-local-any.netdev',
829 '25-vti-tunnel-remote-any.netdev',
830 '25-vti-tunnel.netdev',
833 '25-wireguard-23-peers.netdev',
834 '25-wireguard-23-peers.network',
835 '25-wireguard-preshared-key.txt',
836 '25-wireguard-private-key.txt',
837 '25-wireguard.netdev',
838 '25-wireguard.network',
840 '25-xfrm-independent.netdev',
856 'netdev-link-local-addressing-yes.network',
860 'vxlan-test1.network',
870 remove_fou_ports(self
.fou_ports
)
871 remove_links(self
.links_remove_earlier
)
872 remove_links(self
.links
)
873 stop_networkd(show_logs
=False)
876 remove_fou_ports(self
.fou_ports
)
877 remove_links(self
.links_remove_earlier
)
878 remove_links(self
.links
)
879 remove_unit_from_networkd_path(self
.units
)
880 stop_networkd(show_logs
=True)
882 def test_dropin_and_name_conflict(self
):
883 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
886 self
.wait_online(['dropin-test:off'], setup_state
='unmanaged')
888 output
= check_output('ip link show dropin-test')
890 self
.assertRegex(output
, '00:50:56:c0:00:28')
892 def test_match_udev_property(self
):
893 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
895 self
.wait_online(['dummy98:routable'])
897 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
899 self
.assertRegex(output
, 'Network File: /run/systemd/network/14-match-udev-property')
901 def test_wait_online_any(self
):
902 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
905 self
.wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
907 self
.wait_operstate('bridge99', '(off|no-carrier)', setup_state
='configuring')
908 self
.wait_operstate('test1', 'degraded')
910 def test_bridge(self
):
911 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
914 self
.wait_online(['bridge99:no-carrier'])
916 tick
= os
.sysconf('SC_CLK_TCK')
917 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
918 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
919 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'forward_delay')) / tick
))
920 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'ageing_time')) / tick
))
921 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge', 'priority')))
922 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_querier')))
923 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_snooping')))
924 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'stp_state')))
925 self
.assertEqual(3, int(read_link_attr('bridge99', 'bridge', 'multicast_igmp_version')))
927 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
929 self
.assertRegex(output
, 'Priority: 9')
930 self
.assertRegex(output
, 'STP: yes')
931 self
.assertRegex(output
, 'Multicast IGMP Version: 3')
934 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
937 self
.wait_online(['bond99:off', 'bond98:off'], setup_state
='unmanaged')
939 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
940 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
941 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
942 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
943 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
944 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
945 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
946 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
947 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
948 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
949 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
951 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
952 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
955 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
956 '21-vlan.network', '21-vlan-test1.network')
959 self
.wait_online(['test1:degraded', 'vlan99:routable'])
961 output
= check_output('ip -d link show test1')
963 self
.assertRegex(output
, ' mtu 2000 ')
965 output
= check_output('ip -d link show vlan99')
967 self
.assertRegex(output
, ' mtu 2000 ')
968 self
.assertRegex(output
, 'REORDER_HDR')
969 self
.assertRegex(output
, 'LOOSE_BINDING')
970 self
.assertRegex(output
, 'GVRP')
971 self
.assertRegex(output
, 'MVRP')
972 self
.assertRegex(output
, ' id 99 ')
974 output
= check_output('ip -4 address show dev test1')
976 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
977 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
979 output
= check_output('ip -4 address show dev vlan99')
981 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
983 def test_macvtap(self
):
984 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
985 with self
.subTest(mode
=mode
):
986 if mode
!= 'private':
988 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
989 '11-dummy.netdev', 'macvtap.network')
990 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
991 f
.write('[MACVTAP]\nMode=' + mode
)
994 self
.wait_online(['macvtap99:degraded', 'test1:degraded'])
996 output
= check_output('ip -d link show macvtap99')
998 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
1000 def test_macvlan(self
):
1001 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
1002 with self
.subTest(mode
=mode
):
1003 if mode
!= 'private':
1005 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
1006 '11-dummy.netdev', 'macvlan.network')
1007 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
1008 f
.write('[MACVLAN]\nMode=' + mode
)
1011 self
.wait_online(['macvlan99:degraded', 'test1:degraded'])
1013 output
= check_output('ip -d link show test1')
1015 self
.assertRegex(output
, ' mtu 2000 ')
1017 output
= check_output('ip -d link show macvlan99')
1019 self
.assertRegex(output
, ' mtu 2000 ')
1020 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
1022 @expectedFailureIfModuleIsNotAvailable('ipvlan')
1023 def test_ipvlan(self
):
1024 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1025 with self
.subTest(mode
=mode
, flag
=flag
):
1028 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
1029 '11-dummy.netdev', 'ipvlan.network')
1030 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
1031 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
1034 self
.wait_online(['ipvlan99:degraded', 'test1:degraded'])
1036 output
= check_output('ip -d link show ipvlan99')
1038 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
1040 @expectedFailureIfModuleIsNotAvailable('ipvtap')
1041 def test_ipvtap(self
):
1042 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1043 with self
.subTest(mode
=mode
, flag
=flag
):
1046 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
1047 '11-dummy.netdev', 'ipvtap.network')
1048 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
1049 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
1052 self
.wait_online(['ipvtap99:degraded', 'test1:degraded'])
1054 output
= check_output('ip -d link show ipvtap99')
1056 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
1058 def test_veth(self
):
1059 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
1062 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
1064 output
= check_output('ip -d link show veth99')
1066 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
1067 output
= check_output('ip -d link show veth-peer')
1069 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
1072 copy_unit_to_networkd_unit_path('25-tun.netdev')
1075 self
.wait_online(['tun99:off'], setup_state
='unmanaged')
1077 output
= check_output('ip -d link show tun99')
1079 # Old ip command does not support IFF_ flags
1080 self
.assertRegex(output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
1083 copy_unit_to_networkd_unit_path('25-tap.netdev')
1086 self
.wait_online(['tap99:off'], setup_state
='unmanaged')
1088 output
= check_output('ip -d link show tap99')
1090 # Old ip command does not support IFF_ flags
1091 self
.assertRegex(output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
1093 @expectedFailureIfModuleIsNotAvailable('vrf')
1095 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
1098 self
.wait_online(['vrf99:carrier'])
1100 @expectedFailureIfModuleIsNotAvailable('vcan')
1101 def test_vcan(self
):
1102 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
1105 self
.wait_online(['vcan99:carrier'])
1107 @expectedFailureIfModuleIsNotAvailable('vxcan')
1108 def test_vxcan(self
):
1109 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
1112 self
.wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
1114 @expectedFailureIfModuleIsNotAvailable('wireguard')
1115 def test_wireguard(self
):
1116 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
1117 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
1118 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt')
1120 self
.wait_online(['wg99:carrier', 'wg98:routable'])
1122 if shutil
.which('wg'):
1125 output
= check_output('wg show wg99 listen-port')
1126 self
.assertRegex(output
, '51820')
1127 output
= check_output('wg show wg99 fwmark')
1128 self
.assertRegex(output
, '0x4d2')
1129 output
= check_output('wg show wg99 allowed-ips')
1130 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
1131 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
1132 output
= check_output('wg show wg99 persistent-keepalive')
1133 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
1134 output
= check_output('wg show wg99 endpoints')
1135 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
1136 output
= check_output('wg show wg99 private-key')
1137 self
.assertRegex(output
, r
'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
1138 output
= check_output('wg show wg99 preshared-keys')
1139 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
1140 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
1142 output
= check_output('wg show wg98 private-key')
1143 self
.assertRegex(output
, r
'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
1145 def test_geneve(self
):
1146 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
1149 self
.wait_online(['geneve99:degraded'])
1151 output
= check_output('ip -d link show geneve99')
1153 self
.assertRegex(output
, '192.168.22.1')
1154 self
.assertRegex(output
, '6082')
1155 self
.assertRegex(output
, 'udpcsum')
1156 self
.assertRegex(output
, 'udp6zerocsumrx')
1158 def test_ipip_tunnel(self
):
1159 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
1160 '25-ipip-tunnel.netdev', '25-tunnel.network',
1161 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1162 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1163 '25-ipip-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1165 self
.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'ipiptun96:routable', 'dummy98:degraded'])
1167 output
= check_output('ip -d link show ipiptun99')
1169 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98')
1170 output
= check_output('ip -d link show ipiptun98')
1172 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98')
1173 output
= check_output('ip -d link show ipiptun97')
1175 self
.assertRegex(output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98')
1176 output
= check_output('ip -d link show ipiptun96')
1178 self
.assertRegex(output
, 'ipip (ipip )?remote any local any dev dummy98')
1180 def test_gre_tunnel(self
):
1181 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
1182 '25-gre-tunnel.netdev', '25-tunnel.network',
1183 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1184 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1185 '25-gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1187 self
.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'gretun96:routable', 'dummy98:degraded'])
1189 output
= check_output('ip -d link show gretun99')
1191 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1192 self
.assertRegex(output
, 'ikey 1.2.3.103')
1193 self
.assertRegex(output
, 'okey 1.2.4.103')
1194 self
.assertRegex(output
, 'iseq')
1195 self
.assertRegex(output
, 'oseq')
1196 output
= check_output('ip -d link show gretun98')
1198 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
1199 self
.assertRegex(output
, 'ikey 0.0.0.104')
1200 self
.assertRegex(output
, 'okey 0.0.0.104')
1201 self
.assertNotRegex(output
, 'iseq')
1202 self
.assertNotRegex(output
, 'oseq')
1203 output
= check_output('ip -d link show gretun97')
1205 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
1206 self
.assertRegex(output
, 'ikey 0.0.0.105')
1207 self
.assertRegex(output
, 'okey 0.0.0.105')
1208 self
.assertNotRegex(output
, 'iseq')
1209 self
.assertNotRegex(output
, 'oseq')
1210 output
= check_output('ip -d link show gretun96')
1212 self
.assertRegex(output
, 'gre remote any local any dev dummy98')
1213 self
.assertRegex(output
, 'ikey 0.0.0.106')
1214 self
.assertRegex(output
, 'okey 0.0.0.106')
1215 self
.assertNotRegex(output
, 'iseq')
1216 self
.assertNotRegex(output
, 'oseq')
1218 def test_ip6gre_tunnel(self
):
1219 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
1220 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
1221 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1222 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1223 '25-ip6gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1226 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1228 self
.check_link_exists('dummy98')
1229 self
.check_link_exists('ip6gretun99')
1230 self
.check_link_exists('ip6gretun98')
1231 self
.check_link_exists('ip6gretun97')
1232 self
.check_link_exists('ip6gretun96')
1234 output
= check_output('ip -d link show ip6gretun99')
1236 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1237 output
= check_output('ip -d link show ip6gretun98')
1239 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
1240 output
= check_output('ip -d link show ip6gretun97')
1242 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
1243 output
= check_output('ip -d link show ip6gretun96')
1245 self
.assertRegex(output
, 'ip6gre remote any local any dev dummy98')
1247 def test_gretap_tunnel(self
):
1248 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
1249 '25-gretap-tunnel.netdev', '25-tunnel.network',
1250 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1252 self
.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
1254 output
= check_output('ip -d link show gretap99')
1256 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1257 self
.assertRegex(output
, 'ikey 0.0.0.106')
1258 self
.assertRegex(output
, 'okey 0.0.0.106')
1259 self
.assertRegex(output
, 'iseq')
1260 self
.assertRegex(output
, 'oseq')
1261 output
= check_output('ip -d link show gretap98')
1263 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
1264 self
.assertRegex(output
, 'ikey 0.0.0.107')
1265 self
.assertRegex(output
, 'okey 0.0.0.107')
1266 self
.assertRegex(output
, 'iseq')
1267 self
.assertRegex(output
, 'oseq')
1269 def test_ip6gretap_tunnel(self
):
1270 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
1271 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1272 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1274 self
.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
1276 output
= check_output('ip -d link show ip6gretap99')
1278 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1279 output
= check_output('ip -d link show ip6gretap98')
1281 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1283 def test_vti_tunnel(self
):
1284 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
1285 '25-vti-tunnel.netdev', '25-tunnel.network',
1286 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1287 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1288 '25-vti-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1290 self
.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'vtitun96:routable', 'dummy98:degraded'])
1292 output
= check_output('ip -d link show vtitun99')
1294 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1295 output
= check_output('ip -d link show vtitun98')
1297 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
1298 output
= check_output('ip -d link show vtitun97')
1300 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
1301 output
= check_output('ip -d link show vtitun96')
1303 self
.assertRegex(output
, 'vti remote any local any dev dummy98')
1305 def test_vti6_tunnel(self
):
1306 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
1307 '25-vti6-tunnel.netdev', '25-tunnel.network',
1308 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1309 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1311 self
.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
1313 output
= check_output('ip -d link show vti6tun99')
1315 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1316 output
= check_output('ip -d link show vti6tun98')
1318 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1319 output
= check_output('ip -d link show vti6tun97')
1321 self
.assertRegex(output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1323 def test_ip6tnl_tunnel(self
):
1324 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
1325 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1326 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1327 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1329 self
.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
1331 output
= check_output('ip -d link show ip6tnl99')
1333 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1334 output
= check_output('ip -d link show ip6tnl98')
1336 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1337 output
= check_output('ip -d link show ip6tnl97')
1339 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1341 def test_sit_tunnel(self
):
1342 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1343 '25-sit-tunnel.netdev', '25-tunnel.network',
1344 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1345 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1346 '25-sit-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1348 self
.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'sittun96:routable', 'dummy98:degraded'])
1350 output
= check_output('ip -d link show sittun99')
1352 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1353 output
= check_output('ip -d link show sittun98')
1355 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98")
1356 output
= check_output('ip -d link show sittun97')
1358 self
.assertRegex(output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98")
1359 output
= check_output('ip -d link show sittun96')
1361 self
.assertRegex(output
, "sit (ip6ip )?remote any local any dev dummy98")
1363 def test_isatap_tunnel(self
):
1364 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1365 '25-isatap-tunnel.netdev', '25-tunnel.network')
1367 self
.wait_online(['isataptun99:routable', 'dummy98:degraded'])
1369 output
= check_output('ip -d link show isataptun99')
1371 self
.assertRegex(output
, "isatap ")
1373 def test_6rd_tunnel(self
):
1374 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1375 '25-6rd-tunnel.netdev', '25-tunnel.network')
1377 self
.wait_online(['sittun99:routable', 'dummy98:degraded'])
1379 output
= check_output('ip -d link show sittun99')
1381 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1383 @expectedFailureIfERSPANModuleIsNotAvailable()
1384 def test_erspan_tunnel(self
):
1385 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1386 '25-erspan-tunnel.netdev', '25-tunnel.network',
1387 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1389 self
.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1391 output
= check_output('ip -d link show erspan99')
1393 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1394 self
.assertRegex(output
, 'ikey 0.0.0.101')
1395 self
.assertRegex(output
, 'okey 0.0.0.101')
1396 self
.assertRegex(output
, 'iseq')
1397 self
.assertRegex(output
, 'oseq')
1398 output
= check_output('ip -d link show erspan98')
1400 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1401 self
.assertRegex(output
, '102')
1402 self
.assertRegex(output
, 'ikey 0.0.0.102')
1403 self
.assertRegex(output
, 'okey 0.0.0.102')
1404 self
.assertRegex(output
, 'iseq')
1405 self
.assertRegex(output
, 'oseq')
1407 def test_tunnel_independent(self
):
1408 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1411 self
.wait_online(['ipiptun99:carrier'])
1413 def test_tunnel_independent_loopback(self
):
1414 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent-loopback.netdev', 'netdev-link-local-addressing-yes.network')
1417 self
.wait_online(['ipiptun99:carrier'])
1419 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1420 def test_xfrm(self
):
1421 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'xfrm.network',
1422 '25-xfrm.netdev', 'netdev-link-local-addressing-yes.network')
1425 self
.wait_online(['xfrm99:degraded', 'dummy98:degraded'])
1427 output
= check_output('ip link show dev xfrm99')
1430 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1431 def test_xfrm_independent(self
):
1432 copy_unit_to_networkd_unit_path('25-xfrm-independent.netdev', 'netdev-link-local-addressing-yes.network')
1435 self
.wait_online(['xfrm99:degraded'])
1437 @expectedFailureIfModuleIsNotAvailable('fou')
1439 # The following redundant check is necessary for CentOS CI.
1440 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1441 self
.assertTrue(is_module_available('fou'))
1443 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1444 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1445 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1448 self
.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'], setup_state
='unmanaged')
1450 output
= check_output('ip fou show')
1452 self
.assertRegex(output
, 'port 55555 ipproto 4')
1453 self
.assertRegex(output
, 'port 55556 ipproto 47')
1455 output
= check_output('ip -d link show ipiptun96')
1457 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1458 output
= check_output('ip -d link show sittun96')
1460 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1461 output
= check_output('ip -d link show gretun96')
1463 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1464 output
= check_output('ip -d link show gretap96')
1466 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1468 def test_vxlan(self
):
1469 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1470 '11-dummy.netdev', 'vxlan-test1.network')
1473 self
.wait_online(['test1:degraded', 'vxlan99:degraded'])
1475 output
= check_output('ip -d link show vxlan99')
1477 self
.assertRegex(output
, '999')
1478 self
.assertRegex(output
, '5555')
1479 self
.assertRegex(output
, 'l2miss')
1480 self
.assertRegex(output
, 'l3miss')
1481 self
.assertRegex(output
, 'udpcsum')
1482 self
.assertRegex(output
, 'udp6zerocsumtx')
1483 self
.assertRegex(output
, 'udp6zerocsumrx')
1484 self
.assertRegex(output
, 'remcsumtx')
1485 self
.assertRegex(output
, 'remcsumrx')
1486 self
.assertRegex(output
, 'gbp')
1488 output
= check_output('bridge fdb show dev vxlan99')
1490 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1491 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1492 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1494 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'vxlan99', env
=env
)
1496 self
.assertRegex(output
, 'VNI: 999')
1497 self
.assertRegex(output
, 'Destination Port: 5555')
1498 self
.assertRegex(output
, 'Underlying Device: test1')
1500 def test_macsec(self
):
1501 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1502 'macsec.network', '12-dummy.netdev')
1505 self
.wait_online(['dummy98:degraded', 'macsec99:routable'])
1507 output
= check_output('ip -d link show macsec99')
1509 self
.assertRegex(output
, 'macsec99@dummy98')
1510 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1511 self
.assertRegex(output
, 'encrypt on')
1513 output
= check_output('ip macsec show macsec99')
1515 self
.assertRegex(output
, 'encrypt on')
1516 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1517 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1518 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1519 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1520 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1521 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1522 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1523 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1524 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1525 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1526 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1528 def test_nlmon(self
):
1529 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1532 self
.wait_online(['nlmon99:carrier'])
1534 @expectedFailureIfModuleIsNotAvailable('ifb')
1536 copy_unit_to_networkd_unit_path('25-ifb.netdev', 'netdev-link-local-addressing-yes.network')
1539 self
.wait_online(['ifb99:degraded'])
1541 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1552 '25-l2tp-dummy.network',
1554 '25-l2tp-ip.netdev',
1555 '25-l2tp-udp.netdev']
1557 l2tp_tunnel_ids
= [ '10' ]
1560 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1561 remove_links(self
.links
)
1562 stop_networkd(show_logs
=False)
1565 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1566 remove_links(self
.links
)
1567 remove_unit_from_networkd_path(self
.units
)
1568 stop_networkd(show_logs
=True)
1570 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1571 def test_l2tp_udp(self
):
1572 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1573 '25-l2tp-udp.netdev', '25-l2tp.network')
1576 self
.wait_online(['test1:routable', 'l2tp-ses1:degraded', 'l2tp-ses2:degraded'])
1578 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1580 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1581 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1582 self
.assertRegex(output
, "Peer tunnel 11")
1583 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1584 self
.assertRegex(output
, "UDP checksum: enabled")
1586 output
= check_output('ip l2tp show session tid 10 session_id 15')
1588 self
.assertRegex(output
, "Session 15 in tunnel 10")
1589 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1590 self
.assertRegex(output
, "interface name: l2tp-ses1")
1592 output
= check_output('ip l2tp show session tid 10 session_id 17')
1594 self
.assertRegex(output
, "Session 17 in tunnel 10")
1595 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1596 self
.assertRegex(output
, "interface name: l2tp-ses2")
1598 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1599 def test_l2tp_ip(self
):
1600 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1601 '25-l2tp-ip.netdev', '25-l2tp.network')
1604 self
.wait_online(['test1:routable', 'l2tp-ses3:degraded', 'l2tp-ses4:degraded'])
1606 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1608 self
.assertRegex(output
, "Tunnel 10, encap IP")
1609 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1610 self
.assertRegex(output
, "Peer tunnel 12")
1612 output
= check_output('ip l2tp show session tid 10 session_id 25')
1614 self
.assertRegex(output
, "Session 25 in tunnel 10")
1615 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1616 self
.assertRegex(output
, "interface name: l2tp-ses3")
1618 output
= check_output('ip l2tp show session tid 10 session_id 27')
1620 self
.assertRegex(output
, "Session 27 in tunnel 10")
1621 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1622 self
.assertRegex(output
, "interface name: l2tp-ses4")
1624 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1639 '23-active-slave.network',
1640 '24-keep-configuration-static.network',
1641 '24-search-domain.network',
1642 '25-address-dad-veth-peer.network',
1643 '25-address-dad-veth99.network',
1644 '25-address-link-section.network',
1645 '25-address-preferred-lifetime-zero.network',
1646 '25-address-static.network',
1647 '25-bind-carrier.network',
1648 '25-bond-active-backup-slave.netdev',
1649 '25-fibrule-invert.network',
1650 '25-fibrule-port-range.network',
1651 '25-fibrule-uidrange.network',
1652 '25-gre-tunnel-remote-any.netdev',
1653 '25-ip6gre-tunnel-remote-any.netdev',
1654 '25-ipv6-address-label-section.network',
1655 '25-link-local-addressing-no.network',
1656 '25-link-local-addressing-yes.network',
1657 '25-link-section-unmanaged.network',
1658 '25-neighbor-section.network',
1659 '25-neighbor-next.network',
1660 '25-neighbor-ipv6.network',
1661 '25-neighbor-ip-dummy.network',
1662 '25-neighbor-ip.network',
1663 '25-nexthop.network',
1664 '25-qdisc-cake.network',
1665 '25-qdisc-clsact-and-htb.network',
1666 '25-qdisc-drr.network',
1667 '25-qdisc-hhf.network',
1668 '25-qdisc-ingress-netem-compat.network',
1669 '25-qdisc-pie.network',
1670 '25-route-ipv6-src.network',
1671 '25-route-static.network',
1672 '25-route-vrf.network',
1673 '25-gateway-static.network',
1674 '25-gateway-next-static.network',
1675 '25-sysctl-disable-ipv6.network',
1676 '25-sysctl.network',
1678 '25-veth-peer.network',
1681 '26-link-local-addressing-ipv6.network',
1682 'routing-policy-rule-dummy98.network',
1683 'routing-policy-rule-test1.network']
1685 routing_policy_rule_tables
= ['7', '8', '9']
1686 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1689 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1690 remove_routes(self
.routes
)
1691 remove_links(self
.links
)
1692 stop_networkd(show_logs
=False)
1695 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1696 remove_routes(self
.routes
)
1697 remove_links(self
.links
)
1698 remove_unit_from_networkd_path(self
.units
)
1699 stop_networkd(show_logs
=True)
1701 def test_address_static(self
):
1702 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1705 self
.wait_online(['dummy98:routable'])
1707 output
= check_output('ip -4 address show dev dummy98')
1709 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1710 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1711 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1714 self
.assertNotRegex(output
, '10.10.0.1/16')
1715 self
.assertNotRegex(output
, '10.10.0.2/16')
1717 output
= check_output('ip -4 address show dev dummy98 label 32')
1718 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1720 output
= check_output('ip -4 address show dev dummy98 label 33')
1721 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1723 output
= check_output('ip -4 address show dev dummy98 label 34')
1724 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1726 output
= check_output('ip -4 address show dev dummy98 label 35')
1727 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1729 output
= check_output('ip -6 address show dev dummy98')
1731 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1732 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1733 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1734 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1735 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1736 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1738 def test_address_preferred_lifetime_zero_ipv6(self
):
1739 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero.network', '12-dummy.netdev')
1742 self
.wait_online(['dummy98:routable'])
1744 output
= check_output('ip address show dummy98')
1746 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1747 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1749 output
= check_output('ip route show dev dummy98')
1751 self
.assertRegex(output
, 'default via 20.20.20.1 proto static')
1753 def test_address_dad(self
):
1754 copy_unit_to_networkd_unit_path('25-address-dad-veth99.network', '25-address-dad-veth-peer.network',
1757 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
1759 output
= check_output('ip -4 address show dev veth99')
1761 self
.assertRegex(output
, '192.168.100.10/24')
1763 output
= check_output('ip -4 address show dev veth-peer')
1765 self
.assertNotRegex(output
, '192.168.100.10/24')
1767 def test_configure_without_carrier(self
):
1768 copy_unit_to_networkd_unit_path('11-dummy.netdev')
1770 self
.wait_operstate('test1', 'off', '')
1771 check_output('ip link set dev test1 up carrier off')
1773 copy_unit_to_networkd_unit_path('25-test1.network.d/configure-without-carrier.conf', dropins
=False)
1775 self
.wait_online(['test1:no-carrier'])
1777 carrier_map
= {'on': '1', 'off': '0'}
1778 routable_map
= {'on': 'routable', 'off': 'no-carrier'}
1779 for carrier
in ['off', 'on', 'off']:
1780 with self
.subTest(carrier
=carrier
):
1781 if carrier_map
[carrier
] != read_link_attr('test1', 'carrier'):
1782 check_output(f
'ip link set dev test1 carrier {carrier}')
1783 self
.wait_online([f
'test1:{routable_map[carrier]}'])
1785 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
1787 self
.assertRegex(output
, '192.168.0.15')
1788 self
.assertRegex(output
, '192.168.0.1')
1789 self
.assertRegex(output
, routable_map
[carrier
])
1791 def test_configure_without_carrier_yes_ignore_carrier_loss_no(self
):
1792 copy_unit_to_networkd_unit_path('11-dummy.netdev')
1794 self
.wait_operstate('test1', 'off', '')
1795 check_output('ip link set dev test1 up carrier off')
1797 copy_unit_to_networkd_unit_path('25-test1.network')
1799 self
.wait_online(['test1:no-carrier'])
1801 carrier_map
= {'on': '1', 'off': '0'}
1802 routable_map
= {'on': 'routable', 'off': 'no-carrier'}
1803 for (carrier
, have_config
) in [('off', True), ('on', True), ('off', False)]:
1804 with self
.subTest(carrier
=carrier
, have_config
=have_config
):
1805 if carrier_map
[carrier
] != read_link_attr('test1', 'carrier'):
1806 check_output(f
'ip link set dev test1 carrier {carrier}')
1807 self
.wait_online([f
'test1:{routable_map[carrier]}'])
1809 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
1812 self
.assertRegex(output
, '192.168.0.15')
1813 self
.assertRegex(output
, '192.168.0.1')
1815 self
.assertNotRegex(output
, '192.168.0.15')
1816 self
.assertNotRegex(output
, '192.168.0.1')
1817 self
.assertRegex(output
, routable_map
[carrier
])
1819 def test_routing_policy_rule(self
):
1820 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1822 self
.wait_online(['test1:degraded'])
1824 output
= check_output('ip rule list iif test1 priority 111')
1826 self
.assertRegex(output
, '111:')
1827 self
.assertRegex(output
, 'from 192.168.100.18')
1828 self
.assertRegex(output
, r
'tos (0x08|throughput)\s')
1829 self
.assertRegex(output
, 'iif test1')
1830 self
.assertRegex(output
, 'oif test1')
1831 self
.assertRegex(output
, 'lookup 7')
1833 output
= check_output('ip rule list iif test1 priority 101')
1835 self
.assertRegex(output
, '101:')
1836 self
.assertRegex(output
, 'from all')
1837 self
.assertRegex(output
, 'iif test1')
1838 self
.assertRegex(output
, 'lookup 9')
1840 output
= check_output('ip -6 rule list iif test1 priority 100')
1842 self
.assertRegex(output
, '100:')
1843 self
.assertRegex(output
, 'from all')
1844 self
.assertRegex(output
, 'iif test1')
1845 self
.assertRegex(output
, 'lookup 8')
1847 output
= check_output('ip -6 rule list iif test1 priority 101')
1849 self
.assertRegex(output
, '101:')
1850 self
.assertRegex(output
, 'from all')
1851 self
.assertRegex(output
, 'iif test1')
1852 self
.assertRegex(output
, 'lookup 9')
1854 def test_routing_policy_rule_issue_11280(self
):
1855 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1856 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1858 for trial
in range(3):
1859 # Remove state files only first time
1861 self
.wait_online(['test1:degraded', 'dummy98:degraded'])
1864 output
= check_output('ip rule list table 7')
1866 self
.assertRegex(output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
1868 output
= check_output('ip rule list table 8')
1870 self
.assertRegex(output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1872 stop_networkd(remove_state_files
=False)
1874 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1875 def test_routing_policy_rule_port_range(self
):
1876 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1878 self
.wait_online(['test1:degraded'])
1880 output
= check_output('ip rule')
1882 self
.assertRegex(output
, '111')
1883 self
.assertRegex(output
, 'from 192.168.100.18')
1884 self
.assertRegex(output
, '1123-1150')
1885 self
.assertRegex(output
, '3224-3290')
1886 self
.assertRegex(output
, 'tcp')
1887 self
.assertRegex(output
, 'lookup 7')
1889 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1890 def test_routing_policy_rule_invert(self
):
1891 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1893 self
.wait_online(['test1:degraded'])
1895 output
= check_output('ip rule')
1897 self
.assertRegex(output
, '111')
1898 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
1899 self
.assertRegex(output
, 'tcp')
1900 self
.assertRegex(output
, 'lookup 7')
1902 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable()
1903 def test_routing_policy_rule_uidrange(self
):
1904 copy_unit_to_networkd_unit_path('25-fibrule-uidrange.network', '11-dummy.netdev')
1906 self
.wait_online(['test1:degraded'])
1908 output
= check_output('ip rule')
1910 self
.assertRegex(output
, '111')
1911 self
.assertRegex(output
, 'from 192.168.100.18')
1912 self
.assertRegex(output
, 'lookup 7')
1913 self
.assertRegex(output
, 'uidrange 100-200')
1915 def test_route_static(self
):
1916 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1918 self
.wait_online(['dummy98:routable'])
1920 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
1923 print('### ip -6 route show dev dummy98')
1924 output
= check_output('ip -6 route show dev dummy98')
1926 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1927 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
1929 print('### ip -6 route show dev dummy98 default')
1930 output
= check_output('ip -6 route show dev dummy98 default')
1932 self
.assertRegex(output
, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1934 print('### ip -4 route show dev dummy98')
1935 output
= check_output('ip -4 route show dev dummy98')
1937 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1938 self
.assertRegex(output
, '149.10.124.64 proto static scope link')
1939 self
.assertRegex(output
, '169.254.0.0/16 proto static scope link metric 2048')
1940 self
.assertRegex(output
, '192.168.1.1 proto static initcwnd 20')
1941 self
.assertRegex(output
, '192.168.1.2 proto static initrwnd 30')
1942 self
.assertRegex(output
, 'multicast 149.10.123.4 proto static')
1944 print('### ip -4 route show dev dummy98 default')
1945 output
= check_output('ip -4 route show dev dummy98 default')
1947 self
.assertRegex(output
, 'default via 149.10.125.65 proto static onlink')
1948 self
.assertRegex(output
, 'default via 149.10.124.64 proto static')
1949 self
.assertRegex(output
, 'default proto static')
1951 print('### ip -4 route show table local dev dummy98')
1952 output
= check_output('ip -4 route show table local dev dummy98')
1954 self
.assertRegex(output
, 'local 149.10.123.1 proto static scope host')
1955 self
.assertRegex(output
, 'anycast 149.10.123.2 proto static scope link')
1956 self
.assertRegex(output
, 'broadcast 149.10.123.3 proto static scope link')
1958 print('### ip route show type blackhole')
1959 output
= check_output('ip route show type blackhole')
1961 self
.assertRegex(output
, 'blackhole 202.54.1.2 proto static')
1963 print('### ip route show type unreachable')
1964 output
= check_output('ip route show type unreachable')
1966 self
.assertRegex(output
, 'unreachable 202.54.1.3 proto static')
1968 print('### ip route show type prohibit')
1969 output
= check_output('ip route show type prohibit')
1971 self
.assertRegex(output
, 'prohibit 202.54.1.4 proto static')
1973 print('### ip route show 192.168.10.1')
1974 output
= check_output('ip route show 192.168.10.1')
1976 self
.assertRegex(output
, '192.168.10.1 proto static')
1977 self
.assertRegex(output
, 'nexthop via 149.10.124.59 dev dummy98 weight 10')
1978 self
.assertRegex(output
, 'nexthop via 149.10.124.60 dev dummy98 weight 5')
1980 print('### ip route show 192.168.10.2')
1981 output
= check_output('ip route show 192.168.10.2')
1983 # old ip command does not show IPv6 gateways...
1984 self
.assertRegex(output
, '192.168.10.2 proto static')
1985 self
.assertRegex(output
, 'nexthop')
1986 self
.assertRegex(output
, 'dev dummy98 weight 10')
1987 self
.assertRegex(output
, 'dev dummy98 weight 5')
1989 print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
1990 output
= check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
1992 # old ip command does not show 'nexthop' keyword and weight...
1993 self
.assertRegex(output
, '2001:1234:5:7fff:ff:ff:ff:ff')
1994 self
.assertRegex(output
, 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98')
1995 self
.assertRegex(output
, 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98')
1997 @expectedFailureIfModuleIsNotAvailable('vrf')
1998 def test_route_vrf(self
):
1999 copy_unit_to_networkd_unit_path('25-route-vrf.network', '12-dummy.netdev',
2000 '25-vrf.netdev', '25-vrf.network')
2002 self
.wait_online(['dummy98:routable', 'vrf99:carrier'])
2004 output
= check_output('ip route show vrf vrf99')
2006 self
.assertRegex(output
, 'default via 192.168.100.1')
2008 output
= check_output('ip route show')
2010 self
.assertNotRegex(output
, 'default via 192.168.100.1')
2012 def test_gateway_reconfigure(self
):
2013 copy_unit_to_networkd_unit_path('25-gateway-static.network', '12-dummy.netdev')
2015 self
.wait_online(['dummy98:routable'])
2016 print('### ip -4 route show dev dummy98 default')
2017 output
= check_output('ip -4 route show dev dummy98 default')
2019 self
.assertRegex(output
, 'default via 149.10.124.59 proto static')
2020 self
.assertNotRegex(output
, '149.10.124.60')
2022 remove_unit_from_networkd_path(['25-gateway-static.network'])
2023 copy_unit_to_networkd_unit_path('25-gateway-next-static.network')
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
.assertNotRegex(output
, '149.10.124.59')
2030 self
.assertRegex(output
, 'default via 149.10.124.60 proto static')
2032 def test_ip_route_ipv6_src_route(self
):
2033 # a dummy device does not make the addresses go through tentative state, so we
2034 # reuse a bond from an earlier test, which does make the addresses go through
2035 # tentative state, and do our test on that
2036 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2038 self
.wait_online(['dummy98:enslaved', 'bond199:routable'])
2040 output
= check_output('ip -6 route list dev bond199')
2042 self
.assertRegex(output
, 'abcd::/16')
2043 self
.assertRegex(output
, 'src')
2044 self
.assertRegex(output
, '2001:1234:56:8f63::2')
2046 def test_ip_link_mac_address(self
):
2047 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
2049 self
.wait_online(['dummy98:degraded'])
2051 output
= check_output('ip link show dummy98')
2053 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
2055 def test_ip_link_unmanaged(self
):
2056 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
2059 self
.check_link_exists('dummy98')
2061 self
.wait_operstate('dummy98', 'off', setup_state
='unmanaged')
2063 def test_ipv6_address_label(self
):
2064 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
2066 self
.wait_online(['dummy98:degraded'])
2068 output
= check_output('ip addrlabel list')
2070 self
.assertRegex(output
, '2004:da8:1::/64')
2072 def test_neighbor_section(self
):
2073 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2075 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2077 print('### ip neigh list dev dummy98')
2078 output
= check_output('ip neigh list dev dummy98')
2080 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2081 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2083 def test_neighbor_reconfigure(self
):
2084 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2086 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2088 print('### ip neigh list dev dummy98')
2089 output
= check_output('ip neigh list dev dummy98')
2091 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2092 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2094 remove_unit_from_networkd_path(['25-neighbor-section.network'])
2095 copy_unit_to_networkd_unit_path('25-neighbor-next.network')
2097 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
.assertNotRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2102 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT')
2103 self
.assertNotRegex(output
, '2004:da8:1::1.*PERMANENT')
2105 def test_neighbor_gre(self
):
2106 copy_unit_to_networkd_unit_path('25-neighbor-ip.network', '25-neighbor-ipv6.network', '25-neighbor-ip-dummy.network',
2107 '12-dummy.netdev', '25-gre-tunnel-remote-any.netdev', '25-ip6gre-tunnel-remote-any.netdev')
2109 self
.wait_online(['dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable'], timeout
='40s')
2111 output
= check_output('ip neigh list dev gretun97')
2113 self
.assertRegex(output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT')
2115 output
= check_output('ip neigh list dev ip6gretun97')
2117 self
.assertRegex(output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
2119 def test_link_local_addressing(self
):
2120 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
2121 '25-link-local-addressing-no.network', '12-dummy.netdev')
2123 self
.wait_online(['test1:degraded', 'dummy98:carrier'])
2125 output
= check_output('ip address show dev test1')
2127 self
.assertRegex(output
, 'inet .* scope link')
2128 self
.assertRegex(output
, 'inet6 .* scope link')
2130 output
= check_output('ip address show dev dummy98')
2132 self
.assertNotRegex(output
, 'inet6* .* scope link')
2135 Documentation/networking/ip-sysctl.txt
2137 addr_gen_mode - INTEGER
2138 Defines how link-local and autoconf addresses are generated.
2140 0: generate address based on EUI64 (default)
2141 1: do no generate a link-local address, use EUI64 for addresses generated
2143 2: generate stable privacy addresses, using the secret from
2144 stable_secret (RFC7217)
2145 3: generate stable privacy addresses, using a random secret if unset
2148 test1_addr_gen_mode
= ''
2149 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
2150 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
2154 # if stable_secret is unset, then EIO is returned
2155 test1_addr_gen_mode
= '0'
2157 test1_addr_gen_mode
= '2'
2159 test1_addr_gen_mode
= '0'
2161 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
2162 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
2164 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
2165 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
2167 def test_link_local_addressing_remove_ipv6ll(self
):
2168 copy_unit_to_networkd_unit_path('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
2170 self
.wait_online(['dummy98:degraded'])
2172 output
= check_output('ip address show dev dummy98')
2174 self
.assertRegex(output
, 'inet6 .* scope link')
2176 copy_unit_to_networkd_unit_path('25-link-local-addressing-no.network')
2178 self
.wait_online(['dummy98:carrier'])
2180 output
= check_output('ip address show dev dummy98')
2182 self
.assertNotRegex(output
, 'inet6* .* scope link')
2184 def test_sysctl(self
):
2185 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
2187 self
.wait_online(['dummy98:degraded'])
2189 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
2190 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
2191 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
2192 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
2193 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
2194 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
2195 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
2197 def test_sysctl_disable_ipv6(self
):
2198 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
2200 print('## Disable ipv6')
2201 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
2202 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
2205 self
.wait_online(['dummy98:routable'])
2207 output
= check_output('ip -4 address show dummy98')
2209 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2210 output
= check_output('ip -6 address show dummy98')
2212 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2213 self
.assertRegex(output
, 'inet6 .* scope link')
2214 output
= check_output('ip -4 route show dev dummy98')
2216 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2217 output
= check_output('ip -6 route show dev dummy98')
2219 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2221 check_output('ip link del dummy98')
2223 print('## Enable ipv6')
2224 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
2225 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
2228 self
.wait_online(['dummy98:routable'])
2230 output
= check_output('ip -4 address show dummy98')
2232 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2233 output
= check_output('ip -6 address show dummy98')
2235 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2236 self
.assertRegex(output
, 'inet6 .* scope link')
2237 output
= check_output('ip -4 route show dev dummy98')
2239 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2240 output
= check_output('ip -6 route show dev dummy98')
2242 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2244 def test_bind_carrier(self
):
2245 check_output('ip link add dummy98 type dummy')
2246 check_output('ip link set dummy98 up')
2249 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
2251 self
.wait_online(['test1:routable'])
2253 output
= check_output('ip address show test1')
2255 self
.assertRegex(output
, 'UP,LOWER_UP')
2256 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2257 self
.wait_operstate('test1', 'routable')
2259 check_output('ip link add dummy99 type dummy')
2260 check_output('ip link set dummy99 up')
2262 output
= check_output('ip address show test1')
2264 self
.assertRegex(output
, 'UP,LOWER_UP')
2265 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2266 self
.wait_operstate('test1', 'routable')
2268 check_output('ip link del dummy98')
2270 output
= check_output('ip address show test1')
2272 self
.assertRegex(output
, 'UP,LOWER_UP')
2273 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2274 self
.wait_operstate('test1', 'routable')
2276 check_output('ip link set dummy99 down')
2278 output
= check_output('ip address show test1')
2280 self
.assertNotRegex(output
, 'UP,LOWER_UP')
2281 self
.assertRegex(output
, 'DOWN')
2282 self
.assertNotRegex(output
, '192.168.10')
2283 self
.wait_operstate('test1', 'off')
2285 check_output('ip link set dummy99 up')
2287 output
= check_output('ip address show test1')
2289 self
.assertRegex(output
, 'UP,LOWER_UP')
2290 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2291 self
.wait_operstate('test1', 'routable')
2293 def test_domain(self
):
2294 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
2296 self
.wait_online(['dummy98:routable'])
2298 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2300 self
.assertRegex(output
, 'Address: 192.168.42.100')
2301 self
.assertRegex(output
, 'DNS: 192.168.42.1')
2302 self
.assertRegex(output
, 'Search Domains: one')
2304 def test_keep_configuration_static(self
):
2305 check_output('systemctl stop systemd-networkd')
2307 check_output('ip link add name dummy98 type dummy')
2308 check_output('ip address add 10.1.2.3/16 dev dummy98')
2309 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
2310 output
= check_output('ip address show dummy98')
2312 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2313 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2314 output
= check_output('ip route show dev dummy98')
2317 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
2319 self
.wait_online(['dummy98:routable'])
2321 output
= check_output('ip address show dummy98')
2323 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2324 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2326 @expectedFailureIfNexthopIsNotAvailable()
2327 def test_nexthop(self
):
2328 copy_unit_to_networkd_unit_path('25-nexthop.network', '25-veth.netdev', '25-veth-peer.network')
2330 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2332 output
= check_output('ip nexthop list dev veth99')
2334 self
.assertRegex(output
, '192.168.5.1')
2336 def test_qdisc(self
):
2337 copy_unit_to_networkd_unit_path('25-qdisc-clsact-and-htb.network', '12-dummy.netdev',
2338 '25-qdisc-ingress-netem-compat.network', '11-dummy.netdev')
2339 check_output('modprobe sch_teql max_equalizers=2')
2342 self
.wait_online(['dummy98:routable', 'test1:routable'])
2344 output
= check_output('tc qdisc show dev test1')
2346 self
.assertRegex(output
, 'qdisc netem')
2347 self
.assertRegex(output
, 'limit 100 delay 50.0ms 10.0ms loss 20%')
2348 self
.assertRegex(output
, 'qdisc ingress')
2350 output
= check_output('tc qdisc show dev dummy98')
2352 self
.assertRegex(output
, 'qdisc clsact')
2354 self
.assertRegex(output
, 'qdisc htb 2: root')
2355 self
.assertRegex(output
, r
'default (0x30|30)')
2357 self
.assertRegex(output
, 'qdisc netem 30: parent 2:30')
2358 self
.assertRegex(output
, 'limit 100 delay 50.0ms 10.0ms loss 20%')
2359 self
.assertRegex(output
, 'qdisc fq_codel')
2360 self
.assertRegex(output
, 'limit 20480p flows 2048 quantum 1400 target 10.0ms ce_threshold 100.0ms interval 200.0ms memory_limit 64Mb ecn')
2362 self
.assertRegex(output
, 'qdisc teql1 31: parent 2:31')
2364 self
.assertRegex(output
, 'qdisc fq 32: parent 2:32')
2365 self
.assertRegex(output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
2366 self
.assertRegex(output
, 'quantum 1500')
2367 self
.assertRegex(output
, 'initial_quantum 13000')
2368 self
.assertRegex(output
, 'maxrate 1Mbit')
2370 self
.assertRegex(output
, 'qdisc codel 33: parent 2:33')
2371 self
.assertRegex(output
, 'limit 2000p target 10.0ms ce_threshold 100.0ms interval 50.0ms ecn')
2373 self
.assertRegex(output
, 'qdisc fq_codel 34: parent 2:34')
2374 self
.assertRegex(output
, 'limit 20480p flows 2048 quantum 1400 target 10.0ms ce_threshold 100.0ms interval 200.0ms memory_limit 64Mb ecn')
2376 self
.assertRegex(output
, 'qdisc tbf 35: parent 2:35')
2377 self
.assertRegex(output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70.0ms')
2379 self
.assertRegex(output
, 'qdisc sfq 36: parent 2:36')
2380 self
.assertRegex(output
, 'perturb 5sec')
2382 self
.assertRegex(output
, 'qdisc pfifo 37: parent 2:37')
2383 self
.assertRegex(output
, 'limit 100000p')
2385 self
.assertRegex(output
, 'qdisc gred 38: parent 2:38')
2386 self
.assertRegex(output
, 'vqs 12 default 10 grio')
2388 self
.assertRegex(output
, 'qdisc sfb 39: parent 2:39')
2389 self
.assertRegex(output
, 'limit 200000')
2391 self
.assertRegex(output
, 'qdisc bfifo 3a: parent 2:3a')
2392 self
.assertRegex(output
, 'limit 1000000')
2394 self
.assertRegex(output
, 'qdisc pfifo_head_drop 3b: parent 2:3b')
2395 self
.assertRegex(output
, 'limit 1023p')
2397 self
.assertRegex(output
, 'qdisc pfifo_fast 3c: parent 2:3c')
2399 output
= check_output('tc class show dev dummy98')
2401 self
.assertRegex(output
, 'class htb 2:30 root leaf 30:')
2402 self
.assertRegex(output
, 'class htb 2:31 root leaf 31:')
2403 self
.assertRegex(output
, 'class htb 2:32 root leaf 32:')
2404 self
.assertRegex(output
, 'class htb 2:33 root leaf 33:')
2405 self
.assertRegex(output
, 'class htb 2:34 root leaf 34:')
2406 self
.assertRegex(output
, 'class htb 2:35 root leaf 35:')
2407 self
.assertRegex(output
, 'class htb 2:36 root leaf 36:')
2408 self
.assertRegex(output
, 'class htb 2:37 root leaf 37:')
2409 self
.assertRegex(output
, 'class htb 2:38 root leaf 38:')
2410 self
.assertRegex(output
, 'class htb 2:39 root leaf 39:')
2411 self
.assertRegex(output
, 'class htb 2:3a root leaf 3a:')
2412 self
.assertRegex(output
, 'class htb 2:3b root leaf 3b:')
2413 self
.assertRegex(output
, 'class htb 2:3c root leaf 3c:')
2414 self
.assertRegex(output
, 'prio 1 rate 1Mbit ceil 500Kbit')
2416 def test_qdisc2(self
):
2417 copy_unit_to_networkd_unit_path('25-qdisc-drr.network', '12-dummy.netdev')
2420 self
.wait_online(['dummy98:routable'])
2422 output
= check_output('tc qdisc show dev dummy98')
2424 self
.assertRegex(output
, 'qdisc drr 2: root')
2425 output
= check_output('tc class show dev dummy98')
2427 self
.assertRegex(output
, 'class drr 2:30 root quantum 2000b')
2429 @expectedFailureIfCAKEIsNotAvailable()
2430 def test_qdisc_cake(self
):
2431 copy_unit_to_networkd_unit_path('25-qdisc-cake.network', '12-dummy.netdev')
2433 self
.wait_online(['dummy98:routable'])
2435 output
= check_output('tc qdisc show dev dummy98')
2437 self
.assertRegex(output
, 'qdisc cake 3a: root')
2438 self
.assertRegex(output
, 'bandwidth 500Mbit')
2439 self
.assertRegex(output
, 'overhead 128')
2441 @expectedFailureIfPIEIsNotAvailable()
2442 def test_qdisc_pie(self
):
2443 copy_unit_to_networkd_unit_path('25-qdisc-pie.network', '12-dummy.netdev')
2445 self
.wait_online(['dummy98:routable'])
2447 output
= check_output('tc qdisc show dev dummy98')
2449 self
.assertRegex(output
, 'qdisc pie 3a: root')
2450 self
.assertRegex(output
, 'limit 200000')
2452 @expectedFailureIfHHFIsNotAvailable()
2453 def test_qdisc_hhf(self
):
2454 copy_unit_to_networkd_unit_path('25-qdisc-hhf.network', '12-dummy.netdev')
2456 self
.wait_online(['dummy98:routable'])
2458 output
= check_output('tc qdisc show dev dummy98')
2460 self
.assertRegex(output
, 'qdisc hhf 3a: root')
2461 self
.assertRegex(output
, 'limit 1022p')
2463 class NetworkdStateFileTests(unittest
.TestCase
, Utilities
):
2470 'state-file-tests.network',
2474 remove_links(self
.links
)
2475 stop_networkd(show_logs
=False)
2478 remove_links(self
.links
)
2479 remove_unit_from_networkd_path(self
.units
)
2480 stop_networkd(show_logs
=True)
2482 def test_state_file(self
):
2483 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'state-file-tests.network')
2485 self
.wait_online(['dummy98:routable'])
2487 output
= check_output(*networkctl_cmd
, '--no-legend', 'list', 'dummy98', env
=env
)
2489 ifindex
= output
.split()[0]
2491 path
= os
.path
.join('/run/systemd/netif/links/', ifindex
)
2492 self
.assertTrue(os
.path
.exists(path
))
2495 with
open(path
) as f
:
2497 self
.assertRegex(data
, r
'ADMIN_STATE=configured')
2498 self
.assertRegex(data
, r
'OPER_STATE=routable')
2499 self
.assertRegex(data
, r
'REQUIRED_FOR_ONLINE=yes')
2500 self
.assertRegex(data
, r
'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
2501 self
.assertRegex(data
, r
'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
2502 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
2503 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2504 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2505 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2506 self
.assertRegex(data
, r
'LLMNR=no')
2507 self
.assertRegex(data
, r
'MDNS=yes')
2508 self
.assertRegex(data
, r
'DNSSEC=no')
2509 self
.assertRegex(data
, r
'ADDRESSES=192.168.(10.10|12.12)/24 192.168.(12.12|10.10)/24')
2511 check_output(*resolvectl_cmd
, 'dns', 'dummy98', '10.10.10.12', '10.10.10.13', env
=env
)
2512 check_output(*resolvectl_cmd
, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env
=env
)
2513 check_output(*resolvectl_cmd
, 'llmnr', 'dummy98', 'yes', env
=env
)
2514 check_output(*resolvectl_cmd
, 'mdns', 'dummy98', 'no', env
=env
)
2515 check_output(*resolvectl_cmd
, 'dnssec', 'dummy98', 'yes', env
=env
)
2516 check_output(*timedatectl_cmd
, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env
=env
)
2519 with
open(path
) as f
:
2521 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
2522 self
.assertRegex(data
, r
'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org')
2523 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2524 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2525 self
.assertRegex(data
, r
'LLMNR=yes')
2526 self
.assertRegex(data
, r
'MDNS=no')
2527 self
.assertRegex(data
, r
'DNSSEC=yes')
2529 check_output(*timedatectl_cmd
, 'revert', 'dummy98', env
=env
)
2532 with
open(path
) as f
:
2534 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
2535 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2536 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2537 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2538 self
.assertRegex(data
, r
'LLMNR=yes')
2539 self
.assertRegex(data
, r
'MDNS=no')
2540 self
.assertRegex(data
, r
'DNSSEC=yes')
2542 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
2545 with
open(path
) as f
:
2547 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
2548 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2549 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2550 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2551 self
.assertRegex(data
, r
'LLMNR=no')
2552 self
.assertRegex(data
, r
'MDNS=yes')
2553 self
.assertRegex(data
, r
'DNSSEC=no')
2555 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
2565 '23-active-slave.network',
2566 '23-bond199.network',
2567 '23-primary-slave.network',
2568 '25-bond-active-backup-slave.netdev',
2571 'bond-slave.network']
2574 remove_links(self
.links
)
2575 stop_networkd(show_logs
=False)
2578 remove_links(self
.links
)
2579 remove_unit_from_networkd_path(self
.units
)
2580 stop_networkd(show_logs
=True)
2582 def test_bond_active_slave(self
):
2583 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2585 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2587 output
= check_output('ip -d link show bond199')
2589 self
.assertRegex(output
, 'active_slave dummy98')
2591 def test_bond_primary_slave(self
):
2592 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2594 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2596 output
= check_output('ip -d link show bond199')
2598 self
.assertRegex(output
, 'primary dummy98')
2600 def test_bond_operstate(self
):
2601 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
2602 'bond99.network','bond-slave.network')
2604 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
2606 output
= check_output('ip -d link show dummy98')
2608 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2610 output
= check_output('ip -d link show test1')
2612 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2614 output
= check_output('ip -d link show bond99')
2616 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
2618 self
.wait_operstate('dummy98', 'enslaved')
2619 self
.wait_operstate('test1', 'enslaved')
2620 self
.wait_operstate('bond99', 'routable')
2622 check_output('ip link set dummy98 down')
2624 self
.wait_operstate('dummy98', 'off')
2625 self
.wait_operstate('test1', 'enslaved')
2626 self
.wait_operstate('bond99', 'degraded-carrier')
2628 check_output('ip link set dummy98 up')
2630 self
.wait_operstate('dummy98', 'enslaved')
2631 self
.wait_operstate('test1', 'enslaved')
2632 self
.wait_operstate('bond99', 'routable')
2634 check_output('ip link set dummy98 down')
2635 check_output('ip link set test1 down')
2637 self
.wait_operstate('dummy98', 'off')
2638 self
.wait_operstate('test1', 'off')
2640 if not self
.wait_operstate('bond99', 'no-carrier', setup_timeout
=30, fail_assert
=False):
2641 # Huh? Kernel does not recognize that all slave interfaces are down?
2642 # Let's confirm that networkd's operstate is consistent with ip's result.
2643 self
.assertNotRegex(output
, 'NO-CARRIER')
2645 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
2655 '26-bridge-configure-without-carrier.network',
2656 '26-bridge-slave-interface-1.network',
2657 '26-bridge-slave-interface-2.network',
2658 '26-bridge-vlan-master.network',
2659 '26-bridge-vlan-slave.network',
2660 'bridge99-ignore-carrier-loss.network',
2663 routing_policy_rule_tables
= ['100']
2666 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2667 remove_links(self
.links
)
2668 stop_networkd(show_logs
=False)
2671 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2672 remove_links(self
.links
)
2673 remove_unit_from_networkd_path(self
.units
)
2674 stop_networkd(show_logs
=True)
2676 def test_bridge_vlan(self
):
2677 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
2678 '26-bridge.netdev', '26-bridge-vlan-master.network')
2680 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
2682 output
= check_output('bridge vlan show dev test1')
2684 self
.assertNotRegex(output
, '4063')
2685 for i
in range(4064, 4095):
2686 self
.assertRegex(output
, f
'{i}')
2687 self
.assertNotRegex(output
, '4095')
2689 output
= check_output('bridge vlan show dev bridge99')
2691 self
.assertNotRegex(output
, '4059')
2692 for i
in range(4060, 4095):
2693 self
.assertRegex(output
, f
'{i}')
2694 self
.assertNotRegex(output
, '4095')
2696 def test_bridge_property(self
):
2697 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2698 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2701 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2703 output
= check_output('ip -d link show test1')
2705 self
.assertRegex(output
, 'master')
2706 self
.assertRegex(output
, 'bridge')
2708 output
= check_output('ip -d link show dummy98')
2710 self
.assertRegex(output
, 'master')
2711 self
.assertRegex(output
, 'bridge')
2713 output
= check_output('ip addr show bridge99')
2715 self
.assertRegex(output
, '192.168.0.15/24')
2717 output
= check_output('bridge -d link show dummy98')
2719 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
2720 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
2721 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
2722 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
2723 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
2724 # CONFIG_BRIDGE_IGMP_SNOOPING=y
2725 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
2726 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
2727 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
2728 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
2729 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
2730 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'priority'), '23')
2731 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard'), '1')
2732 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'root_block'), '1')
2734 output
= check_output('bridge -d link show test1')
2736 self
.assertEqual(read_bridge_port_attr('bridge99', 'test1', 'priority'), '0')
2738 check_output('ip address add 192.168.0.16/24 dev bridge99')
2741 output
= check_output('ip addr show bridge99')
2743 self
.assertRegex(output
, '192.168.0.16/24')
2746 print('### ip -6 route list table all dev bridge99')
2747 output
= check_output('ip -6 route list table all dev bridge99')
2749 self
.assertRegex(output
, 'ff00::/8 table local metric 256 pref medium')
2751 self
.assertEqual(call('ip link del test1'), 0)
2753 self
.wait_operstate('bridge99', 'degraded-carrier')
2755 check_output('ip link del dummy98')
2757 self
.wait_operstate('bridge99', 'no-carrier')
2759 output
= check_output('ip address show bridge99')
2761 self
.assertRegex(output
, 'NO-CARRIER')
2762 self
.assertNotRegex(output
, '192.168.0.15/24')
2763 self
.assertNotRegex(output
, '192.168.0.16/24')
2765 print('### ip -6 route list table all dev bridge99')
2766 output
= check_output('ip -6 route list table all dev bridge99')
2768 self
.assertRegex(output
, 'ff00::/8 table local metric 256 (linkdown )?pref medium')
2770 def test_bridge_configure_without_carrier(self
):
2771 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-configure-without-carrier.network',
2775 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
2776 for test
in ['no-slave', 'add-slave', 'slave-up', 'slave-no-carrier', 'slave-carrier', 'slave-down']:
2777 with self
.subTest(test
=test
):
2778 if test
== 'no-slave':
2779 # bridge has no slaves; it's up but *might* not have carrier
2780 self
.wait_online(['bridge99:no-carrier'])
2781 # due to a bug in the kernel, newly-created bridges are brought up
2782 # *with* carrier, unless they have had any setting changed; e.g.
2783 # their mac set, priority set, etc. Then, they will lose carrier
2784 # as soon as a (down) slave interface is added, and regain carrier
2785 # again once the slave interface is brought up.
2786 #self.check_link_attr('bridge99', 'carrier', '0')
2787 elif test
== 'add-slave':
2788 # add slave to bridge, but leave it down; bridge is definitely no-carrier
2789 self
.check_link_attr('test1', 'operstate', 'down')
2790 check_output('ip link set dev test1 master bridge99')
2791 self
.wait_online(['bridge99:no-carrier:no-carrier'])
2792 self
.check_link_attr('bridge99', 'carrier', '0')
2793 elif test
== 'slave-up':
2794 # bring up slave, which will have carrier; bridge gains carrier
2795 check_output('ip link set dev test1 up')
2796 self
.wait_online(['bridge99:routable'])
2797 self
.check_link_attr('bridge99', 'carrier', '1')
2798 elif test
== 'slave-no-carrier':
2799 # drop slave carrier; bridge loses carrier
2800 check_output('ip link set dev test1 carrier off')
2801 self
.wait_online(['bridge99:no-carrier:no-carrier'])
2802 self
.check_link_attr('bridge99', 'carrier', '0')
2803 elif test
== 'slave-carrier':
2804 # restore slave carrier; bridge gains carrier
2805 check_output('ip link set dev test1 carrier on')
2806 self
.wait_online(['bridge99:routable'])
2807 self
.check_link_attr('bridge99', 'carrier', '1')
2808 elif test
== 'slave-down':
2809 # bring down slave; bridge loses carrier
2810 check_output('ip link set dev test1 down')
2811 self
.wait_online(['bridge99:no-carrier:no-carrier'])
2812 self
.check_link_attr('bridge99', 'carrier', '0')
2814 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
2816 self
.assertRegex(output
, '10.1.2.3')
2817 self
.assertRegex(output
, '10.1.2.1')
2819 def test_bridge_ignore_carrier_loss(self
):
2820 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2821 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2822 'bridge99-ignore-carrier-loss.network')
2824 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2826 check_output('ip address add 192.168.0.16/24 dev bridge99')
2829 check_output('ip link del test1')
2830 check_output('ip link del dummy98')
2833 output
= check_output('ip address show bridge99')
2835 self
.assertRegex(output
, 'NO-CARRIER')
2836 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2837 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
2839 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
2840 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
2841 'bridge99-ignore-carrier-loss.network')
2843 self
.wait_online(['bridge99:no-carrier'])
2845 for trial
in range(4):
2846 check_output('ip link add dummy98 type dummy')
2847 check_output('ip link set dummy98 up')
2849 check_output('ip link del dummy98')
2851 self
.wait_online(['bridge99:routable', 'dummy98:enslaved'])
2853 output
= check_output('ip address show bridge99')
2855 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2857 output
= check_output('ip rule list table 100')
2859 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
2861 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
2865 '23-emit-lldp.network',
2870 remove_links(self
.links
)
2871 stop_networkd(show_logs
=False)
2874 remove_links(self
.links
)
2875 remove_unit_from_networkd_path(self
.units
)
2876 stop_networkd(show_logs
=True)
2878 def test_lldp(self
):
2879 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
2881 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
2883 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
2885 self
.assertRegex(output
, 'veth-peer')
2886 self
.assertRegex(output
, 'veth99')
2888 class NetworkdRATests(unittest
.TestCase
, Utilities
):
2893 'ipv6-prefix.network',
2894 'ipv6-prefix-veth.network',
2895 'ipv6-prefix-veth-token-static.network',
2896 'ipv6-prefix-veth-token-static-explicit.network',
2897 'ipv6-prefix-veth-token-static-multiple.network',
2898 'ipv6-prefix-veth-token-prefixstable.network']
2901 remove_links(self
.links
)
2902 stop_networkd(show_logs
=False)
2905 remove_links(self
.links
)
2906 remove_unit_from_networkd_path(self
.units
)
2907 stop_networkd(show_logs
=True)
2909 def test_ipv6_prefix_delegation(self
):
2910 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
2912 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2914 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
2916 self
.assertRegex(output
, 'fe80::')
2917 self
.assertRegex(output
, '2002:da8:1::1')
2919 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2921 self
.assertRegex(output
, '2002:da8:1:0')
2923 def test_ipv6_token_static(self
):
2924 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static.network')
2926 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2928 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2930 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
2932 def test_ipv6_token_static_explicit(self
):
2933 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static-explicit.network')
2935 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2937 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2939 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
2941 def test_ipv6_token_static_multiple(self
):
2942 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static-multiple.network')
2944 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2946 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2948 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
2949 self
.assertRegex(output
, '2002:da8:1:0:fa:de:ca:fe')
2951 def test_ipv6_token_prefixstable(self
):
2952 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable.network')
2954 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2956 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2958 self
.assertRegex(output
, '2002:da8:1:0')
2960 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
2965 'dhcp-client.network',
2966 'dhcp-client-timezone-router.network',
2967 'dhcp-server.network',
2968 'dhcp-server-timezone-router.network']
2971 remove_links(self
.links
)
2972 stop_networkd(show_logs
=False)
2975 remove_links(self
.links
)
2976 remove_unit_from_networkd_path(self
.units
)
2977 stop_networkd(show_logs
=True)
2979 def test_dhcp_server(self
):
2980 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
2982 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2984 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2986 self
.assertRegex(output
, '192.168.5.*')
2987 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
2988 self
.assertRegex(output
, 'DNS: 192.168.5.1')
2989 self
.assertRegex(output
, 'NTP: 192.168.5.1')
2991 def test_emit_router_timezone(self
):
2992 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
2994 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2996 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2998 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
2999 self
.assertRegex(output
, '192.168.5.*')
3000 self
.assertRegex(output
, 'Europe/Berlin')
3002 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
3011 'dhcp-client-anonymize.network',
3012 'dhcp-client-decline.network',
3013 'dhcp-client-gateway-ipv4.network',
3014 'dhcp-client-gateway-ipv6.network',
3015 'dhcp-client-gateway-onlink-implicit.network',
3016 'dhcp-client-ipv4-dhcp-settings.network',
3017 'dhcp-client-ipv4-only-ipv6-disabled.network',
3018 'dhcp-client-ipv4-only.network',
3019 'dhcp-client-ipv4-use-routes-use-gateway.network',
3020 'dhcp-client-ipv6-only.network',
3021 'dhcp-client-ipv6-rapid-commit.network',
3022 'dhcp-client-keep-configuration-dhcp-on-stop.network',
3023 'dhcp-client-keep-configuration-dhcp.network',
3024 'dhcp-client-listen-port.network',
3025 'dhcp-client-reassign-static-routes-ipv4.network',
3026 'dhcp-client-reassign-static-routes-ipv6.network',
3027 'dhcp-client-route-metric.network',
3028 'dhcp-client-route-table.network',
3029 'dhcp-client-use-dns-ipv4-and-ra.network',
3030 'dhcp-client-use-dns-ipv4.network',
3031 'dhcp-client-use-dns-no.network',
3032 'dhcp-client-use-dns-yes.network',
3033 'dhcp-client-use-domains.network',
3034 'dhcp-client-vrf.network',
3035 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
3036 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
3037 'dhcp-client-with-static-address.network',
3038 'dhcp-client.network',
3039 'dhcp-server-decline.network',
3040 'dhcp-server-veth-peer.network',
3041 'dhcp-v4-server-veth-peer.network',
3045 stop_dnsmasq(dnsmasq_pid_file
)
3046 remove_links(self
.links
)
3047 stop_networkd(show_logs
=False)
3050 stop_dnsmasq(dnsmasq_pid_file
)
3053 remove_links(self
.links
)
3054 remove_unit_from_networkd_path(self
.units
)
3055 stop_networkd(show_logs
=True)
3057 def test_dhcp_client_ipv6_only(self
):
3058 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3061 self
.wait_online(['veth-peer:carrier'])
3063 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3065 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3067 self
.assertRegex(output
, '2600::')
3068 self
.assertNotRegex(output
, '192.168.5')
3070 # Confirm that ipv6 token is not set in the kernel
3071 output
= check_output('ip token show dev veth99')
3073 self
.assertRegex(output
, 'token :: dev veth99')
3075 def test_dhcp_client_ipv4_only(self
):
3076 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
3079 self
.wait_online(['veth-peer:carrier'])
3080 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
3081 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3083 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3085 self
.assertNotRegex(output
, '2600::')
3086 self
.assertRegex(output
, '192.168.5')
3087 self
.assertRegex(output
, '192.168.5.6')
3088 self
.assertRegex(output
, '192.168.5.7')
3090 # checking routes to DNS servers
3091 output
= check_output('ip route show dev veth99')
3093 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3094 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3095 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3097 stop_dnsmasq(dnsmasq_pid_file
)
3098 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8', lease_time
='2m')
3100 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3101 print('Wait for the dynamic address to be renewed')
3104 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3106 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3108 self
.assertNotRegex(output
, '2600::')
3109 self
.assertRegex(output
, '192.168.5')
3110 self
.assertNotRegex(output
, '192.168.5.6')
3111 self
.assertRegex(output
, '192.168.5.7')
3112 self
.assertRegex(output
, '192.168.5.8')
3114 # checking routes to DNS servers
3115 output
= check_output('ip route show dev veth99')
3117 self
.assertNotRegex(output
, r
'192.168.5.6')
3118 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3119 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3120 self
.assertRegex(output
, r
'192.168.5.8 proto dhcp scope link src 192.168.5.181 metric 1024')
3122 def test_dhcp_client_ipv4_use_routes_gateway(self
):
3123 for (routes
, gateway
, dnsroutes
) in itertools
.product([True, False, None], repeat
=3):
3125 with self
.subTest(routes
=routes
, gateway
=gateway
, dnsroutes
=dnsroutes
):
3126 self
._test
_dhcp
_client
_ipv
4_use
_routes
_gateway
(routes
, gateway
, dnsroutes
)
3129 def _test_dhcp_client_ipv4_use_routes_gateway(self
, routes
, gateway
, dnsroutes
):
3130 testunit
= 'dhcp-client-ipv4-use-routes-use-gateway.network'
3131 testunits
= ['25-veth.netdev', 'dhcp-server-veth-peer.network', testunit
]
3133 testunits
.append(f
'{testunit}.d/use-routes-{routes}.conf');
3135 testunits
.append(f
'{testunit}.d/use-gateway-{gateway}.conf');
3136 if dnsroutes
!= None:
3137 testunits
.append(f
'{testunit}.d/use-dns-routes-{dnsroutes}.conf');
3138 copy_unit_to_networkd_unit_path(*testunits
, dropins
=False)
3141 self
.wait_online(['veth-peer:carrier'])
3142 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
3143 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3145 output
= check_output('ip route show dev veth99')
3148 # UseRoutes= defaults to true
3149 useroutes
= routes
in [True, None]
3150 # UseGateway= defaults to useroutes
3151 usegateway
= useroutes
if gateway
== None else gateway
3155 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.181 metric 1024')
3157 self
.assertNotRegex(output
, r
'192.168.5.5')
3161 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.181 metric 1024')
3163 self
.assertNotRegex(output
, r
'default via 192.168.5.1')
3165 # Check RoutesToDNS=, which defaults to false
3167 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3168 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3170 self
.assertNotRegex(output
, r
'192.168.5.6')
3171 self
.assertNotRegex(output
, r
'192.168.5.7')
3173 def test_dhcp_client_ipv4_ipv6(self
):
3174 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
3175 'dhcp-client-ipv4-only.network')
3177 self
.wait_online(['veth-peer:carrier'])
3179 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3181 # link become 'routable' when at least one protocol provide an valid address.
3182 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3183 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3185 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3187 self
.assertRegex(output
, '2600::')
3188 self
.assertRegex(output
, '192.168.5')
3190 def test_dhcp_client_settings(self
):
3191 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
3194 self
.wait_online(['veth-peer:carrier'])
3196 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3198 print('## ip address show dev veth99')
3199 output
= check_output('ip address show dev veth99')
3201 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3202 self
.assertRegex(output
, '192.168.5')
3203 self
.assertRegex(output
, '1492')
3205 print('## ip route show table main dev veth99')
3206 output
= check_output('ip route show table main dev veth99')
3209 main_table_is_empty
= output
== ''
3210 if not main_table_is_empty
:
3211 self
.assertNotRegex(output
, 'proto dhcp')
3213 print('## ip route show table 211 dev veth99')
3214 output
= check_output('ip route show table 211 dev veth99')
3216 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
3217 if main_table_is_empty
:
3218 self
.assertRegex(output
, '192.168.5.0/24 proto dhcp')
3219 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
3220 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
3222 print('## dnsmasq log')
3223 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
3224 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
3225 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
3226 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
3228 def test_dhcp6_client_settings_rapidcommit_true(self
):
3229 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3231 self
.wait_online(['veth-peer:carrier'])
3233 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3235 output
= check_output('ip address show dev veth99')
3237 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3238 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
3240 def test_dhcp6_client_settings_rapidcommit_false(self
):
3241 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
3243 self
.wait_online(['veth-peer:carrier'])
3245 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3247 output
= check_output('ip address show dev veth99')
3249 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3250 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
3252 def test_dhcp_client_settings_anonymize(self
):
3253 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
3255 self
.wait_online(['veth-peer:carrier'])
3257 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3259 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
3260 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
3261 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
3263 def test_dhcp_client_listen_port(self
):
3264 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
3266 self
.wait_online(['veth-peer:carrier'])
3267 start_dnsmasq('--dhcp-alternate-port=67,5555')
3268 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3270 output
= check_output('ip -4 address show dev veth99')
3272 self
.assertRegex(output
, '192.168.5.* dynamic')
3274 def test_dhcp_client_with_static_address(self
):
3275 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
3276 'dhcp-client-with-static-address.network')
3278 self
.wait_online(['veth-peer:carrier'])
3280 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3282 output
= check_output('ip address show dev veth99 scope global')
3284 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
3285 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
3287 output
= check_output('ip route show dev veth99')
3289 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
3290 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
3291 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
3292 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
3294 def test_dhcp_route_table_id(self
):
3295 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
3297 self
.wait_online(['veth-peer:carrier'])
3299 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3301 output
= check_output('ip route show table 12')
3303 self
.assertRegex(output
, 'veth99 proto dhcp')
3304 self
.assertRegex(output
, '192.168.5.1')
3306 def test_dhcp_route_metric(self
):
3307 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
3309 self
.wait_online(['veth-peer:carrier'])
3311 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3313 output
= check_output('ip route show dev veth99')
3315 self
.assertRegex(output
, 'metric 24')
3317 def test_dhcp_client_reassign_static_routes_ipv4(self
):
3318 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3319 'dhcp-client-reassign-static-routes-ipv4.network')
3321 self
.wait_online(['veth-peer:carrier'])
3322 start_dnsmasq(lease_time
='2m')
3323 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3325 output
= check_output('ip address show dev veth99 scope global')
3327 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3329 output
= check_output('ip route show dev veth99')
3331 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3332 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3333 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3334 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3336 stop_dnsmasq(dnsmasq_pid_file
)
3337 start_dnsmasq(ipv4_range
='192.168.5.210,192.168.5.220', lease_time
='2m')
3339 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3340 print('Wait for the dynamic address to be renewed')
3343 self
.wait_online(['veth99:routable'])
3345 output
= check_output('ip route show dev veth99')
3347 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3348 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3349 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3350 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3352 def test_dhcp_client_reassign_static_routes_ipv6(self
):
3353 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3354 'dhcp-client-reassign-static-routes-ipv6.network')
3356 self
.wait_online(['veth-peer:carrier'])
3357 start_dnsmasq(lease_time
='2m')
3358 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3360 output
= check_output('ip address show dev veth99 scope global')
3362 self
.assertRegex(output
, r
'inet6 2600::[0-9a-f]*/128 scope global (noprefixroute dynamic|dynamic noprefixroute)')
3364 output
= check_output('ip -6 route show dev veth99')
3366 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3367 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3369 stop_dnsmasq(dnsmasq_pid_file
)
3370 start_dnsmasq(ipv6_range
='2600::30,2600::40', lease_time
='2m')
3372 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3373 print('Wait for the dynamic address to be renewed')
3376 self
.wait_online(['veth99:routable'])
3378 output
= check_output('ip -6 route show dev veth99')
3380 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3381 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3383 def test_dhcp_keep_configuration_dhcp(self
):
3384 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
3386 self
.wait_online(['veth-peer:carrier'])
3387 start_dnsmasq(lease_time
='2m')
3388 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3390 output
= check_output('ip address show dev veth99 scope global')
3392 self
.assertRegex(output
, r
'192.168.5.*')
3394 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3396 self
.assertRegex(output
, r
'192.168.5.*')
3398 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
3399 stop_dnsmasq(dnsmasq_pid_file
)
3401 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3402 print('Wait for the dynamic address to be expired')
3405 print('The lease address should be kept after lease expired')
3406 output
= check_output('ip address show dev veth99 scope global')
3408 self
.assertRegex(output
, r
'192.168.5.*')
3410 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3412 self
.assertRegex(output
, r
'192.168.5.*')
3414 check_output('systemctl stop systemd-networkd')
3416 print('The lease address should be kept after networkd stopped')
3417 output
= check_output('ip address show dev veth99 scope global')
3419 self
.assertRegex(output
, r
'192.168.5.*')
3421 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3423 self
.assertRegex(output
, r
'192.168.5.*')
3426 self
.wait_online(['veth-peer:routable'])
3428 print('Still the lease address should be kept after networkd restarted')
3429 output
= check_output('ip address show dev veth99 scope global')
3431 self
.assertRegex(output
, r
'192.168.5.*')
3433 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3435 self
.assertRegex(output
, r
'192.168.5.*')
3437 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
3438 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
3440 self
.wait_online(['veth-peer:carrier'])
3441 start_dnsmasq(lease_time
='2m')
3442 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3444 output
= check_output('ip address show dev veth99 scope global')
3446 self
.assertRegex(output
, r
'192.168.5.*')
3448 stop_dnsmasq(dnsmasq_pid_file
)
3449 check_output('systemctl stop systemd-networkd')
3451 output
= check_output('ip address show dev veth99 scope global')
3453 self
.assertRegex(output
, r
'192.168.5.*')
3456 self
.wait_online(['veth-peer:routable'])
3458 output
= check_output('ip address show dev veth99 scope global')
3460 self
.assertNotRegex(output
, r
'192.168.5.*')
3462 def test_dhcp_client_reuse_address_as_static(self
):
3463 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
3465 self
.wait_online(['veth-peer:carrier'])
3467 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3469 # link become 'routable' when at least one protocol provide an valid address.
3470 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3471 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3473 output
= check_output('ip address show dev veth99 scope global')
3475 self
.assertRegex(output
, '192.168.5')
3476 self
.assertRegex(output
, '2600::')
3478 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
3479 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
3480 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
3481 print(static_network
)
3483 remove_unit_from_networkd_path(['dhcp-client.network'])
3485 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
3486 f
.write(static_network
)
3488 # When networkd started, the links are already configured, so let's wait for 5 seconds
3489 # the links to be re-configured.
3491 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3493 output
= check_output('ip -4 address show dev veth99 scope global')
3495 self
.assertRegex(output
, '192.168.5')
3496 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3498 output
= check_output('ip -6 address show dev veth99 scope global')
3500 self
.assertRegex(output
, '2600::')
3501 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3503 @expectedFailureIfModuleIsNotAvailable('vrf')
3504 def test_dhcp_client_vrf(self
):
3505 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
3506 '25-vrf.netdev', '25-vrf.network')
3508 self
.wait_online(['veth-peer:carrier'])
3510 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
3512 # link become 'routable' when at least one protocol provide an valid address.
3513 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3514 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3516 print('## ip -d link show dev vrf99')
3517 output
= check_output('ip -d link show dev vrf99')
3519 self
.assertRegex(output
, 'vrf table 42')
3521 print('## ip address show vrf vrf99')
3522 output
= check_output('ip address show vrf vrf99')
3524 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3525 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3526 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3527 self
.assertRegex(output
, 'inet6 .* scope link')
3529 print('## ip address show dev veth99')
3530 output
= check_output('ip address show dev veth99')
3532 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3533 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3534 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3535 self
.assertRegex(output
, 'inet6 .* scope link')
3537 print('## ip route show vrf vrf99')
3538 output
= check_output('ip route show vrf vrf99')
3540 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
3541 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
3542 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
3543 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
3544 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
3546 print('## ip route show table main dev veth99')
3547 output
= check_output('ip route show table main dev veth99')
3549 self
.assertEqual(output
, '')
3551 def test_dhcp_client_gateway_ipv4(self
):
3552 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3553 'dhcp-client-gateway-ipv4.network')
3555 self
.wait_online(['veth-peer:carrier'])
3557 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3559 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3561 self
.assertRegex(output
, '10.0.0.0/8 via 192.168.5.1 proto static')
3563 def test_dhcp_client_gateway_ipv6(self
):
3564 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3565 'dhcp-client-gateway-ipv6.network')
3567 self
.wait_online(['veth-peer:carrier'])
3569 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3571 output
= check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
3573 self
.assertRegex(output
, 'via fe80::1034:56ff:fe78:9abd')
3575 def test_dhcp_client_gateway_onlink_implicit(self
):
3576 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3577 'dhcp-client-gateway-onlink-implicit.network')
3579 self
.wait_online(['veth-peer:carrier'])
3581 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3583 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3585 self
.assertRegex(output
, '192.168.5')
3587 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3589 self
.assertRegex(output
, 'onlink')
3590 output
= check_output('ip route list dev veth99 192.168.100.0/24')
3592 self
.assertRegex(output
, 'onlink')
3594 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
3595 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3596 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
3598 self
.wait_online(['veth-peer:carrier'])
3599 start_dnsmasq(lease_time
='2m')
3600 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3602 output
= check_output('ip address show dev veth99')
3605 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3606 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3607 output
= check_output('ip -6 address show dev veth99 scope link')
3608 self
.assertRegex(output
, 'inet6 .* scope link')
3609 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3610 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3611 output
= check_output('ip -4 address show dev veth99 scope link')
3612 self
.assertNotRegex(output
, 'inet .* scope link')
3614 print('Wait for the dynamic address to be expired')
3617 output
= check_output('ip address show dev veth99')
3620 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3621 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3622 output
= check_output('ip -6 address show dev veth99 scope link')
3623 self
.assertRegex(output
, 'inet6 .* scope link')
3624 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3625 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3626 output
= check_output('ip -4 address show dev veth99 scope link')
3627 self
.assertNotRegex(output
, 'inet .* scope link')
3629 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
3631 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
3632 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3633 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
3635 self
.wait_online(['veth99:degraded', 'veth-peer:routable'])
3637 output
= check_output('ip address show dev veth99')
3640 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3641 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3642 output
= check_output('ip -6 address show dev veth99 scope link')
3643 self
.assertRegex(output
, 'inet6 .* scope link')
3644 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3645 self
.assertNotRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3646 output
= check_output('ip -4 address show dev veth99 scope link')
3647 self
.assertRegex(output
, 'inet .* scope link')
3649 def test_dhcp_client_route_remove_on_renew(self
):
3650 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3651 'dhcp-client-ipv4-only-ipv6-disabled.network')
3653 self
.wait_online(['veth-peer:carrier'])
3654 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
3655 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3657 # test for issue #12490
3659 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3661 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3663 for line
in output
.splitlines():
3664 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3665 address1
= line
.split()[1].split('/')[0]
3668 output
= check_output('ip -4 route show dev veth99')
3670 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3671 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3673 stop_dnsmasq(dnsmasq_pid_file
)
3674 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
3676 print('Wait for the dynamic address to be expired')
3679 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3681 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3683 for line
in output
.splitlines():
3684 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3685 address2
= line
.split()[1].split('/')[0]
3688 self
.assertNotEqual(address1
, address2
)
3690 output
= check_output('ip -4 route show dev veth99')
3692 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3693 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3694 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
3695 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
3697 def test_dhcp_client_use_dns_yes(self
):
3698 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-yes.network')
3701 self
.wait_online(['veth-peer:carrier'])
3702 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3703 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3705 # link become 'routable' when at least one protocol provide an valid address.
3706 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3707 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3710 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3712 self
.assertRegex(output
, '192.168.5.1')
3713 self
.assertRegex(output
, '2600::1')
3715 def test_dhcp_client_use_dns_no(self
):
3716 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-no.network')
3719 self
.wait_online(['veth-peer:carrier'])
3720 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3721 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3723 # link become 'routable' when at least one protocol provide an valid address.
3724 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3725 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3728 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3730 self
.assertNotRegex(output
, '192.168.5.1')
3731 self
.assertNotRegex(output
, '2600::1')
3733 def test_dhcp_client_use_dns_ipv4(self
):
3734 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4.network')
3737 self
.wait_online(['veth-peer:carrier'])
3738 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3739 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3741 # link become 'routable' when at least one protocol provide an valid address.
3742 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3743 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3746 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3748 self
.assertRegex(output
, '192.168.5.1')
3749 self
.assertNotRegex(output
, '2600::1')
3751 def test_dhcp_client_use_dns_ipv4_and_ra(self
):
3752 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4-and-ra.network')
3755 self
.wait_online(['veth-peer:carrier'])
3756 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3757 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3759 # link become 'routable' when at least one protocol provide an valid address.
3760 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3761 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3764 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3766 self
.assertRegex(output
, '192.168.5.1')
3767 self
.assertRegex(output
, '2600::1')
3769 def test_dhcp_client_use_domains(self
):
3770 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-domains.network')
3773 self
.wait_online(['veth-peer:carrier'])
3774 start_dnsmasq('--dhcp-option=option:domain-search,example.com')
3775 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3777 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3779 self
.assertRegex(output
, 'Search Domains: example.com')
3782 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
3784 self
.assertRegex(output
, 'example.com')
3786 def test_dhcp_client_decline(self
):
3787 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-decline.network', 'dhcp-client-decline.network')
3790 self
.wait_online(['veth-peer:carrier'])
3791 rc
= call(*wait_online_cmd
, '--timeout=10s', '--interface=veth99:routable', env
=env
)
3792 self
.assertTrue(rc
== 1)
3794 class NetworkdIPv6PrefixTests(unittest
.TestCase
, Utilities
):
3799 'ipv6ra-prefix-client.network',
3800 'ipv6ra-prefix.network'
3804 remove_links(self
.links
)
3805 stop_networkd(show_logs
=False)
3809 remove_links(self
.links
)
3810 remove_unit_from_networkd_path(self
.units
)
3811 stop_networkd(show_logs
=True)
3813 def test_ipv6_route_prefix(self
):
3814 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client.network', 'ipv6ra-prefix.network')
3817 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3819 output
= check_output('ip -6 route show dev veth-peer')
3821 self
.assertRegex(output
, '2001:db8:0:1::/64 proto ra')
3823 output
= check_output('ip addr show dev veth99')
3825 self
.assertNotRegex(output
, '2001:db8:0:1')
3826 self
.assertRegex(output
, '2001:db8:0:2')
3828 class NetworkdMTUTests(unittest
.TestCase
, Utilities
):
3833 '12-dummy-mtu.netdev',
3834 '12-dummy-mtu.link',
3839 remove_links(self
.links
)
3840 stop_networkd(show_logs
=False)
3844 remove_links(self
.links
)
3845 remove_unit_from_networkd_path(self
.units
)
3846 stop_networkd(show_logs
=True)
3848 def check_mtu(self
, mtu
, ipv6_mtu
=None, reset
=True):
3854 self
.wait_online(['dummy98:routable'])
3855 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
3856 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
3858 # test normal restart
3860 self
.wait_online(['dummy98:routable'])
3861 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
3862 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
3865 self
.reset_check_mtu(mtu
, ipv6_mtu
)
3867 def reset_check_mtu(self
, mtu
, ipv6_mtu
=None):
3868 ''' test setting mtu/ipv6_mtu with interface already up '''
3871 # note - changing the device mtu resets the ipv6 mtu
3872 run('ip link set up mtu 1501 dev dummy98')
3873 run('ip link set up mtu 1500 dev dummy98')
3874 self
.assertEqual(read_link_attr('dummy98', 'mtu'), '1500')
3875 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), '1500')
3877 self
.check_mtu(mtu
, ipv6_mtu
, reset
=False)
3879 def test_mtu_network(self
):
3880 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
3881 self
.check_mtu('1600')
3883 def test_mtu_netdev(self
):
3884 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network', dropins
=False)
3885 # note - MTU set by .netdev happens ONLY at device creation!
3886 self
.check_mtu('1600', reset
=False)
3888 def test_mtu_link(self
):
3889 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', dropins
=False)
3890 # must reload udev because it only picks up new files after 3 second delay
3891 call('udevadm control --reload')
3892 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
3893 self
.check_mtu('1600', reset
=False)
3895 def test_ipv6_mtu(self
):
3896 ''' set ipv6 mtu without setting device mtu '''
3897 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
3898 self
.check_mtu('1500', '1400')
3900 def test_ipv6_mtu_toolarge(self
):
3901 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
3902 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
3903 self
.check_mtu('1500', '1500')
3905 def test_mtu_network_ipv6_mtu(self
):
3906 ''' set ipv6 mtu and set device mtu via network file '''
3907 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
3908 self
.check_mtu('1600', '1550')
3910 def test_mtu_netdev_ipv6_mtu(self
):
3911 ''' set ipv6 mtu and set device mtu via netdev file '''
3912 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
3913 self
.check_mtu('1600', '1550', reset
=False)
3915 def test_mtu_link_ipv6_mtu(self
):
3916 ''' set ipv6 mtu and set device mtu via link file '''
3917 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
3918 # must reload udev because it only picks up new files after 3 second delay
3919 call('udevadm control --reload')
3920 self
.check_mtu('1600', '1550', reset
=False)
3923 if __name__
== '__main__':
3924 parser
= argparse
.ArgumentParser()
3925 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
3926 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
3927 parser
.add_argument('--resolved', help='Path to systemd-resolved', dest
='resolved_bin')
3928 parser
.add_argument('--udevd', help='Path to systemd-udevd', dest
='udevd_bin')
3929 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
3930 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
3931 parser
.add_argument('--resolvectl', help='Path to resolvectl', dest
='resolvectl_bin')
3932 parser
.add_argument('--timedatectl', help='Path to timedatectl', dest
='timedatectl_bin')
3933 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
3934 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
3935 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
3936 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
3937 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
3938 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
3941 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
:
3942 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
3943 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
3944 resolved_bin
= os
.path
.join(ns
.build_dir
, 'systemd-resolved')
3945 udevd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-udevd')
3946 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
3947 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
3948 resolvectl_bin
= os
.path
.join(ns
.build_dir
, 'resolvectl')
3949 timedatectl_bin
= os
.path
.join(ns
.build_dir
, 'timedatectl')
3952 networkd_bin
= ns
.networkd_bin
3954 resolved_bin
= ns
.resolved_bin
3956 udevd_bin
= ns
.udevd_bin
3957 if ns
.wait_online_bin
:
3958 wait_online_bin
= ns
.wait_online_bin
3959 if ns
.networkctl_bin
:
3960 networkctl_bin
= ns
.networkctl_bin
3961 if ns
.resolvectl_bin
:
3962 resolvectl_bin
= ns
.resolvectl_bin
3963 if ns
.timedatectl_bin
:
3964 timedatectl_bin
= ns
.timedatectl_bin
3966 use_valgrind
= ns
.use_valgrind
3967 enable_debug
= ns
.enable_debug
3968 asan_options
= ns
.asan_options
3969 lsan_options
= ns
.lsan_options
3970 ubsan_options
= ns
.ubsan_options
3973 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
3974 resolvectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin
]
3975 timedatectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin
]
3976 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
3978 networkctl_cmd
= [networkctl_bin
]
3979 resolvectl_cmd
= [resolvectl_bin
]
3980 timedatectl_cmd
= [timedatectl_bin
]
3981 wait_online_cmd
= [wait_online_bin
]
3984 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
3986 env
.update({ 'ASAN_OPTIONS' : asan_options
})
3988 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
3990 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
3993 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,