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 wait_online_bin
=shutil
.which('systemd-networkd-wait-online', path
=which_paths
)
31 networkctl_bin
=shutil
.which('networkctl', path
=which_paths
)
32 resolvectl_bin
=shutil
.which('resolvectl', path
=which_paths
)
33 timedatectl_bin
=shutil
.which('timedatectl', path
=which_paths
)
44 def check_output(*command
, **kwargs
):
45 # This replaces both check_output and check_call (output can be ignored)
46 command
= command
[0].split() + list(command
[1:])
47 return subprocess
.check_output(command
, universal_newlines
=True, **kwargs
).rstrip()
49 def call(*command
, **kwargs
):
50 command
= command
[0].split() + list(command
[1:])
51 return subprocess
.call(command
, universal_newlines
=True, **kwargs
)
53 def run(*command
, **kwargs
):
54 command
= command
[0].split() + list(command
[1:])
55 return subprocess
.run(command
, universal_newlines
=True, **kwargs
)
57 def is_module_available(module_name
):
58 lsmod_output
= check_output('lsmod')
59 module_re
= re
.compile(rf
'^{re.escape(module_name)}\b', re
.MULTILINE
)
60 return module_re
.search(lsmod_output
) or not call('modprobe', module_name
, stderr
=subprocess
.DEVNULL
)
62 def expectedFailureIfModuleIsNotAvailable(module_name
):
64 if not is_module_available(module_name
):
65 return unittest
.expectedFailure(func
)
70 def expectedFailureIfERSPANModuleIsNotAvailable():
72 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
)
74 call('ip link del erspan99')
77 return unittest
.expectedFailure(func
)
81 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable():
83 rc
= call('ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7', stderr
=subprocess
.DEVNULL
)
85 call('ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
88 return unittest
.expectedFailure(func
)
92 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
94 rc
= call('ip rule add not from 192.168.100.19 ipproto tcp table 7', stderr
=subprocess
.DEVNULL
)
96 call('ip rule del not from 192.168.100.19 ipproto tcp table 7')
99 return unittest
.expectedFailure(func
)
103 def expectedFailureIfLinkFileFieldIsNotSet():
106 rc
= call('ip link add name dummy99 type dummy', stderr
=subprocess
.DEVNULL
)
108 ret
= run('udevadm info -w10s /sys/class/net/dummy99', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
109 if ret
.returncode
== 0 and 'E: ID_NET_LINK_FILE=' in ret
.stdout
.rstrip():
111 call('ip link del dummy99')
116 return unittest
.expectedFailure(func
)
120 def expectedFailureIfNexthopIsNotAvailable():
122 rc
= call('ip nexthop list', stderr
=subprocess
.DEVNULL
)
126 return unittest
.expectedFailure(func
)
130 def expectedFailureIfAlternativeNameIsNotAvailable():
132 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
133 rc
= call('ip link prop add dev dummy98 altname hogehogehogehogehoge', stderr
=subprocess
.DEVNULL
)
137 return unittest
.expectedFailure(func
)
144 os
.makedirs(network_unit_file_path
, exist_ok
=True)
145 os
.makedirs(networkd_ci_path
, exist_ok
=True)
147 shutil
.rmtree(networkd_ci_path
)
148 copytree(os
.path
.join(os
.path
.dirname(os
.path
.abspath(__file__
)), 'conf'), networkd_ci_path
)
150 for u
in ['systemd-networkd.socket', 'systemd-networkd.service', 'systemd-resolved.service', 'firewalld.service']:
151 if call(f
'systemctl is-active --quiet {u}') == 0:
152 check_output(f
'systemctl stop {u}')
153 running_units
.append(u
)
157 'StartLimitIntervalSec=0',
164 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin
,
168 drop_in
+= ['ExecStart=!!' + networkd_bin
]
170 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
172 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
174 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
176 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
177 if asan_options
or lsan_options
or ubsan_options
:
178 drop_in
+= ['SystemCallFilter=']
179 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
180 drop_in
+= ['MemoryDenyWriteExecute=no']
182 os
.makedirs('/run/systemd/system/systemd-networkd.service.d', exist_ok
=True)
183 with
open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode
='w') as f
:
184 f
.write('\n'.join(drop_in
))
192 drop_in
+= ['ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + resolved_bin
]
194 drop_in
+= ['ExecStart=!!' + resolved_bin
]
196 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
198 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
200 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
202 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
203 if asan_options
or lsan_options
or ubsan_options
:
204 drop_in
+= ['SystemCallFilter=']
205 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
206 drop_in
+= ['MemoryDenyWriteExecute=no']
208 os
.makedirs('/run/systemd/system/systemd-resolved.service.d', exist_ok
=True)
209 with
open('/run/systemd/system/systemd-resolved.service.d/00-override.conf', mode
='w') as f
:
210 f
.write('\n'.join(drop_in
))
212 check_output('systemctl daemon-reload')
213 print(check_output('systemctl cat systemd-networkd.service'))
214 print(check_output('systemctl cat systemd-resolved.service'))
215 check_output('systemctl restart systemd-resolved')
217 def tearDownModule():
220 shutil
.rmtree(networkd_ci_path
)
222 for u
in ['systemd-networkd.service', 'systemd-resolved.service']:
223 check_output(f
'systemctl stop {u}')
225 shutil
.rmtree('/run/systemd/system/systemd-networkd.service.d')
226 shutil
.rmtree('/run/systemd/system/systemd-resolved.service.d')
227 check_output('systemctl daemon-reload')
229 for u
in running_units
:
230 check_output(f
'systemctl start {u}')
232 def read_link_attr(*args
):
233 with
open(os
.path
.join('/sys/class/net/', *args
)) as f
:
234 return f
.readline().strip()
236 def read_bridge_port_attr(bridge
, link
, attribute
):
237 path_bridge
= os
.path
.join('/sys/devices/virtual/net', bridge
)
238 path_port
= 'lower_' + link
+ '/brport'
239 path
= os
.path
.join(path_bridge
, path_port
)
241 with
open(os
.path
.join(path
, attribute
)) as f
:
242 return f
.readline().strip()
244 def link_exists(link
):
245 return os
.path
.exists(os
.path
.join('/sys/class/net', link
))
247 def remove_links(links
):
249 if link_exists(link
):
250 call('ip link del dev', link
)
253 def remove_fou_ports(ports
):
255 call('ip fou del port', port
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
257 def remove_routing_policy_rule_tables(tables
):
261 rc
= call('ip rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
263 def remove_routes(routes
):
264 for route_type
, addr
in routes
:
265 call('ip route del', route_type
, addr
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
267 def remove_l2tp_tunnels(tunnel_ids
):
268 output
= check_output('ip l2tp show tunnel')
269 for tid
in tunnel_ids
:
270 words
='Tunnel ' + tid
+ ', encap'
272 call('ip l2tp del tunnel tid', tid
)
275 def read_ipv6_sysctl_attr(link
, attribute
):
276 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, link
), attribute
)) as f
:
277 return f
.readline().strip()
279 def read_ipv4_sysctl_attr(link
, attribute
):
280 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv4_path
, link
), attribute
)) as f
:
281 return f
.readline().strip()
283 def copy_unit_to_networkd_unit_path(*units
, dropins
=True):
284 """Copy networkd unit files into the testbed.
286 Any networkd unit file type can be specified, as well as drop-in files.
288 By default, all drop-ins for a specified unit file are copied in;
289 to avoid that specify dropins=False.
291 When a drop-in file is specified, its unit file is also copied in automatically.
295 if dropins
and os
.path
.exists(os
.path
.join(networkd_ci_path
, unit
+ '.d')):
296 copytree(os
.path
.join(networkd_ci_path
, unit
+ '.d'), os
.path
.join(network_unit_file_path
, unit
+ '.d'))
297 if unit
.endswith('.conf'):
299 dropindir
= os
.path
.join(network_unit_file_path
, os
.path
.dirname(dropin
))
300 os
.makedirs(dropindir
, exist_ok
=True)
301 shutil
.copy(os
.path
.join(networkd_ci_path
, dropin
), dropindir
)
302 unit
= os
.path
.dirname(dropin
).rstrip('.d')
303 shutil
.copy(os
.path
.join(networkd_ci_path
, unit
), network_unit_file_path
)
305 def remove_unit_from_networkd_path(units
):
306 """Remove previously copied unit files from the testbed.
308 Drop-ins will be removed automatically.
311 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
))):
312 os
.remove(os
.path
.join(network_unit_file_path
, unit
))
313 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
+ '.d'))):
314 shutil
.rmtree(os
.path
.join(network_unit_file_path
, unit
+ '.d'))
316 def start_dnsmasq(additional_options
='', ipv4_range
='192.168.5.10,192.168.5.200', ipv6_range
='2600::10,2600::20', lease_time
='1h'):
317 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
318 check_output(dnsmasq_command
)
320 def stop_dnsmasq(pid_file
):
321 if os
.path
.exists(pid_file
):
322 with
open(pid_file
, 'r') as f
:
323 pid
= f
.read().rstrip(' \t\r\n\0')
324 os
.kill(int(pid
), signal
.SIGTERM
)
328 def search_words_in_dnsmasq_log(words
, show_all
=False):
329 if os
.path
.exists(dnsmasq_log_file
):
330 with
open (dnsmasq_log_file
) as in_file
:
331 contents
= in_file
.read()
334 for line
in contents
.splitlines():
337 print("%s, %s" % (words
, line
))
341 def remove_lease_file():
342 if os
.path
.exists(os
.path
.join(networkd_ci_path
, 'lease')):
343 os
.remove(os
.path
.join(networkd_ci_path
, 'lease'))
345 def remove_log_file():
346 if os
.path
.exists(dnsmasq_log_file
):
347 os
.remove(dnsmasq_log_file
)
349 def remove_networkd_state_files():
350 if os
.path
.exists(os
.path
.join(networkd_runtime_directory
, 'state')):
351 os
.remove(os
.path
.join(networkd_runtime_directory
, 'state'))
353 def stop_networkd(show_logs
=True, remove_state_files
=True):
355 invocation_id
= check_output('systemctl show systemd-networkd -p InvocationID --value')
356 check_output('systemctl stop systemd-networkd')
358 print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
))
359 if remove_state_files
:
360 remove_networkd_state_files()
362 def start_networkd(sleep_sec
=0):
363 check_output('systemctl start systemd-networkd')
365 time
.sleep(sleep_sec
)
367 def restart_networkd(sleep_sec
=0, show_logs
=True, remove_state_files
=True):
368 stop_networkd(show_logs
, remove_state_files
)
369 start_networkd(sleep_sec
)
373 def check_link_exists(self
, link
):
374 self
.assertTrue(link_exists(link
))
376 def wait_operstate(self
, link
, operstate
='degraded', setup_state
='configured', setup_timeout
=5, fail_assert
=True):
377 """Wait for the link to reach the specified operstate and/or setup state.
379 Specify None or '' for either operstate or setup_state to ignore that state.
380 This will recheck until the state conditions are met or the timeout expires.
382 If the link successfully matches the requested state, this returns True.
383 If this times out waiting for the link to match, the behavior depends on the
384 'fail_assert' parameter; if True, this causes a test assertion failure,
385 otherwise this returns False. The default is to cause assertion failure.
387 Note that this function matches on *exactly* the given operstate and setup_state.
388 To wait for a link to reach *or exceed* a given operstate, use wait_online().
395 for secs
in range(setup_timeout
+ 1):
396 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
, env
=env
)
398 if re
.search(rf
'(?m)^\s*State:\s+{operstate}\s+\({setup_state}\)\s*$', output
):
400 # don't bother sleeping if time is up
401 if secs
< setup_timeout
:
404 self
.fail(f
'Timed out waiting for {link} to reach state {operstate}/{setup_state}')
407 def wait_online(self
, links_with_operstate
, timeout
='20s', bool_any
=False, setup_state
='configured', setup_timeout
=5):
408 """Wait for the link(s) to reach the specified operstate and/or setup state.
410 This is similar to wait_operstate() but can be used for multiple links,
411 and it also calls systemd-networkd-wait-online to wait for the given operstate.
412 The operstate should be specified in the link name, like 'eth0:degraded'.
413 If just a link name is provided, wait-online's default operstate to wait for is degraded.
415 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
416 'setup_timeout' controls the per-link timeout waiting for the setup_state.
418 Set 'bool_any' to True to wait for any (instead of all) of the given links.
419 If this is set, no setup_state checks are done.
421 Note that this function waits for the link(s) to reach *or exceed* the given operstate.
422 However, the setup_state, if specified, must be matched *exactly*.
424 This returns if the link(s) reached the requested operstate/setup_state; otherwise it
425 raises CalledProcessError or fails test assertion.
427 args
= wait_online_cmd
+ [f
'--timeout={timeout}'] + [f
'--interface={link}' for link
in links_with_operstate
]
431 check_output(*args
, env
=env
)
432 except subprocess
.CalledProcessError
:
433 for link
in links_with_operstate
:
434 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
.split(':')[0], env
=env
)
437 if not bool_any
and setup_state
:
438 for link
in links_with_operstate
:
439 self
.wait_operstate(link
.split(':')[0], None, setup_state
, setup_timeout
)
441 def wait_address(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
442 for i
in range(timeout_sec
):
445 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
446 if re
.search(address_regex
, output
):
449 self
.assertRegex(output
, address_regex
)
451 class NetworkctlTests(unittest
.TestCase
, Utilities
):
461 '11-dummy-mtu.netdev',
465 '25-address-static.network',
467 'netdev-link-local-addressing-yes.network',
471 remove_links(self
.links
)
472 stop_networkd(show_logs
=False)
475 remove_links(self
.links
)
476 remove_unit_from_networkd_path(self
.units
)
477 stop_networkd(show_logs
=True)
479 @expectedFailureIfAlternativeNameIsNotAvailable()
480 def test_altname(self
):
481 copy_unit_to_networkd_unit_path('netdev-link-local-addressing-yes.network', '12-dummy.netdev', '12-dummy.link')
482 check_output('udevadm control --reload')
484 self
.wait_online(['dummy98:degraded'])
486 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
487 self
.assertRegex(output
, 'hogehogehogehogehogehoge')
489 def test_reconfigure(self
):
490 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
492 self
.wait_online(['dummy98:routable'])
494 output
= check_output('ip -4 address show dev dummy98')
496 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
497 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
498 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
500 check_output('ip address del 10.1.2.3/16 dev dummy98')
501 check_output('ip address del 10.1.2.4/16 dev dummy98')
502 check_output('ip address del 10.2.2.4/16 dev dummy98')
504 check_output(*networkctl_cmd
, 'reconfigure', 'dummy98', env
=env
)
505 self
.wait_online(['dummy98:routable'])
507 output
= check_output('ip -4 address show dev dummy98')
509 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
510 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
511 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
513 def test_reload(self
):
516 copy_unit_to_networkd_unit_path('11-dummy.netdev')
517 check_output(*networkctl_cmd
, 'reload', env
=env
)
518 self
.wait_operstate('test1', 'off', setup_state
='unmanaged')
520 copy_unit_to_networkd_unit_path('11-dummy.network')
521 check_output(*networkctl_cmd
, 'reload', env
=env
)
522 self
.wait_online(['test1:degraded'])
524 remove_unit_from_networkd_path(['11-dummy.network'])
525 check_output(*networkctl_cmd
, 'reload', env
=env
)
526 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
528 remove_unit_from_networkd_path(['11-dummy.netdev'])
529 check_output(*networkctl_cmd
, 'reload', env
=env
)
530 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
532 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
533 check_output(*networkctl_cmd
, 'reload', env
=env
)
534 self
.wait_operstate('test1', 'degraded')
537 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
540 self
.wait_online(['test1:degraded'])
542 output
= check_output(*networkctl_cmd
, 'list', env
=env
)
543 self
.assertRegex(output
, '1 lo ')
544 self
.assertRegex(output
, 'test1')
546 output
= check_output(*networkctl_cmd
, 'list', 'test1', env
=env
)
547 self
.assertNotRegex(output
, '1 lo ')
548 self
.assertRegex(output
, 'test1')
550 output
= check_output(*networkctl_cmd
, 'list', 'te*', env
=env
)
551 self
.assertNotRegex(output
, '1 lo ')
552 self
.assertRegex(output
, 'test1')
554 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'te*', env
=env
)
555 self
.assertNotRegex(output
, '1: lo ')
556 self
.assertRegex(output
, 'test1')
558 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'tes[a-z][0-9]', env
=env
)
559 self
.assertNotRegex(output
, '1: lo ')
560 self
.assertRegex(output
, 'test1')
563 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
566 self
.wait_online(['test1:degraded'])
568 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
569 self
.assertRegex(output
, 'MTU: 1600')
572 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
574 self
.wait_online(['test1:degraded'])
576 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
578 self
.assertRegex(output
, 'Type: ether')
580 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
582 self
.assertRegex(output
, 'Type: loopback')
584 @expectedFailureIfLinkFileFieldIsNotSet()
585 def test_udev_link_file(self
):
586 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
588 self
.wait_online(['test1:degraded'])
590 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
592 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
593 self
.assertRegex(output
, r
'Network File: /run/systemd/network/11-dummy.network')
595 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
597 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
598 self
.assertRegex(output
, r
'Network File: n/a')
600 def test_delete_links(self
):
601 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
602 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
605 self
.wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
607 check_output(*networkctl_cmd
, 'delete', 'test1', 'veth99', env
=env
)
608 self
.assertFalse(link_exists('test1'))
609 self
.assertFalse(link_exists('veth99'))
610 self
.assertFalse(link_exists('veth-peer'))
612 class NetworkdNetDevTests(unittest
.TestCase
, Utilities
):
614 links_remove_earlier
= [
679 '10-dropin-test.netdev',
683 '13-not-match-udev-property.network',
684 '14-match-udev-property.network',
685 '15-name-conflict-test.netdev',
688 '21-vlan-test1.network',
691 '25-6rd-tunnel.netdev',
693 '25-bond-balanced-tlb.netdev',
695 '25-bridge-configure-without-carrier.network',
697 '25-erspan-tunnel-local-any.netdev',
698 '25-erspan-tunnel.netdev',
699 '25-fou-gretap.netdev',
701 '25-fou-ipip.netdev',
702 '25-fou-ipproto-gre.netdev',
703 '25-fou-ipproto-ipip.netdev',
706 '25-gretap-tunnel-local-any.netdev',
707 '25-gretap-tunnel.netdev',
708 '25-gre-tunnel-any-any.netdev',
709 '25-gre-tunnel-local-any.netdev',
710 '25-gre-tunnel-remote-any.netdev',
711 '25-gre-tunnel.netdev',
713 '25-ip6gretap-tunnel-local-any.netdev',
714 '25-ip6gretap-tunnel.netdev',
715 '25-ip6gre-tunnel-any-any.netdev',
716 '25-ip6gre-tunnel-local-any.netdev',
717 '25-ip6gre-tunnel-remote-any.netdev',
718 '25-ip6gre-tunnel.netdev',
719 '25-ip6tnl-tunnel-any-any.netdev',
720 '25-ip6tnl-tunnel-local-any.netdev',
721 '25-ip6tnl-tunnel-remote-any.netdev',
722 '25-ip6tnl-tunnel.netdev',
723 '25-ipip-tunnel-any-any.netdev',
724 '25-ipip-tunnel-independent.netdev',
725 '25-ipip-tunnel-independent-loopback.netdev',
726 '25-ipip-tunnel-local-any.netdev',
727 '25-ipip-tunnel-remote-any.netdev',
728 '25-ipip-tunnel.netdev',
731 '25-isatap-tunnel.netdev',
736 '25-sit-tunnel-any-any.netdev',
737 '25-sit-tunnel-local-any.netdev',
738 '25-sit-tunnel-remote-any.netdev',
739 '25-sit-tunnel.netdev',
742 '25-tunnel-local-any.network',
743 '25-tunnel-remote-any.network',
748 '25-vti6-tunnel-any-any.netdev',
749 '25-vti6-tunnel-local-any.netdev',
750 '25-vti6-tunnel-remote-any.netdev',
751 '25-vti6-tunnel.netdev',
752 '25-vti-tunnel-any-any.netdev',
753 '25-vti-tunnel-local-any.netdev',
754 '25-vti-tunnel-remote-any.netdev',
755 '25-vti-tunnel.netdev',
758 '25-wireguard-23-peers.netdev',
759 '25-wireguard-23-peers.network',
760 '25-wireguard-preshared-key.txt',
761 '25-wireguard-private-key.txt',
762 '25-wireguard.netdev',
763 '25-wireguard.network',
765 '25-xfrm-independent.netdev',
781 'netdev-link-local-addressing-yes.network',
785 'vxlan-test1.network',
795 remove_fou_ports(self
.fou_ports
)
796 remove_links(self
.links_remove_earlier
)
797 remove_links(self
.links
)
798 stop_networkd(show_logs
=False)
801 remove_fou_ports(self
.fou_ports
)
802 remove_links(self
.links_remove_earlier
)
803 remove_links(self
.links
)
804 remove_unit_from_networkd_path(self
.units
)
805 stop_networkd(show_logs
=True)
807 def test_dropin_and_name_conflict(self
):
808 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
811 self
.wait_online(['dropin-test:off'], setup_state
='unmanaged')
813 output
= check_output('ip link show dropin-test')
815 self
.assertRegex(output
, '00:50:56:c0:00:28')
817 def test_match_udev_property(self
):
818 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
820 self
.wait_online(['dummy98:routable'])
822 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
824 self
.assertRegex(output
, 'Network File: /run/systemd/network/14-match-udev-property')
826 def test_wait_online_any(self
):
827 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
830 self
.wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
832 self
.wait_operstate('bridge99', '(off|no-carrier)', setup_state
='configuring')
833 self
.wait_operstate('test1', 'degraded')
835 def test_bridge(self
):
836 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
839 self
.wait_online(['bridge99:no-carrier'])
841 tick
= os
.sysconf('SC_CLK_TCK')
842 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
843 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
844 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'forward_delay')) / tick
))
845 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'ageing_time')) / tick
))
846 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge', 'priority')))
847 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_querier')))
848 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_snooping')))
849 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'stp_state')))
850 self
.assertEqual(3, int(read_link_attr('bridge99', 'bridge', 'multicast_igmp_version')))
852 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
854 self
.assertRegex(output
, 'Priority: 9')
855 self
.assertRegex(output
, 'STP: yes')
856 self
.assertRegex(output
, 'Multicast IGMP Version: 3')
859 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
862 self
.wait_online(['bond99:off', 'bond98:off'], setup_state
='unmanaged')
864 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
865 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
866 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
867 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
868 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
869 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
870 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
871 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
872 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
873 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
874 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
876 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
877 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
880 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
881 '21-vlan.network', '21-vlan-test1.network')
884 self
.wait_online(['test1:degraded', 'vlan99:routable'])
886 output
= check_output('ip -d link show test1')
888 self
.assertRegex(output
, ' mtu 2000 ')
890 output
= check_output('ip -d link show vlan99')
892 self
.assertRegex(output
, ' mtu 2000 ')
893 self
.assertRegex(output
, 'REORDER_HDR')
894 self
.assertRegex(output
, 'LOOSE_BINDING')
895 self
.assertRegex(output
, 'GVRP')
896 self
.assertRegex(output
, 'MVRP')
897 self
.assertRegex(output
, ' id 99 ')
899 output
= check_output('ip -4 address show dev test1')
901 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
902 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
904 output
= check_output('ip -4 address show dev vlan99')
906 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
908 def test_macvtap(self
):
909 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
910 with self
.subTest(mode
=mode
):
911 if mode
!= 'private':
913 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
914 '11-dummy.netdev', 'macvtap.network')
915 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
916 f
.write('[MACVTAP]\nMode=' + mode
)
919 self
.wait_online(['macvtap99:degraded', 'test1:degraded'])
921 output
= check_output('ip -d link show macvtap99')
923 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
925 def test_macvlan(self
):
926 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
927 with self
.subTest(mode
=mode
):
928 if mode
!= 'private':
930 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
931 '11-dummy.netdev', 'macvlan.network')
932 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
933 f
.write('[MACVLAN]\nMode=' + mode
)
936 self
.wait_online(['macvlan99:degraded', 'test1:degraded'])
938 output
= check_output('ip -d link show test1')
940 self
.assertRegex(output
, ' mtu 2000 ')
942 output
= check_output('ip -d link show macvlan99')
944 self
.assertRegex(output
, ' mtu 2000 ')
945 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
947 @expectedFailureIfModuleIsNotAvailable('ipvlan')
948 def test_ipvlan(self
):
949 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
950 with self
.subTest(mode
=mode
, flag
=flag
):
953 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
954 '11-dummy.netdev', 'ipvlan.network')
955 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
956 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
959 self
.wait_online(['ipvlan99:degraded', 'test1:degraded'])
961 output
= check_output('ip -d link show ipvlan99')
963 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
965 @expectedFailureIfModuleIsNotAvailable('ipvtap')
966 def test_ipvtap(self
):
967 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
968 with self
.subTest(mode
=mode
, flag
=flag
):
971 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
972 '11-dummy.netdev', 'ipvtap.network')
973 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
974 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
977 self
.wait_online(['ipvtap99:degraded', 'test1:degraded'])
979 output
= check_output('ip -d link show ipvtap99')
981 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
984 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
987 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
989 output
= check_output('ip -d link show veth99')
991 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
992 output
= check_output('ip -d link show veth-peer')
994 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
997 copy_unit_to_networkd_unit_path('25-tun.netdev')
1000 self
.wait_online(['tun99:off'], setup_state
='unmanaged')
1002 output
= check_output('ip -d link show tun99')
1004 # Old ip command does not support IFF_ flags
1005 self
.assertRegex(output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
1008 copy_unit_to_networkd_unit_path('25-tap.netdev')
1011 self
.wait_online(['tap99:off'], setup_state
='unmanaged')
1013 output
= check_output('ip -d link show tap99')
1015 # Old ip command does not support IFF_ flags
1016 self
.assertRegex(output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
1018 @expectedFailureIfModuleIsNotAvailable('vrf')
1020 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
1023 self
.wait_online(['vrf99:carrier'])
1025 @expectedFailureIfModuleIsNotAvailable('vcan')
1026 def test_vcan(self
):
1027 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
1030 self
.wait_online(['vcan99:carrier'])
1032 @expectedFailureIfModuleIsNotAvailable('vxcan')
1033 def test_vxcan(self
):
1034 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
1037 self
.wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
1039 @expectedFailureIfModuleIsNotAvailable('wireguard')
1040 def test_wireguard(self
):
1041 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
1042 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
1043 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt')
1045 self
.wait_online(['wg99:carrier', 'wg98:routable'])
1047 if shutil
.which('wg'):
1050 output
= check_output('wg show wg99 listen-port')
1051 self
.assertRegex(output
, '51820')
1052 output
= check_output('wg show wg99 fwmark')
1053 self
.assertRegex(output
, '0x4d2')
1054 output
= check_output('wg show wg99 allowed-ips')
1055 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
1056 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
1057 output
= check_output('wg show wg99 persistent-keepalive')
1058 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
1059 output
= check_output('wg show wg99 endpoints')
1060 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
1061 output
= check_output('wg show wg99 private-key')
1062 self
.assertRegex(output
, r
'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
1063 output
= check_output('wg show wg99 preshared-keys')
1064 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
1065 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
1067 output
= check_output('wg show wg98 private-key')
1068 self
.assertRegex(output
, r
'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
1070 def test_geneve(self
):
1071 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
1074 self
.wait_online(['geneve99:degraded'])
1076 output
= check_output('ip -d link show geneve99')
1078 self
.assertRegex(output
, '192.168.22.1')
1079 self
.assertRegex(output
, '6082')
1080 self
.assertRegex(output
, 'udpcsum')
1081 self
.assertRegex(output
, 'udp6zerocsumrx')
1083 def test_ipip_tunnel(self
):
1084 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
1085 '25-ipip-tunnel.netdev', '25-tunnel.network',
1086 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1087 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1088 '25-ipip-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1090 self
.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'ipiptun96:routable', 'dummy98:degraded'])
1092 output
= check_output('ip -d link show ipiptun99')
1094 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98')
1095 output
= check_output('ip -d link show ipiptun98')
1097 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98')
1098 output
= check_output('ip -d link show ipiptun97')
1100 self
.assertRegex(output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98')
1101 output
= check_output('ip -d link show ipiptun96')
1103 self
.assertRegex(output
, 'ipip (ipip )?remote any local any dev dummy98')
1105 def test_gre_tunnel(self
):
1106 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
1107 '25-gre-tunnel.netdev', '25-tunnel.network',
1108 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1109 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1110 '25-gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1112 self
.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'gretun96:routable', 'dummy98:degraded'])
1114 output
= check_output('ip -d link show gretun99')
1116 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1117 self
.assertRegex(output
, 'ikey 1.2.3.103')
1118 self
.assertRegex(output
, 'okey 1.2.4.103')
1119 self
.assertRegex(output
, 'iseq')
1120 self
.assertRegex(output
, 'oseq')
1121 output
= check_output('ip -d link show gretun98')
1123 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
1124 self
.assertRegex(output
, 'ikey 0.0.0.104')
1125 self
.assertRegex(output
, 'okey 0.0.0.104')
1126 self
.assertNotRegex(output
, 'iseq')
1127 self
.assertNotRegex(output
, 'oseq')
1128 output
= check_output('ip -d link show gretun97')
1130 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
1131 self
.assertRegex(output
, 'ikey 0.0.0.105')
1132 self
.assertRegex(output
, 'okey 0.0.0.105')
1133 self
.assertNotRegex(output
, 'iseq')
1134 self
.assertNotRegex(output
, 'oseq')
1135 output
= check_output('ip -d link show gretun96')
1137 self
.assertRegex(output
, 'gre remote any local any dev dummy98')
1138 self
.assertRegex(output
, 'ikey 0.0.0.106')
1139 self
.assertRegex(output
, 'okey 0.0.0.106')
1140 self
.assertNotRegex(output
, 'iseq')
1141 self
.assertNotRegex(output
, 'oseq')
1143 def test_ip6gre_tunnel(self
):
1144 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
1145 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
1146 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1147 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1148 '25-ip6gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1151 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1153 self
.check_link_exists('dummy98')
1154 self
.check_link_exists('ip6gretun99')
1155 self
.check_link_exists('ip6gretun98')
1156 self
.check_link_exists('ip6gretun97')
1157 self
.check_link_exists('ip6gretun96')
1159 output
= check_output('ip -d link show ip6gretun99')
1161 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1162 output
= check_output('ip -d link show ip6gretun98')
1164 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
1165 output
= check_output('ip -d link show ip6gretun97')
1167 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
1168 output
= check_output('ip -d link show ip6gretun96')
1170 self
.assertRegex(output
, 'ip6gre remote any local any dev dummy98')
1172 def test_gretap_tunnel(self
):
1173 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
1174 '25-gretap-tunnel.netdev', '25-tunnel.network',
1175 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1177 self
.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
1179 output
= check_output('ip -d link show gretap99')
1181 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1182 self
.assertRegex(output
, 'ikey 0.0.0.106')
1183 self
.assertRegex(output
, 'okey 0.0.0.106')
1184 self
.assertRegex(output
, 'iseq')
1185 self
.assertRegex(output
, 'oseq')
1186 output
= check_output('ip -d link show gretap98')
1188 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
1189 self
.assertRegex(output
, 'ikey 0.0.0.107')
1190 self
.assertRegex(output
, 'okey 0.0.0.107')
1191 self
.assertRegex(output
, 'iseq')
1192 self
.assertRegex(output
, 'oseq')
1194 def test_ip6gretap_tunnel(self
):
1195 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
1196 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1197 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1199 self
.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
1201 output
= check_output('ip -d link show ip6gretap99')
1203 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1204 output
= check_output('ip -d link show ip6gretap98')
1206 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1208 def test_vti_tunnel(self
):
1209 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
1210 '25-vti-tunnel.netdev', '25-tunnel.network',
1211 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1212 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1213 '25-vti-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1215 self
.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'vtitun96:routable', 'dummy98:degraded'])
1217 output
= check_output('ip -d link show vtitun99')
1219 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1220 output
= check_output('ip -d link show vtitun98')
1222 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
1223 output
= check_output('ip -d link show vtitun97')
1225 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
1226 output
= check_output('ip -d link show vtitun96')
1228 self
.assertRegex(output
, 'vti remote any local any dev dummy98')
1230 def test_vti6_tunnel(self
):
1231 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
1232 '25-vti6-tunnel.netdev', '25-tunnel.network',
1233 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1234 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1236 self
.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
1238 output
= check_output('ip -d link show vti6tun99')
1240 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1241 output
= check_output('ip -d link show vti6tun98')
1243 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1244 output
= check_output('ip -d link show vti6tun97')
1246 self
.assertRegex(output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1248 def test_ip6tnl_tunnel(self
):
1249 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
1250 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1251 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1252 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1254 self
.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
1256 output
= check_output('ip -d link show ip6tnl99')
1258 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1259 output
= check_output('ip -d link show ip6tnl98')
1261 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1262 output
= check_output('ip -d link show ip6tnl97')
1264 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1266 def test_sit_tunnel(self
):
1267 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1268 '25-sit-tunnel.netdev', '25-tunnel.network',
1269 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1270 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1271 '25-sit-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1273 self
.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'sittun96:routable', 'dummy98:degraded'])
1275 output
= check_output('ip -d link show sittun99')
1277 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1278 output
= check_output('ip -d link show sittun98')
1280 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98")
1281 output
= check_output('ip -d link show sittun97')
1283 self
.assertRegex(output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98")
1284 output
= check_output('ip -d link show sittun96')
1286 self
.assertRegex(output
, "sit (ip6ip )?remote any local any dev dummy98")
1288 def test_isatap_tunnel(self
):
1289 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1290 '25-isatap-tunnel.netdev', '25-tunnel.network')
1292 self
.wait_online(['isataptun99:routable', 'dummy98:degraded'])
1294 output
= check_output('ip -d link show isataptun99')
1296 self
.assertRegex(output
, "isatap ")
1298 def test_6rd_tunnel(self
):
1299 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1300 '25-6rd-tunnel.netdev', '25-tunnel.network')
1302 self
.wait_online(['sittun99:routable', 'dummy98:degraded'])
1304 output
= check_output('ip -d link show sittun99')
1306 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1308 @expectedFailureIfERSPANModuleIsNotAvailable()
1309 def test_erspan_tunnel(self
):
1310 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1311 '25-erspan-tunnel.netdev', '25-tunnel.network',
1312 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1314 self
.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1316 output
= check_output('ip -d link show erspan99')
1318 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1319 self
.assertRegex(output
, 'ikey 0.0.0.101')
1320 self
.assertRegex(output
, 'okey 0.0.0.101')
1321 self
.assertRegex(output
, 'iseq')
1322 self
.assertRegex(output
, 'oseq')
1323 output
= check_output('ip -d link show erspan98')
1325 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1326 self
.assertRegex(output
, '102')
1327 self
.assertRegex(output
, 'ikey 0.0.0.102')
1328 self
.assertRegex(output
, 'okey 0.0.0.102')
1329 self
.assertRegex(output
, 'iseq')
1330 self
.assertRegex(output
, 'oseq')
1332 def test_tunnel_independent(self
):
1333 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1336 self
.wait_online(['ipiptun99:carrier'])
1338 def test_tunnel_independent_loopback(self
):
1339 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent-loopback.netdev', 'netdev-link-local-addressing-yes.network')
1342 self
.wait_online(['ipiptun99:carrier'])
1344 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1345 def test_xfrm(self
):
1346 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'xfrm.network',
1347 '25-xfrm.netdev', 'netdev-link-local-addressing-yes.network')
1350 self
.wait_online(['xfrm99:degraded', 'dummy98:degraded'])
1352 output
= check_output('ip link show dev xfrm99')
1355 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1356 def test_xfrm_independent(self
):
1357 copy_unit_to_networkd_unit_path('25-xfrm-independent.netdev', 'netdev-link-local-addressing-yes.network')
1360 self
.wait_online(['xfrm99:degraded'])
1362 @expectedFailureIfModuleIsNotAvailable('fou')
1364 # The following redundant check is necessary for CentOS CI.
1365 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1366 self
.assertTrue(is_module_available('fou'))
1368 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1369 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1370 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1373 self
.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'], setup_state
='unmanaged')
1375 output
= check_output('ip fou show')
1377 self
.assertRegex(output
, 'port 55555 ipproto 4')
1378 self
.assertRegex(output
, 'port 55556 ipproto 47')
1380 output
= check_output('ip -d link show ipiptun96')
1382 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1383 output
= check_output('ip -d link show sittun96')
1385 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1386 output
= check_output('ip -d link show gretun96')
1388 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1389 output
= check_output('ip -d link show gretap96')
1391 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1393 def test_vxlan(self
):
1394 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1395 '11-dummy.netdev', 'vxlan-test1.network')
1398 self
.wait_online(['test1:degraded', 'vxlan99:degraded'])
1400 output
= check_output('ip -d link show vxlan99')
1402 self
.assertRegex(output
, '999')
1403 self
.assertRegex(output
, '5555')
1404 self
.assertRegex(output
, 'l2miss')
1405 self
.assertRegex(output
, 'l3miss')
1406 self
.assertRegex(output
, 'udpcsum')
1407 self
.assertRegex(output
, 'udp6zerocsumtx')
1408 self
.assertRegex(output
, 'udp6zerocsumrx')
1409 self
.assertRegex(output
, 'remcsumtx')
1410 self
.assertRegex(output
, 'remcsumrx')
1411 self
.assertRegex(output
, 'gbp')
1413 output
= check_output('bridge fdb show dev vxlan99')
1415 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1416 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1417 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1419 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'vxlan99', env
=env
)
1421 self
.assertRegex(output
, 'VNI: 999')
1422 self
.assertRegex(output
, 'Destination Port: 5555')
1423 self
.assertRegex(output
, 'Underlying Device: test1')
1425 def test_macsec(self
):
1426 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1427 'macsec.network', '12-dummy.netdev')
1430 self
.wait_online(['dummy98:degraded', 'macsec99:routable'])
1432 output
= check_output('ip -d link show macsec99')
1434 self
.assertRegex(output
, 'macsec99@dummy98')
1435 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1436 self
.assertRegex(output
, 'encrypt on')
1438 output
= check_output('ip macsec show macsec99')
1440 self
.assertRegex(output
, 'encrypt on')
1441 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1442 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1443 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1444 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1445 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1446 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1447 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1448 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1449 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1450 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1451 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1453 def test_nlmon(self
):
1454 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1457 self
.wait_online(['nlmon99:carrier'])
1459 @expectedFailureIfModuleIsNotAvailable('ifb')
1461 copy_unit_to_networkd_unit_path('25-ifb.netdev', 'netdev-link-local-addressing-yes.network')
1464 self
.wait_online(['ifb99:degraded'])
1466 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1477 '25-l2tp-dummy.network',
1479 '25-l2tp-ip.netdev',
1480 '25-l2tp-udp.netdev']
1482 l2tp_tunnel_ids
= [ '10' ]
1485 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1486 remove_links(self
.links
)
1487 stop_networkd(show_logs
=False)
1490 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1491 remove_links(self
.links
)
1492 remove_unit_from_networkd_path(self
.units
)
1493 stop_networkd(show_logs
=True)
1495 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1496 def test_l2tp_udp(self
):
1497 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1498 '25-l2tp-udp.netdev', '25-l2tp.network')
1501 self
.wait_online(['test1:routable', 'l2tp-ses1:degraded', 'l2tp-ses2:degraded'])
1503 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1505 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1506 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1507 self
.assertRegex(output
, "Peer tunnel 11")
1508 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1509 self
.assertRegex(output
, "UDP checksum: enabled")
1511 output
= check_output('ip l2tp show session tid 10 session_id 15')
1513 self
.assertRegex(output
, "Session 15 in tunnel 10")
1514 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1515 self
.assertRegex(output
, "interface name: l2tp-ses1")
1517 output
= check_output('ip l2tp show session tid 10 session_id 17')
1519 self
.assertRegex(output
, "Session 17 in tunnel 10")
1520 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1521 self
.assertRegex(output
, "interface name: l2tp-ses2")
1523 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1524 def test_l2tp_ip(self
):
1525 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1526 '25-l2tp-ip.netdev', '25-l2tp.network')
1529 self
.wait_online(['test1:routable', 'l2tp-ses3:degraded', 'l2tp-ses4:degraded'])
1531 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1533 self
.assertRegex(output
, "Tunnel 10, encap IP")
1534 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1535 self
.assertRegex(output
, "Peer tunnel 12")
1537 output
= check_output('ip l2tp show session tid 10 session_id 25')
1539 self
.assertRegex(output
, "Session 25 in tunnel 10")
1540 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1541 self
.assertRegex(output
, "interface name: l2tp-ses3")
1543 output
= check_output('ip l2tp show session tid 10 session_id 27')
1545 self
.assertRegex(output
, "Session 27 in tunnel 10")
1546 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1547 self
.assertRegex(output
, "interface name: l2tp-ses4")
1549 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1563 '23-active-slave.network',
1564 '24-keep-configuration-static.network',
1565 '24-search-domain.network',
1566 '25-address-dad-veth-peer.network',
1567 '25-address-dad-veth99.network',
1568 '25-address-link-section.network',
1569 '25-address-preferred-lifetime-zero.network',
1570 '25-address-static.network',
1571 '25-bind-carrier.network',
1572 '25-bond-active-backup-slave.netdev',
1573 '25-fibrule-invert.network',
1574 '25-fibrule-port-range.network',
1575 '25-gre-tunnel-remote-any.netdev',
1576 '25-ip6gre-tunnel-remote-any.netdev',
1577 '25-ipv6-address-label-section.network',
1578 '25-link-local-addressing-no.network',
1579 '25-link-local-addressing-yes.network',
1580 '25-link-section-unmanaged.network',
1581 '25-neighbor-section.network',
1582 '25-neighbor-next.network',
1583 '25-neighbor-ipv6.network',
1584 '25-neighbor-ip-dummy.network',
1585 '25-neighbor-ip.network',
1586 '25-nexthop.network',
1587 '25-qdisc-fq-codel.network',
1588 '25-qdisc-netem-and-fqcodel.network',
1589 '25-qdisc-tbf-and-sfq.network',
1590 '25-route-ipv6-src.network',
1591 '25-route-static.network',
1592 '25-gateway-static.network',
1593 '25-gateway-next-static.network',
1594 '25-sysctl-disable-ipv6.network',
1595 '25-sysctl.network',
1596 '25-veth-peer.network',
1598 '26-link-local-addressing-ipv6.network',
1599 'configure-without-carrier.network',
1600 'routing-policy-rule-dummy98.network',
1601 'routing-policy-rule-test1.network']
1603 routing_policy_rule_tables
= ['7', '8', '9']
1604 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1607 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1608 remove_routes(self
.routes
)
1609 remove_links(self
.links
)
1610 stop_networkd(show_logs
=False)
1613 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1614 remove_routes(self
.routes
)
1615 remove_links(self
.links
)
1616 remove_unit_from_networkd_path(self
.units
)
1617 stop_networkd(show_logs
=True)
1619 def test_address_static(self
):
1620 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1623 self
.wait_online(['dummy98:routable'])
1625 output
= check_output('ip -4 address show dev dummy98')
1627 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1628 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1629 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1632 self
.assertNotRegex(output
, '10.10.0.1/16')
1633 self
.assertNotRegex(output
, '10.10.0.2/16')
1635 output
= check_output('ip -4 address show dev dummy98 label 32')
1636 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1638 output
= check_output('ip -4 address show dev dummy98 label 33')
1639 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1641 output
= check_output('ip -4 address show dev dummy98 label 34')
1642 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1644 output
= check_output('ip -4 address show dev dummy98 label 35')
1645 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1647 output
= check_output('ip -6 address show dev dummy98')
1649 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1650 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1651 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1652 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1653 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1654 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1656 def test_address_preferred_lifetime_zero_ipv6(self
):
1657 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero.network', '12-dummy.netdev')
1660 self
.wait_online(['dummy98:routable'])
1662 output
= check_output('ip address show dummy98')
1664 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1665 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1667 output
= check_output('ip route show dev dummy98')
1669 self
.assertRegex(output
, 'default via 20.20.20.1 proto static')
1671 def test_address_dad(self
):
1672 copy_unit_to_networkd_unit_path('25-address-dad-veth99.network', '25-address-dad-veth-peer.network',
1675 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
1677 output
= check_output('ip -4 address show dev veth99')
1679 self
.assertRegex(output
, '192.168.100.10/24')
1681 output
= check_output('ip -4 address show dev veth-peer')
1683 self
.assertNotRegex(output
, '192.168.100.10/24')
1685 def test_configure_without_carrier(self
):
1686 copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
1688 self
.wait_online(['test1:routable'])
1690 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
1692 self
.assertRegex(output
, '192.168.0.15')
1693 self
.assertRegex(output
, '192.168.0.1')
1694 self
.assertRegex(output
, 'routable')
1696 def test_routing_policy_rule(self
):
1697 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1699 self
.wait_online(['test1:degraded'])
1701 output
= check_output('ip rule list iif test1 priority 111')
1703 self
.assertRegex(output
, '111:')
1704 self
.assertRegex(output
, 'from 192.168.100.18')
1705 self
.assertRegex(output
, r
'tos (0x08|throughput)\s')
1706 self
.assertRegex(output
, 'iif test1')
1707 self
.assertRegex(output
, 'oif test1')
1708 self
.assertRegex(output
, 'lookup 7')
1710 output
= check_output('ip rule list iif test1 priority 101')
1712 self
.assertRegex(output
, '101:')
1713 self
.assertRegex(output
, 'from all')
1714 self
.assertRegex(output
, 'iif test1')
1715 self
.assertRegex(output
, 'lookup 9')
1717 output
= check_output('ip -6 rule list iif test1 priority 100')
1719 self
.assertRegex(output
, '100:')
1720 self
.assertRegex(output
, 'from all')
1721 self
.assertRegex(output
, 'iif test1')
1722 self
.assertRegex(output
, 'lookup 8')
1724 output
= check_output('ip -6 rule list iif test1 priority 101')
1726 self
.assertRegex(output
, '101:')
1727 self
.assertRegex(output
, 'from all')
1728 self
.assertRegex(output
, 'iif test1')
1729 self
.assertRegex(output
, 'lookup 9')
1731 def test_routing_policy_rule_issue_11280(self
):
1732 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1733 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1735 for trial
in range(3):
1736 # Remove state files only first time
1738 self
.wait_online(['test1:degraded', 'dummy98:degraded'])
1741 output
= check_output('ip rule list table 7')
1743 self
.assertRegex(output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
1745 output
= check_output('ip rule list table 8')
1747 self
.assertRegex(output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1749 stop_networkd(remove_state_files
=False)
1751 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1752 def test_routing_policy_rule_port_range(self
):
1753 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1755 self
.wait_online(['test1:degraded'])
1757 output
= check_output('ip rule')
1759 self
.assertRegex(output
, '111')
1760 self
.assertRegex(output
, 'from 192.168.100.18')
1761 self
.assertRegex(output
, '1123-1150')
1762 self
.assertRegex(output
, '3224-3290')
1763 self
.assertRegex(output
, 'tcp')
1764 self
.assertRegex(output
, 'lookup 7')
1766 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1767 def test_routing_policy_rule_invert(self
):
1768 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1770 self
.wait_online(['test1:degraded'])
1772 output
= check_output('ip rule')
1774 self
.assertRegex(output
, '111')
1775 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
1776 self
.assertRegex(output
, 'tcp')
1777 self
.assertRegex(output
, 'lookup 7')
1779 def test_route_static(self
):
1780 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1782 self
.wait_online(['dummy98:routable'])
1784 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
1787 print('### ip -6 route show dev dummy98')
1788 output
= check_output('ip -6 route show dev dummy98')
1790 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1791 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
1793 print('### ip -6 route show dev dummy98 default')
1794 output
= check_output('ip -6 route show dev dummy98 default')
1796 self
.assertRegex(output
, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1798 print('### ip -4 route show dev dummy98')
1799 output
= check_output('ip -4 route show dev dummy98')
1801 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1802 self
.assertRegex(output
, '149.10.124.64 proto static scope link')
1803 self
.assertRegex(output
, '169.254.0.0/16 proto static scope link metric 2048')
1804 self
.assertRegex(output
, '192.168.1.1 proto static initcwnd 20')
1805 self
.assertRegex(output
, '192.168.1.2 proto static initrwnd 30')
1806 self
.assertRegex(output
, 'multicast 149.10.123.4 proto static')
1808 print('### ip -4 route show dev dummy98 default')
1809 output
= check_output('ip -4 route show dev dummy98 default')
1811 self
.assertRegex(output
, 'default via 149.10.125.65 proto static onlink')
1812 self
.assertRegex(output
, 'default via 149.10.124.64 proto static')
1813 self
.assertRegex(output
, 'default proto static')
1815 print('### ip -4 route show table local dev dummy98')
1816 output
= check_output('ip -4 route show table local dev dummy98')
1818 self
.assertRegex(output
, 'local 149.10.123.1 proto static scope host')
1819 self
.assertRegex(output
, 'anycast 149.10.123.2 proto static scope link')
1820 self
.assertRegex(output
, 'broadcast 149.10.123.3 proto static scope link')
1822 print('### ip route show type blackhole')
1823 output
= check_output('ip route show type blackhole')
1825 self
.assertRegex(output
, 'blackhole 202.54.1.2 proto static')
1827 print('### ip route show type unreachable')
1828 output
= check_output('ip route show type unreachable')
1830 self
.assertRegex(output
, 'unreachable 202.54.1.3 proto static')
1832 print('### ip route show type prohibit')
1833 output
= check_output('ip route show type prohibit')
1835 self
.assertRegex(output
, 'prohibit 202.54.1.4 proto static')
1837 print('### ip route show 192.168.10.1')
1838 output
= check_output('ip route show 192.168.10.1')
1840 self
.assertRegex(output
, '192.168.10.1 proto static')
1841 self
.assertRegex(output
, 'nexthop via 149.10.124.59 dev dummy98 weight 10')
1842 self
.assertRegex(output
, 'nexthop via 149.10.124.60 dev dummy98 weight 5')
1844 print('### ip route show 192.168.10.2')
1845 output
= check_output('ip route show 192.168.10.2')
1847 # old ip command does not show IPv6 gateways...
1848 self
.assertRegex(output
, '192.168.10.2 proto static')
1849 self
.assertRegex(output
, 'nexthop')
1850 self
.assertRegex(output
, 'dev dummy98 weight 10')
1851 self
.assertRegex(output
, 'dev dummy98 weight 5')
1853 print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
1854 output
= check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
1856 # old ip command does not show 'nexthop' keyword and weight...
1857 self
.assertRegex(output
, '2001:1234:5:7fff:ff:ff:ff:ff')
1858 self
.assertRegex(output
, 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98')
1859 self
.assertRegex(output
, 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98')
1861 def test_gateway_reconfigure(self
):
1862 copy_unit_to_networkd_unit_path('25-gateway-static.network', '12-dummy.netdev')
1864 self
.wait_online(['dummy98:routable'])
1865 print('### ip -4 route show dev dummy98 default')
1866 output
= check_output('ip -4 route show dev dummy98 default')
1868 self
.assertRegex(output
, 'default via 149.10.124.59 proto static')
1869 self
.assertNotRegex(output
, '149.10.124.60')
1871 remove_unit_from_networkd_path(['25-gateway-static.network'])
1872 copy_unit_to_networkd_unit_path('25-gateway-next-static.network')
1874 self
.wait_online(['dummy98:routable'])
1875 print('### ip -4 route show dev dummy98 default')
1876 output
= check_output('ip -4 route show dev dummy98 default')
1878 self
.assertNotRegex(output
, '149.10.124.59')
1879 self
.assertRegex(output
, 'default via 149.10.124.60 proto static')
1881 def test_ip_route_ipv6_src_route(self
):
1882 # a dummy device does not make the addresses go through tentative state, so we
1883 # reuse a bond from an earlier test, which does make the addresses go through
1884 # tentative state, and do our test on that
1885 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1887 self
.wait_online(['dummy98:enslaved', 'bond199:routable'])
1889 output
= check_output('ip -6 route list dev bond199')
1891 self
.assertRegex(output
, 'abcd::/16')
1892 self
.assertRegex(output
, 'src')
1893 self
.assertRegex(output
, '2001:1234:56:8f63::2')
1895 def test_ip_link_mac_address(self
):
1896 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
1898 self
.wait_online(['dummy98:degraded'])
1900 output
= check_output('ip link show dummy98')
1902 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
1904 def test_ip_link_unmanaged(self
):
1905 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
1908 self
.check_link_exists('dummy98')
1910 self
.wait_operstate('dummy98', 'off', setup_state
='unmanaged')
1912 def test_ipv6_address_label(self
):
1913 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
1915 self
.wait_online(['dummy98:degraded'])
1917 output
= check_output('ip addrlabel list')
1919 self
.assertRegex(output
, '2004:da8:1::/64')
1921 def test_neighbor_section(self
):
1922 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
1924 self
.wait_online(['dummy98:degraded'], timeout
='40s')
1926 print('### ip neigh list dev dummy98')
1927 output
= check_output('ip neigh list dev dummy98')
1929 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
1930 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
1932 def test_neighbor_reconfigure(self
):
1933 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
1935 self
.wait_online(['dummy98:degraded'], timeout
='40s')
1937 print('### ip neigh list dev dummy98')
1938 output
= check_output('ip neigh list dev dummy98')
1940 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
1941 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
1943 remove_unit_from_networkd_path(['25-neighbor-section.network'])
1944 copy_unit_to_networkd_unit_path('25-neighbor-next.network')
1946 self
.wait_online(['dummy98:degraded'], timeout
='40s')
1947 print('### ip neigh list dev dummy98')
1948 output
= check_output('ip neigh list dev dummy98')
1950 self
.assertNotRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
1951 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT')
1952 self
.assertNotRegex(output
, '2004:da8:1::1.*PERMANENT')
1954 def test_neighbor_gre(self
):
1955 copy_unit_to_networkd_unit_path('25-neighbor-ip.network', '25-neighbor-ipv6.network', '25-neighbor-ip-dummy.network',
1956 '12-dummy.netdev', '25-gre-tunnel-remote-any.netdev', '25-ip6gre-tunnel-remote-any.netdev')
1958 self
.wait_online(['dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable'], timeout
='40s')
1960 output
= check_output('ip neigh list dev gretun97')
1962 self
.assertRegex(output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT')
1964 output
= check_output('ip neigh list dev ip6gretun97')
1966 self
.assertRegex(output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
1968 def test_link_local_addressing(self
):
1969 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
1970 '25-link-local-addressing-no.network', '12-dummy.netdev')
1972 self
.wait_online(['test1:degraded', 'dummy98:carrier'])
1974 output
= check_output('ip address show dev test1')
1976 self
.assertRegex(output
, 'inet .* scope link')
1977 self
.assertRegex(output
, 'inet6 .* scope link')
1979 output
= check_output('ip address show dev dummy98')
1981 self
.assertNotRegex(output
, 'inet6* .* scope link')
1984 Documentation/networking/ip-sysctl.txt
1986 addr_gen_mode - INTEGER
1987 Defines how link-local and autoconf addresses are generated.
1989 0: generate address based on EUI64 (default)
1990 1: do no generate a link-local address, use EUI64 for addresses generated
1992 2: generate stable privacy addresses, using the secret from
1993 stable_secret (RFC7217)
1994 3: generate stable privacy addresses, using a random secret if unset
1997 test1_addr_gen_mode
= ''
1998 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
1999 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
2003 # if stable_secret is unset, then EIO is returned
2004 test1_addr_gen_mode
= '0'
2006 test1_addr_gen_mode
= '2'
2008 test1_addr_gen_mode
= '0'
2010 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
2011 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
2013 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
2014 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
2016 def test_link_local_addressing_remove_ipv6ll(self
):
2017 copy_unit_to_networkd_unit_path('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
2019 self
.wait_online(['dummy98:degraded'])
2021 output
= check_output('ip address show dev dummy98')
2023 self
.assertRegex(output
, 'inet6 .* scope link')
2025 copy_unit_to_networkd_unit_path('25-link-local-addressing-no.network')
2027 self
.wait_online(['dummy98:carrier'])
2029 output
= check_output('ip address show dev dummy98')
2031 self
.assertNotRegex(output
, 'inet6* .* scope link')
2033 def test_sysctl(self
):
2034 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
2036 self
.wait_online(['dummy98:degraded'])
2038 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
2039 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
2040 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
2041 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
2042 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
2043 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
2044 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
2046 def test_sysctl_disable_ipv6(self
):
2047 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
2049 print('## Disable ipv6')
2050 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
2051 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
2054 self
.wait_online(['dummy98:routable'])
2056 output
= check_output('ip -4 address show dummy98')
2058 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2059 output
= check_output('ip -6 address show dummy98')
2061 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2062 self
.assertRegex(output
, 'inet6 .* scope link')
2063 output
= check_output('ip -4 route show dev dummy98')
2065 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2066 output
= check_output('ip -6 route show dev dummy98')
2068 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2070 check_output('ip link del dummy98')
2072 print('## Enable ipv6')
2073 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
2074 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
2077 self
.wait_online(['dummy98:routable'])
2079 output
= check_output('ip -4 address show dummy98')
2081 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2082 output
= check_output('ip -6 address show dummy98')
2084 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2085 self
.assertRegex(output
, 'inet6 .* scope link')
2086 output
= check_output('ip -4 route show dev dummy98')
2088 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2089 output
= check_output('ip -6 route show dev dummy98')
2091 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2093 def test_bind_carrier(self
):
2094 check_output('ip link add dummy98 type dummy')
2095 check_output('ip link set dummy98 up')
2098 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
2100 self
.wait_online(['test1:routable'])
2102 output
= check_output('ip address show test1')
2104 self
.assertRegex(output
, 'UP,LOWER_UP')
2105 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2106 self
.wait_operstate('test1', 'routable')
2108 check_output('ip link add dummy99 type dummy')
2109 check_output('ip link set dummy99 up')
2111 output
= check_output('ip address show test1')
2113 self
.assertRegex(output
, 'UP,LOWER_UP')
2114 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2115 self
.wait_operstate('test1', 'routable')
2117 check_output('ip link del dummy98')
2119 output
= check_output('ip address show test1')
2121 self
.assertRegex(output
, 'UP,LOWER_UP')
2122 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2123 self
.wait_operstate('test1', 'routable')
2125 check_output('ip link set dummy99 down')
2127 output
= check_output('ip address show test1')
2129 self
.assertNotRegex(output
, 'UP,LOWER_UP')
2130 self
.assertRegex(output
, 'DOWN')
2131 self
.assertNotRegex(output
, '192.168.10')
2132 self
.wait_operstate('test1', 'off')
2134 check_output('ip link set dummy99 up')
2136 output
= check_output('ip address show test1')
2138 self
.assertRegex(output
, 'UP,LOWER_UP')
2139 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2140 self
.wait_operstate('test1', 'routable')
2142 def test_domain(self
):
2143 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
2145 self
.wait_online(['dummy98:routable'])
2147 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2149 self
.assertRegex(output
, 'Address: 192.168.42.100')
2150 self
.assertRegex(output
, 'DNS: 192.168.42.1')
2151 self
.assertRegex(output
, 'Search Domains: one')
2153 def test_keep_configuration_static(self
):
2154 check_output('systemctl stop systemd-networkd')
2156 check_output('ip link add name dummy98 type dummy')
2157 check_output('ip address add 10.1.2.3/16 dev dummy98')
2158 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
2159 output
= check_output('ip address show dummy98')
2161 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2162 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2163 output
= check_output('ip route show dev dummy98')
2166 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
2168 self
.wait_online(['dummy98:routable'])
2170 output
= check_output('ip address show dummy98')
2172 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2173 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2175 @expectedFailureIfNexthopIsNotAvailable()
2176 def test_nexthop(self
):
2177 copy_unit_to_networkd_unit_path('25-nexthop.network', '25-veth.netdev', '25-veth-peer.network')
2179 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2181 output
= check_output('ip nexthop list dev veth99')
2183 self
.assertRegex(output
, '192.168.5.1')
2185 def test_qdisc(self
):
2186 copy_unit_to_networkd_unit_path('25-qdisc-netem-and-fqcodel.network', '12-dummy.netdev',
2187 '25-qdisc-tbf-and-sfq.network', '11-dummy.netdev')
2190 self
.wait_online(['dummy98:routable', 'test1:routable'])
2192 output
= check_output('tc qdisc show dev dummy98')
2194 self
.assertRegex(output
, 'qdisc netem')
2195 self
.assertRegex(output
, 'limit 100 delay 50.0ms 10.0ms loss 20%')
2196 self
.assertRegex(output
, 'qdisc fq_codel')
2197 self
.assertRegex(output
, 'limit 20480p flows 2048 quantum 1400 target 10.0ms ce_threshold 100.0ms interval 200.0ms memory_limit 64Mb ecn')
2198 output
= check_output('tc qdisc show dev test1')
2200 self
.assertRegex(output
, 'qdisc tbf')
2201 self
.assertRegex(output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70.0ms')
2202 self
.assertRegex(output
, 'qdisc sfq')
2203 self
.assertRegex(output
, 'perturb 5sec')
2205 def test_qdisc2(self
):
2206 copy_unit_to_networkd_unit_path('25-qdisc-fq-codel.network', '12-dummy.netdev')
2209 self
.wait_online(['dummy98:routable'])
2211 output
= check_output('tc qdisc show dev dummy98')
2213 self
.assertRegex(output
, 'qdisc fq')
2214 self
.assertRegex(output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
2215 self
.assertRegex(output
, 'quantum 1500')
2216 self
.assertRegex(output
, 'initial_quantum 13000')
2217 self
.assertRegex(output
, 'maxrate 1Mbit')
2218 self
.assertRegex(output
, 'qdisc codel')
2219 self
.assertRegex(output
, 'limit 2000p target 10.0ms ce_threshold 100.0ms interval 50.0ms ecn')
2221 class NetworkdStateFileTests(unittest
.TestCase
, Utilities
):
2228 'state-file-tests.network',
2232 remove_links(self
.links
)
2233 stop_networkd(show_logs
=False)
2236 remove_links(self
.links
)
2237 remove_unit_from_networkd_path(self
.units
)
2238 stop_networkd(show_logs
=True)
2240 def test_state_file(self
):
2241 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'state-file-tests.network')
2243 self
.wait_online(['dummy98:routable'])
2245 output
= check_output(*networkctl_cmd
, '--no-legend', 'list', 'dummy98', env
=env
)
2247 ifindex
= output
.split()[0]
2249 path
= os
.path
.join('/run/systemd/netif/links/', ifindex
)
2250 self
.assertTrue(os
.path
.exists(path
))
2253 with
open(path
) as f
:
2255 self
.assertRegex(data
, r
'ADMIN_STATE=configured')
2256 self
.assertRegex(data
, r
'OPER_STATE=routable')
2257 self
.assertRegex(data
, r
'REQUIRED_FOR_ONLINE=yes')
2258 self
.assertRegex(data
, r
'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
2259 self
.assertRegex(data
, r
'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
2260 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
2261 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2262 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2263 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2264 self
.assertRegex(data
, r
'LLMNR=no')
2265 self
.assertRegex(data
, r
'MDNS=yes')
2266 self
.assertRegex(data
, r
'DNSSEC=no')
2267 self
.assertRegex(data
, r
'ADDRESSES=192.168.(10.10|12.12)/24 192.168.(12.12|10.10)/24')
2269 check_output(*resolvectl_cmd
, 'dns', 'dummy98', '10.10.10.12', '10.10.10.13', env
=env
)
2270 check_output(*resolvectl_cmd
, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env
=env
)
2271 check_output(*resolvectl_cmd
, 'llmnr', 'dummy98', 'yes', env
=env
)
2272 check_output(*resolvectl_cmd
, 'mdns', 'dummy98', 'no', env
=env
)
2273 check_output(*resolvectl_cmd
, 'dnssec', 'dummy98', 'yes', env
=env
)
2274 check_output(*timedatectl_cmd
, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env
=env
)
2277 with
open(path
) as f
:
2279 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
2280 self
.assertRegex(data
, r
'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org')
2281 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2282 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2283 self
.assertRegex(data
, r
'LLMNR=yes')
2284 self
.assertRegex(data
, r
'MDNS=no')
2285 self
.assertRegex(data
, r
'DNSSEC=yes')
2287 check_output(*timedatectl_cmd
, 'revert', 'dummy98', env
=env
)
2290 with
open(path
) as f
:
2292 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
2293 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2294 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2295 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2296 self
.assertRegex(data
, r
'LLMNR=yes')
2297 self
.assertRegex(data
, r
'MDNS=no')
2298 self
.assertRegex(data
, r
'DNSSEC=yes')
2300 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
2303 with
open(path
) as f
:
2305 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
2306 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2307 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2308 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2309 self
.assertRegex(data
, r
'LLMNR=no')
2310 self
.assertRegex(data
, r
'MDNS=yes')
2311 self
.assertRegex(data
, r
'DNSSEC=no')
2313 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
2323 '23-active-slave.network',
2324 '23-bond199.network',
2325 '23-primary-slave.network',
2326 '25-bond-active-backup-slave.netdev',
2329 'bond-slave.network']
2332 remove_links(self
.links
)
2333 stop_networkd(show_logs
=False)
2336 remove_links(self
.links
)
2337 remove_unit_from_networkd_path(self
.units
)
2338 stop_networkd(show_logs
=True)
2340 def test_bond_active_slave(self
):
2341 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2343 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2345 output
= check_output('ip -d link show bond199')
2347 self
.assertRegex(output
, 'active_slave dummy98')
2349 def test_bond_primary_slave(self
):
2350 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2352 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2354 output
= check_output('ip -d link show bond199')
2356 self
.assertRegex(output
, 'primary dummy98')
2358 def test_bond_operstate(self
):
2359 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
2360 'bond99.network','bond-slave.network')
2362 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
2364 output
= check_output('ip -d link show dummy98')
2366 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2368 output
= check_output('ip -d link show test1')
2370 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2372 output
= check_output('ip -d link show bond99')
2374 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
2376 self
.wait_operstate('dummy98', 'enslaved')
2377 self
.wait_operstate('test1', 'enslaved')
2378 self
.wait_operstate('bond99', 'routable')
2380 check_output('ip link set dummy98 down')
2382 self
.wait_operstate('dummy98', 'off')
2383 self
.wait_operstate('test1', 'enslaved')
2384 self
.wait_operstate('bond99', 'degraded-carrier')
2386 check_output('ip link set dummy98 up')
2388 self
.wait_operstate('dummy98', 'enslaved')
2389 self
.wait_operstate('test1', 'enslaved')
2390 self
.wait_operstate('bond99', 'routable')
2392 check_output('ip link set dummy98 down')
2393 check_output('ip link set test1 down')
2395 self
.wait_operstate('dummy98', 'off')
2396 self
.wait_operstate('test1', 'off')
2398 if not self
.wait_operstate('bond99', 'no-carrier', setup_timeout
=30, fail_assert
=False):
2399 # Huh? Kernel does not recognize that all slave interfaces are down?
2400 # Let's confirm that networkd's operstate is consistent with ip's result.
2401 self
.assertNotRegex(output
, 'NO-CARRIER')
2403 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
2413 '26-bridge-slave-interface-1.network',
2414 '26-bridge-slave-interface-2.network',
2415 '26-bridge-vlan-master.network',
2416 '26-bridge-vlan-slave.network',
2417 'bridge99-ignore-carrier-loss.network',
2420 routing_policy_rule_tables
= ['100']
2423 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2424 remove_links(self
.links
)
2425 stop_networkd(show_logs
=False)
2428 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2429 remove_links(self
.links
)
2430 remove_unit_from_networkd_path(self
.units
)
2431 stop_networkd(show_logs
=True)
2433 def test_bridge_vlan(self
):
2434 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
2435 '26-bridge.netdev', '26-bridge-vlan-master.network')
2437 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
2439 output
= check_output('bridge vlan show dev test1')
2441 self
.assertNotRegex(output
, '4063')
2442 for i
in range(4064, 4095):
2443 self
.assertRegex(output
, f
'{i}')
2444 self
.assertNotRegex(output
, '4095')
2446 output
= check_output('bridge vlan show dev bridge99')
2448 self
.assertNotRegex(output
, '4059')
2449 for i
in range(4060, 4095):
2450 self
.assertRegex(output
, f
'{i}')
2451 self
.assertNotRegex(output
, '4095')
2453 def test_bridge_property(self
):
2454 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2455 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2458 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2460 output
= check_output('ip -d link show test1')
2462 self
.assertRegex(output
, 'master')
2463 self
.assertRegex(output
, 'bridge')
2465 output
= check_output('ip -d link show dummy98')
2467 self
.assertRegex(output
, 'master')
2468 self
.assertRegex(output
, 'bridge')
2470 output
= check_output('ip addr show bridge99')
2472 self
.assertRegex(output
, '192.168.0.15/24')
2474 output
= check_output('bridge -d link show dummy98')
2476 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
2477 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
2478 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
2479 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
2480 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
2481 # CONFIG_BRIDGE_IGMP_SNOOPING=y
2482 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
2483 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
2484 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
2485 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
2486 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
2487 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'priority'), '23')
2488 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard'), '1')
2489 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'root_block'), '1')
2491 output
= check_output('bridge -d link show test1')
2493 self
.assertEqual(read_bridge_port_attr('bridge99', 'test1', 'priority'), '0')
2495 check_output('ip address add 192.168.0.16/24 dev bridge99')
2498 output
= check_output('ip addr show bridge99')
2500 self
.assertRegex(output
, '192.168.0.16/24')
2503 print('### ip -6 route list table all dev bridge99')
2504 output
= check_output('ip -6 route list table all dev bridge99')
2506 self
.assertRegex(output
, 'ff00::/8 table local metric 256 pref medium')
2508 self
.assertEqual(call('ip link del test1'), 0)
2510 self
.wait_operstate('bridge99', 'degraded-carrier')
2512 check_output('ip link del dummy98')
2514 self
.wait_operstate('bridge99', 'no-carrier')
2516 output
= check_output('ip address show bridge99')
2518 self
.assertRegex(output
, 'NO-CARRIER')
2519 self
.assertNotRegex(output
, '192.168.0.15/24')
2520 self
.assertNotRegex(output
, '192.168.0.16/24')
2522 print('### ip -6 route list table all dev bridge99')
2523 output
= check_output('ip -6 route list table all dev bridge99')
2525 self
.assertRegex(output
, 'ff00::/8 table local metric 256 (linkdown )?pref medium')
2527 def test_bridge_ignore_carrier_loss(self
):
2528 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2529 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2530 'bridge99-ignore-carrier-loss.network')
2532 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2534 check_output('ip address add 192.168.0.16/24 dev bridge99')
2537 check_output('ip link del test1')
2538 check_output('ip link del dummy98')
2541 output
= check_output('ip address show bridge99')
2543 self
.assertRegex(output
, 'NO-CARRIER')
2544 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2545 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
2547 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
2548 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
2549 'bridge99-ignore-carrier-loss.network')
2551 self
.wait_online(['bridge99:no-carrier'])
2553 for trial
in range(4):
2554 check_output('ip link add dummy98 type dummy')
2555 check_output('ip link set dummy98 up')
2557 check_output('ip link del dummy98')
2559 self
.wait_online(['bridge99:routable', 'dummy98:enslaved'])
2561 output
= check_output('ip address show bridge99')
2563 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2565 output
= check_output('ip rule list table 100')
2567 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
2569 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
2573 '23-emit-lldp.network',
2578 remove_links(self
.links
)
2579 stop_networkd(show_logs
=False)
2582 remove_links(self
.links
)
2583 remove_unit_from_networkd_path(self
.units
)
2584 stop_networkd(show_logs
=True)
2586 def test_lldp(self
):
2587 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
2589 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
2591 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
2593 self
.assertRegex(output
, 'veth-peer')
2594 self
.assertRegex(output
, 'veth99')
2596 class NetworkdRATests(unittest
.TestCase
, Utilities
):
2601 'ipv6-prefix.network',
2602 'ipv6-prefix-veth.network']
2605 remove_links(self
.links
)
2606 stop_networkd(show_logs
=False)
2609 remove_links(self
.links
)
2610 remove_unit_from_networkd_path(self
.units
)
2611 stop_networkd(show_logs
=True)
2613 def test_ipv6_prefix_delegation(self
):
2614 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
2616 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2618 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2620 self
.assertRegex(output
, '2002:da8:1:0')
2622 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
2627 'dhcp-client.network',
2628 'dhcp-client-timezone-router.network',
2629 'dhcp-server.network',
2630 'dhcp-server-timezone-router.network']
2633 remove_links(self
.links
)
2634 stop_networkd(show_logs
=False)
2637 remove_links(self
.links
)
2638 remove_unit_from_networkd_path(self
.units
)
2639 stop_networkd(show_logs
=True)
2641 def test_dhcp_server(self
):
2642 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
2644 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2646 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2648 self
.assertRegex(output
, '192.168.5.*')
2649 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
2650 self
.assertRegex(output
, 'DNS: 192.168.5.1')
2651 self
.assertRegex(output
, 'NTP: 192.168.5.1')
2653 def test_emit_router_timezone(self
):
2654 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
2656 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2658 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2660 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
2661 self
.assertRegex(output
, '192.168.5.*')
2662 self
.assertRegex(output
, 'Europe/Berlin')
2664 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
2673 'dhcp-client-anonymize.network',
2674 'dhcp-client-decline.network',
2675 'dhcp-client-gateway-ipv4.network',
2676 'dhcp-client-gateway-ipv6.network',
2677 'dhcp-client-gateway-onlink-implicit.network',
2678 'dhcp-client-ipv4-dhcp-settings.network',
2679 'dhcp-client-ipv4-only-ipv6-disabled.network',
2680 'dhcp-client-ipv4-only.network',
2681 'dhcp-client-ipv6-only.network',
2682 'dhcp-client-ipv6-rapid-commit.network',
2683 'dhcp-client-keep-configuration-dhcp-on-stop.network',
2684 'dhcp-client-keep-configuration-dhcp.network',
2685 'dhcp-client-listen-port.network',
2686 'dhcp-client-reassign-static-routes-ipv4.network',
2687 'dhcp-client-reassign-static-routes-ipv6.network',
2688 'dhcp-client-route-metric.network',
2689 'dhcp-client-route-table.network',
2690 'dhcp-client-use-dns-ipv4-and-ra.network',
2691 'dhcp-client-use-dns-ipv4.network',
2692 'dhcp-client-use-dns-no.network',
2693 'dhcp-client-use-dns-yes.network',
2694 'dhcp-client-use-domains.network',
2695 'dhcp-client-use-routes-no.network',
2696 'dhcp-client-vrf.network',
2697 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
2698 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
2699 'dhcp-client-with-static-address.network',
2700 'dhcp-client.network',
2701 'dhcp-server-decline.network',
2702 'dhcp-server-veth-peer.network',
2703 'dhcp-v4-server-veth-peer.network',
2704 'dhcp-client-use-domains.network',
2708 stop_dnsmasq(dnsmasq_pid_file
)
2709 remove_links(self
.links
)
2710 stop_networkd(show_logs
=False)
2713 stop_dnsmasq(dnsmasq_pid_file
)
2716 remove_links(self
.links
)
2717 remove_unit_from_networkd_path(self
.units
)
2718 stop_networkd(show_logs
=True)
2720 def test_dhcp_client_ipv6_only(self
):
2721 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2724 self
.wait_online(['veth-peer:carrier'])
2726 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2728 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2730 self
.assertRegex(output
, '2600::')
2731 self
.assertNotRegex(output
, '192.168.5')
2733 # Confirm that ipv6 token is not set in the kernel
2734 output
= check_output('ip token show dev veth99')
2736 self
.assertRegex(output
, 'token :: dev veth99')
2738 def test_dhcp_client_ipv4_only(self
):
2739 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
2742 self
.wait_online(['veth-peer:carrier'])
2743 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
2744 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2746 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2748 self
.assertNotRegex(output
, '2600::')
2749 self
.assertRegex(output
, '192.168.5')
2750 self
.assertRegex(output
, '192.168.5.6')
2751 self
.assertRegex(output
, '192.168.5.7')
2753 # checking routes to DNS servers
2754 output
= check_output('ip route show dev veth99')
2756 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
2757 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
2758 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
2760 stop_dnsmasq(dnsmasq_pid_file
)
2761 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8', lease_time
='2m')
2763 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2764 print('Wait for the dynamic address to be renewed')
2767 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2769 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2771 self
.assertNotRegex(output
, '2600::')
2772 self
.assertRegex(output
, '192.168.5')
2773 self
.assertNotRegex(output
, '192.168.5.6')
2774 self
.assertRegex(output
, '192.168.5.7')
2775 self
.assertRegex(output
, '192.168.5.8')
2777 # checking routes to DNS servers
2778 output
= check_output('ip route show dev veth99')
2780 self
.assertNotRegex(output
, r
'192.168.5.6')
2781 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
2782 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
2783 self
.assertRegex(output
, r
'192.168.5.8 proto dhcp scope link src 192.168.5.181 metric 1024')
2785 def test_dhcp_client_ipv4_ipv6(self
):
2786 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
2787 'dhcp-client-ipv4-only.network')
2789 self
.wait_online(['veth-peer:carrier'])
2791 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2793 # link become 'routable' when at least one protocol provide an valid address.
2794 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2795 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2797 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2799 self
.assertRegex(output
, '2600::')
2800 self
.assertRegex(output
, '192.168.5')
2802 def test_dhcp_client_settings(self
):
2803 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
2806 self
.wait_online(['veth-peer:carrier'])
2808 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2810 print('## ip address show dev veth99')
2811 output
= check_output('ip address show dev veth99')
2813 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2814 self
.assertRegex(output
, '192.168.5')
2815 self
.assertRegex(output
, '1492')
2817 print('## ip route show table main dev veth99')
2818 output
= check_output('ip route show table main dev veth99')
2821 main_table_is_empty
= output
== ''
2822 if not main_table_is_empty
:
2823 self
.assertNotRegex(output
, 'proto dhcp')
2825 print('## ip route show table 211 dev veth99')
2826 output
= check_output('ip route show table 211 dev veth99')
2828 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
2829 if main_table_is_empty
:
2830 self
.assertRegex(output
, '192.168.5.0/24 proto dhcp')
2831 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
2832 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
2834 print('## dnsmasq log')
2835 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
2836 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
2837 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
2838 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
2840 def test_dhcp6_client_settings_rapidcommit_true(self
):
2841 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2843 self
.wait_online(['veth-peer:carrier'])
2845 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2847 output
= check_output('ip address show dev veth99')
2849 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2850 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
2852 def test_dhcp6_client_settings_rapidcommit_false(self
):
2853 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
2855 self
.wait_online(['veth-peer:carrier'])
2857 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2859 output
= check_output('ip address show dev veth99')
2861 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2862 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
2864 def test_dhcp_client_settings_anonymize(self
):
2865 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
2867 self
.wait_online(['veth-peer:carrier'])
2869 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2871 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
2872 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
2873 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
2875 def test_dhcp_client_listen_port(self
):
2876 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
2878 self
.wait_online(['veth-peer:carrier'])
2879 start_dnsmasq('--dhcp-alternate-port=67,5555')
2880 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2882 output
= check_output('ip -4 address show dev veth99')
2884 self
.assertRegex(output
, '192.168.5.* dynamic')
2886 def test_dhcp_client_with_static_address(self
):
2887 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
2888 'dhcp-client-with-static-address.network')
2890 self
.wait_online(['veth-peer:carrier'])
2892 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2894 output
= check_output('ip address show dev veth99 scope global')
2896 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
2897 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
2899 output
= check_output('ip route show dev veth99')
2901 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
2902 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
2903 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
2904 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
2906 def test_dhcp_route_table_id(self
):
2907 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
2909 self
.wait_online(['veth-peer:carrier'])
2911 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2913 output
= check_output('ip route show table 12')
2915 self
.assertRegex(output
, 'veth99 proto dhcp')
2916 self
.assertRegex(output
, '192.168.5.1')
2918 def test_dhcp_route_metric(self
):
2919 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
2921 self
.wait_online(['veth-peer:carrier'])
2923 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2925 output
= check_output('ip route show dev veth99')
2927 self
.assertRegex(output
, 'metric 24')
2929 def test_dhcp_client_reassign_static_routes_ipv4(self
):
2930 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2931 'dhcp-client-reassign-static-routes-ipv4.network')
2933 self
.wait_online(['veth-peer:carrier'])
2934 start_dnsmasq(lease_time
='2m')
2935 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2937 output
= check_output('ip address show dev veth99 scope global')
2939 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2941 output
= check_output('ip route show dev veth99')
2943 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
2944 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
2945 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
2946 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
2948 stop_dnsmasq(dnsmasq_pid_file
)
2949 start_dnsmasq(ipv4_range
='192.168.5.210,192.168.5.220', lease_time
='2m')
2951 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2952 print('Wait for the dynamic address to be renewed')
2955 self
.wait_online(['veth99:routable'])
2957 output
= check_output('ip route show dev veth99')
2959 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
2960 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
2961 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
2962 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
2964 def test_dhcp_client_reassign_static_routes_ipv6(self
):
2965 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2966 'dhcp-client-reassign-static-routes-ipv6.network')
2968 self
.wait_online(['veth-peer:carrier'])
2969 start_dnsmasq(lease_time
='2m')
2970 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2972 output
= check_output('ip address show dev veth99 scope global')
2974 self
.assertRegex(output
, r
'inet6 2600::[0-9a-f]*/128 scope global (noprefixroute dynamic|dynamic noprefixroute)')
2976 output
= check_output('ip -6 route show dev veth99')
2978 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
2979 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
2981 stop_dnsmasq(dnsmasq_pid_file
)
2982 start_dnsmasq(ipv6_range
='2600::30,2600::40', lease_time
='2m')
2984 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2985 print('Wait for the dynamic address to be renewed')
2988 self
.wait_online(['veth99:routable'])
2990 output
= check_output('ip -6 route show dev veth99')
2992 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
2993 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
2995 def test_dhcp_keep_configuration_dhcp(self
):
2996 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
2998 self
.wait_online(['veth-peer:carrier'])
2999 start_dnsmasq(lease_time
='2m')
3000 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3002 output
= check_output('ip address show dev veth99 scope global')
3004 self
.assertRegex(output
, r
'192.168.5.*')
3006 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3008 self
.assertRegex(output
, r
'192.168.5.*')
3010 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
3011 stop_dnsmasq(dnsmasq_pid_file
)
3013 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3014 print('Wait for the dynamic address to be expired')
3017 print('The lease address should be kept after lease expired')
3018 output
= check_output('ip address show dev veth99 scope global')
3020 self
.assertRegex(output
, r
'192.168.5.*')
3022 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3024 self
.assertRegex(output
, r
'192.168.5.*')
3026 check_output('systemctl stop systemd-networkd')
3028 print('The lease address should be kept after networkd stopped')
3029 output
= check_output('ip address show dev veth99 scope global')
3031 self
.assertRegex(output
, r
'192.168.5.*')
3033 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3035 self
.assertRegex(output
, r
'192.168.5.*')
3038 self
.wait_online(['veth-peer:routable'])
3040 print('Still the lease address should be kept after networkd restarted')
3041 output
= check_output('ip address show dev veth99 scope global')
3043 self
.assertRegex(output
, r
'192.168.5.*')
3045 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3047 self
.assertRegex(output
, r
'192.168.5.*')
3049 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
3050 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
3052 self
.wait_online(['veth-peer:carrier'])
3053 start_dnsmasq(lease_time
='2m')
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
'192.168.5.*')
3060 stop_dnsmasq(dnsmasq_pid_file
)
3061 check_output('systemctl stop systemd-networkd')
3063 output
= check_output('ip address show dev veth99 scope global')
3065 self
.assertRegex(output
, r
'192.168.5.*')
3068 self
.wait_online(['veth-peer:routable'])
3070 output
= check_output('ip address show dev veth99 scope global')
3072 self
.assertNotRegex(output
, r
'192.168.5.*')
3074 def test_dhcp_client_reuse_address_as_static(self
):
3075 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
3077 self
.wait_online(['veth-peer:carrier'])
3079 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3081 # link become 'routable' when at least one protocol provide an valid address.
3082 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3083 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3085 output
= check_output('ip address show dev veth99 scope global')
3087 self
.assertRegex(output
, '192.168.5')
3088 self
.assertRegex(output
, '2600::')
3090 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
3091 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
3092 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
3093 print(static_network
)
3095 remove_unit_from_networkd_path(['dhcp-client.network'])
3097 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
3098 f
.write(static_network
)
3100 # When networkd started, the links are already configured, so let's wait for 5 seconds
3101 # the links to be re-configured.
3103 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3105 output
= check_output('ip -4 address show dev veth99 scope global')
3107 self
.assertRegex(output
, '192.168.5')
3108 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3110 output
= check_output('ip -6 address show dev veth99 scope global')
3112 self
.assertRegex(output
, '2600::')
3113 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3115 @expectedFailureIfModuleIsNotAvailable('vrf')
3116 def test_dhcp_client_vrf(self
):
3117 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
3118 '25-vrf.netdev', '25-vrf.network')
3120 self
.wait_online(['veth-peer:carrier'])
3122 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
3124 # link become 'routable' when at least one protocol provide an valid address.
3125 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3126 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3128 print('## ip -d link show dev vrf99')
3129 output
= check_output('ip -d link show dev vrf99')
3131 self
.assertRegex(output
, 'vrf table 42')
3133 print('## ip address show vrf vrf99')
3134 output
= check_output('ip address show vrf vrf99')
3136 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3137 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3138 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3139 self
.assertRegex(output
, 'inet6 .* scope link')
3141 print('## ip address show dev veth99')
3142 output
= check_output('ip address show dev veth99')
3144 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3145 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3146 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3147 self
.assertRegex(output
, 'inet6 .* scope link')
3149 print('## ip route show vrf vrf99')
3150 output
= check_output('ip route show vrf vrf99')
3152 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
3153 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
3154 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
3155 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
3156 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
3158 print('## ip route show table main dev veth99')
3159 output
= check_output('ip route show table main dev veth99')
3161 self
.assertEqual(output
, '')
3163 def test_dhcp_client_gateway_ipv4(self
):
3164 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3165 'dhcp-client-gateway-ipv4.network')
3167 self
.wait_online(['veth-peer:carrier'])
3169 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3171 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3173 self
.assertRegex(output
, '10.0.0.0/8 via 192.168.5.1 proto static')
3175 def test_dhcp_client_gateway_ipv6(self
):
3176 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3177 'dhcp-client-gateway-ipv6.network')
3179 self
.wait_online(['veth-peer:carrier'])
3181 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3183 output
= check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
3185 self
.assertRegex(output
, 'via fe80::1034:56ff:fe78:9abd')
3187 def test_dhcp_client_gateway_onlink_implicit(self
):
3188 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3189 'dhcp-client-gateway-onlink-implicit.network')
3191 self
.wait_online(['veth-peer:carrier'])
3193 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3195 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3197 self
.assertRegex(output
, '192.168.5')
3199 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3201 self
.assertRegex(output
, 'onlink')
3202 output
= check_output('ip route list dev veth99 192.168.100.0/24')
3204 self
.assertRegex(output
, 'onlink')
3206 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
3207 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3208 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
3210 self
.wait_online(['veth-peer:carrier'])
3211 start_dnsmasq(lease_time
='2m')
3212 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3214 output
= check_output('ip address show dev veth99')
3217 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3218 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3219 output
= check_output('ip -6 address show dev veth99 scope link')
3220 self
.assertRegex(output
, 'inet6 .* scope link')
3221 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3222 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3223 output
= check_output('ip -4 address show dev veth99 scope link')
3224 self
.assertNotRegex(output
, 'inet .* scope link')
3226 print('Wait for the dynamic address to be expired')
3229 output
= check_output('ip address show dev veth99')
3232 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3233 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3234 output
= check_output('ip -6 address show dev veth99 scope link')
3235 self
.assertRegex(output
, 'inet6 .* scope link')
3236 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3237 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3238 output
= check_output('ip -4 address show dev veth99 scope link')
3239 self
.assertNotRegex(output
, 'inet .* scope link')
3241 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
3243 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
3244 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3245 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
3247 self
.wait_online(['veth99:degraded', 'veth-peer:routable'])
3249 output
= check_output('ip address show dev veth99')
3252 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3253 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3254 output
= check_output('ip -6 address show dev veth99 scope link')
3255 self
.assertRegex(output
, 'inet6 .* scope link')
3256 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3257 self
.assertNotRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3258 output
= check_output('ip -4 address show dev veth99 scope link')
3259 self
.assertRegex(output
, 'inet .* scope link')
3261 def test_dhcp_client_route_remove_on_renew(self
):
3262 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3263 'dhcp-client-ipv4-only-ipv6-disabled.network')
3265 self
.wait_online(['veth-peer:carrier'])
3266 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
3267 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3269 # test for issue #12490
3271 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3273 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3275 for line
in output
.splitlines():
3276 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3277 address1
= line
.split()[1].split('/')[0]
3280 output
= check_output('ip -4 route show dev veth99')
3282 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3283 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3285 stop_dnsmasq(dnsmasq_pid_file
)
3286 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
3288 print('Wait for the dynamic address to be expired')
3291 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3293 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3295 for line
in output
.splitlines():
3296 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3297 address2
= line
.split()[1].split('/')[0]
3300 self
.assertNotEqual(address1
, address2
)
3302 output
= check_output('ip -4 route show dev veth99')
3304 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3305 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3306 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
3307 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
3309 def test_dhcp_client_use_dns_yes(self
):
3310 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-yes.network')
3313 self
.wait_online(['veth-peer:carrier'])
3314 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3315 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3317 # link become 'routable' when at least one protocol provide an valid address.
3318 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3319 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3322 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3324 self
.assertRegex(output
, '192.168.5.1')
3325 self
.assertRegex(output
, '2600::1')
3327 def test_dhcp_client_use_dns_no(self
):
3328 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-no.network')
3331 self
.wait_online(['veth-peer:carrier'])
3332 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3333 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3335 # link become 'routable' when at least one protocol provide an valid address.
3336 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3337 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3340 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3342 self
.assertNotRegex(output
, '192.168.5.1')
3343 self
.assertNotRegex(output
, '2600::1')
3345 def test_dhcp_client_use_dns_ipv4(self
):
3346 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4.network')
3349 self
.wait_online(['veth-peer:carrier'])
3350 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3351 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3353 # link become 'routable' when at least one protocol provide an valid address.
3354 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3355 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3358 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3360 self
.assertRegex(output
, '192.168.5.1')
3361 self
.assertNotRegex(output
, '2600::1')
3363 def test_dhcp_client_use_dns_ipv4_and_ra(self
):
3364 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4-and-ra.network')
3367 self
.wait_online(['veth-peer:carrier'])
3368 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3369 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3371 # link become 'routable' when at least one protocol provide an valid address.
3372 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3373 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3376 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3378 self
.assertRegex(output
, '192.168.5.1')
3379 self
.assertRegex(output
, '2600::1')
3381 def test_dhcp_client_use_domains(self
):
3382 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-domains.network')
3385 self
.wait_online(['veth-peer:carrier'])
3386 start_dnsmasq('--dhcp-option=option:domain-search,example.com')
3387 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3389 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3391 self
.assertRegex(output
, 'Search Domains: example.com')
3394 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
3396 self
.assertRegex(output
, 'example.com')
3398 def test_dhcp_client_decline(self
):
3399 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-decline.network', 'dhcp-client-decline.network')
3402 self
.wait_online(['veth-peer:carrier'])
3403 rc
= call(*wait_online_cmd
, '--timeout=10s', '--interface=veth99:routable', env
=env
)
3404 self
.assertTrue(rc
== 1)
3406 class NetworkdIPv6PrefixTests(unittest
.TestCase
, Utilities
):
3411 'ipv6ra-prefix-client.network',
3412 'ipv6ra-prefix.network'
3416 remove_links(self
.links
)
3417 stop_networkd(show_logs
=False)
3421 remove_links(self
.links
)
3422 remove_unit_from_networkd_path(self
.units
)
3423 stop_networkd(show_logs
=True)
3425 def test_ipv6_route_prefix(self
):
3426 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client.network', 'ipv6ra-prefix.network')
3429 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3431 output
= check_output('ip', '-6', 'route', 'show', 'dev', 'veth-peer')
3433 self
.assertRegex(output
, '2001:db8:0:1::/64 proto ra')
3435 class NetworkdMTUTests(unittest
.TestCase
, Utilities
):
3440 '12-dummy-mtu.netdev',
3441 '12-dummy-mtu.link',
3446 remove_links(self
.links
)
3447 stop_networkd(show_logs
=False)
3451 remove_links(self
.links
)
3452 remove_unit_from_networkd_path(self
.units
)
3453 stop_networkd(show_logs
=True)
3455 def check_mtu(self
, mtu
, ipv6_mtu
=None, reset
=True):
3461 self
.wait_online(['dummy98:routable'])
3462 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
3463 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
3465 # test normal restart
3467 self
.wait_online(['dummy98:routable'])
3468 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
3469 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
3472 self
.reset_check_mtu(mtu
, ipv6_mtu
)
3474 def reset_check_mtu(self
, mtu
, ipv6_mtu
=None):
3475 ''' test setting mtu/ipv6_mtu with interface already up '''
3478 # note - changing the device mtu resets the ipv6 mtu
3479 run('ip link set up mtu 1501 dev dummy98')
3480 run('ip link set up mtu 1500 dev dummy98')
3481 self
.assertEqual(read_link_attr('dummy98', 'mtu'), '1500')
3482 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), '1500')
3484 self
.check_mtu(mtu
, ipv6_mtu
, reset
=False)
3486 def test_mtu_network(self
):
3487 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
3488 self
.check_mtu('1600')
3490 def test_mtu_netdev(self
):
3491 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network', dropins
=False)
3492 # note - MTU set by .netdev happens ONLY at device creation!
3493 self
.check_mtu('1600', reset
=False)
3495 def test_mtu_link(self
):
3496 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', dropins
=False)
3497 # must reload udev because it only picks up new files after 3 second delay
3498 call('udevadm control --reload')
3499 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
3500 self
.check_mtu('1600', reset
=False)
3502 def test_ipv6_mtu(self
):
3503 ''' set ipv6 mtu without setting device mtu '''
3504 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
3505 self
.check_mtu('1500', '1400')
3507 def test_ipv6_mtu_toolarge(self
):
3508 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
3509 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
3510 self
.check_mtu('1500', '1500')
3512 def test_mtu_network_ipv6_mtu(self
):
3513 ''' set ipv6 mtu and set device mtu via network file '''
3514 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
3515 self
.check_mtu('1600', '1550')
3517 def test_mtu_netdev_ipv6_mtu(self
):
3518 ''' set ipv6 mtu and set device mtu via netdev file '''
3519 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
3520 self
.check_mtu('1600', '1550', reset
=False)
3522 def test_mtu_link_ipv6_mtu(self
):
3523 ''' set ipv6 mtu and set device mtu via link file '''
3524 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
3525 # must reload udev because it only picks up new files after 3 second delay
3526 call('udevadm control --reload')
3527 self
.check_mtu('1600', '1550', reset
=False)
3530 if __name__
== '__main__':
3531 parser
= argparse
.ArgumentParser()
3532 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
3533 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
3534 parser
.add_argument('--resolved', help='Path to systemd-resolved', dest
='resolved_bin')
3535 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
3536 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
3537 parser
.add_argument('--resolvectl', help='Path to resolvectl', dest
='resolvectl_bin')
3538 parser
.add_argument('--timedatectl', help='Path to timedatectl', dest
='timedatectl_bin')
3539 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
3540 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
3541 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
3542 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
3543 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
3544 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
3547 if ns
.networkd_bin
or ns
.resolved_bin
or ns
.wait_online_bin
or ns
.networkctl_bin
or ns
.resolvectl_bin
or ns
.timedatectl_bin
:
3548 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
3549 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
3550 resolved_bin
= os
.path
.join(ns
.build_dir
, 'systemd-resolved')
3551 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
3552 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
3553 resolvectl_bin
= os
.path
.join(ns
.build_dir
, 'resolvectl')
3554 timedatectl_bin
= os
.path
.join(ns
.build_dir
, 'timedatectl')
3557 networkd_bin
= ns
.networkd_bin
3559 resolved_bin
= ns
.resolved_bin
3560 if ns
.wait_online_bin
:
3561 wait_online_bin
= ns
.wait_online_bin
3562 if ns
.networkctl_bin
:
3563 networkctl_bin
= ns
.networkctl_bin
3564 if ns
.resolvectl_bin
:
3565 resolvectl_bin
= ns
.resolvectl_bin
3566 if ns
.timedatectl_bin
:
3567 timedatectl_bin
= ns
.timedatectl_bin
3569 use_valgrind
= ns
.use_valgrind
3570 enable_debug
= ns
.enable_debug
3571 asan_options
= ns
.asan_options
3572 lsan_options
= ns
.lsan_options
3573 ubsan_options
= ns
.ubsan_options
3576 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
3577 resolvectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin
]
3578 timedatectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin
]
3579 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
3581 networkctl_cmd
= [networkctl_bin
]
3582 resolvectl_cmd
= [resolvectl_bin
]
3583 timedatectl_cmd
= [timedatectl_bin
]
3584 wait_online_cmd
= [wait_online_bin
]
3587 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
3589 env
.update({ 'ASAN_OPTIONS' : asan_options
})
3591 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
3593 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
3596 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,