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 expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable():
106 rc
= call('ip rule add from 192.168.100.19 table 7 uidrange 200-300', stderr
=subprocess
.DEVNULL
)
108 ret
= run('ip rule list from 192.168.100.19 table 7', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
109 if ret
.returncode
== 0 and 'uidrange 200-300' in ret
.stdout
.rstrip():
111 call('ip rule del from 192.168.100.19 table 7 uidrange 200-300')
116 return unittest
.expectedFailure(func
)
120 def expectedFailureIfLinkFileFieldIsNotSet():
123 rc
= call('ip link add name dummy99 type dummy', stderr
=subprocess
.DEVNULL
)
125 ret
= run('udevadm info -w10s /sys/class/net/dummy99', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
126 if ret
.returncode
== 0 and 'E: ID_NET_LINK_FILE=' in ret
.stdout
.rstrip():
128 call('ip link del dummy99')
133 return unittest
.expectedFailure(func
)
137 def expectedFailureIfNexthopIsNotAvailable():
139 rc
= call('ip nexthop list', stderr
=subprocess
.DEVNULL
)
143 return unittest
.expectedFailure(func
)
147 def expectedFailureIfAlternativeNameIsNotAvailable():
149 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
150 rc
= call('ip link prop add dev dummy98 altname hogehogehogehogehoge', stderr
=subprocess
.DEVNULL
)
154 return unittest
.expectedFailure(func
)
161 os
.makedirs(network_unit_file_path
, exist_ok
=True)
162 os
.makedirs(networkd_ci_path
, exist_ok
=True)
164 shutil
.rmtree(networkd_ci_path
)
165 copytree(os
.path
.join(os
.path
.dirname(os
.path
.abspath(__file__
)), 'conf'), networkd_ci_path
)
167 for u
in ['systemd-networkd.socket', 'systemd-networkd.service', 'systemd-resolved.service', 'firewalld.service']:
168 if call(f
'systemctl is-active --quiet {u}') == 0:
169 check_output(f
'systemctl stop {u}')
170 running_units
.append(u
)
174 'StartLimitIntervalSec=0',
181 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin
,
185 drop_in
+= ['ExecStart=!!' + networkd_bin
]
187 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
189 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
191 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
193 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
194 if asan_options
or lsan_options
or ubsan_options
:
195 drop_in
+= ['SystemCallFilter=']
196 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
197 drop_in
+= ['MemoryDenyWriteExecute=no']
199 os
.makedirs('/run/systemd/system/systemd-networkd.service.d', exist_ok
=True)
200 with
open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode
='w') as f
:
201 f
.write('\n'.join(drop_in
))
209 drop_in
+= ['ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + resolved_bin
]
211 drop_in
+= ['ExecStart=!!' + resolved_bin
]
213 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
215 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
217 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
219 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
220 if asan_options
or lsan_options
or ubsan_options
:
221 drop_in
+= ['SystemCallFilter=']
222 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
223 drop_in
+= ['MemoryDenyWriteExecute=no']
225 os
.makedirs('/run/systemd/system/systemd-resolved.service.d', exist_ok
=True)
226 with
open('/run/systemd/system/systemd-resolved.service.d/00-override.conf', mode
='w') as f
:
227 f
.write('\n'.join(drop_in
))
229 check_output('systemctl daemon-reload')
230 print(check_output('systemctl cat systemd-networkd.service'))
231 print(check_output('systemctl cat systemd-resolved.service'))
232 check_output('systemctl restart systemd-resolved')
234 def tearDownModule():
237 shutil
.rmtree(networkd_ci_path
)
239 for u
in ['systemd-networkd.service', 'systemd-resolved.service']:
240 check_output(f
'systemctl stop {u}')
242 shutil
.rmtree('/run/systemd/system/systemd-networkd.service.d')
243 shutil
.rmtree('/run/systemd/system/systemd-resolved.service.d')
244 check_output('systemctl daemon-reload')
246 for u
in running_units
:
247 check_output(f
'systemctl start {u}')
249 def read_link_attr(*args
):
250 with
open(os
.path
.join('/sys/class/net/', *args
)) as f
:
251 return f
.readline().strip()
253 def read_bridge_port_attr(bridge
, link
, attribute
):
254 path_bridge
= os
.path
.join('/sys/devices/virtual/net', bridge
)
255 path_port
= 'lower_' + link
+ '/brport'
256 path
= os
.path
.join(path_bridge
, path_port
)
258 with
open(os
.path
.join(path
, attribute
)) as f
:
259 return f
.readline().strip()
261 def link_exists(link
):
262 return os
.path
.exists(os
.path
.join('/sys/class/net', link
))
264 def remove_links(links
):
266 if link_exists(link
):
267 call('ip link del dev', link
)
270 def remove_fou_ports(ports
):
272 call('ip fou del port', port
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
274 def remove_routing_policy_rule_tables(tables
):
278 rc
= call('ip rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
280 def remove_routes(routes
):
281 for route_type
, addr
in routes
:
282 call('ip route del', route_type
, addr
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
284 def remove_l2tp_tunnels(tunnel_ids
):
285 output
= check_output('ip l2tp show tunnel')
286 for tid
in tunnel_ids
:
287 words
='Tunnel ' + tid
+ ', encap'
289 call('ip l2tp del tunnel tid', tid
)
292 def read_ipv6_sysctl_attr(link
, attribute
):
293 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, link
), attribute
)) as f
:
294 return f
.readline().strip()
296 def read_ipv4_sysctl_attr(link
, attribute
):
297 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv4_path
, link
), attribute
)) as f
:
298 return f
.readline().strip()
300 def copy_unit_to_networkd_unit_path(*units
, dropins
=True):
301 """Copy networkd unit files into the testbed.
303 Any networkd unit file type can be specified, as well as drop-in files.
305 By default, all drop-ins for a specified unit file are copied in;
306 to avoid that specify dropins=False.
308 When a drop-in file is specified, its unit file is also copied in automatically.
312 if dropins
and os
.path
.exists(os
.path
.join(networkd_ci_path
, unit
+ '.d')):
313 copytree(os
.path
.join(networkd_ci_path
, unit
+ '.d'), os
.path
.join(network_unit_file_path
, unit
+ '.d'))
314 if unit
.endswith('.conf'):
316 dropindir
= os
.path
.join(network_unit_file_path
, os
.path
.dirname(dropin
))
317 os
.makedirs(dropindir
, exist_ok
=True)
318 shutil
.copy(os
.path
.join(networkd_ci_path
, dropin
), dropindir
)
319 unit
= os
.path
.dirname(dropin
).rstrip('.d')
320 shutil
.copy(os
.path
.join(networkd_ci_path
, unit
), network_unit_file_path
)
322 def remove_unit_from_networkd_path(units
):
323 """Remove previously copied unit files from the testbed.
325 Drop-ins will be removed automatically.
328 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
))):
329 os
.remove(os
.path
.join(network_unit_file_path
, unit
))
330 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
+ '.d'))):
331 shutil
.rmtree(os
.path
.join(network_unit_file_path
, unit
+ '.d'))
333 def start_dnsmasq(additional_options
='', ipv4_range
='192.168.5.10,192.168.5.200', ipv6_range
='2600::10,2600::20', lease_time
='1h'):
334 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
335 check_output(dnsmasq_command
)
337 def stop_dnsmasq(pid_file
):
338 if os
.path
.exists(pid_file
):
339 with
open(pid_file
, 'r') as f
:
340 pid
= f
.read().rstrip(' \t\r\n\0')
341 os
.kill(int(pid
), signal
.SIGTERM
)
345 def search_words_in_dnsmasq_log(words
, show_all
=False):
346 if os
.path
.exists(dnsmasq_log_file
):
347 with
open (dnsmasq_log_file
) as in_file
:
348 contents
= in_file
.read()
351 for line
in contents
.splitlines():
354 print("%s, %s" % (words
, line
))
358 def remove_lease_file():
359 if os
.path
.exists(os
.path
.join(networkd_ci_path
, 'lease')):
360 os
.remove(os
.path
.join(networkd_ci_path
, 'lease'))
362 def remove_log_file():
363 if os
.path
.exists(dnsmasq_log_file
):
364 os
.remove(dnsmasq_log_file
)
366 def remove_networkd_state_files():
367 if os
.path
.exists(os
.path
.join(networkd_runtime_directory
, 'state')):
368 os
.remove(os
.path
.join(networkd_runtime_directory
, 'state'))
370 def stop_networkd(show_logs
=True, remove_state_files
=True):
372 invocation_id
= check_output('systemctl show systemd-networkd -p InvocationID --value')
373 check_output('systemctl stop systemd-networkd')
375 print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
))
376 if remove_state_files
:
377 remove_networkd_state_files()
379 def start_networkd(sleep_sec
=0):
380 check_output('systemctl start systemd-networkd')
382 time
.sleep(sleep_sec
)
384 def restart_networkd(sleep_sec
=0, show_logs
=True, remove_state_files
=True):
385 stop_networkd(show_logs
, remove_state_files
)
386 start_networkd(sleep_sec
)
390 def check_link_exists(self
, link
):
391 self
.assertTrue(link_exists(link
))
393 def wait_operstate(self
, link
, operstate
='degraded', setup_state
='configured', setup_timeout
=5, fail_assert
=True):
394 """Wait for the link to reach the specified operstate and/or setup state.
396 Specify None or '' for either operstate or setup_state to ignore that state.
397 This will recheck until the state conditions are met or the timeout expires.
399 If the link successfully matches the requested state, this returns True.
400 If this times out waiting for the link to match, the behavior depends on the
401 'fail_assert' parameter; if True, this causes a test assertion failure,
402 otherwise this returns False. The default is to cause assertion failure.
404 Note that this function matches on *exactly* the given operstate and setup_state.
405 To wait for a link to reach *or exceed* a given operstate, use wait_online().
412 for secs
in range(setup_timeout
+ 1):
413 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
, env
=env
)
415 if re
.search(rf
'(?m)^\s*State:\s+{operstate}\s+\({setup_state}\)\s*$', output
):
417 # don't bother sleeping if time is up
418 if secs
< setup_timeout
:
421 self
.fail(f
'Timed out waiting for {link} to reach state {operstate}/{setup_state}')
424 def wait_online(self
, links_with_operstate
, timeout
='20s', bool_any
=False, setup_state
='configured', setup_timeout
=5):
425 """Wait for the link(s) to reach the specified operstate and/or setup state.
427 This is similar to wait_operstate() but can be used for multiple links,
428 and it also calls systemd-networkd-wait-online to wait for the given operstate.
429 The operstate should be specified in the link name, like 'eth0:degraded'.
430 If just a link name is provided, wait-online's default operstate to wait for is degraded.
432 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
433 'setup_timeout' controls the per-link timeout waiting for the setup_state.
435 Set 'bool_any' to True to wait for any (instead of all) of the given links.
436 If this is set, no setup_state checks are done.
438 Note that this function waits for the link(s) to reach *or exceed* the given operstate.
439 However, the setup_state, if specified, must be matched *exactly*.
441 This returns if the link(s) reached the requested operstate/setup_state; otherwise it
442 raises CalledProcessError or fails test assertion.
444 args
= wait_online_cmd
+ [f
'--timeout={timeout}'] + [f
'--interface={link}' for link
in links_with_operstate
]
448 check_output(*args
, env
=env
)
449 except subprocess
.CalledProcessError
:
450 for link
in links_with_operstate
:
451 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
.split(':')[0], env
=env
)
454 if not bool_any
and setup_state
:
455 for link
in links_with_operstate
:
456 self
.wait_operstate(link
.split(':')[0], None, setup_state
, setup_timeout
)
458 def wait_address(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
459 for i
in range(timeout_sec
):
462 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
463 if re
.search(address_regex
, output
):
466 self
.assertRegex(output
, address_regex
)
468 class NetworkctlTests(unittest
.TestCase
, Utilities
):
478 '11-dummy-mtu.netdev',
482 '25-address-static.network',
484 'netdev-link-local-addressing-yes.network',
488 remove_links(self
.links
)
489 stop_networkd(show_logs
=False)
492 remove_links(self
.links
)
493 remove_unit_from_networkd_path(self
.units
)
494 stop_networkd(show_logs
=True)
496 @expectedFailureIfAlternativeNameIsNotAvailable()
497 def test_altname(self
):
498 copy_unit_to_networkd_unit_path('netdev-link-local-addressing-yes.network', '12-dummy.netdev', '12-dummy.link')
499 check_output('udevadm control --reload')
501 self
.wait_online(['dummy98:degraded'])
503 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
504 self
.assertRegex(output
, 'hogehogehogehogehogehoge')
506 def test_reconfigure(self
):
507 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
509 self
.wait_online(['dummy98:routable'])
511 output
= check_output('ip -4 address show dev dummy98')
513 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
514 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
515 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
517 check_output('ip address del 10.1.2.3/16 dev dummy98')
518 check_output('ip address del 10.1.2.4/16 dev dummy98')
519 check_output('ip address del 10.2.2.4/16 dev dummy98')
521 check_output(*networkctl_cmd
, 'reconfigure', 'dummy98', env
=env
)
522 self
.wait_online(['dummy98:routable'])
524 output
= check_output('ip -4 address show dev dummy98')
526 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
527 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
528 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
530 def test_reload(self
):
533 copy_unit_to_networkd_unit_path('11-dummy.netdev')
534 check_output(*networkctl_cmd
, 'reload', env
=env
)
535 self
.wait_operstate('test1', 'off', setup_state
='unmanaged')
537 copy_unit_to_networkd_unit_path('11-dummy.network')
538 check_output(*networkctl_cmd
, 'reload', env
=env
)
539 self
.wait_online(['test1:degraded'])
541 remove_unit_from_networkd_path(['11-dummy.network'])
542 check_output(*networkctl_cmd
, 'reload', env
=env
)
543 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
545 remove_unit_from_networkd_path(['11-dummy.netdev'])
546 check_output(*networkctl_cmd
, 'reload', env
=env
)
547 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
549 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
550 check_output(*networkctl_cmd
, 'reload', env
=env
)
551 self
.wait_operstate('test1', 'degraded')
554 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
557 self
.wait_online(['test1:degraded'])
559 output
= check_output(*networkctl_cmd
, 'list', env
=env
)
560 self
.assertRegex(output
, '1 lo ')
561 self
.assertRegex(output
, 'test1')
563 output
= check_output(*networkctl_cmd
, 'list', 'test1', env
=env
)
564 self
.assertNotRegex(output
, '1 lo ')
565 self
.assertRegex(output
, 'test1')
567 output
= check_output(*networkctl_cmd
, 'list', 'te*', env
=env
)
568 self
.assertNotRegex(output
, '1 lo ')
569 self
.assertRegex(output
, 'test1')
571 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'te*', env
=env
)
572 self
.assertNotRegex(output
, '1: lo ')
573 self
.assertRegex(output
, 'test1')
575 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'tes[a-z][0-9]', env
=env
)
576 self
.assertNotRegex(output
, '1: lo ')
577 self
.assertRegex(output
, 'test1')
580 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
583 self
.wait_online(['test1:degraded'])
585 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
586 self
.assertRegex(output
, 'MTU: 1600')
589 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
591 self
.wait_online(['test1:degraded'])
593 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
595 self
.assertRegex(output
, 'Type: ether')
597 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
599 self
.assertRegex(output
, 'Type: loopback')
601 @expectedFailureIfLinkFileFieldIsNotSet()
602 def test_udev_link_file(self
):
603 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
605 self
.wait_online(['test1:degraded'])
607 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
609 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
610 self
.assertRegex(output
, r
'Network File: /run/systemd/network/11-dummy.network')
612 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
614 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
615 self
.assertRegex(output
, r
'Network File: n/a')
617 def test_delete_links(self
):
618 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
619 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
622 self
.wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
624 check_output(*networkctl_cmd
, 'delete', 'test1', 'veth99', env
=env
)
625 self
.assertFalse(link_exists('test1'))
626 self
.assertFalse(link_exists('veth99'))
627 self
.assertFalse(link_exists('veth-peer'))
629 class NetworkdNetDevTests(unittest
.TestCase
, Utilities
):
631 links_remove_earlier
= [
696 '10-dropin-test.netdev',
700 '13-not-match-udev-property.network',
701 '14-match-udev-property.network',
702 '15-name-conflict-test.netdev',
705 '21-vlan-test1.network',
708 '25-6rd-tunnel.netdev',
710 '25-bond-balanced-tlb.netdev',
712 '25-bridge-configure-without-carrier.network',
714 '25-erspan-tunnel-local-any.netdev',
715 '25-erspan-tunnel.netdev',
716 '25-fou-gretap.netdev',
718 '25-fou-ipip.netdev',
719 '25-fou-ipproto-gre.netdev',
720 '25-fou-ipproto-ipip.netdev',
723 '25-gretap-tunnel-local-any.netdev',
724 '25-gretap-tunnel.netdev',
725 '25-gre-tunnel-any-any.netdev',
726 '25-gre-tunnel-local-any.netdev',
727 '25-gre-tunnel-remote-any.netdev',
728 '25-gre-tunnel.netdev',
730 '25-ip6gretap-tunnel-local-any.netdev',
731 '25-ip6gretap-tunnel.netdev',
732 '25-ip6gre-tunnel-any-any.netdev',
733 '25-ip6gre-tunnel-local-any.netdev',
734 '25-ip6gre-tunnel-remote-any.netdev',
735 '25-ip6gre-tunnel.netdev',
736 '25-ip6tnl-tunnel-any-any.netdev',
737 '25-ip6tnl-tunnel-local-any.netdev',
738 '25-ip6tnl-tunnel-remote-any.netdev',
739 '25-ip6tnl-tunnel.netdev',
740 '25-ipip-tunnel-any-any.netdev',
741 '25-ipip-tunnel-independent.netdev',
742 '25-ipip-tunnel-independent-loopback.netdev',
743 '25-ipip-tunnel-local-any.netdev',
744 '25-ipip-tunnel-remote-any.netdev',
745 '25-ipip-tunnel.netdev',
748 '25-isatap-tunnel.netdev',
753 '25-sit-tunnel-any-any.netdev',
754 '25-sit-tunnel-local-any.netdev',
755 '25-sit-tunnel-remote-any.netdev',
756 '25-sit-tunnel.netdev',
759 '25-tunnel-local-any.network',
760 '25-tunnel-remote-any.network',
765 '25-vti6-tunnel-any-any.netdev',
766 '25-vti6-tunnel-local-any.netdev',
767 '25-vti6-tunnel-remote-any.netdev',
768 '25-vti6-tunnel.netdev',
769 '25-vti-tunnel-any-any.netdev',
770 '25-vti-tunnel-local-any.netdev',
771 '25-vti-tunnel-remote-any.netdev',
772 '25-vti-tunnel.netdev',
775 '25-wireguard-23-peers.netdev',
776 '25-wireguard-23-peers.network',
777 '25-wireguard-preshared-key.txt',
778 '25-wireguard-private-key.txt',
779 '25-wireguard.netdev',
780 '25-wireguard.network',
782 '25-xfrm-independent.netdev',
798 'netdev-link-local-addressing-yes.network',
802 'vxlan-test1.network',
812 remove_fou_ports(self
.fou_ports
)
813 remove_links(self
.links_remove_earlier
)
814 remove_links(self
.links
)
815 stop_networkd(show_logs
=False)
818 remove_fou_ports(self
.fou_ports
)
819 remove_links(self
.links_remove_earlier
)
820 remove_links(self
.links
)
821 remove_unit_from_networkd_path(self
.units
)
822 stop_networkd(show_logs
=True)
824 def test_dropin_and_name_conflict(self
):
825 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
828 self
.wait_online(['dropin-test:off'], setup_state
='unmanaged')
830 output
= check_output('ip link show dropin-test')
832 self
.assertRegex(output
, '00:50:56:c0:00:28')
834 def test_match_udev_property(self
):
835 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
837 self
.wait_online(['dummy98:routable'])
839 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
841 self
.assertRegex(output
, 'Network File: /run/systemd/network/14-match-udev-property')
843 def test_wait_online_any(self
):
844 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
847 self
.wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
849 self
.wait_operstate('bridge99', '(off|no-carrier)', setup_state
='configuring')
850 self
.wait_operstate('test1', 'degraded')
852 def test_bridge(self
):
853 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
856 self
.wait_online(['bridge99:no-carrier'])
858 tick
= os
.sysconf('SC_CLK_TCK')
859 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
860 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
861 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'forward_delay')) / tick
))
862 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'ageing_time')) / tick
))
863 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge', 'priority')))
864 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_querier')))
865 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_snooping')))
866 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'stp_state')))
867 self
.assertEqual(3, int(read_link_attr('bridge99', 'bridge', 'multicast_igmp_version')))
869 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
871 self
.assertRegex(output
, 'Priority: 9')
872 self
.assertRegex(output
, 'STP: yes')
873 self
.assertRegex(output
, 'Multicast IGMP Version: 3')
876 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
879 self
.wait_online(['bond99:off', 'bond98:off'], setup_state
='unmanaged')
881 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
882 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
883 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
884 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
885 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
886 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
887 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
888 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
889 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
890 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
891 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
893 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
894 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
897 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
898 '21-vlan.network', '21-vlan-test1.network')
901 self
.wait_online(['test1:degraded', 'vlan99:routable'])
903 output
= check_output('ip -d link show test1')
905 self
.assertRegex(output
, ' mtu 2000 ')
907 output
= check_output('ip -d link show vlan99')
909 self
.assertRegex(output
, ' mtu 2000 ')
910 self
.assertRegex(output
, 'REORDER_HDR')
911 self
.assertRegex(output
, 'LOOSE_BINDING')
912 self
.assertRegex(output
, 'GVRP')
913 self
.assertRegex(output
, 'MVRP')
914 self
.assertRegex(output
, ' id 99 ')
916 output
= check_output('ip -4 address show dev test1')
918 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
919 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
921 output
= check_output('ip -4 address show dev vlan99')
923 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
925 def test_macvtap(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-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
931 '11-dummy.netdev', 'macvtap.network')
932 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
933 f
.write('[MACVTAP]\nMode=' + mode
)
936 self
.wait_online(['macvtap99:degraded', 'test1:degraded'])
938 output
= check_output('ip -d link show macvtap99')
940 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
942 def test_macvlan(self
):
943 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
944 with self
.subTest(mode
=mode
):
945 if mode
!= 'private':
947 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
948 '11-dummy.netdev', 'macvlan.network')
949 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
950 f
.write('[MACVLAN]\nMode=' + mode
)
953 self
.wait_online(['macvlan99:degraded', 'test1:degraded'])
955 output
= check_output('ip -d link show test1')
957 self
.assertRegex(output
, ' mtu 2000 ')
959 output
= check_output('ip -d link show macvlan99')
961 self
.assertRegex(output
, ' mtu 2000 ')
962 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
964 @expectedFailureIfModuleIsNotAvailable('ipvlan')
965 def test_ipvlan(self
):
966 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
967 with self
.subTest(mode
=mode
, flag
=flag
):
970 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
971 '11-dummy.netdev', 'ipvlan.network')
972 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
973 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
976 self
.wait_online(['ipvlan99:degraded', 'test1:degraded'])
978 output
= check_output('ip -d link show ipvlan99')
980 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
982 @expectedFailureIfModuleIsNotAvailable('ipvtap')
983 def test_ipvtap(self
):
984 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
985 with self
.subTest(mode
=mode
, flag
=flag
):
988 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
989 '11-dummy.netdev', 'ipvtap.network')
990 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
991 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
994 self
.wait_online(['ipvtap99:degraded', 'test1:degraded'])
996 output
= check_output('ip -d link show ipvtap99')
998 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
1000 def test_veth(self
):
1001 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
1004 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
1006 output
= check_output('ip -d link show veth99')
1008 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
1009 output
= check_output('ip -d link show veth-peer')
1011 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
1014 copy_unit_to_networkd_unit_path('25-tun.netdev')
1017 self
.wait_online(['tun99:off'], setup_state
='unmanaged')
1019 output
= check_output('ip -d link show tun99')
1021 # Old ip command does not support IFF_ flags
1022 self
.assertRegex(output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
1025 copy_unit_to_networkd_unit_path('25-tap.netdev')
1028 self
.wait_online(['tap99:off'], setup_state
='unmanaged')
1030 output
= check_output('ip -d link show tap99')
1032 # Old ip command does not support IFF_ flags
1033 self
.assertRegex(output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
1035 @expectedFailureIfModuleIsNotAvailable('vrf')
1037 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
1040 self
.wait_online(['vrf99:carrier'])
1042 @expectedFailureIfModuleIsNotAvailable('vcan')
1043 def test_vcan(self
):
1044 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
1047 self
.wait_online(['vcan99:carrier'])
1049 @expectedFailureIfModuleIsNotAvailable('vxcan')
1050 def test_vxcan(self
):
1051 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
1054 self
.wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
1056 @expectedFailureIfModuleIsNotAvailable('wireguard')
1057 def test_wireguard(self
):
1058 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
1059 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
1060 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt')
1062 self
.wait_online(['wg99:carrier', 'wg98:routable'])
1064 if shutil
.which('wg'):
1067 output
= check_output('wg show wg99 listen-port')
1068 self
.assertRegex(output
, '51820')
1069 output
= check_output('wg show wg99 fwmark')
1070 self
.assertRegex(output
, '0x4d2')
1071 output
= check_output('wg show wg99 allowed-ips')
1072 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
1073 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
1074 output
= check_output('wg show wg99 persistent-keepalive')
1075 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
1076 output
= check_output('wg show wg99 endpoints')
1077 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
1078 output
= check_output('wg show wg99 private-key')
1079 self
.assertRegex(output
, r
'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
1080 output
= check_output('wg show wg99 preshared-keys')
1081 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
1082 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
1084 output
= check_output('wg show wg98 private-key')
1085 self
.assertRegex(output
, r
'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
1087 def test_geneve(self
):
1088 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
1091 self
.wait_online(['geneve99:degraded'])
1093 output
= check_output('ip -d link show geneve99')
1095 self
.assertRegex(output
, '192.168.22.1')
1096 self
.assertRegex(output
, '6082')
1097 self
.assertRegex(output
, 'udpcsum')
1098 self
.assertRegex(output
, 'udp6zerocsumrx')
1100 def test_ipip_tunnel(self
):
1101 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
1102 '25-ipip-tunnel.netdev', '25-tunnel.network',
1103 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1104 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1105 '25-ipip-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1107 self
.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'ipiptun96:routable', 'dummy98:degraded'])
1109 output
= check_output('ip -d link show ipiptun99')
1111 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98')
1112 output
= check_output('ip -d link show ipiptun98')
1114 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98')
1115 output
= check_output('ip -d link show ipiptun97')
1117 self
.assertRegex(output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98')
1118 output
= check_output('ip -d link show ipiptun96')
1120 self
.assertRegex(output
, 'ipip (ipip )?remote any local any dev dummy98')
1122 def test_gre_tunnel(self
):
1123 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
1124 '25-gre-tunnel.netdev', '25-tunnel.network',
1125 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1126 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1127 '25-gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1129 self
.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'gretun96:routable', 'dummy98:degraded'])
1131 output
= check_output('ip -d link show gretun99')
1133 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1134 self
.assertRegex(output
, 'ikey 1.2.3.103')
1135 self
.assertRegex(output
, 'okey 1.2.4.103')
1136 self
.assertRegex(output
, 'iseq')
1137 self
.assertRegex(output
, 'oseq')
1138 output
= check_output('ip -d link show gretun98')
1140 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
1141 self
.assertRegex(output
, 'ikey 0.0.0.104')
1142 self
.assertRegex(output
, 'okey 0.0.0.104')
1143 self
.assertNotRegex(output
, 'iseq')
1144 self
.assertNotRegex(output
, 'oseq')
1145 output
= check_output('ip -d link show gretun97')
1147 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
1148 self
.assertRegex(output
, 'ikey 0.0.0.105')
1149 self
.assertRegex(output
, 'okey 0.0.0.105')
1150 self
.assertNotRegex(output
, 'iseq')
1151 self
.assertNotRegex(output
, 'oseq')
1152 output
= check_output('ip -d link show gretun96')
1154 self
.assertRegex(output
, 'gre remote any local any dev dummy98')
1155 self
.assertRegex(output
, 'ikey 0.0.0.106')
1156 self
.assertRegex(output
, 'okey 0.0.0.106')
1157 self
.assertNotRegex(output
, 'iseq')
1158 self
.assertNotRegex(output
, 'oseq')
1160 def test_ip6gre_tunnel(self
):
1161 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
1162 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
1163 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1164 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1165 '25-ip6gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1168 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1170 self
.check_link_exists('dummy98')
1171 self
.check_link_exists('ip6gretun99')
1172 self
.check_link_exists('ip6gretun98')
1173 self
.check_link_exists('ip6gretun97')
1174 self
.check_link_exists('ip6gretun96')
1176 output
= check_output('ip -d link show ip6gretun99')
1178 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1179 output
= check_output('ip -d link show ip6gretun98')
1181 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
1182 output
= check_output('ip -d link show ip6gretun97')
1184 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
1185 output
= check_output('ip -d link show ip6gretun96')
1187 self
.assertRegex(output
, 'ip6gre remote any local any dev dummy98')
1189 def test_gretap_tunnel(self
):
1190 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
1191 '25-gretap-tunnel.netdev', '25-tunnel.network',
1192 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1194 self
.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
1196 output
= check_output('ip -d link show gretap99')
1198 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1199 self
.assertRegex(output
, 'ikey 0.0.0.106')
1200 self
.assertRegex(output
, 'okey 0.0.0.106')
1201 self
.assertRegex(output
, 'iseq')
1202 self
.assertRegex(output
, 'oseq')
1203 output
= check_output('ip -d link show gretap98')
1205 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
1206 self
.assertRegex(output
, 'ikey 0.0.0.107')
1207 self
.assertRegex(output
, 'okey 0.0.0.107')
1208 self
.assertRegex(output
, 'iseq')
1209 self
.assertRegex(output
, 'oseq')
1211 def test_ip6gretap_tunnel(self
):
1212 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
1213 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1214 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1216 self
.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
1218 output
= check_output('ip -d link show ip6gretap99')
1220 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1221 output
= check_output('ip -d link show ip6gretap98')
1223 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1225 def test_vti_tunnel(self
):
1226 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
1227 '25-vti-tunnel.netdev', '25-tunnel.network',
1228 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1229 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1230 '25-vti-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1232 self
.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'vtitun96:routable', 'dummy98:degraded'])
1234 output
= check_output('ip -d link show vtitun99')
1236 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1237 output
= check_output('ip -d link show vtitun98')
1239 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
1240 output
= check_output('ip -d link show vtitun97')
1242 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
1243 output
= check_output('ip -d link show vtitun96')
1245 self
.assertRegex(output
, 'vti remote any local any dev dummy98')
1247 def test_vti6_tunnel(self
):
1248 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
1249 '25-vti6-tunnel.netdev', '25-tunnel.network',
1250 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1251 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1253 self
.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
1255 output
= check_output('ip -d link show vti6tun99')
1257 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1258 output
= check_output('ip -d link show vti6tun98')
1260 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1261 output
= check_output('ip -d link show vti6tun97')
1263 self
.assertRegex(output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1265 def test_ip6tnl_tunnel(self
):
1266 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
1267 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1268 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1269 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1271 self
.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
1273 output
= check_output('ip -d link show ip6tnl99')
1275 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1276 output
= check_output('ip -d link show ip6tnl98')
1278 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1279 output
= check_output('ip -d link show ip6tnl97')
1281 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1283 def test_sit_tunnel(self
):
1284 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1285 '25-sit-tunnel.netdev', '25-tunnel.network',
1286 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1287 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1288 '25-sit-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1290 self
.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'sittun96:routable', 'dummy98:degraded'])
1292 output
= check_output('ip -d link show sittun99')
1294 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1295 output
= check_output('ip -d link show sittun98')
1297 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98")
1298 output
= check_output('ip -d link show sittun97')
1300 self
.assertRegex(output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98")
1301 output
= check_output('ip -d link show sittun96')
1303 self
.assertRegex(output
, "sit (ip6ip )?remote any local any dev dummy98")
1305 def test_isatap_tunnel(self
):
1306 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1307 '25-isatap-tunnel.netdev', '25-tunnel.network')
1309 self
.wait_online(['isataptun99:routable', 'dummy98:degraded'])
1311 output
= check_output('ip -d link show isataptun99')
1313 self
.assertRegex(output
, "isatap ")
1315 def test_6rd_tunnel(self
):
1316 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1317 '25-6rd-tunnel.netdev', '25-tunnel.network')
1319 self
.wait_online(['sittun99:routable', 'dummy98:degraded'])
1321 output
= check_output('ip -d link show sittun99')
1323 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1325 @expectedFailureIfERSPANModuleIsNotAvailable()
1326 def test_erspan_tunnel(self
):
1327 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1328 '25-erspan-tunnel.netdev', '25-tunnel.network',
1329 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1331 self
.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1333 output
= check_output('ip -d link show erspan99')
1335 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1336 self
.assertRegex(output
, 'ikey 0.0.0.101')
1337 self
.assertRegex(output
, 'okey 0.0.0.101')
1338 self
.assertRegex(output
, 'iseq')
1339 self
.assertRegex(output
, 'oseq')
1340 output
= check_output('ip -d link show erspan98')
1342 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1343 self
.assertRegex(output
, '102')
1344 self
.assertRegex(output
, 'ikey 0.0.0.102')
1345 self
.assertRegex(output
, 'okey 0.0.0.102')
1346 self
.assertRegex(output
, 'iseq')
1347 self
.assertRegex(output
, 'oseq')
1349 def test_tunnel_independent(self
):
1350 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1353 self
.wait_online(['ipiptun99:carrier'])
1355 def test_tunnel_independent_loopback(self
):
1356 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent-loopback.netdev', 'netdev-link-local-addressing-yes.network')
1359 self
.wait_online(['ipiptun99:carrier'])
1361 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1362 def test_xfrm(self
):
1363 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'xfrm.network',
1364 '25-xfrm.netdev', 'netdev-link-local-addressing-yes.network')
1367 self
.wait_online(['xfrm99:degraded', 'dummy98:degraded'])
1369 output
= check_output('ip link show dev xfrm99')
1372 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1373 def test_xfrm_independent(self
):
1374 copy_unit_to_networkd_unit_path('25-xfrm-independent.netdev', 'netdev-link-local-addressing-yes.network')
1377 self
.wait_online(['xfrm99:degraded'])
1379 @expectedFailureIfModuleIsNotAvailable('fou')
1381 # The following redundant check is necessary for CentOS CI.
1382 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1383 self
.assertTrue(is_module_available('fou'))
1385 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1386 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1387 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1390 self
.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'], setup_state
='unmanaged')
1392 output
= check_output('ip fou show')
1394 self
.assertRegex(output
, 'port 55555 ipproto 4')
1395 self
.assertRegex(output
, 'port 55556 ipproto 47')
1397 output
= check_output('ip -d link show ipiptun96')
1399 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1400 output
= check_output('ip -d link show sittun96')
1402 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1403 output
= check_output('ip -d link show gretun96')
1405 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1406 output
= check_output('ip -d link show gretap96')
1408 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1410 def test_vxlan(self
):
1411 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1412 '11-dummy.netdev', 'vxlan-test1.network')
1415 self
.wait_online(['test1:degraded', 'vxlan99:degraded'])
1417 output
= check_output('ip -d link show vxlan99')
1419 self
.assertRegex(output
, '999')
1420 self
.assertRegex(output
, '5555')
1421 self
.assertRegex(output
, 'l2miss')
1422 self
.assertRegex(output
, 'l3miss')
1423 self
.assertRegex(output
, 'udpcsum')
1424 self
.assertRegex(output
, 'udp6zerocsumtx')
1425 self
.assertRegex(output
, 'udp6zerocsumrx')
1426 self
.assertRegex(output
, 'remcsumtx')
1427 self
.assertRegex(output
, 'remcsumrx')
1428 self
.assertRegex(output
, 'gbp')
1430 output
= check_output('bridge fdb show dev vxlan99')
1432 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1433 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1434 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1436 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'vxlan99', env
=env
)
1438 self
.assertRegex(output
, 'VNI: 999')
1439 self
.assertRegex(output
, 'Destination Port: 5555')
1440 self
.assertRegex(output
, 'Underlying Device: test1')
1442 def test_macsec(self
):
1443 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1444 'macsec.network', '12-dummy.netdev')
1447 self
.wait_online(['dummy98:degraded', 'macsec99:routable'])
1449 output
= check_output('ip -d link show macsec99')
1451 self
.assertRegex(output
, 'macsec99@dummy98')
1452 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1453 self
.assertRegex(output
, 'encrypt on')
1455 output
= check_output('ip macsec show macsec99')
1457 self
.assertRegex(output
, 'encrypt on')
1458 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1459 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1460 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1461 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1462 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1463 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1464 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1465 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1466 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1467 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1468 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1470 def test_nlmon(self
):
1471 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1474 self
.wait_online(['nlmon99:carrier'])
1476 @expectedFailureIfModuleIsNotAvailable('ifb')
1478 copy_unit_to_networkd_unit_path('25-ifb.netdev', 'netdev-link-local-addressing-yes.network')
1481 self
.wait_online(['ifb99:degraded'])
1483 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1494 '25-l2tp-dummy.network',
1496 '25-l2tp-ip.netdev',
1497 '25-l2tp-udp.netdev']
1499 l2tp_tunnel_ids
= [ '10' ]
1502 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1503 remove_links(self
.links
)
1504 stop_networkd(show_logs
=False)
1507 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1508 remove_links(self
.links
)
1509 remove_unit_from_networkd_path(self
.units
)
1510 stop_networkd(show_logs
=True)
1512 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1513 def test_l2tp_udp(self
):
1514 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1515 '25-l2tp-udp.netdev', '25-l2tp.network')
1518 self
.wait_online(['test1:routable', 'l2tp-ses1:degraded', 'l2tp-ses2:degraded'])
1520 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1522 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1523 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1524 self
.assertRegex(output
, "Peer tunnel 11")
1525 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1526 self
.assertRegex(output
, "UDP checksum: enabled")
1528 output
= check_output('ip l2tp show session tid 10 session_id 15')
1530 self
.assertRegex(output
, "Session 15 in tunnel 10")
1531 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1532 self
.assertRegex(output
, "interface name: l2tp-ses1")
1534 output
= check_output('ip l2tp show session tid 10 session_id 17')
1536 self
.assertRegex(output
, "Session 17 in tunnel 10")
1537 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1538 self
.assertRegex(output
, "interface name: l2tp-ses2")
1540 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1541 def test_l2tp_ip(self
):
1542 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1543 '25-l2tp-ip.netdev', '25-l2tp.network')
1546 self
.wait_online(['test1:routable', 'l2tp-ses3:degraded', 'l2tp-ses4:degraded'])
1548 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1550 self
.assertRegex(output
, "Tunnel 10, encap IP")
1551 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1552 self
.assertRegex(output
, "Peer tunnel 12")
1554 output
= check_output('ip l2tp show session tid 10 session_id 25')
1556 self
.assertRegex(output
, "Session 25 in tunnel 10")
1557 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1558 self
.assertRegex(output
, "interface name: l2tp-ses3")
1560 output
= check_output('ip l2tp show session tid 10 session_id 27')
1562 self
.assertRegex(output
, "Session 27 in tunnel 10")
1563 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1564 self
.assertRegex(output
, "interface name: l2tp-ses4")
1566 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1580 '23-active-slave.network',
1581 '24-keep-configuration-static.network',
1582 '24-search-domain.network',
1583 '25-address-dad-veth-peer.network',
1584 '25-address-dad-veth99.network',
1585 '25-address-link-section.network',
1586 '25-address-preferred-lifetime-zero.network',
1587 '25-address-static.network',
1588 '25-bind-carrier.network',
1589 '25-bond-active-backup-slave.netdev',
1590 '25-fibrule-invert.network',
1591 '25-fibrule-port-range.network',
1592 '25-fibrule-uidrange.network',
1593 '25-gre-tunnel-remote-any.netdev',
1594 '25-ip6gre-tunnel-remote-any.netdev',
1595 '25-ipv6-address-label-section.network',
1596 '25-link-local-addressing-no.network',
1597 '25-link-local-addressing-yes.network',
1598 '25-link-section-unmanaged.network',
1599 '25-neighbor-section.network',
1600 '25-neighbor-next.network',
1601 '25-neighbor-ipv6.network',
1602 '25-neighbor-ip-dummy.network',
1603 '25-neighbor-ip.network',
1604 '25-nexthop.network',
1605 '25-qdisc-fq-codel.network',
1606 '25-qdisc-netem-and-fqcodel.network',
1607 '25-qdisc-tbf-and-sfq.network',
1608 '25-route-ipv6-src.network',
1609 '25-route-static.network',
1610 '25-gateway-static.network',
1611 '25-gateway-next-static.network',
1612 '25-sysctl-disable-ipv6.network',
1613 '25-sysctl.network',
1614 '25-veth-peer.network',
1616 '26-link-local-addressing-ipv6.network',
1617 'configure-without-carrier.network',
1618 'routing-policy-rule-dummy98.network',
1619 'routing-policy-rule-test1.network']
1621 routing_policy_rule_tables
= ['7', '8', '9']
1622 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1625 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1626 remove_routes(self
.routes
)
1627 remove_links(self
.links
)
1628 stop_networkd(show_logs
=False)
1631 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1632 remove_routes(self
.routes
)
1633 remove_links(self
.links
)
1634 remove_unit_from_networkd_path(self
.units
)
1635 stop_networkd(show_logs
=True)
1637 def test_address_static(self
):
1638 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1641 self
.wait_online(['dummy98:routable'])
1643 output
= check_output('ip -4 address show dev dummy98')
1645 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1646 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1647 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1650 self
.assertNotRegex(output
, '10.10.0.1/16')
1651 self
.assertNotRegex(output
, '10.10.0.2/16')
1653 output
= check_output('ip -4 address show dev dummy98 label 32')
1654 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1656 output
= check_output('ip -4 address show dev dummy98 label 33')
1657 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1659 output
= check_output('ip -4 address show dev dummy98 label 34')
1660 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1662 output
= check_output('ip -4 address show dev dummy98 label 35')
1663 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1665 output
= check_output('ip -6 address show dev dummy98')
1667 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1668 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1669 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1670 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1671 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1672 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1674 def test_address_preferred_lifetime_zero_ipv6(self
):
1675 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero.network', '12-dummy.netdev')
1678 self
.wait_online(['dummy98:routable'])
1680 output
= check_output('ip address show dummy98')
1682 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1683 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1685 output
= check_output('ip route show dev dummy98')
1687 self
.assertRegex(output
, 'default via 20.20.20.1 proto static')
1689 def test_address_dad(self
):
1690 copy_unit_to_networkd_unit_path('25-address-dad-veth99.network', '25-address-dad-veth-peer.network',
1693 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
1695 output
= check_output('ip -4 address show dev veth99')
1697 self
.assertRegex(output
, '192.168.100.10/24')
1699 output
= check_output('ip -4 address show dev veth-peer')
1701 self
.assertNotRegex(output
, '192.168.100.10/24')
1703 def test_configure_without_carrier(self
):
1704 copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
1706 self
.wait_online(['test1:routable'])
1708 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
1710 self
.assertRegex(output
, '192.168.0.15')
1711 self
.assertRegex(output
, '192.168.0.1')
1712 self
.assertRegex(output
, 'routable')
1714 def test_routing_policy_rule(self
):
1715 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1717 self
.wait_online(['test1:degraded'])
1719 output
= check_output('ip rule list iif test1 priority 111')
1721 self
.assertRegex(output
, '111:')
1722 self
.assertRegex(output
, 'from 192.168.100.18')
1723 self
.assertRegex(output
, r
'tos (0x08|throughput)\s')
1724 self
.assertRegex(output
, 'iif test1')
1725 self
.assertRegex(output
, 'oif test1')
1726 self
.assertRegex(output
, 'lookup 7')
1728 output
= check_output('ip rule list iif test1 priority 101')
1730 self
.assertRegex(output
, '101:')
1731 self
.assertRegex(output
, 'from all')
1732 self
.assertRegex(output
, 'iif test1')
1733 self
.assertRegex(output
, 'lookup 9')
1735 output
= check_output('ip -6 rule list iif test1 priority 100')
1737 self
.assertRegex(output
, '100:')
1738 self
.assertRegex(output
, 'from all')
1739 self
.assertRegex(output
, 'iif test1')
1740 self
.assertRegex(output
, 'lookup 8')
1742 output
= check_output('ip -6 rule list iif test1 priority 101')
1744 self
.assertRegex(output
, '101:')
1745 self
.assertRegex(output
, 'from all')
1746 self
.assertRegex(output
, 'iif test1')
1747 self
.assertRegex(output
, 'lookup 9')
1749 def test_routing_policy_rule_issue_11280(self
):
1750 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1751 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1753 for trial
in range(3):
1754 # Remove state files only first time
1756 self
.wait_online(['test1:degraded', 'dummy98:degraded'])
1759 output
= check_output('ip rule list table 7')
1761 self
.assertRegex(output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
1763 output
= check_output('ip rule list table 8')
1765 self
.assertRegex(output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1767 stop_networkd(remove_state_files
=False)
1769 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1770 def test_routing_policy_rule_port_range(self
):
1771 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1773 self
.wait_online(['test1:degraded'])
1775 output
= check_output('ip rule')
1777 self
.assertRegex(output
, '111')
1778 self
.assertRegex(output
, 'from 192.168.100.18')
1779 self
.assertRegex(output
, '1123-1150')
1780 self
.assertRegex(output
, '3224-3290')
1781 self
.assertRegex(output
, 'tcp')
1782 self
.assertRegex(output
, 'lookup 7')
1784 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1785 def test_routing_policy_rule_invert(self
):
1786 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1788 self
.wait_online(['test1:degraded'])
1790 output
= check_output('ip rule')
1792 self
.assertRegex(output
, '111')
1793 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
1794 self
.assertRegex(output
, 'tcp')
1795 self
.assertRegex(output
, 'lookup 7')
1797 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable()
1798 def test_routing_policy_rule_uidrange(self
):
1799 copy_unit_to_networkd_unit_path('25-fibrule-uidrange.network', '11-dummy.netdev')
1801 self
.wait_online(['test1:degraded'])
1803 output
= check_output('ip rule')
1805 self
.assertRegex(output
, '111')
1806 self
.assertRegex(output
, 'from 192.168.100.18')
1807 self
.assertRegex(output
, 'lookup 7')
1808 self
.assertRegex(output
, 'uidrange 100-200')
1810 def test_route_static(self
):
1811 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1813 self
.wait_online(['dummy98:routable'])
1815 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
1818 print('### ip -6 route show dev dummy98')
1819 output
= check_output('ip -6 route show dev dummy98')
1821 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1822 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
1824 print('### ip -6 route show dev dummy98 default')
1825 output
= check_output('ip -6 route show dev dummy98 default')
1827 self
.assertRegex(output
, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1829 print('### ip -4 route show dev dummy98')
1830 output
= check_output('ip -4 route show dev dummy98')
1832 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1833 self
.assertRegex(output
, '149.10.124.64 proto static scope link')
1834 self
.assertRegex(output
, '169.254.0.0/16 proto static scope link metric 2048')
1835 self
.assertRegex(output
, '192.168.1.1 proto static initcwnd 20')
1836 self
.assertRegex(output
, '192.168.1.2 proto static initrwnd 30')
1837 self
.assertRegex(output
, 'multicast 149.10.123.4 proto static')
1839 print('### ip -4 route show dev dummy98 default')
1840 output
= check_output('ip -4 route show dev dummy98 default')
1842 self
.assertRegex(output
, 'default via 149.10.125.65 proto static onlink')
1843 self
.assertRegex(output
, 'default via 149.10.124.64 proto static')
1844 self
.assertRegex(output
, 'default proto static')
1846 print('### ip -4 route show table local dev dummy98')
1847 output
= check_output('ip -4 route show table local dev dummy98')
1849 self
.assertRegex(output
, 'local 149.10.123.1 proto static scope host')
1850 self
.assertRegex(output
, 'anycast 149.10.123.2 proto static scope link')
1851 self
.assertRegex(output
, 'broadcast 149.10.123.3 proto static scope link')
1853 print('### ip route show type blackhole')
1854 output
= check_output('ip route show type blackhole')
1856 self
.assertRegex(output
, 'blackhole 202.54.1.2 proto static')
1858 print('### ip route show type unreachable')
1859 output
= check_output('ip route show type unreachable')
1861 self
.assertRegex(output
, 'unreachable 202.54.1.3 proto static')
1863 print('### ip route show type prohibit')
1864 output
= check_output('ip route show type prohibit')
1866 self
.assertRegex(output
, 'prohibit 202.54.1.4 proto static')
1868 print('### ip route show 192.168.10.1')
1869 output
= check_output('ip route show 192.168.10.1')
1871 self
.assertRegex(output
, '192.168.10.1 proto static')
1872 self
.assertRegex(output
, 'nexthop via 149.10.124.59 dev dummy98 weight 10')
1873 self
.assertRegex(output
, 'nexthop via 149.10.124.60 dev dummy98 weight 5')
1875 print('### ip route show 192.168.10.2')
1876 output
= check_output('ip route show 192.168.10.2')
1878 # old ip command does not show IPv6 gateways...
1879 self
.assertRegex(output
, '192.168.10.2 proto static')
1880 self
.assertRegex(output
, 'nexthop')
1881 self
.assertRegex(output
, 'dev dummy98 weight 10')
1882 self
.assertRegex(output
, 'dev dummy98 weight 5')
1884 print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
1885 output
= check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
1887 # old ip command does not show 'nexthop' keyword and weight...
1888 self
.assertRegex(output
, '2001:1234:5:7fff:ff:ff:ff:ff')
1889 self
.assertRegex(output
, 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98')
1890 self
.assertRegex(output
, 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98')
1892 def test_gateway_reconfigure(self
):
1893 copy_unit_to_networkd_unit_path('25-gateway-static.network', '12-dummy.netdev')
1895 self
.wait_online(['dummy98:routable'])
1896 print('### ip -4 route show dev dummy98 default')
1897 output
= check_output('ip -4 route show dev dummy98 default')
1899 self
.assertRegex(output
, 'default via 149.10.124.59 proto static')
1900 self
.assertNotRegex(output
, '149.10.124.60')
1902 remove_unit_from_networkd_path(['25-gateway-static.network'])
1903 copy_unit_to_networkd_unit_path('25-gateway-next-static.network')
1905 self
.wait_online(['dummy98:routable'])
1906 print('### ip -4 route show dev dummy98 default')
1907 output
= check_output('ip -4 route show dev dummy98 default')
1909 self
.assertNotRegex(output
, '149.10.124.59')
1910 self
.assertRegex(output
, 'default via 149.10.124.60 proto static')
1912 def test_ip_route_ipv6_src_route(self
):
1913 # a dummy device does not make the addresses go through tentative state, so we
1914 # reuse a bond from an earlier test, which does make the addresses go through
1915 # tentative state, and do our test on that
1916 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1918 self
.wait_online(['dummy98:enslaved', 'bond199:routable'])
1920 output
= check_output('ip -6 route list dev bond199')
1922 self
.assertRegex(output
, 'abcd::/16')
1923 self
.assertRegex(output
, 'src')
1924 self
.assertRegex(output
, '2001:1234:56:8f63::2')
1926 def test_ip_link_mac_address(self
):
1927 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
1929 self
.wait_online(['dummy98:degraded'])
1931 output
= check_output('ip link show dummy98')
1933 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
1935 def test_ip_link_unmanaged(self
):
1936 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
1939 self
.check_link_exists('dummy98')
1941 self
.wait_operstate('dummy98', 'off', setup_state
='unmanaged')
1943 def test_ipv6_address_label(self
):
1944 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
1946 self
.wait_online(['dummy98:degraded'])
1948 output
= check_output('ip addrlabel list')
1950 self
.assertRegex(output
, '2004:da8:1::/64')
1952 def test_neighbor_section(self
):
1953 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
1955 self
.wait_online(['dummy98:degraded'], timeout
='40s')
1957 print('### ip neigh list dev dummy98')
1958 output
= check_output('ip neigh list dev dummy98')
1960 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
1961 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
1963 def test_neighbor_reconfigure(self
):
1964 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
1966 self
.wait_online(['dummy98:degraded'], timeout
='40s')
1968 print('### ip neigh list dev dummy98')
1969 output
= check_output('ip neigh list dev dummy98')
1971 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
1972 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
1974 remove_unit_from_networkd_path(['25-neighbor-section.network'])
1975 copy_unit_to_networkd_unit_path('25-neighbor-next.network')
1977 self
.wait_online(['dummy98:degraded'], timeout
='40s')
1978 print('### ip neigh list dev dummy98')
1979 output
= check_output('ip neigh list dev dummy98')
1981 self
.assertNotRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
1982 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT')
1983 self
.assertNotRegex(output
, '2004:da8:1::1.*PERMANENT')
1985 def test_neighbor_gre(self
):
1986 copy_unit_to_networkd_unit_path('25-neighbor-ip.network', '25-neighbor-ipv6.network', '25-neighbor-ip-dummy.network',
1987 '12-dummy.netdev', '25-gre-tunnel-remote-any.netdev', '25-ip6gre-tunnel-remote-any.netdev')
1989 self
.wait_online(['dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable'], timeout
='40s')
1991 output
= check_output('ip neigh list dev gretun97')
1993 self
.assertRegex(output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT')
1995 output
= check_output('ip neigh list dev ip6gretun97')
1997 self
.assertRegex(output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
1999 def test_link_local_addressing(self
):
2000 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
2001 '25-link-local-addressing-no.network', '12-dummy.netdev')
2003 self
.wait_online(['test1:degraded', 'dummy98:carrier'])
2005 output
= check_output('ip address show dev test1')
2007 self
.assertRegex(output
, 'inet .* scope link')
2008 self
.assertRegex(output
, 'inet6 .* scope link')
2010 output
= check_output('ip address show dev dummy98')
2012 self
.assertNotRegex(output
, 'inet6* .* scope link')
2015 Documentation/networking/ip-sysctl.txt
2017 addr_gen_mode - INTEGER
2018 Defines how link-local and autoconf addresses are generated.
2020 0: generate address based on EUI64 (default)
2021 1: do no generate a link-local address, use EUI64 for addresses generated
2023 2: generate stable privacy addresses, using the secret from
2024 stable_secret (RFC7217)
2025 3: generate stable privacy addresses, using a random secret if unset
2028 test1_addr_gen_mode
= ''
2029 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
2030 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
2034 # if stable_secret is unset, then EIO is returned
2035 test1_addr_gen_mode
= '0'
2037 test1_addr_gen_mode
= '2'
2039 test1_addr_gen_mode
= '0'
2041 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
2042 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
2044 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
2045 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
2047 def test_link_local_addressing_remove_ipv6ll(self
):
2048 copy_unit_to_networkd_unit_path('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
2050 self
.wait_online(['dummy98:degraded'])
2052 output
= check_output('ip address show dev dummy98')
2054 self
.assertRegex(output
, 'inet6 .* scope link')
2056 copy_unit_to_networkd_unit_path('25-link-local-addressing-no.network')
2058 self
.wait_online(['dummy98:carrier'])
2060 output
= check_output('ip address show dev dummy98')
2062 self
.assertNotRegex(output
, 'inet6* .* scope link')
2064 def test_sysctl(self
):
2065 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
2067 self
.wait_online(['dummy98:degraded'])
2069 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
2070 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
2071 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
2072 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
2073 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
2074 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
2075 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
2077 def test_sysctl_disable_ipv6(self
):
2078 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
2080 print('## Disable ipv6')
2081 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
2082 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
2085 self
.wait_online(['dummy98:routable'])
2087 output
= check_output('ip -4 address show dummy98')
2089 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2090 output
= check_output('ip -6 address show dummy98')
2092 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2093 self
.assertRegex(output
, 'inet6 .* scope link')
2094 output
= check_output('ip -4 route show dev dummy98')
2096 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2097 output
= check_output('ip -6 route show dev dummy98')
2099 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2101 check_output('ip link del dummy98')
2103 print('## Enable ipv6')
2104 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
2105 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
2108 self
.wait_online(['dummy98:routable'])
2110 output
= check_output('ip -4 address show dummy98')
2112 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2113 output
= check_output('ip -6 address show dummy98')
2115 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2116 self
.assertRegex(output
, 'inet6 .* scope link')
2117 output
= check_output('ip -4 route show dev dummy98')
2119 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2120 output
= check_output('ip -6 route show dev dummy98')
2122 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2124 def test_bind_carrier(self
):
2125 check_output('ip link add dummy98 type dummy')
2126 check_output('ip link set dummy98 up')
2129 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
2131 self
.wait_online(['test1:routable'])
2133 output
= check_output('ip address show test1')
2135 self
.assertRegex(output
, 'UP,LOWER_UP')
2136 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2137 self
.wait_operstate('test1', 'routable')
2139 check_output('ip link add dummy99 type dummy')
2140 check_output('ip link set dummy99 up')
2142 output
= check_output('ip address show test1')
2144 self
.assertRegex(output
, 'UP,LOWER_UP')
2145 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2146 self
.wait_operstate('test1', 'routable')
2148 check_output('ip link del dummy98')
2150 output
= check_output('ip address show test1')
2152 self
.assertRegex(output
, 'UP,LOWER_UP')
2153 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2154 self
.wait_operstate('test1', 'routable')
2156 check_output('ip link set dummy99 down')
2158 output
= check_output('ip address show test1')
2160 self
.assertNotRegex(output
, 'UP,LOWER_UP')
2161 self
.assertRegex(output
, 'DOWN')
2162 self
.assertNotRegex(output
, '192.168.10')
2163 self
.wait_operstate('test1', 'off')
2165 check_output('ip link set dummy99 up')
2167 output
= check_output('ip address show test1')
2169 self
.assertRegex(output
, 'UP,LOWER_UP')
2170 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2171 self
.wait_operstate('test1', 'routable')
2173 def test_domain(self
):
2174 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
2176 self
.wait_online(['dummy98:routable'])
2178 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2180 self
.assertRegex(output
, 'Address: 192.168.42.100')
2181 self
.assertRegex(output
, 'DNS: 192.168.42.1')
2182 self
.assertRegex(output
, 'Search Domains: one')
2184 def test_keep_configuration_static(self
):
2185 check_output('systemctl stop systemd-networkd')
2187 check_output('ip link add name dummy98 type dummy')
2188 check_output('ip address add 10.1.2.3/16 dev dummy98')
2189 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
2190 output
= check_output('ip address show dummy98')
2192 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2193 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2194 output
= check_output('ip route show dev dummy98')
2197 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
2199 self
.wait_online(['dummy98:routable'])
2201 output
= check_output('ip address show dummy98')
2203 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2204 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2206 @expectedFailureIfNexthopIsNotAvailable()
2207 def test_nexthop(self
):
2208 copy_unit_to_networkd_unit_path('25-nexthop.network', '25-veth.netdev', '25-veth-peer.network')
2210 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2212 output
= check_output('ip nexthop list dev veth99')
2214 self
.assertRegex(output
, '192.168.5.1')
2216 def test_qdisc(self
):
2217 copy_unit_to_networkd_unit_path('25-qdisc-netem-and-fqcodel.network', '12-dummy.netdev',
2218 '25-qdisc-tbf-and-sfq.network', '11-dummy.netdev')
2221 self
.wait_online(['dummy98:routable', 'test1:routable'])
2223 output
= check_output('tc qdisc show dev dummy98')
2225 self
.assertRegex(output
, 'qdisc netem')
2226 self
.assertRegex(output
, 'limit 100 delay 50.0ms 10.0ms loss 20%')
2227 self
.assertRegex(output
, 'qdisc fq_codel')
2228 self
.assertRegex(output
, 'limit 20480p flows 2048 quantum 1400 target 10.0ms ce_threshold 100.0ms interval 200.0ms memory_limit 64Mb ecn')
2229 output
= check_output('tc qdisc show dev test1')
2231 self
.assertRegex(output
, 'qdisc tbf')
2232 self
.assertRegex(output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70.0ms')
2233 self
.assertRegex(output
, 'qdisc sfq')
2234 self
.assertRegex(output
, 'perturb 5sec')
2236 def test_qdisc2(self
):
2237 copy_unit_to_networkd_unit_path('25-qdisc-fq-codel.network', '12-dummy.netdev')
2240 self
.wait_online(['dummy98:routable'])
2242 output
= check_output('tc qdisc show dev dummy98')
2244 self
.assertRegex(output
, 'qdisc fq')
2245 self
.assertRegex(output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
2246 self
.assertRegex(output
, 'quantum 1500')
2247 self
.assertRegex(output
, 'initial_quantum 13000')
2248 self
.assertRegex(output
, 'maxrate 1Mbit')
2249 self
.assertRegex(output
, 'qdisc codel')
2250 self
.assertRegex(output
, 'limit 2000p target 10.0ms ce_threshold 100.0ms interval 50.0ms ecn')
2252 class NetworkdStateFileTests(unittest
.TestCase
, Utilities
):
2259 'state-file-tests.network',
2263 remove_links(self
.links
)
2264 stop_networkd(show_logs
=False)
2267 remove_links(self
.links
)
2268 remove_unit_from_networkd_path(self
.units
)
2269 stop_networkd(show_logs
=True)
2271 def test_state_file(self
):
2272 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'state-file-tests.network')
2274 self
.wait_online(['dummy98:routable'])
2276 output
= check_output(*networkctl_cmd
, '--no-legend', 'list', 'dummy98', env
=env
)
2278 ifindex
= output
.split()[0]
2280 path
= os
.path
.join('/run/systemd/netif/links/', ifindex
)
2281 self
.assertTrue(os
.path
.exists(path
))
2284 with
open(path
) as f
:
2286 self
.assertRegex(data
, r
'ADMIN_STATE=configured')
2287 self
.assertRegex(data
, r
'OPER_STATE=routable')
2288 self
.assertRegex(data
, r
'REQUIRED_FOR_ONLINE=yes')
2289 self
.assertRegex(data
, r
'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
2290 self
.assertRegex(data
, r
'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
2291 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
2292 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2293 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2294 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2295 self
.assertRegex(data
, r
'LLMNR=no')
2296 self
.assertRegex(data
, r
'MDNS=yes')
2297 self
.assertRegex(data
, r
'DNSSEC=no')
2298 self
.assertRegex(data
, r
'ADDRESSES=192.168.(10.10|12.12)/24 192.168.(12.12|10.10)/24')
2300 check_output(*resolvectl_cmd
, 'dns', 'dummy98', '10.10.10.12', '10.10.10.13', env
=env
)
2301 check_output(*resolvectl_cmd
, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env
=env
)
2302 check_output(*resolvectl_cmd
, 'llmnr', 'dummy98', 'yes', env
=env
)
2303 check_output(*resolvectl_cmd
, 'mdns', 'dummy98', 'no', env
=env
)
2304 check_output(*resolvectl_cmd
, 'dnssec', 'dummy98', 'yes', env
=env
)
2305 check_output(*timedatectl_cmd
, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env
=env
)
2308 with
open(path
) as f
:
2310 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
2311 self
.assertRegex(data
, r
'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org')
2312 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2313 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2314 self
.assertRegex(data
, r
'LLMNR=yes')
2315 self
.assertRegex(data
, r
'MDNS=no')
2316 self
.assertRegex(data
, r
'DNSSEC=yes')
2318 check_output(*timedatectl_cmd
, 'revert', 'dummy98', env
=env
)
2321 with
open(path
) as f
:
2323 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
2324 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2325 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2326 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2327 self
.assertRegex(data
, r
'LLMNR=yes')
2328 self
.assertRegex(data
, r
'MDNS=no')
2329 self
.assertRegex(data
, r
'DNSSEC=yes')
2331 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
2334 with
open(path
) as f
:
2336 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
2337 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2338 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2339 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2340 self
.assertRegex(data
, r
'LLMNR=no')
2341 self
.assertRegex(data
, r
'MDNS=yes')
2342 self
.assertRegex(data
, r
'DNSSEC=no')
2344 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
2354 '23-active-slave.network',
2355 '23-bond199.network',
2356 '23-primary-slave.network',
2357 '25-bond-active-backup-slave.netdev',
2360 'bond-slave.network']
2363 remove_links(self
.links
)
2364 stop_networkd(show_logs
=False)
2367 remove_links(self
.links
)
2368 remove_unit_from_networkd_path(self
.units
)
2369 stop_networkd(show_logs
=True)
2371 def test_bond_active_slave(self
):
2372 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2374 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2376 output
= check_output('ip -d link show bond199')
2378 self
.assertRegex(output
, 'active_slave dummy98')
2380 def test_bond_primary_slave(self
):
2381 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2383 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2385 output
= check_output('ip -d link show bond199')
2387 self
.assertRegex(output
, 'primary dummy98')
2389 def test_bond_operstate(self
):
2390 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
2391 'bond99.network','bond-slave.network')
2393 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
2395 output
= check_output('ip -d link show dummy98')
2397 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2399 output
= check_output('ip -d link show test1')
2401 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2403 output
= check_output('ip -d link show bond99')
2405 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
2407 self
.wait_operstate('dummy98', 'enslaved')
2408 self
.wait_operstate('test1', 'enslaved')
2409 self
.wait_operstate('bond99', 'routable')
2411 check_output('ip link set dummy98 down')
2413 self
.wait_operstate('dummy98', 'off')
2414 self
.wait_operstate('test1', 'enslaved')
2415 self
.wait_operstate('bond99', 'degraded-carrier')
2417 check_output('ip link set dummy98 up')
2419 self
.wait_operstate('dummy98', 'enslaved')
2420 self
.wait_operstate('test1', 'enslaved')
2421 self
.wait_operstate('bond99', 'routable')
2423 check_output('ip link set dummy98 down')
2424 check_output('ip link set test1 down')
2426 self
.wait_operstate('dummy98', 'off')
2427 self
.wait_operstate('test1', 'off')
2429 if not self
.wait_operstate('bond99', 'no-carrier', setup_timeout
=30, fail_assert
=False):
2430 # Huh? Kernel does not recognize that all slave interfaces are down?
2431 # Let's confirm that networkd's operstate is consistent with ip's result.
2432 self
.assertNotRegex(output
, 'NO-CARRIER')
2434 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
2444 '26-bridge-slave-interface-1.network',
2445 '26-bridge-slave-interface-2.network',
2446 '26-bridge-vlan-master.network',
2447 '26-bridge-vlan-slave.network',
2448 'bridge99-ignore-carrier-loss.network',
2451 routing_policy_rule_tables
= ['100']
2454 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2455 remove_links(self
.links
)
2456 stop_networkd(show_logs
=False)
2459 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2460 remove_links(self
.links
)
2461 remove_unit_from_networkd_path(self
.units
)
2462 stop_networkd(show_logs
=True)
2464 def test_bridge_vlan(self
):
2465 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
2466 '26-bridge.netdev', '26-bridge-vlan-master.network')
2468 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
2470 output
= check_output('bridge vlan show dev test1')
2472 self
.assertNotRegex(output
, '4063')
2473 for i
in range(4064, 4095):
2474 self
.assertRegex(output
, f
'{i}')
2475 self
.assertNotRegex(output
, '4095')
2477 output
= check_output('bridge vlan show dev bridge99')
2479 self
.assertNotRegex(output
, '4059')
2480 for i
in range(4060, 4095):
2481 self
.assertRegex(output
, f
'{i}')
2482 self
.assertNotRegex(output
, '4095')
2484 def test_bridge_property(self
):
2485 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2486 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2489 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2491 output
= check_output('ip -d link show test1')
2493 self
.assertRegex(output
, 'master')
2494 self
.assertRegex(output
, 'bridge')
2496 output
= check_output('ip -d link show dummy98')
2498 self
.assertRegex(output
, 'master')
2499 self
.assertRegex(output
, 'bridge')
2501 output
= check_output('ip addr show bridge99')
2503 self
.assertRegex(output
, '192.168.0.15/24')
2505 output
= check_output('bridge -d link show dummy98')
2507 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
2508 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
2509 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
2510 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
2511 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
2512 # CONFIG_BRIDGE_IGMP_SNOOPING=y
2513 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
2514 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
2515 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
2516 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
2517 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
2518 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'priority'), '23')
2519 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard'), '1')
2520 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'root_block'), '1')
2522 output
= check_output('bridge -d link show test1')
2524 self
.assertEqual(read_bridge_port_attr('bridge99', 'test1', 'priority'), '0')
2526 check_output('ip address add 192.168.0.16/24 dev bridge99')
2529 output
= check_output('ip addr show bridge99')
2531 self
.assertRegex(output
, '192.168.0.16/24')
2534 print('### ip -6 route list table all dev bridge99')
2535 output
= check_output('ip -6 route list table all dev bridge99')
2537 self
.assertRegex(output
, 'ff00::/8 table local metric 256 pref medium')
2539 self
.assertEqual(call('ip link del test1'), 0)
2541 self
.wait_operstate('bridge99', 'degraded-carrier')
2543 check_output('ip link del dummy98')
2545 self
.wait_operstate('bridge99', 'no-carrier')
2547 output
= check_output('ip address show bridge99')
2549 self
.assertRegex(output
, 'NO-CARRIER')
2550 self
.assertNotRegex(output
, '192.168.0.15/24')
2551 self
.assertNotRegex(output
, '192.168.0.16/24')
2553 print('### ip -6 route list table all dev bridge99')
2554 output
= check_output('ip -6 route list table all dev bridge99')
2556 self
.assertRegex(output
, 'ff00::/8 table local metric 256 (linkdown )?pref medium')
2558 def test_bridge_ignore_carrier_loss(self
):
2559 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2560 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2561 'bridge99-ignore-carrier-loss.network')
2563 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2565 check_output('ip address add 192.168.0.16/24 dev bridge99')
2568 check_output('ip link del test1')
2569 check_output('ip link del dummy98')
2572 output
= check_output('ip address show bridge99')
2574 self
.assertRegex(output
, 'NO-CARRIER')
2575 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2576 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
2578 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
2579 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
2580 'bridge99-ignore-carrier-loss.network')
2582 self
.wait_online(['bridge99:no-carrier'])
2584 for trial
in range(4):
2585 check_output('ip link add dummy98 type dummy')
2586 check_output('ip link set dummy98 up')
2588 check_output('ip link del dummy98')
2590 self
.wait_online(['bridge99:routable', 'dummy98:enslaved'])
2592 output
= check_output('ip address show bridge99')
2594 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2596 output
= check_output('ip rule list table 100')
2598 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
2600 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
2604 '23-emit-lldp.network',
2609 remove_links(self
.links
)
2610 stop_networkd(show_logs
=False)
2613 remove_links(self
.links
)
2614 remove_unit_from_networkd_path(self
.units
)
2615 stop_networkd(show_logs
=True)
2617 def test_lldp(self
):
2618 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
2620 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
2622 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
2624 self
.assertRegex(output
, 'veth-peer')
2625 self
.assertRegex(output
, 'veth99')
2627 class NetworkdRATests(unittest
.TestCase
, Utilities
):
2632 'ipv6-prefix.network',
2633 'ipv6-prefix-veth.network']
2636 remove_links(self
.links
)
2637 stop_networkd(show_logs
=False)
2640 remove_links(self
.links
)
2641 remove_unit_from_networkd_path(self
.units
)
2642 stop_networkd(show_logs
=True)
2644 def test_ipv6_prefix_delegation(self
):
2645 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
2647 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2649 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2651 self
.assertRegex(output
, '2002:da8:1:0')
2653 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
2658 'dhcp-client.network',
2659 'dhcp-client-timezone-router.network',
2660 'dhcp-server.network',
2661 'dhcp-server-timezone-router.network']
2664 remove_links(self
.links
)
2665 stop_networkd(show_logs
=False)
2668 remove_links(self
.links
)
2669 remove_unit_from_networkd_path(self
.units
)
2670 stop_networkd(show_logs
=True)
2672 def test_dhcp_server(self
):
2673 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
2675 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2677 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2679 self
.assertRegex(output
, '192.168.5.*')
2680 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
2681 self
.assertRegex(output
, 'DNS: 192.168.5.1')
2682 self
.assertRegex(output
, 'NTP: 192.168.5.1')
2684 def test_emit_router_timezone(self
):
2685 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
2687 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2689 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2691 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
2692 self
.assertRegex(output
, '192.168.5.*')
2693 self
.assertRegex(output
, 'Europe/Berlin')
2695 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
2704 'dhcp-client-anonymize.network',
2705 'dhcp-client-decline.network',
2706 'dhcp-client-gateway-ipv4.network',
2707 'dhcp-client-gateway-ipv6.network',
2708 'dhcp-client-gateway-onlink-implicit.network',
2709 'dhcp-client-ipv4-dhcp-settings.network',
2710 'dhcp-client-ipv4-only-ipv6-disabled.network',
2711 'dhcp-client-ipv4-only.network',
2712 'dhcp-client-ipv6-only.network',
2713 'dhcp-client-ipv6-rapid-commit.network',
2714 'dhcp-client-keep-configuration-dhcp-on-stop.network',
2715 'dhcp-client-keep-configuration-dhcp.network',
2716 'dhcp-client-listen-port.network',
2717 'dhcp-client-reassign-static-routes-ipv4.network',
2718 'dhcp-client-reassign-static-routes-ipv6.network',
2719 'dhcp-client-route-metric.network',
2720 'dhcp-client-route-table.network',
2721 'dhcp-client-use-dns-ipv4-and-ra.network',
2722 'dhcp-client-use-dns-ipv4.network',
2723 'dhcp-client-use-dns-no.network',
2724 'dhcp-client-use-dns-yes.network',
2725 'dhcp-client-use-domains.network',
2726 'dhcp-client-use-routes-no.network',
2727 'dhcp-client-vrf.network',
2728 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
2729 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
2730 'dhcp-client-with-static-address.network',
2731 'dhcp-client.network',
2732 'dhcp-server-decline.network',
2733 'dhcp-server-veth-peer.network',
2734 'dhcp-v4-server-veth-peer.network',
2735 'dhcp-client-use-domains.network',
2739 stop_dnsmasq(dnsmasq_pid_file
)
2740 remove_links(self
.links
)
2741 stop_networkd(show_logs
=False)
2744 stop_dnsmasq(dnsmasq_pid_file
)
2747 remove_links(self
.links
)
2748 remove_unit_from_networkd_path(self
.units
)
2749 stop_networkd(show_logs
=True)
2751 def test_dhcp_client_ipv6_only(self
):
2752 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2755 self
.wait_online(['veth-peer:carrier'])
2757 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2759 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2761 self
.assertRegex(output
, '2600::')
2762 self
.assertNotRegex(output
, '192.168.5')
2764 # Confirm that ipv6 token is not set in the kernel
2765 output
= check_output('ip token show dev veth99')
2767 self
.assertRegex(output
, 'token :: dev veth99')
2769 def test_dhcp_client_ipv4_only(self
):
2770 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
2773 self
.wait_online(['veth-peer:carrier'])
2774 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
2775 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2777 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2779 self
.assertNotRegex(output
, '2600::')
2780 self
.assertRegex(output
, '192.168.5')
2781 self
.assertRegex(output
, '192.168.5.6')
2782 self
.assertRegex(output
, '192.168.5.7')
2784 # checking routes to DNS servers
2785 output
= check_output('ip route show dev veth99')
2787 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
2788 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
2789 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
2791 stop_dnsmasq(dnsmasq_pid_file
)
2792 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8', lease_time
='2m')
2794 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2795 print('Wait for the dynamic address to be renewed')
2798 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2800 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2802 self
.assertNotRegex(output
, '2600::')
2803 self
.assertRegex(output
, '192.168.5')
2804 self
.assertNotRegex(output
, '192.168.5.6')
2805 self
.assertRegex(output
, '192.168.5.7')
2806 self
.assertRegex(output
, '192.168.5.8')
2808 # checking routes to DNS servers
2809 output
= check_output('ip route show dev veth99')
2811 self
.assertNotRegex(output
, r
'192.168.5.6')
2812 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
2813 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
2814 self
.assertRegex(output
, r
'192.168.5.8 proto dhcp scope link src 192.168.5.181 metric 1024')
2816 def test_dhcp_client_ipv4_ipv6(self
):
2817 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
2818 'dhcp-client-ipv4-only.network')
2820 self
.wait_online(['veth-peer:carrier'])
2822 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2824 # link become 'routable' when at least one protocol provide an valid address.
2825 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2826 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2828 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2830 self
.assertRegex(output
, '2600::')
2831 self
.assertRegex(output
, '192.168.5')
2833 def test_dhcp_client_settings(self
):
2834 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
2837 self
.wait_online(['veth-peer:carrier'])
2839 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2841 print('## ip address show dev veth99')
2842 output
= check_output('ip address show dev veth99')
2844 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2845 self
.assertRegex(output
, '192.168.5')
2846 self
.assertRegex(output
, '1492')
2848 print('## ip route show table main dev veth99')
2849 output
= check_output('ip route show table main dev veth99')
2852 main_table_is_empty
= output
== ''
2853 if not main_table_is_empty
:
2854 self
.assertNotRegex(output
, 'proto dhcp')
2856 print('## ip route show table 211 dev veth99')
2857 output
= check_output('ip route show table 211 dev veth99')
2859 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
2860 if main_table_is_empty
:
2861 self
.assertRegex(output
, '192.168.5.0/24 proto dhcp')
2862 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
2863 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
2865 print('## dnsmasq log')
2866 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
2867 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
2868 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
2869 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
2871 def test_dhcp6_client_settings_rapidcommit_true(self
):
2872 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2874 self
.wait_online(['veth-peer:carrier'])
2876 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2878 output
= check_output('ip address show dev veth99')
2880 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2881 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
2883 def test_dhcp6_client_settings_rapidcommit_false(self
):
2884 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
2886 self
.wait_online(['veth-peer:carrier'])
2888 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2890 output
= check_output('ip address show dev veth99')
2892 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2893 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
2895 def test_dhcp_client_settings_anonymize(self
):
2896 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
2898 self
.wait_online(['veth-peer:carrier'])
2900 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2902 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
2903 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
2904 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
2906 def test_dhcp_client_listen_port(self
):
2907 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
2909 self
.wait_online(['veth-peer:carrier'])
2910 start_dnsmasq('--dhcp-alternate-port=67,5555')
2911 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2913 output
= check_output('ip -4 address show dev veth99')
2915 self
.assertRegex(output
, '192.168.5.* dynamic')
2917 def test_dhcp_client_with_static_address(self
):
2918 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
2919 'dhcp-client-with-static-address.network')
2921 self
.wait_online(['veth-peer:carrier'])
2923 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2925 output
= check_output('ip address show dev veth99 scope global')
2927 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
2928 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
2930 output
= check_output('ip route show dev veth99')
2932 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
2933 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
2934 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
2935 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
2937 def test_dhcp_route_table_id(self
):
2938 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
2940 self
.wait_online(['veth-peer:carrier'])
2942 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2944 output
= check_output('ip route show table 12')
2946 self
.assertRegex(output
, 'veth99 proto dhcp')
2947 self
.assertRegex(output
, '192.168.5.1')
2949 def test_dhcp_route_metric(self
):
2950 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
2952 self
.wait_online(['veth-peer:carrier'])
2954 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2956 output
= check_output('ip route show dev veth99')
2958 self
.assertRegex(output
, 'metric 24')
2960 def test_dhcp_client_reassign_static_routes_ipv4(self
):
2961 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2962 'dhcp-client-reassign-static-routes-ipv4.network')
2964 self
.wait_online(['veth-peer:carrier'])
2965 start_dnsmasq(lease_time
='2m')
2966 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2968 output
= check_output('ip address show dev veth99 scope global')
2970 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2972 output
= check_output('ip route show dev veth99')
2974 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
2975 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
2976 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
2977 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
2979 stop_dnsmasq(dnsmasq_pid_file
)
2980 start_dnsmasq(ipv4_range
='192.168.5.210,192.168.5.220', lease_time
='2m')
2982 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2983 print('Wait for the dynamic address to be renewed')
2986 self
.wait_online(['veth99:routable'])
2988 output
= check_output('ip route show dev veth99')
2990 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
2991 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
2992 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
2993 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
2995 def test_dhcp_client_reassign_static_routes_ipv6(self
):
2996 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2997 'dhcp-client-reassign-static-routes-ipv6.network')
2999 self
.wait_online(['veth-peer:carrier'])
3000 start_dnsmasq(lease_time
='2m')
3001 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3003 output
= check_output('ip address show dev veth99 scope global')
3005 self
.assertRegex(output
, r
'inet6 2600::[0-9a-f]*/128 scope global (noprefixroute dynamic|dynamic noprefixroute)')
3007 output
= check_output('ip -6 route show dev veth99')
3009 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3010 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3012 stop_dnsmasq(dnsmasq_pid_file
)
3013 start_dnsmasq(ipv6_range
='2600::30,2600::40', lease_time
='2m')
3015 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3016 print('Wait for the dynamic address to be renewed')
3019 self
.wait_online(['veth99:routable'])
3021 output
= check_output('ip -6 route show dev veth99')
3023 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3024 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3026 def test_dhcp_keep_configuration_dhcp(self
):
3027 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
3029 self
.wait_online(['veth-peer:carrier'])
3030 start_dnsmasq(lease_time
='2m')
3031 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3033 output
= check_output('ip address show dev veth99 scope global')
3035 self
.assertRegex(output
, r
'192.168.5.*')
3037 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3039 self
.assertRegex(output
, r
'192.168.5.*')
3041 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
3042 stop_dnsmasq(dnsmasq_pid_file
)
3044 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3045 print('Wait for the dynamic address to be expired')
3048 print('The lease address should be kept after lease expired')
3049 output
= check_output('ip address show dev veth99 scope global')
3051 self
.assertRegex(output
, r
'192.168.5.*')
3053 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3055 self
.assertRegex(output
, r
'192.168.5.*')
3057 check_output('systemctl stop systemd-networkd')
3059 print('The lease address should be kept after networkd stopped')
3060 output
= check_output('ip address show dev veth99 scope global')
3062 self
.assertRegex(output
, r
'192.168.5.*')
3064 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3066 self
.assertRegex(output
, r
'192.168.5.*')
3069 self
.wait_online(['veth-peer:routable'])
3071 print('Still the lease address should be kept after networkd restarted')
3072 output
= check_output('ip address show dev veth99 scope global')
3074 self
.assertRegex(output
, r
'192.168.5.*')
3076 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3078 self
.assertRegex(output
, r
'192.168.5.*')
3080 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
3081 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
3083 self
.wait_online(['veth-peer:carrier'])
3084 start_dnsmasq(lease_time
='2m')
3085 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3087 output
= check_output('ip address show dev veth99 scope global')
3089 self
.assertRegex(output
, r
'192.168.5.*')
3091 stop_dnsmasq(dnsmasq_pid_file
)
3092 check_output('systemctl stop systemd-networkd')
3094 output
= check_output('ip address show dev veth99 scope global')
3096 self
.assertRegex(output
, r
'192.168.5.*')
3099 self
.wait_online(['veth-peer:routable'])
3101 output
= check_output('ip address show dev veth99 scope global')
3103 self
.assertNotRegex(output
, r
'192.168.5.*')
3105 def test_dhcp_client_reuse_address_as_static(self
):
3106 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
3108 self
.wait_online(['veth-peer:carrier'])
3110 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3112 # link become 'routable' when at least one protocol provide an valid address.
3113 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3114 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3116 output
= check_output('ip address show dev veth99 scope global')
3118 self
.assertRegex(output
, '192.168.5')
3119 self
.assertRegex(output
, '2600::')
3121 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
3122 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
3123 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
3124 print(static_network
)
3126 remove_unit_from_networkd_path(['dhcp-client.network'])
3128 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
3129 f
.write(static_network
)
3131 # When networkd started, the links are already configured, so let's wait for 5 seconds
3132 # the links to be re-configured.
3134 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3136 output
= check_output('ip -4 address show dev veth99 scope global')
3138 self
.assertRegex(output
, '192.168.5')
3139 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3141 output
= check_output('ip -6 address show dev veth99 scope global')
3143 self
.assertRegex(output
, '2600::')
3144 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3146 @expectedFailureIfModuleIsNotAvailable('vrf')
3147 def test_dhcp_client_vrf(self
):
3148 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
3149 '25-vrf.netdev', '25-vrf.network')
3151 self
.wait_online(['veth-peer:carrier'])
3153 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
3155 # link become 'routable' when at least one protocol provide an valid address.
3156 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3157 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3159 print('## ip -d link show dev vrf99')
3160 output
= check_output('ip -d link show dev vrf99')
3162 self
.assertRegex(output
, 'vrf table 42')
3164 print('## ip address show vrf vrf99')
3165 output
= check_output('ip address show vrf vrf99')
3167 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3168 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3169 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3170 self
.assertRegex(output
, 'inet6 .* scope link')
3172 print('## ip address show dev veth99')
3173 output
= check_output('ip address show dev veth99')
3175 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3176 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3177 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3178 self
.assertRegex(output
, 'inet6 .* scope link')
3180 print('## ip route show vrf vrf99')
3181 output
= check_output('ip route show vrf vrf99')
3183 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
3184 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
3185 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
3186 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
3187 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
3189 print('## ip route show table main dev veth99')
3190 output
= check_output('ip route show table main dev veth99')
3192 self
.assertEqual(output
, '')
3194 def test_dhcp_client_gateway_ipv4(self
):
3195 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3196 'dhcp-client-gateway-ipv4.network')
3198 self
.wait_online(['veth-peer:carrier'])
3200 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3202 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3204 self
.assertRegex(output
, '10.0.0.0/8 via 192.168.5.1 proto static')
3206 def test_dhcp_client_gateway_ipv6(self
):
3207 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3208 'dhcp-client-gateway-ipv6.network')
3210 self
.wait_online(['veth-peer:carrier'])
3212 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3214 output
= check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
3216 self
.assertRegex(output
, 'via fe80::1034:56ff:fe78:9abd')
3218 def test_dhcp_client_gateway_onlink_implicit(self
):
3219 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3220 'dhcp-client-gateway-onlink-implicit.network')
3222 self
.wait_online(['veth-peer:carrier'])
3224 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3226 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3228 self
.assertRegex(output
, '192.168.5')
3230 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3232 self
.assertRegex(output
, 'onlink')
3233 output
= check_output('ip route list dev veth99 192.168.100.0/24')
3235 self
.assertRegex(output
, 'onlink')
3237 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
3238 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3239 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
3241 self
.wait_online(['veth-peer:carrier'])
3242 start_dnsmasq(lease_time
='2m')
3243 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3245 output
= check_output('ip address show dev veth99')
3248 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3249 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3250 output
= check_output('ip -6 address show dev veth99 scope link')
3251 self
.assertRegex(output
, 'inet6 .* scope link')
3252 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3253 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3254 output
= check_output('ip -4 address show dev veth99 scope link')
3255 self
.assertNotRegex(output
, 'inet .* scope link')
3257 print('Wait for the dynamic address to be expired')
3260 output
= check_output('ip address show dev veth99')
3263 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3264 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3265 output
= check_output('ip -6 address show dev veth99 scope link')
3266 self
.assertRegex(output
, 'inet6 .* scope link')
3267 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3268 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3269 output
= check_output('ip -4 address show dev veth99 scope link')
3270 self
.assertNotRegex(output
, 'inet .* scope link')
3272 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
3274 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
3275 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3276 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
3278 self
.wait_online(['veth99:degraded', 'veth-peer:routable'])
3280 output
= check_output('ip address show dev veth99')
3283 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3284 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3285 output
= check_output('ip -6 address show dev veth99 scope link')
3286 self
.assertRegex(output
, 'inet6 .* scope link')
3287 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3288 self
.assertNotRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3289 output
= check_output('ip -4 address show dev veth99 scope link')
3290 self
.assertRegex(output
, 'inet .* scope link')
3292 def test_dhcp_client_route_remove_on_renew(self
):
3293 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3294 'dhcp-client-ipv4-only-ipv6-disabled.network')
3296 self
.wait_online(['veth-peer:carrier'])
3297 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
3298 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3300 # test for issue #12490
3302 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3304 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3306 for line
in output
.splitlines():
3307 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3308 address1
= line
.split()[1].split('/')[0]
3311 output
= check_output('ip -4 route show dev veth99')
3313 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3314 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3316 stop_dnsmasq(dnsmasq_pid_file
)
3317 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
3319 print('Wait for the dynamic address to be expired')
3322 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3324 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3326 for line
in output
.splitlines():
3327 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3328 address2
= line
.split()[1].split('/')[0]
3331 self
.assertNotEqual(address1
, address2
)
3333 output
= check_output('ip -4 route show dev veth99')
3335 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3336 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3337 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
3338 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
3340 def test_dhcp_client_use_dns_yes(self
):
3341 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-yes.network')
3344 self
.wait_online(['veth-peer:carrier'])
3345 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3346 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3348 # link become 'routable' when at least one protocol provide an valid address.
3349 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3350 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3353 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3355 self
.assertRegex(output
, '192.168.5.1')
3356 self
.assertRegex(output
, '2600::1')
3358 def test_dhcp_client_use_dns_no(self
):
3359 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-no.network')
3362 self
.wait_online(['veth-peer:carrier'])
3363 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3364 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3366 # link become 'routable' when at least one protocol provide an valid address.
3367 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3368 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3371 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3373 self
.assertNotRegex(output
, '192.168.5.1')
3374 self
.assertNotRegex(output
, '2600::1')
3376 def test_dhcp_client_use_dns_ipv4(self
):
3377 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4.network')
3380 self
.wait_online(['veth-peer:carrier'])
3381 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3382 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3384 # link become 'routable' when at least one protocol provide an valid address.
3385 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3386 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3389 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3391 self
.assertRegex(output
, '192.168.5.1')
3392 self
.assertNotRegex(output
, '2600::1')
3394 def test_dhcp_client_use_dns_ipv4_and_ra(self
):
3395 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4-and-ra.network')
3398 self
.wait_online(['veth-peer:carrier'])
3399 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3400 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3402 # link become 'routable' when at least one protocol provide an valid address.
3403 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3404 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3407 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3409 self
.assertRegex(output
, '192.168.5.1')
3410 self
.assertRegex(output
, '2600::1')
3412 def test_dhcp_client_use_domains(self
):
3413 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-domains.network')
3416 self
.wait_online(['veth-peer:carrier'])
3417 start_dnsmasq('--dhcp-option=option:domain-search,example.com')
3418 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3420 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3422 self
.assertRegex(output
, 'Search Domains: example.com')
3425 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
3427 self
.assertRegex(output
, 'example.com')
3429 def test_dhcp_client_decline(self
):
3430 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-decline.network', 'dhcp-client-decline.network')
3433 self
.wait_online(['veth-peer:carrier'])
3434 rc
= call(*wait_online_cmd
, '--timeout=10s', '--interface=veth99:routable', env
=env
)
3435 self
.assertTrue(rc
== 1)
3437 class NetworkdIPv6PrefixTests(unittest
.TestCase
, Utilities
):
3442 'ipv6ra-prefix-client.network',
3443 'ipv6ra-prefix.network'
3447 remove_links(self
.links
)
3448 stop_networkd(show_logs
=False)
3452 remove_links(self
.links
)
3453 remove_unit_from_networkd_path(self
.units
)
3454 stop_networkd(show_logs
=True)
3456 def test_ipv6_route_prefix(self
):
3457 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client.network', 'ipv6ra-prefix.network')
3460 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3462 output
= check_output('ip', '-6', 'route', 'show', 'dev', 'veth-peer')
3464 self
.assertRegex(output
, '2001:db8:0:1::/64 proto ra')
3466 class NetworkdMTUTests(unittest
.TestCase
, Utilities
):
3471 '12-dummy-mtu.netdev',
3472 '12-dummy-mtu.link',
3477 remove_links(self
.links
)
3478 stop_networkd(show_logs
=False)
3482 remove_links(self
.links
)
3483 remove_unit_from_networkd_path(self
.units
)
3484 stop_networkd(show_logs
=True)
3486 def check_mtu(self
, mtu
, ipv6_mtu
=None, reset
=True):
3492 self
.wait_online(['dummy98:routable'])
3493 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
3494 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
3496 # test normal restart
3498 self
.wait_online(['dummy98:routable'])
3499 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
3500 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
3503 self
.reset_check_mtu(mtu
, ipv6_mtu
)
3505 def reset_check_mtu(self
, mtu
, ipv6_mtu
=None):
3506 ''' test setting mtu/ipv6_mtu with interface already up '''
3509 # note - changing the device mtu resets the ipv6 mtu
3510 run('ip link set up mtu 1501 dev dummy98')
3511 run('ip link set up mtu 1500 dev dummy98')
3512 self
.assertEqual(read_link_attr('dummy98', 'mtu'), '1500')
3513 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), '1500')
3515 self
.check_mtu(mtu
, ipv6_mtu
, reset
=False)
3517 def test_mtu_network(self
):
3518 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
3519 self
.check_mtu('1600')
3521 def test_mtu_netdev(self
):
3522 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network', dropins
=False)
3523 # note - MTU set by .netdev happens ONLY at device creation!
3524 self
.check_mtu('1600', reset
=False)
3526 def test_mtu_link(self
):
3527 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', dropins
=False)
3528 # must reload udev because it only picks up new files after 3 second delay
3529 call('udevadm control --reload')
3530 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
3531 self
.check_mtu('1600', reset
=False)
3533 def test_ipv6_mtu(self
):
3534 ''' set ipv6 mtu without setting device mtu '''
3535 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
3536 self
.check_mtu('1500', '1400')
3538 def test_ipv6_mtu_toolarge(self
):
3539 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
3540 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
3541 self
.check_mtu('1500', '1500')
3543 def test_mtu_network_ipv6_mtu(self
):
3544 ''' set ipv6 mtu and set device mtu via network file '''
3545 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
3546 self
.check_mtu('1600', '1550')
3548 def test_mtu_netdev_ipv6_mtu(self
):
3549 ''' set ipv6 mtu and set device mtu via netdev file '''
3550 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
3551 self
.check_mtu('1600', '1550', reset
=False)
3553 def test_mtu_link_ipv6_mtu(self
):
3554 ''' set ipv6 mtu and set device mtu via link file '''
3555 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
3556 # must reload udev because it only picks up new files after 3 second delay
3557 call('udevadm control --reload')
3558 self
.check_mtu('1600', '1550', reset
=False)
3561 if __name__
== '__main__':
3562 parser
= argparse
.ArgumentParser()
3563 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
3564 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
3565 parser
.add_argument('--resolved', help='Path to systemd-resolved', dest
='resolved_bin')
3566 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
3567 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
3568 parser
.add_argument('--resolvectl', help='Path to resolvectl', dest
='resolvectl_bin')
3569 parser
.add_argument('--timedatectl', help='Path to timedatectl', dest
='timedatectl_bin')
3570 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
3571 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
3572 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
3573 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
3574 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
3575 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
3578 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
:
3579 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
3580 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
3581 resolved_bin
= os
.path
.join(ns
.build_dir
, 'systemd-resolved')
3582 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
3583 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
3584 resolvectl_bin
= os
.path
.join(ns
.build_dir
, 'resolvectl')
3585 timedatectl_bin
= os
.path
.join(ns
.build_dir
, 'timedatectl')
3588 networkd_bin
= ns
.networkd_bin
3590 resolved_bin
= ns
.resolved_bin
3591 if ns
.wait_online_bin
:
3592 wait_online_bin
= ns
.wait_online_bin
3593 if ns
.networkctl_bin
:
3594 networkctl_bin
= ns
.networkctl_bin
3595 if ns
.resolvectl_bin
:
3596 resolvectl_bin
= ns
.resolvectl_bin
3597 if ns
.timedatectl_bin
:
3598 timedatectl_bin
= ns
.timedatectl_bin
3600 use_valgrind
= ns
.use_valgrind
3601 enable_debug
= ns
.enable_debug
3602 asan_options
= ns
.asan_options
3603 lsan_options
= ns
.lsan_options
3604 ubsan_options
= ns
.ubsan_options
3607 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
3608 resolvectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin
]
3609 timedatectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin
]
3610 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
3612 networkctl_cmd
= [networkctl_bin
]
3613 resolvectl_cmd
= [resolvectl_bin
]
3614 timedatectl_cmd
= [timedatectl_bin
]
3615 wait_online_cmd
= [wait_online_bin
]
3618 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
3620 env
.update({ 'ASAN_OPTIONS' : asan_options
})
3622 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
3624 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
3627 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,