2 # SPDX-License-Identifier: LGPL-2.1+
3 # systemd-networkd tests
15 from shutil
import copytree
17 network_unit_file_path
='/run/systemd/network'
18 networkd_runtime_directory
='/run/systemd/netif'
19 networkd_ci_path
='/run/networkd-ci'
20 network_sysctl_ipv6_path
='/proc/sys/net/ipv6/conf'
21 network_sysctl_ipv4_path
='/proc/sys/net/ipv4/conf'
23 dnsmasq_pid_file
='/run/networkd-ci/test-test-dnsmasq.pid'
24 dnsmasq_log_file
='/run/networkd-ci/test-dnsmasq-log-file'
26 systemd_lib_paths
=['/usr/lib/systemd', '/lib/systemd']
27 which_paths
=':'.join(systemd_lib_paths
+ os
.getenv('PATH', os
.defpath
).lstrip(':').split(':'))
29 networkd_bin
=shutil
.which('systemd-networkd', path
=which_paths
)
30 resolved_bin
=shutil
.which('systemd-resolved', path
=which_paths
)
31 udevd_bin
=shutil
.which('systemd-udevd', path
=which_paths
)
32 wait_online_bin
=shutil
.which('systemd-networkd-wait-online', path
=which_paths
)
33 networkctl_bin
=shutil
.which('networkctl', path
=which_paths
)
34 resolvectl_bin
=shutil
.which('resolvectl', path
=which_paths
)
35 timedatectl_bin
=shutil
.which('timedatectl', path
=which_paths
)
46 def check_output(*command
, **kwargs
):
47 # This replaces both check_output and check_call (output can be ignored)
48 command
= command
[0].split() + list(command
[1:])
49 return subprocess
.check_output(command
, universal_newlines
=True, **kwargs
).rstrip()
51 def call(*command
, **kwargs
):
52 command
= command
[0].split() + list(command
[1:])
53 return subprocess
.call(command
, universal_newlines
=True, **kwargs
)
55 def run(*command
, **kwargs
):
56 command
= command
[0].split() + list(command
[1:])
57 return subprocess
.run(command
, universal_newlines
=True, **kwargs
)
59 def is_module_available(module_name
):
60 lsmod_output
= check_output('lsmod')
61 module_re
= re
.compile(rf
'^{re.escape(module_name)}\b', re
.MULTILINE
)
62 return module_re
.search(lsmod_output
) or not call('modprobe', module_name
, stderr
=subprocess
.DEVNULL
)
64 def expectedFailureIfModuleIsNotAvailable(module_name
):
66 if not is_module_available(module_name
):
67 return unittest
.expectedFailure(func
)
72 def expectedFailureIfERSPANModuleIsNotAvailable():
74 rc
= call('ip link add dev erspan99 type erspan seq key 30 local 192.168.1.4 remote 192.168.1.1 erspan_ver 1 erspan 123', stderr
=subprocess
.DEVNULL
)
76 call('ip link del erspan99')
79 return unittest
.expectedFailure(func
)
83 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable():
85 rc
= call('ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7', stderr
=subprocess
.DEVNULL
)
87 call('ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
90 return unittest
.expectedFailure(func
)
94 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
96 rc
= call('ip rule add not from 192.168.100.19 ipproto tcp table 7', stderr
=subprocess
.DEVNULL
)
98 call('ip rule del not from 192.168.100.19 ipproto tcp table 7')
101 return unittest
.expectedFailure(func
)
105 def expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable():
108 rc
= call('ip rule add from 192.168.100.19 table 7 uidrange 200-300', stderr
=subprocess
.DEVNULL
)
110 ret
= run('ip rule list from 192.168.100.19 table 7', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
111 if ret
.returncode
== 0 and 'uidrange 200-300' in ret
.stdout
.rstrip():
113 call('ip rule del from 192.168.100.19 table 7 uidrange 200-300')
118 return unittest
.expectedFailure(func
)
122 def expectedFailureIfLinkFileFieldIsNotSet():
125 rc
= call('ip link add name dummy99 type dummy', stderr
=subprocess
.DEVNULL
)
127 ret
= run('udevadm info -w10s /sys/class/net/dummy99', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
128 if ret
.returncode
== 0 and 'E: ID_NET_LINK_FILE=' in ret
.stdout
.rstrip():
130 call('ip link del dummy99')
135 return unittest
.expectedFailure(func
)
139 def expectedFailureIfNexthopIsNotAvailable():
141 rc
= call('ip nexthop list', stderr
=subprocess
.DEVNULL
)
145 return unittest
.expectedFailure(func
)
149 def expectedFailureIfAlternativeNameIsNotAvailable():
151 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
152 rc
= call('ip link prop add dev dummy98 altname hogehogehogehogehoge', stderr
=subprocess
.DEVNULL
)
153 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
157 return unittest
.expectedFailure(func
)
161 def expectedFailureIfCAKEIsNotAvailable():
163 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
164 rc
= call('tc qdisc add dev dummy98 parent root cake', stderr
=subprocess
.DEVNULL
)
165 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
169 return unittest
.expectedFailure(func
)
173 def expectedFailureIfPIEIsNotAvailable():
175 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
176 rc
= call('tc qdisc add dev dummy98 parent root pie', stderr
=subprocess
.DEVNULL
)
177 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
181 return unittest
.expectedFailure(func
)
185 def expectedFailureIfHHFIsNotAvailable():
187 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
188 rc
= call('tc qdisc add dev dummy98 parent root hhf', stderr
=subprocess
.DEVNULL
)
189 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
193 return unittest
.expectedFailure(func
)
197 def expectedFailureIfETSIsNotAvailable():
199 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
200 rc
= call('tc qdisc add dev dummy98 parent root ets bands 10', stderr
=subprocess
.DEVNULL
)
201 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
205 return unittest
.expectedFailure(func
)
212 os
.makedirs(network_unit_file_path
, exist_ok
=True)
213 os
.makedirs(networkd_ci_path
, exist_ok
=True)
215 shutil
.rmtree(networkd_ci_path
)
216 copytree(os
.path
.join(os
.path
.dirname(os
.path
.abspath(__file__
)), 'conf'), networkd_ci_path
)
218 for u
in ['systemd-networkd.socket', 'systemd-networkd.service', 'systemd-resolved.service',
219 'systemd-udevd-kernel.socket', 'systemd-udevd-control.socket', 'systemd-udevd.service',
220 'firewalld.service']:
221 if call(f
'systemctl is-active --quiet {u}') == 0:
222 check_output(f
'systemctl stop {u}')
223 running_units
.append(u
)
227 'StartLimitIntervalSec=0',
234 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin
,
238 drop_in
+= ['ExecStart=!!' + networkd_bin
]
240 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
242 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
244 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
246 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
247 if asan_options
or lsan_options
or ubsan_options
:
248 drop_in
+= ['SystemCallFilter=']
249 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
250 drop_in
+= ['MemoryDenyWriteExecute=no']
252 os
.makedirs('/run/systemd/system/systemd-networkd.service.d', exist_ok
=True)
253 with
open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode
='w') as f
:
254 f
.write('\n'.join(drop_in
))
262 drop_in
+= ['ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + resolved_bin
]
264 drop_in
+= ['ExecStart=!!' + resolved_bin
]
266 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
268 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
270 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
272 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
273 if asan_options
or lsan_options
or ubsan_options
:
274 drop_in
+= ['SystemCallFilter=']
275 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
276 drop_in
+= ['MemoryDenyWriteExecute=no']
278 os
.makedirs('/run/systemd/system/systemd-resolved.service.d', exist_ok
=True)
279 with
open('/run/systemd/system/systemd-resolved.service.d/00-override.conf', mode
='w') as f
:
280 f
.write('\n'.join(drop_in
))
285 'ExecStart=!!' + udevd_bin
,
288 os
.makedirs('/run/systemd/system/systemd-udevd.service.d', exist_ok
=True)
289 with
open('/run/systemd/system/systemd-udevd.service.d/00-override.conf', mode
='w') as f
:
290 f
.write('\n'.join(drop_in
))
292 check_output('systemctl daemon-reload')
293 print(check_output('systemctl cat systemd-networkd.service'))
294 print(check_output('systemctl cat systemd-resolved.service'))
295 print(check_output('systemctl cat systemd-udevd.service'))
296 check_output('systemctl restart systemd-resolved')
297 check_output('systemctl restart systemd-udevd')
299 def tearDownModule():
302 shutil
.rmtree(networkd_ci_path
)
304 for u
in ['systemd-networkd.service', 'systemd-resolved.service']:
305 check_output(f
'systemctl stop {u}')
307 shutil
.rmtree('/run/systemd/system/systemd-networkd.service.d')
308 shutil
.rmtree('/run/systemd/system/systemd-resolved.service.d')
309 shutil
.rmtree('/run/systemd/system/systemd-udevd.service.d')
310 check_output('systemctl daemon-reload')
311 check_output('systemctl restart systemd-udevd.service')
313 for u
in running_units
:
314 check_output(f
'systemctl start {u}')
316 def read_link_attr(*args
):
317 with
open(os
.path
.join('/sys/class/net/', *args
)) as f
:
318 return f
.readline().strip()
320 def read_bridge_port_attr(bridge
, link
, attribute
):
321 path_bridge
= os
.path
.join('/sys/devices/virtual/net', bridge
)
322 path_port
= 'lower_' + link
+ '/brport'
323 path
= os
.path
.join(path_bridge
, path_port
)
325 with
open(os
.path
.join(path
, attribute
)) as f
:
326 return f
.readline().strip()
328 def link_exists(link
):
329 return os
.path
.exists(os
.path
.join('/sys/class/net', link
))
331 def remove_links(links
):
333 if link_exists(link
):
334 call('ip link del dev', link
)
337 def remove_fou_ports(ports
):
339 call('ip fou del port', port
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
341 def remove_routing_policy_rule_tables(tables
):
345 rc
= call('ip rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
347 def remove_routes(routes
):
348 for route_type
, addr
in routes
:
349 call('ip route del', route_type
, addr
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
351 def remove_l2tp_tunnels(tunnel_ids
):
352 output
= check_output('ip l2tp show tunnel')
353 for tid
in tunnel_ids
:
354 words
='Tunnel ' + tid
+ ', encap'
356 call('ip l2tp del tunnel tid', tid
)
359 def read_ipv6_sysctl_attr(link
, attribute
):
360 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, link
), attribute
)) as f
:
361 return f
.readline().strip()
363 def read_ipv4_sysctl_attr(link
, attribute
):
364 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv4_path
, link
), attribute
)) as f
:
365 return f
.readline().strip()
367 def copy_unit_to_networkd_unit_path(*units
, dropins
=True):
368 """Copy networkd unit files into the testbed.
370 Any networkd unit file type can be specified, as well as drop-in files.
372 By default, all drop-ins for a specified unit file are copied in;
373 to avoid that specify dropins=False.
375 When a drop-in file is specified, its unit file is also copied in automatically.
379 if dropins
and os
.path
.exists(os
.path
.join(networkd_ci_path
, unit
+ '.d')):
380 copytree(os
.path
.join(networkd_ci_path
, unit
+ '.d'), os
.path
.join(network_unit_file_path
, unit
+ '.d'))
381 if unit
.endswith('.conf'):
383 dropindir
= os
.path
.join(network_unit_file_path
, os
.path
.dirname(dropin
))
384 os
.makedirs(dropindir
, exist_ok
=True)
385 shutil
.copy(os
.path
.join(networkd_ci_path
, dropin
), dropindir
)
386 unit
= os
.path
.dirname(dropin
).rstrip('.d')
387 shutil
.copy(os
.path
.join(networkd_ci_path
, unit
), network_unit_file_path
)
389 def remove_unit_from_networkd_path(units
):
390 """Remove previously copied unit files from the testbed.
392 Drop-ins will be removed automatically.
395 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
))):
396 os
.remove(os
.path
.join(network_unit_file_path
, unit
))
397 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
+ '.d'))):
398 shutil
.rmtree(os
.path
.join(network_unit_file_path
, unit
+ '.d'))
400 def start_dnsmasq(additional_options
='', ipv4_range
='192.168.5.10,192.168.5.200', ipv6_range
='2600::10,2600::20', lease_time
='1h'):
401 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
402 check_output(dnsmasq_command
)
404 def stop_dnsmasq(pid_file
):
405 if os
.path
.exists(pid_file
):
406 with
open(pid_file
, 'r') as f
:
407 pid
= f
.read().rstrip(' \t\r\n\0')
408 os
.kill(int(pid
), signal
.SIGTERM
)
412 def search_words_in_dnsmasq_log(words
, show_all
=False):
413 if os
.path
.exists(dnsmasq_log_file
):
414 with
open (dnsmasq_log_file
) as in_file
:
415 contents
= in_file
.read()
418 for line
in contents
.splitlines():
421 print("%s, %s" % (words
, line
))
425 def remove_lease_file():
426 if os
.path
.exists(os
.path
.join(networkd_ci_path
, 'lease')):
427 os
.remove(os
.path
.join(networkd_ci_path
, 'lease'))
429 def remove_log_file():
430 if os
.path
.exists(dnsmasq_log_file
):
431 os
.remove(dnsmasq_log_file
)
433 def remove_networkd_state_files():
434 if os
.path
.exists(os
.path
.join(networkd_runtime_directory
, 'state')):
435 os
.remove(os
.path
.join(networkd_runtime_directory
, 'state'))
437 def stop_networkd(show_logs
=True, remove_state_files
=True):
439 invocation_id
= check_output('systemctl show systemd-networkd -p InvocationID --value')
440 check_output('systemctl stop systemd-networkd')
442 print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
))
443 if remove_state_files
:
444 remove_networkd_state_files()
446 def start_networkd(sleep_sec
=0):
447 check_output('systemctl start systemd-networkd')
449 time
.sleep(sleep_sec
)
451 def restart_networkd(sleep_sec
=0, show_logs
=True, remove_state_files
=True):
452 stop_networkd(show_logs
, remove_state_files
)
453 start_networkd(sleep_sec
)
457 def check_link_exists(self
, link
):
458 self
.assertTrue(link_exists(link
))
460 def check_link_attr(self
, *args
):
461 self
.assertEqual(read_link_attr(*args
[:-1]), args
[-1]);
463 def wait_operstate(self
, link
, operstate
='degraded', setup_state
='configured', setup_timeout
=5, fail_assert
=True):
464 """Wait for the link to reach the specified operstate and/or setup state.
466 Specify None or '' for either operstate or setup_state to ignore that state.
467 This will recheck until the state conditions are met or the timeout expires.
469 If the link successfully matches the requested state, this returns True.
470 If this times out waiting for the link to match, the behavior depends on the
471 'fail_assert' parameter; if True, this causes a test assertion failure,
472 otherwise this returns False. The default is to cause assertion failure.
474 Note that this function matches on *exactly* the given operstate and setup_state.
475 To wait for a link to reach *or exceed* a given operstate, use wait_online().
482 for secs
in range(setup_timeout
+ 1):
483 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
, env
=env
)
485 if re
.search(rf
'(?m)^\s*State:\s+{operstate}\s+\({setup_state}\)\s*$', output
):
487 # don't bother sleeping if time is up
488 if secs
< setup_timeout
:
491 self
.fail(f
'Timed out waiting for {link} to reach state {operstate}/{setup_state}')
494 def wait_online(self
, links_with_operstate
, timeout
='20s', bool_any
=False, setup_state
='configured', setup_timeout
=5):
495 """Wait for the link(s) to reach the specified operstate and/or setup state.
497 This is similar to wait_operstate() but can be used for multiple links,
498 and it also calls systemd-networkd-wait-online to wait for the given operstate.
499 The operstate should be specified in the link name, like 'eth0:degraded'.
500 If just a link name is provided, wait-online's default operstate to wait for is degraded.
502 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
503 'setup_timeout' controls the per-link timeout waiting for the setup_state.
505 Set 'bool_any' to True to wait for any (instead of all) of the given links.
506 If this is set, no setup_state checks are done.
508 Note that this function waits for the link(s) to reach *or exceed* the given operstate.
509 However, the setup_state, if specified, must be matched *exactly*.
511 This returns if the link(s) reached the requested operstate/setup_state; otherwise it
512 raises CalledProcessError or fails test assertion.
514 args
= wait_online_cmd
+ [f
'--timeout={timeout}'] + [f
'--interface={link}' for link
in links_with_operstate
]
518 check_output(*args
, env
=env
)
519 except subprocess
.CalledProcessError
:
520 for link
in links_with_operstate
:
521 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
.split(':')[0], env
=env
)
524 if not bool_any
and setup_state
:
525 for link
in links_with_operstate
:
526 self
.wait_operstate(link
.split(':')[0], None, setup_state
, setup_timeout
)
528 def wait_address(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
529 for i
in range(timeout_sec
):
532 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
533 if re
.search(address_regex
, output
):
536 self
.assertRegex(output
, address_regex
)
538 class NetworkctlTests(unittest
.TestCase
, Utilities
):
548 '11-dummy-mtu.netdev',
552 '25-address-static.network',
554 'netdev-link-local-addressing-yes.network',
558 remove_links(self
.links
)
559 stop_networkd(show_logs
=False)
562 remove_links(self
.links
)
563 remove_unit_from_networkd_path(self
.units
)
564 stop_networkd(show_logs
=True)
566 @expectedFailureIfAlternativeNameIsNotAvailable()
567 def test_altname(self
):
568 copy_unit_to_networkd_unit_path('netdev-link-local-addressing-yes.network', '12-dummy.netdev', '12-dummy.link')
569 check_output('udevadm control --reload')
571 self
.wait_online(['dummy98:degraded'])
573 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
574 self
.assertRegex(output
, 'hogehogehogehogehogehoge')
576 def test_reconfigure(self
):
577 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
579 self
.wait_online(['dummy98:routable'])
581 output
= check_output('ip -4 address show dev dummy98')
583 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
584 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
585 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
587 check_output('ip address del 10.1.2.3/16 dev dummy98')
588 check_output('ip address del 10.1.2.4/16 dev dummy98')
589 check_output('ip address del 10.2.2.4/16 dev dummy98')
591 check_output(*networkctl_cmd
, 'reconfigure', 'dummy98', env
=env
)
592 self
.wait_online(['dummy98:routable'])
594 output
= check_output('ip -4 address show dev dummy98')
596 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
597 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
598 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
600 def test_reload(self
):
603 copy_unit_to_networkd_unit_path('11-dummy.netdev')
604 check_output(*networkctl_cmd
, 'reload', env
=env
)
605 self
.wait_operstate('test1', 'off', setup_state
='unmanaged')
607 copy_unit_to_networkd_unit_path('11-dummy.network')
608 check_output(*networkctl_cmd
, 'reload', env
=env
)
609 self
.wait_online(['test1:degraded'])
611 remove_unit_from_networkd_path(['11-dummy.network'])
612 check_output(*networkctl_cmd
, 'reload', env
=env
)
613 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
615 remove_unit_from_networkd_path(['11-dummy.netdev'])
616 check_output(*networkctl_cmd
, 'reload', env
=env
)
617 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
619 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
620 check_output(*networkctl_cmd
, 'reload', env
=env
)
621 self
.wait_operstate('test1', 'degraded')
624 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
627 self
.wait_online(['test1:degraded'])
629 output
= check_output(*networkctl_cmd
, 'list', env
=env
)
630 self
.assertRegex(output
, '1 lo ')
631 self
.assertRegex(output
, 'test1')
633 output
= check_output(*networkctl_cmd
, 'list', 'test1', env
=env
)
634 self
.assertNotRegex(output
, '1 lo ')
635 self
.assertRegex(output
, 'test1')
637 output
= check_output(*networkctl_cmd
, 'list', 'te*', env
=env
)
638 self
.assertNotRegex(output
, '1 lo ')
639 self
.assertRegex(output
, 'test1')
641 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'te*', env
=env
)
642 self
.assertNotRegex(output
, '1: lo ')
643 self
.assertRegex(output
, 'test1')
645 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'tes[a-z][0-9]', env
=env
)
646 self
.assertNotRegex(output
, '1: lo ')
647 self
.assertRegex(output
, 'test1')
650 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
653 self
.wait_online(['test1:degraded'])
655 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
656 self
.assertRegex(output
, 'MTU: 1600')
659 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
661 self
.wait_online(['test1:degraded'])
663 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
665 self
.assertRegex(output
, 'Type: ether')
667 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
669 self
.assertRegex(output
, 'Type: loopback')
671 @expectedFailureIfLinkFileFieldIsNotSet()
672 def test_udev_link_file(self
):
673 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
675 self
.wait_online(['test1:degraded'])
677 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
679 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
680 self
.assertRegex(output
, r
'Network File: /run/systemd/network/11-dummy.network')
682 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
684 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
685 self
.assertRegex(output
, r
'Network File: n/a')
687 def test_delete_links(self
):
688 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
689 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
692 self
.wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
694 check_output(*networkctl_cmd
, 'delete', 'test1', 'veth99', env
=env
)
695 self
.assertFalse(link_exists('test1'))
696 self
.assertFalse(link_exists('veth99'))
697 self
.assertFalse(link_exists('veth-peer'))
699 class NetworkdNetDevTests(unittest
.TestCase
, Utilities
):
701 links_remove_earlier
= [
767 '10-dropin-test.netdev',
771 '13-not-match-udev-property.network',
772 '14-match-udev-property.network',
773 '15-name-conflict-test.netdev',
776 '21-vlan-test1.network',
779 '25-6rd-tunnel.netdev',
781 '25-bond-balanced-tlb.netdev',
783 '25-bridge-configure-without-carrier.network',
785 '25-erspan-tunnel-local-any.netdev',
786 '25-erspan-tunnel.netdev',
787 '25-fou-gretap.netdev',
789 '25-fou-ipip.netdev',
790 '25-fou-ipproto-gre.netdev',
791 '25-fou-ipproto-ipip.netdev',
794 '25-gretap-tunnel-local-any.netdev',
795 '25-gretap-tunnel.netdev',
796 '25-gre-tunnel-any-any.netdev',
797 '25-gre-tunnel-local-any.netdev',
798 '25-gre-tunnel-remote-any.netdev',
799 '25-gre-tunnel.netdev',
801 '25-ip6gretap-tunnel-local-any.netdev',
802 '25-ip6gretap-tunnel.netdev',
803 '25-ip6gre-tunnel-any-any.netdev',
804 '25-ip6gre-tunnel-local-any.netdev',
805 '25-ip6gre-tunnel-remote-any.netdev',
806 '25-ip6gre-tunnel.netdev',
807 '25-ip6tnl-tunnel-any-any.netdev',
808 '25-ip6tnl-tunnel-local-any.netdev',
809 '25-ip6tnl-tunnel-remote-any.netdev',
810 '25-ip6tnl-tunnel.netdev',
811 '25-ipip-tunnel-any-any.netdev',
812 '25-ipip-tunnel-independent.netdev',
813 '25-ipip-tunnel-independent-loopback.netdev',
814 '25-ipip-tunnel-local-any.netdev',
815 '25-ipip-tunnel-remote-any.netdev',
816 '25-ipip-tunnel.netdev',
819 '25-isatap-tunnel.netdev',
824 '25-sit-tunnel-any-any.netdev',
825 '25-sit-tunnel-local-any.netdev',
826 '25-sit-tunnel-remote-any.netdev',
827 '25-sit-tunnel.netdev',
830 '25-tunnel-local-any.network',
831 '25-tunnel-remote-any.network',
836 '25-vti6-tunnel-any-any.netdev',
837 '25-vti6-tunnel-local-any.netdev',
838 '25-vti6-tunnel-remote-any.netdev',
839 '25-vti6-tunnel.netdev',
840 '25-vti-tunnel-any-any.netdev',
841 '25-vti-tunnel-local-any.netdev',
842 '25-vti-tunnel-remote-any.netdev',
843 '25-vti-tunnel.netdev',
846 '25-wireguard-23-peers.netdev',
847 '25-wireguard-23-peers.network',
848 '25-wireguard-no-peer.netdev',
849 '25-wireguard-no-peer.network',
850 '25-wireguard-preshared-key.txt',
851 '25-wireguard-private-key.txt',
852 '25-wireguard.netdev',
853 '25-wireguard.network',
855 '25-xfrm-independent.netdev',
871 'netdev-link-local-addressing-yes.network',
875 'vxlan-test1.network',
885 remove_fou_ports(self
.fou_ports
)
886 remove_links(self
.links_remove_earlier
)
887 remove_links(self
.links
)
888 stop_networkd(show_logs
=False)
891 remove_fou_ports(self
.fou_ports
)
892 remove_links(self
.links_remove_earlier
)
893 remove_links(self
.links
)
894 remove_unit_from_networkd_path(self
.units
)
895 stop_networkd(show_logs
=True)
897 def test_dropin_and_name_conflict(self
):
898 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
901 self
.wait_online(['dropin-test:off'], setup_state
='unmanaged')
903 output
= check_output('ip link show dropin-test')
905 self
.assertRegex(output
, '00:50:56:c0:00:28')
907 def test_match_udev_property(self
):
908 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
910 self
.wait_online(['dummy98:routable'])
912 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
914 self
.assertRegex(output
, 'Network File: /run/systemd/network/14-match-udev-property')
916 def test_wait_online_any(self
):
917 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
920 self
.wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
922 self
.wait_operstate('bridge99', '(off|no-carrier)', setup_state
='configuring')
923 self
.wait_operstate('test1', 'degraded')
925 def test_bridge(self
):
926 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
929 self
.wait_online(['bridge99:no-carrier'])
931 tick
= os
.sysconf('SC_CLK_TCK')
932 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
933 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
934 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'forward_delay')) / tick
))
935 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'ageing_time')) / tick
))
936 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge', 'priority')))
937 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_querier')))
938 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_snooping')))
939 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'stp_state')))
940 self
.assertEqual(3, int(read_link_attr('bridge99', 'bridge', 'multicast_igmp_version')))
942 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
944 self
.assertRegex(output
, 'Priority: 9')
945 self
.assertRegex(output
, 'STP: yes')
946 self
.assertRegex(output
, 'Multicast IGMP Version: 3')
949 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
952 self
.wait_online(['bond99:off', 'bond98:off'], setup_state
='unmanaged')
954 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
955 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
956 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
957 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
958 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
959 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
960 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
961 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
962 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
963 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
964 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
966 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
967 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
970 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
971 '21-vlan.network', '21-vlan-test1.network')
974 self
.wait_online(['test1:degraded', 'vlan99:routable'])
976 output
= check_output('ip -d link show test1')
978 self
.assertRegex(output
, ' mtu 2000 ')
980 output
= check_output('ip -d link show vlan99')
982 self
.assertRegex(output
, ' mtu 2000 ')
983 self
.assertRegex(output
, 'REORDER_HDR')
984 self
.assertRegex(output
, 'LOOSE_BINDING')
985 self
.assertRegex(output
, 'GVRP')
986 self
.assertRegex(output
, 'MVRP')
987 self
.assertRegex(output
, ' id 99 ')
989 output
= check_output('ip -4 address show dev test1')
991 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
992 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
994 output
= check_output('ip -4 address show dev vlan99')
996 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
998 def test_macvtap(self
):
999 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
1000 with self
.subTest(mode
=mode
):
1001 if mode
!= 'private':
1003 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
1004 '11-dummy.netdev', 'macvtap.network')
1005 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
1006 f
.write('[MACVTAP]\nMode=' + mode
)
1009 self
.wait_online(['macvtap99:degraded', 'test1:degraded'])
1011 output
= check_output('ip -d link show macvtap99')
1013 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
1015 def test_macvlan(self
):
1016 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
1017 with self
.subTest(mode
=mode
):
1018 if mode
!= 'private':
1020 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
1021 '11-dummy.netdev', 'macvlan.network')
1022 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
1023 f
.write('[MACVLAN]\nMode=' + mode
)
1026 self
.wait_online(['macvlan99:degraded', 'test1:degraded'])
1028 output
= check_output('ip -d link show test1')
1030 self
.assertRegex(output
, ' mtu 2000 ')
1032 output
= check_output('ip -d link show macvlan99')
1034 self
.assertRegex(output
, ' mtu 2000 ')
1035 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
1037 @expectedFailureIfModuleIsNotAvailable('ipvlan')
1038 def test_ipvlan(self
):
1039 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1040 with self
.subTest(mode
=mode
, flag
=flag
):
1043 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
1044 '11-dummy.netdev', 'ipvlan.network')
1045 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
1046 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
1049 self
.wait_online(['ipvlan99:degraded', 'test1:degraded'])
1051 output
= check_output('ip -d link show ipvlan99')
1053 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
1055 @expectedFailureIfModuleIsNotAvailable('ipvtap')
1056 def test_ipvtap(self
):
1057 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1058 with self
.subTest(mode
=mode
, flag
=flag
):
1061 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
1062 '11-dummy.netdev', 'ipvtap.network')
1063 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
1064 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
1067 self
.wait_online(['ipvtap99:degraded', 'test1:degraded'])
1069 output
= check_output('ip -d link show ipvtap99')
1071 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
1073 def test_veth(self
):
1074 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
1077 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
1079 output
= check_output('ip -d link show veth99')
1081 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
1082 output
= check_output('ip -d link show veth-peer')
1084 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
1087 copy_unit_to_networkd_unit_path('25-tun.netdev')
1090 self
.wait_online(['tun99:off'], setup_state
='unmanaged')
1092 output
= check_output('ip -d link show tun99')
1094 # Old ip command does not support IFF_ flags
1095 self
.assertRegex(output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
1098 copy_unit_to_networkd_unit_path('25-tap.netdev')
1101 self
.wait_online(['tap99:off'], setup_state
='unmanaged')
1103 output
= check_output('ip -d link show tap99')
1105 # Old ip command does not support IFF_ flags
1106 self
.assertRegex(output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
1108 @expectedFailureIfModuleIsNotAvailable('vrf')
1110 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
1113 self
.wait_online(['vrf99:carrier'])
1115 @expectedFailureIfModuleIsNotAvailable('vcan')
1116 def test_vcan(self
):
1117 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
1120 self
.wait_online(['vcan99:carrier'])
1122 @expectedFailureIfModuleIsNotAvailable('vxcan')
1123 def test_vxcan(self
):
1124 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
1127 self
.wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
1129 @expectedFailureIfModuleIsNotAvailable('wireguard')
1130 def test_wireguard(self
):
1131 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
1132 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
1133 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt',
1134 '25-wireguard-no-peer.netdev', '25-wireguard-no-peer.network')
1136 self
.wait_online(['wg99:carrier', 'wg98:routable', 'wg97:carrier'])
1138 if shutil
.which('wg'):
1141 output
= check_output('wg show wg99 listen-port')
1142 self
.assertRegex(output
, '51820')
1143 output
= check_output('wg show wg99 fwmark')
1144 self
.assertRegex(output
, '0x4d2')
1145 output
= check_output('wg show wg99 allowed-ips')
1146 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
1147 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
1148 output
= check_output('wg show wg99 persistent-keepalive')
1149 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
1150 output
= check_output('wg show wg99 endpoints')
1151 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
1152 output
= check_output('wg show wg99 private-key')
1153 self
.assertRegex(output
, r
'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
1154 output
= check_output('wg show wg99 preshared-keys')
1155 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
1156 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
1158 output
= check_output('wg show wg98 private-key')
1159 self
.assertRegex(output
, r
'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
1161 output
= check_output('wg show wg97 listen-port')
1162 self
.assertRegex(output
, '51821')
1163 output
= check_output('wg show wg97 fwmark')
1164 self
.assertRegex(output
, '0x4d3')
1166 def test_geneve(self
):
1167 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
1170 self
.wait_online(['geneve99:degraded'])
1172 output
= check_output('ip -d link show geneve99')
1174 self
.assertRegex(output
, '192.168.22.1')
1175 self
.assertRegex(output
, '6082')
1176 self
.assertRegex(output
, 'udpcsum')
1177 self
.assertRegex(output
, 'udp6zerocsumrx')
1179 def test_ipip_tunnel(self
):
1180 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
1181 '25-ipip-tunnel.netdev', '25-tunnel.network',
1182 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1183 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1184 '25-ipip-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1186 self
.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'ipiptun96:routable', 'dummy98:degraded'])
1188 output
= check_output('ip -d link show ipiptun99')
1190 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98')
1191 output
= check_output('ip -d link show ipiptun98')
1193 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98')
1194 output
= check_output('ip -d link show ipiptun97')
1196 self
.assertRegex(output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98')
1197 output
= check_output('ip -d link show ipiptun96')
1199 self
.assertRegex(output
, 'ipip (ipip )?remote any local any dev dummy98')
1201 def test_gre_tunnel(self
):
1202 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
1203 '25-gre-tunnel.netdev', '25-tunnel.network',
1204 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1205 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1206 '25-gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1208 self
.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'gretun96:routable', 'dummy98:degraded'])
1210 output
= check_output('ip -d link show gretun99')
1212 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1213 self
.assertRegex(output
, 'ikey 1.2.3.103')
1214 self
.assertRegex(output
, 'okey 1.2.4.103')
1215 self
.assertRegex(output
, 'iseq')
1216 self
.assertRegex(output
, 'oseq')
1217 output
= check_output('ip -d link show gretun98')
1219 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
1220 self
.assertRegex(output
, 'ikey 0.0.0.104')
1221 self
.assertRegex(output
, 'okey 0.0.0.104')
1222 self
.assertNotRegex(output
, 'iseq')
1223 self
.assertNotRegex(output
, 'oseq')
1224 output
= check_output('ip -d link show gretun97')
1226 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
1227 self
.assertRegex(output
, 'ikey 0.0.0.105')
1228 self
.assertRegex(output
, 'okey 0.0.0.105')
1229 self
.assertNotRegex(output
, 'iseq')
1230 self
.assertNotRegex(output
, 'oseq')
1231 output
= check_output('ip -d link show gretun96')
1233 self
.assertRegex(output
, 'gre remote any local any dev dummy98')
1234 self
.assertRegex(output
, 'ikey 0.0.0.106')
1235 self
.assertRegex(output
, 'okey 0.0.0.106')
1236 self
.assertNotRegex(output
, 'iseq')
1237 self
.assertNotRegex(output
, 'oseq')
1239 def test_ip6gre_tunnel(self
):
1240 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
1241 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
1242 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1243 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1244 '25-ip6gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1247 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1249 self
.check_link_exists('dummy98')
1250 self
.check_link_exists('ip6gretun99')
1251 self
.check_link_exists('ip6gretun98')
1252 self
.check_link_exists('ip6gretun97')
1253 self
.check_link_exists('ip6gretun96')
1255 output
= check_output('ip -d link show ip6gretun99')
1257 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1258 output
= check_output('ip -d link show ip6gretun98')
1260 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
1261 output
= check_output('ip -d link show ip6gretun97')
1263 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
1264 output
= check_output('ip -d link show ip6gretun96')
1266 self
.assertRegex(output
, 'ip6gre remote any local any dev dummy98')
1268 def test_gretap_tunnel(self
):
1269 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
1270 '25-gretap-tunnel.netdev', '25-tunnel.network',
1271 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1273 self
.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
1275 output
= check_output('ip -d link show gretap99')
1277 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1278 self
.assertRegex(output
, 'ikey 0.0.0.106')
1279 self
.assertRegex(output
, 'okey 0.0.0.106')
1280 self
.assertRegex(output
, 'iseq')
1281 self
.assertRegex(output
, 'oseq')
1282 output
= check_output('ip -d link show gretap98')
1284 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
1285 self
.assertRegex(output
, 'ikey 0.0.0.107')
1286 self
.assertRegex(output
, 'okey 0.0.0.107')
1287 self
.assertRegex(output
, 'iseq')
1288 self
.assertRegex(output
, 'oseq')
1290 def test_ip6gretap_tunnel(self
):
1291 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
1292 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1293 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1295 self
.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
1297 output
= check_output('ip -d link show ip6gretap99')
1299 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1300 output
= check_output('ip -d link show ip6gretap98')
1302 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1304 def test_vti_tunnel(self
):
1305 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
1306 '25-vti-tunnel.netdev', '25-tunnel.network',
1307 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1308 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1309 '25-vti-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1311 self
.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'vtitun96:routable', 'dummy98:degraded'])
1313 output
= check_output('ip -d link show vtitun99')
1315 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1316 output
= check_output('ip -d link show vtitun98')
1318 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
1319 output
= check_output('ip -d link show vtitun97')
1321 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
1322 output
= check_output('ip -d link show vtitun96')
1324 self
.assertRegex(output
, 'vti remote any local any dev dummy98')
1326 def test_vti6_tunnel(self
):
1327 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
1328 '25-vti6-tunnel.netdev', '25-tunnel.network',
1329 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1330 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1332 self
.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
1334 output
= check_output('ip -d link show vti6tun99')
1336 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1337 output
= check_output('ip -d link show vti6tun98')
1339 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1340 output
= check_output('ip -d link show vti6tun97')
1342 self
.assertRegex(output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1344 def test_ip6tnl_tunnel(self
):
1345 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
1346 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1347 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1348 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1350 self
.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
1352 output
= check_output('ip -d link show ip6tnl99')
1354 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1355 output
= check_output('ip -d link show ip6tnl98')
1357 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1358 output
= check_output('ip -d link show ip6tnl97')
1360 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1362 def test_sit_tunnel(self
):
1363 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1364 '25-sit-tunnel.netdev', '25-tunnel.network',
1365 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1366 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1367 '25-sit-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1369 self
.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'sittun96:routable', 'dummy98:degraded'])
1371 output
= check_output('ip -d link show sittun99')
1373 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1374 output
= check_output('ip -d link show sittun98')
1376 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98")
1377 output
= check_output('ip -d link show sittun97')
1379 self
.assertRegex(output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98")
1380 output
= check_output('ip -d link show sittun96')
1382 self
.assertRegex(output
, "sit (ip6ip )?remote any local any dev dummy98")
1384 def test_isatap_tunnel(self
):
1385 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1386 '25-isatap-tunnel.netdev', '25-tunnel.network')
1388 self
.wait_online(['isataptun99:routable', 'dummy98:degraded'])
1390 output
= check_output('ip -d link show isataptun99')
1392 self
.assertRegex(output
, "isatap ")
1394 def test_6rd_tunnel(self
):
1395 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1396 '25-6rd-tunnel.netdev', '25-tunnel.network')
1398 self
.wait_online(['sittun99:routable', 'dummy98:degraded'])
1400 output
= check_output('ip -d link show sittun99')
1402 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1404 @expectedFailureIfERSPANModuleIsNotAvailable()
1405 def test_erspan_tunnel(self
):
1406 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1407 '25-erspan-tunnel.netdev', '25-tunnel.network',
1408 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1410 self
.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1412 output
= check_output('ip -d link show erspan99')
1414 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1415 self
.assertRegex(output
, 'ikey 0.0.0.101')
1416 self
.assertRegex(output
, 'okey 0.0.0.101')
1417 self
.assertRegex(output
, 'iseq')
1418 self
.assertRegex(output
, 'oseq')
1419 output
= check_output('ip -d link show erspan98')
1421 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1422 self
.assertRegex(output
, '102')
1423 self
.assertRegex(output
, 'ikey 0.0.0.102')
1424 self
.assertRegex(output
, 'okey 0.0.0.102')
1425 self
.assertRegex(output
, 'iseq')
1426 self
.assertRegex(output
, 'oseq')
1428 def test_tunnel_independent(self
):
1429 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1432 self
.wait_online(['ipiptun99:carrier'])
1434 def test_tunnel_independent_loopback(self
):
1435 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent-loopback.netdev', 'netdev-link-local-addressing-yes.network')
1438 self
.wait_online(['ipiptun99:carrier'])
1440 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1441 def test_xfrm(self
):
1442 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'xfrm.network',
1443 '25-xfrm.netdev', 'netdev-link-local-addressing-yes.network')
1446 self
.wait_online(['xfrm99:degraded', 'dummy98:degraded'])
1448 output
= check_output('ip link show dev xfrm99')
1451 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1452 def test_xfrm_independent(self
):
1453 copy_unit_to_networkd_unit_path('25-xfrm-independent.netdev', 'netdev-link-local-addressing-yes.network')
1456 self
.wait_online(['xfrm99:degraded'])
1458 @expectedFailureIfModuleIsNotAvailable('fou')
1460 # The following redundant check is necessary for CentOS CI.
1461 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1462 self
.assertTrue(is_module_available('fou'))
1464 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1465 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1466 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1469 self
.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'], setup_state
='unmanaged')
1471 output
= check_output('ip fou show')
1473 self
.assertRegex(output
, 'port 55555 ipproto 4')
1474 self
.assertRegex(output
, 'port 55556 ipproto 47')
1476 output
= check_output('ip -d link show ipiptun96')
1478 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1479 output
= check_output('ip -d link show sittun96')
1481 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1482 output
= check_output('ip -d link show gretun96')
1484 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1485 output
= check_output('ip -d link show gretap96')
1487 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1489 def test_vxlan(self
):
1490 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1491 '11-dummy.netdev', 'vxlan-test1.network')
1494 self
.wait_online(['test1:degraded', 'vxlan99:degraded'])
1496 output
= check_output('ip -d link show vxlan99')
1498 self
.assertRegex(output
, '999')
1499 self
.assertRegex(output
, '5555')
1500 self
.assertRegex(output
, 'l2miss')
1501 self
.assertRegex(output
, 'l3miss')
1502 self
.assertRegex(output
, 'udpcsum')
1503 self
.assertRegex(output
, 'udp6zerocsumtx')
1504 self
.assertRegex(output
, 'udp6zerocsumrx')
1505 self
.assertRegex(output
, 'remcsumtx')
1506 self
.assertRegex(output
, 'remcsumrx')
1507 self
.assertRegex(output
, 'gbp')
1509 output
= check_output('bridge fdb show dev vxlan99')
1511 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1512 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1513 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1515 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'vxlan99', env
=env
)
1517 self
.assertRegex(output
, 'VNI: 999')
1518 self
.assertRegex(output
, 'Destination Port: 5555')
1519 self
.assertRegex(output
, 'Underlying Device: test1')
1521 def test_macsec(self
):
1522 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1523 'macsec.network', '12-dummy.netdev')
1526 self
.wait_online(['dummy98:degraded', 'macsec99:routable'])
1528 output
= check_output('ip -d link show macsec99')
1530 self
.assertRegex(output
, 'macsec99@dummy98')
1531 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1532 self
.assertRegex(output
, 'encrypt on')
1534 output
= check_output('ip macsec show macsec99')
1536 self
.assertRegex(output
, 'encrypt on')
1537 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1538 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1539 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1540 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1541 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1542 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1543 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1544 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1545 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1546 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1547 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1549 def test_nlmon(self
):
1550 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1553 self
.wait_online(['nlmon99:carrier'])
1555 @expectedFailureIfModuleIsNotAvailable('ifb')
1557 copy_unit_to_networkd_unit_path('25-ifb.netdev', 'netdev-link-local-addressing-yes.network')
1560 self
.wait_online(['ifb99:degraded'])
1562 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1573 '25-l2tp-dummy.network',
1575 '25-l2tp-ip.netdev',
1576 '25-l2tp-udp.netdev']
1578 l2tp_tunnel_ids
= [ '10' ]
1581 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1582 remove_links(self
.links
)
1583 stop_networkd(show_logs
=False)
1586 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1587 remove_links(self
.links
)
1588 remove_unit_from_networkd_path(self
.units
)
1589 stop_networkd(show_logs
=True)
1591 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1592 def test_l2tp_udp(self
):
1593 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1594 '25-l2tp-udp.netdev', '25-l2tp.network')
1597 self
.wait_online(['test1:routable', 'l2tp-ses1:degraded', 'l2tp-ses2:degraded'])
1599 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1601 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1602 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1603 self
.assertRegex(output
, "Peer tunnel 11")
1604 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1605 self
.assertRegex(output
, "UDP checksum: enabled")
1607 output
= check_output('ip l2tp show session tid 10 session_id 15')
1609 self
.assertRegex(output
, "Session 15 in tunnel 10")
1610 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1611 self
.assertRegex(output
, "interface name: l2tp-ses1")
1613 output
= check_output('ip l2tp show session tid 10 session_id 17')
1615 self
.assertRegex(output
, "Session 17 in tunnel 10")
1616 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1617 self
.assertRegex(output
, "interface name: l2tp-ses2")
1619 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1620 def test_l2tp_ip(self
):
1621 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1622 '25-l2tp-ip.netdev', '25-l2tp.network')
1625 self
.wait_online(['test1:routable', 'l2tp-ses3:degraded', 'l2tp-ses4:degraded'])
1627 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1629 self
.assertRegex(output
, "Tunnel 10, encap IP")
1630 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1631 self
.assertRegex(output
, "Peer tunnel 12")
1633 output
= check_output('ip l2tp show session tid 10 session_id 25')
1635 self
.assertRegex(output
, "Session 25 in tunnel 10")
1636 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1637 self
.assertRegex(output
, "interface name: l2tp-ses3")
1639 output
= check_output('ip l2tp show session tid 10 session_id 27')
1641 self
.assertRegex(output
, "Session 27 in tunnel 10")
1642 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1643 self
.assertRegex(output
, "interface name: l2tp-ses4")
1645 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1660 '23-active-slave.network',
1661 '24-keep-configuration-static.network',
1662 '24-search-domain.network',
1663 '25-address-dad-veth-peer.network',
1664 '25-address-dad-veth99.network',
1665 '25-address-link-section.network',
1666 '25-address-preferred-lifetime-zero.network',
1667 '25-address-static.network',
1668 '25-bind-carrier.network',
1669 '25-bond-active-backup-slave.netdev',
1670 '25-fibrule-invert.network',
1671 '25-fibrule-port-range.network',
1672 '25-fibrule-uidrange.network',
1673 '25-gre-tunnel-remote-any.netdev',
1674 '25-ip6gre-tunnel-remote-any.netdev',
1675 '25-ipv6-address-label-section.network',
1676 '25-link-local-addressing-no.network',
1677 '25-link-local-addressing-yes.network',
1678 '25-link-section-unmanaged.network',
1679 '25-neighbor-section.network',
1680 '25-neighbor-next.network',
1681 '25-neighbor-ipv6.network',
1682 '25-neighbor-ip-dummy.network',
1683 '25-neighbor-ip.network',
1684 '25-nexthop.network',
1685 '25-qdisc-cake.network',
1686 '25-qdisc-clsact-and-htb.network',
1687 '25-qdisc-drr.network',
1688 '25-qdisc-ets.network',
1689 '25-qdisc-hhf.network',
1690 '25-qdisc-ingress-netem-compat.network',
1691 '25-qdisc-pie.network',
1692 '25-qdisc-qfq.network',
1693 '25-route-ipv6-src.network',
1694 '25-route-static.network',
1695 '25-route-vrf.network',
1696 '25-gateway-static.network',
1697 '25-gateway-next-static.network',
1698 '25-sysctl-disable-ipv6.network',
1699 '25-sysctl.network',
1701 '25-veth-peer.network',
1704 '26-link-local-addressing-ipv6.network',
1705 'routing-policy-rule-dummy98.network',
1706 'routing-policy-rule-test1.network']
1708 routing_policy_rule_tables
= ['7', '8', '9']
1709 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1712 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1713 remove_routes(self
.routes
)
1714 remove_links(self
.links
)
1715 stop_networkd(show_logs
=False)
1718 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1719 remove_routes(self
.routes
)
1720 remove_links(self
.links
)
1721 remove_unit_from_networkd_path(self
.units
)
1722 stop_networkd(show_logs
=True)
1724 def test_address_static(self
):
1725 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1728 self
.wait_online(['dummy98:routable'])
1730 output
= check_output('ip -4 address show dev dummy98')
1732 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1733 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1734 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1737 self
.assertNotRegex(output
, '10.10.0.1/16')
1738 self
.assertNotRegex(output
, '10.10.0.2/16')
1740 output
= check_output('ip -4 address show dev dummy98 label 32')
1741 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1743 output
= check_output('ip -4 address show dev dummy98 label 33')
1744 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1746 output
= check_output('ip -4 address show dev dummy98 label 34')
1747 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1749 output
= check_output('ip -4 address show dev dummy98 label 35')
1750 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1752 output
= check_output('ip -6 address show dev dummy98')
1754 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1755 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1756 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1757 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1758 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1759 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1761 def test_address_preferred_lifetime_zero_ipv6(self
):
1762 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero.network', '12-dummy.netdev')
1765 self
.wait_online(['dummy98:routable'])
1767 output
= check_output('ip address show dummy98')
1769 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1770 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1772 output
= check_output('ip route show dev dummy98')
1774 self
.assertRegex(output
, 'default via 20.20.20.1 proto static')
1776 def test_address_dad(self
):
1777 copy_unit_to_networkd_unit_path('25-address-dad-veth99.network', '25-address-dad-veth-peer.network',
1780 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
1782 output
= check_output('ip -4 address show dev veth99')
1784 self
.assertRegex(output
, '192.168.100.10/24')
1786 output
= check_output('ip -4 address show dev veth-peer')
1788 self
.assertNotRegex(output
, '192.168.100.10/24')
1790 def test_configure_without_carrier(self
):
1791 copy_unit_to_networkd_unit_path('11-dummy.netdev')
1793 self
.wait_operstate('test1', 'off', '')
1794 check_output('ip link set dev test1 up carrier off')
1796 copy_unit_to_networkd_unit_path('25-test1.network.d/configure-without-carrier.conf', dropins
=False)
1798 self
.wait_online(['test1:no-carrier'])
1800 carrier_map
= {'on': '1', 'off': '0'}
1801 routable_map
= {'on': 'routable', 'off': 'no-carrier'}
1802 for carrier
in ['off', 'on', 'off']:
1803 with self
.subTest(carrier
=carrier
):
1804 if carrier_map
[carrier
] != read_link_attr('test1', 'carrier'):
1805 check_output(f
'ip link set dev test1 carrier {carrier}')
1806 self
.wait_online([f
'test1:{routable_map[carrier]}'])
1808 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
1810 self
.assertRegex(output
, '192.168.0.15')
1811 self
.assertRegex(output
, '192.168.0.1')
1812 self
.assertRegex(output
, routable_map
[carrier
])
1814 def test_configure_without_carrier_yes_ignore_carrier_loss_no(self
):
1815 copy_unit_to_networkd_unit_path('11-dummy.netdev')
1817 self
.wait_operstate('test1', 'off', '')
1818 check_output('ip link set dev test1 up carrier off')
1820 copy_unit_to_networkd_unit_path('25-test1.network')
1822 self
.wait_online(['test1:no-carrier'])
1824 carrier_map
= {'on': '1', 'off': '0'}
1825 routable_map
= {'on': 'routable', 'off': 'no-carrier'}
1826 for (carrier
, have_config
) in [('off', True), ('on', True), ('off', False)]:
1827 with self
.subTest(carrier
=carrier
, have_config
=have_config
):
1828 if carrier_map
[carrier
] != read_link_attr('test1', 'carrier'):
1829 check_output(f
'ip link set dev test1 carrier {carrier}')
1830 self
.wait_online([f
'test1:{routable_map[carrier]}'])
1832 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
1835 self
.assertRegex(output
, '192.168.0.15')
1836 self
.assertRegex(output
, '192.168.0.1')
1838 self
.assertNotRegex(output
, '192.168.0.15')
1839 self
.assertNotRegex(output
, '192.168.0.1')
1840 self
.assertRegex(output
, routable_map
[carrier
])
1842 def test_routing_policy_rule(self
):
1843 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1845 self
.wait_online(['test1:degraded'])
1847 output
= check_output('ip rule list iif test1 priority 111')
1849 self
.assertRegex(output
, '111:')
1850 self
.assertRegex(output
, 'from 192.168.100.18')
1851 self
.assertRegex(output
, r
'tos (0x08|throughput)\s')
1852 self
.assertRegex(output
, 'iif test1')
1853 self
.assertRegex(output
, 'oif test1')
1854 self
.assertRegex(output
, 'lookup 7')
1856 output
= check_output('ip rule list iif test1 priority 101')
1858 self
.assertRegex(output
, '101:')
1859 self
.assertRegex(output
, 'from all')
1860 self
.assertRegex(output
, 'iif test1')
1861 self
.assertRegex(output
, 'lookup 9')
1863 output
= check_output('ip -6 rule list iif test1 priority 100')
1865 self
.assertRegex(output
, '100:')
1866 self
.assertRegex(output
, 'from all')
1867 self
.assertRegex(output
, 'iif test1')
1868 self
.assertRegex(output
, 'lookup 8')
1870 output
= check_output('ip -6 rule list iif test1 priority 101')
1872 self
.assertRegex(output
, '101:')
1873 self
.assertRegex(output
, 'from all')
1874 self
.assertRegex(output
, 'iif test1')
1875 self
.assertRegex(output
, 'lookup 9')
1877 def test_routing_policy_rule_issue_11280(self
):
1878 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1879 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1881 for trial
in range(3):
1882 # Remove state files only first time
1884 self
.wait_online(['test1:degraded', 'dummy98:degraded'])
1887 output
= check_output('ip rule list table 7')
1889 self
.assertRegex(output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
1891 output
= check_output('ip rule list table 8')
1893 self
.assertRegex(output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1895 stop_networkd(remove_state_files
=False)
1897 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1898 def test_routing_policy_rule_port_range(self
):
1899 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1901 self
.wait_online(['test1:degraded'])
1903 output
= check_output('ip rule')
1905 self
.assertRegex(output
, '111')
1906 self
.assertRegex(output
, 'from 192.168.100.18')
1907 self
.assertRegex(output
, '1123-1150')
1908 self
.assertRegex(output
, '3224-3290')
1909 self
.assertRegex(output
, 'tcp')
1910 self
.assertRegex(output
, 'lookup 7')
1912 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1913 def test_routing_policy_rule_invert(self
):
1914 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1916 self
.wait_online(['test1:degraded'])
1918 output
= check_output('ip rule')
1920 self
.assertRegex(output
, '111')
1921 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
1922 self
.assertRegex(output
, 'tcp')
1923 self
.assertRegex(output
, 'lookup 7')
1925 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable()
1926 def test_routing_policy_rule_uidrange(self
):
1927 copy_unit_to_networkd_unit_path('25-fibrule-uidrange.network', '11-dummy.netdev')
1929 self
.wait_online(['test1:degraded'])
1931 output
= check_output('ip rule')
1933 self
.assertRegex(output
, '111')
1934 self
.assertRegex(output
, 'from 192.168.100.18')
1935 self
.assertRegex(output
, 'lookup 7')
1936 self
.assertRegex(output
, 'uidrange 100-200')
1938 def test_route_static(self
):
1939 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1941 self
.wait_online(['dummy98:routable'])
1943 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
1946 print('### ip -6 route show dev dummy98')
1947 output
= check_output('ip -6 route show dev dummy98')
1949 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1950 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
1952 print('### ip -6 route show dev dummy98 default')
1953 output
= check_output('ip -6 route show dev dummy98 default')
1955 self
.assertRegex(output
, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1957 print('### ip -4 route show dev dummy98')
1958 output
= check_output('ip -4 route show dev dummy98')
1960 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1961 self
.assertRegex(output
, '149.10.124.64 proto static scope link')
1962 self
.assertRegex(output
, '169.254.0.0/16 proto static scope link metric 2048')
1963 self
.assertRegex(output
, '192.168.1.1 proto static initcwnd 20')
1964 self
.assertRegex(output
, '192.168.1.2 proto static initrwnd 30')
1965 self
.assertRegex(output
, 'multicast 149.10.123.4 proto static')
1967 print('### ip -4 route show dev dummy98 default')
1968 output
= check_output('ip -4 route show dev dummy98 default')
1970 self
.assertRegex(output
, 'default via 149.10.125.65 proto static onlink')
1971 self
.assertRegex(output
, 'default via 149.10.124.64 proto static')
1972 self
.assertRegex(output
, 'default proto static')
1974 print('### ip -4 route show table local dev dummy98')
1975 output
= check_output('ip -4 route show table local dev dummy98')
1977 self
.assertRegex(output
, 'local 149.10.123.1 proto static scope host')
1978 self
.assertRegex(output
, 'anycast 149.10.123.2 proto static scope link')
1979 self
.assertRegex(output
, 'broadcast 149.10.123.3 proto static scope link')
1981 print('### ip route show type blackhole')
1982 output
= check_output('ip route show type blackhole')
1984 self
.assertRegex(output
, 'blackhole 202.54.1.2 proto static')
1986 print('### ip route show type unreachable')
1987 output
= check_output('ip route show type unreachable')
1989 self
.assertRegex(output
, 'unreachable 202.54.1.3 proto static')
1991 print('### ip route show type prohibit')
1992 output
= check_output('ip route show type prohibit')
1994 self
.assertRegex(output
, 'prohibit 202.54.1.4 proto static')
1996 print('### ip route show 192.168.10.1')
1997 output
= check_output('ip route show 192.168.10.1')
1999 self
.assertRegex(output
, '192.168.10.1 proto static')
2000 self
.assertRegex(output
, 'nexthop via 149.10.124.59 dev dummy98 weight 10')
2001 self
.assertRegex(output
, 'nexthop via 149.10.124.60 dev dummy98 weight 5')
2003 print('### ip route show 192.168.10.2')
2004 output
= check_output('ip route show 192.168.10.2')
2006 # old ip command does not show IPv6 gateways...
2007 self
.assertRegex(output
, '192.168.10.2 proto static')
2008 self
.assertRegex(output
, 'nexthop')
2009 self
.assertRegex(output
, 'dev dummy98 weight 10')
2010 self
.assertRegex(output
, 'dev dummy98 weight 5')
2012 print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2013 output
= check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2015 # old ip command does not show 'nexthop' keyword and weight...
2016 self
.assertRegex(output
, '2001:1234:5:7fff:ff:ff:ff:ff')
2017 self
.assertRegex(output
, 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98')
2018 self
.assertRegex(output
, 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98')
2020 @expectedFailureIfModuleIsNotAvailable('vrf')
2021 def test_route_vrf(self
):
2022 copy_unit_to_networkd_unit_path('25-route-vrf.network', '12-dummy.netdev',
2023 '25-vrf.netdev', '25-vrf.network')
2025 self
.wait_online(['dummy98:routable', 'vrf99:carrier'])
2027 output
= check_output('ip route show vrf vrf99')
2029 self
.assertRegex(output
, 'default via 192.168.100.1')
2031 output
= check_output('ip route show')
2033 self
.assertNotRegex(output
, 'default via 192.168.100.1')
2035 def test_gateway_reconfigure(self
):
2036 copy_unit_to_networkd_unit_path('25-gateway-static.network', '12-dummy.netdev')
2038 self
.wait_online(['dummy98:routable'])
2039 print('### ip -4 route show dev dummy98 default')
2040 output
= check_output('ip -4 route show dev dummy98 default')
2042 self
.assertRegex(output
, 'default via 149.10.124.59 proto static')
2043 self
.assertNotRegex(output
, '149.10.124.60')
2045 remove_unit_from_networkd_path(['25-gateway-static.network'])
2046 copy_unit_to_networkd_unit_path('25-gateway-next-static.network')
2048 self
.wait_online(['dummy98:routable'])
2049 print('### ip -4 route show dev dummy98 default')
2050 output
= check_output('ip -4 route show dev dummy98 default')
2052 self
.assertNotRegex(output
, '149.10.124.59')
2053 self
.assertRegex(output
, 'default via 149.10.124.60 proto static')
2055 def test_ip_route_ipv6_src_route(self
):
2056 # a dummy device does not make the addresses go through tentative state, so we
2057 # reuse a bond from an earlier test, which does make the addresses go through
2058 # tentative state, and do our test on that
2059 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2061 self
.wait_online(['dummy98:enslaved', 'bond199:routable'])
2063 output
= check_output('ip -6 route list dev bond199')
2065 self
.assertRegex(output
, 'abcd::/16')
2066 self
.assertRegex(output
, 'src')
2067 self
.assertRegex(output
, '2001:1234:56:8f63::2')
2069 def test_ip_link_mac_address(self
):
2070 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
2072 self
.wait_online(['dummy98:degraded'])
2074 output
= check_output('ip link show dummy98')
2076 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
2078 def test_ip_link_unmanaged(self
):
2079 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
2082 self
.check_link_exists('dummy98')
2084 self
.wait_operstate('dummy98', 'off', setup_state
='unmanaged')
2086 def test_ipv6_address_label(self
):
2087 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
2089 self
.wait_online(['dummy98:degraded'])
2091 output
= check_output('ip addrlabel list')
2093 self
.assertRegex(output
, '2004:da8:1::/64')
2095 def test_neighbor_section(self
):
2096 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2098 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2100 print('### ip neigh list dev dummy98')
2101 output
= check_output('ip neigh list dev dummy98')
2103 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2104 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2106 def test_neighbor_reconfigure(self
):
2107 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2109 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2111 print('### ip neigh list dev dummy98')
2112 output
= check_output('ip neigh list dev dummy98')
2114 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2115 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2117 remove_unit_from_networkd_path(['25-neighbor-section.network'])
2118 copy_unit_to_networkd_unit_path('25-neighbor-next.network')
2120 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2121 print('### ip neigh list dev dummy98')
2122 output
= check_output('ip neigh list dev dummy98')
2124 self
.assertNotRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2125 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT')
2126 self
.assertNotRegex(output
, '2004:da8:1::1.*PERMANENT')
2128 def test_neighbor_gre(self
):
2129 copy_unit_to_networkd_unit_path('25-neighbor-ip.network', '25-neighbor-ipv6.network', '25-neighbor-ip-dummy.network',
2130 '12-dummy.netdev', '25-gre-tunnel-remote-any.netdev', '25-ip6gre-tunnel-remote-any.netdev')
2132 self
.wait_online(['dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable'], timeout
='40s')
2134 output
= check_output('ip neigh list dev gretun97')
2136 self
.assertRegex(output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT')
2138 output
= check_output('ip neigh list dev ip6gretun97')
2140 self
.assertRegex(output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
2142 def test_link_local_addressing(self
):
2143 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
2144 '25-link-local-addressing-no.network', '12-dummy.netdev')
2146 self
.wait_online(['test1:degraded', 'dummy98:carrier'])
2148 output
= check_output('ip address show dev test1')
2150 self
.assertRegex(output
, 'inet .* scope link')
2151 self
.assertRegex(output
, 'inet6 .* scope link')
2153 output
= check_output('ip address show dev dummy98')
2155 self
.assertNotRegex(output
, 'inet6* .* scope link')
2158 Documentation/networking/ip-sysctl.txt
2160 addr_gen_mode - INTEGER
2161 Defines how link-local and autoconf addresses are generated.
2163 0: generate address based on EUI64 (default)
2164 1: do no generate a link-local address, use EUI64 for addresses generated
2166 2: generate stable privacy addresses, using the secret from
2167 stable_secret (RFC7217)
2168 3: generate stable privacy addresses, using a random secret if unset
2171 test1_addr_gen_mode
= ''
2172 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
2173 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
2177 # if stable_secret is unset, then EIO is returned
2178 test1_addr_gen_mode
= '0'
2180 test1_addr_gen_mode
= '2'
2182 test1_addr_gen_mode
= '0'
2184 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
2185 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
2187 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
2188 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
2190 def test_link_local_addressing_remove_ipv6ll(self
):
2191 copy_unit_to_networkd_unit_path('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
2193 self
.wait_online(['dummy98:degraded'])
2195 output
= check_output('ip address show dev dummy98')
2197 self
.assertRegex(output
, 'inet6 .* scope link')
2199 copy_unit_to_networkd_unit_path('25-link-local-addressing-no.network')
2201 self
.wait_online(['dummy98:carrier'])
2203 output
= check_output('ip address show dev dummy98')
2205 self
.assertNotRegex(output
, 'inet6* .* scope link')
2207 def test_sysctl(self
):
2208 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
2210 self
.wait_online(['dummy98:degraded'])
2212 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
2213 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
2214 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
2215 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
2216 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
2217 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
2218 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
2219 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'accept_local'), '1')
2221 def test_sysctl_disable_ipv6(self
):
2222 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
2224 print('## Disable ipv6')
2225 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
2226 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
2229 self
.wait_online(['dummy98:routable'])
2231 output
= check_output('ip -4 address show dummy98')
2233 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2234 output
= check_output('ip -6 address show dummy98')
2236 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2237 self
.assertRegex(output
, 'inet6 .* scope link')
2238 output
= check_output('ip -4 route show dev dummy98')
2240 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2241 output
= check_output('ip -6 route show dev dummy98')
2243 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2245 check_output('ip link del dummy98')
2247 print('## Enable ipv6')
2248 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
2249 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
2252 self
.wait_online(['dummy98:routable'])
2254 output
= check_output('ip -4 address show dummy98')
2256 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2257 output
= check_output('ip -6 address show dummy98')
2259 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2260 self
.assertRegex(output
, 'inet6 .* scope link')
2261 output
= check_output('ip -4 route show dev dummy98')
2263 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2264 output
= check_output('ip -6 route show dev dummy98')
2266 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2268 def test_bind_carrier(self
):
2269 check_output('ip link add dummy98 type dummy')
2270 check_output('ip link set dummy98 up')
2273 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
2275 self
.wait_online(['test1:routable'])
2277 output
= check_output('ip address show test1')
2279 self
.assertRegex(output
, 'UP,LOWER_UP')
2280 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2281 self
.wait_operstate('test1', 'routable')
2283 check_output('ip link add dummy99 type dummy')
2284 check_output('ip link set dummy99 up')
2286 output
= check_output('ip address show test1')
2288 self
.assertRegex(output
, 'UP,LOWER_UP')
2289 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2290 self
.wait_operstate('test1', 'routable')
2292 check_output('ip link del dummy98')
2294 output
= check_output('ip address show test1')
2296 self
.assertRegex(output
, 'UP,LOWER_UP')
2297 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2298 self
.wait_operstate('test1', 'routable')
2300 check_output('ip link set dummy99 down')
2302 output
= check_output('ip address show test1')
2304 self
.assertNotRegex(output
, 'UP,LOWER_UP')
2305 self
.assertRegex(output
, 'DOWN')
2306 self
.assertNotRegex(output
, '192.168.10')
2307 self
.wait_operstate('test1', 'off')
2309 check_output('ip link set dummy99 up')
2311 output
= check_output('ip address show test1')
2313 self
.assertRegex(output
, 'UP,LOWER_UP')
2314 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2315 self
.wait_operstate('test1', 'routable')
2317 def test_domain(self
):
2318 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
2320 self
.wait_online(['dummy98:routable'])
2322 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2324 self
.assertRegex(output
, 'Address: 192.168.42.100')
2325 self
.assertRegex(output
, 'DNS: 192.168.42.1')
2326 self
.assertRegex(output
, 'Search Domains: one')
2328 def test_keep_configuration_static(self
):
2329 check_output('systemctl stop systemd-networkd')
2331 check_output('ip link add name dummy98 type dummy')
2332 check_output('ip address add 10.1.2.3/16 dev dummy98')
2333 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
2334 output
= check_output('ip address show dummy98')
2336 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2337 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2338 output
= check_output('ip route show dev dummy98')
2341 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
2343 self
.wait_online(['dummy98:routable'])
2345 output
= check_output('ip address show dummy98')
2347 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2348 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2350 @expectedFailureIfNexthopIsNotAvailable()
2351 def test_nexthop(self
):
2352 copy_unit_to_networkd_unit_path('25-nexthop.network', '25-veth.netdev', '25-veth-peer.network')
2354 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2356 output
= check_output('ip nexthop list dev veth99')
2358 self
.assertRegex(output
, '192.168.5.1')
2360 def test_qdisc(self
):
2361 copy_unit_to_networkd_unit_path('25-qdisc-clsact-and-htb.network', '12-dummy.netdev',
2362 '25-qdisc-ingress-netem-compat.network', '11-dummy.netdev')
2363 check_output('modprobe sch_teql max_equalizers=2')
2366 self
.wait_online(['dummy98:routable', 'test1:routable'])
2368 output
= check_output('tc qdisc show dev test1')
2370 self
.assertRegex(output
, 'qdisc netem')
2371 self
.assertRegex(output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
2372 self
.assertRegex(output
, 'qdisc ingress')
2374 output
= check_output('tc qdisc show dev dummy98')
2376 self
.assertRegex(output
, 'qdisc clsact')
2378 self
.assertRegex(output
, 'qdisc htb 2: root')
2379 self
.assertRegex(output
, r
'default (0x30|30)')
2381 self
.assertRegex(output
, 'qdisc netem 30: parent 2:30')
2382 self
.assertRegex(output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
2383 self
.assertRegex(output
, 'qdisc fq_codel')
2384 self
.assertRegex(output
, 'limit 20480p flows 2048 quantum 1400 target 10(.0)?ms ce_threshold 100(.0)?ms interval 200(.0)?ms memory_limit 64Mb ecn')
2386 self
.assertRegex(output
, 'qdisc teql1 31: parent 2:31')
2388 self
.assertRegex(output
, 'qdisc fq 32: parent 2:32')
2389 self
.assertRegex(output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
2390 self
.assertRegex(output
, 'quantum 1500')
2391 self
.assertRegex(output
, 'initial_quantum 13000')
2392 self
.assertRegex(output
, 'maxrate 1Mbit')
2394 self
.assertRegex(output
, 'qdisc codel 33: parent 2:33')
2395 self
.assertRegex(output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn')
2397 self
.assertRegex(output
, 'qdisc fq_codel 34: parent 2:34')
2398 self
.assertRegex(output
, 'limit 20480p flows 2048 quantum 1400 target 10(.0)?ms ce_threshold 100(.0)?ms interval 200(.0)?ms memory_limit 64Mb ecn')
2400 self
.assertRegex(output
, 'qdisc tbf 35: parent 2:35')
2401 self
.assertRegex(output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms')
2403 self
.assertRegex(output
, 'qdisc sfq 36: parent 2:36')
2404 self
.assertRegex(output
, 'perturb 5sec')
2406 self
.assertRegex(output
, 'qdisc pfifo 37: parent 2:37')
2407 self
.assertRegex(output
, 'limit 100000p')
2409 self
.assertRegex(output
, 'qdisc gred 38: parent 2:38')
2410 self
.assertRegex(output
, 'vqs 12 default 10 grio')
2412 self
.assertRegex(output
, 'qdisc sfb 39: parent 2:39')
2413 self
.assertRegex(output
, 'limit 200000')
2415 self
.assertRegex(output
, 'qdisc bfifo 3a: parent 2:3a')
2416 self
.assertRegex(output
, 'limit 1000000')
2418 self
.assertRegex(output
, 'qdisc pfifo_head_drop 3b: parent 2:3b')
2419 self
.assertRegex(output
, 'limit 1023p')
2421 self
.assertRegex(output
, 'qdisc pfifo_fast 3c: parent 2:3c')
2423 output
= check_output('tc -d class show dev dummy98')
2425 self
.assertRegex(output
, 'class htb 2:30 root leaf 30:')
2426 self
.assertRegex(output
, 'class htb 2:31 root leaf 31:')
2427 self
.assertRegex(output
, 'class htb 2:32 root leaf 32:')
2428 self
.assertRegex(output
, 'class htb 2:33 root leaf 33:')
2429 self
.assertRegex(output
, 'class htb 2:34 root leaf 34:')
2430 self
.assertRegex(output
, 'class htb 2:35 root leaf 35:')
2431 self
.assertRegex(output
, 'class htb 2:36 root leaf 36:')
2432 self
.assertRegex(output
, 'class htb 2:37 root leaf 37:')
2433 self
.assertRegex(output
, 'class htb 2:38 root leaf 38:')
2434 self
.assertRegex(output
, 'class htb 2:39 root leaf 39:')
2435 self
.assertRegex(output
, 'class htb 2:3a root leaf 3a:')
2436 self
.assertRegex(output
, 'class htb 2:3b root leaf 3b:')
2437 self
.assertRegex(output
, 'class htb 2:3c root leaf 3c:')
2438 self
.assertRegex(output
, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit')
2439 self
.assertRegex(output
, 'burst 123456')
2440 self
.assertRegex(output
, 'cburst 123457')
2442 def test_qdisc2(self
):
2443 copy_unit_to_networkd_unit_path('25-qdisc-drr.network', '12-dummy.netdev',
2444 '25-qdisc-qfq.network', '11-dummy.netdev')
2447 self
.wait_online(['dummy98:routable', 'test1:routable'])
2449 output
= check_output('tc qdisc show dev dummy98')
2451 self
.assertRegex(output
, 'qdisc drr 2: root')
2452 output
= check_output('tc class show dev dummy98')
2454 self
.assertRegex(output
, 'class drr 2:30 root quantum 2000b')
2456 output
= check_output('tc qdisc show dev test1')
2458 self
.assertRegex(output
, 'qdisc qfq 2: root')
2459 output
= check_output('tc class show dev test1')
2461 self
.assertRegex(output
, 'class qfq 2:30 root weight 2 maxpkt 16000')
2462 self
.assertRegex(output
, 'class qfq 2:31 root weight 10 maxpkt 8000')
2464 @expectedFailureIfCAKEIsNotAvailable()
2465 def test_qdisc_cake(self
):
2466 copy_unit_to_networkd_unit_path('25-qdisc-cake.network', '12-dummy.netdev')
2468 self
.wait_online(['dummy98:routable'])
2470 output
= check_output('tc qdisc show dev dummy98')
2472 self
.assertRegex(output
, 'qdisc cake 3a: root')
2473 self
.assertRegex(output
, 'bandwidth 500Mbit')
2474 self
.assertRegex(output
, 'overhead 128')
2476 @expectedFailureIfPIEIsNotAvailable()
2477 def test_qdisc_pie(self
):
2478 copy_unit_to_networkd_unit_path('25-qdisc-pie.network', '12-dummy.netdev')
2480 self
.wait_online(['dummy98:routable'])
2482 output
= check_output('tc qdisc show dev dummy98')
2484 self
.assertRegex(output
, 'qdisc pie 3a: root')
2485 self
.assertRegex(output
, 'limit 200000')
2487 @expectedFailureIfHHFIsNotAvailable()
2488 def test_qdisc_hhf(self
):
2489 copy_unit_to_networkd_unit_path('25-qdisc-hhf.network', '12-dummy.netdev')
2491 self
.wait_online(['dummy98:routable'])
2493 output
= check_output('tc qdisc show dev dummy98')
2495 self
.assertRegex(output
, 'qdisc hhf 3a: root')
2496 self
.assertRegex(output
, 'limit 1022p')
2498 @expectedFailureIfETSIsNotAvailable()
2499 def test_qdisc_ets(self
):
2500 copy_unit_to_networkd_unit_path('25-qdisc-ets.network', '12-dummy.netdev')
2502 self
.wait_online(['dummy98:routable'])
2504 output
= check_output('tc qdisc show dev dummy98')
2506 self
.assertRegex(output
, 'qdisc ets 3a: root')
2507 self
.assertRegex(output
, 'bands 10 strict 3')
2508 self
.assertRegex(output
, 'quanta 1 2 3 4 5')
2509 self
.assertRegex(output
, 'priomap 3 4 5 6 7')
2511 class NetworkdStateFileTests(unittest
.TestCase
, Utilities
):
2518 'state-file-tests.network',
2522 remove_links(self
.links
)
2523 stop_networkd(show_logs
=False)
2526 remove_links(self
.links
)
2527 remove_unit_from_networkd_path(self
.units
)
2528 stop_networkd(show_logs
=True)
2530 def test_state_file(self
):
2531 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'state-file-tests.network')
2533 self
.wait_online(['dummy98:routable'])
2535 output
= check_output(*networkctl_cmd
, '--no-legend', 'list', 'dummy98', env
=env
)
2537 ifindex
= output
.split()[0]
2539 path
= os
.path
.join('/run/systemd/netif/links/', ifindex
)
2540 self
.assertTrue(os
.path
.exists(path
))
2543 with
open(path
) as f
:
2545 self
.assertRegex(data
, r
'ADMIN_STATE=configured')
2546 self
.assertRegex(data
, r
'OPER_STATE=routable')
2547 self
.assertRegex(data
, r
'REQUIRED_FOR_ONLINE=yes')
2548 self
.assertRegex(data
, r
'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
2549 self
.assertRegex(data
, r
'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
2550 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
2551 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2552 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2553 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2554 self
.assertRegex(data
, r
'LLMNR=no')
2555 self
.assertRegex(data
, r
'MDNS=yes')
2556 self
.assertRegex(data
, r
'DNSSEC=no')
2557 self
.assertRegex(data
, r
'ADDRESSES=192.168.(10.10|12.12)/24 192.168.(12.12|10.10)/24')
2559 check_output(*resolvectl_cmd
, 'dns', 'dummy98', '10.10.10.12', '10.10.10.13', env
=env
)
2560 check_output(*resolvectl_cmd
, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env
=env
)
2561 check_output(*resolvectl_cmd
, 'llmnr', 'dummy98', 'yes', env
=env
)
2562 check_output(*resolvectl_cmd
, 'mdns', 'dummy98', 'no', env
=env
)
2563 check_output(*resolvectl_cmd
, 'dnssec', 'dummy98', 'yes', env
=env
)
2564 check_output(*timedatectl_cmd
, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env
=env
)
2567 with
open(path
) as f
:
2569 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
2570 self
.assertRegex(data
, r
'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org')
2571 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2572 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2573 self
.assertRegex(data
, r
'LLMNR=yes')
2574 self
.assertRegex(data
, r
'MDNS=no')
2575 self
.assertRegex(data
, r
'DNSSEC=yes')
2577 check_output(*timedatectl_cmd
, 'revert', 'dummy98', env
=env
)
2580 with
open(path
) as f
:
2582 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
2583 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2584 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2585 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2586 self
.assertRegex(data
, r
'LLMNR=yes')
2587 self
.assertRegex(data
, r
'MDNS=no')
2588 self
.assertRegex(data
, r
'DNSSEC=yes')
2590 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
2593 with
open(path
) as f
:
2595 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
2596 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2597 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2598 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2599 self
.assertRegex(data
, r
'LLMNR=no')
2600 self
.assertRegex(data
, r
'MDNS=yes')
2601 self
.assertRegex(data
, r
'DNSSEC=no')
2603 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
2613 '23-active-slave.network',
2614 '23-bond199.network',
2615 '23-primary-slave.network',
2616 '25-bond-active-backup-slave.netdev',
2619 'bond-slave.network']
2622 remove_links(self
.links
)
2623 stop_networkd(show_logs
=False)
2626 remove_links(self
.links
)
2627 remove_unit_from_networkd_path(self
.units
)
2628 stop_networkd(show_logs
=True)
2630 def test_bond_active_slave(self
):
2631 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2633 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2635 output
= check_output('ip -d link show bond199')
2637 self
.assertRegex(output
, 'active_slave dummy98')
2639 def test_bond_primary_slave(self
):
2640 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2642 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2644 output
= check_output('ip -d link show bond199')
2646 self
.assertRegex(output
, 'primary dummy98')
2648 def test_bond_operstate(self
):
2649 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
2650 'bond99.network','bond-slave.network')
2652 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
2654 output
= check_output('ip -d link show dummy98')
2656 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2658 output
= check_output('ip -d link show test1')
2660 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2662 output
= check_output('ip -d link show bond99')
2664 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
2666 self
.wait_operstate('dummy98', 'enslaved')
2667 self
.wait_operstate('test1', 'enslaved')
2668 self
.wait_operstate('bond99', 'routable')
2670 check_output('ip link set dummy98 down')
2672 self
.wait_operstate('dummy98', 'off')
2673 self
.wait_operstate('test1', 'enslaved')
2674 self
.wait_operstate('bond99', 'degraded-carrier')
2676 check_output('ip link set dummy98 up')
2678 self
.wait_operstate('dummy98', 'enslaved')
2679 self
.wait_operstate('test1', 'enslaved')
2680 self
.wait_operstate('bond99', 'routable')
2682 check_output('ip link set dummy98 down')
2683 check_output('ip link set test1 down')
2685 self
.wait_operstate('dummy98', 'off')
2686 self
.wait_operstate('test1', 'off')
2688 if not self
.wait_operstate('bond99', 'no-carrier', setup_timeout
=30, fail_assert
=False):
2689 # Huh? Kernel does not recognize that all slave interfaces are down?
2690 # Let's confirm that networkd's operstate is consistent with ip's result.
2691 self
.assertNotRegex(output
, 'NO-CARRIER')
2693 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
2703 '26-bridge-configure-without-carrier.network',
2704 '26-bridge-slave-interface-1.network',
2705 '26-bridge-slave-interface-2.network',
2706 '26-bridge-vlan-master.network',
2707 '26-bridge-vlan-slave.network',
2708 'bridge99-ignore-carrier-loss.network',
2711 routing_policy_rule_tables
= ['100']
2714 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2715 remove_links(self
.links
)
2716 stop_networkd(show_logs
=False)
2719 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2720 remove_links(self
.links
)
2721 remove_unit_from_networkd_path(self
.units
)
2722 stop_networkd(show_logs
=True)
2724 def test_bridge_vlan(self
):
2725 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
2726 '26-bridge.netdev', '26-bridge-vlan-master.network')
2728 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
2730 output
= check_output('bridge vlan show dev test1')
2732 self
.assertNotRegex(output
, '4063')
2733 for i
in range(4064, 4095):
2734 self
.assertRegex(output
, f
'{i}')
2735 self
.assertNotRegex(output
, '4095')
2737 output
= check_output('bridge vlan show dev bridge99')
2739 self
.assertNotRegex(output
, '4059')
2740 for i
in range(4060, 4095):
2741 self
.assertRegex(output
, f
'{i}')
2742 self
.assertNotRegex(output
, '4095')
2744 def test_bridge_property(self
):
2745 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2746 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2749 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2751 output
= check_output('ip -d link show test1')
2753 self
.assertRegex(output
, 'master')
2754 self
.assertRegex(output
, 'bridge')
2756 output
= check_output('ip -d link show dummy98')
2758 self
.assertRegex(output
, 'master')
2759 self
.assertRegex(output
, 'bridge')
2761 output
= check_output('ip addr show bridge99')
2763 self
.assertRegex(output
, '192.168.0.15/24')
2765 output
= check_output('bridge -d link show dummy98')
2767 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
2768 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
2769 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
2770 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
2771 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
2772 # CONFIG_BRIDGE_IGMP_SNOOPING=y
2773 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
2774 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
2775 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
2776 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
2777 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
2778 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'priority'), '23')
2779 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard'), '1')
2780 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'root_block'), '1')
2782 output
= check_output('bridge -d link show test1')
2784 self
.assertEqual(read_bridge_port_attr('bridge99', 'test1', 'priority'), '0')
2786 check_output('ip address add 192.168.0.16/24 dev bridge99')
2789 output
= check_output('ip addr show bridge99')
2791 self
.assertRegex(output
, '192.168.0.16/24')
2794 print('### ip -6 route list table all dev bridge99')
2795 output
= check_output('ip -6 route list table all dev bridge99')
2797 self
.assertRegex(output
, 'ff00::/8 table local metric 256 pref medium')
2799 self
.assertEqual(call('ip link del test1'), 0)
2801 self
.wait_operstate('bridge99', 'degraded-carrier')
2803 check_output('ip link del dummy98')
2805 self
.wait_operstate('bridge99', 'no-carrier')
2807 output
= check_output('ip address show bridge99')
2809 self
.assertRegex(output
, 'NO-CARRIER')
2810 self
.assertNotRegex(output
, '192.168.0.15/24')
2811 self
.assertNotRegex(output
, '192.168.0.16/24')
2813 print('### ip -6 route list table all dev bridge99')
2814 output
= check_output('ip -6 route list table all dev bridge99')
2816 self
.assertRegex(output
, 'ff00::/8 table local metric 256 (linkdown )?pref medium')
2818 def test_bridge_configure_without_carrier(self
):
2819 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-configure-without-carrier.network',
2823 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
2824 for test
in ['no-slave', 'add-slave', 'slave-up', 'slave-no-carrier', 'slave-carrier', 'slave-down']:
2825 with self
.subTest(test
=test
):
2826 if test
== 'no-slave':
2827 # bridge has no slaves; it's up but *might* not have carrier
2828 # It may take very long time that the interface become configured state.
2829 self
.wait_online(['bridge99:no-carrier'], timeout
='2m', setup_state
=None)
2830 # due to a bug in the kernel, newly-created bridges are brought up
2831 # *with* carrier, unless they have had any setting changed; e.g.
2832 # their mac set, priority set, etc. Then, they will lose carrier
2833 # as soon as a (down) slave interface is added, and regain carrier
2834 # again once the slave interface is brought up.
2835 #self.check_link_attr('bridge99', 'carrier', '0')
2836 elif test
== 'add-slave':
2837 # add slave to bridge, but leave it down; bridge is definitely no-carrier
2838 self
.check_link_attr('test1', 'operstate', 'down')
2839 check_output('ip link set dev test1 master bridge99')
2840 self
.wait_online(['bridge99:no-carrier:no-carrier'], setup_state
=None)
2841 self
.check_link_attr('bridge99', 'carrier', '0')
2842 elif test
== 'slave-up':
2843 # bring up slave, which will have carrier; bridge gains carrier
2844 check_output('ip link set dev test1 up')
2845 self
.wait_online(['bridge99:routable'])
2846 self
.check_link_attr('bridge99', 'carrier', '1')
2847 elif test
== 'slave-no-carrier':
2848 # drop slave carrier; bridge loses carrier
2849 check_output('ip link set dev test1 carrier off')
2850 self
.wait_online(['bridge99:no-carrier:no-carrier'])
2851 self
.check_link_attr('bridge99', 'carrier', '0')
2852 elif test
== 'slave-carrier':
2853 # restore slave carrier; bridge gains carrier
2854 check_output('ip link set dev test1 carrier on')
2855 self
.wait_online(['bridge99:routable'])
2856 self
.check_link_attr('bridge99', 'carrier', '1')
2857 elif test
== 'slave-down':
2858 # bring down slave; bridge loses carrier
2859 check_output('ip link set dev test1 down')
2860 self
.wait_online(['bridge99:no-carrier:no-carrier'])
2861 self
.check_link_attr('bridge99', 'carrier', '0')
2863 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
2865 self
.assertRegex(output
, '10.1.2.3')
2866 self
.assertRegex(output
, '10.1.2.1')
2868 def test_bridge_ignore_carrier_loss(self
):
2869 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2870 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2871 'bridge99-ignore-carrier-loss.network')
2873 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2875 check_output('ip address add 192.168.0.16/24 dev bridge99')
2878 check_output('ip link del test1')
2879 check_output('ip link del dummy98')
2882 output
= check_output('ip address show bridge99')
2884 self
.assertRegex(output
, 'NO-CARRIER')
2885 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2886 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
2888 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
2889 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
2890 'bridge99-ignore-carrier-loss.network')
2892 self
.wait_online(['bridge99:no-carrier'])
2894 for trial
in range(4):
2895 check_output('ip link add dummy98 type dummy')
2896 check_output('ip link set dummy98 up')
2898 check_output('ip link del dummy98')
2900 self
.wait_online(['bridge99:routable', 'dummy98:enslaved'])
2902 output
= check_output('ip address show bridge99')
2904 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2906 output
= check_output('ip rule list table 100')
2908 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
2910 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
2914 '23-emit-lldp.network',
2919 remove_links(self
.links
)
2920 stop_networkd(show_logs
=False)
2923 remove_links(self
.links
)
2924 remove_unit_from_networkd_path(self
.units
)
2925 stop_networkd(show_logs
=True)
2927 def test_lldp(self
):
2928 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
2930 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
2932 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
2934 self
.assertRegex(output
, 'veth-peer')
2935 self
.assertRegex(output
, 'veth99')
2937 class NetworkdRATests(unittest
.TestCase
, Utilities
):
2942 'ipv6-prefix.network',
2943 'ipv6-prefix-veth.network',
2944 'ipv6-prefix-veth-token-static.network',
2945 'ipv6-prefix-veth-token-static-explicit.network',
2946 'ipv6-prefix-veth-token-static-multiple.network',
2947 'ipv6-prefix-veth-token-prefixstable.network']
2950 remove_links(self
.links
)
2951 stop_networkd(show_logs
=False)
2954 remove_links(self
.links
)
2955 remove_unit_from_networkd_path(self
.units
)
2956 stop_networkd(show_logs
=True)
2958 def test_ipv6_prefix_delegation(self
):
2959 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
2961 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2963 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
2965 self
.assertRegex(output
, 'fe80::')
2966 self
.assertRegex(output
, '2002:da8:1::1')
2968 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2970 self
.assertRegex(output
, '2002:da8:1:0')
2972 def test_ipv6_token_static(self
):
2973 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static.network')
2975 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2977 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2979 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
2981 def test_ipv6_token_static_explicit(self
):
2982 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static-explicit.network')
2984 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2986 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2988 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
2990 def test_ipv6_token_static_multiple(self
):
2991 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static-multiple.network')
2993 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2995 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
2997 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
2998 self
.assertRegex(output
, '2002:da8:1:0:fa:de:ca:fe')
3000 def test_ipv6_token_prefixstable(self
):
3001 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable.network')
3003 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3005 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3007 self
.assertRegex(output
, '2002:da8:1:0')
3009 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
3014 'dhcp-client.network',
3015 'dhcp-client-timezone-router.network',
3016 'dhcp-server.network',
3017 'dhcp-server-timezone-router.network']
3020 remove_links(self
.links
)
3021 stop_networkd(show_logs
=False)
3024 remove_links(self
.links
)
3025 remove_unit_from_networkd_path(self
.units
)
3026 stop_networkd(show_logs
=True)
3028 def test_dhcp_server(self
):
3029 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
3031 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3033 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3035 self
.assertRegex(output
, '192.168.5.*')
3036 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
3037 self
.assertRegex(output
, 'DNS: 192.168.5.1')
3038 self
.assertRegex(output
, 'NTP: 192.168.5.1')
3040 def test_emit_router_timezone(self
):
3041 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
3043 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3045 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3047 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
3048 self
.assertRegex(output
, '192.168.5.*')
3049 self
.assertRegex(output
, 'Europe/Berlin')
3051 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
3060 'dhcp-client-anonymize.network',
3061 'dhcp-client-decline.network',
3062 'dhcp-client-gateway-ipv4.network',
3063 'dhcp-client-gateway-ipv6.network',
3064 'dhcp-client-gateway-onlink-implicit.network',
3065 'dhcp-client-ipv4-dhcp-settings.network',
3066 'dhcp-client-ipv4-only-ipv6-disabled.network',
3067 'dhcp-client-ipv4-only.network',
3068 'dhcp-client-ipv4-use-routes-use-gateway.network',
3069 'dhcp-client-ipv6-only.network',
3070 'dhcp-client-ipv6-rapid-commit.network',
3071 'dhcp-client-keep-configuration-dhcp-on-stop.network',
3072 'dhcp-client-keep-configuration-dhcp.network',
3073 'dhcp-client-listen-port.network',
3074 'dhcp-client-reassign-static-routes-ipv4.network',
3075 'dhcp-client-reassign-static-routes-ipv6.network',
3076 'dhcp-client-route-metric.network',
3077 'dhcp-client-route-table.network',
3078 'dhcp-client-use-dns-ipv4-and-ra.network',
3079 'dhcp-client-use-dns-ipv4.network',
3080 'dhcp-client-use-dns-no.network',
3081 'dhcp-client-use-dns-yes.network',
3082 'dhcp-client-use-domains.network',
3083 'dhcp-client-vrf.network',
3084 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
3085 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
3086 'dhcp-client-with-static-address.network',
3087 'dhcp-client.network',
3088 'dhcp-server-decline.network',
3089 'dhcp-server-veth-peer.network',
3090 'dhcp-v4-server-veth-peer.network',
3094 stop_dnsmasq(dnsmasq_pid_file
)
3095 remove_links(self
.links
)
3096 stop_networkd(show_logs
=False)
3099 stop_dnsmasq(dnsmasq_pid_file
)
3102 remove_links(self
.links
)
3103 remove_unit_from_networkd_path(self
.units
)
3104 stop_networkd(show_logs
=True)
3106 def test_dhcp_client_ipv6_only(self
):
3107 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3110 self
.wait_online(['veth-peer:carrier'])
3112 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3114 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3116 self
.assertRegex(output
, '2600::')
3117 self
.assertNotRegex(output
, '192.168.5')
3119 # Confirm that ipv6 token is not set in the kernel
3120 output
= check_output('ip token show dev veth99')
3122 self
.assertRegex(output
, 'token :: dev veth99')
3124 def test_dhcp_client_ipv4_only(self
):
3125 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
3128 self
.wait_online(['veth-peer:carrier'])
3129 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
3130 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3132 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3134 self
.assertNotRegex(output
, '2600::')
3135 self
.assertRegex(output
, '192.168.5')
3136 self
.assertRegex(output
, '192.168.5.6')
3137 self
.assertRegex(output
, '192.168.5.7')
3139 # checking routes to DNS servers
3140 output
= check_output('ip route show dev veth99')
3142 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3143 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3144 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3146 stop_dnsmasq(dnsmasq_pid_file
)
3147 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8', lease_time
='2m')
3149 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3150 print('Wait for the dynamic address to be renewed')
3153 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3155 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3157 self
.assertNotRegex(output
, '2600::')
3158 self
.assertRegex(output
, '192.168.5')
3159 self
.assertNotRegex(output
, '192.168.5.6')
3160 self
.assertRegex(output
, '192.168.5.7')
3161 self
.assertRegex(output
, '192.168.5.8')
3163 # checking routes to DNS servers
3164 output
= check_output('ip route show dev veth99')
3166 self
.assertNotRegex(output
, r
'192.168.5.6')
3167 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3168 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3169 self
.assertRegex(output
, r
'192.168.5.8 proto dhcp scope link src 192.168.5.181 metric 1024')
3171 def test_dhcp_client_ipv4_use_routes_gateway(self
):
3172 for (routes
, gateway
, dnsroutes
) in itertools
.product([True, False, None], repeat
=3):
3174 with self
.subTest(routes
=routes
, gateway
=gateway
, dnsroutes
=dnsroutes
):
3175 self
._test
_dhcp
_client
_ipv
4_use
_routes
_gateway
(routes
, gateway
, dnsroutes
)
3178 def _test_dhcp_client_ipv4_use_routes_gateway(self
, routes
, gateway
, dnsroutes
):
3179 testunit
= 'dhcp-client-ipv4-use-routes-use-gateway.network'
3180 testunits
= ['25-veth.netdev', 'dhcp-server-veth-peer.network', testunit
]
3182 testunits
.append(f
'{testunit}.d/use-routes-{routes}.conf');
3184 testunits
.append(f
'{testunit}.d/use-gateway-{gateway}.conf');
3185 if dnsroutes
!= None:
3186 testunits
.append(f
'{testunit}.d/use-dns-routes-{dnsroutes}.conf');
3187 copy_unit_to_networkd_unit_path(*testunits
, dropins
=False)
3190 self
.wait_online(['veth-peer:carrier'])
3191 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
3192 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3194 output
= check_output('ip route show dev veth99')
3197 # UseRoutes= defaults to true
3198 useroutes
= routes
in [True, None]
3199 # UseGateway= defaults to useroutes
3200 usegateway
= useroutes
if gateway
== None else gateway
3204 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.181 metric 1024')
3206 self
.assertNotRegex(output
, r
'192.168.5.5')
3210 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.181 metric 1024')
3212 self
.assertNotRegex(output
, r
'default via 192.168.5.1')
3214 # Check RoutesToDNS=, which defaults to false
3216 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3217 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3219 self
.assertNotRegex(output
, r
'192.168.5.6')
3220 self
.assertNotRegex(output
, r
'192.168.5.7')
3222 def test_dhcp_client_ipv4_ipv6(self
):
3223 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
3224 'dhcp-client-ipv4-only.network')
3226 self
.wait_online(['veth-peer:carrier'])
3228 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3230 # link become 'routable' when at least one protocol provide an valid address.
3231 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3232 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3234 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3236 self
.assertRegex(output
, '2600::')
3237 self
.assertRegex(output
, '192.168.5')
3239 def test_dhcp_client_settings(self
):
3240 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
3243 self
.wait_online(['veth-peer:carrier'])
3245 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3247 print('## ip address show dev veth99')
3248 output
= check_output('ip address show dev veth99')
3250 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3251 self
.assertRegex(output
, '192.168.5')
3252 self
.assertRegex(output
, '1492')
3254 print('## ip route show table main dev veth99')
3255 output
= check_output('ip route show table main dev veth99')
3258 main_table_is_empty
= output
== ''
3259 if not main_table_is_empty
:
3260 self
.assertNotRegex(output
, 'proto dhcp')
3262 print('## ip route show table 211 dev veth99')
3263 output
= check_output('ip route show table 211 dev veth99')
3265 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
3266 if main_table_is_empty
:
3267 self
.assertRegex(output
, '192.168.5.0/24 proto dhcp')
3268 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
3269 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
3271 print('## dnsmasq log')
3272 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
3273 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
3274 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
3275 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
3277 def test_dhcp6_client_settings_rapidcommit_true(self
):
3278 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3280 self
.wait_online(['veth-peer:carrier'])
3282 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3284 output
= check_output('ip address show dev veth99')
3286 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3287 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
3289 def test_dhcp6_client_settings_rapidcommit_false(self
):
3290 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
3292 self
.wait_online(['veth-peer:carrier'])
3294 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3296 output
= check_output('ip address show dev veth99')
3298 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3299 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
3301 def test_dhcp_client_settings_anonymize(self
):
3302 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
3304 self
.wait_online(['veth-peer:carrier'])
3306 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3308 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
3309 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
3310 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
3312 def test_dhcp_client_listen_port(self
):
3313 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
3315 self
.wait_online(['veth-peer:carrier'])
3316 start_dnsmasq('--dhcp-alternate-port=67,5555')
3317 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3319 output
= check_output('ip -4 address show dev veth99')
3321 self
.assertRegex(output
, '192.168.5.* dynamic')
3323 def test_dhcp_client_with_static_address(self
):
3324 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
3325 'dhcp-client-with-static-address.network')
3327 self
.wait_online(['veth-peer:carrier'])
3329 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3331 output
= check_output('ip address show dev veth99 scope global')
3333 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
3334 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
3336 output
= check_output('ip route show dev veth99')
3338 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
3339 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
3340 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
3341 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
3343 def test_dhcp_route_table_id(self
):
3344 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
3346 self
.wait_online(['veth-peer:carrier'])
3348 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3350 output
= check_output('ip route show table 12')
3352 self
.assertRegex(output
, 'veth99 proto dhcp')
3353 self
.assertRegex(output
, '192.168.5.1')
3355 def test_dhcp_route_metric(self
):
3356 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
3358 self
.wait_online(['veth-peer:carrier'])
3360 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3362 output
= check_output('ip route show dev veth99')
3364 self
.assertRegex(output
, 'metric 24')
3366 def test_dhcp_client_reassign_static_routes_ipv4(self
):
3367 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3368 'dhcp-client-reassign-static-routes-ipv4.network')
3370 self
.wait_online(['veth-peer:carrier'])
3371 start_dnsmasq(lease_time
='2m')
3372 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3374 output
= check_output('ip address show dev veth99 scope global')
3376 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3378 output
= check_output('ip route show dev veth99')
3380 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3381 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3382 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3383 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3385 stop_dnsmasq(dnsmasq_pid_file
)
3386 start_dnsmasq(ipv4_range
='192.168.5.210,192.168.5.220', lease_time
='2m')
3388 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3389 print('Wait for the dynamic address to be renewed')
3392 self
.wait_online(['veth99:routable'])
3394 output
= check_output('ip route show dev veth99')
3396 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3397 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3398 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3399 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3401 def test_dhcp_client_reassign_static_routes_ipv6(self
):
3402 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3403 'dhcp-client-reassign-static-routes-ipv6.network')
3405 self
.wait_online(['veth-peer:carrier'])
3406 start_dnsmasq(lease_time
='2m')
3407 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3409 output
= check_output('ip address show dev veth99 scope global')
3411 self
.assertRegex(output
, r
'inet6 2600::[0-9a-f]*/128 scope global (noprefixroute dynamic|dynamic noprefixroute)')
3413 output
= check_output('ip -6 route show dev veth99')
3415 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3416 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3418 stop_dnsmasq(dnsmasq_pid_file
)
3419 start_dnsmasq(ipv6_range
='2600::30,2600::40', lease_time
='2m')
3421 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3422 print('Wait for the dynamic address to be renewed')
3425 self
.wait_online(['veth99:routable'])
3427 output
= check_output('ip -6 route show dev veth99')
3429 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3430 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3432 def test_dhcp_keep_configuration_dhcp(self
):
3433 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
3435 self
.wait_online(['veth-peer:carrier'])
3436 start_dnsmasq(lease_time
='2m')
3437 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3439 output
= check_output('ip address show dev veth99 scope global')
3441 self
.assertRegex(output
, r
'192.168.5.*')
3443 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3445 self
.assertRegex(output
, r
'192.168.5.*')
3447 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
3448 stop_dnsmasq(dnsmasq_pid_file
)
3450 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3451 print('Wait for the dynamic address to be expired')
3454 print('The lease address should be kept after lease expired')
3455 output
= check_output('ip address show dev veth99 scope global')
3457 self
.assertRegex(output
, r
'192.168.5.*')
3459 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3461 self
.assertRegex(output
, r
'192.168.5.*')
3463 check_output('systemctl stop systemd-networkd')
3465 print('The lease address should be kept after networkd stopped')
3466 output
= check_output('ip address show dev veth99 scope global')
3468 self
.assertRegex(output
, r
'192.168.5.*')
3470 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3472 self
.assertRegex(output
, r
'192.168.5.*')
3475 self
.wait_online(['veth-peer:routable'])
3477 print('Still the lease address should be kept after networkd restarted')
3478 output
= check_output('ip address show dev veth99 scope global')
3480 self
.assertRegex(output
, r
'192.168.5.*')
3482 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3484 self
.assertRegex(output
, r
'192.168.5.*')
3486 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
3487 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
3489 self
.wait_online(['veth-peer:carrier'])
3490 start_dnsmasq(lease_time
='2m')
3491 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3493 output
= check_output('ip address show dev veth99 scope global')
3495 self
.assertRegex(output
, r
'192.168.5.*')
3497 stop_dnsmasq(dnsmasq_pid_file
)
3498 check_output('systemctl stop systemd-networkd')
3500 output
= check_output('ip address show dev veth99 scope global')
3502 self
.assertRegex(output
, r
'192.168.5.*')
3505 self
.wait_online(['veth-peer:routable'])
3507 output
= check_output('ip address show dev veth99 scope global')
3509 self
.assertNotRegex(output
, r
'192.168.5.*')
3511 def test_dhcp_client_reuse_address_as_static(self
):
3512 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
3514 self
.wait_online(['veth-peer:carrier'])
3516 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3518 # link become 'routable' when at least one protocol provide an valid address.
3519 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3520 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3522 output
= check_output('ip address show dev veth99 scope global')
3524 self
.assertRegex(output
, '192.168.5')
3525 self
.assertRegex(output
, '2600::')
3527 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
3528 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
3529 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
3530 print(static_network
)
3532 remove_unit_from_networkd_path(['dhcp-client.network'])
3534 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
3535 f
.write(static_network
)
3537 # When networkd started, the links are already configured, so let's wait for 5 seconds
3538 # the links to be re-configured.
3540 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3542 output
= check_output('ip -4 address show dev veth99 scope global')
3544 self
.assertRegex(output
, '192.168.5')
3545 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3547 output
= check_output('ip -6 address show dev veth99 scope global')
3549 self
.assertRegex(output
, '2600::')
3550 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3552 @expectedFailureIfModuleIsNotAvailable('vrf')
3553 def test_dhcp_client_vrf(self
):
3554 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
3555 '25-vrf.netdev', '25-vrf.network')
3557 self
.wait_online(['veth-peer:carrier'])
3559 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
3561 # link become 'routable' when at least one protocol provide an valid address.
3562 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3563 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3565 print('## ip -d link show dev vrf99')
3566 output
= check_output('ip -d link show dev vrf99')
3568 self
.assertRegex(output
, 'vrf table 42')
3570 print('## ip address show vrf vrf99')
3571 output
= check_output('ip address show vrf vrf99')
3573 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3574 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3575 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3576 self
.assertRegex(output
, 'inet6 .* scope link')
3578 print('## ip address show dev veth99')
3579 output
= check_output('ip address show dev veth99')
3581 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3582 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3583 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3584 self
.assertRegex(output
, 'inet6 .* scope link')
3586 print('## ip route show vrf vrf99')
3587 output
= check_output('ip route show vrf vrf99')
3589 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
3590 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
3591 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
3592 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
3593 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
3595 print('## ip route show table main dev veth99')
3596 output
= check_output('ip route show table main dev veth99')
3598 self
.assertEqual(output
, '')
3600 def test_dhcp_client_gateway_ipv4(self
):
3601 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3602 'dhcp-client-gateway-ipv4.network')
3604 self
.wait_online(['veth-peer:carrier'])
3606 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3608 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3610 self
.assertRegex(output
, '10.0.0.0/8 via 192.168.5.1 proto static')
3612 def test_dhcp_client_gateway_ipv6(self
):
3613 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3614 'dhcp-client-gateway-ipv6.network')
3616 self
.wait_online(['veth-peer:carrier'])
3618 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3620 output
= check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
3622 self
.assertRegex(output
, 'via fe80::1034:56ff:fe78:9abd')
3624 def test_dhcp_client_gateway_onlink_implicit(self
):
3625 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3626 'dhcp-client-gateway-onlink-implicit.network')
3628 self
.wait_online(['veth-peer:carrier'])
3630 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3632 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3634 self
.assertRegex(output
, '192.168.5')
3636 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3638 self
.assertRegex(output
, 'onlink')
3639 output
= check_output('ip route list dev veth99 192.168.100.0/24')
3641 self
.assertRegex(output
, 'onlink')
3643 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
3644 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3645 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
3647 self
.wait_online(['veth-peer:carrier'])
3648 start_dnsmasq(lease_time
='2m')
3649 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3651 output
= check_output('ip address show dev veth99')
3654 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3655 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3656 output
= check_output('ip -6 address show dev veth99 scope link')
3657 self
.assertRegex(output
, 'inet6 .* scope link')
3658 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3659 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3660 output
= check_output('ip -4 address show dev veth99 scope link')
3661 self
.assertNotRegex(output
, 'inet .* scope link')
3663 print('Wait for the dynamic address to be expired')
3666 output
= check_output('ip address show dev veth99')
3669 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3670 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3671 output
= check_output('ip -6 address show dev veth99 scope link')
3672 self
.assertRegex(output
, 'inet6 .* scope link')
3673 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3674 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3675 output
= check_output('ip -4 address show dev veth99 scope link')
3676 self
.assertNotRegex(output
, 'inet .* scope link')
3678 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
3680 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
3681 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3682 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
3684 self
.wait_online(['veth99:degraded', 'veth-peer:routable'])
3686 output
= check_output('ip address show dev veth99')
3689 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3690 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3691 output
= check_output('ip -6 address show dev veth99 scope link')
3692 self
.assertRegex(output
, 'inet6 .* scope link')
3693 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3694 self
.assertNotRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3695 output
= check_output('ip -4 address show dev veth99 scope link')
3696 self
.assertRegex(output
, 'inet .* scope link')
3698 def test_dhcp_client_route_remove_on_renew(self
):
3699 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3700 'dhcp-client-ipv4-only-ipv6-disabled.network')
3702 self
.wait_online(['veth-peer:carrier'])
3703 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
3704 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3706 # test for issue #12490
3708 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3710 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3712 for line
in output
.splitlines():
3713 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3714 address1
= line
.split()[1].split('/')[0]
3717 output
= check_output('ip -4 route show dev veth99')
3719 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3720 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3722 stop_dnsmasq(dnsmasq_pid_file
)
3723 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
3725 print('Wait for the dynamic address to be expired')
3728 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3730 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3732 for line
in output
.splitlines():
3733 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3734 address2
= line
.split()[1].split('/')[0]
3737 self
.assertNotEqual(address1
, address2
)
3739 output
= check_output('ip -4 route show dev veth99')
3741 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3742 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3743 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
3744 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
3746 def test_dhcp_client_use_dns_yes(self
):
3747 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-yes.network')
3750 self
.wait_online(['veth-peer:carrier'])
3751 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3752 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3754 # link become 'routable' when at least one protocol provide an valid address.
3755 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3756 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3759 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3761 self
.assertRegex(output
, '192.168.5.1')
3762 self
.assertRegex(output
, '2600::1')
3764 def test_dhcp_client_use_dns_no(self
):
3765 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-no.network')
3768 self
.wait_online(['veth-peer:carrier'])
3769 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3770 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3772 # link become 'routable' when at least one protocol provide an valid address.
3773 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3774 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3777 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3779 self
.assertNotRegex(output
, '192.168.5.1')
3780 self
.assertNotRegex(output
, '2600::1')
3782 def test_dhcp_client_use_dns_ipv4(self
):
3783 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4.network')
3786 self
.wait_online(['veth-peer:carrier'])
3787 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3788 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3790 # link become 'routable' when at least one protocol provide an valid address.
3791 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3792 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3795 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3797 self
.assertRegex(output
, '192.168.5.1')
3798 self
.assertNotRegex(output
, '2600::1')
3800 def test_dhcp_client_use_dns_ipv4_and_ra(self
):
3801 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4-and-ra.network')
3804 self
.wait_online(['veth-peer:carrier'])
3805 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3806 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3808 # link become 'routable' when at least one protocol provide an valid address.
3809 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3810 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3813 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3815 self
.assertRegex(output
, '192.168.5.1')
3816 self
.assertRegex(output
, '2600::1')
3818 def test_dhcp_client_use_domains(self
):
3819 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-domains.network')
3822 self
.wait_online(['veth-peer:carrier'])
3823 start_dnsmasq('--dhcp-option=option:domain-search,example.com')
3824 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3826 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3828 self
.assertRegex(output
, 'Search Domains: example.com')
3831 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
3833 self
.assertRegex(output
, 'example.com')
3835 def test_dhcp_client_decline(self
):
3836 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-decline.network', 'dhcp-client-decline.network')
3839 self
.wait_online(['veth-peer:carrier'])
3840 rc
= call(*wait_online_cmd
, '--timeout=10s', '--interface=veth99:routable', env
=env
)
3841 self
.assertTrue(rc
== 1)
3843 class NetworkdIPv6PrefixTests(unittest
.TestCase
, Utilities
):
3848 'ipv6ra-prefix-client.network',
3849 'ipv6ra-prefix.network'
3853 remove_links(self
.links
)
3854 stop_networkd(show_logs
=False)
3858 remove_links(self
.links
)
3859 remove_unit_from_networkd_path(self
.units
)
3860 stop_networkd(show_logs
=True)
3862 def test_ipv6_route_prefix(self
):
3863 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client.network', 'ipv6ra-prefix.network')
3866 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3868 output
= check_output('ip -6 route show dev veth-peer')
3870 self
.assertRegex(output
, '2001:db8:0:1::/64 proto ra')
3872 output
= check_output('ip addr show dev veth99')
3874 self
.assertNotRegex(output
, '2001:db8:0:1')
3875 self
.assertRegex(output
, '2001:db8:0:2')
3877 class NetworkdMTUTests(unittest
.TestCase
, Utilities
):
3882 '12-dummy-mtu.netdev',
3883 '12-dummy-mtu.link',
3888 remove_links(self
.links
)
3889 stop_networkd(show_logs
=False)
3893 remove_links(self
.links
)
3894 remove_unit_from_networkd_path(self
.units
)
3895 stop_networkd(show_logs
=True)
3897 def check_mtu(self
, mtu
, ipv6_mtu
=None, reset
=True):
3903 self
.wait_online(['dummy98:routable'])
3904 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
3905 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
3907 # test normal restart
3909 self
.wait_online(['dummy98:routable'])
3910 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
3911 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
3914 self
.reset_check_mtu(mtu
, ipv6_mtu
)
3916 def reset_check_mtu(self
, mtu
, ipv6_mtu
=None):
3917 ''' test setting mtu/ipv6_mtu with interface already up '''
3920 # note - changing the device mtu resets the ipv6 mtu
3921 run('ip link set up mtu 1501 dev dummy98')
3922 run('ip link set up mtu 1500 dev dummy98')
3923 self
.assertEqual(read_link_attr('dummy98', 'mtu'), '1500')
3924 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), '1500')
3926 self
.check_mtu(mtu
, ipv6_mtu
, reset
=False)
3928 def test_mtu_network(self
):
3929 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
3930 self
.check_mtu('1600')
3932 def test_mtu_netdev(self
):
3933 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network', dropins
=False)
3934 # note - MTU set by .netdev happens ONLY at device creation!
3935 self
.check_mtu('1600', reset
=False)
3937 def test_mtu_link(self
):
3938 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', dropins
=False)
3939 # must reload udev because it only picks up new files after 3 second delay
3940 call('udevadm control --reload')
3941 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
3942 self
.check_mtu('1600', reset
=False)
3944 def test_ipv6_mtu(self
):
3945 ''' set ipv6 mtu without setting device mtu '''
3946 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
3947 self
.check_mtu('1500', '1400')
3949 def test_ipv6_mtu_toolarge(self
):
3950 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
3951 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
3952 self
.check_mtu('1500', '1500')
3954 def test_mtu_network_ipv6_mtu(self
):
3955 ''' set ipv6 mtu and set device mtu via network file '''
3956 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
3957 self
.check_mtu('1600', '1550')
3959 def test_mtu_netdev_ipv6_mtu(self
):
3960 ''' set ipv6 mtu and set device mtu via netdev file '''
3961 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
3962 self
.check_mtu('1600', '1550', reset
=False)
3964 def test_mtu_link_ipv6_mtu(self
):
3965 ''' set ipv6 mtu and set device mtu via link file '''
3966 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
3967 # must reload udev because it only picks up new files after 3 second delay
3968 call('udevadm control --reload')
3969 self
.check_mtu('1600', '1550', reset
=False)
3972 if __name__
== '__main__':
3973 parser
= argparse
.ArgumentParser()
3974 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
3975 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
3976 parser
.add_argument('--resolved', help='Path to systemd-resolved', dest
='resolved_bin')
3977 parser
.add_argument('--udevd', help='Path to systemd-udevd', dest
='udevd_bin')
3978 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
3979 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
3980 parser
.add_argument('--resolvectl', help='Path to resolvectl', dest
='resolvectl_bin')
3981 parser
.add_argument('--timedatectl', help='Path to timedatectl', dest
='timedatectl_bin')
3982 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
3983 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
3984 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
3985 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
3986 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
3987 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
3990 if ns
.networkd_bin
or ns
.resolved_bin
or ns
.udevd_bin
or ns
.wait_online_bin
or ns
.networkctl_bin
or ns
.resolvectl_bin
or ns
.timedatectl_bin
:
3991 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
3992 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
3993 resolved_bin
= os
.path
.join(ns
.build_dir
, 'systemd-resolved')
3994 udevd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-udevd')
3995 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
3996 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
3997 resolvectl_bin
= os
.path
.join(ns
.build_dir
, 'resolvectl')
3998 timedatectl_bin
= os
.path
.join(ns
.build_dir
, 'timedatectl')
4001 networkd_bin
= ns
.networkd_bin
4003 resolved_bin
= ns
.resolved_bin
4005 udevd_bin
= ns
.udevd_bin
4006 if ns
.wait_online_bin
:
4007 wait_online_bin
= ns
.wait_online_bin
4008 if ns
.networkctl_bin
:
4009 networkctl_bin
= ns
.networkctl_bin
4010 if ns
.resolvectl_bin
:
4011 resolvectl_bin
= ns
.resolvectl_bin
4012 if ns
.timedatectl_bin
:
4013 timedatectl_bin
= ns
.timedatectl_bin
4015 use_valgrind
= ns
.use_valgrind
4016 enable_debug
= ns
.enable_debug
4017 asan_options
= ns
.asan_options
4018 lsan_options
= ns
.lsan_options
4019 ubsan_options
= ns
.ubsan_options
4022 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
4023 resolvectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin
]
4024 timedatectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin
]
4025 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
4027 networkctl_cmd
= [networkctl_bin
]
4028 resolvectl_cmd
= [resolvectl_bin
]
4029 timedatectl_cmd
= [timedatectl_bin
]
4030 wait_online_cmd
= [wait_online_bin
]
4033 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
4035 env
.update({ 'ASAN_OPTIONS' : asan_options
})
4037 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
4039 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
4042 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,