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-root-compat.network',
1624 '25-qdisc-fq-codel.network',
1625 '25-qdisc-ingress-netem-compat.network',
1626 '25-qdisc-ingress-root.network',
1627 '25-qdisc-netem-and-fqcodel.network',
1628 '25-qdisc-tbf-and-sfq.network',
1629 '25-qdisc-teql.network',
1630 '25-route-ipv6-src.network',
1631 '25-route-static.network',
1632 '25-route-vrf.network',
1633 '25-gateway-static.network',
1634 '25-gateway-next-static.network',
1635 '25-sysctl-disable-ipv6.network',
1636 '25-sysctl.network',
1637 '25-veth-peer.network',
1640 '26-link-local-addressing-ipv6.network',
1641 'configure-without-carrier.network',
1642 'routing-policy-rule-dummy98.network',
1643 'routing-policy-rule-test1.network']
1645 routing_policy_rule_tables
= ['7', '8', '9']
1646 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1649 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1650 remove_routes(self
.routes
)
1651 remove_links(self
.links
)
1652 stop_networkd(show_logs
=False)
1655 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1656 remove_routes(self
.routes
)
1657 remove_links(self
.links
)
1658 remove_unit_from_networkd_path(self
.units
)
1659 stop_networkd(show_logs
=True)
1661 def test_address_static(self
):
1662 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1665 self
.wait_online(['dummy98:routable'])
1667 output
= check_output('ip -4 address show dev dummy98')
1669 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1670 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1671 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1674 self
.assertNotRegex(output
, '10.10.0.1/16')
1675 self
.assertNotRegex(output
, '10.10.0.2/16')
1677 output
= check_output('ip -4 address show dev dummy98 label 32')
1678 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1680 output
= check_output('ip -4 address show dev dummy98 label 33')
1681 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1683 output
= check_output('ip -4 address show dev dummy98 label 34')
1684 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1686 output
= check_output('ip -4 address show dev dummy98 label 35')
1687 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1689 output
= check_output('ip -6 address show dev dummy98')
1691 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1692 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1693 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1694 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1695 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1696 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1698 def test_address_preferred_lifetime_zero_ipv6(self
):
1699 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero.network', '12-dummy.netdev')
1702 self
.wait_online(['dummy98:routable'])
1704 output
= check_output('ip address show dummy98')
1706 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1707 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1709 output
= check_output('ip route show dev dummy98')
1711 self
.assertRegex(output
, 'default via 20.20.20.1 proto static')
1713 def test_address_dad(self
):
1714 copy_unit_to_networkd_unit_path('25-address-dad-veth99.network', '25-address-dad-veth-peer.network',
1717 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
1719 output
= check_output('ip -4 address show dev veth99')
1721 self
.assertRegex(output
, '192.168.100.10/24')
1723 output
= check_output('ip -4 address show dev veth-peer')
1725 self
.assertNotRegex(output
, '192.168.100.10/24')
1727 def test_configure_without_carrier(self
):
1728 copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
1730 self
.wait_online(['test1:routable'])
1732 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
1734 self
.assertRegex(output
, '192.168.0.15')
1735 self
.assertRegex(output
, '192.168.0.1')
1736 self
.assertRegex(output
, 'routable')
1738 def test_routing_policy_rule(self
):
1739 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1741 self
.wait_online(['test1:degraded'])
1743 output
= check_output('ip rule list iif test1 priority 111')
1745 self
.assertRegex(output
, '111:')
1746 self
.assertRegex(output
, 'from 192.168.100.18')
1747 self
.assertRegex(output
, r
'tos (0x08|throughput)\s')
1748 self
.assertRegex(output
, 'iif test1')
1749 self
.assertRegex(output
, 'oif test1')
1750 self
.assertRegex(output
, 'lookup 7')
1752 output
= check_output('ip rule list iif test1 priority 101')
1754 self
.assertRegex(output
, '101:')
1755 self
.assertRegex(output
, 'from all')
1756 self
.assertRegex(output
, 'iif test1')
1757 self
.assertRegex(output
, 'lookup 9')
1759 output
= check_output('ip -6 rule list iif test1 priority 100')
1761 self
.assertRegex(output
, '100:')
1762 self
.assertRegex(output
, 'from all')
1763 self
.assertRegex(output
, 'iif test1')
1764 self
.assertRegex(output
, 'lookup 8')
1766 output
= check_output('ip -6 rule list iif test1 priority 101')
1768 self
.assertRegex(output
, '101:')
1769 self
.assertRegex(output
, 'from all')
1770 self
.assertRegex(output
, 'iif test1')
1771 self
.assertRegex(output
, 'lookup 9')
1773 def test_routing_policy_rule_issue_11280(self
):
1774 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1775 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1777 for trial
in range(3):
1778 # Remove state files only first time
1780 self
.wait_online(['test1:degraded', 'dummy98:degraded'])
1783 output
= check_output('ip rule list table 7')
1785 self
.assertRegex(output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
1787 output
= check_output('ip rule list table 8')
1789 self
.assertRegex(output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1791 stop_networkd(remove_state_files
=False)
1793 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1794 def test_routing_policy_rule_port_range(self
):
1795 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1797 self
.wait_online(['test1:degraded'])
1799 output
= check_output('ip rule')
1801 self
.assertRegex(output
, '111')
1802 self
.assertRegex(output
, 'from 192.168.100.18')
1803 self
.assertRegex(output
, '1123-1150')
1804 self
.assertRegex(output
, '3224-3290')
1805 self
.assertRegex(output
, 'tcp')
1806 self
.assertRegex(output
, 'lookup 7')
1808 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1809 def test_routing_policy_rule_invert(self
):
1810 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1812 self
.wait_online(['test1:degraded'])
1814 output
= check_output('ip rule')
1816 self
.assertRegex(output
, '111')
1817 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
1818 self
.assertRegex(output
, 'tcp')
1819 self
.assertRegex(output
, 'lookup 7')
1821 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable()
1822 def test_routing_policy_rule_uidrange(self
):
1823 copy_unit_to_networkd_unit_path('25-fibrule-uidrange.network', '11-dummy.netdev')
1825 self
.wait_online(['test1:degraded'])
1827 output
= check_output('ip rule')
1829 self
.assertRegex(output
, '111')
1830 self
.assertRegex(output
, 'from 192.168.100.18')
1831 self
.assertRegex(output
, 'lookup 7')
1832 self
.assertRegex(output
, 'uidrange 100-200')
1834 def test_route_static(self
):
1835 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1837 self
.wait_online(['dummy98:routable'])
1839 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
1842 print('### ip -6 route show dev dummy98')
1843 output
= check_output('ip -6 route show dev dummy98')
1845 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1846 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
1848 print('### ip -6 route show dev dummy98 default')
1849 output
= check_output('ip -6 route show dev dummy98 default')
1851 self
.assertRegex(output
, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1853 print('### ip -4 route show dev dummy98')
1854 output
= check_output('ip -4 route show dev dummy98')
1856 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1857 self
.assertRegex(output
, '149.10.124.64 proto static scope link')
1858 self
.assertRegex(output
, '169.254.0.0/16 proto static scope link metric 2048')
1859 self
.assertRegex(output
, '192.168.1.1 proto static initcwnd 20')
1860 self
.assertRegex(output
, '192.168.1.2 proto static initrwnd 30')
1861 self
.assertRegex(output
, 'multicast 149.10.123.4 proto static')
1863 print('### ip -4 route show dev dummy98 default')
1864 output
= check_output('ip -4 route show dev dummy98 default')
1866 self
.assertRegex(output
, 'default via 149.10.125.65 proto static onlink')
1867 self
.assertRegex(output
, 'default via 149.10.124.64 proto static')
1868 self
.assertRegex(output
, 'default proto static')
1870 print('### ip -4 route show table local dev dummy98')
1871 output
= check_output('ip -4 route show table local dev dummy98')
1873 self
.assertRegex(output
, 'local 149.10.123.1 proto static scope host')
1874 self
.assertRegex(output
, 'anycast 149.10.123.2 proto static scope link')
1875 self
.assertRegex(output
, 'broadcast 149.10.123.3 proto static scope link')
1877 print('### ip route show type blackhole')
1878 output
= check_output('ip route show type blackhole')
1880 self
.assertRegex(output
, 'blackhole 202.54.1.2 proto static')
1882 print('### ip route show type unreachable')
1883 output
= check_output('ip route show type unreachable')
1885 self
.assertRegex(output
, 'unreachable 202.54.1.3 proto static')
1887 print('### ip route show type prohibit')
1888 output
= check_output('ip route show type prohibit')
1890 self
.assertRegex(output
, 'prohibit 202.54.1.4 proto static')
1892 print('### ip route show 192.168.10.1')
1893 output
= check_output('ip route show 192.168.10.1')
1895 self
.assertRegex(output
, '192.168.10.1 proto static')
1896 self
.assertRegex(output
, 'nexthop via 149.10.124.59 dev dummy98 weight 10')
1897 self
.assertRegex(output
, 'nexthop via 149.10.124.60 dev dummy98 weight 5')
1899 print('### ip route show 192.168.10.2')
1900 output
= check_output('ip route show 192.168.10.2')
1902 # old ip command does not show IPv6 gateways...
1903 self
.assertRegex(output
, '192.168.10.2 proto static')
1904 self
.assertRegex(output
, 'nexthop')
1905 self
.assertRegex(output
, 'dev dummy98 weight 10')
1906 self
.assertRegex(output
, 'dev dummy98 weight 5')
1908 print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
1909 output
= check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
1911 # old ip command does not show 'nexthop' keyword and weight...
1912 self
.assertRegex(output
, '2001:1234:5:7fff:ff:ff:ff:ff')
1913 self
.assertRegex(output
, 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98')
1914 self
.assertRegex(output
, 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98')
1916 @expectedFailureIfModuleIsNotAvailable('vrf')
1917 def test_route_vrf(self
):
1918 copy_unit_to_networkd_unit_path('25-route-vrf.network', '12-dummy.netdev',
1919 '25-vrf.netdev', '25-vrf.network')
1921 self
.wait_online(['dummy98:routable', 'vrf99:carrier'])
1923 output
= check_output('ip route show vrf vrf99')
1925 self
.assertRegex(output
, 'default via 192.168.100.1')
1927 output
= check_output('ip route show')
1929 self
.assertNotRegex(output
, 'default via 192.168.100.1')
1931 def test_gateway_reconfigure(self
):
1932 copy_unit_to_networkd_unit_path('25-gateway-static.network', '12-dummy.netdev')
1934 self
.wait_online(['dummy98:routable'])
1935 print('### ip -4 route show dev dummy98 default')
1936 output
= check_output('ip -4 route show dev dummy98 default')
1938 self
.assertRegex(output
, 'default via 149.10.124.59 proto static')
1939 self
.assertNotRegex(output
, '149.10.124.60')
1941 remove_unit_from_networkd_path(['25-gateway-static.network'])
1942 copy_unit_to_networkd_unit_path('25-gateway-next-static.network')
1944 self
.wait_online(['dummy98:routable'])
1945 print('### ip -4 route show dev dummy98 default')
1946 output
= check_output('ip -4 route show dev dummy98 default')
1948 self
.assertNotRegex(output
, '149.10.124.59')
1949 self
.assertRegex(output
, 'default via 149.10.124.60 proto static')
1951 def test_ip_route_ipv6_src_route(self
):
1952 # a dummy device does not make the addresses go through tentative state, so we
1953 # reuse a bond from an earlier test, which does make the addresses go through
1954 # tentative state, and do our test on that
1955 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1957 self
.wait_online(['dummy98:enslaved', 'bond199:routable'])
1959 output
= check_output('ip -6 route list dev bond199')
1961 self
.assertRegex(output
, 'abcd::/16')
1962 self
.assertRegex(output
, 'src')
1963 self
.assertRegex(output
, '2001:1234:56:8f63::2')
1965 def test_ip_link_mac_address(self
):
1966 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
1968 self
.wait_online(['dummy98:degraded'])
1970 output
= check_output('ip link show dummy98')
1972 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
1974 def test_ip_link_unmanaged(self
):
1975 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
1978 self
.check_link_exists('dummy98')
1980 self
.wait_operstate('dummy98', 'off', setup_state
='unmanaged')
1982 def test_ipv6_address_label(self
):
1983 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
1985 self
.wait_online(['dummy98:degraded'])
1987 output
= check_output('ip addrlabel list')
1989 self
.assertRegex(output
, '2004:da8:1::/64')
1991 def test_neighbor_section(self
):
1992 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
1994 self
.wait_online(['dummy98:degraded'], timeout
='40s')
1996 print('### ip neigh list dev dummy98')
1997 output
= check_output('ip neigh list dev dummy98')
1999 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2000 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2002 def test_neighbor_reconfigure(self
):
2003 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2005 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2007 print('### ip neigh list dev dummy98')
2008 output
= check_output('ip neigh list dev dummy98')
2010 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2011 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2013 remove_unit_from_networkd_path(['25-neighbor-section.network'])
2014 copy_unit_to_networkd_unit_path('25-neighbor-next.network')
2016 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2017 print('### ip neigh list dev dummy98')
2018 output
= check_output('ip neigh list dev dummy98')
2020 self
.assertNotRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2021 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT')
2022 self
.assertNotRegex(output
, '2004:da8:1::1.*PERMANENT')
2024 def test_neighbor_gre(self
):
2025 copy_unit_to_networkd_unit_path('25-neighbor-ip.network', '25-neighbor-ipv6.network', '25-neighbor-ip-dummy.network',
2026 '12-dummy.netdev', '25-gre-tunnel-remote-any.netdev', '25-ip6gre-tunnel-remote-any.netdev')
2028 self
.wait_online(['dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable'], timeout
='40s')
2030 output
= check_output('ip neigh list dev gretun97')
2032 self
.assertRegex(output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT')
2034 output
= check_output('ip neigh list dev ip6gretun97')
2036 self
.assertRegex(output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
2038 def test_link_local_addressing(self
):
2039 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
2040 '25-link-local-addressing-no.network', '12-dummy.netdev')
2042 self
.wait_online(['test1:degraded', 'dummy98:carrier'])
2044 output
= check_output('ip address show dev test1')
2046 self
.assertRegex(output
, 'inet .* scope link')
2047 self
.assertRegex(output
, 'inet6 .* scope link')
2049 output
= check_output('ip address show dev dummy98')
2051 self
.assertNotRegex(output
, 'inet6* .* scope link')
2054 Documentation/networking/ip-sysctl.txt
2056 addr_gen_mode - INTEGER
2057 Defines how link-local and autoconf addresses are generated.
2059 0: generate address based on EUI64 (default)
2060 1: do no generate a link-local address, use EUI64 for addresses generated
2062 2: generate stable privacy addresses, using the secret from
2063 stable_secret (RFC7217)
2064 3: generate stable privacy addresses, using a random secret if unset
2067 test1_addr_gen_mode
= ''
2068 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
2069 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
2073 # if stable_secret is unset, then EIO is returned
2074 test1_addr_gen_mode
= '0'
2076 test1_addr_gen_mode
= '2'
2078 test1_addr_gen_mode
= '0'
2080 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
2081 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
2083 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
2084 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
2086 def test_link_local_addressing_remove_ipv6ll(self
):
2087 copy_unit_to_networkd_unit_path('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
2089 self
.wait_online(['dummy98:degraded'])
2091 output
= check_output('ip address show dev dummy98')
2093 self
.assertRegex(output
, 'inet6 .* scope link')
2095 copy_unit_to_networkd_unit_path('25-link-local-addressing-no.network')
2097 self
.wait_online(['dummy98:carrier'])
2099 output
= check_output('ip address show dev dummy98')
2101 self
.assertNotRegex(output
, 'inet6* .* scope link')
2103 def test_sysctl(self
):
2104 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
2106 self
.wait_online(['dummy98:degraded'])
2108 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
2109 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
2110 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
2111 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
2112 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
2113 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
2114 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
2116 def test_sysctl_disable_ipv6(self
):
2117 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
2119 print('## Disable ipv6')
2120 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
2121 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
2124 self
.wait_online(['dummy98:routable'])
2126 output
= check_output('ip -4 address show dummy98')
2128 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2129 output
= check_output('ip -6 address show dummy98')
2131 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2132 self
.assertRegex(output
, 'inet6 .* scope link')
2133 output
= check_output('ip -4 route show dev dummy98')
2135 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2136 output
= check_output('ip -6 route show dev dummy98')
2138 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2140 check_output('ip link del dummy98')
2142 print('## Enable ipv6')
2143 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
2144 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
2147 self
.wait_online(['dummy98:routable'])
2149 output
= check_output('ip -4 address show dummy98')
2151 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2152 output
= check_output('ip -6 address show dummy98')
2154 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2155 self
.assertRegex(output
, 'inet6 .* scope link')
2156 output
= check_output('ip -4 route show dev dummy98')
2158 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2159 output
= check_output('ip -6 route show dev dummy98')
2161 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2163 def test_bind_carrier(self
):
2164 check_output('ip link add dummy98 type dummy')
2165 check_output('ip link set dummy98 up')
2168 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
2170 self
.wait_online(['test1:routable'])
2172 output
= check_output('ip address show test1')
2174 self
.assertRegex(output
, 'UP,LOWER_UP')
2175 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2176 self
.wait_operstate('test1', 'routable')
2178 check_output('ip link add dummy99 type dummy')
2179 check_output('ip link set dummy99 up')
2181 output
= check_output('ip address show test1')
2183 self
.assertRegex(output
, 'UP,LOWER_UP')
2184 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2185 self
.wait_operstate('test1', 'routable')
2187 check_output('ip link del dummy98')
2189 output
= check_output('ip address show test1')
2191 self
.assertRegex(output
, 'UP,LOWER_UP')
2192 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2193 self
.wait_operstate('test1', 'routable')
2195 check_output('ip link set dummy99 down')
2197 output
= check_output('ip address show test1')
2199 self
.assertNotRegex(output
, 'UP,LOWER_UP')
2200 self
.assertRegex(output
, 'DOWN')
2201 self
.assertNotRegex(output
, '192.168.10')
2202 self
.wait_operstate('test1', 'off')
2204 check_output('ip link set dummy99 up')
2206 output
= check_output('ip address show test1')
2208 self
.assertRegex(output
, 'UP,LOWER_UP')
2209 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2210 self
.wait_operstate('test1', 'routable')
2212 def test_domain(self
):
2213 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
2215 self
.wait_online(['dummy98:routable'])
2217 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2219 self
.assertRegex(output
, 'Address: 192.168.42.100')
2220 self
.assertRegex(output
, 'DNS: 192.168.42.1')
2221 self
.assertRegex(output
, 'Search Domains: one')
2223 def test_keep_configuration_static(self
):
2224 check_output('systemctl stop systemd-networkd')
2226 check_output('ip link add name dummy98 type dummy')
2227 check_output('ip address add 10.1.2.3/16 dev dummy98')
2228 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
2229 output
= check_output('ip address show dummy98')
2231 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2232 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2233 output
= check_output('ip route show dev dummy98')
2236 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
2238 self
.wait_online(['dummy98:routable'])
2240 output
= check_output('ip address show dummy98')
2242 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2243 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2245 @expectedFailureIfNexthopIsNotAvailable()
2246 def test_nexthop(self
):
2247 copy_unit_to_networkd_unit_path('25-nexthop.network', '25-veth.netdev', '25-veth-peer.network')
2249 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2251 output
= check_output('ip nexthop list dev veth99')
2253 self
.assertRegex(output
, '192.168.5.1')
2255 def test_qdisc(self
):
2256 copy_unit_to_networkd_unit_path('25-qdisc-netem-and-fqcodel.network', '12-dummy.netdev',
2257 '25-qdisc-tbf-and-sfq.network', '11-dummy.netdev')
2260 self
.wait_online(['dummy98:routable', 'test1:routable'])
2262 output
= check_output('tc qdisc show dev dummy98')
2264 self
.assertRegex(output
, 'qdisc netem 1f:')
2265 self
.assertRegex(output
, 'limit 100 delay 50.0ms 10.0ms loss 20%')
2266 self
.assertRegex(output
, 'qdisc fq_codel')
2267 self
.assertRegex(output
, 'limit 20480p flows 2048 quantum 1400 target 10.0ms ce_threshold 100.0ms interval 200.0ms memory_limit 64Mb ecn')
2268 output
= check_output('tc qdisc show dev test1')
2270 self
.assertRegex(output
, 'qdisc tbf 3f:')
2271 self
.assertRegex(output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70.0ms')
2272 self
.assertRegex(output
, 'qdisc sfq')
2273 self
.assertRegex(output
, 'perturb 5sec')
2275 def test_qdisc2(self
):
2276 copy_unit_to_networkd_unit_path('25-qdisc-fq-codel.network', '12-dummy.netdev',
2277 '25-qdisc-ingress-root.network', '11-dummy.netdev')
2280 self
.wait_online(['dummy98:routable', 'test1:routable'])
2282 output
= check_output('tc qdisc show dev dummy98')
2284 self
.assertRegex(output
, 'qdisc fq 3:')
2285 self
.assertRegex(output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
2286 self
.assertRegex(output
, 'quantum 1500')
2287 self
.assertRegex(output
, 'initial_quantum 13000')
2288 self
.assertRegex(output
, 'maxrate 1Mbit')
2289 self
.assertRegex(output
, 'qdisc codel')
2290 self
.assertRegex(output
, 'limit 2000p target 10.0ms ce_threshold 100.0ms interval 50.0ms ecn')
2291 output
= check_output('tc qdisc show dev test1')
2293 self
.assertRegex(output
, 'qdisc ingress')
2295 def test_qdisc3(self
):
2296 copy_unit_to_networkd_unit_path('25-qdisc-clsact-root-compat.network', '12-dummy.netdev',
2297 '25-qdisc-ingress-netem-compat.network', '11-dummy.netdev')
2300 self
.wait_online(['dummy98:routable', 'test1:routable'])
2302 output
= check_output('tc qdisc show dev dummy98')
2304 self
.assertRegex(output
, 'qdisc clsact')
2305 output
= check_output('tc qdisc show dev test1')
2307 self
.assertRegex(output
, 'qdisc netem')
2308 self
.assertRegex(output
, 'limit 100 delay 50.0ms 10.0ms loss 20%')
2309 self
.assertRegex(output
, 'qdisc ingress')
2311 def test_qdisc4(self
):
2312 copy_unit_to_networkd_unit_path('25-qdisc-teql.network', '12-dummy.netdev')
2313 check_output('modprobe sch_teql max_equalizers=2')
2316 self
.wait_online(['dummy98:routable'])
2318 output
= check_output('tc qdisc show dev dummy98')
2320 self
.assertRegex(output
, 'qdisc teql1 2:')
2322 class NetworkdStateFileTests(unittest
.TestCase
, Utilities
):
2329 'state-file-tests.network',
2333 remove_links(self
.links
)
2334 stop_networkd(show_logs
=False)
2337 remove_links(self
.links
)
2338 remove_unit_from_networkd_path(self
.units
)
2339 stop_networkd(show_logs
=True)
2341 def test_state_file(self
):
2342 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'state-file-tests.network')
2344 self
.wait_online(['dummy98:routable'])
2346 output
= check_output(*networkctl_cmd
, '--no-legend', 'list', 'dummy98', env
=env
)
2348 ifindex
= output
.split()[0]
2350 path
= os
.path
.join('/run/systemd/netif/links/', ifindex
)
2351 self
.assertTrue(os
.path
.exists(path
))
2354 with
open(path
) as f
:
2356 self
.assertRegex(data
, r
'ADMIN_STATE=configured')
2357 self
.assertRegex(data
, r
'OPER_STATE=routable')
2358 self
.assertRegex(data
, r
'REQUIRED_FOR_ONLINE=yes')
2359 self
.assertRegex(data
, r
'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
2360 self
.assertRegex(data
, r
'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
2361 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
2362 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2363 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2364 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2365 self
.assertRegex(data
, r
'LLMNR=no')
2366 self
.assertRegex(data
, r
'MDNS=yes')
2367 self
.assertRegex(data
, r
'DNSSEC=no')
2368 self
.assertRegex(data
, r
'ADDRESSES=192.168.(10.10|12.12)/24 192.168.(12.12|10.10)/24')
2370 check_output(*resolvectl_cmd
, 'dns', 'dummy98', '10.10.10.12', '10.10.10.13', env
=env
)
2371 check_output(*resolvectl_cmd
, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env
=env
)
2372 check_output(*resolvectl_cmd
, 'llmnr', 'dummy98', 'yes', env
=env
)
2373 check_output(*resolvectl_cmd
, 'mdns', 'dummy98', 'no', env
=env
)
2374 check_output(*resolvectl_cmd
, 'dnssec', 'dummy98', 'yes', env
=env
)
2375 check_output(*timedatectl_cmd
, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env
=env
)
2378 with
open(path
) as f
:
2380 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
2381 self
.assertRegex(data
, r
'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org')
2382 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2383 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2384 self
.assertRegex(data
, r
'LLMNR=yes')
2385 self
.assertRegex(data
, r
'MDNS=no')
2386 self
.assertRegex(data
, r
'DNSSEC=yes')
2388 check_output(*timedatectl_cmd
, 'revert', 'dummy98', env
=env
)
2391 with
open(path
) as f
:
2393 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
2394 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2395 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2396 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2397 self
.assertRegex(data
, r
'LLMNR=yes')
2398 self
.assertRegex(data
, r
'MDNS=no')
2399 self
.assertRegex(data
, r
'DNSSEC=yes')
2401 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
2404 with
open(path
) as f
:
2406 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
2407 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2408 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2409 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2410 self
.assertRegex(data
, r
'LLMNR=no')
2411 self
.assertRegex(data
, r
'MDNS=yes')
2412 self
.assertRegex(data
, r
'DNSSEC=no')
2414 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
2424 '23-active-slave.network',
2425 '23-bond199.network',
2426 '23-primary-slave.network',
2427 '25-bond-active-backup-slave.netdev',
2430 'bond-slave.network']
2433 remove_links(self
.links
)
2434 stop_networkd(show_logs
=False)
2437 remove_links(self
.links
)
2438 remove_unit_from_networkd_path(self
.units
)
2439 stop_networkd(show_logs
=True)
2441 def test_bond_active_slave(self
):
2442 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2444 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2446 output
= check_output('ip -d link show bond199')
2448 self
.assertRegex(output
, 'active_slave dummy98')
2450 def test_bond_primary_slave(self
):
2451 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2453 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2455 output
= check_output('ip -d link show bond199')
2457 self
.assertRegex(output
, 'primary dummy98')
2459 def test_bond_operstate(self
):
2460 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
2461 'bond99.network','bond-slave.network')
2463 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
2465 output
= check_output('ip -d link show dummy98')
2467 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2469 output
= check_output('ip -d link show test1')
2471 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2473 output
= check_output('ip -d link show bond99')
2475 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
2477 self
.wait_operstate('dummy98', 'enslaved')
2478 self
.wait_operstate('test1', 'enslaved')
2479 self
.wait_operstate('bond99', 'routable')
2481 check_output('ip link set dummy98 down')
2483 self
.wait_operstate('dummy98', 'off')
2484 self
.wait_operstate('test1', 'enslaved')
2485 self
.wait_operstate('bond99', 'degraded-carrier')
2487 check_output('ip link set dummy98 up')
2489 self
.wait_operstate('dummy98', 'enslaved')
2490 self
.wait_operstate('test1', 'enslaved')
2491 self
.wait_operstate('bond99', 'routable')
2493 check_output('ip link set dummy98 down')
2494 check_output('ip link set test1 down')
2496 self
.wait_operstate('dummy98', 'off')
2497 self
.wait_operstate('test1', 'off')
2499 if not self
.wait_operstate('bond99', 'no-carrier', setup_timeout
=30, fail_assert
=False):
2500 # Huh? Kernel does not recognize that all slave interfaces are down?
2501 # Let's confirm that networkd's operstate is consistent with ip's result.
2502 self
.assertNotRegex(output
, 'NO-CARRIER')
2504 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
2514 '26-bridge-slave-interface-1.network',
2515 '26-bridge-slave-interface-2.network',
2516 '26-bridge-vlan-master.network',
2517 '26-bridge-vlan-slave.network',
2518 'bridge99-ignore-carrier-loss.network',
2521 routing_policy_rule_tables
= ['100']
2524 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2525 remove_links(self
.links
)
2526 stop_networkd(show_logs
=False)
2529 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2530 remove_links(self
.links
)
2531 remove_unit_from_networkd_path(self
.units
)
2532 stop_networkd(show_logs
=True)
2534 def test_bridge_vlan(self
):
2535 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
2536 '26-bridge.netdev', '26-bridge-vlan-master.network')
2538 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
2540 output
= check_output('bridge vlan show dev test1')
2542 self
.assertNotRegex(output
, '4063')
2543 for i
in range(4064, 4095):
2544 self
.assertRegex(output
, f
'{i}')
2545 self
.assertNotRegex(output
, '4095')
2547 output
= check_output('bridge vlan show dev bridge99')
2549 self
.assertNotRegex(output
, '4059')
2550 for i
in range(4060, 4095):
2551 self
.assertRegex(output
, f
'{i}')
2552 self
.assertNotRegex(output
, '4095')
2554 def test_bridge_property(self
):
2555 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2556 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2559 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2561 output
= check_output('ip -d link show test1')
2563 self
.assertRegex(output
, 'master')
2564 self
.assertRegex(output
, 'bridge')
2566 output
= check_output('ip -d link show dummy98')
2568 self
.assertRegex(output
, 'master')
2569 self
.assertRegex(output
, 'bridge')
2571 output
= check_output('ip addr show bridge99')
2573 self
.assertRegex(output
, '192.168.0.15/24')
2575 output
= check_output('bridge -d link show dummy98')
2577 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
2578 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
2579 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
2580 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
2581 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
2582 # CONFIG_BRIDGE_IGMP_SNOOPING=y
2583 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
2584 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
2585 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
2586 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
2587 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
2588 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'priority'), '23')
2589 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard'), '1')
2590 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'root_block'), '1')
2592 output
= check_output('bridge -d link show test1')
2594 self
.assertEqual(read_bridge_port_attr('bridge99', 'test1', 'priority'), '0')
2596 check_output('ip address add 192.168.0.16/24 dev bridge99')
2599 output
= check_output('ip addr show bridge99')
2601 self
.assertRegex(output
, '192.168.0.16/24')
2604 print('### ip -6 route list table all dev bridge99')
2605 output
= check_output('ip -6 route list table all dev bridge99')
2607 self
.assertRegex(output
, 'ff00::/8 table local metric 256 pref medium')
2609 self
.assertEqual(call('ip link del test1'), 0)
2611 self
.wait_operstate('bridge99', 'degraded-carrier')
2613 check_output('ip link del dummy98')
2615 self
.wait_operstate('bridge99', 'no-carrier')
2617 output
= check_output('ip address show bridge99')
2619 self
.assertRegex(output
, 'NO-CARRIER')
2620 self
.assertNotRegex(output
, '192.168.0.15/24')
2621 self
.assertNotRegex(output
, '192.168.0.16/24')
2623 print('### ip -6 route list table all dev bridge99')
2624 output
= check_output('ip -6 route list table all dev bridge99')
2626 self
.assertRegex(output
, 'ff00::/8 table local metric 256 (linkdown )?pref medium')
2628 def test_bridge_ignore_carrier_loss(self
):
2629 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2630 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2631 'bridge99-ignore-carrier-loss.network')
2633 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2635 check_output('ip address add 192.168.0.16/24 dev bridge99')
2638 check_output('ip link del test1')
2639 check_output('ip link del dummy98')
2642 output
= check_output('ip address show bridge99')
2644 self
.assertRegex(output
, 'NO-CARRIER')
2645 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2646 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
2648 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
2649 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
2650 'bridge99-ignore-carrier-loss.network')
2652 self
.wait_online(['bridge99:no-carrier'])
2654 for trial
in range(4):
2655 check_output('ip link add dummy98 type dummy')
2656 check_output('ip link set dummy98 up')
2658 check_output('ip link del dummy98')
2660 self
.wait_online(['bridge99:routable', 'dummy98:enslaved'])
2662 output
= check_output('ip address show bridge99')
2664 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2666 output
= check_output('ip rule list table 100')
2668 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
2670 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
2674 '23-emit-lldp.network',
2679 remove_links(self
.links
)
2680 stop_networkd(show_logs
=False)
2683 remove_links(self
.links
)
2684 remove_unit_from_networkd_path(self
.units
)
2685 stop_networkd(show_logs
=True)
2687 def test_lldp(self
):
2688 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
2690 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
2692 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
2694 self
.assertRegex(output
, 'veth-peer')
2695 self
.assertRegex(output
, 'veth99')
2697 class NetworkdRATests(unittest
.TestCase
, Utilities
):
2702 'ipv6-prefix.network',
2703 'ipv6-prefix-veth.network',
2704 'ipv6-prefix-veth-token-static.network',
2705 'ipv6-prefix-veth-token-static-explicit.network',
2706 'ipv6-prefix-veth-token-static-multiple.network',
2707 'ipv6-prefix-veth-token-prefixstable.network']
2710 remove_links(self
.links
)
2711 stop_networkd(show_logs
=False)
2714 remove_links(self
.links
)
2715 remove_unit_from_networkd_path(self
.units
)
2716 stop_networkd(show_logs
=True)
2718 def test_ipv6_prefix_delegation(self
):
2719 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
2721 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2723 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
2725 self
.assertRegex(output
, 'fe80::')
2726 self
.assertRegex(output
, '2002:da8:1::1')
2728 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2730 self
.assertRegex(output
, '2002:da8:1:0')
2732 def test_ipv6_token_static(self
):
2733 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static.network')
2735 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2737 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2739 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
2741 def test_ipv6_token_static_explicit(self
):
2742 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static-explicit.network')
2744 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2746 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2748 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
2750 def test_ipv6_token_static_multiple(self
):
2751 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static-multiple.network')
2753 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2755 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2757 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
2758 self
.assertRegex(output
, '2002:da8:1:0:fa:de:ca:fe')
2760 def test_ipv6_token_prefixstable(self
):
2761 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable.network')
2763 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2765 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2767 self
.assertRegex(output
, '2002:da8:1:0')
2769 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
2774 'dhcp-client.network',
2775 'dhcp-client-timezone-router.network',
2776 'dhcp-server.network',
2777 'dhcp-server-timezone-router.network']
2780 remove_links(self
.links
)
2781 stop_networkd(show_logs
=False)
2784 remove_links(self
.links
)
2785 remove_unit_from_networkd_path(self
.units
)
2786 stop_networkd(show_logs
=True)
2788 def test_dhcp_server(self
):
2789 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
2791 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2793 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2795 self
.assertRegex(output
, '192.168.5.*')
2796 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
2797 self
.assertRegex(output
, 'DNS: 192.168.5.1')
2798 self
.assertRegex(output
, 'NTP: 192.168.5.1')
2800 def test_emit_router_timezone(self
):
2801 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
2803 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2805 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2807 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
2808 self
.assertRegex(output
, '192.168.5.*')
2809 self
.assertRegex(output
, 'Europe/Berlin')
2811 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
2820 'dhcp-client-anonymize.network',
2821 'dhcp-client-decline.network',
2822 'dhcp-client-gateway-ipv4.network',
2823 'dhcp-client-gateway-ipv6.network',
2824 'dhcp-client-gateway-onlink-implicit.network',
2825 'dhcp-client-ipv4-dhcp-settings.network',
2826 'dhcp-client-ipv4-only-ipv6-disabled.network',
2827 'dhcp-client-ipv4-only.network',
2828 'dhcp-client-ipv4-use-routes-no.network',
2829 'dhcp-client-ipv6-only.network',
2830 'dhcp-client-ipv6-rapid-commit.network',
2831 'dhcp-client-keep-configuration-dhcp-on-stop.network',
2832 'dhcp-client-keep-configuration-dhcp.network',
2833 'dhcp-client-listen-port.network',
2834 'dhcp-client-reassign-static-routes-ipv4.network',
2835 'dhcp-client-reassign-static-routes-ipv6.network',
2836 'dhcp-client-route-metric.network',
2837 'dhcp-client-route-table.network',
2838 'dhcp-client-use-dns-ipv4-and-ra.network',
2839 'dhcp-client-use-dns-ipv4.network',
2840 'dhcp-client-use-dns-no.network',
2841 'dhcp-client-use-dns-yes.network',
2842 'dhcp-client-use-domains.network',
2843 'dhcp-client-use-routes-no.network',
2844 'dhcp-client-vrf.network',
2845 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
2846 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
2847 'dhcp-client-with-static-address.network',
2848 'dhcp-client.network',
2849 'dhcp-server-decline.network',
2850 'dhcp-server-veth-peer.network',
2851 'dhcp-v4-server-veth-peer.network',
2852 'dhcp-client-use-domains.network',
2856 stop_dnsmasq(dnsmasq_pid_file
)
2857 remove_links(self
.links
)
2858 stop_networkd(show_logs
=False)
2861 stop_dnsmasq(dnsmasq_pid_file
)
2864 remove_links(self
.links
)
2865 remove_unit_from_networkd_path(self
.units
)
2866 stop_networkd(show_logs
=True)
2868 def test_dhcp_client_ipv6_only(self
):
2869 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2872 self
.wait_online(['veth-peer:carrier'])
2874 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2876 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2878 self
.assertRegex(output
, '2600::')
2879 self
.assertNotRegex(output
, '192.168.5')
2881 # Confirm that ipv6 token is not set in the kernel
2882 output
= check_output('ip token show dev veth99')
2884 self
.assertRegex(output
, 'token :: dev veth99')
2886 def test_dhcp_client_ipv4_only(self
):
2887 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
2890 self
.wait_online(['veth-peer:carrier'])
2891 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
2892 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2894 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2896 self
.assertNotRegex(output
, '2600::')
2897 self
.assertRegex(output
, '192.168.5')
2898 self
.assertRegex(output
, '192.168.5.6')
2899 self
.assertRegex(output
, '192.168.5.7')
2901 # checking routes to DNS servers
2902 output
= check_output('ip route show dev veth99')
2904 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
2905 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
2906 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
2908 stop_dnsmasq(dnsmasq_pid_file
)
2909 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8', lease_time
='2m')
2911 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2912 print('Wait for the dynamic address to be renewed')
2915 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2917 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2919 self
.assertNotRegex(output
, '2600::')
2920 self
.assertRegex(output
, '192.168.5')
2921 self
.assertNotRegex(output
, '192.168.5.6')
2922 self
.assertRegex(output
, '192.168.5.7')
2923 self
.assertRegex(output
, '192.168.5.8')
2925 # checking routes to DNS servers
2926 output
= check_output('ip route show dev veth99')
2928 self
.assertNotRegex(output
, r
'192.168.5.6')
2929 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
2930 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
2931 self
.assertRegex(output
, r
'192.168.5.8 proto dhcp scope link src 192.168.5.181 metric 1024')
2933 def test_dhcp_client_ipv4_use_routes_no(self
):
2934 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-use-routes-no.network')
2937 self
.wait_online(['veth-peer:carrier'])
2938 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
2939 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2941 output
= check_output('ip route show dev veth99')
2943 self
.assertNotRegex(output
, r
'192.168.5.5')
2944 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.181 metric 1024')
2945 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
2947 def test_dhcp_client_ipv4_ipv6(self
):
2948 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
2949 'dhcp-client-ipv4-only.network')
2951 self
.wait_online(['veth-peer:carrier'])
2953 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2955 # link become 'routable' when at least one protocol provide an valid address.
2956 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2957 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2959 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2961 self
.assertRegex(output
, '2600::')
2962 self
.assertRegex(output
, '192.168.5')
2964 def test_dhcp_client_settings(self
):
2965 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
2968 self
.wait_online(['veth-peer:carrier'])
2970 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2972 print('## ip address show dev veth99')
2973 output
= check_output('ip address show dev veth99')
2975 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2976 self
.assertRegex(output
, '192.168.5')
2977 self
.assertRegex(output
, '1492')
2979 print('## ip route show table main dev veth99')
2980 output
= check_output('ip route show table main dev veth99')
2983 main_table_is_empty
= output
== ''
2984 if not main_table_is_empty
:
2985 self
.assertNotRegex(output
, 'proto dhcp')
2987 print('## ip route show table 211 dev veth99')
2988 output
= check_output('ip route show table 211 dev veth99')
2990 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
2991 if main_table_is_empty
:
2992 self
.assertRegex(output
, '192.168.5.0/24 proto dhcp')
2993 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
2994 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
2996 print('## dnsmasq log')
2997 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
2998 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
2999 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
3000 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
3002 def test_dhcp6_client_settings_rapidcommit_true(self
):
3003 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3005 self
.wait_online(['veth-peer:carrier'])
3007 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3009 output
= check_output('ip address show dev veth99')
3011 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3012 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
3014 def test_dhcp6_client_settings_rapidcommit_false(self
):
3015 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
3017 self
.wait_online(['veth-peer:carrier'])
3019 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3021 output
= check_output('ip address show dev veth99')
3023 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3024 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
3026 def test_dhcp_client_settings_anonymize(self
):
3027 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
3029 self
.wait_online(['veth-peer:carrier'])
3031 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3033 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
3034 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
3035 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
3037 def test_dhcp_client_listen_port(self
):
3038 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
3040 self
.wait_online(['veth-peer:carrier'])
3041 start_dnsmasq('--dhcp-alternate-port=67,5555')
3042 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3044 output
= check_output('ip -4 address show dev veth99')
3046 self
.assertRegex(output
, '192.168.5.* dynamic')
3048 def test_dhcp_client_with_static_address(self
):
3049 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
3050 'dhcp-client-with-static-address.network')
3052 self
.wait_online(['veth-peer:carrier'])
3054 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3056 output
= check_output('ip address show dev veth99 scope global')
3058 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
3059 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
3061 output
= check_output('ip route show dev veth99')
3063 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
3064 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
3065 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
3066 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
3068 def test_dhcp_route_table_id(self
):
3069 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
3071 self
.wait_online(['veth-peer:carrier'])
3073 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3075 output
= check_output('ip route show table 12')
3077 self
.assertRegex(output
, 'veth99 proto dhcp')
3078 self
.assertRegex(output
, '192.168.5.1')
3080 def test_dhcp_route_metric(self
):
3081 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
3083 self
.wait_online(['veth-peer:carrier'])
3085 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3087 output
= check_output('ip route show dev veth99')
3089 self
.assertRegex(output
, 'metric 24')
3091 def test_dhcp_client_reassign_static_routes_ipv4(self
):
3092 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3093 'dhcp-client-reassign-static-routes-ipv4.network')
3095 self
.wait_online(['veth-peer:carrier'])
3096 start_dnsmasq(lease_time
='2m')
3097 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3099 output
= check_output('ip address show dev veth99 scope global')
3101 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3103 output
= check_output('ip route show dev veth99')
3105 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3106 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3107 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3108 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3110 stop_dnsmasq(dnsmasq_pid_file
)
3111 start_dnsmasq(ipv4_range
='192.168.5.210,192.168.5.220', lease_time
='2m')
3113 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3114 print('Wait for the dynamic address to be renewed')
3117 self
.wait_online(['veth99:routable'])
3119 output
= check_output('ip route show dev veth99')
3121 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3122 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3123 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3124 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3126 def test_dhcp_client_reassign_static_routes_ipv6(self
):
3127 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3128 'dhcp-client-reassign-static-routes-ipv6.network')
3130 self
.wait_online(['veth-peer:carrier'])
3131 start_dnsmasq(lease_time
='2m')
3132 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3134 output
= check_output('ip address show dev veth99 scope global')
3136 self
.assertRegex(output
, r
'inet6 2600::[0-9a-f]*/128 scope global (noprefixroute dynamic|dynamic noprefixroute)')
3138 output
= check_output('ip -6 route show dev veth99')
3140 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3141 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3143 stop_dnsmasq(dnsmasq_pid_file
)
3144 start_dnsmasq(ipv6_range
='2600::30,2600::40', lease_time
='2m')
3146 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3147 print('Wait for the dynamic address to be renewed')
3150 self
.wait_online(['veth99:routable'])
3152 output
= check_output('ip -6 route show dev veth99')
3154 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3155 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3157 def test_dhcp_keep_configuration_dhcp(self
):
3158 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
3160 self
.wait_online(['veth-peer:carrier'])
3161 start_dnsmasq(lease_time
='2m')
3162 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3164 output
= check_output('ip address show dev veth99 scope global')
3166 self
.assertRegex(output
, r
'192.168.5.*')
3168 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3170 self
.assertRegex(output
, r
'192.168.5.*')
3172 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
3173 stop_dnsmasq(dnsmasq_pid_file
)
3175 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3176 print('Wait for the dynamic address to be expired')
3179 print('The lease address should be kept after lease expired')
3180 output
= check_output('ip address show dev veth99 scope global')
3182 self
.assertRegex(output
, r
'192.168.5.*')
3184 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3186 self
.assertRegex(output
, r
'192.168.5.*')
3188 check_output('systemctl stop systemd-networkd')
3190 print('The lease address should be kept after networkd stopped')
3191 output
= check_output('ip address show dev veth99 scope global')
3193 self
.assertRegex(output
, r
'192.168.5.*')
3195 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3197 self
.assertRegex(output
, r
'192.168.5.*')
3200 self
.wait_online(['veth-peer:routable'])
3202 print('Still the lease address should be kept after networkd restarted')
3203 output
= check_output('ip address show dev veth99 scope global')
3205 self
.assertRegex(output
, r
'192.168.5.*')
3207 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3209 self
.assertRegex(output
, r
'192.168.5.*')
3211 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
3212 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
3214 self
.wait_online(['veth-peer:carrier'])
3215 start_dnsmasq(lease_time
='2m')
3216 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3218 output
= check_output('ip address show dev veth99 scope global')
3220 self
.assertRegex(output
, r
'192.168.5.*')
3222 stop_dnsmasq(dnsmasq_pid_file
)
3223 check_output('systemctl stop systemd-networkd')
3225 output
= check_output('ip address show dev veth99 scope global')
3227 self
.assertRegex(output
, r
'192.168.5.*')
3230 self
.wait_online(['veth-peer:routable'])
3232 output
= check_output('ip address show dev veth99 scope global')
3234 self
.assertNotRegex(output
, r
'192.168.5.*')
3236 def test_dhcp_client_reuse_address_as_static(self
):
3237 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
3239 self
.wait_online(['veth-peer:carrier'])
3241 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3243 # link become 'routable' when at least one protocol provide an valid address.
3244 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3245 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3247 output
= check_output('ip address show dev veth99 scope global')
3249 self
.assertRegex(output
, '192.168.5')
3250 self
.assertRegex(output
, '2600::')
3252 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
3253 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
3254 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
3255 print(static_network
)
3257 remove_unit_from_networkd_path(['dhcp-client.network'])
3259 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
3260 f
.write(static_network
)
3262 # When networkd started, the links are already configured, so let's wait for 5 seconds
3263 # the links to be re-configured.
3265 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3267 output
= check_output('ip -4 address show dev veth99 scope global')
3269 self
.assertRegex(output
, '192.168.5')
3270 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3272 output
= check_output('ip -6 address show dev veth99 scope global')
3274 self
.assertRegex(output
, '2600::')
3275 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3277 @expectedFailureIfModuleIsNotAvailable('vrf')
3278 def test_dhcp_client_vrf(self
):
3279 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
3280 '25-vrf.netdev', '25-vrf.network')
3282 self
.wait_online(['veth-peer:carrier'])
3284 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
3286 # link become 'routable' when at least one protocol provide an valid address.
3287 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3288 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3290 print('## ip -d link show dev vrf99')
3291 output
= check_output('ip -d link show dev vrf99')
3293 self
.assertRegex(output
, 'vrf table 42')
3295 print('## ip address show vrf vrf99')
3296 output
= check_output('ip address show vrf vrf99')
3298 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3299 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3300 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3301 self
.assertRegex(output
, 'inet6 .* scope link')
3303 print('## ip address show dev veth99')
3304 output
= check_output('ip address show dev veth99')
3306 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3307 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3308 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3309 self
.assertRegex(output
, 'inet6 .* scope link')
3311 print('## ip route show vrf vrf99')
3312 output
= check_output('ip route show vrf vrf99')
3314 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
3315 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
3316 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
3317 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
3318 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
3320 print('## ip route show table main dev veth99')
3321 output
= check_output('ip route show table main dev veth99')
3323 self
.assertEqual(output
, '')
3325 def test_dhcp_client_gateway_ipv4(self
):
3326 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3327 'dhcp-client-gateway-ipv4.network')
3329 self
.wait_online(['veth-peer:carrier'])
3331 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3333 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3335 self
.assertRegex(output
, '10.0.0.0/8 via 192.168.5.1 proto static')
3337 def test_dhcp_client_gateway_ipv6(self
):
3338 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3339 'dhcp-client-gateway-ipv6.network')
3341 self
.wait_online(['veth-peer:carrier'])
3343 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3345 output
= check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
3347 self
.assertRegex(output
, 'via fe80::1034:56ff:fe78:9abd')
3349 def test_dhcp_client_gateway_onlink_implicit(self
):
3350 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3351 'dhcp-client-gateway-onlink-implicit.network')
3353 self
.wait_online(['veth-peer:carrier'])
3355 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3357 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3359 self
.assertRegex(output
, '192.168.5')
3361 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3363 self
.assertRegex(output
, 'onlink')
3364 output
= check_output('ip route list dev veth99 192.168.100.0/24')
3366 self
.assertRegex(output
, 'onlink')
3368 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
3369 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3370 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
3372 self
.wait_online(['veth-peer:carrier'])
3373 start_dnsmasq(lease_time
='2m')
3374 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
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 print('Wait for the dynamic address to be expired')
3391 output
= check_output('ip address show dev veth99')
3394 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3395 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3396 output
= check_output('ip -6 address show dev veth99 scope link')
3397 self
.assertRegex(output
, 'inet6 .* scope link')
3398 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3399 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3400 output
= check_output('ip -4 address show dev veth99 scope link')
3401 self
.assertNotRegex(output
, 'inet .* scope link')
3403 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
3405 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
3406 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3407 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
3409 self
.wait_online(['veth99:degraded', 'veth-peer:routable'])
3411 output
= check_output('ip address show dev veth99')
3414 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3415 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3416 output
= check_output('ip -6 address show dev veth99 scope link')
3417 self
.assertRegex(output
, 'inet6 .* scope link')
3418 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3419 self
.assertNotRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3420 output
= check_output('ip -4 address show dev veth99 scope link')
3421 self
.assertRegex(output
, 'inet .* scope link')
3423 def test_dhcp_client_route_remove_on_renew(self
):
3424 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3425 'dhcp-client-ipv4-only-ipv6-disabled.network')
3427 self
.wait_online(['veth-peer:carrier'])
3428 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
3429 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3431 # test for issue #12490
3433 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3435 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3437 for line
in output
.splitlines():
3438 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3439 address1
= line
.split()[1].split('/')[0]
3442 output
= check_output('ip -4 route show dev veth99')
3444 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3445 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3447 stop_dnsmasq(dnsmasq_pid_file
)
3448 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
3450 print('Wait for the dynamic address to be expired')
3453 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3455 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3457 for line
in output
.splitlines():
3458 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3459 address2
= line
.split()[1].split('/')[0]
3462 self
.assertNotEqual(address1
, address2
)
3464 output
= check_output('ip -4 route show dev veth99')
3466 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3467 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3468 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
3469 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
3471 def test_dhcp_client_use_dns_yes(self
):
3472 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-yes.network')
3475 self
.wait_online(['veth-peer:carrier'])
3476 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3477 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3479 # link become 'routable' when at least one protocol provide an valid address.
3480 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3481 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3484 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3486 self
.assertRegex(output
, '192.168.5.1')
3487 self
.assertRegex(output
, '2600::1')
3489 def test_dhcp_client_use_dns_no(self
):
3490 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-no.network')
3493 self
.wait_online(['veth-peer:carrier'])
3494 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3495 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3497 # link become 'routable' when at least one protocol provide an valid address.
3498 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3499 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3502 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3504 self
.assertNotRegex(output
, '192.168.5.1')
3505 self
.assertNotRegex(output
, '2600::1')
3507 def test_dhcp_client_use_dns_ipv4(self
):
3508 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4.network')
3511 self
.wait_online(['veth-peer:carrier'])
3512 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3513 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3515 # link become 'routable' when at least one protocol provide an valid address.
3516 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3517 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3520 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3522 self
.assertRegex(output
, '192.168.5.1')
3523 self
.assertNotRegex(output
, '2600::1')
3525 def test_dhcp_client_use_dns_ipv4_and_ra(self
):
3526 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4-and-ra.network')
3529 self
.wait_online(['veth-peer:carrier'])
3530 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3531 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3533 # link become 'routable' when at least one protocol provide an valid address.
3534 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3535 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3538 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3540 self
.assertRegex(output
, '192.168.5.1')
3541 self
.assertRegex(output
, '2600::1')
3543 def test_dhcp_client_use_domains(self
):
3544 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-domains.network')
3547 self
.wait_online(['veth-peer:carrier'])
3548 start_dnsmasq('--dhcp-option=option:domain-search,example.com')
3549 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3551 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3553 self
.assertRegex(output
, 'Search Domains: example.com')
3556 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
3558 self
.assertRegex(output
, 'example.com')
3560 def test_dhcp_client_decline(self
):
3561 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-decline.network', 'dhcp-client-decline.network')
3564 self
.wait_online(['veth-peer:carrier'])
3565 rc
= call(*wait_online_cmd
, '--timeout=10s', '--interface=veth99:routable', env
=env
)
3566 self
.assertTrue(rc
== 1)
3568 class NetworkdIPv6PrefixTests(unittest
.TestCase
, Utilities
):
3573 'ipv6ra-prefix-client.network',
3574 'ipv6ra-prefix.network'
3578 remove_links(self
.links
)
3579 stop_networkd(show_logs
=False)
3583 remove_links(self
.links
)
3584 remove_unit_from_networkd_path(self
.units
)
3585 stop_networkd(show_logs
=True)
3587 def test_ipv6_route_prefix(self
):
3588 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client.network', 'ipv6ra-prefix.network')
3591 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3593 output
= check_output('ip', '-6', 'route', 'show', 'dev', 'veth-peer')
3595 self
.assertRegex(output
, '2001:db8:0:1::/64 proto ra')
3597 class NetworkdMTUTests(unittest
.TestCase
, Utilities
):
3602 '12-dummy-mtu.netdev',
3603 '12-dummy-mtu.link',
3608 remove_links(self
.links
)
3609 stop_networkd(show_logs
=False)
3613 remove_links(self
.links
)
3614 remove_unit_from_networkd_path(self
.units
)
3615 stop_networkd(show_logs
=True)
3617 def check_mtu(self
, mtu
, ipv6_mtu
=None, reset
=True):
3623 self
.wait_online(['dummy98:routable'])
3624 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
3625 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
3627 # test normal restart
3629 self
.wait_online(['dummy98:routable'])
3630 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
3631 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
3634 self
.reset_check_mtu(mtu
, ipv6_mtu
)
3636 def reset_check_mtu(self
, mtu
, ipv6_mtu
=None):
3637 ''' test setting mtu/ipv6_mtu with interface already up '''
3640 # note - changing the device mtu resets the ipv6 mtu
3641 run('ip link set up mtu 1501 dev dummy98')
3642 run('ip link set up mtu 1500 dev dummy98')
3643 self
.assertEqual(read_link_attr('dummy98', 'mtu'), '1500')
3644 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), '1500')
3646 self
.check_mtu(mtu
, ipv6_mtu
, reset
=False)
3648 def test_mtu_network(self
):
3649 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
3650 self
.check_mtu('1600')
3652 def test_mtu_netdev(self
):
3653 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network', dropins
=False)
3654 # note - MTU set by .netdev happens ONLY at device creation!
3655 self
.check_mtu('1600', reset
=False)
3657 def test_mtu_link(self
):
3658 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', dropins
=False)
3659 # must reload udev because it only picks up new files after 3 second delay
3660 call('udevadm control --reload')
3661 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
3662 self
.check_mtu('1600', reset
=False)
3664 def test_ipv6_mtu(self
):
3665 ''' set ipv6 mtu without setting device mtu '''
3666 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
3667 self
.check_mtu('1500', '1400')
3669 def test_ipv6_mtu_toolarge(self
):
3670 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
3671 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
3672 self
.check_mtu('1500', '1500')
3674 def test_mtu_network_ipv6_mtu(self
):
3675 ''' set ipv6 mtu and set device mtu via network file '''
3676 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
3677 self
.check_mtu('1600', '1550')
3679 def test_mtu_netdev_ipv6_mtu(self
):
3680 ''' set ipv6 mtu and set device mtu via netdev file '''
3681 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
3682 self
.check_mtu('1600', '1550', reset
=False)
3684 def test_mtu_link_ipv6_mtu(self
):
3685 ''' set ipv6 mtu and set device mtu via link file '''
3686 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
3687 # must reload udev because it only picks up new files after 3 second delay
3688 call('udevadm control --reload')
3689 self
.check_mtu('1600', '1550', reset
=False)
3692 if __name__
== '__main__':
3693 parser
= argparse
.ArgumentParser()
3694 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
3695 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
3696 parser
.add_argument('--resolved', help='Path to systemd-resolved', dest
='resolved_bin')
3697 parser
.add_argument('--udevd', help='Path to systemd-udevd', dest
='udevd_bin')
3698 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
3699 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
3700 parser
.add_argument('--resolvectl', help='Path to resolvectl', dest
='resolvectl_bin')
3701 parser
.add_argument('--timedatectl', help='Path to timedatectl', dest
='timedatectl_bin')
3702 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
3703 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
3704 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
3705 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
3706 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
3707 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
3710 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
:
3711 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
3712 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
3713 resolved_bin
= os
.path
.join(ns
.build_dir
, 'systemd-resolved')
3714 udevd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-udevd')
3715 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
3716 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
3717 resolvectl_bin
= os
.path
.join(ns
.build_dir
, 'resolvectl')
3718 timedatectl_bin
= os
.path
.join(ns
.build_dir
, 'timedatectl')
3721 networkd_bin
= ns
.networkd_bin
3723 resolved_bin
= ns
.resolved_bin
3725 udevd_bin
= ns
.udevd_bin
3726 if ns
.wait_online_bin
:
3727 wait_online_bin
= ns
.wait_online_bin
3728 if ns
.networkctl_bin
:
3729 networkctl_bin
= ns
.networkctl_bin
3730 if ns
.resolvectl_bin
:
3731 resolvectl_bin
= ns
.resolvectl_bin
3732 if ns
.timedatectl_bin
:
3733 timedatectl_bin
= ns
.timedatectl_bin
3735 use_valgrind
= ns
.use_valgrind
3736 enable_debug
= ns
.enable_debug
3737 asan_options
= ns
.asan_options
3738 lsan_options
= ns
.lsan_options
3739 ubsan_options
= ns
.ubsan_options
3742 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
3743 resolvectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin
]
3744 timedatectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin
]
3745 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
3747 networkctl_cmd
= [networkctl_bin
]
3748 resolvectl_cmd
= [resolvectl_bin
]
3749 timedatectl_cmd
= [timedatectl_bin
]
3750 wait_online_cmd
= [wait_online_bin
]
3753 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
3755 env
.update({ 'ASAN_OPTIONS' : asan_options
})
3757 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
3759 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
3762 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,