2 # SPDX-License-Identifier: LGPL-2.1+
3 # systemd-networkd tests
14 from shutil
import copytree
16 network_unit_file_path
='/run/systemd/network'
17 networkd_runtime_directory
='/run/systemd/netif'
18 networkd_ci_path
='/run/networkd-ci'
19 network_sysctl_ipv6_path
='/proc/sys/net/ipv6/conf'
20 network_sysctl_ipv4_path
='/proc/sys/net/ipv4/conf'
22 dnsmasq_pid_file
='/run/networkd-ci/test-test-dnsmasq.pid'
23 dnsmasq_log_file
='/run/networkd-ci/test-dnsmasq-log-file'
25 systemd_lib_paths
=['/usr/lib/systemd', '/lib/systemd']
26 which_paths
=':'.join(systemd_lib_paths
+ os
.getenv('PATH', os
.defpath
).lstrip(':').split(':'))
28 networkd_bin
=shutil
.which('systemd-networkd', path
=which_paths
)
29 resolved_bin
=shutil
.which('systemd-resolved', path
=which_paths
)
30 udevd_bin
=shutil
.which('systemd-udevd', path
=which_paths
)
31 wait_online_bin
=shutil
.which('systemd-networkd-wait-online', path
=which_paths
)
32 networkctl_bin
=shutil
.which('networkctl', path
=which_paths
)
33 resolvectl_bin
=shutil
.which('resolvectl', path
=which_paths
)
34 timedatectl_bin
=shutil
.which('timedatectl', path
=which_paths
)
45 def check_output(*command
, **kwargs
):
46 # This replaces both check_output and check_call (output can be ignored)
47 command
= command
[0].split() + list(command
[1:])
48 return subprocess
.check_output(command
, universal_newlines
=True, **kwargs
).rstrip()
50 def call(*command
, **kwargs
):
51 command
= command
[0].split() + list(command
[1:])
52 return subprocess
.call(command
, universal_newlines
=True, **kwargs
)
54 def run(*command
, **kwargs
):
55 command
= command
[0].split() + list(command
[1:])
56 return subprocess
.run(command
, universal_newlines
=True, **kwargs
)
58 def is_module_available(module_name
):
59 lsmod_output
= check_output('lsmod')
60 module_re
= re
.compile(rf
'^{re.escape(module_name)}\b', re
.MULTILINE
)
61 return module_re
.search(lsmod_output
) or not call('modprobe', module_name
, stderr
=subprocess
.DEVNULL
)
63 def expectedFailureIfModuleIsNotAvailable(module_name
):
65 if not is_module_available(module_name
):
66 return unittest
.expectedFailure(func
)
71 def expectedFailureIfERSPANModuleIsNotAvailable():
73 rc
= call('ip link add dev erspan99 type erspan seq key 30 local 192.168.1.4 remote 192.168.1.1 erspan_ver 1 erspan 123', stderr
=subprocess
.DEVNULL
)
75 call('ip link del erspan99')
78 return unittest
.expectedFailure(func
)
82 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable():
84 rc
= call('ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7', stderr
=subprocess
.DEVNULL
)
86 call('ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
89 return unittest
.expectedFailure(func
)
93 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
95 rc
= call('ip rule add not from 192.168.100.19 ipproto tcp table 7', stderr
=subprocess
.DEVNULL
)
97 call('ip rule del not from 192.168.100.19 ipproto tcp table 7')
100 return unittest
.expectedFailure(func
)
104 def expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable():
107 rc
= call('ip rule add from 192.168.100.19 table 7 uidrange 200-300', stderr
=subprocess
.DEVNULL
)
109 ret
= run('ip rule list from 192.168.100.19 table 7', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
110 if ret
.returncode
== 0 and 'uidrange 200-300' in ret
.stdout
.rstrip():
112 call('ip rule del from 192.168.100.19 table 7 uidrange 200-300')
117 return unittest
.expectedFailure(func
)
121 def expectedFailureIfLinkFileFieldIsNotSet():
124 rc
= call('ip link add name dummy99 type dummy', stderr
=subprocess
.DEVNULL
)
126 ret
= run('udevadm info -w10s /sys/class/net/dummy99', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
127 if ret
.returncode
== 0 and 'E: ID_NET_LINK_FILE=' in ret
.stdout
.rstrip():
129 call('ip link del dummy99')
134 return unittest
.expectedFailure(func
)
138 def expectedFailureIfNexthopIsNotAvailable():
140 rc
= call('ip nexthop list', stderr
=subprocess
.DEVNULL
)
144 return unittest
.expectedFailure(func
)
148 def expectedFailureIfAlternativeNameIsNotAvailable():
150 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
151 rc
= call('ip link prop add dev dummy98 altname hogehogehogehogehoge', stderr
=subprocess
.DEVNULL
)
155 return unittest
.expectedFailure(func
)
162 os
.makedirs(network_unit_file_path
, exist_ok
=True)
163 os
.makedirs(networkd_ci_path
, exist_ok
=True)
165 shutil
.rmtree(networkd_ci_path
)
166 copytree(os
.path
.join(os
.path
.dirname(os
.path
.abspath(__file__
)), 'conf'), networkd_ci_path
)
168 for u
in ['systemd-networkd.socket', 'systemd-networkd.service', 'systemd-resolved.service',
169 'systemd-udevd-kernel.socket', 'systemd-udevd-control.socket', 'systemd-udevd.service',
170 'firewalld.service']:
171 if call(f
'systemctl is-active --quiet {u}') == 0:
172 check_output(f
'systemctl stop {u}')
173 running_units
.append(u
)
177 'StartLimitIntervalSec=0',
184 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin
,
188 drop_in
+= ['ExecStart=!!' + networkd_bin
]
190 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
192 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
194 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
196 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
197 if asan_options
or lsan_options
or ubsan_options
:
198 drop_in
+= ['SystemCallFilter=']
199 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
200 drop_in
+= ['MemoryDenyWriteExecute=no']
202 os
.makedirs('/run/systemd/system/systemd-networkd.service.d', exist_ok
=True)
203 with
open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode
='w') as f
:
204 f
.write('\n'.join(drop_in
))
212 drop_in
+= ['ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + resolved_bin
]
214 drop_in
+= ['ExecStart=!!' + resolved_bin
]
216 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
218 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
220 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
222 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
223 if asan_options
or lsan_options
or ubsan_options
:
224 drop_in
+= ['SystemCallFilter=']
225 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
226 drop_in
+= ['MemoryDenyWriteExecute=no']
228 os
.makedirs('/run/systemd/system/systemd-resolved.service.d', exist_ok
=True)
229 with
open('/run/systemd/system/systemd-resolved.service.d/00-override.conf', mode
='w') as f
:
230 f
.write('\n'.join(drop_in
))
235 'ExecStart=!!' + udevd_bin
,
238 os
.makedirs('/run/systemd/system/systemd-udevd.service.d', exist_ok
=True)
239 with
open('/run/systemd/system/systemd-udevd.service.d/00-override.conf', mode
='w') as f
:
240 f
.write('\n'.join(drop_in
))
242 check_output('systemctl daemon-reload')
243 print(check_output('systemctl cat systemd-networkd.service'))
244 print(check_output('systemctl cat systemd-resolved.service'))
245 print(check_output('systemctl cat systemd-udevd.service'))
246 check_output('systemctl restart systemd-resolved')
247 check_output('systemctl restart systemd-udevd')
249 def tearDownModule():
252 shutil
.rmtree(networkd_ci_path
)
254 for u
in ['systemd-networkd.service', 'systemd-resolved.service']:
255 check_output(f
'systemctl stop {u}')
257 shutil
.rmtree('/run/systemd/system/systemd-networkd.service.d')
258 shutil
.rmtree('/run/systemd/system/systemd-resolved.service.d')
259 shutil
.rmtree('/run/systemd/system/systemd-udevd.service.d')
260 check_output('systemctl daemon-reload')
261 check_output('systemctl restart systemd-udevd.service')
263 for u
in running_units
:
264 check_output(f
'systemctl start {u}')
266 def read_link_attr(*args
):
267 with
open(os
.path
.join('/sys/class/net/', *args
)) as f
:
268 return f
.readline().strip()
270 def read_bridge_port_attr(bridge
, link
, attribute
):
271 path_bridge
= os
.path
.join('/sys/devices/virtual/net', bridge
)
272 path_port
= 'lower_' + link
+ '/brport'
273 path
= os
.path
.join(path_bridge
, path_port
)
275 with
open(os
.path
.join(path
, attribute
)) as f
:
276 return f
.readline().strip()
278 def link_exists(link
):
279 return os
.path
.exists(os
.path
.join('/sys/class/net', link
))
281 def remove_links(links
):
283 if link_exists(link
):
284 call('ip link del dev', link
)
287 def remove_fou_ports(ports
):
289 call('ip fou del port', port
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
291 def remove_routing_policy_rule_tables(tables
):
295 rc
= call('ip rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
297 def remove_routes(routes
):
298 for route_type
, addr
in routes
:
299 call('ip route del', route_type
, addr
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
301 def remove_l2tp_tunnels(tunnel_ids
):
302 output
= check_output('ip l2tp show tunnel')
303 for tid
in tunnel_ids
:
304 words
='Tunnel ' + tid
+ ', encap'
306 call('ip l2tp del tunnel tid', tid
)
309 def read_ipv6_sysctl_attr(link
, attribute
):
310 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, link
), attribute
)) as f
:
311 return f
.readline().strip()
313 def read_ipv4_sysctl_attr(link
, attribute
):
314 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv4_path
, link
), attribute
)) as f
:
315 return f
.readline().strip()
317 def copy_unit_to_networkd_unit_path(*units
, dropins
=True):
318 """Copy networkd unit files into the testbed.
320 Any networkd unit file type can be specified, as well as drop-in files.
322 By default, all drop-ins for a specified unit file are copied in;
323 to avoid that specify dropins=False.
325 When a drop-in file is specified, its unit file is also copied in automatically.
329 if dropins
and os
.path
.exists(os
.path
.join(networkd_ci_path
, unit
+ '.d')):
330 copytree(os
.path
.join(networkd_ci_path
, unit
+ '.d'), os
.path
.join(network_unit_file_path
, unit
+ '.d'))
331 if unit
.endswith('.conf'):
333 dropindir
= os
.path
.join(network_unit_file_path
, os
.path
.dirname(dropin
))
334 os
.makedirs(dropindir
, exist_ok
=True)
335 shutil
.copy(os
.path
.join(networkd_ci_path
, dropin
), dropindir
)
336 unit
= os
.path
.dirname(dropin
).rstrip('.d')
337 shutil
.copy(os
.path
.join(networkd_ci_path
, unit
), network_unit_file_path
)
339 def remove_unit_from_networkd_path(units
):
340 """Remove previously copied unit files from the testbed.
342 Drop-ins will be removed automatically.
345 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
))):
346 os
.remove(os
.path
.join(network_unit_file_path
, unit
))
347 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
+ '.d'))):
348 shutil
.rmtree(os
.path
.join(network_unit_file_path
, unit
+ '.d'))
350 def start_dnsmasq(additional_options
='', ipv4_range
='192.168.5.10,192.168.5.200', ipv6_range
='2600::10,2600::20', lease_time
='1h'):
351 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
352 check_output(dnsmasq_command
)
354 def stop_dnsmasq(pid_file
):
355 if os
.path
.exists(pid_file
):
356 with
open(pid_file
, 'r') as f
:
357 pid
= f
.read().rstrip(' \t\r\n\0')
358 os
.kill(int(pid
), signal
.SIGTERM
)
362 def search_words_in_dnsmasq_log(words
, show_all
=False):
363 if os
.path
.exists(dnsmasq_log_file
):
364 with
open (dnsmasq_log_file
) as in_file
:
365 contents
= in_file
.read()
368 for line
in contents
.splitlines():
371 print("%s, %s" % (words
, line
))
375 def remove_lease_file():
376 if os
.path
.exists(os
.path
.join(networkd_ci_path
, 'lease')):
377 os
.remove(os
.path
.join(networkd_ci_path
, 'lease'))
379 def remove_log_file():
380 if os
.path
.exists(dnsmasq_log_file
):
381 os
.remove(dnsmasq_log_file
)
383 def remove_networkd_state_files():
384 if os
.path
.exists(os
.path
.join(networkd_runtime_directory
, 'state')):
385 os
.remove(os
.path
.join(networkd_runtime_directory
, 'state'))
387 def stop_networkd(show_logs
=True, remove_state_files
=True):
389 invocation_id
= check_output('systemctl show systemd-networkd -p InvocationID --value')
390 check_output('systemctl stop systemd-networkd')
392 print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
))
393 if remove_state_files
:
394 remove_networkd_state_files()
396 def start_networkd(sleep_sec
=0):
397 check_output('systemctl start systemd-networkd')
399 time
.sleep(sleep_sec
)
401 def restart_networkd(sleep_sec
=0, show_logs
=True, remove_state_files
=True):
402 stop_networkd(show_logs
, remove_state_files
)
403 start_networkd(sleep_sec
)
407 def check_link_exists(self
, link
):
408 self
.assertTrue(link_exists(link
))
410 def wait_operstate(self
, link
, operstate
='degraded', setup_state
='configured', setup_timeout
=5, fail_assert
=True):
411 """Wait for the link to reach the specified operstate and/or setup state.
413 Specify None or '' for either operstate or setup_state to ignore that state.
414 This will recheck until the state conditions are met or the timeout expires.
416 If the link successfully matches the requested state, this returns True.
417 If this times out waiting for the link to match, the behavior depends on the
418 'fail_assert' parameter; if True, this causes a test assertion failure,
419 otherwise this returns False. The default is to cause assertion failure.
421 Note that this function matches on *exactly* the given operstate and setup_state.
422 To wait for a link to reach *or exceed* a given operstate, use wait_online().
429 for secs
in range(setup_timeout
+ 1):
430 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
, env
=env
)
432 if re
.search(rf
'(?m)^\s*State:\s+{operstate}\s+\({setup_state}\)\s*$', output
):
434 # don't bother sleeping if time is up
435 if secs
< setup_timeout
:
438 self
.fail(f
'Timed out waiting for {link} to reach state {operstate}/{setup_state}')
441 def wait_online(self
, links_with_operstate
, timeout
='20s', bool_any
=False, setup_state
='configured', setup_timeout
=5):
442 """Wait for the link(s) to reach the specified operstate and/or setup state.
444 This is similar to wait_operstate() but can be used for multiple links,
445 and it also calls systemd-networkd-wait-online to wait for the given operstate.
446 The operstate should be specified in the link name, like 'eth0:degraded'.
447 If just a link name is provided, wait-online's default operstate to wait for is degraded.
449 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
450 'setup_timeout' controls the per-link timeout waiting for the setup_state.
452 Set 'bool_any' to True to wait for any (instead of all) of the given links.
453 If this is set, no setup_state checks are done.
455 Note that this function waits for the link(s) to reach *or exceed* the given operstate.
456 However, the setup_state, if specified, must be matched *exactly*.
458 This returns if the link(s) reached the requested operstate/setup_state; otherwise it
459 raises CalledProcessError or fails test assertion.
461 args
= wait_online_cmd
+ [f
'--timeout={timeout}'] + [f
'--interface={link}' for link
in links_with_operstate
]
465 check_output(*args
, env
=env
)
466 except subprocess
.CalledProcessError
:
467 for link
in links_with_operstate
:
468 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
.split(':')[0], env
=env
)
471 if not bool_any
and setup_state
:
472 for link
in links_with_operstate
:
473 self
.wait_operstate(link
.split(':')[0], None, setup_state
, setup_timeout
)
475 def wait_address(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
476 for i
in range(timeout_sec
):
479 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
480 if re
.search(address_regex
, output
):
483 self
.assertRegex(output
, address_regex
)
485 class NetworkctlTests(unittest
.TestCase
, Utilities
):
495 '11-dummy-mtu.netdev',
499 '25-address-static.network',
501 'netdev-link-local-addressing-yes.network',
505 remove_links(self
.links
)
506 stop_networkd(show_logs
=False)
509 remove_links(self
.links
)
510 remove_unit_from_networkd_path(self
.units
)
511 stop_networkd(show_logs
=True)
513 @expectedFailureIfAlternativeNameIsNotAvailable()
514 def test_altname(self
):
515 copy_unit_to_networkd_unit_path('netdev-link-local-addressing-yes.network', '12-dummy.netdev', '12-dummy.link')
516 check_output('udevadm control --reload')
518 self
.wait_online(['dummy98:degraded'])
520 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
521 self
.assertRegex(output
, 'hogehogehogehogehogehoge')
523 def test_reconfigure(self
):
524 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
526 self
.wait_online(['dummy98:routable'])
528 output
= check_output('ip -4 address show dev dummy98')
530 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
531 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
532 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
534 check_output('ip address del 10.1.2.3/16 dev dummy98')
535 check_output('ip address del 10.1.2.4/16 dev dummy98')
536 check_output('ip address del 10.2.2.4/16 dev dummy98')
538 check_output(*networkctl_cmd
, 'reconfigure', 'dummy98', env
=env
)
539 self
.wait_online(['dummy98:routable'])
541 output
= check_output('ip -4 address show dev dummy98')
543 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
544 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
545 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
547 def test_reload(self
):
550 copy_unit_to_networkd_unit_path('11-dummy.netdev')
551 check_output(*networkctl_cmd
, 'reload', env
=env
)
552 self
.wait_operstate('test1', 'off', setup_state
='unmanaged')
554 copy_unit_to_networkd_unit_path('11-dummy.network')
555 check_output(*networkctl_cmd
, 'reload', env
=env
)
556 self
.wait_online(['test1:degraded'])
558 remove_unit_from_networkd_path(['11-dummy.network'])
559 check_output(*networkctl_cmd
, 'reload', env
=env
)
560 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
562 remove_unit_from_networkd_path(['11-dummy.netdev'])
563 check_output(*networkctl_cmd
, 'reload', env
=env
)
564 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
566 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
567 check_output(*networkctl_cmd
, 'reload', env
=env
)
568 self
.wait_operstate('test1', 'degraded')
571 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
574 self
.wait_online(['test1:degraded'])
576 output
= check_output(*networkctl_cmd
, 'list', env
=env
)
577 self
.assertRegex(output
, '1 lo ')
578 self
.assertRegex(output
, 'test1')
580 output
= check_output(*networkctl_cmd
, 'list', 'test1', env
=env
)
581 self
.assertNotRegex(output
, '1 lo ')
582 self
.assertRegex(output
, 'test1')
584 output
= check_output(*networkctl_cmd
, 'list', 'te*', env
=env
)
585 self
.assertNotRegex(output
, '1 lo ')
586 self
.assertRegex(output
, 'test1')
588 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'te*', env
=env
)
589 self
.assertNotRegex(output
, '1: lo ')
590 self
.assertRegex(output
, 'test1')
592 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'tes[a-z][0-9]', env
=env
)
593 self
.assertNotRegex(output
, '1: lo ')
594 self
.assertRegex(output
, 'test1')
597 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
600 self
.wait_online(['test1:degraded'])
602 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
603 self
.assertRegex(output
, 'MTU: 1600')
606 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
608 self
.wait_online(['test1:degraded'])
610 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
612 self
.assertRegex(output
, 'Type: ether')
614 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
616 self
.assertRegex(output
, 'Type: loopback')
618 @expectedFailureIfLinkFileFieldIsNotSet()
619 def test_udev_link_file(self
):
620 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
622 self
.wait_online(['test1:degraded'])
624 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
626 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
627 self
.assertRegex(output
, r
'Network File: /run/systemd/network/11-dummy.network')
629 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
631 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
632 self
.assertRegex(output
, r
'Network File: n/a')
634 def test_delete_links(self
):
635 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
636 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
639 self
.wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
641 check_output(*networkctl_cmd
, 'delete', 'test1', 'veth99', env
=env
)
642 self
.assertFalse(link_exists('test1'))
643 self
.assertFalse(link_exists('veth99'))
644 self
.assertFalse(link_exists('veth-peer'))
646 class NetworkdNetDevTests(unittest
.TestCase
, Utilities
):
648 links_remove_earlier
= [
713 '10-dropin-test.netdev',
717 '13-not-match-udev-property.network',
718 '14-match-udev-property.network',
719 '15-name-conflict-test.netdev',
722 '21-vlan-test1.network',
725 '25-6rd-tunnel.netdev',
727 '25-bond-balanced-tlb.netdev',
729 '25-bridge-configure-without-carrier.network',
731 '25-erspan-tunnel-local-any.netdev',
732 '25-erspan-tunnel.netdev',
733 '25-fou-gretap.netdev',
735 '25-fou-ipip.netdev',
736 '25-fou-ipproto-gre.netdev',
737 '25-fou-ipproto-ipip.netdev',
740 '25-gretap-tunnel-local-any.netdev',
741 '25-gretap-tunnel.netdev',
742 '25-gre-tunnel-any-any.netdev',
743 '25-gre-tunnel-local-any.netdev',
744 '25-gre-tunnel-remote-any.netdev',
745 '25-gre-tunnel.netdev',
747 '25-ip6gretap-tunnel-local-any.netdev',
748 '25-ip6gretap-tunnel.netdev',
749 '25-ip6gre-tunnel-any-any.netdev',
750 '25-ip6gre-tunnel-local-any.netdev',
751 '25-ip6gre-tunnel-remote-any.netdev',
752 '25-ip6gre-tunnel.netdev',
753 '25-ip6tnl-tunnel-any-any.netdev',
754 '25-ip6tnl-tunnel-local-any.netdev',
755 '25-ip6tnl-tunnel-remote-any.netdev',
756 '25-ip6tnl-tunnel.netdev',
757 '25-ipip-tunnel-any-any.netdev',
758 '25-ipip-tunnel-independent.netdev',
759 '25-ipip-tunnel-independent-loopback.netdev',
760 '25-ipip-tunnel-local-any.netdev',
761 '25-ipip-tunnel-remote-any.netdev',
762 '25-ipip-tunnel.netdev',
765 '25-isatap-tunnel.netdev',
770 '25-sit-tunnel-any-any.netdev',
771 '25-sit-tunnel-local-any.netdev',
772 '25-sit-tunnel-remote-any.netdev',
773 '25-sit-tunnel.netdev',
776 '25-tunnel-local-any.network',
777 '25-tunnel-remote-any.network',
782 '25-vti6-tunnel-any-any.netdev',
783 '25-vti6-tunnel-local-any.netdev',
784 '25-vti6-tunnel-remote-any.netdev',
785 '25-vti6-tunnel.netdev',
786 '25-vti-tunnel-any-any.netdev',
787 '25-vti-tunnel-local-any.netdev',
788 '25-vti-tunnel-remote-any.netdev',
789 '25-vti-tunnel.netdev',
792 '25-wireguard-23-peers.netdev',
793 '25-wireguard-23-peers.network',
794 '25-wireguard-preshared-key.txt',
795 '25-wireguard-private-key.txt',
796 '25-wireguard.netdev',
797 '25-wireguard.network',
799 '25-xfrm-independent.netdev',
815 'netdev-link-local-addressing-yes.network',
819 'vxlan-test1.network',
829 remove_fou_ports(self
.fou_ports
)
830 remove_links(self
.links_remove_earlier
)
831 remove_links(self
.links
)
832 stop_networkd(show_logs
=False)
835 remove_fou_ports(self
.fou_ports
)
836 remove_links(self
.links_remove_earlier
)
837 remove_links(self
.links
)
838 remove_unit_from_networkd_path(self
.units
)
839 stop_networkd(show_logs
=True)
841 def test_dropin_and_name_conflict(self
):
842 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
845 self
.wait_online(['dropin-test:off'], setup_state
='unmanaged')
847 output
= check_output('ip link show dropin-test')
849 self
.assertRegex(output
, '00:50:56:c0:00:28')
851 def test_match_udev_property(self
):
852 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
854 self
.wait_online(['dummy98:routable'])
856 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
858 self
.assertRegex(output
, 'Network File: /run/systemd/network/14-match-udev-property')
860 def test_wait_online_any(self
):
861 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
864 self
.wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
866 self
.wait_operstate('bridge99', '(off|no-carrier)', setup_state
='configuring')
867 self
.wait_operstate('test1', 'degraded')
869 def test_bridge(self
):
870 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
873 self
.wait_online(['bridge99:no-carrier'])
875 tick
= os
.sysconf('SC_CLK_TCK')
876 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
877 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
878 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'forward_delay')) / tick
))
879 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'ageing_time')) / tick
))
880 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge', 'priority')))
881 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_querier')))
882 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_snooping')))
883 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'stp_state')))
884 self
.assertEqual(3, int(read_link_attr('bridge99', 'bridge', 'multicast_igmp_version')))
886 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
888 self
.assertRegex(output
, 'Priority: 9')
889 self
.assertRegex(output
, 'STP: yes')
890 self
.assertRegex(output
, 'Multicast IGMP Version: 3')
893 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
896 self
.wait_online(['bond99:off', 'bond98:off'], setup_state
='unmanaged')
898 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
899 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
900 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
901 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
902 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
903 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
904 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
905 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
906 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
907 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
908 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
910 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
911 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
914 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
915 '21-vlan.network', '21-vlan-test1.network')
918 self
.wait_online(['test1:degraded', 'vlan99:routable'])
920 output
= check_output('ip -d link show test1')
922 self
.assertRegex(output
, ' mtu 2000 ')
924 output
= check_output('ip -d link show vlan99')
926 self
.assertRegex(output
, ' mtu 2000 ')
927 self
.assertRegex(output
, 'REORDER_HDR')
928 self
.assertRegex(output
, 'LOOSE_BINDING')
929 self
.assertRegex(output
, 'GVRP')
930 self
.assertRegex(output
, 'MVRP')
931 self
.assertRegex(output
, ' id 99 ')
933 output
= check_output('ip -4 address show dev test1')
935 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
936 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
938 output
= check_output('ip -4 address show dev vlan99')
940 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
942 def test_macvtap(self
):
943 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
944 with self
.subTest(mode
=mode
):
945 if mode
!= 'private':
947 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
948 '11-dummy.netdev', 'macvtap.network')
949 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
950 f
.write('[MACVTAP]\nMode=' + mode
)
953 self
.wait_online(['macvtap99:degraded', 'test1:degraded'])
955 output
= check_output('ip -d link show macvtap99')
957 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
959 def test_macvlan(self
):
960 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
961 with self
.subTest(mode
=mode
):
962 if mode
!= 'private':
964 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
965 '11-dummy.netdev', 'macvlan.network')
966 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
967 f
.write('[MACVLAN]\nMode=' + mode
)
970 self
.wait_online(['macvlan99:degraded', 'test1:degraded'])
972 output
= check_output('ip -d link show test1')
974 self
.assertRegex(output
, ' mtu 2000 ')
976 output
= check_output('ip -d link show macvlan99')
978 self
.assertRegex(output
, ' mtu 2000 ')
979 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
981 @expectedFailureIfModuleIsNotAvailable('ipvlan')
982 def test_ipvlan(self
):
983 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
984 with self
.subTest(mode
=mode
, flag
=flag
):
987 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
988 '11-dummy.netdev', 'ipvlan.network')
989 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
990 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
993 self
.wait_online(['ipvlan99:degraded', 'test1:degraded'])
995 output
= check_output('ip -d link show ipvlan99')
997 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
999 @expectedFailureIfModuleIsNotAvailable('ipvtap')
1000 def test_ipvtap(self
):
1001 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1002 with self
.subTest(mode
=mode
, flag
=flag
):
1005 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
1006 '11-dummy.netdev', 'ipvtap.network')
1007 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
1008 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
1011 self
.wait_online(['ipvtap99:degraded', 'test1:degraded'])
1013 output
= check_output('ip -d link show ipvtap99')
1015 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
1017 def test_veth(self
):
1018 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
1021 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
1023 output
= check_output('ip -d link show veth99')
1025 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
1026 output
= check_output('ip -d link show veth-peer')
1028 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
1031 copy_unit_to_networkd_unit_path('25-tun.netdev')
1034 self
.wait_online(['tun99:off'], setup_state
='unmanaged')
1036 output
= check_output('ip -d link show tun99')
1038 # Old ip command does not support IFF_ flags
1039 self
.assertRegex(output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
1042 copy_unit_to_networkd_unit_path('25-tap.netdev')
1045 self
.wait_online(['tap99:off'], setup_state
='unmanaged')
1047 output
= check_output('ip -d link show tap99')
1049 # Old ip command does not support IFF_ flags
1050 self
.assertRegex(output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
1052 @expectedFailureIfModuleIsNotAvailable('vrf')
1054 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
1057 self
.wait_online(['vrf99:carrier'])
1059 @expectedFailureIfModuleIsNotAvailable('vcan')
1060 def test_vcan(self
):
1061 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
1064 self
.wait_online(['vcan99:carrier'])
1066 @expectedFailureIfModuleIsNotAvailable('vxcan')
1067 def test_vxcan(self
):
1068 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
1071 self
.wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
1073 @expectedFailureIfModuleIsNotAvailable('wireguard')
1074 def test_wireguard(self
):
1075 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
1076 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
1077 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt')
1079 self
.wait_online(['wg99:carrier', 'wg98:routable'])
1081 if shutil
.which('wg'):
1084 output
= check_output('wg show wg99 listen-port')
1085 self
.assertRegex(output
, '51820')
1086 output
= check_output('wg show wg99 fwmark')
1087 self
.assertRegex(output
, '0x4d2')
1088 output
= check_output('wg show wg99 allowed-ips')
1089 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
1090 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
1091 output
= check_output('wg show wg99 persistent-keepalive')
1092 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
1093 output
= check_output('wg show wg99 endpoints')
1094 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
1095 output
= check_output('wg show wg99 private-key')
1096 self
.assertRegex(output
, r
'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
1097 output
= check_output('wg show wg99 preshared-keys')
1098 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
1099 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
1101 output
= check_output('wg show wg98 private-key')
1102 self
.assertRegex(output
, r
'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
1104 def test_geneve(self
):
1105 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
1108 self
.wait_online(['geneve99:degraded'])
1110 output
= check_output('ip -d link show geneve99')
1112 self
.assertRegex(output
, '192.168.22.1')
1113 self
.assertRegex(output
, '6082')
1114 self
.assertRegex(output
, 'udpcsum')
1115 self
.assertRegex(output
, 'udp6zerocsumrx')
1117 def test_ipip_tunnel(self
):
1118 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
1119 '25-ipip-tunnel.netdev', '25-tunnel.network',
1120 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1121 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1122 '25-ipip-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1124 self
.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'ipiptun96:routable', 'dummy98:degraded'])
1126 output
= check_output('ip -d link show ipiptun99')
1128 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98')
1129 output
= check_output('ip -d link show ipiptun98')
1131 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98')
1132 output
= check_output('ip -d link show ipiptun97')
1134 self
.assertRegex(output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98')
1135 output
= check_output('ip -d link show ipiptun96')
1137 self
.assertRegex(output
, 'ipip (ipip )?remote any local any dev dummy98')
1139 def test_gre_tunnel(self
):
1140 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
1141 '25-gre-tunnel.netdev', '25-tunnel.network',
1142 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1143 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1144 '25-gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1146 self
.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'gretun96:routable', 'dummy98:degraded'])
1148 output
= check_output('ip -d link show gretun99')
1150 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1151 self
.assertRegex(output
, 'ikey 1.2.3.103')
1152 self
.assertRegex(output
, 'okey 1.2.4.103')
1153 self
.assertRegex(output
, 'iseq')
1154 self
.assertRegex(output
, 'oseq')
1155 output
= check_output('ip -d link show gretun98')
1157 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
1158 self
.assertRegex(output
, 'ikey 0.0.0.104')
1159 self
.assertRegex(output
, 'okey 0.0.0.104')
1160 self
.assertNotRegex(output
, 'iseq')
1161 self
.assertNotRegex(output
, 'oseq')
1162 output
= check_output('ip -d link show gretun97')
1164 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
1165 self
.assertRegex(output
, 'ikey 0.0.0.105')
1166 self
.assertRegex(output
, 'okey 0.0.0.105')
1167 self
.assertNotRegex(output
, 'iseq')
1168 self
.assertNotRegex(output
, 'oseq')
1169 output
= check_output('ip -d link show gretun96')
1171 self
.assertRegex(output
, 'gre remote any local any dev dummy98')
1172 self
.assertRegex(output
, 'ikey 0.0.0.106')
1173 self
.assertRegex(output
, 'okey 0.0.0.106')
1174 self
.assertNotRegex(output
, 'iseq')
1175 self
.assertNotRegex(output
, 'oseq')
1177 def test_ip6gre_tunnel(self
):
1178 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
1179 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
1180 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1181 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1182 '25-ip6gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1185 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1187 self
.check_link_exists('dummy98')
1188 self
.check_link_exists('ip6gretun99')
1189 self
.check_link_exists('ip6gretun98')
1190 self
.check_link_exists('ip6gretun97')
1191 self
.check_link_exists('ip6gretun96')
1193 output
= check_output('ip -d link show ip6gretun99')
1195 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1196 output
= check_output('ip -d link show ip6gretun98')
1198 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
1199 output
= check_output('ip -d link show ip6gretun97')
1201 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
1202 output
= check_output('ip -d link show ip6gretun96')
1204 self
.assertRegex(output
, 'ip6gre remote any local any dev dummy98')
1206 def test_gretap_tunnel(self
):
1207 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
1208 '25-gretap-tunnel.netdev', '25-tunnel.network',
1209 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1211 self
.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
1213 output
= check_output('ip -d link show gretap99')
1215 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1216 self
.assertRegex(output
, 'ikey 0.0.0.106')
1217 self
.assertRegex(output
, 'okey 0.0.0.106')
1218 self
.assertRegex(output
, 'iseq')
1219 self
.assertRegex(output
, 'oseq')
1220 output
= check_output('ip -d link show gretap98')
1222 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
1223 self
.assertRegex(output
, 'ikey 0.0.0.107')
1224 self
.assertRegex(output
, 'okey 0.0.0.107')
1225 self
.assertRegex(output
, 'iseq')
1226 self
.assertRegex(output
, 'oseq')
1228 def test_ip6gretap_tunnel(self
):
1229 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
1230 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1231 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1233 self
.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
1235 output
= check_output('ip -d link show ip6gretap99')
1237 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1238 output
= check_output('ip -d link show ip6gretap98')
1240 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1242 def test_vti_tunnel(self
):
1243 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
1244 '25-vti-tunnel.netdev', '25-tunnel.network',
1245 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1246 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1247 '25-vti-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1249 self
.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'vtitun96:routable', 'dummy98:degraded'])
1251 output
= check_output('ip -d link show vtitun99')
1253 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1254 output
= check_output('ip -d link show vtitun98')
1256 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
1257 output
= check_output('ip -d link show vtitun97')
1259 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
1260 output
= check_output('ip -d link show vtitun96')
1262 self
.assertRegex(output
, 'vti remote any local any dev dummy98')
1264 def test_vti6_tunnel(self
):
1265 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
1266 '25-vti6-tunnel.netdev', '25-tunnel.network',
1267 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1268 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1270 self
.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
1272 output
= check_output('ip -d link show vti6tun99')
1274 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1275 output
= check_output('ip -d link show vti6tun98')
1277 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1278 output
= check_output('ip -d link show vti6tun97')
1280 self
.assertRegex(output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1282 def test_ip6tnl_tunnel(self
):
1283 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
1284 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1285 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1286 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1288 self
.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
1290 output
= check_output('ip -d link show ip6tnl99')
1292 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1293 output
= check_output('ip -d link show ip6tnl98')
1295 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1296 output
= check_output('ip -d link show ip6tnl97')
1298 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1300 def test_sit_tunnel(self
):
1301 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1302 '25-sit-tunnel.netdev', '25-tunnel.network',
1303 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1304 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1305 '25-sit-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1307 self
.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'sittun96:routable', 'dummy98:degraded'])
1309 output
= check_output('ip -d link show sittun99')
1311 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1312 output
= check_output('ip -d link show sittun98')
1314 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98")
1315 output
= check_output('ip -d link show sittun97')
1317 self
.assertRegex(output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98")
1318 output
= check_output('ip -d link show sittun96')
1320 self
.assertRegex(output
, "sit (ip6ip )?remote any local any dev dummy98")
1322 def test_isatap_tunnel(self
):
1323 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1324 '25-isatap-tunnel.netdev', '25-tunnel.network')
1326 self
.wait_online(['isataptun99:routable', 'dummy98:degraded'])
1328 output
= check_output('ip -d link show isataptun99')
1330 self
.assertRegex(output
, "isatap ")
1332 def test_6rd_tunnel(self
):
1333 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1334 '25-6rd-tunnel.netdev', '25-tunnel.network')
1336 self
.wait_online(['sittun99:routable', 'dummy98:degraded'])
1338 output
= check_output('ip -d link show sittun99')
1340 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1342 @expectedFailureIfERSPANModuleIsNotAvailable()
1343 def test_erspan_tunnel(self
):
1344 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1345 '25-erspan-tunnel.netdev', '25-tunnel.network',
1346 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1348 self
.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1350 output
= check_output('ip -d link show erspan99')
1352 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1353 self
.assertRegex(output
, 'ikey 0.0.0.101')
1354 self
.assertRegex(output
, 'okey 0.0.0.101')
1355 self
.assertRegex(output
, 'iseq')
1356 self
.assertRegex(output
, 'oseq')
1357 output
= check_output('ip -d link show erspan98')
1359 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1360 self
.assertRegex(output
, '102')
1361 self
.assertRegex(output
, 'ikey 0.0.0.102')
1362 self
.assertRegex(output
, 'okey 0.0.0.102')
1363 self
.assertRegex(output
, 'iseq')
1364 self
.assertRegex(output
, 'oseq')
1366 def test_tunnel_independent(self
):
1367 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1370 self
.wait_online(['ipiptun99:carrier'])
1372 def test_tunnel_independent_loopback(self
):
1373 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent-loopback.netdev', 'netdev-link-local-addressing-yes.network')
1376 self
.wait_online(['ipiptun99:carrier'])
1378 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1379 def test_xfrm(self
):
1380 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'xfrm.network',
1381 '25-xfrm.netdev', 'netdev-link-local-addressing-yes.network')
1384 self
.wait_online(['xfrm99:degraded', 'dummy98:degraded'])
1386 output
= check_output('ip link show dev xfrm99')
1389 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1390 def test_xfrm_independent(self
):
1391 copy_unit_to_networkd_unit_path('25-xfrm-independent.netdev', 'netdev-link-local-addressing-yes.network')
1394 self
.wait_online(['xfrm99:degraded'])
1396 @expectedFailureIfModuleIsNotAvailable('fou')
1398 # The following redundant check is necessary for CentOS CI.
1399 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1400 self
.assertTrue(is_module_available('fou'))
1402 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1403 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1404 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1407 self
.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'], setup_state
='unmanaged')
1409 output
= check_output('ip fou show')
1411 self
.assertRegex(output
, 'port 55555 ipproto 4')
1412 self
.assertRegex(output
, 'port 55556 ipproto 47')
1414 output
= check_output('ip -d link show ipiptun96')
1416 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1417 output
= check_output('ip -d link show sittun96')
1419 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1420 output
= check_output('ip -d link show gretun96')
1422 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1423 output
= check_output('ip -d link show gretap96')
1425 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1427 def test_vxlan(self
):
1428 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1429 '11-dummy.netdev', 'vxlan-test1.network')
1432 self
.wait_online(['test1:degraded', 'vxlan99:degraded'])
1434 output
= check_output('ip -d link show vxlan99')
1436 self
.assertRegex(output
, '999')
1437 self
.assertRegex(output
, '5555')
1438 self
.assertRegex(output
, 'l2miss')
1439 self
.assertRegex(output
, 'l3miss')
1440 self
.assertRegex(output
, 'udpcsum')
1441 self
.assertRegex(output
, 'udp6zerocsumtx')
1442 self
.assertRegex(output
, 'udp6zerocsumrx')
1443 self
.assertRegex(output
, 'remcsumtx')
1444 self
.assertRegex(output
, 'remcsumrx')
1445 self
.assertRegex(output
, 'gbp')
1447 output
= check_output('bridge fdb show dev vxlan99')
1449 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1450 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1451 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1453 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'vxlan99', env
=env
)
1455 self
.assertRegex(output
, 'VNI: 999')
1456 self
.assertRegex(output
, 'Destination Port: 5555')
1457 self
.assertRegex(output
, 'Underlying Device: test1')
1459 def test_macsec(self
):
1460 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1461 'macsec.network', '12-dummy.netdev')
1464 self
.wait_online(['dummy98:degraded', 'macsec99:routable'])
1466 output
= check_output('ip -d link show macsec99')
1468 self
.assertRegex(output
, 'macsec99@dummy98')
1469 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1470 self
.assertRegex(output
, 'encrypt on')
1472 output
= check_output('ip macsec show macsec99')
1474 self
.assertRegex(output
, 'encrypt on')
1475 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1476 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1477 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1478 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1479 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1480 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1481 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1482 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1483 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1484 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1485 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1487 def test_nlmon(self
):
1488 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1491 self
.wait_online(['nlmon99:carrier'])
1493 @expectedFailureIfModuleIsNotAvailable('ifb')
1495 copy_unit_to_networkd_unit_path('25-ifb.netdev', 'netdev-link-local-addressing-yes.network')
1498 self
.wait_online(['ifb99:degraded'])
1500 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1511 '25-l2tp-dummy.network',
1513 '25-l2tp-ip.netdev',
1514 '25-l2tp-udp.netdev']
1516 l2tp_tunnel_ids
= [ '10' ]
1519 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1520 remove_links(self
.links
)
1521 stop_networkd(show_logs
=False)
1524 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1525 remove_links(self
.links
)
1526 remove_unit_from_networkd_path(self
.units
)
1527 stop_networkd(show_logs
=True)
1529 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1530 def test_l2tp_udp(self
):
1531 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1532 '25-l2tp-udp.netdev', '25-l2tp.network')
1535 self
.wait_online(['test1:routable', 'l2tp-ses1:degraded', 'l2tp-ses2:degraded'])
1537 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1539 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1540 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1541 self
.assertRegex(output
, "Peer tunnel 11")
1542 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1543 self
.assertRegex(output
, "UDP checksum: enabled")
1545 output
= check_output('ip l2tp show session tid 10 session_id 15')
1547 self
.assertRegex(output
, "Session 15 in tunnel 10")
1548 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1549 self
.assertRegex(output
, "interface name: l2tp-ses1")
1551 output
= check_output('ip l2tp show session tid 10 session_id 17')
1553 self
.assertRegex(output
, "Session 17 in tunnel 10")
1554 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1555 self
.assertRegex(output
, "interface name: l2tp-ses2")
1557 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1558 def test_l2tp_ip(self
):
1559 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1560 '25-l2tp-ip.netdev', '25-l2tp.network')
1563 self
.wait_online(['test1:routable', 'l2tp-ses3:degraded', 'l2tp-ses4:degraded'])
1565 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1567 self
.assertRegex(output
, "Tunnel 10, encap IP")
1568 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1569 self
.assertRegex(output
, "Peer tunnel 12")
1571 output
= check_output('ip l2tp show session tid 10 session_id 25')
1573 self
.assertRegex(output
, "Session 25 in tunnel 10")
1574 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1575 self
.assertRegex(output
, "interface name: l2tp-ses3")
1577 output
= check_output('ip l2tp show session tid 10 session_id 27')
1579 self
.assertRegex(output
, "Session 27 in tunnel 10")
1580 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1581 self
.assertRegex(output
, "interface name: l2tp-ses4")
1583 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1598 '23-active-slave.network',
1599 '24-keep-configuration-static.network',
1600 '24-search-domain.network',
1601 '25-address-dad-veth-peer.network',
1602 '25-address-dad-veth99.network',
1603 '25-address-link-section.network',
1604 '25-address-preferred-lifetime-zero.network',
1605 '25-address-static.network',
1606 '25-bind-carrier.network',
1607 '25-bond-active-backup-slave.netdev',
1608 '25-fibrule-invert.network',
1609 '25-fibrule-port-range.network',
1610 '25-fibrule-uidrange.network',
1611 '25-gre-tunnel-remote-any.netdev',
1612 '25-ip6gre-tunnel-remote-any.netdev',
1613 '25-ipv6-address-label-section.network',
1614 '25-link-local-addressing-no.network',
1615 '25-link-local-addressing-yes.network',
1616 '25-link-section-unmanaged.network',
1617 '25-neighbor-section.network',
1618 '25-neighbor-next.network',
1619 '25-neighbor-ipv6.network',
1620 '25-neighbor-ip-dummy.network',
1621 '25-neighbor-ip.network',
1622 '25-nexthop.network',
1623 '25-qdisc-clsact-and-htb.network',
1624 '25-qdisc-ingress-netem-compat.network',
1625 '25-route-ipv6-src.network',
1626 '25-route-static.network',
1627 '25-route-vrf.network',
1628 '25-gateway-static.network',
1629 '25-gateway-next-static.network',
1630 '25-sysctl-disable-ipv6.network',
1631 '25-sysctl.network',
1632 '25-veth-peer.network',
1635 '26-link-local-addressing-ipv6.network',
1636 'configure-without-carrier.network',
1637 'routing-policy-rule-dummy98.network',
1638 'routing-policy-rule-test1.network']
1640 routing_policy_rule_tables
= ['7', '8', '9']
1641 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1644 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1645 remove_routes(self
.routes
)
1646 remove_links(self
.links
)
1647 stop_networkd(show_logs
=False)
1650 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1651 remove_routes(self
.routes
)
1652 remove_links(self
.links
)
1653 remove_unit_from_networkd_path(self
.units
)
1654 stop_networkd(show_logs
=True)
1656 def test_address_static(self
):
1657 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1660 self
.wait_online(['dummy98:routable'])
1662 output
= check_output('ip -4 address show dev dummy98')
1664 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1665 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1666 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1669 self
.assertNotRegex(output
, '10.10.0.1/16')
1670 self
.assertNotRegex(output
, '10.10.0.2/16')
1672 output
= check_output('ip -4 address show dev dummy98 label 32')
1673 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1675 output
= check_output('ip -4 address show dev dummy98 label 33')
1676 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1678 output
= check_output('ip -4 address show dev dummy98 label 34')
1679 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1681 output
= check_output('ip -4 address show dev dummy98 label 35')
1682 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1684 output
= check_output('ip -6 address show dev dummy98')
1686 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1687 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1688 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1689 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1690 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1691 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1693 def test_address_preferred_lifetime_zero_ipv6(self
):
1694 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero.network', '12-dummy.netdev')
1697 self
.wait_online(['dummy98:routable'])
1699 output
= check_output('ip address show dummy98')
1701 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1702 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1704 output
= check_output('ip route show dev dummy98')
1706 self
.assertRegex(output
, 'default via 20.20.20.1 proto static')
1708 def test_address_dad(self
):
1709 copy_unit_to_networkd_unit_path('25-address-dad-veth99.network', '25-address-dad-veth-peer.network',
1712 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
1714 output
= check_output('ip -4 address show dev veth99')
1716 self
.assertRegex(output
, '192.168.100.10/24')
1718 output
= check_output('ip -4 address show dev veth-peer')
1720 self
.assertNotRegex(output
, '192.168.100.10/24')
1722 def test_configure_without_carrier(self
):
1723 copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
1725 self
.wait_online(['test1:routable'])
1727 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
1729 self
.assertRegex(output
, '192.168.0.15')
1730 self
.assertRegex(output
, '192.168.0.1')
1731 self
.assertRegex(output
, 'routable')
1733 def test_routing_policy_rule(self
):
1734 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1736 self
.wait_online(['test1:degraded'])
1738 output
= check_output('ip rule list iif test1 priority 111')
1740 self
.assertRegex(output
, '111:')
1741 self
.assertRegex(output
, 'from 192.168.100.18')
1742 self
.assertRegex(output
, r
'tos (0x08|throughput)\s')
1743 self
.assertRegex(output
, 'iif test1')
1744 self
.assertRegex(output
, 'oif test1')
1745 self
.assertRegex(output
, 'lookup 7')
1747 output
= check_output('ip rule list iif test1 priority 101')
1749 self
.assertRegex(output
, '101:')
1750 self
.assertRegex(output
, 'from all')
1751 self
.assertRegex(output
, 'iif test1')
1752 self
.assertRegex(output
, 'lookup 9')
1754 output
= check_output('ip -6 rule list iif test1 priority 100')
1756 self
.assertRegex(output
, '100:')
1757 self
.assertRegex(output
, 'from all')
1758 self
.assertRegex(output
, 'iif test1')
1759 self
.assertRegex(output
, 'lookup 8')
1761 output
= check_output('ip -6 rule list iif test1 priority 101')
1763 self
.assertRegex(output
, '101:')
1764 self
.assertRegex(output
, 'from all')
1765 self
.assertRegex(output
, 'iif test1')
1766 self
.assertRegex(output
, 'lookup 9')
1768 def test_routing_policy_rule_issue_11280(self
):
1769 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1770 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1772 for trial
in range(3):
1773 # Remove state files only first time
1775 self
.wait_online(['test1:degraded', 'dummy98:degraded'])
1778 output
= check_output('ip rule list table 7')
1780 self
.assertRegex(output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
1782 output
= check_output('ip rule list table 8')
1784 self
.assertRegex(output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1786 stop_networkd(remove_state_files
=False)
1788 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1789 def test_routing_policy_rule_port_range(self
):
1790 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1792 self
.wait_online(['test1:degraded'])
1794 output
= check_output('ip rule')
1796 self
.assertRegex(output
, '111')
1797 self
.assertRegex(output
, 'from 192.168.100.18')
1798 self
.assertRegex(output
, '1123-1150')
1799 self
.assertRegex(output
, '3224-3290')
1800 self
.assertRegex(output
, 'tcp')
1801 self
.assertRegex(output
, 'lookup 7')
1803 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1804 def test_routing_policy_rule_invert(self
):
1805 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1807 self
.wait_online(['test1:degraded'])
1809 output
= check_output('ip rule')
1811 self
.assertRegex(output
, '111')
1812 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
1813 self
.assertRegex(output
, 'tcp')
1814 self
.assertRegex(output
, 'lookup 7')
1816 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable()
1817 def test_routing_policy_rule_uidrange(self
):
1818 copy_unit_to_networkd_unit_path('25-fibrule-uidrange.network', '11-dummy.netdev')
1820 self
.wait_online(['test1:degraded'])
1822 output
= check_output('ip rule')
1824 self
.assertRegex(output
, '111')
1825 self
.assertRegex(output
, 'from 192.168.100.18')
1826 self
.assertRegex(output
, 'lookup 7')
1827 self
.assertRegex(output
, 'uidrange 100-200')
1829 def test_route_static(self
):
1830 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1832 self
.wait_online(['dummy98:routable'])
1834 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
1837 print('### ip -6 route show dev dummy98')
1838 output
= check_output('ip -6 route show dev dummy98')
1840 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1841 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
1843 print('### ip -6 route show dev dummy98 default')
1844 output
= check_output('ip -6 route show dev dummy98 default')
1846 self
.assertRegex(output
, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1848 print('### ip -4 route show dev dummy98')
1849 output
= check_output('ip -4 route show dev dummy98')
1851 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1852 self
.assertRegex(output
, '149.10.124.64 proto static scope link')
1853 self
.assertRegex(output
, '169.254.0.0/16 proto static scope link metric 2048')
1854 self
.assertRegex(output
, '192.168.1.1 proto static initcwnd 20')
1855 self
.assertRegex(output
, '192.168.1.2 proto static initrwnd 30')
1856 self
.assertRegex(output
, 'multicast 149.10.123.4 proto static')
1858 print('### ip -4 route show dev dummy98 default')
1859 output
= check_output('ip -4 route show dev dummy98 default')
1861 self
.assertRegex(output
, 'default via 149.10.125.65 proto static onlink')
1862 self
.assertRegex(output
, 'default via 149.10.124.64 proto static')
1863 self
.assertRegex(output
, 'default proto static')
1865 print('### ip -4 route show table local dev dummy98')
1866 output
= check_output('ip -4 route show table local dev dummy98')
1868 self
.assertRegex(output
, 'local 149.10.123.1 proto static scope host')
1869 self
.assertRegex(output
, 'anycast 149.10.123.2 proto static scope link')
1870 self
.assertRegex(output
, 'broadcast 149.10.123.3 proto static scope link')
1872 print('### ip route show type blackhole')
1873 output
= check_output('ip route show type blackhole')
1875 self
.assertRegex(output
, 'blackhole 202.54.1.2 proto static')
1877 print('### ip route show type unreachable')
1878 output
= check_output('ip route show type unreachable')
1880 self
.assertRegex(output
, 'unreachable 202.54.1.3 proto static')
1882 print('### ip route show type prohibit')
1883 output
= check_output('ip route show type prohibit')
1885 self
.assertRegex(output
, 'prohibit 202.54.1.4 proto static')
1887 print('### ip route show 192.168.10.1')
1888 output
= check_output('ip route show 192.168.10.1')
1890 self
.assertRegex(output
, '192.168.10.1 proto static')
1891 self
.assertRegex(output
, 'nexthop via 149.10.124.59 dev dummy98 weight 10')
1892 self
.assertRegex(output
, 'nexthop via 149.10.124.60 dev dummy98 weight 5')
1894 print('### ip route show 192.168.10.2')
1895 output
= check_output('ip route show 192.168.10.2')
1897 # old ip command does not show IPv6 gateways...
1898 self
.assertRegex(output
, '192.168.10.2 proto static')
1899 self
.assertRegex(output
, 'nexthop')
1900 self
.assertRegex(output
, 'dev dummy98 weight 10')
1901 self
.assertRegex(output
, 'dev dummy98 weight 5')
1903 print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
1904 output
= check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
1906 # old ip command does not show 'nexthop' keyword and weight...
1907 self
.assertRegex(output
, '2001:1234:5:7fff:ff:ff:ff:ff')
1908 self
.assertRegex(output
, 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98')
1909 self
.assertRegex(output
, 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98')
1911 @expectedFailureIfModuleIsNotAvailable('vrf')
1912 def test_route_vrf(self
):
1913 copy_unit_to_networkd_unit_path('25-route-vrf.network', '12-dummy.netdev',
1914 '25-vrf.netdev', '25-vrf.network')
1916 self
.wait_online(['dummy98:routable', 'vrf99:carrier'])
1918 output
= check_output('ip route show vrf vrf99')
1920 self
.assertRegex(output
, 'default via 192.168.100.1')
1922 output
= check_output('ip route show')
1924 self
.assertNotRegex(output
, 'default via 192.168.100.1')
1926 def test_gateway_reconfigure(self
):
1927 copy_unit_to_networkd_unit_path('25-gateway-static.network', '12-dummy.netdev')
1929 self
.wait_online(['dummy98:routable'])
1930 print('### ip -4 route show dev dummy98 default')
1931 output
= check_output('ip -4 route show dev dummy98 default')
1933 self
.assertRegex(output
, 'default via 149.10.124.59 proto static')
1934 self
.assertNotRegex(output
, '149.10.124.60')
1936 remove_unit_from_networkd_path(['25-gateway-static.network'])
1937 copy_unit_to_networkd_unit_path('25-gateway-next-static.network')
1939 self
.wait_online(['dummy98:routable'])
1940 print('### ip -4 route show dev dummy98 default')
1941 output
= check_output('ip -4 route show dev dummy98 default')
1943 self
.assertNotRegex(output
, '149.10.124.59')
1944 self
.assertRegex(output
, 'default via 149.10.124.60 proto static')
1946 def test_ip_route_ipv6_src_route(self
):
1947 # a dummy device does not make the addresses go through tentative state, so we
1948 # reuse a bond from an earlier test, which does make the addresses go through
1949 # tentative state, and do our test on that
1950 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1952 self
.wait_online(['dummy98:enslaved', 'bond199:routable'])
1954 output
= check_output('ip -6 route list dev bond199')
1956 self
.assertRegex(output
, 'abcd::/16')
1957 self
.assertRegex(output
, 'src')
1958 self
.assertRegex(output
, '2001:1234:56:8f63::2')
1960 def test_ip_link_mac_address(self
):
1961 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
1963 self
.wait_online(['dummy98:degraded'])
1965 output
= check_output('ip link show dummy98')
1967 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
1969 def test_ip_link_unmanaged(self
):
1970 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
1973 self
.check_link_exists('dummy98')
1975 self
.wait_operstate('dummy98', 'off', setup_state
='unmanaged')
1977 def test_ipv6_address_label(self
):
1978 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
1980 self
.wait_online(['dummy98:degraded'])
1982 output
= check_output('ip addrlabel list')
1984 self
.assertRegex(output
, '2004:da8:1::/64')
1986 def test_neighbor_section(self
):
1987 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
1989 self
.wait_online(['dummy98:degraded'], timeout
='40s')
1991 print('### ip neigh list dev dummy98')
1992 output
= check_output('ip neigh list dev dummy98')
1994 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
1995 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
1997 def test_neighbor_reconfigure(self
):
1998 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2000 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2002 print('### ip neigh list dev dummy98')
2003 output
= check_output('ip neigh list dev dummy98')
2005 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2006 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2008 remove_unit_from_networkd_path(['25-neighbor-section.network'])
2009 copy_unit_to_networkd_unit_path('25-neighbor-next.network')
2011 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2012 print('### ip neigh list dev dummy98')
2013 output
= check_output('ip neigh list dev dummy98')
2015 self
.assertNotRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2016 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT')
2017 self
.assertNotRegex(output
, '2004:da8:1::1.*PERMANENT')
2019 def test_neighbor_gre(self
):
2020 copy_unit_to_networkd_unit_path('25-neighbor-ip.network', '25-neighbor-ipv6.network', '25-neighbor-ip-dummy.network',
2021 '12-dummy.netdev', '25-gre-tunnel-remote-any.netdev', '25-ip6gre-tunnel-remote-any.netdev')
2023 self
.wait_online(['dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable'], timeout
='40s')
2025 output
= check_output('ip neigh list dev gretun97')
2027 self
.assertRegex(output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT')
2029 output
= check_output('ip neigh list dev ip6gretun97')
2031 self
.assertRegex(output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
2033 def test_link_local_addressing(self
):
2034 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
2035 '25-link-local-addressing-no.network', '12-dummy.netdev')
2037 self
.wait_online(['test1:degraded', 'dummy98:carrier'])
2039 output
= check_output('ip address show dev test1')
2041 self
.assertRegex(output
, 'inet .* scope link')
2042 self
.assertRegex(output
, 'inet6 .* scope link')
2044 output
= check_output('ip address show dev dummy98')
2046 self
.assertNotRegex(output
, 'inet6* .* scope link')
2049 Documentation/networking/ip-sysctl.txt
2051 addr_gen_mode - INTEGER
2052 Defines how link-local and autoconf addresses are generated.
2054 0: generate address based on EUI64 (default)
2055 1: do no generate a link-local address, use EUI64 for addresses generated
2057 2: generate stable privacy addresses, using the secret from
2058 stable_secret (RFC7217)
2059 3: generate stable privacy addresses, using a random secret if unset
2062 test1_addr_gen_mode
= ''
2063 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
2064 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
2068 # if stable_secret is unset, then EIO is returned
2069 test1_addr_gen_mode
= '0'
2071 test1_addr_gen_mode
= '2'
2073 test1_addr_gen_mode
= '0'
2075 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
2076 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
2078 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
2079 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
2081 def test_link_local_addressing_remove_ipv6ll(self
):
2082 copy_unit_to_networkd_unit_path('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
2084 self
.wait_online(['dummy98:degraded'])
2086 output
= check_output('ip address show dev dummy98')
2088 self
.assertRegex(output
, 'inet6 .* scope link')
2090 copy_unit_to_networkd_unit_path('25-link-local-addressing-no.network')
2092 self
.wait_online(['dummy98:carrier'])
2094 output
= check_output('ip address show dev dummy98')
2096 self
.assertNotRegex(output
, 'inet6* .* scope link')
2098 def test_sysctl(self
):
2099 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
2101 self
.wait_online(['dummy98:degraded'])
2103 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
2104 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
2105 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
2106 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
2107 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
2108 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
2109 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
2111 def test_sysctl_disable_ipv6(self
):
2112 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
2114 print('## Disable ipv6')
2115 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
2116 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
2119 self
.wait_online(['dummy98:routable'])
2121 output
= check_output('ip -4 address show dummy98')
2123 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2124 output
= check_output('ip -6 address show dummy98')
2126 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2127 self
.assertRegex(output
, 'inet6 .* scope link')
2128 output
= check_output('ip -4 route show dev dummy98')
2130 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2131 output
= check_output('ip -6 route show dev dummy98')
2133 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2135 check_output('ip link del dummy98')
2137 print('## Enable ipv6')
2138 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
2139 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
2142 self
.wait_online(['dummy98:routable'])
2144 output
= check_output('ip -4 address show dummy98')
2146 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2147 output
= check_output('ip -6 address show dummy98')
2149 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2150 self
.assertRegex(output
, 'inet6 .* scope link')
2151 output
= check_output('ip -4 route show dev dummy98')
2153 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2154 output
= check_output('ip -6 route show dev dummy98')
2156 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2158 def test_bind_carrier(self
):
2159 check_output('ip link add dummy98 type dummy')
2160 check_output('ip link set dummy98 up')
2163 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
2165 self
.wait_online(['test1:routable'])
2167 output
= check_output('ip address show test1')
2169 self
.assertRegex(output
, 'UP,LOWER_UP')
2170 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2171 self
.wait_operstate('test1', 'routable')
2173 check_output('ip link add dummy99 type dummy')
2174 check_output('ip link set dummy99 up')
2176 output
= check_output('ip address show test1')
2178 self
.assertRegex(output
, 'UP,LOWER_UP')
2179 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2180 self
.wait_operstate('test1', 'routable')
2182 check_output('ip link del dummy98')
2184 output
= check_output('ip address show test1')
2186 self
.assertRegex(output
, 'UP,LOWER_UP')
2187 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2188 self
.wait_operstate('test1', 'routable')
2190 check_output('ip link set dummy99 down')
2192 output
= check_output('ip address show test1')
2194 self
.assertNotRegex(output
, 'UP,LOWER_UP')
2195 self
.assertRegex(output
, 'DOWN')
2196 self
.assertNotRegex(output
, '192.168.10')
2197 self
.wait_operstate('test1', 'off')
2199 check_output('ip link set dummy99 up')
2201 output
= check_output('ip address show test1')
2203 self
.assertRegex(output
, 'UP,LOWER_UP')
2204 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2205 self
.wait_operstate('test1', 'routable')
2207 def test_domain(self
):
2208 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
2210 self
.wait_online(['dummy98:routable'])
2212 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2214 self
.assertRegex(output
, 'Address: 192.168.42.100')
2215 self
.assertRegex(output
, 'DNS: 192.168.42.1')
2216 self
.assertRegex(output
, 'Search Domains: one')
2218 def test_keep_configuration_static(self
):
2219 check_output('systemctl stop systemd-networkd')
2221 check_output('ip link add name dummy98 type dummy')
2222 check_output('ip address add 10.1.2.3/16 dev dummy98')
2223 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
2224 output
= check_output('ip address show dummy98')
2226 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2227 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2228 output
= check_output('ip route show dev dummy98')
2231 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
2233 self
.wait_online(['dummy98:routable'])
2235 output
= check_output('ip address show dummy98')
2237 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2238 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2240 @expectedFailureIfNexthopIsNotAvailable()
2241 def test_nexthop(self
):
2242 copy_unit_to_networkd_unit_path('25-nexthop.network', '25-veth.netdev', '25-veth-peer.network')
2244 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2246 output
= check_output('ip nexthop list dev veth99')
2248 self
.assertRegex(output
, '192.168.5.1')
2250 def test_qdisc(self
):
2251 copy_unit_to_networkd_unit_path('25-qdisc-clsact-and-htb.network', '12-dummy.netdev',
2252 '25-qdisc-ingress-netem-compat.network', '11-dummy.netdev')
2253 check_output('modprobe sch_teql max_equalizers=2')
2256 self
.wait_online(['dummy98:routable', 'test1:routable'])
2258 output
= check_output('tc qdisc show dev test1')
2260 self
.assertRegex(output
, 'qdisc netem')
2261 self
.assertRegex(output
, 'limit 100 delay 50.0ms 10.0ms loss 20%')
2262 self
.assertRegex(output
, 'qdisc ingress')
2264 output
= check_output('tc qdisc show dev dummy98')
2266 self
.assertRegex(output
, 'qdisc clsact')
2268 self
.assertRegex(output
, 'qdisc htb 2: root')
2269 self
.assertRegex(output
, r
'default (0x30|30)')
2271 self
.assertRegex(output
, 'qdisc netem 30: parent 2:30')
2272 self
.assertRegex(output
, 'limit 100 delay 50.0ms 10.0ms loss 20%')
2273 self
.assertRegex(output
, 'qdisc fq_codel')
2274 self
.assertRegex(output
, 'limit 20480p flows 2048 quantum 1400 target 10.0ms ce_threshold 100.0ms interval 200.0ms memory_limit 64Mb ecn')
2276 self
.assertRegex(output
, 'qdisc teql1 31: parent 2:31')
2278 self
.assertRegex(output
, 'qdisc fq 32: parent 2:32')
2279 self
.assertRegex(output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
2280 self
.assertRegex(output
, 'quantum 1500')
2281 self
.assertRegex(output
, 'initial_quantum 13000')
2282 self
.assertRegex(output
, 'maxrate 1Mbit')
2284 self
.assertRegex(output
, 'qdisc codel 33: parent 2:33')
2285 self
.assertRegex(output
, 'limit 2000p target 10.0ms ce_threshold 100.0ms interval 50.0ms ecn')
2287 self
.assertRegex(output
, 'qdisc fq_codel 34: parent 2:34')
2288 self
.assertRegex(output
, 'limit 20480p flows 2048 quantum 1400 target 10.0ms ce_threshold 100.0ms interval 200.0ms memory_limit 64Mb ecn')
2290 self
.assertRegex(output
, 'qdisc tbf 35: parent 2:35')
2291 self
.assertRegex(output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70.0ms')
2293 self
.assertRegex(output
, 'qdisc sfq 36: parent 2:36')
2294 self
.assertRegex(output
, 'perturb 5sec')
2296 output
= check_output('tc class show dev dummy98')
2298 self
.assertRegex(output
, 'class htb 2:30 root leaf 30:')
2299 self
.assertRegex(output
, 'class htb 2:31 root leaf 31:')
2300 self
.assertRegex(output
, 'class htb 2:32 root leaf 32:')
2301 self
.assertRegex(output
, 'class htb 2:33 root leaf 33:')
2302 self
.assertRegex(output
, 'class htb 2:34 root leaf 34:')
2303 self
.assertRegex(output
, 'class htb 2:35 root leaf 35:')
2304 self
.assertRegex(output
, 'class htb 2:36 root leaf 36:')
2305 self
.assertRegex(output
, 'prio 1 rate 1Mbit ceil 500Kbit')
2307 class NetworkdStateFileTests(unittest
.TestCase
, Utilities
):
2314 'state-file-tests.network',
2318 remove_links(self
.links
)
2319 stop_networkd(show_logs
=False)
2322 remove_links(self
.links
)
2323 remove_unit_from_networkd_path(self
.units
)
2324 stop_networkd(show_logs
=True)
2326 def test_state_file(self
):
2327 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'state-file-tests.network')
2329 self
.wait_online(['dummy98:routable'])
2331 output
= check_output(*networkctl_cmd
, '--no-legend', 'list', 'dummy98', env
=env
)
2333 ifindex
= output
.split()[0]
2335 path
= os
.path
.join('/run/systemd/netif/links/', ifindex
)
2336 self
.assertTrue(os
.path
.exists(path
))
2339 with
open(path
) as f
:
2341 self
.assertRegex(data
, r
'ADMIN_STATE=configured')
2342 self
.assertRegex(data
, r
'OPER_STATE=routable')
2343 self
.assertRegex(data
, r
'REQUIRED_FOR_ONLINE=yes')
2344 self
.assertRegex(data
, r
'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
2345 self
.assertRegex(data
, r
'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
2346 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
2347 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2348 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2349 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2350 self
.assertRegex(data
, r
'LLMNR=no')
2351 self
.assertRegex(data
, r
'MDNS=yes')
2352 self
.assertRegex(data
, r
'DNSSEC=no')
2353 self
.assertRegex(data
, r
'ADDRESSES=192.168.(10.10|12.12)/24 192.168.(12.12|10.10)/24')
2355 check_output(*resolvectl_cmd
, 'dns', 'dummy98', '10.10.10.12', '10.10.10.13', env
=env
)
2356 check_output(*resolvectl_cmd
, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env
=env
)
2357 check_output(*resolvectl_cmd
, 'llmnr', 'dummy98', 'yes', env
=env
)
2358 check_output(*resolvectl_cmd
, 'mdns', 'dummy98', 'no', env
=env
)
2359 check_output(*resolvectl_cmd
, 'dnssec', 'dummy98', 'yes', env
=env
)
2360 check_output(*timedatectl_cmd
, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env
=env
)
2363 with
open(path
) as f
:
2365 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
2366 self
.assertRegex(data
, r
'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org')
2367 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2368 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2369 self
.assertRegex(data
, r
'LLMNR=yes')
2370 self
.assertRegex(data
, r
'MDNS=no')
2371 self
.assertRegex(data
, r
'DNSSEC=yes')
2373 check_output(*timedatectl_cmd
, 'revert', 'dummy98', env
=env
)
2376 with
open(path
) as f
:
2378 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
2379 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2380 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2381 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2382 self
.assertRegex(data
, r
'LLMNR=yes')
2383 self
.assertRegex(data
, r
'MDNS=no')
2384 self
.assertRegex(data
, r
'DNSSEC=yes')
2386 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
2389 with
open(path
) as f
:
2391 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
2392 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2393 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2394 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2395 self
.assertRegex(data
, r
'LLMNR=no')
2396 self
.assertRegex(data
, r
'MDNS=yes')
2397 self
.assertRegex(data
, r
'DNSSEC=no')
2399 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
2409 '23-active-slave.network',
2410 '23-bond199.network',
2411 '23-primary-slave.network',
2412 '25-bond-active-backup-slave.netdev',
2415 'bond-slave.network']
2418 remove_links(self
.links
)
2419 stop_networkd(show_logs
=False)
2422 remove_links(self
.links
)
2423 remove_unit_from_networkd_path(self
.units
)
2424 stop_networkd(show_logs
=True)
2426 def test_bond_active_slave(self
):
2427 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2429 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2431 output
= check_output('ip -d link show bond199')
2433 self
.assertRegex(output
, 'active_slave dummy98')
2435 def test_bond_primary_slave(self
):
2436 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2438 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2440 output
= check_output('ip -d link show bond199')
2442 self
.assertRegex(output
, 'primary dummy98')
2444 def test_bond_operstate(self
):
2445 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
2446 'bond99.network','bond-slave.network')
2448 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
2450 output
= check_output('ip -d link show dummy98')
2452 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2454 output
= check_output('ip -d link show test1')
2456 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2458 output
= check_output('ip -d link show bond99')
2460 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
2462 self
.wait_operstate('dummy98', 'enslaved')
2463 self
.wait_operstate('test1', 'enslaved')
2464 self
.wait_operstate('bond99', 'routable')
2466 check_output('ip link set dummy98 down')
2468 self
.wait_operstate('dummy98', 'off')
2469 self
.wait_operstate('test1', 'enslaved')
2470 self
.wait_operstate('bond99', 'degraded-carrier')
2472 check_output('ip link set dummy98 up')
2474 self
.wait_operstate('dummy98', 'enslaved')
2475 self
.wait_operstate('test1', 'enslaved')
2476 self
.wait_operstate('bond99', 'routable')
2478 check_output('ip link set dummy98 down')
2479 check_output('ip link set test1 down')
2481 self
.wait_operstate('dummy98', 'off')
2482 self
.wait_operstate('test1', 'off')
2484 if not self
.wait_operstate('bond99', 'no-carrier', setup_timeout
=30, fail_assert
=False):
2485 # Huh? Kernel does not recognize that all slave interfaces are down?
2486 # Let's confirm that networkd's operstate is consistent with ip's result.
2487 self
.assertNotRegex(output
, 'NO-CARRIER')
2489 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
2499 '26-bridge-slave-interface-1.network',
2500 '26-bridge-slave-interface-2.network',
2501 '26-bridge-vlan-master.network',
2502 '26-bridge-vlan-slave.network',
2503 'bridge99-ignore-carrier-loss.network',
2506 routing_policy_rule_tables
= ['100']
2509 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2510 remove_links(self
.links
)
2511 stop_networkd(show_logs
=False)
2514 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2515 remove_links(self
.links
)
2516 remove_unit_from_networkd_path(self
.units
)
2517 stop_networkd(show_logs
=True)
2519 def test_bridge_vlan(self
):
2520 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
2521 '26-bridge.netdev', '26-bridge-vlan-master.network')
2523 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
2525 output
= check_output('bridge vlan show dev test1')
2527 self
.assertNotRegex(output
, '4063')
2528 for i
in range(4064, 4095):
2529 self
.assertRegex(output
, f
'{i}')
2530 self
.assertNotRegex(output
, '4095')
2532 output
= check_output('bridge vlan show dev bridge99')
2534 self
.assertNotRegex(output
, '4059')
2535 for i
in range(4060, 4095):
2536 self
.assertRegex(output
, f
'{i}')
2537 self
.assertNotRegex(output
, '4095')
2539 def test_bridge_property(self
):
2540 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2541 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2544 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2546 output
= check_output('ip -d link show test1')
2548 self
.assertRegex(output
, 'master')
2549 self
.assertRegex(output
, 'bridge')
2551 output
= check_output('ip -d link show dummy98')
2553 self
.assertRegex(output
, 'master')
2554 self
.assertRegex(output
, 'bridge')
2556 output
= check_output('ip addr show bridge99')
2558 self
.assertRegex(output
, '192.168.0.15/24')
2560 output
= check_output('bridge -d link show dummy98')
2562 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
2563 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
2564 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
2565 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
2566 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
2567 # CONFIG_BRIDGE_IGMP_SNOOPING=y
2568 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
2569 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
2570 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
2571 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
2572 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
2573 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'priority'), '23')
2574 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard'), '1')
2575 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'root_block'), '1')
2577 output
= check_output('bridge -d link show test1')
2579 self
.assertEqual(read_bridge_port_attr('bridge99', 'test1', 'priority'), '0')
2581 check_output('ip address add 192.168.0.16/24 dev bridge99')
2584 output
= check_output('ip addr show bridge99')
2586 self
.assertRegex(output
, '192.168.0.16/24')
2589 print('### ip -6 route list table all dev bridge99')
2590 output
= check_output('ip -6 route list table all dev bridge99')
2592 self
.assertRegex(output
, 'ff00::/8 table local metric 256 pref medium')
2594 self
.assertEqual(call('ip link del test1'), 0)
2596 self
.wait_operstate('bridge99', 'degraded-carrier')
2598 check_output('ip link del dummy98')
2600 self
.wait_operstate('bridge99', 'no-carrier')
2602 output
= check_output('ip address show bridge99')
2604 self
.assertRegex(output
, 'NO-CARRIER')
2605 self
.assertNotRegex(output
, '192.168.0.15/24')
2606 self
.assertNotRegex(output
, '192.168.0.16/24')
2608 print('### ip -6 route list table all dev bridge99')
2609 output
= check_output('ip -6 route list table all dev bridge99')
2611 self
.assertRegex(output
, 'ff00::/8 table local metric 256 (linkdown )?pref medium')
2613 def test_bridge_ignore_carrier_loss(self
):
2614 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2615 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2616 'bridge99-ignore-carrier-loss.network')
2618 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2620 check_output('ip address add 192.168.0.16/24 dev bridge99')
2623 check_output('ip link del test1')
2624 check_output('ip link del dummy98')
2627 output
= check_output('ip address show bridge99')
2629 self
.assertRegex(output
, 'NO-CARRIER')
2630 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2631 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
2633 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
2634 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
2635 'bridge99-ignore-carrier-loss.network')
2637 self
.wait_online(['bridge99:no-carrier'])
2639 for trial
in range(4):
2640 check_output('ip link add dummy98 type dummy')
2641 check_output('ip link set dummy98 up')
2643 check_output('ip link del dummy98')
2645 self
.wait_online(['bridge99:routable', 'dummy98:enslaved'])
2647 output
= check_output('ip address show bridge99')
2649 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2651 output
= check_output('ip rule list table 100')
2653 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
2655 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
2659 '23-emit-lldp.network',
2664 remove_links(self
.links
)
2665 stop_networkd(show_logs
=False)
2668 remove_links(self
.links
)
2669 remove_unit_from_networkd_path(self
.units
)
2670 stop_networkd(show_logs
=True)
2672 def test_lldp(self
):
2673 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
2675 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
2677 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
2679 self
.assertRegex(output
, 'veth-peer')
2680 self
.assertRegex(output
, 'veth99')
2682 class NetworkdRATests(unittest
.TestCase
, Utilities
):
2687 'ipv6-prefix.network',
2688 'ipv6-prefix-veth.network',
2689 'ipv6-prefix-veth-token-static.network',
2690 'ipv6-prefix-veth-token-static-explicit.network',
2691 'ipv6-prefix-veth-token-static-multiple.network',
2692 'ipv6-prefix-veth-token-prefixstable.network']
2695 remove_links(self
.links
)
2696 stop_networkd(show_logs
=False)
2699 remove_links(self
.links
)
2700 remove_unit_from_networkd_path(self
.units
)
2701 stop_networkd(show_logs
=True)
2703 def test_ipv6_prefix_delegation(self
):
2704 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
2706 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2708 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
2710 self
.assertRegex(output
, 'fe80::')
2711 self
.assertRegex(output
, '2002:da8:1::1')
2713 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2715 self
.assertRegex(output
, '2002:da8:1:0')
2717 def test_ipv6_token_static(self
):
2718 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static.network')
2720 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2722 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2724 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
2726 def test_ipv6_token_static_explicit(self
):
2727 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static-explicit.network')
2729 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2731 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2733 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
2735 def test_ipv6_token_static_multiple(self
):
2736 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static-multiple.network')
2738 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2740 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2742 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
2743 self
.assertRegex(output
, '2002:da8:1:0:fa:de:ca:fe')
2745 def test_ipv6_token_prefixstable(self
):
2746 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable.network')
2748 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2750 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2752 self
.assertRegex(output
, '2002:da8:1:0')
2754 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
2759 'dhcp-client.network',
2760 'dhcp-client-timezone-router.network',
2761 'dhcp-server.network',
2762 'dhcp-server-timezone-router.network']
2765 remove_links(self
.links
)
2766 stop_networkd(show_logs
=False)
2769 remove_links(self
.links
)
2770 remove_unit_from_networkd_path(self
.units
)
2771 stop_networkd(show_logs
=True)
2773 def test_dhcp_server(self
):
2774 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
2776 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2778 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2780 self
.assertRegex(output
, '192.168.5.*')
2781 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
2782 self
.assertRegex(output
, 'DNS: 192.168.5.1')
2783 self
.assertRegex(output
, 'NTP: 192.168.5.1')
2785 def test_emit_router_timezone(self
):
2786 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
2788 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2790 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2792 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
2793 self
.assertRegex(output
, '192.168.5.*')
2794 self
.assertRegex(output
, 'Europe/Berlin')
2796 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
2805 'dhcp-client-anonymize.network',
2806 'dhcp-client-decline.network',
2807 'dhcp-client-gateway-ipv4.network',
2808 'dhcp-client-gateway-ipv6.network',
2809 'dhcp-client-gateway-onlink-implicit.network',
2810 'dhcp-client-ipv4-dhcp-settings.network',
2811 'dhcp-client-ipv4-only-ipv6-disabled.network',
2812 'dhcp-client-ipv4-only.network',
2813 'dhcp-client-ipv4-use-routes-no.network',
2814 'dhcp-client-ipv6-only.network',
2815 'dhcp-client-ipv6-rapid-commit.network',
2816 'dhcp-client-keep-configuration-dhcp-on-stop.network',
2817 'dhcp-client-keep-configuration-dhcp.network',
2818 'dhcp-client-listen-port.network',
2819 'dhcp-client-reassign-static-routes-ipv4.network',
2820 'dhcp-client-reassign-static-routes-ipv6.network',
2821 'dhcp-client-route-metric.network',
2822 'dhcp-client-route-table.network',
2823 'dhcp-client-use-dns-ipv4-and-ra.network',
2824 'dhcp-client-use-dns-ipv4.network',
2825 'dhcp-client-use-dns-no.network',
2826 'dhcp-client-use-dns-yes.network',
2827 'dhcp-client-use-domains.network',
2828 'dhcp-client-use-routes-no.network',
2829 'dhcp-client-vrf.network',
2830 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
2831 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
2832 'dhcp-client-with-static-address.network',
2833 'dhcp-client.network',
2834 'dhcp-server-decline.network',
2835 'dhcp-server-veth-peer.network',
2836 'dhcp-v4-server-veth-peer.network',
2837 'dhcp-client-use-domains.network',
2841 stop_dnsmasq(dnsmasq_pid_file
)
2842 remove_links(self
.links
)
2843 stop_networkd(show_logs
=False)
2846 stop_dnsmasq(dnsmasq_pid_file
)
2849 remove_links(self
.links
)
2850 remove_unit_from_networkd_path(self
.units
)
2851 stop_networkd(show_logs
=True)
2853 def test_dhcp_client_ipv6_only(self
):
2854 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2857 self
.wait_online(['veth-peer:carrier'])
2859 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2861 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2863 self
.assertRegex(output
, '2600::')
2864 self
.assertNotRegex(output
, '192.168.5')
2866 # Confirm that ipv6 token is not set in the kernel
2867 output
= check_output('ip token show dev veth99')
2869 self
.assertRegex(output
, 'token :: dev veth99')
2871 def test_dhcp_client_ipv4_only(self
):
2872 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
2875 self
.wait_online(['veth-peer:carrier'])
2876 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
2877 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2879 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2881 self
.assertNotRegex(output
, '2600::')
2882 self
.assertRegex(output
, '192.168.5')
2883 self
.assertRegex(output
, '192.168.5.6')
2884 self
.assertRegex(output
, '192.168.5.7')
2886 # checking routes to DNS servers
2887 output
= check_output('ip route show dev veth99')
2889 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
2890 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
2891 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
2893 stop_dnsmasq(dnsmasq_pid_file
)
2894 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8', lease_time
='2m')
2896 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2897 print('Wait for the dynamic address to be renewed')
2900 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2902 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2904 self
.assertNotRegex(output
, '2600::')
2905 self
.assertRegex(output
, '192.168.5')
2906 self
.assertNotRegex(output
, '192.168.5.6')
2907 self
.assertRegex(output
, '192.168.5.7')
2908 self
.assertRegex(output
, '192.168.5.8')
2910 # checking routes to DNS servers
2911 output
= check_output('ip route show dev veth99')
2913 self
.assertNotRegex(output
, r
'192.168.5.6')
2914 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
2915 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
2916 self
.assertRegex(output
, r
'192.168.5.8 proto dhcp scope link src 192.168.5.181 metric 1024')
2918 def test_dhcp_client_ipv4_use_routes_no(self
):
2919 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-use-routes-no.network')
2922 self
.wait_online(['veth-peer:carrier'])
2923 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
2924 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2926 output
= check_output('ip route show dev veth99')
2928 self
.assertNotRegex(output
, r
'192.168.5.5')
2929 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.181 metric 1024')
2930 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
2932 def test_dhcp_client_ipv4_ipv6(self
):
2933 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
2934 'dhcp-client-ipv4-only.network')
2936 self
.wait_online(['veth-peer:carrier'])
2938 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2940 # link become 'routable' when at least one protocol provide an valid address.
2941 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2942 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2944 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2946 self
.assertRegex(output
, '2600::')
2947 self
.assertRegex(output
, '192.168.5')
2949 def test_dhcp_client_settings(self
):
2950 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
2953 self
.wait_online(['veth-peer:carrier'])
2955 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2957 print('## ip address show dev veth99')
2958 output
= check_output('ip address show dev veth99')
2960 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2961 self
.assertRegex(output
, '192.168.5')
2962 self
.assertRegex(output
, '1492')
2964 print('## ip route show table main dev veth99')
2965 output
= check_output('ip route show table main dev veth99')
2968 main_table_is_empty
= output
== ''
2969 if not main_table_is_empty
:
2970 self
.assertNotRegex(output
, 'proto dhcp')
2972 print('## ip route show table 211 dev veth99')
2973 output
= check_output('ip route show table 211 dev veth99')
2975 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
2976 if main_table_is_empty
:
2977 self
.assertRegex(output
, '192.168.5.0/24 proto dhcp')
2978 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
2979 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
2981 print('## dnsmasq log')
2982 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
2983 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
2984 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
2985 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
2987 def test_dhcp6_client_settings_rapidcommit_true(self
):
2988 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2990 self
.wait_online(['veth-peer:carrier'])
2992 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2994 output
= check_output('ip address show dev veth99')
2996 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2997 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
2999 def test_dhcp6_client_settings_rapidcommit_false(self
):
3000 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
3002 self
.wait_online(['veth-peer:carrier'])
3004 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3006 output
= check_output('ip address show dev veth99')
3008 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3009 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
3011 def test_dhcp_client_settings_anonymize(self
):
3012 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
3014 self
.wait_online(['veth-peer:carrier'])
3016 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3018 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
3019 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
3020 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
3022 def test_dhcp_client_listen_port(self
):
3023 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
3025 self
.wait_online(['veth-peer:carrier'])
3026 start_dnsmasq('--dhcp-alternate-port=67,5555')
3027 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3029 output
= check_output('ip -4 address show dev veth99')
3031 self
.assertRegex(output
, '192.168.5.* dynamic')
3033 def test_dhcp_client_with_static_address(self
):
3034 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
3035 'dhcp-client-with-static-address.network')
3037 self
.wait_online(['veth-peer:carrier'])
3039 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3041 output
= check_output('ip address show dev veth99 scope global')
3043 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
3044 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
3046 output
= check_output('ip route show dev veth99')
3048 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
3049 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
3050 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
3051 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
3053 def test_dhcp_route_table_id(self
):
3054 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
3056 self
.wait_online(['veth-peer:carrier'])
3058 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3060 output
= check_output('ip route show table 12')
3062 self
.assertRegex(output
, 'veth99 proto dhcp')
3063 self
.assertRegex(output
, '192.168.5.1')
3065 def test_dhcp_route_metric(self
):
3066 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
3068 self
.wait_online(['veth-peer:carrier'])
3070 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3072 output
= check_output('ip route show dev veth99')
3074 self
.assertRegex(output
, 'metric 24')
3076 def test_dhcp_client_reassign_static_routes_ipv4(self
):
3077 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3078 'dhcp-client-reassign-static-routes-ipv4.network')
3080 self
.wait_online(['veth-peer:carrier'])
3081 start_dnsmasq(lease_time
='2m')
3082 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3084 output
= check_output('ip address show dev veth99 scope global')
3086 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3088 output
= check_output('ip route show dev veth99')
3090 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3091 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3092 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3093 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3095 stop_dnsmasq(dnsmasq_pid_file
)
3096 start_dnsmasq(ipv4_range
='192.168.5.210,192.168.5.220', lease_time
='2m')
3098 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3099 print('Wait for the dynamic address to be renewed')
3102 self
.wait_online(['veth99:routable'])
3104 output
= check_output('ip route show dev veth99')
3106 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3107 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3108 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3109 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3111 def test_dhcp_client_reassign_static_routes_ipv6(self
):
3112 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3113 'dhcp-client-reassign-static-routes-ipv6.network')
3115 self
.wait_online(['veth-peer:carrier'])
3116 start_dnsmasq(lease_time
='2m')
3117 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3119 output
= check_output('ip address show dev veth99 scope global')
3121 self
.assertRegex(output
, r
'inet6 2600::[0-9a-f]*/128 scope global (noprefixroute dynamic|dynamic noprefixroute)')
3123 output
= check_output('ip -6 route show dev veth99')
3125 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3126 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3128 stop_dnsmasq(dnsmasq_pid_file
)
3129 start_dnsmasq(ipv6_range
='2600::30,2600::40', lease_time
='2m')
3131 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3132 print('Wait for the dynamic address to be renewed')
3135 self
.wait_online(['veth99:routable'])
3137 output
= check_output('ip -6 route show dev veth99')
3139 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3140 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3142 def test_dhcp_keep_configuration_dhcp(self
):
3143 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
3145 self
.wait_online(['veth-peer:carrier'])
3146 start_dnsmasq(lease_time
='2m')
3147 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3149 output
= check_output('ip address show dev veth99 scope global')
3151 self
.assertRegex(output
, r
'192.168.5.*')
3153 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3155 self
.assertRegex(output
, r
'192.168.5.*')
3157 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
3158 stop_dnsmasq(dnsmasq_pid_file
)
3160 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3161 print('Wait for the dynamic address to be expired')
3164 print('The lease address should be kept after lease expired')
3165 output
= check_output('ip address show dev veth99 scope global')
3167 self
.assertRegex(output
, r
'192.168.5.*')
3169 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3171 self
.assertRegex(output
, r
'192.168.5.*')
3173 check_output('systemctl stop systemd-networkd')
3175 print('The lease address should be kept after networkd stopped')
3176 output
= check_output('ip address show dev veth99 scope global')
3178 self
.assertRegex(output
, r
'192.168.5.*')
3180 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3182 self
.assertRegex(output
, r
'192.168.5.*')
3185 self
.wait_online(['veth-peer:routable'])
3187 print('Still the lease address should be kept after networkd restarted')
3188 output
= check_output('ip address show dev veth99 scope global')
3190 self
.assertRegex(output
, r
'192.168.5.*')
3192 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3194 self
.assertRegex(output
, r
'192.168.5.*')
3196 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
3197 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
3199 self
.wait_online(['veth-peer:carrier'])
3200 start_dnsmasq(lease_time
='2m')
3201 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3203 output
= check_output('ip address show dev veth99 scope global')
3205 self
.assertRegex(output
, r
'192.168.5.*')
3207 stop_dnsmasq(dnsmasq_pid_file
)
3208 check_output('systemctl stop systemd-networkd')
3210 output
= check_output('ip address show dev veth99 scope global')
3212 self
.assertRegex(output
, r
'192.168.5.*')
3215 self
.wait_online(['veth-peer:routable'])
3217 output
= check_output('ip address show dev veth99 scope global')
3219 self
.assertNotRegex(output
, r
'192.168.5.*')
3221 def test_dhcp_client_reuse_address_as_static(self
):
3222 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
3224 self
.wait_online(['veth-peer:carrier'])
3226 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3228 # link become 'routable' when at least one protocol provide an valid address.
3229 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3230 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3232 output
= check_output('ip address show dev veth99 scope global')
3234 self
.assertRegex(output
, '192.168.5')
3235 self
.assertRegex(output
, '2600::')
3237 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
3238 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
3239 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
3240 print(static_network
)
3242 remove_unit_from_networkd_path(['dhcp-client.network'])
3244 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
3245 f
.write(static_network
)
3247 # When networkd started, the links are already configured, so let's wait for 5 seconds
3248 # the links to be re-configured.
3250 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3252 output
= check_output('ip -4 address show dev veth99 scope global')
3254 self
.assertRegex(output
, '192.168.5')
3255 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3257 output
= check_output('ip -6 address show dev veth99 scope global')
3259 self
.assertRegex(output
, '2600::')
3260 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3262 @expectedFailureIfModuleIsNotAvailable('vrf')
3263 def test_dhcp_client_vrf(self
):
3264 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
3265 '25-vrf.netdev', '25-vrf.network')
3267 self
.wait_online(['veth-peer:carrier'])
3269 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
3271 # link become 'routable' when at least one protocol provide an valid address.
3272 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3273 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3275 print('## ip -d link show dev vrf99')
3276 output
= check_output('ip -d link show dev vrf99')
3278 self
.assertRegex(output
, 'vrf table 42')
3280 print('## ip address show vrf vrf99')
3281 output
= check_output('ip address show vrf vrf99')
3283 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3284 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3285 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3286 self
.assertRegex(output
, 'inet6 .* scope link')
3288 print('## ip address show dev veth99')
3289 output
= check_output('ip address show dev veth99')
3291 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3292 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3293 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3294 self
.assertRegex(output
, 'inet6 .* scope link')
3296 print('## ip route show vrf vrf99')
3297 output
= check_output('ip route show vrf vrf99')
3299 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
3300 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
3301 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
3302 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
3303 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
3305 print('## ip route show table main dev veth99')
3306 output
= check_output('ip route show table main dev veth99')
3308 self
.assertEqual(output
, '')
3310 def test_dhcp_client_gateway_ipv4(self
):
3311 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3312 'dhcp-client-gateway-ipv4.network')
3314 self
.wait_online(['veth-peer:carrier'])
3316 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3318 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3320 self
.assertRegex(output
, '10.0.0.0/8 via 192.168.5.1 proto static')
3322 def test_dhcp_client_gateway_ipv6(self
):
3323 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3324 'dhcp-client-gateway-ipv6.network')
3326 self
.wait_online(['veth-peer:carrier'])
3328 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3330 output
= check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
3332 self
.assertRegex(output
, 'via fe80::1034:56ff:fe78:9abd')
3334 def test_dhcp_client_gateway_onlink_implicit(self
):
3335 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3336 'dhcp-client-gateway-onlink-implicit.network')
3338 self
.wait_online(['veth-peer:carrier'])
3340 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3342 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3344 self
.assertRegex(output
, '192.168.5')
3346 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3348 self
.assertRegex(output
, 'onlink')
3349 output
= check_output('ip route list dev veth99 192.168.100.0/24')
3351 self
.assertRegex(output
, 'onlink')
3353 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
3354 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3355 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
3357 self
.wait_online(['veth-peer:carrier'])
3358 start_dnsmasq(lease_time
='2m')
3359 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3361 output
= check_output('ip address show dev veth99')
3364 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3365 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3366 output
= check_output('ip -6 address show dev veth99 scope link')
3367 self
.assertRegex(output
, 'inet6 .* scope link')
3368 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3369 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3370 output
= check_output('ip -4 address show dev veth99 scope link')
3371 self
.assertNotRegex(output
, 'inet .* scope link')
3373 print('Wait for the dynamic address to be expired')
3376 output
= check_output('ip address show dev veth99')
3379 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3380 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3381 output
= check_output('ip -6 address show dev veth99 scope link')
3382 self
.assertRegex(output
, 'inet6 .* scope link')
3383 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3384 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3385 output
= check_output('ip -4 address show dev veth99 scope link')
3386 self
.assertNotRegex(output
, 'inet .* scope link')
3388 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
3390 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
3391 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3392 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
3394 self
.wait_online(['veth99:degraded', 'veth-peer:routable'])
3396 output
= check_output('ip address show dev veth99')
3399 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3400 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3401 output
= check_output('ip -6 address show dev veth99 scope link')
3402 self
.assertRegex(output
, 'inet6 .* scope link')
3403 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3404 self
.assertNotRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3405 output
= check_output('ip -4 address show dev veth99 scope link')
3406 self
.assertRegex(output
, 'inet .* scope link')
3408 def test_dhcp_client_route_remove_on_renew(self
):
3409 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3410 'dhcp-client-ipv4-only-ipv6-disabled.network')
3412 self
.wait_online(['veth-peer:carrier'])
3413 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
3414 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3416 # test for issue #12490
3418 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3420 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3422 for line
in output
.splitlines():
3423 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3424 address1
= line
.split()[1].split('/')[0]
3427 output
= check_output('ip -4 route show dev veth99')
3429 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3430 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3432 stop_dnsmasq(dnsmasq_pid_file
)
3433 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
3435 print('Wait for the dynamic address to be expired')
3438 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3440 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3442 for line
in output
.splitlines():
3443 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3444 address2
= line
.split()[1].split('/')[0]
3447 self
.assertNotEqual(address1
, address2
)
3449 output
= check_output('ip -4 route show dev veth99')
3451 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3452 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3453 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
3454 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
3456 def test_dhcp_client_use_dns_yes(self
):
3457 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-yes.network')
3460 self
.wait_online(['veth-peer:carrier'])
3461 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3462 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3464 # link become 'routable' when at least one protocol provide an valid address.
3465 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3466 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3469 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3471 self
.assertRegex(output
, '192.168.5.1')
3472 self
.assertRegex(output
, '2600::1')
3474 def test_dhcp_client_use_dns_no(self
):
3475 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-no.network')
3478 self
.wait_online(['veth-peer:carrier'])
3479 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3480 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3482 # link become 'routable' when at least one protocol provide an valid address.
3483 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3484 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3487 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3489 self
.assertNotRegex(output
, '192.168.5.1')
3490 self
.assertNotRegex(output
, '2600::1')
3492 def test_dhcp_client_use_dns_ipv4(self
):
3493 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4.network')
3496 self
.wait_online(['veth-peer:carrier'])
3497 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3498 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3500 # link become 'routable' when at least one protocol provide an valid address.
3501 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3502 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3505 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3507 self
.assertRegex(output
, '192.168.5.1')
3508 self
.assertNotRegex(output
, '2600::1')
3510 def test_dhcp_client_use_dns_ipv4_and_ra(self
):
3511 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4-and-ra.network')
3514 self
.wait_online(['veth-peer:carrier'])
3515 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3516 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3518 # link become 'routable' when at least one protocol provide an valid address.
3519 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3520 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3523 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3525 self
.assertRegex(output
, '192.168.5.1')
3526 self
.assertRegex(output
, '2600::1')
3528 def test_dhcp_client_use_domains(self
):
3529 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-domains.network')
3532 self
.wait_online(['veth-peer:carrier'])
3533 start_dnsmasq('--dhcp-option=option:domain-search,example.com')
3534 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3536 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3538 self
.assertRegex(output
, 'Search Domains: example.com')
3541 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
3543 self
.assertRegex(output
, 'example.com')
3545 def test_dhcp_client_decline(self
):
3546 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-decline.network', 'dhcp-client-decline.network')
3549 self
.wait_online(['veth-peer:carrier'])
3550 rc
= call(*wait_online_cmd
, '--timeout=10s', '--interface=veth99:routable', env
=env
)
3551 self
.assertTrue(rc
== 1)
3553 class NetworkdIPv6PrefixTests(unittest
.TestCase
, Utilities
):
3558 'ipv6ra-prefix-client.network',
3559 'ipv6ra-prefix.network'
3563 remove_links(self
.links
)
3564 stop_networkd(show_logs
=False)
3568 remove_links(self
.links
)
3569 remove_unit_from_networkd_path(self
.units
)
3570 stop_networkd(show_logs
=True)
3572 def test_ipv6_route_prefix(self
):
3573 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client.network', 'ipv6ra-prefix.network')
3576 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3578 output
= check_output('ip', '-6', 'route', 'show', 'dev', 'veth-peer')
3580 self
.assertRegex(output
, '2001:db8:0:1::/64 proto ra')
3582 class NetworkdMTUTests(unittest
.TestCase
, Utilities
):
3587 '12-dummy-mtu.netdev',
3588 '12-dummy-mtu.link',
3593 remove_links(self
.links
)
3594 stop_networkd(show_logs
=False)
3598 remove_links(self
.links
)
3599 remove_unit_from_networkd_path(self
.units
)
3600 stop_networkd(show_logs
=True)
3602 def check_mtu(self
, mtu
, ipv6_mtu
=None, reset
=True):
3608 self
.wait_online(['dummy98:routable'])
3609 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
3610 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
3612 # test normal restart
3614 self
.wait_online(['dummy98:routable'])
3615 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
3616 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
3619 self
.reset_check_mtu(mtu
, ipv6_mtu
)
3621 def reset_check_mtu(self
, mtu
, ipv6_mtu
=None):
3622 ''' test setting mtu/ipv6_mtu with interface already up '''
3625 # note - changing the device mtu resets the ipv6 mtu
3626 run('ip link set up mtu 1501 dev dummy98')
3627 run('ip link set up mtu 1500 dev dummy98')
3628 self
.assertEqual(read_link_attr('dummy98', 'mtu'), '1500')
3629 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), '1500')
3631 self
.check_mtu(mtu
, ipv6_mtu
, reset
=False)
3633 def test_mtu_network(self
):
3634 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
3635 self
.check_mtu('1600')
3637 def test_mtu_netdev(self
):
3638 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network', dropins
=False)
3639 # note - MTU set by .netdev happens ONLY at device creation!
3640 self
.check_mtu('1600', reset
=False)
3642 def test_mtu_link(self
):
3643 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', dropins
=False)
3644 # must reload udev because it only picks up new files after 3 second delay
3645 call('udevadm control --reload')
3646 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
3647 self
.check_mtu('1600', reset
=False)
3649 def test_ipv6_mtu(self
):
3650 ''' set ipv6 mtu without setting device mtu '''
3651 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
3652 self
.check_mtu('1500', '1400')
3654 def test_ipv6_mtu_toolarge(self
):
3655 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
3656 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
3657 self
.check_mtu('1500', '1500')
3659 def test_mtu_network_ipv6_mtu(self
):
3660 ''' set ipv6 mtu and set device mtu via network file '''
3661 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
3662 self
.check_mtu('1600', '1550')
3664 def test_mtu_netdev_ipv6_mtu(self
):
3665 ''' set ipv6 mtu and set device mtu via netdev file '''
3666 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
3667 self
.check_mtu('1600', '1550', reset
=False)
3669 def test_mtu_link_ipv6_mtu(self
):
3670 ''' set ipv6 mtu and set device mtu via link file '''
3671 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
3672 # must reload udev because it only picks up new files after 3 second delay
3673 call('udevadm control --reload')
3674 self
.check_mtu('1600', '1550', reset
=False)
3677 if __name__
== '__main__':
3678 parser
= argparse
.ArgumentParser()
3679 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
3680 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
3681 parser
.add_argument('--resolved', help='Path to systemd-resolved', dest
='resolved_bin')
3682 parser
.add_argument('--udevd', help='Path to systemd-udevd', dest
='udevd_bin')
3683 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
3684 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
3685 parser
.add_argument('--resolvectl', help='Path to resolvectl', dest
='resolvectl_bin')
3686 parser
.add_argument('--timedatectl', help='Path to timedatectl', dest
='timedatectl_bin')
3687 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
3688 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
3689 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
3690 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
3691 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
3692 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
3695 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
:
3696 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
3697 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
3698 resolved_bin
= os
.path
.join(ns
.build_dir
, 'systemd-resolved')
3699 udevd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-udevd')
3700 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
3701 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
3702 resolvectl_bin
= os
.path
.join(ns
.build_dir
, 'resolvectl')
3703 timedatectl_bin
= os
.path
.join(ns
.build_dir
, 'timedatectl')
3706 networkd_bin
= ns
.networkd_bin
3708 resolved_bin
= ns
.resolved_bin
3710 udevd_bin
= ns
.udevd_bin
3711 if ns
.wait_online_bin
:
3712 wait_online_bin
= ns
.wait_online_bin
3713 if ns
.networkctl_bin
:
3714 networkctl_bin
= ns
.networkctl_bin
3715 if ns
.resolvectl_bin
:
3716 resolvectl_bin
= ns
.resolvectl_bin
3717 if ns
.timedatectl_bin
:
3718 timedatectl_bin
= ns
.timedatectl_bin
3720 use_valgrind
= ns
.use_valgrind
3721 enable_debug
= ns
.enable_debug
3722 asan_options
= ns
.asan_options
3723 lsan_options
= ns
.lsan_options
3724 ubsan_options
= ns
.ubsan_options
3727 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
3728 resolvectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin
]
3729 timedatectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin
]
3730 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
3732 networkctl_cmd
= [networkctl_bin
]
3733 resolvectl_cmd
= [resolvectl_bin
]
3734 timedatectl_cmd
= [timedatectl_bin
]
3735 wait_online_cmd
= [wait_online_bin
]
3738 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
3740 env
.update({ 'ASAN_OPTIONS' : asan_options
})
3742 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
3744 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
3747 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,