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 expectedFailureIfNetdevsimWithSRIOVIsNotAvailable():
163 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
164 rc
= call('modprobe netdevsim', stderr
=subprocess
.DEVNULL
)
166 return unittest
.expectedFailure(func
)
169 with
open('/sys/bus/netdevsim/new_device', mode
='w') as f
:
171 except Exception as error
:
172 return unittest
.expectedFailure(func
)
174 call('udevadm settle')
175 call('udevadm info -w10s /sys/devices/netdevsim99/net/eni99np1', stderr
=subprocess
.DEVNULL
)
177 with
open('/sys/class/net/eni99np1/device/sriov_numvfs', mode
='w') as f
:
179 except Exception as error
:
180 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
181 return unittest
.expectedFailure(func
)
183 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
188 def expectedFailureIfCAKEIsNotAvailable():
190 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
191 rc
= call('tc qdisc add dev dummy98 parent root cake', stderr
=subprocess
.DEVNULL
)
192 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
196 return unittest
.expectedFailure(func
)
200 def expectedFailureIfPIEIsNotAvailable():
202 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
203 rc
= call('tc qdisc add dev dummy98 parent root pie', stderr
=subprocess
.DEVNULL
)
204 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
208 return unittest
.expectedFailure(func
)
212 def expectedFailureIfHHFIsNotAvailable():
214 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
215 rc
= call('tc qdisc add dev dummy98 parent root hhf', stderr
=subprocess
.DEVNULL
)
216 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
220 return unittest
.expectedFailure(func
)
224 def expectedFailureIfETSIsNotAvailable():
226 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
227 rc
= call('tc qdisc add dev dummy98 parent root ets bands 10', stderr
=subprocess
.DEVNULL
)
228 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
232 return unittest
.expectedFailure(func
)
236 def expectedFailureIfFQPIEIsNotAvailable():
238 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
239 rc
= call('tc qdisc add dev dummy98 parent root fq_pie', stderr
=subprocess
.DEVNULL
)
240 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
244 return unittest
.expectedFailure(func
)
251 os
.makedirs(network_unit_file_path
, exist_ok
=True)
252 os
.makedirs(networkd_ci_path
, exist_ok
=True)
254 shutil
.rmtree(networkd_ci_path
)
255 copytree(os
.path
.join(os
.path
.dirname(os
.path
.abspath(__file__
)), 'conf'), networkd_ci_path
)
257 for u
in ['systemd-networkd.socket', 'systemd-networkd.service', 'systemd-resolved.service',
258 'systemd-udevd-kernel.socket', 'systemd-udevd-control.socket', 'systemd-udevd.service',
259 'firewalld.service']:
260 if call(f
'systemctl is-active --quiet {u}') == 0:
261 check_output(f
'systemctl stop {u}')
262 running_units
.append(u
)
266 'StartLimitIntervalSec=0',
273 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin
,
277 drop_in
+= ['ExecStart=!!' + networkd_bin
]
279 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
281 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
283 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
285 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
286 if asan_options
or lsan_options
or ubsan_options
:
287 drop_in
+= ['SystemCallFilter=']
288 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
289 drop_in
+= ['MemoryDenyWriteExecute=no']
291 os
.makedirs('/run/systemd/system/systemd-networkd.service.d', exist_ok
=True)
292 with
open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode
='w') as f
:
293 f
.write('\n'.join(drop_in
))
301 drop_in
+= ['ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + resolved_bin
]
303 drop_in
+= ['ExecStart=!!' + resolved_bin
]
305 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
307 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
309 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
311 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
312 if asan_options
or lsan_options
or ubsan_options
:
313 drop_in
+= ['SystemCallFilter=']
314 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
315 drop_in
+= ['MemoryDenyWriteExecute=no']
317 os
.makedirs('/run/systemd/system/systemd-resolved.service.d', exist_ok
=True)
318 with
open('/run/systemd/system/systemd-resolved.service.d/00-override.conf', mode
='w') as f
:
319 f
.write('\n'.join(drop_in
))
324 'ExecStart=!!' + udevd_bin
,
327 os
.makedirs('/run/systemd/system/systemd-udevd.service.d', exist_ok
=True)
328 with
open('/run/systemd/system/systemd-udevd.service.d/00-override.conf', mode
='w') as f
:
329 f
.write('\n'.join(drop_in
))
331 check_output('systemctl daemon-reload')
332 print(check_output('systemctl cat systemd-networkd.service'))
333 print(check_output('systemctl cat systemd-resolved.service'))
334 print(check_output('systemctl cat systemd-udevd.service'))
335 check_output('systemctl restart systemd-resolved')
336 check_output('systemctl restart systemd-udevd')
338 def tearDownModule():
341 shutil
.rmtree(networkd_ci_path
)
343 for u
in ['systemd-networkd.socket', 'systemd-networkd.service', 'systemd-resolved.service']:
344 check_output(f
'systemctl stop {u}')
346 shutil
.rmtree('/run/systemd/system/systemd-networkd.service.d')
347 shutil
.rmtree('/run/systemd/system/systemd-resolved.service.d')
348 shutil
.rmtree('/run/systemd/system/systemd-udevd.service.d')
349 check_output('systemctl daemon-reload')
350 check_output('systemctl restart systemd-udevd.service')
352 for u
in running_units
:
353 check_output(f
'systemctl start {u}')
355 def read_link_attr(*args
):
356 with
open(os
.path
.join('/sys/class/net/', *args
)) as f
:
357 return f
.readline().strip()
359 def read_bridge_port_attr(bridge
, link
, attribute
):
360 path_bridge
= os
.path
.join('/sys/devices/virtual/net', bridge
)
361 path_port
= 'lower_' + link
+ '/brport'
362 path
= os
.path
.join(path_bridge
, path_port
)
364 with
open(os
.path
.join(path
, attribute
)) as f
:
365 return f
.readline().strip()
367 def link_exists(link
):
368 return os
.path
.exists(os
.path
.join('/sys/class/net', link
))
370 def remove_links(links
):
372 if link_exists(link
):
373 call('ip link del dev', link
)
376 def remove_fou_ports(ports
):
378 call('ip fou del port', port
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
380 def remove_routing_policy_rule_tables(tables
):
384 rc
= call('ip rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
386 def remove_routes(routes
):
387 for route_type
, addr
in routes
:
388 call('ip route del', route_type
, addr
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
390 def remove_l2tp_tunnels(tunnel_ids
):
391 output
= check_output('ip l2tp show tunnel')
392 for tid
in tunnel_ids
:
393 words
='Tunnel ' + tid
+ ', encap'
395 call('ip l2tp del tunnel tid', tid
)
398 def read_ipv6_sysctl_attr(link
, attribute
):
399 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, link
), attribute
)) as f
:
400 return f
.readline().strip()
402 def read_ipv4_sysctl_attr(link
, attribute
):
403 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv4_path
, link
), attribute
)) as f
:
404 return f
.readline().strip()
406 def copy_unit_to_networkd_unit_path(*units
, dropins
=True):
407 """Copy networkd unit files into the testbed.
409 Any networkd unit file type can be specified, as well as drop-in files.
411 By default, all drop-ins for a specified unit file are copied in;
412 to avoid that specify dropins=False.
414 When a drop-in file is specified, its unit file is also copied in automatically.
418 if dropins
and os
.path
.exists(os
.path
.join(networkd_ci_path
, unit
+ '.d')):
419 copytree(os
.path
.join(networkd_ci_path
, unit
+ '.d'), os
.path
.join(network_unit_file_path
, unit
+ '.d'))
420 if unit
.endswith('.conf'):
422 dropindir
= os
.path
.join(network_unit_file_path
, os
.path
.dirname(dropin
))
423 os
.makedirs(dropindir
, exist_ok
=True)
424 shutil
.copy(os
.path
.join(networkd_ci_path
, dropin
), dropindir
)
425 unit
= os
.path
.dirname(dropin
).rstrip('.d')
426 shutil
.copy(os
.path
.join(networkd_ci_path
, unit
), network_unit_file_path
)
428 def remove_unit_from_networkd_path(units
):
429 """Remove previously copied unit files from the testbed.
431 Drop-ins will be removed automatically.
434 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
))):
435 os
.remove(os
.path
.join(network_unit_file_path
, unit
))
436 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
+ '.d'))):
437 shutil
.rmtree(os
.path
.join(network_unit_file_path
, unit
+ '.d'))
439 def start_dnsmasq(additional_options
='', ipv4_range
='192.168.5.10,192.168.5.200', ipv6_range
='2600::10,2600::20', lease_time
='1h'):
440 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
441 check_output(dnsmasq_command
)
443 def stop_dnsmasq(pid_file
):
444 if os
.path
.exists(pid_file
):
445 with
open(pid_file
, 'r') as f
:
446 pid
= f
.read().rstrip(' \t\r\n\0')
447 os
.kill(int(pid
), signal
.SIGTERM
)
451 def search_words_in_dnsmasq_log(words
, show_all
=False):
452 if os
.path
.exists(dnsmasq_log_file
):
453 with
open (dnsmasq_log_file
) as in_file
:
454 contents
= in_file
.read()
457 for line
in contents
.splitlines():
460 print("%s, %s" % (words
, line
))
464 def remove_lease_file():
465 if os
.path
.exists(os
.path
.join(networkd_ci_path
, 'lease')):
466 os
.remove(os
.path
.join(networkd_ci_path
, 'lease'))
468 def remove_log_file():
469 if os
.path
.exists(dnsmasq_log_file
):
470 os
.remove(dnsmasq_log_file
)
472 def remove_networkd_state_files():
473 if os
.path
.exists(os
.path
.join(networkd_runtime_directory
, 'state')):
474 os
.remove(os
.path
.join(networkd_runtime_directory
, 'state'))
476 def stop_networkd(show_logs
=True, remove_state_files
=True):
478 invocation_id
= check_output('systemctl show systemd-networkd -p InvocationID --value')
479 check_output('systemctl stop systemd-networkd.socket')
480 check_output('systemctl stop systemd-networkd.service')
482 print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
))
483 if remove_state_files
:
484 remove_networkd_state_files()
486 def start_networkd(sleep_sec
=0):
487 check_output('systemctl start systemd-networkd')
489 time
.sleep(sleep_sec
)
491 def restart_networkd(sleep_sec
=0, show_logs
=True, remove_state_files
=True):
492 stop_networkd(show_logs
, remove_state_files
)
493 start_networkd(sleep_sec
)
497 def check_link_exists(self
, link
):
498 self
.assertTrue(link_exists(link
))
500 def check_link_attr(self
, *args
):
501 self
.assertEqual(read_link_attr(*args
[:-1]), args
[-1]);
503 def wait_operstate(self
, link
, operstate
='degraded', setup_state
='configured', setup_timeout
=5, fail_assert
=True):
504 """Wait for the link to reach the specified operstate and/or setup state.
506 Specify None or '' for either operstate or setup_state to ignore that state.
507 This will recheck until the state conditions are met or the timeout expires.
509 If the link successfully matches the requested state, this returns True.
510 If this times out waiting for the link to match, the behavior depends on the
511 'fail_assert' parameter; if True, this causes a test assertion failure,
512 otherwise this returns False. The default is to cause assertion failure.
514 Note that this function matches on *exactly* the given operstate and setup_state.
515 To wait for a link to reach *or exceed* a given operstate, use wait_online().
522 for secs
in range(setup_timeout
+ 1):
523 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
, env
=env
)
525 if re
.search(rf
'(?m)^\s*State:\s+{operstate}\s+\({setup_state}\)\s*$', output
):
527 # don't bother sleeping if time is up
528 if secs
< setup_timeout
:
531 self
.fail(f
'Timed out waiting for {link} to reach state {operstate}/{setup_state}')
534 def wait_online(self
, links_with_operstate
, timeout
='20s', bool_any
=False, setup_state
='configured', setup_timeout
=5):
535 """Wait for the link(s) to reach the specified operstate and/or setup state.
537 This is similar to wait_operstate() but can be used for multiple links,
538 and it also calls systemd-networkd-wait-online to wait for the given operstate.
539 The operstate should be specified in the link name, like 'eth0:degraded'.
540 If just a link name is provided, wait-online's default operstate to wait for is degraded.
542 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
543 'setup_timeout' controls the per-link timeout waiting for the setup_state.
545 Set 'bool_any' to True to wait for any (instead of all) of the given links.
546 If this is set, no setup_state checks are done.
548 Note that this function waits for the link(s) to reach *or exceed* the given operstate.
549 However, the setup_state, if specified, must be matched *exactly*.
551 This returns if the link(s) reached the requested operstate/setup_state; otherwise it
552 raises CalledProcessError or fails test assertion.
554 args
= wait_online_cmd
+ [f
'--timeout={timeout}'] + [f
'--interface={link}' for link
in links_with_operstate
]
558 check_output(*args
, env
=env
)
559 except subprocess
.CalledProcessError
:
560 for link
in links_with_operstate
:
561 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
.split(':')[0], env
=env
)
564 if not bool_any
and setup_state
:
565 for link
in links_with_operstate
:
566 self
.wait_operstate(link
.split(':')[0], None, setup_state
, setup_timeout
)
568 def wait_address(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
569 for i
in range(timeout_sec
):
572 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
573 if re
.search(address_regex
, output
) and 'tentative' not in output
:
576 self
.assertRegex(output
, address_regex
)
578 class NetworkctlTests(unittest
.TestCase
, Utilities
):
588 '11-dummy-mtu.netdev',
592 '25-address-static.network',
594 'netdev-link-local-addressing-yes.network',
598 remove_links(self
.links
)
599 stop_networkd(show_logs
=False)
602 remove_links(self
.links
)
603 remove_unit_from_networkd_path(self
.units
)
604 stop_networkd(show_logs
=True)
606 @expectedFailureIfAlternativeNameIsNotAvailable()
607 def test_altname(self
):
608 copy_unit_to_networkd_unit_path('netdev-link-local-addressing-yes.network', '12-dummy.netdev', '12-dummy.link')
609 check_output('udevadm control --reload')
611 self
.wait_online(['dummy98:degraded'])
613 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
614 self
.assertRegex(output
, 'hogehogehogehogehogehoge')
616 def test_reconfigure(self
):
617 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
619 self
.wait_online(['dummy98:routable'])
621 output
= check_output('ip -4 address show dev dummy98')
623 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
624 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
625 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
627 check_output('ip address del 10.1.2.3/16 dev dummy98')
628 check_output('ip address del 10.1.2.4/16 dev dummy98')
629 check_output('ip address del 10.2.2.4/16 dev dummy98')
631 check_output(*networkctl_cmd
, 'reconfigure', 'dummy98', env
=env
)
632 self
.wait_online(['dummy98:routable'])
634 output
= check_output('ip -4 address show dev dummy98')
636 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
637 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
638 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
640 def test_reload(self
):
643 copy_unit_to_networkd_unit_path('11-dummy.netdev')
644 check_output(*networkctl_cmd
, 'reload', env
=env
)
645 self
.wait_operstate('test1', 'off', setup_state
='unmanaged')
647 copy_unit_to_networkd_unit_path('11-dummy.network')
648 check_output(*networkctl_cmd
, 'reload', env
=env
)
649 self
.wait_online(['test1:degraded'])
651 remove_unit_from_networkd_path(['11-dummy.network'])
652 check_output(*networkctl_cmd
, 'reload', env
=env
)
653 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
655 remove_unit_from_networkd_path(['11-dummy.netdev'])
656 check_output(*networkctl_cmd
, 'reload', env
=env
)
657 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
659 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
660 check_output(*networkctl_cmd
, 'reload', env
=env
)
661 self
.wait_operstate('test1', 'degraded')
664 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
667 self
.wait_online(['test1:degraded'])
669 output
= check_output(*networkctl_cmd
, 'list', env
=env
)
670 self
.assertRegex(output
, '1 lo ')
671 self
.assertRegex(output
, 'test1')
673 output
= check_output(*networkctl_cmd
, 'list', 'test1', env
=env
)
674 self
.assertNotRegex(output
, '1 lo ')
675 self
.assertRegex(output
, 'test1')
677 output
= check_output(*networkctl_cmd
, 'list', 'te*', env
=env
)
678 self
.assertNotRegex(output
, '1 lo ')
679 self
.assertRegex(output
, 'test1')
681 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'te*', env
=env
)
682 self
.assertNotRegex(output
, '1: lo ')
683 self
.assertRegex(output
, 'test1')
685 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'tes[a-z][0-9]', env
=env
)
686 self
.assertNotRegex(output
, '1: lo ')
687 self
.assertRegex(output
, 'test1')
690 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
693 self
.wait_online(['test1:degraded'])
695 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
696 self
.assertRegex(output
, 'MTU: 1600')
699 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
701 self
.wait_online(['test1:degraded'])
703 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
705 self
.assertRegex(output
, 'Type: ether')
707 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
709 self
.assertRegex(output
, 'Type: loopback')
711 @expectedFailureIfLinkFileFieldIsNotSet()
712 def test_udev_link_file(self
):
713 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
715 self
.wait_online(['test1:degraded'])
717 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
719 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
720 self
.assertRegex(output
, r
'Network File: /run/systemd/network/11-dummy.network')
722 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
724 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
725 self
.assertRegex(output
, r
'Network File: n/a')
727 def test_delete_links(self
):
728 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
729 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
732 self
.wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
734 check_output(*networkctl_cmd
, 'delete', 'test1', 'veth99', env
=env
)
735 self
.assertFalse(link_exists('test1'))
736 self
.assertFalse(link_exists('veth99'))
737 self
.assertFalse(link_exists('veth-peer'))
739 class NetworkdNetDevTests(unittest
.TestCase
, Utilities
):
741 links_remove_earlier
= [
807 '10-dropin-test.netdev',
811 '13-not-match-udev-property.network',
812 '14-match-udev-property.network',
813 '15-name-conflict-test.netdev',
816 '21-vlan-test1.network',
819 '25-6rd-tunnel.netdev',
821 '25-bond-balanced-tlb.netdev',
823 '25-bridge-configure-without-carrier.network',
825 '25-erspan-tunnel-local-any.netdev',
826 '25-erspan-tunnel.netdev',
827 '25-fou-gretap.netdev',
829 '25-fou-ipip.netdev',
830 '25-fou-ipproto-gre.netdev',
831 '25-fou-ipproto-ipip.netdev',
834 '25-gretap-tunnel-local-any.netdev',
835 '25-gretap-tunnel.netdev',
836 '25-gre-tunnel-any-any.netdev',
837 '25-gre-tunnel-local-any.netdev',
838 '25-gre-tunnel-remote-any.netdev',
839 '25-gre-tunnel.netdev',
841 '25-ip6gretap-tunnel-local-any.netdev',
842 '25-ip6gretap-tunnel.netdev',
843 '25-ip6gre-tunnel-any-any.netdev',
844 '25-ip6gre-tunnel-local-any.netdev',
845 '25-ip6gre-tunnel-remote-any.netdev',
846 '25-ip6gre-tunnel.netdev',
847 '25-ip6tnl-tunnel-any-any.netdev',
848 '25-ip6tnl-tunnel-local-any.netdev',
849 '25-ip6tnl-tunnel-remote-any.netdev',
850 '25-ip6tnl-tunnel.netdev',
851 '25-ipip-tunnel-any-any.netdev',
852 '25-ipip-tunnel-independent.netdev',
853 '25-ipip-tunnel-independent-loopback.netdev',
854 '25-ipip-tunnel-local-any.netdev',
855 '25-ipip-tunnel-remote-any.netdev',
856 '25-ipip-tunnel.netdev',
859 '25-isatap-tunnel.netdev',
864 '25-sit-tunnel-any-any.netdev',
865 '25-sit-tunnel-local-any.netdev',
866 '25-sit-tunnel-remote-any.netdev',
867 '25-sit-tunnel.netdev',
870 '25-tunnel-local-any.network',
871 '25-tunnel-remote-any.network',
876 '25-vti6-tunnel-any-any.netdev',
877 '25-vti6-tunnel-local-any.netdev',
878 '25-vti6-tunnel-remote-any.netdev',
879 '25-vti6-tunnel.netdev',
880 '25-vti-tunnel-any-any.netdev',
881 '25-vti-tunnel-local-any.netdev',
882 '25-vti-tunnel-remote-any.netdev',
883 '25-vti-tunnel.netdev',
886 '25-wireguard-23-peers.netdev',
887 '25-wireguard-23-peers.network',
888 '25-wireguard-no-peer.netdev',
889 '25-wireguard-no-peer.network',
890 '25-wireguard-preshared-key.txt',
891 '25-wireguard-private-key.txt',
892 '25-wireguard.netdev',
893 '25-wireguard.network',
895 '25-xfrm-independent.netdev',
911 'netdev-link-local-addressing-yes.network',
915 'vxlan-test1.network',
925 remove_fou_ports(self
.fou_ports
)
926 remove_links(self
.links_remove_earlier
)
927 remove_links(self
.links
)
928 stop_networkd(show_logs
=False)
931 remove_fou_ports(self
.fou_ports
)
932 remove_links(self
.links_remove_earlier
)
933 remove_links(self
.links
)
934 remove_unit_from_networkd_path(self
.units
)
935 stop_networkd(show_logs
=True)
937 def test_dropin_and_name_conflict(self
):
938 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
941 self
.wait_online(['dropin-test:off'], setup_state
='unmanaged')
943 output
= check_output('ip link show dropin-test')
945 self
.assertRegex(output
, '00:50:56:c0:00:28')
947 def test_match_udev_property(self
):
948 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
950 self
.wait_online(['dummy98:routable'])
952 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
954 self
.assertRegex(output
, 'Network File: /run/systemd/network/14-match-udev-property')
956 def test_wait_online_any(self
):
957 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
960 self
.wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
962 self
.wait_operstate('bridge99', '(off|no-carrier)', setup_state
='configuring')
963 self
.wait_operstate('test1', 'degraded')
965 def test_bridge(self
):
966 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
969 self
.wait_online(['bridge99:no-carrier'])
971 tick
= os
.sysconf('SC_CLK_TCK')
972 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
973 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
974 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'forward_delay')) / tick
))
975 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'ageing_time')) / tick
))
976 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge', 'priority')))
977 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_querier')))
978 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_snooping')))
979 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'stp_state')))
980 self
.assertEqual(3, int(read_link_attr('bridge99', 'bridge', 'multicast_igmp_version')))
982 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
984 self
.assertRegex(output
, 'Priority: 9')
985 self
.assertRegex(output
, 'STP: yes')
986 self
.assertRegex(output
, 'Multicast IGMP Version: 3')
989 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
992 self
.wait_online(['bond99:off', 'bond98:off'], setup_state
='unmanaged')
994 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
995 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
996 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
997 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
998 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
999 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
1000 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
1001 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
1002 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
1003 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
1004 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
1006 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
1007 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
1009 def test_vlan(self
):
1010 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
1011 '21-vlan.network', '21-vlan-test1.network')
1014 self
.wait_online(['test1:degraded', 'vlan99:routable'])
1016 output
= check_output('ip -d link show test1')
1018 self
.assertRegex(output
, ' mtu 2000 ')
1020 output
= check_output('ip -d link show vlan99')
1022 self
.assertRegex(output
, ' mtu 2000 ')
1023 self
.assertRegex(output
, 'REORDER_HDR')
1024 self
.assertRegex(output
, 'LOOSE_BINDING')
1025 self
.assertRegex(output
, 'GVRP')
1026 self
.assertRegex(output
, 'MVRP')
1027 self
.assertRegex(output
, ' id 99 ')
1029 output
= check_output('ip -4 address show dev test1')
1031 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
1032 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
1034 output
= check_output('ip -4 address show dev vlan99')
1036 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
1038 def test_macvtap(self
):
1039 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
1040 with self
.subTest(mode
=mode
):
1041 if mode
!= 'private':
1043 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
1044 '11-dummy.netdev', 'macvtap.network')
1045 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
1046 f
.write('[MACVTAP]\nMode=' + mode
)
1049 self
.wait_online(['macvtap99:degraded', 'test1:degraded'])
1051 output
= check_output('ip -d link show macvtap99')
1053 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
1055 def test_macvlan(self
):
1056 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
1057 with self
.subTest(mode
=mode
):
1058 if mode
!= 'private':
1060 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
1061 '11-dummy.netdev', 'macvlan.network')
1062 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
1063 f
.write('[MACVLAN]\nMode=' + mode
)
1066 self
.wait_online(['macvlan99:degraded', 'test1:degraded'])
1068 output
= check_output('ip -d link show test1')
1070 self
.assertRegex(output
, ' mtu 2000 ')
1072 output
= check_output('ip -d link show macvlan99')
1074 self
.assertRegex(output
, ' mtu 2000 ')
1075 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
1077 @expectedFailureIfModuleIsNotAvailable('ipvlan')
1078 def test_ipvlan(self
):
1079 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1080 with self
.subTest(mode
=mode
, flag
=flag
):
1083 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
1084 '11-dummy.netdev', 'ipvlan.network')
1085 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
1086 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
1089 self
.wait_online(['ipvlan99:degraded', 'test1:degraded'])
1091 output
= check_output('ip -d link show ipvlan99')
1093 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
1095 @expectedFailureIfModuleIsNotAvailable('ipvtap')
1096 def test_ipvtap(self
):
1097 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1098 with self
.subTest(mode
=mode
, flag
=flag
):
1101 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
1102 '11-dummy.netdev', 'ipvtap.network')
1103 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
1104 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
1107 self
.wait_online(['ipvtap99:degraded', 'test1:degraded'])
1109 output
= check_output('ip -d link show ipvtap99')
1111 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
1113 def test_veth(self
):
1114 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
1117 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
1119 output
= check_output('ip -d link show veth99')
1121 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
1122 output
= check_output('ip -d link show veth-peer')
1124 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
1127 copy_unit_to_networkd_unit_path('25-tun.netdev')
1130 self
.wait_online(['tun99:off'], setup_state
='unmanaged')
1132 output
= check_output('ip -d link show tun99')
1134 # Old ip command does not support IFF_ flags
1135 self
.assertRegex(output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
1138 copy_unit_to_networkd_unit_path('25-tap.netdev')
1141 self
.wait_online(['tap99:off'], setup_state
='unmanaged')
1143 output
= check_output('ip -d link show tap99')
1145 # Old ip command does not support IFF_ flags
1146 self
.assertRegex(output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
1148 @expectedFailureIfModuleIsNotAvailable('vrf')
1150 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
1153 self
.wait_online(['vrf99:carrier'])
1155 @expectedFailureIfModuleIsNotAvailable('vcan')
1156 def test_vcan(self
):
1157 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
1160 self
.wait_online(['vcan99:carrier'])
1162 @expectedFailureIfModuleIsNotAvailable('vxcan')
1163 def test_vxcan(self
):
1164 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
1167 self
.wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
1169 @expectedFailureIfModuleIsNotAvailable('wireguard')
1170 def test_wireguard(self
):
1171 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
1172 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
1173 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt',
1174 '25-wireguard-no-peer.netdev', '25-wireguard-no-peer.network')
1176 self
.wait_online(['wg99:carrier', 'wg98:routable', 'wg97:carrier'])
1178 if shutil
.which('wg'):
1181 output
= check_output('wg show wg99 listen-port')
1182 self
.assertRegex(output
, '51820')
1183 output
= check_output('wg show wg99 fwmark')
1184 self
.assertRegex(output
, '0x4d2')
1185 output
= check_output('wg show wg99 allowed-ips')
1186 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
1187 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
1188 output
= check_output('wg show wg99 persistent-keepalive')
1189 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
1190 output
= check_output('wg show wg99 endpoints')
1191 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
1192 output
= check_output('wg show wg99 private-key')
1193 self
.assertRegex(output
, r
'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
1194 output
= check_output('wg show wg99 preshared-keys')
1195 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
1196 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
1198 output
= check_output('wg show wg98 private-key')
1199 self
.assertRegex(output
, r
'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
1201 output
= check_output('wg show wg97 listen-port')
1202 self
.assertRegex(output
, '51821')
1203 output
= check_output('wg show wg97 fwmark')
1204 self
.assertRegex(output
, '0x4d3')
1206 def test_geneve(self
):
1207 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
1210 self
.wait_online(['geneve99:degraded'])
1212 output
= check_output('ip -d link show geneve99')
1214 self
.assertRegex(output
, '192.168.22.1')
1215 self
.assertRegex(output
, '6082')
1216 self
.assertRegex(output
, 'udpcsum')
1217 self
.assertRegex(output
, 'udp6zerocsumrx')
1219 def test_ipip_tunnel(self
):
1220 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
1221 '25-ipip-tunnel.netdev', '25-tunnel.network',
1222 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1223 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1224 '25-ipip-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1226 self
.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'ipiptun96:routable', 'dummy98:degraded'])
1228 output
= check_output('ip -d link show ipiptun99')
1230 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98')
1231 output
= check_output('ip -d link show ipiptun98')
1233 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98')
1234 output
= check_output('ip -d link show ipiptun97')
1236 self
.assertRegex(output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98')
1237 output
= check_output('ip -d link show ipiptun96')
1239 self
.assertRegex(output
, 'ipip (ipip )?remote any local any dev dummy98')
1241 def test_gre_tunnel(self
):
1242 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
1243 '25-gre-tunnel.netdev', '25-tunnel.network',
1244 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1245 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1246 '25-gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1248 self
.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'gretun96:routable', 'dummy98:degraded'])
1250 output
= check_output('ip -d link show gretun99')
1252 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1253 self
.assertRegex(output
, 'ikey 1.2.3.103')
1254 self
.assertRegex(output
, 'okey 1.2.4.103')
1255 self
.assertRegex(output
, 'iseq')
1256 self
.assertRegex(output
, 'oseq')
1257 output
= check_output('ip -d link show gretun98')
1259 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
1260 self
.assertRegex(output
, 'ikey 0.0.0.104')
1261 self
.assertRegex(output
, 'okey 0.0.0.104')
1262 self
.assertNotRegex(output
, 'iseq')
1263 self
.assertNotRegex(output
, 'oseq')
1264 output
= check_output('ip -d link show gretun97')
1266 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
1267 self
.assertRegex(output
, 'ikey 0.0.0.105')
1268 self
.assertRegex(output
, 'okey 0.0.0.105')
1269 self
.assertNotRegex(output
, 'iseq')
1270 self
.assertNotRegex(output
, 'oseq')
1271 output
= check_output('ip -d link show gretun96')
1273 self
.assertRegex(output
, 'gre remote any local any dev dummy98')
1274 self
.assertRegex(output
, 'ikey 0.0.0.106')
1275 self
.assertRegex(output
, 'okey 0.0.0.106')
1276 self
.assertNotRegex(output
, 'iseq')
1277 self
.assertNotRegex(output
, 'oseq')
1279 def test_ip6gre_tunnel(self
):
1280 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
1281 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
1282 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1283 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1284 '25-ip6gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1287 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1289 self
.check_link_exists('dummy98')
1290 self
.check_link_exists('ip6gretun99')
1291 self
.check_link_exists('ip6gretun98')
1292 self
.check_link_exists('ip6gretun97')
1293 self
.check_link_exists('ip6gretun96')
1295 output
= check_output('ip -d link show ip6gretun99')
1297 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1298 output
= check_output('ip -d link show ip6gretun98')
1300 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
1301 output
= check_output('ip -d link show ip6gretun97')
1303 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
1304 output
= check_output('ip -d link show ip6gretun96')
1306 self
.assertRegex(output
, 'ip6gre remote any local any dev dummy98')
1308 def test_gretap_tunnel(self
):
1309 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
1310 '25-gretap-tunnel.netdev', '25-tunnel.network',
1311 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1313 self
.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
1315 output
= check_output('ip -d link show gretap99')
1317 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1318 self
.assertRegex(output
, 'ikey 0.0.0.106')
1319 self
.assertRegex(output
, 'okey 0.0.0.106')
1320 self
.assertRegex(output
, 'iseq')
1321 self
.assertRegex(output
, 'oseq')
1322 output
= check_output('ip -d link show gretap98')
1324 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
1325 self
.assertRegex(output
, 'ikey 0.0.0.107')
1326 self
.assertRegex(output
, 'okey 0.0.0.107')
1327 self
.assertRegex(output
, 'iseq')
1328 self
.assertRegex(output
, 'oseq')
1330 def test_ip6gretap_tunnel(self
):
1331 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
1332 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1333 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1335 self
.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
1337 output
= check_output('ip -d link show ip6gretap99')
1339 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1340 output
= check_output('ip -d link show ip6gretap98')
1342 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1344 def test_vti_tunnel(self
):
1345 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
1346 '25-vti-tunnel.netdev', '25-tunnel.network',
1347 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1348 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1349 '25-vti-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1351 self
.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'vtitun96:routable', 'dummy98:degraded'])
1353 output
= check_output('ip -d link show vtitun99')
1355 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1356 output
= check_output('ip -d link show vtitun98')
1358 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
1359 output
= check_output('ip -d link show vtitun97')
1361 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
1362 output
= check_output('ip -d link show vtitun96')
1364 self
.assertRegex(output
, 'vti remote any local any dev dummy98')
1366 def test_vti6_tunnel(self
):
1367 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
1368 '25-vti6-tunnel.netdev', '25-tunnel.network',
1369 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1370 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1372 self
.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
1374 output
= check_output('ip -d link show vti6tun99')
1376 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1377 output
= check_output('ip -d link show vti6tun98')
1379 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1380 output
= check_output('ip -d link show vti6tun97')
1382 self
.assertRegex(output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1384 def test_ip6tnl_tunnel(self
):
1385 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
1386 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1387 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1388 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1390 self
.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
1392 output
= check_output('ip -d link show ip6tnl99')
1394 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1395 output
= check_output('ip -d link show ip6tnl98')
1397 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1398 output
= check_output('ip -d link show ip6tnl97')
1400 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1402 def test_sit_tunnel(self
):
1403 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1404 '25-sit-tunnel.netdev', '25-tunnel.network',
1405 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1406 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1407 '25-sit-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1409 self
.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'sittun96:routable', 'dummy98:degraded'])
1411 output
= check_output('ip -d link show sittun99')
1413 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1414 output
= check_output('ip -d link show sittun98')
1416 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98")
1417 output
= check_output('ip -d link show sittun97')
1419 self
.assertRegex(output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98")
1420 output
= check_output('ip -d link show sittun96')
1422 self
.assertRegex(output
, "sit (ip6ip )?remote any local any dev dummy98")
1424 def test_isatap_tunnel(self
):
1425 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1426 '25-isatap-tunnel.netdev', '25-tunnel.network')
1428 self
.wait_online(['isataptun99:routable', 'dummy98:degraded'])
1430 output
= check_output('ip -d link show isataptun99')
1432 self
.assertRegex(output
, "isatap ")
1434 def test_6rd_tunnel(self
):
1435 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1436 '25-6rd-tunnel.netdev', '25-tunnel.network')
1438 self
.wait_online(['sittun99:routable', 'dummy98:degraded'])
1440 output
= check_output('ip -d link show sittun99')
1442 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1444 @expectedFailureIfERSPANModuleIsNotAvailable()
1445 def test_erspan_tunnel(self
):
1446 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1447 '25-erspan-tunnel.netdev', '25-tunnel.network',
1448 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1450 self
.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1452 output
= check_output('ip -d link show erspan99')
1454 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1455 self
.assertRegex(output
, 'ikey 0.0.0.101')
1456 self
.assertRegex(output
, 'okey 0.0.0.101')
1457 self
.assertRegex(output
, 'iseq')
1458 self
.assertRegex(output
, 'oseq')
1459 output
= check_output('ip -d link show erspan98')
1461 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1462 self
.assertRegex(output
, '102')
1463 self
.assertRegex(output
, 'ikey 0.0.0.102')
1464 self
.assertRegex(output
, 'okey 0.0.0.102')
1465 self
.assertRegex(output
, 'iseq')
1466 self
.assertRegex(output
, 'oseq')
1468 def test_tunnel_independent(self
):
1469 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1472 self
.wait_online(['ipiptun99:carrier'])
1474 def test_tunnel_independent_loopback(self
):
1475 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent-loopback.netdev', 'netdev-link-local-addressing-yes.network')
1478 self
.wait_online(['ipiptun99:carrier'])
1480 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1481 def test_xfrm(self
):
1482 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'xfrm.network',
1483 '25-xfrm.netdev', 'netdev-link-local-addressing-yes.network')
1486 self
.wait_online(['xfrm99:degraded', 'dummy98:degraded'])
1488 output
= check_output('ip link show dev xfrm99')
1491 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1492 def test_xfrm_independent(self
):
1493 copy_unit_to_networkd_unit_path('25-xfrm-independent.netdev', 'netdev-link-local-addressing-yes.network')
1496 self
.wait_online(['xfrm99:degraded'])
1498 @expectedFailureIfModuleIsNotAvailable('fou')
1500 # The following redundant check is necessary for CentOS CI.
1501 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1502 self
.assertTrue(is_module_available('fou'))
1504 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1505 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1506 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1509 self
.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'], setup_state
='unmanaged')
1511 output
= check_output('ip fou show')
1513 self
.assertRegex(output
, 'port 55555 ipproto 4')
1514 self
.assertRegex(output
, 'port 55556 ipproto 47')
1516 output
= check_output('ip -d link show ipiptun96')
1518 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1519 output
= check_output('ip -d link show sittun96')
1521 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1522 output
= check_output('ip -d link show gretun96')
1524 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1525 output
= check_output('ip -d link show gretap96')
1527 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1529 def test_vxlan(self
):
1530 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1531 '11-dummy.netdev', 'vxlan-test1.network')
1534 self
.wait_online(['test1:degraded', 'vxlan99:degraded'])
1536 output
= check_output('ip -d link show vxlan99')
1538 self
.assertRegex(output
, '999')
1539 self
.assertRegex(output
, '5555')
1540 self
.assertRegex(output
, 'l2miss')
1541 self
.assertRegex(output
, 'l3miss')
1542 self
.assertRegex(output
, 'udpcsum')
1543 self
.assertRegex(output
, 'udp6zerocsumtx')
1544 self
.assertRegex(output
, 'udp6zerocsumrx')
1545 self
.assertRegex(output
, 'remcsumtx')
1546 self
.assertRegex(output
, 'remcsumrx')
1547 self
.assertRegex(output
, 'gbp')
1549 output
= check_output('bridge fdb show dev vxlan99')
1551 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1552 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1553 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1555 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'vxlan99', env
=env
)
1557 self
.assertRegex(output
, 'VNI: 999')
1558 self
.assertRegex(output
, 'Destination Port: 5555')
1559 self
.assertRegex(output
, 'Underlying Device: test1')
1561 def test_macsec(self
):
1562 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1563 'macsec.network', '12-dummy.netdev')
1566 self
.wait_online(['dummy98:degraded', 'macsec99:routable'])
1568 output
= check_output('ip -d link show macsec99')
1570 self
.assertRegex(output
, 'macsec99@dummy98')
1571 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1572 self
.assertRegex(output
, 'encrypt on')
1574 output
= check_output('ip macsec show macsec99')
1576 self
.assertRegex(output
, 'encrypt on')
1577 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1578 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1579 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1580 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1581 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1582 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1583 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1584 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1585 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1586 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1587 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1589 def test_nlmon(self
):
1590 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1593 self
.wait_online(['nlmon99:carrier'])
1595 @expectedFailureIfModuleIsNotAvailable('ifb')
1597 copy_unit_to_networkd_unit_path('25-ifb.netdev', 'netdev-link-local-addressing-yes.network')
1600 self
.wait_online(['ifb99:degraded'])
1602 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1613 '25-l2tp-dummy.network',
1615 '25-l2tp-ip.netdev',
1616 '25-l2tp-udp.netdev']
1618 l2tp_tunnel_ids
= [ '10' ]
1621 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1622 remove_links(self
.links
)
1623 stop_networkd(show_logs
=False)
1626 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1627 remove_links(self
.links
)
1628 remove_unit_from_networkd_path(self
.units
)
1629 stop_networkd(show_logs
=True)
1631 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1632 def test_l2tp_udp(self
):
1633 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1634 '25-l2tp-udp.netdev', '25-l2tp.network')
1637 self
.wait_online(['test1:routable', 'l2tp-ses1:degraded', 'l2tp-ses2:degraded'])
1639 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1641 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1642 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1643 self
.assertRegex(output
, "Peer tunnel 11")
1644 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1645 self
.assertRegex(output
, "UDP checksum: enabled")
1647 output
= check_output('ip l2tp show session tid 10 session_id 15')
1649 self
.assertRegex(output
, "Session 15 in tunnel 10")
1650 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1651 self
.assertRegex(output
, "interface name: l2tp-ses1")
1653 output
= check_output('ip l2tp show session tid 10 session_id 17')
1655 self
.assertRegex(output
, "Session 17 in tunnel 10")
1656 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1657 self
.assertRegex(output
, "interface name: l2tp-ses2")
1659 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1660 def test_l2tp_ip(self
):
1661 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1662 '25-l2tp-ip.netdev', '25-l2tp.network')
1665 self
.wait_online(['test1:routable', 'l2tp-ses3:degraded', 'l2tp-ses4:degraded'])
1667 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1669 self
.assertRegex(output
, "Tunnel 10, encap IP")
1670 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1671 self
.assertRegex(output
, "Peer tunnel 12")
1673 output
= check_output('ip l2tp show session tid 10 session_id 25')
1675 self
.assertRegex(output
, "Session 25 in tunnel 10")
1676 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1677 self
.assertRegex(output
, "interface name: l2tp-ses3")
1679 output
= check_output('ip l2tp show session tid 10 session_id 27')
1681 self
.assertRegex(output
, "Session 27 in tunnel 10")
1682 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1683 self
.assertRegex(output
, "interface name: l2tp-ses4")
1685 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1700 '23-active-slave.network',
1701 '24-keep-configuration-static.network',
1702 '24-search-domain.network',
1703 '25-address-dad-veth-peer.network',
1704 '25-address-dad-veth99.network',
1705 '25-address-link-section.network',
1706 '25-address-preferred-lifetime-zero.network',
1707 '25-address-static.network',
1708 '25-bind-carrier.network',
1709 '25-bond-active-backup-slave.netdev',
1710 '25-fibrule-invert.network',
1711 '25-fibrule-port-range.network',
1712 '25-fibrule-uidrange.network',
1713 '25-gre-tunnel-remote-any.netdev',
1714 '25-ip6gre-tunnel-remote-any.netdev',
1715 '25-ipv6-address-label-section.network',
1716 '25-link-local-addressing-no.network',
1717 '25-link-local-addressing-yes.network',
1718 '25-link-section-unmanaged.network',
1719 '25-neighbor-section.network',
1720 '25-neighbor-next.network',
1721 '25-neighbor-ipv6.network',
1722 '25-neighbor-ip-dummy.network',
1723 '25-neighbor-ip.network',
1724 '25-nexthop.network',
1725 '25-qdisc-cake.network',
1726 '25-qdisc-clsact-and-htb.network',
1727 '25-qdisc-drr.network',
1728 '25-qdisc-ets.network',
1729 '25-qdisc-fq_pie.network',
1730 '25-qdisc-hhf.network',
1731 '25-qdisc-ingress-netem-compat.network',
1732 '25-qdisc-pie.network',
1733 '25-qdisc-qfq.network',
1734 '25-prefix-route-with-vrf.network',
1735 '25-prefix-route-without-vrf.network',
1736 '25-route-ipv6-src.network',
1737 '25-route-static.network',
1738 '25-route-vrf.network',
1739 '25-gateway-static.network',
1740 '25-gateway-next-static.network',
1742 '25-sysctl-disable-ipv6.network',
1743 '25-sysctl.network',
1745 '25-veth-peer.network',
1749 '26-link-local-addressing-ipv6.network',
1750 'routing-policy-rule-dummy98.network',
1751 'routing-policy-rule-test1.network',
1752 'routing-policy-rule-reconfigure.network',
1755 routing_policy_rule_tables
= ['7', '8', '9', '1011']
1756 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1759 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1760 remove_routes(self
.routes
)
1761 remove_links(self
.links
)
1762 stop_networkd(show_logs
=False)
1765 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1766 remove_routes(self
.routes
)
1767 remove_links(self
.links
)
1768 remove_unit_from_networkd_path(self
.units
)
1769 stop_networkd(show_logs
=True)
1771 def test_address_static(self
):
1772 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1775 self
.wait_online(['dummy98:routable'])
1777 output
= check_output('ip -4 address show dev dummy98')
1779 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1780 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1781 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1783 # test for ENOBUFS issue #17012
1784 for i
in range(1,254):
1785 self
.assertRegex(output
, f
'inet 10.3.3.{i}/16 brd 10.3.255.255')
1788 self
.assertNotRegex(output
, '10.10.0.1/16')
1789 self
.assertNotRegex(output
, '10.10.0.2/16')
1791 output
= check_output('ip -4 address show dev dummy98 label 32')
1792 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1794 output
= check_output('ip -4 address show dev dummy98 label 33')
1795 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1797 output
= check_output('ip -4 address show dev dummy98 label 34')
1798 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1800 output
= check_output('ip -4 address show dev dummy98 label 35')
1801 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1803 output
= check_output('ip -6 address show dev dummy98')
1805 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1806 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1807 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1808 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1809 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1810 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1813 self
.wait_online(['dummy98:routable'])
1815 # test for ENOBUFS issue #17012
1816 output
= check_output('ip -4 address show dev dummy98')
1817 for i
in range(1,254):
1818 self
.assertRegex(output
, f
'inet 10.3.3.{i}/16 brd 10.3.255.255')
1820 def test_address_preferred_lifetime_zero_ipv6(self
):
1821 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero.network', '12-dummy.netdev')
1824 self
.wait_online(['dummy98:routable'])
1826 output
= check_output('ip address show dummy98')
1828 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1829 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1831 output
= check_output('ip route show dev dummy98')
1833 self
.assertRegex(output
, 'default via 20.20.20.1 proto static')
1835 def test_address_dad(self
):
1836 copy_unit_to_networkd_unit_path('25-address-dad-veth99.network', '25-address-dad-veth-peer.network',
1839 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
1841 output
= check_output('ip -4 address show dev veth99')
1843 self
.assertRegex(output
, '192.168.100.10/24')
1845 output
= check_output('ip -4 address show dev veth-peer')
1847 self
.assertNotRegex(output
, '192.168.100.10/24')
1849 @expectedFailureIfModuleIsNotAvailable('vrf')
1850 def test_prefix_route(self
):
1851 copy_unit_to_networkd_unit_path('25-prefix-route-with-vrf.network', '12-dummy.netdev',
1852 '25-prefix-route-without-vrf.network', '11-dummy.netdev',
1853 '25-vrf.netdev', '25-vrf.network')
1854 for trial
in range(2):
1860 self
.wait_online(['dummy98:routable', 'test1:routable', 'vrf99:carrier'])
1862 output
= check_output('ip route show table 42 dev dummy98')
1863 print('### ip route show table 42 dev dummy98')
1865 self
.assertRegex(output
, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1')
1866 self
.assertRegex(output
, 'broadcast 10.20.33.0 proto kernel scope link src 10.20.33.1')
1867 self
.assertRegex(output
, '10.20.33.0/24 proto kernel scope link src 10.20.33.1')
1868 self
.assertRegex(output
, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1')
1869 self
.assertRegex(output
, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1')
1870 self
.assertRegex(output
, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1')
1871 self
.assertRegex(output
, 'broadcast 10.20.55.0 proto kernel scope link src 10.20.55.1')
1872 self
.assertRegex(output
, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1')
1873 self
.assertRegex(output
, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1')
1874 output
= check_output('ip -6 route show table 42 dev dummy98')
1875 print('### ip -6 route show table 42 dev dummy98')
1879 self
.assertRegex(output
, 'local fdde:11:22::1 proto kernel metric 0 pref medium')
1880 #self.assertRegex(output, 'fdde:11:22::1 proto kernel metric 256 pref medium')
1881 self
.assertRegex(output
, 'local fdde:11:33::1 proto kernel metric 0 pref medium')
1882 self
.assertRegex(output
, 'fdde:11:33::/64 proto kernel metric 256 pref medium')
1883 self
.assertRegex(output
, 'local fdde:11:44::1 proto kernel metric 0 pref medium')
1884 self
.assertRegex(output
, 'local fdde:11:55::1 proto kernel metric 0 pref medium')
1885 self
.assertRegex(output
, 'fe80::/64 proto kernel metric 256 pref medium')
1886 self
.assertRegex(output
, 'ff00::/8 metric 256 pref medium')
1890 output
= check_output('ip route show dev test1')
1891 print('### ip route show dev test1')
1893 self
.assertRegex(output
, '10.21.33.0/24 proto kernel scope link src 10.21.33.1')
1894 output
= check_output('ip route show table local dev test1')
1895 print('### ip route show table local dev test1')
1897 self
.assertRegex(output
, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1')
1898 self
.assertRegex(output
, 'broadcast 10.21.33.0 proto kernel scope link src 10.21.33.1')
1899 self
.assertRegex(output
, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1')
1900 self
.assertRegex(output
, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1')
1901 self
.assertRegex(output
, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1')
1902 self
.assertRegex(output
, 'broadcast 10.21.55.0 proto kernel scope link src 10.21.55.1')
1903 self
.assertRegex(output
, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1')
1904 self
.assertRegex(output
, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1')
1905 output
= check_output('ip -6 route show dev test1')
1906 print('### ip -6 route show dev test1')
1908 self
.assertRegex(output
, 'fdde:12:22::1 proto kernel metric 256 pref medium')
1909 self
.assertRegex(output
, 'fdde:12:33::/64 proto kernel metric 256 pref medium')
1910 self
.assertRegex(output
, 'fe80::/64 proto kernel metric 256 pref medium')
1911 output
= check_output('ip -6 route show table local dev test1')
1912 print('### ip -6 route show table local dev test1')
1914 self
.assertRegex(output
, 'local fdde:12:22::1 proto kernel metric 0 pref medium')
1915 self
.assertRegex(output
, 'local fdde:12:33::1 proto kernel metric 0 pref medium')
1916 self
.assertRegex(output
, 'local fdde:12:44::1 proto kernel metric 0 pref medium')
1917 self
.assertRegex(output
, 'local fdde:12:55::1 proto kernel metric 0 pref medium')
1918 self
.assertRegex(output
, 'ff00::/8 metric 256 pref medium')
1920 def test_configure_without_carrier(self
):
1921 copy_unit_to_networkd_unit_path('11-dummy.netdev')
1923 self
.wait_operstate('test1', 'off', '')
1924 check_output('ip link set dev test1 up carrier off')
1926 copy_unit_to_networkd_unit_path('25-test1.network.d/configure-without-carrier.conf', dropins
=False)
1928 self
.wait_online(['test1:no-carrier'])
1930 carrier_map
= {'on': '1', 'off': '0'}
1931 routable_map
= {'on': 'routable', 'off': 'no-carrier'}
1932 for carrier
in ['off', 'on', 'off']:
1933 with self
.subTest(carrier
=carrier
):
1934 if carrier_map
[carrier
] != read_link_attr('test1', 'carrier'):
1935 check_output(f
'ip link set dev test1 carrier {carrier}')
1936 self
.wait_online([f
'test1:{routable_map[carrier]}'])
1938 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
1940 self
.assertRegex(output
, '192.168.0.15')
1941 self
.assertRegex(output
, '192.168.0.1')
1942 self
.assertRegex(output
, routable_map
[carrier
])
1944 def test_configure_without_carrier_yes_ignore_carrier_loss_no(self
):
1945 copy_unit_to_networkd_unit_path('11-dummy.netdev')
1947 self
.wait_operstate('test1', 'off', '')
1948 check_output('ip link set dev test1 up carrier off')
1950 copy_unit_to_networkd_unit_path('25-test1.network')
1952 self
.wait_online(['test1:no-carrier'])
1954 carrier_map
= {'on': '1', 'off': '0'}
1955 routable_map
= {'on': 'routable', 'off': 'no-carrier'}
1956 for (carrier
, have_config
) in [('off', True), ('on', True), ('off', False)]:
1957 with self
.subTest(carrier
=carrier
, have_config
=have_config
):
1958 if carrier_map
[carrier
] != read_link_attr('test1', 'carrier'):
1959 check_output(f
'ip link set dev test1 carrier {carrier}')
1960 self
.wait_online([f
'test1:{routable_map[carrier]}'])
1962 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
1965 self
.assertRegex(output
, '192.168.0.15')
1966 self
.assertRegex(output
, '192.168.0.1')
1968 self
.assertNotRegex(output
, '192.168.0.15')
1969 self
.assertNotRegex(output
, '192.168.0.1')
1970 self
.assertRegex(output
, routable_map
[carrier
])
1972 def test_routing_policy_rule(self
):
1973 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1975 self
.wait_online(['test1:degraded'])
1977 output
= check_output('ip rule list iif test1 priority 111')
1979 self
.assertRegex(output
, '111:')
1980 self
.assertRegex(output
, 'from 192.168.100.18')
1981 self
.assertRegex(output
, r
'tos (0x08|throughput)\s')
1982 self
.assertRegex(output
, 'iif test1')
1983 self
.assertRegex(output
, 'oif test1')
1984 self
.assertRegex(output
, 'lookup 7')
1986 output
= check_output('ip rule list iif test1 priority 101')
1988 self
.assertRegex(output
, '101:')
1989 self
.assertRegex(output
, 'from all')
1990 self
.assertRegex(output
, 'iif test1')
1991 self
.assertRegex(output
, 'lookup 9')
1993 output
= check_output('ip -6 rule list iif test1 priority 100')
1995 self
.assertRegex(output
, '100:')
1996 self
.assertRegex(output
, 'from all')
1997 self
.assertRegex(output
, 'iif test1')
1998 self
.assertRegex(output
, 'lookup 8')
2000 def test_routing_policy_rule_issue_11280(self
):
2001 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
2002 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
2004 for trial
in range(3):
2005 # Remove state files only first time
2007 self
.wait_online(['test1:degraded', 'dummy98:degraded'])
2010 output
= check_output('ip rule list table 7')
2012 self
.assertRegex(output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
2014 output
= check_output('ip rule list table 8')
2016 self
.assertRegex(output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
2018 stop_networkd(remove_state_files
=False)
2020 def test_routing_policy_rule_reconfigure(self
):
2021 copy_unit_to_networkd_unit_path('routing-policy-rule-reconfigure.network', '11-dummy.netdev')
2023 self
.wait_online(['test1:degraded'])
2025 output
= check_output('ip rule list table 1011')
2027 self
.assertRegex(output
, '10111: from all fwmark 0x3f3 lookup 1011')
2028 self
.assertRegex(output
, '10112: from all oif test1 lookup 1011')
2029 self
.assertRegex(output
, '10113: from all iif test1 lookup 1011')
2030 self
.assertRegex(output
, '10114: from 192.168.8.254 lookup 1011')
2032 run('ip rule delete priority 10111')
2033 run('ip rule delete priority 10112')
2034 run('ip rule delete priority 10113')
2035 run('ip rule delete priority 10114')
2036 run('ip rule delete priority 10115')
2038 output
= check_output('ip rule list table 1011')
2040 self
.assertEqual(output
, '')
2042 run(*networkctl_cmd
, 'reconfigure', 'test1', env
=env
)
2044 self
.wait_online(['test1:degraded'])
2046 output
= check_output('ip rule list table 1011')
2048 self
.assertRegex(output
, '10111: from all fwmark 0x3f3 lookup 1011')
2049 self
.assertRegex(output
, '10112: from all oif test1 lookup 1011')
2050 self
.assertRegex(output
, '10113: from all iif test1 lookup 1011')
2051 self
.assertRegex(output
, '10114: from 192.168.8.254 lookup 1011')
2053 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
2054 def test_routing_policy_rule_port_range(self
):
2055 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
2057 self
.wait_online(['test1:degraded'])
2059 output
= check_output('ip rule')
2061 self
.assertRegex(output
, '111')
2062 self
.assertRegex(output
, 'from 192.168.100.18')
2063 self
.assertRegex(output
, '1123-1150')
2064 self
.assertRegex(output
, '3224-3290')
2065 self
.assertRegex(output
, 'tcp')
2066 self
.assertRegex(output
, 'lookup 7')
2068 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
2069 def test_routing_policy_rule_invert(self
):
2070 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
2072 self
.wait_online(['test1:degraded'])
2074 output
= check_output('ip rule')
2076 self
.assertRegex(output
, '111')
2077 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
2078 self
.assertRegex(output
, 'tcp')
2079 self
.assertRegex(output
, 'lookup 7')
2081 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable()
2082 def test_routing_policy_rule_uidrange(self
):
2083 copy_unit_to_networkd_unit_path('25-fibrule-uidrange.network', '11-dummy.netdev')
2085 self
.wait_online(['test1:degraded'])
2087 output
= check_output('ip rule')
2089 self
.assertRegex(output
, '111')
2090 self
.assertRegex(output
, 'from 192.168.100.18')
2091 self
.assertRegex(output
, 'lookup 7')
2092 self
.assertRegex(output
, 'uidrange 100-200')
2094 def test_route_static(self
):
2095 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
2097 self
.wait_online(['dummy98:routable'])
2099 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2102 print('### ip -6 route show dev dummy98')
2103 output
= check_output('ip -6 route show dev dummy98')
2105 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
2106 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
2108 print('### ip -6 route show dev dummy98 default')
2109 output
= check_output('ip -6 route show dev dummy98 default')
2111 self
.assertRegex(output
, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
2113 print('### ip -4 route show dev dummy98')
2114 output
= check_output('ip -4 route show dev dummy98')
2116 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
2117 self
.assertRegex(output
, '149.10.124.64 proto static scope link')
2118 self
.assertRegex(output
, '169.254.0.0/16 proto static scope link metric 2048')
2119 self
.assertRegex(output
, '192.168.1.1 proto static initcwnd 20')
2120 self
.assertRegex(output
, '192.168.1.2 proto static initrwnd 30')
2121 self
.assertRegex(output
, 'multicast 149.10.123.4 proto static')
2123 print('### ip -4 route show dev dummy98 default')
2124 output
= check_output('ip -4 route show dev dummy98 default')
2126 self
.assertRegex(output
, 'default via 149.10.125.65 proto static onlink')
2127 self
.assertRegex(output
, 'default via 149.10.124.64 proto static')
2128 self
.assertRegex(output
, 'default proto static')
2130 print('### ip -4 route show table local dev dummy98')
2131 output
= check_output('ip -4 route show table local dev dummy98')
2133 self
.assertRegex(output
, 'local 149.10.123.1 proto static scope host')
2134 self
.assertRegex(output
, 'anycast 149.10.123.2 proto static scope link')
2135 self
.assertRegex(output
, 'broadcast 149.10.123.3 proto static scope link')
2137 print('### ip route show type blackhole')
2138 output
= check_output('ip route show type blackhole')
2140 self
.assertRegex(output
, 'blackhole 202.54.1.2 proto static')
2142 print('### ip route show type unreachable')
2143 output
= check_output('ip route show type unreachable')
2145 self
.assertRegex(output
, 'unreachable 202.54.1.3 proto static')
2147 print('### ip route show type prohibit')
2148 output
= check_output('ip route show type prohibit')
2150 self
.assertRegex(output
, 'prohibit 202.54.1.4 proto static')
2152 print('### ip route show 192.168.10.1')
2153 output
= check_output('ip route show 192.168.10.1')
2155 self
.assertRegex(output
, '192.168.10.1 proto static')
2156 self
.assertRegex(output
, 'nexthop via 149.10.124.59 dev dummy98 weight 10')
2157 self
.assertRegex(output
, 'nexthop via 149.10.124.60 dev dummy98 weight 5')
2159 print('### ip route show 192.168.10.2')
2160 output
= check_output('ip route show 192.168.10.2')
2162 # old ip command does not show IPv6 gateways...
2163 self
.assertRegex(output
, '192.168.10.2 proto static')
2164 self
.assertRegex(output
, 'nexthop')
2165 self
.assertRegex(output
, 'dev dummy98 weight 10')
2166 self
.assertRegex(output
, 'dev dummy98 weight 5')
2168 print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2169 output
= check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2171 # old ip command does not show 'nexthop' keyword and weight...
2172 self
.assertRegex(output
, '2001:1234:5:7fff:ff:ff:ff:ff')
2173 self
.assertRegex(output
, 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98')
2174 self
.assertRegex(output
, 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98')
2176 @expectedFailureIfModuleIsNotAvailable('vrf')
2177 def test_route_vrf(self
):
2178 copy_unit_to_networkd_unit_path('25-route-vrf.network', '12-dummy.netdev',
2179 '25-vrf.netdev', '25-vrf.network')
2181 self
.wait_online(['dummy98:routable', 'vrf99:carrier'])
2183 output
= check_output('ip route show vrf vrf99')
2185 self
.assertRegex(output
, 'default via 192.168.100.1')
2187 output
= check_output('ip route show')
2189 self
.assertNotRegex(output
, 'default via 192.168.100.1')
2191 def test_gateway_reconfigure(self
):
2192 copy_unit_to_networkd_unit_path('25-gateway-static.network', '12-dummy.netdev')
2194 self
.wait_online(['dummy98:routable'])
2195 print('### ip -4 route show dev dummy98 default')
2196 output
= check_output('ip -4 route show dev dummy98 default')
2198 self
.assertRegex(output
, 'default via 149.10.124.59 proto static')
2199 self
.assertNotRegex(output
, '149.10.124.60')
2201 remove_unit_from_networkd_path(['25-gateway-static.network'])
2202 copy_unit_to_networkd_unit_path('25-gateway-next-static.network')
2204 self
.wait_online(['dummy98:routable'])
2205 print('### ip -4 route show dev dummy98 default')
2206 output
= check_output('ip -4 route show dev dummy98 default')
2208 self
.assertNotRegex(output
, '149.10.124.59')
2209 self
.assertRegex(output
, 'default via 149.10.124.60 proto static')
2211 def test_ip_route_ipv6_src_route(self
):
2212 # a dummy device does not make the addresses go through tentative state, so we
2213 # reuse a bond from an earlier test, which does make the addresses go through
2214 # tentative state, and do our test on that
2215 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2217 self
.wait_online(['dummy98:enslaved', 'bond199:routable'])
2219 output
= check_output('ip -6 route list dev bond199')
2221 self
.assertRegex(output
, 'abcd::/16')
2222 self
.assertRegex(output
, 'src')
2223 self
.assertRegex(output
, '2001:1234:56:8f63::2')
2225 def test_ip_link_mac_address(self
):
2226 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
2228 self
.wait_online(['dummy98:degraded'])
2230 output
= check_output('ip link show dummy98')
2232 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
2234 def test_ip_link_unmanaged(self
):
2235 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
2238 self
.check_link_exists('dummy98')
2240 self
.wait_operstate('dummy98', 'off', setup_state
='unmanaged')
2242 def test_ipv6_address_label(self
):
2243 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
2245 self
.wait_online(['dummy98:degraded'])
2247 output
= check_output('ip addrlabel list')
2249 self
.assertRegex(output
, '2004:da8:1::/64')
2251 def test_neighbor_section(self
):
2252 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2254 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2256 print('### ip neigh list dev dummy98')
2257 output
= check_output('ip neigh list dev dummy98')
2259 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2260 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2262 def test_neighbor_reconfigure(self
):
2263 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2265 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2267 print('### ip neigh list dev dummy98')
2268 output
= check_output('ip neigh list dev dummy98')
2270 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2271 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2273 remove_unit_from_networkd_path(['25-neighbor-section.network'])
2274 copy_unit_to_networkd_unit_path('25-neighbor-next.network')
2276 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2277 print('### ip neigh list dev dummy98')
2278 output
= check_output('ip neigh list dev dummy98')
2280 self
.assertNotRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2281 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT')
2282 self
.assertNotRegex(output
, '2004:da8:1::1.*PERMANENT')
2284 def test_neighbor_gre(self
):
2285 copy_unit_to_networkd_unit_path('25-neighbor-ip.network', '25-neighbor-ipv6.network', '25-neighbor-ip-dummy.network',
2286 '12-dummy.netdev', '25-gre-tunnel-remote-any.netdev', '25-ip6gre-tunnel-remote-any.netdev')
2288 self
.wait_online(['dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable'], timeout
='40s')
2290 output
= check_output('ip neigh list dev gretun97')
2292 self
.assertRegex(output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT')
2294 output
= check_output('ip neigh list dev ip6gretun97')
2296 self
.assertRegex(output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
2298 def test_link_local_addressing(self
):
2299 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
2300 '25-link-local-addressing-no.network', '12-dummy.netdev')
2302 self
.wait_online(['test1:degraded', 'dummy98:carrier'])
2304 output
= check_output('ip address show dev test1')
2306 self
.assertRegex(output
, 'inet .* scope link')
2307 self
.assertRegex(output
, 'inet6 .* scope link')
2309 output
= check_output('ip address show dev dummy98')
2311 self
.assertNotRegex(output
, 'inet6* .* scope link')
2314 Documentation/networking/ip-sysctl.txt
2316 addr_gen_mode - INTEGER
2317 Defines how link-local and autoconf addresses are generated.
2319 0: generate address based on EUI64 (default)
2320 1: do no generate a link-local address, use EUI64 for addresses generated
2322 2: generate stable privacy addresses, using the secret from
2323 stable_secret (RFC7217)
2324 3: generate stable privacy addresses, using a random secret if unset
2327 test1_addr_gen_mode
= ''
2328 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
2329 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
2333 # if stable_secret is unset, then EIO is returned
2334 test1_addr_gen_mode
= '0'
2336 test1_addr_gen_mode
= '2'
2338 test1_addr_gen_mode
= '0'
2340 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
2341 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
2343 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
2344 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
2346 def test_link_local_addressing_remove_ipv6ll(self
):
2347 copy_unit_to_networkd_unit_path('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
2349 self
.wait_online(['dummy98:degraded'])
2351 output
= check_output('ip address show dev dummy98')
2353 self
.assertRegex(output
, 'inet6 .* scope link')
2355 copy_unit_to_networkd_unit_path('25-link-local-addressing-no.network')
2357 self
.wait_online(['dummy98:carrier'])
2359 output
= check_output('ip address show dev dummy98')
2361 self
.assertNotRegex(output
, 'inet6* .* scope link')
2363 def test_sysctl(self
):
2364 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
2366 self
.wait_online(['dummy98:degraded'])
2368 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
2369 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
2370 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
2371 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
2372 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
2373 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
2374 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
2375 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'accept_local'), '1')
2377 def test_sysctl_disable_ipv6(self
):
2378 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
2380 print('## Disable ipv6')
2381 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
2382 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
2385 self
.wait_online(['dummy98:routable'])
2387 output
= check_output('ip -4 address show dummy98')
2389 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2390 output
= check_output('ip -6 address show dummy98')
2392 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2393 self
.assertRegex(output
, 'inet6 .* scope link')
2394 output
= check_output('ip -4 route show dev dummy98')
2396 self
.assertRegex(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2397 output
= check_output('ip -6 route show dev dummy98')
2399 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2401 check_output('ip link del dummy98')
2403 print('## Enable ipv6')
2404 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
2405 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
2408 self
.wait_online(['dummy98:routable'])
2410 output
= check_output('ip -4 address show dummy98')
2412 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2413 output
= check_output('ip -6 address show dummy98')
2415 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2416 self
.assertRegex(output
, 'inet6 .* scope link')
2417 output
= check_output('ip -4 route show dev dummy98')
2419 self
.assertRegex(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2420 output
= check_output('ip -6 route show dev dummy98')
2422 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2424 def test_bind_carrier(self
):
2425 check_output('ip link add dummy98 type dummy')
2426 check_output('ip link set dummy98 up')
2429 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
2431 self
.wait_online(['test1:routable'])
2433 output
= check_output('ip address show test1')
2435 self
.assertRegex(output
, 'UP,LOWER_UP')
2436 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2437 self
.wait_operstate('test1', 'routable')
2439 check_output('ip link add dummy99 type dummy')
2440 check_output('ip link set dummy99 up')
2442 output
= check_output('ip address show test1')
2444 self
.assertRegex(output
, 'UP,LOWER_UP')
2445 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2446 self
.wait_operstate('test1', 'routable')
2448 check_output('ip link del dummy98')
2450 output
= check_output('ip address show test1')
2452 self
.assertRegex(output
, 'UP,LOWER_UP')
2453 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2454 self
.wait_operstate('test1', 'routable')
2456 check_output('ip link set dummy99 down')
2458 output
= check_output('ip address show test1')
2460 self
.assertNotRegex(output
, 'UP,LOWER_UP')
2461 self
.assertRegex(output
, 'DOWN')
2462 self
.assertNotRegex(output
, '192.168.10')
2463 self
.wait_operstate('test1', 'off')
2465 check_output('ip link set dummy99 up')
2467 output
= check_output('ip address show test1')
2469 self
.assertRegex(output
, 'UP,LOWER_UP')
2470 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2471 self
.wait_operstate('test1', 'routable')
2473 def test_domain(self
):
2474 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
2476 self
.wait_online(['dummy98:routable'])
2478 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2480 self
.assertRegex(output
, 'Address: 192.168.42.100')
2481 self
.assertRegex(output
, 'DNS: 192.168.42.1')
2482 self
.assertRegex(output
, 'Search Domains: one')
2484 def test_keep_configuration_static(self
):
2485 check_output('systemctl stop systemd-networkd.socket')
2486 check_output('systemctl stop systemd-networkd.service')
2488 check_output('ip link add name dummy98 type dummy')
2489 check_output('ip address add 10.1.2.3/16 dev dummy98')
2490 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
2491 output
= check_output('ip address show dummy98')
2493 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2494 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2495 output
= check_output('ip route show dev dummy98')
2498 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
2500 self
.wait_online(['dummy98:routable'])
2502 output
= check_output('ip address show dummy98')
2504 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2505 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2507 @expectedFailureIfNexthopIsNotAvailable()
2508 def test_nexthop(self
):
2509 copy_unit_to_networkd_unit_path('25-nexthop.network', '25-veth.netdev', '25-veth-peer.network')
2511 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2513 output
= check_output('ip nexthop list dev veth99')
2515 self
.assertRegex(output
, '192.168.5.1')
2517 def test_qdisc(self
):
2518 copy_unit_to_networkd_unit_path('25-qdisc-clsact-and-htb.network', '12-dummy.netdev',
2519 '25-qdisc-ingress-netem-compat.network', '11-dummy.netdev')
2520 check_output('modprobe sch_teql max_equalizers=2')
2523 self
.wait_online(['dummy98:routable', 'test1:routable'])
2525 output
= check_output('tc qdisc show dev test1')
2527 self
.assertRegex(output
, 'qdisc netem')
2528 self
.assertRegex(output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
2529 self
.assertRegex(output
, 'qdisc ingress')
2531 output
= check_output('tc qdisc show dev dummy98')
2533 self
.assertRegex(output
, 'qdisc clsact')
2535 self
.assertRegex(output
, 'qdisc htb 2: root')
2536 self
.assertRegex(output
, r
'default (0x30|30)')
2538 self
.assertRegex(output
, 'qdisc netem 30: parent 2:30')
2539 self
.assertRegex(output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
2540 self
.assertRegex(output
, 'qdisc fq_codel')
2541 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')
2543 self
.assertRegex(output
, 'qdisc teql1 31: parent 2:31')
2545 self
.assertRegex(output
, 'qdisc fq 32: parent 2:32')
2546 self
.assertRegex(output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
2547 self
.assertRegex(output
, 'quantum 1500')
2548 self
.assertRegex(output
, 'initial_quantum 13000')
2549 self
.assertRegex(output
, 'maxrate 1Mbit')
2551 self
.assertRegex(output
, 'qdisc codel 33: parent 2:33')
2552 self
.assertRegex(output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn')
2554 self
.assertRegex(output
, 'qdisc fq_codel 34: parent 2:34')
2555 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')
2557 self
.assertRegex(output
, 'qdisc tbf 35: parent 2:35')
2558 self
.assertRegex(output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms')
2560 self
.assertRegex(output
, 'qdisc sfq 36: parent 2:36')
2561 self
.assertRegex(output
, 'perturb 5sec')
2563 self
.assertRegex(output
, 'qdisc pfifo 37: parent 2:37')
2564 self
.assertRegex(output
, 'limit 100000p')
2566 self
.assertRegex(output
, 'qdisc gred 38: parent 2:38')
2567 self
.assertRegex(output
, 'vqs 12 default 10 grio')
2569 self
.assertRegex(output
, 'qdisc sfb 39: parent 2:39')
2570 self
.assertRegex(output
, 'limit 200000')
2572 self
.assertRegex(output
, 'qdisc bfifo 3a: parent 2:3a')
2573 self
.assertRegex(output
, 'limit 1000000')
2575 self
.assertRegex(output
, 'qdisc pfifo_head_drop 3b: parent 2:3b')
2576 self
.assertRegex(output
, 'limit 1023p')
2578 self
.assertRegex(output
, 'qdisc pfifo_fast 3c: parent 2:3c')
2580 output
= check_output('tc -d class show dev dummy98')
2582 self
.assertRegex(output
, 'class htb 2:30 root leaf 30:')
2583 self
.assertRegex(output
, 'class htb 2:31 root leaf 31:')
2584 self
.assertRegex(output
, 'class htb 2:32 root leaf 32:')
2585 self
.assertRegex(output
, 'class htb 2:33 root leaf 33:')
2586 self
.assertRegex(output
, 'class htb 2:34 root leaf 34:')
2587 self
.assertRegex(output
, 'class htb 2:35 root leaf 35:')
2588 self
.assertRegex(output
, 'class htb 2:36 root leaf 36:')
2589 self
.assertRegex(output
, 'class htb 2:37 root leaf 37:')
2590 self
.assertRegex(output
, 'class htb 2:38 root leaf 38:')
2591 self
.assertRegex(output
, 'class htb 2:39 root leaf 39:')
2592 self
.assertRegex(output
, 'class htb 2:3a root leaf 3a:')
2593 self
.assertRegex(output
, 'class htb 2:3b root leaf 3b:')
2594 self
.assertRegex(output
, 'class htb 2:3c root leaf 3c:')
2595 self
.assertRegex(output
, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit')
2596 self
.assertRegex(output
, 'burst 123456')
2597 self
.assertRegex(output
, 'cburst 123457')
2599 def test_qdisc2(self
):
2600 copy_unit_to_networkd_unit_path('25-qdisc-drr.network', '12-dummy.netdev',
2601 '25-qdisc-qfq.network', '11-dummy.netdev')
2604 self
.wait_online(['dummy98:routable', 'test1:routable'])
2606 output
= check_output('tc qdisc show dev dummy98')
2608 self
.assertRegex(output
, 'qdisc drr 2: root')
2609 output
= check_output('tc class show dev dummy98')
2611 self
.assertRegex(output
, 'class drr 2:30 root quantum 2000b')
2613 output
= check_output('tc qdisc show dev test1')
2615 self
.assertRegex(output
, 'qdisc qfq 2: root')
2616 output
= check_output('tc class show dev test1')
2618 self
.assertRegex(output
, 'class qfq 2:30 root weight 2 maxpkt 16000')
2619 self
.assertRegex(output
, 'class qfq 2:31 root weight 10 maxpkt 8000')
2621 @expectedFailureIfCAKEIsNotAvailable()
2622 def test_qdisc_cake(self
):
2623 copy_unit_to_networkd_unit_path('25-qdisc-cake.network', '12-dummy.netdev')
2625 self
.wait_online(['dummy98:routable'])
2627 output
= check_output('tc qdisc show dev dummy98')
2629 self
.assertRegex(output
, 'qdisc cake 3a: root')
2630 self
.assertRegex(output
, 'bandwidth 500Mbit')
2631 self
.assertRegex(output
, 'overhead 128')
2633 @expectedFailureIfPIEIsNotAvailable()
2634 def test_qdisc_pie(self
):
2635 copy_unit_to_networkd_unit_path('25-qdisc-pie.network', '12-dummy.netdev')
2637 self
.wait_online(['dummy98:routable'])
2639 output
= check_output('tc qdisc show dev dummy98')
2641 self
.assertRegex(output
, 'qdisc pie 3a: root')
2642 self
.assertRegex(output
, 'limit 200000')
2644 @expectedFailureIfHHFIsNotAvailable()
2645 def test_qdisc_hhf(self
):
2646 copy_unit_to_networkd_unit_path('25-qdisc-hhf.network', '12-dummy.netdev')
2648 self
.wait_online(['dummy98:routable'])
2650 output
= check_output('tc qdisc show dev dummy98')
2652 self
.assertRegex(output
, 'qdisc hhf 3a: root')
2653 self
.assertRegex(output
, 'limit 1022p')
2655 @expectedFailureIfETSIsNotAvailable()
2656 def test_qdisc_ets(self
):
2657 copy_unit_to_networkd_unit_path('25-qdisc-ets.network', '12-dummy.netdev')
2659 self
.wait_online(['dummy98:routable'])
2661 output
= check_output('tc qdisc show dev dummy98')
2664 self
.assertRegex(output
, 'qdisc ets 3a: root')
2665 self
.assertRegex(output
, 'bands 10 strict 3')
2666 self
.assertRegex(output
, 'quanta 1 2 3 4 5')
2667 self
.assertRegex(output
, 'priomap 3 4 5 6 7')
2669 @expectedFailureIfFQPIEIsNotAvailable()
2670 def test_qdisc_fq_pie(self
):
2671 copy_unit_to_networkd_unit_path('25-qdisc-fq_pie.network', '12-dummy.netdev')
2673 self
.wait_online(['dummy98:routable'])
2675 output
= check_output('tc qdisc show dev dummy98')
2678 self
.assertRegex(output
, 'qdisc fq_pie 3a: root')
2679 self
.assertRegex(output
, 'limit 200000p')
2681 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable()
2682 def test_sriov(self
):
2683 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
2684 call('modprobe netdevsim', stderr
=subprocess
.DEVNULL
)
2685 with
open('/sys/bus/netdevsim/new_device', mode
='w') as f
:
2688 call('udevadm settle')
2689 call('udevadm info -w10s /sys/devices/netdevsim99/net/eni99np1', stderr
=subprocess
.DEVNULL
)
2690 with
open('/sys/class/net/eni99np1/device/sriov_numvfs', mode
='w') as f
:
2693 copy_unit_to_networkd_unit_path('25-sriov.network')
2695 self
.wait_online(['eni99np1:routable'])
2697 output
= check_output('ip link show dev eni99np1')
2699 self
.assertRegex(output
,
2700 'vf 0 .*00:11:22:33:44:55.*vlan 5, qos 1, vlan protocol 802.1ad, spoof checking on, link-state enable, trust on, query_rss on\n *'
2701 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
2702 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
2705 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
2707 class NetworkdStateFileTests(unittest
.TestCase
, Utilities
):
2714 'state-file-tests.network',
2718 remove_links(self
.links
)
2719 stop_networkd(show_logs
=False)
2722 remove_links(self
.links
)
2723 remove_unit_from_networkd_path(self
.units
)
2724 stop_networkd(show_logs
=True)
2726 def test_state_file(self
):
2727 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'state-file-tests.network')
2729 self
.wait_online(['dummy98:routable'])
2731 output
= check_output(*networkctl_cmd
, '--no-legend', 'list', 'dummy98', env
=env
)
2733 ifindex
= output
.split()[0]
2735 path
= os
.path
.join('/run/systemd/netif/links/', ifindex
)
2736 self
.assertTrue(os
.path
.exists(path
))
2738 # make link state file updated
2739 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
2741 with
open(path
) as f
:
2743 self
.assertRegex(data
, r
'ADMIN_STATE=configured')
2744 self
.assertRegex(data
, r
'OPER_STATE=routable')
2745 self
.assertRegex(data
, r
'REQUIRED_FOR_ONLINE=yes')
2746 self
.assertRegex(data
, r
'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
2747 self
.assertRegex(data
, r
'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
2748 self
.assertRegex(data
, r
'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
2749 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2750 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2751 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2752 self
.assertRegex(data
, r
'LLMNR=no')
2753 self
.assertRegex(data
, r
'MDNS=yes')
2754 self
.assertRegex(data
, r
'DNSSEC=no')
2755 self
.assertRegex(data
, r
'ADDRESSES=192.168.(10.10|12.12)/24 192.168.(12.12|10.10)/24')
2757 check_output(*resolvectl_cmd
, 'dns', 'dummy98', '10.10.10.12#ccc.com', '10.10.10.13', '1111:2222::3333', env
=env
)
2758 check_output(*resolvectl_cmd
, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env
=env
)
2759 check_output(*resolvectl_cmd
, 'llmnr', 'dummy98', 'yes', env
=env
)
2760 check_output(*resolvectl_cmd
, 'mdns', 'dummy98', 'no', env
=env
)
2761 check_output(*resolvectl_cmd
, 'dnssec', 'dummy98', 'yes', env
=env
)
2762 check_output(*timedatectl_cmd
, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env
=env
)
2764 with
open(path
) as f
:
2766 self
.assertRegex(data
, r
'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333')
2767 self
.assertRegex(data
, r
'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org')
2768 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2769 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2770 self
.assertRegex(data
, r
'LLMNR=yes')
2771 self
.assertRegex(data
, r
'MDNS=no')
2772 self
.assertRegex(data
, r
'DNSSEC=yes')
2774 check_output(*timedatectl_cmd
, 'revert', 'dummy98', env
=env
)
2776 with
open(path
) as f
:
2778 self
.assertRegex(data
, r
'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333')
2779 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2780 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2781 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2782 self
.assertRegex(data
, r
'LLMNR=yes')
2783 self
.assertRegex(data
, r
'MDNS=no')
2784 self
.assertRegex(data
, r
'DNSSEC=yes')
2786 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
2788 with
open(path
) as f
:
2790 self
.assertRegex(data
, r
'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
2791 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2792 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2793 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2794 self
.assertRegex(data
, r
'LLMNR=no')
2795 self
.assertRegex(data
, r
'MDNS=yes')
2796 self
.assertRegex(data
, r
'DNSSEC=no')
2798 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
2808 '23-active-slave.network',
2809 '23-bond199.network',
2810 '23-primary-slave.network',
2811 '25-bond-active-backup-slave.netdev',
2814 'bond-slave.network']
2817 remove_links(self
.links
)
2818 stop_networkd(show_logs
=False)
2821 remove_links(self
.links
)
2822 remove_unit_from_networkd_path(self
.units
)
2823 stop_networkd(show_logs
=True)
2825 def test_bond_active_slave(self
):
2826 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2828 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2830 output
= check_output('ip -d link show bond199')
2832 self
.assertRegex(output
, 'active_slave dummy98')
2834 def test_bond_primary_slave(self
):
2835 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2837 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2839 output
= check_output('ip -d link show bond199')
2841 self
.assertRegex(output
, 'primary dummy98')
2843 def test_bond_operstate(self
):
2844 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
2845 'bond99.network','bond-slave.network')
2847 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
2849 output
= check_output('ip -d link show dummy98')
2851 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2853 output
= check_output('ip -d link show test1')
2855 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2857 output
= check_output('ip -d link show bond99')
2859 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
2861 self
.wait_operstate('dummy98', 'enslaved')
2862 self
.wait_operstate('test1', 'enslaved')
2863 self
.wait_operstate('bond99', 'routable')
2865 check_output('ip link set dummy98 down')
2867 self
.wait_operstate('dummy98', 'off')
2868 self
.wait_operstate('test1', 'enslaved')
2869 self
.wait_operstate('bond99', 'degraded-carrier')
2871 check_output('ip link set dummy98 up')
2873 self
.wait_operstate('dummy98', 'enslaved')
2874 self
.wait_operstate('test1', 'enslaved')
2875 self
.wait_operstate('bond99', 'routable')
2877 check_output('ip link set dummy98 down')
2878 check_output('ip link set test1 down')
2880 self
.wait_operstate('dummy98', 'off')
2881 self
.wait_operstate('test1', 'off')
2883 if not self
.wait_operstate('bond99', 'no-carrier', setup_timeout
=30, fail_assert
=False):
2884 # Huh? Kernel does not recognize that all slave interfaces are down?
2885 # Let's confirm that networkd's operstate is consistent with ip's result.
2886 self
.assertNotRegex(output
, 'NO-CARRIER')
2888 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
2898 '26-bridge-configure-without-carrier.network',
2899 '26-bridge-mdb-master.network',
2900 '26-bridge-mdb-slave.network',
2901 '26-bridge-slave-interface-1.network',
2902 '26-bridge-slave-interface-2.network',
2903 '26-bridge-vlan-master.network',
2904 '26-bridge-vlan-slave.network',
2905 'bridge99-ignore-carrier-loss.network',
2908 routing_policy_rule_tables
= ['100']
2911 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2912 remove_links(self
.links
)
2913 stop_networkd(show_logs
=False)
2916 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2917 remove_links(self
.links
)
2918 remove_unit_from_networkd_path(self
.units
)
2919 stop_networkd(show_logs
=True)
2921 def test_bridge_vlan(self
):
2922 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
2923 '26-bridge.netdev', '26-bridge-vlan-master.network')
2925 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
2927 output
= check_output('bridge vlan show dev test1')
2929 self
.assertNotRegex(output
, '4063')
2930 for i
in range(4064, 4095):
2931 self
.assertRegex(output
, f
'{i}')
2932 self
.assertNotRegex(output
, '4095')
2934 output
= check_output('bridge vlan show dev bridge99')
2936 self
.assertNotRegex(output
, '4059')
2937 for i
in range(4060, 4095):
2938 self
.assertRegex(output
, f
'{i}')
2939 self
.assertNotRegex(output
, '4095')
2941 def test_bridge_mdb(self
):
2942 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-mdb-slave.network',
2943 '26-bridge.netdev', '26-bridge-mdb-master.network')
2945 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
2947 output
= check_output('bridge mdb show dev bridge99')
2949 self
.assertRegex(output
, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064')
2950 self
.assertRegex(output
, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065')
2952 def test_bridge_property(self
):
2953 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2954 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2957 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2959 output
= check_output('ip -d link show test1')
2961 self
.assertRegex(output
, 'master')
2962 self
.assertRegex(output
, 'bridge')
2964 output
= check_output('ip -d link show dummy98')
2966 self
.assertRegex(output
, 'master')
2967 self
.assertRegex(output
, 'bridge')
2969 output
= check_output('ip addr show bridge99')
2971 self
.assertRegex(output
, '192.168.0.15/24')
2973 output
= check_output('bridge -d link show dummy98')
2975 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
2976 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
2977 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
2978 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
2979 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
2980 # CONFIG_BRIDGE_IGMP_SNOOPING=y
2981 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
2982 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
2983 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
2984 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
2985 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
2986 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'priority'), '23')
2987 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard'), '1')
2988 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'root_block'), '1')
2990 output
= check_output('bridge -d link show test1')
2992 self
.assertEqual(read_bridge_port_attr('bridge99', 'test1', 'priority'), '0')
2994 check_output('ip address add 192.168.0.16/24 dev bridge99')
2997 output
= check_output('ip addr show bridge99')
2999 self
.assertRegex(output
, '192.168.0.16/24')
3002 print('### ip -6 route list table all dev bridge99')
3003 output
= check_output('ip -6 route list table all dev bridge99')
3005 self
.assertRegex(output
, 'ff00::/8 table local metric 256 pref medium')
3007 self
.assertEqual(call('ip link del test1'), 0)
3009 self
.wait_operstate('bridge99', 'degraded-carrier')
3011 check_output('ip link del dummy98')
3013 self
.wait_operstate('bridge99', 'no-carrier')
3015 output
= check_output('ip address show bridge99')
3017 self
.assertRegex(output
, 'NO-CARRIER')
3018 self
.assertNotRegex(output
, '192.168.0.15/24')
3019 self
.assertNotRegex(output
, '192.168.0.16/24')
3021 print('### ip -6 route list table all dev bridge99')
3022 output
= check_output('ip -6 route list table all dev bridge99')
3024 self
.assertRegex(output
, 'ff00::/8 table local metric 256 (linkdown )?pref medium')
3026 def test_bridge_configure_without_carrier(self
):
3027 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-configure-without-carrier.network',
3031 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
3032 for test
in ['no-slave', 'add-slave', 'slave-up', 'slave-no-carrier', 'slave-carrier', 'slave-down']:
3033 with self
.subTest(test
=test
):
3034 if test
== 'no-slave':
3035 # bridge has no slaves; it's up but *might* not have carrier
3036 self
.wait_operstate('bridge99', operstate
=r
'(no-carrier|routable)', setup_state
=None, setup_timeout
=30)
3037 # due to a bug in the kernel, newly-created bridges are brought up
3038 # *with* carrier, unless they have had any setting changed; e.g.
3039 # their mac set, priority set, etc. Then, they will lose carrier
3040 # as soon as a (down) slave interface is added, and regain carrier
3041 # again once the slave interface is brought up.
3042 #self.check_link_attr('bridge99', 'carrier', '0')
3043 elif test
== 'add-slave':
3044 # add slave to bridge, but leave it down; bridge is definitely no-carrier
3045 self
.check_link_attr('test1', 'operstate', 'down')
3046 check_output('ip link set dev test1 master bridge99')
3047 self
.wait_operstate('bridge99', operstate
='no-carrier', setup_state
=None)
3048 self
.check_link_attr('bridge99', 'carrier', '0')
3049 elif test
== 'slave-up':
3050 # bring up slave, which will have carrier; bridge gains carrier
3051 check_output('ip link set dev test1 up')
3052 self
.wait_online(['bridge99:routable'])
3053 self
.check_link_attr('bridge99', 'carrier', '1')
3054 elif test
== 'slave-no-carrier':
3055 # drop slave carrier; bridge loses carrier
3056 check_output('ip link set dev test1 carrier off')
3057 self
.wait_online(['bridge99:no-carrier:no-carrier'])
3058 self
.check_link_attr('bridge99', 'carrier', '0')
3059 elif test
== 'slave-carrier':
3060 # restore slave carrier; bridge gains carrier
3061 check_output('ip link set dev test1 carrier on')
3062 self
.wait_online(['bridge99:routable'])
3063 self
.check_link_attr('bridge99', 'carrier', '1')
3064 elif test
== 'slave-down':
3065 # bring down slave; bridge loses carrier
3066 check_output('ip link set dev test1 down')
3067 self
.wait_online(['bridge99:no-carrier:no-carrier'])
3068 self
.check_link_attr('bridge99', 'carrier', '0')
3070 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
3071 self
.assertRegex(output
, '10.1.2.3')
3072 self
.assertRegex(output
, '10.1.2.1')
3074 def test_bridge_ignore_carrier_loss(self
):
3075 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
3076 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
3077 'bridge99-ignore-carrier-loss.network')
3079 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
3081 check_output('ip address add 192.168.0.16/24 dev bridge99')
3084 check_output('ip link del test1')
3085 check_output('ip link del dummy98')
3088 output
= check_output('ip address show bridge99')
3090 self
.assertRegex(output
, 'NO-CARRIER')
3091 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
3092 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
3094 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
3095 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
3096 'bridge99-ignore-carrier-loss.network')
3098 self
.wait_online(['bridge99:no-carrier'])
3100 for trial
in range(4):
3101 check_output('ip link add dummy98 type dummy')
3102 check_output('ip link set dummy98 up')
3104 check_output('ip link del dummy98')
3106 self
.wait_online(['bridge99:routable', 'dummy98:enslaved'])
3108 output
= check_output('ip address show bridge99')
3110 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
3112 output
= check_output('ip rule list table 100')
3114 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
3116 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
3120 '23-emit-lldp.network',
3125 remove_links(self
.links
)
3126 stop_networkd(show_logs
=False)
3129 remove_links(self
.links
)
3130 remove_unit_from_networkd_path(self
.units
)
3131 stop_networkd(show_logs
=True)
3133 def test_lldp(self
):
3134 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
3136 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
3138 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
3140 self
.assertRegex(output
, 'veth-peer')
3141 self
.assertRegex(output
, 'veth99')
3143 class NetworkdRATests(unittest
.TestCase
, Utilities
):
3148 'ipv6-prefix.network',
3149 'ipv6-prefix-veth.network',
3150 'ipv6-prefix-veth-token-static.network',
3151 'ipv6-prefix-veth-token-prefixstable.network',
3152 'ipv6-prefix-veth-token-prefixstable-without-address.network']
3155 remove_links(self
.links
)
3156 stop_networkd(show_logs
=False)
3159 remove_links(self
.links
)
3160 remove_unit_from_networkd_path(self
.units
)
3161 stop_networkd(show_logs
=True)
3163 def test_ipv6_prefix_delegation(self
):
3164 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
3166 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3168 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3170 self
.assertRegex(output
, 'fe80::')
3171 self
.assertRegex(output
, '2002:da8:1::1')
3173 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3175 self
.assertRegex(output
, '2002:da8:1:0')
3177 def test_ipv6_token_static(self
):
3178 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static.network')
3180 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3182 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3184 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
3185 self
.assertRegex(output
, '2002:da8:1:0:fa:de:ca:fe')
3186 self
.assertRegex(output
, '2002:da8:2:0:1a:2b:3c:4d')
3187 self
.assertRegex(output
, '2002:da8:2:0:fa:de:ca:fe')
3189 def test_ipv6_token_prefixstable(self
):
3190 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable.network')
3192 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3194 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3196 self
.assertRegex(output
, '2002:da8:1:0')
3197 self
.assertRegex(output
, '2002:da8:2:0.*78:9abc') # EUI
3199 def test_ipv6_token_prefixstable_without_address(self
):
3200 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable-without-address.network')
3202 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3204 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3206 self
.assertRegex(output
, '2002:da8:1:0')
3207 self
.assertRegex(output
, '2002:da8:2:0')
3209 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
3214 'dhcp-client.network',
3215 'dhcp-client-timezone-router.network',
3216 'dhcp-server.network',
3217 'dhcp-server-timezone-router.network']
3220 remove_links(self
.links
)
3221 stop_networkd(show_logs
=False)
3224 remove_links(self
.links
)
3225 remove_unit_from_networkd_path(self
.units
)
3226 stop_networkd(show_logs
=True)
3228 def test_dhcp_server(self
):
3229 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
3231 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3233 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3235 self
.assertRegex(output
, '192.168.5.*')
3236 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
3237 self
.assertRegex(output
, 'DNS: 192.168.5.1')
3238 self
.assertRegex(output
, 'NTP: 192.168.5.1')
3240 def test_emit_router_timezone(self
):
3241 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
3243 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3245 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3247 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
3248 self
.assertRegex(output
, '192.168.5.*')
3249 self
.assertRegex(output
, 'Europe/Berlin')
3251 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
3260 'dhcp-client-anonymize.network',
3261 'dhcp-client-decline.network',
3262 'dhcp-client-gateway-ipv4.network',
3263 'dhcp-client-gateway-ipv6.network',
3264 'dhcp-client-gateway-onlink-implicit.network',
3265 'dhcp-client-ipv4-dhcp-settings.network',
3266 'dhcp-client-ipv4-only-ipv6-disabled.network',
3267 'dhcp-client-ipv4-only.network',
3268 'dhcp-client-ipv4-use-routes-use-gateway.network',
3269 'dhcp-client-ipv6-only.network',
3270 'dhcp-client-ipv6-rapid-commit.network',
3271 'dhcp-client-keep-configuration-dhcp-on-stop.network',
3272 'dhcp-client-keep-configuration-dhcp.network',
3273 'dhcp-client-listen-port.network',
3274 'dhcp-client-reassign-static-routes-ipv4.network',
3275 'dhcp-client-reassign-static-routes-ipv6.network',
3276 'dhcp-client-route-metric.network',
3277 'dhcp-client-route-table.network',
3278 'dhcp-client-use-dns-ipv4-and-ra.network',
3279 'dhcp-client-use-dns-ipv4.network',
3280 'dhcp-client-use-dns-no.network',
3281 'dhcp-client-use-dns-yes.network',
3282 'dhcp-client-use-domains.network',
3283 'dhcp-client-vrf.network',
3284 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
3285 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
3286 'dhcp-client-with-static-address.network',
3287 'dhcp-client.network',
3288 'dhcp-server-decline.network',
3289 'dhcp-server-veth-peer.network',
3290 'dhcp-v4-server-veth-peer.network',
3294 stop_dnsmasq(dnsmasq_pid_file
)
3295 remove_links(self
.links
)
3296 stop_networkd(show_logs
=False)
3299 stop_dnsmasq(dnsmasq_pid_file
)
3302 remove_links(self
.links
)
3303 remove_unit_from_networkd_path(self
.units
)
3304 stop_networkd(show_logs
=True)
3306 def test_dhcp_client_ipv6_only(self
):
3307 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3310 self
.wait_online(['veth-peer:carrier'])
3312 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3314 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3316 self
.assertRegex(output
, '2600::')
3317 self
.assertNotRegex(output
, '192.168.5')
3319 output
= check_output('ip addr show dev veth99')
3321 self
.assertRegex(output
, '2600::')
3322 self
.assertNotRegex(output
, '192.168.5')
3323 self
.assertNotRegex(output
, 'tentative')
3325 # Confirm that ipv6 token is not set in the kernel
3326 output
= check_output('ip token show dev veth99')
3328 self
.assertRegex(output
, 'token :: dev veth99')
3330 def test_dhcp_client_ipv4_only(self
):
3331 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
3334 self
.wait_online(['veth-peer:carrier'])
3335 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
3336 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3338 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3340 self
.assertNotRegex(output
, '2600::')
3341 self
.assertRegex(output
, '192.168.5')
3342 self
.assertRegex(output
, '192.168.5.6')
3343 self
.assertRegex(output
, '192.168.5.7')
3345 # checking routes to DNS servers
3346 output
= check_output('ip route show dev veth99')
3348 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3349 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3350 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3352 stop_dnsmasq(dnsmasq_pid_file
)
3353 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8', lease_time
='2m')
3355 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3356 print('Wait for the dynamic address to be renewed')
3359 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3361 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3363 self
.assertNotRegex(output
, '2600::')
3364 self
.assertRegex(output
, '192.168.5')
3365 self
.assertNotRegex(output
, '192.168.5.6')
3366 self
.assertRegex(output
, '192.168.5.7')
3367 self
.assertRegex(output
, '192.168.5.8')
3369 # checking routes to DNS servers
3370 output
= check_output('ip route show dev veth99')
3372 self
.assertNotRegex(output
, r
'192.168.5.6')
3373 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3374 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3375 self
.assertRegex(output
, r
'192.168.5.8 proto dhcp scope link src 192.168.5.181 metric 1024')
3377 def test_dhcp_client_ipv4_use_routes_gateway(self
):
3378 for (routes
, gateway
, dnsroutes
) in itertools
.product([True, False, None], repeat
=3):
3380 with self
.subTest(routes
=routes
, gateway
=gateway
, dnsroutes
=dnsroutes
):
3381 self
._test
_dhcp
_client
_ipv
4_use
_routes
_gateway
(routes
, gateway
, dnsroutes
)
3384 def _test_dhcp_client_ipv4_use_routes_gateway(self
, routes
, gateway
, dnsroutes
):
3385 testunit
= 'dhcp-client-ipv4-use-routes-use-gateway.network'
3386 testunits
= ['25-veth.netdev', 'dhcp-server-veth-peer.network', testunit
]
3388 testunits
.append(f
'{testunit}.d/use-routes-{routes}.conf');
3390 testunits
.append(f
'{testunit}.d/use-gateway-{gateway}.conf');
3391 if dnsroutes
!= None:
3392 testunits
.append(f
'{testunit}.d/use-dns-routes-{dnsroutes}.conf');
3393 copy_unit_to_networkd_unit_path(*testunits
, dropins
=False)
3396 self
.wait_online(['veth-peer:carrier'])
3397 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
3398 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3400 output
= check_output('ip route show dev veth99')
3403 # UseRoutes= defaults to true
3404 useroutes
= routes
in [True, None]
3405 # UseGateway= defaults to useroutes
3406 usegateway
= useroutes
if gateway
== None else gateway
3410 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.181 metric 1024')
3412 self
.assertNotRegex(output
, r
'192.168.5.5')
3416 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.181 metric 1024')
3418 self
.assertNotRegex(output
, r
'default via 192.168.5.1')
3420 # Check RoutesToDNS=, which defaults to false
3422 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3423 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3425 self
.assertNotRegex(output
, r
'192.168.5.6')
3426 self
.assertNotRegex(output
, r
'192.168.5.7')
3428 def test_dhcp_client_ipv4_ipv6(self
):
3429 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
3430 'dhcp-client-ipv4-only.network')
3432 self
.wait_online(['veth-peer:carrier'])
3434 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3436 # link become 'routable' when at least one protocol provide an valid address.
3437 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3438 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3440 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3442 self
.assertRegex(output
, '2600::')
3443 self
.assertRegex(output
, '192.168.5')
3445 def test_dhcp_client_settings(self
):
3446 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
3449 self
.wait_online(['veth-peer:carrier'])
3451 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3453 print('## ip address show dev veth99')
3454 output
= check_output('ip address show dev veth99')
3456 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3457 self
.assertRegex(output
, '192.168.5')
3458 self
.assertRegex(output
, '1492')
3460 print('## ip route show table main dev veth99')
3461 output
= check_output('ip route show table main dev veth99')
3464 main_table_is_empty
= output
== ''
3465 if not main_table_is_empty
:
3466 self
.assertNotRegex(output
, 'proto dhcp')
3468 print('## ip route show table 211 dev veth99')
3469 output
= check_output('ip route show table 211 dev veth99')
3471 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
3472 if main_table_is_empty
:
3473 self
.assertRegex(output
, '192.168.5.0/24 proto dhcp')
3474 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
3475 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
3477 print('## dnsmasq log')
3478 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
3479 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
3480 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
3481 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
3483 def test_dhcp6_client_settings_rapidcommit_true(self
):
3484 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3486 self
.wait_online(['veth-peer:carrier'])
3488 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3490 output
= check_output('ip address show dev veth99')
3492 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3493 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
3495 def test_dhcp6_client_settings_rapidcommit_false(self
):
3496 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
3498 self
.wait_online(['veth-peer:carrier'])
3500 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3502 output
= check_output('ip address show dev veth99')
3504 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3505 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
3507 def test_dhcp_client_settings_anonymize(self
):
3508 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
3510 self
.wait_online(['veth-peer:carrier'])
3512 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3514 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
3515 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
3516 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
3518 def test_dhcp_client_listen_port(self
):
3519 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
3521 self
.wait_online(['veth-peer:carrier'])
3522 start_dnsmasq('--dhcp-alternate-port=67,5555')
3523 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3525 output
= check_output('ip -4 address show dev veth99')
3527 self
.assertRegex(output
, '192.168.5.* dynamic')
3529 def test_dhcp_client_with_static_address(self
):
3530 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
3531 'dhcp-client-with-static-address.network')
3533 self
.wait_online(['veth-peer:carrier'])
3535 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3537 output
= check_output('ip address show dev veth99 scope global')
3539 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
3540 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
3542 output
= check_output('ip route show dev veth99')
3544 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
3545 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
3546 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
3547 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
3549 def test_dhcp_route_table_id(self
):
3550 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
3552 self
.wait_online(['veth-peer:carrier'])
3554 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3556 output
= check_output('ip route show table 12')
3558 self
.assertRegex(output
, 'veth99 proto dhcp')
3559 self
.assertRegex(output
, '192.168.5.1')
3561 def test_dhcp_route_metric(self
):
3562 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
3564 self
.wait_online(['veth-peer:carrier'])
3566 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3568 output
= check_output('ip route show dev veth99')
3570 self
.assertRegex(output
, 'metric 24')
3572 def test_dhcp_client_reassign_static_routes_ipv4(self
):
3573 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3574 'dhcp-client-reassign-static-routes-ipv4.network')
3576 self
.wait_online(['veth-peer:carrier'])
3577 start_dnsmasq(lease_time
='2m')
3578 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3580 output
= check_output('ip address show dev veth99 scope global')
3582 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3584 output
= check_output('ip route show dev veth99')
3586 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3587 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3588 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3589 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3591 stop_dnsmasq(dnsmasq_pid_file
)
3592 start_dnsmasq(ipv4_range
='192.168.5.210,192.168.5.220', lease_time
='2m')
3594 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3595 print('Wait for the dynamic address to be renewed')
3598 self
.wait_online(['veth99:routable'])
3600 output
= check_output('ip route show dev veth99')
3602 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3603 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3604 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3605 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3607 def test_dhcp_client_reassign_static_routes_ipv6(self
):
3608 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3609 'dhcp-client-reassign-static-routes-ipv6.network')
3611 self
.wait_online(['veth-peer:carrier'])
3612 start_dnsmasq(lease_time
='2m')
3613 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3615 output
= check_output('ip address show dev veth99 scope global')
3617 self
.assertRegex(output
, r
'inet6 2600::[0-9a-f]*/128 scope global (noprefixroute dynamic|dynamic noprefixroute)')
3619 output
= check_output('ip -6 route show dev veth99')
3621 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3622 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3624 stop_dnsmasq(dnsmasq_pid_file
)
3625 start_dnsmasq(ipv6_range
='2600::30,2600::40', lease_time
='2m')
3627 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3628 print('Wait for the dynamic address to be renewed')
3631 self
.wait_online(['veth99:routable'])
3633 output
= check_output('ip -6 route show dev veth99')
3635 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3636 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3638 def test_dhcp_keep_configuration_dhcp(self
):
3639 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
3641 self
.wait_online(['veth-peer:carrier'])
3642 start_dnsmasq(lease_time
='2m')
3643 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3645 output
= check_output('ip address show dev veth99 scope global')
3647 self
.assertRegex(output
, r
'192.168.5.*')
3649 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3651 self
.assertRegex(output
, r
'192.168.5.*')
3653 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
3654 stop_dnsmasq(dnsmasq_pid_file
)
3656 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3657 print('Wait for the dynamic address to be expired')
3660 print('The lease address should be kept after lease expired')
3661 output
= check_output('ip address show dev veth99 scope global')
3663 self
.assertRegex(output
, r
'192.168.5.*')
3665 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3667 self
.assertRegex(output
, r
'192.168.5.*')
3669 check_output('systemctl stop systemd-networkd.socket')
3670 check_output('systemctl stop systemd-networkd.service')
3672 print('The lease address should be kept after networkd stopped')
3673 output
= check_output('ip address show dev veth99 scope global')
3675 self
.assertRegex(output
, r
'192.168.5.*')
3677 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3679 self
.assertRegex(output
, r
'192.168.5.*')
3682 self
.wait_online(['veth-peer:routable'])
3684 print('Still the lease address should be kept after networkd restarted')
3685 output
= check_output('ip address show dev veth99 scope global')
3687 self
.assertRegex(output
, r
'192.168.5.*')
3689 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3691 self
.assertRegex(output
, r
'192.168.5.*')
3693 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
3694 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
3696 self
.wait_online(['veth-peer:carrier'])
3697 start_dnsmasq(lease_time
='2m')
3698 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3700 output
= check_output('ip address show dev veth99 scope global')
3702 self
.assertRegex(output
, r
'192.168.5.*')
3704 stop_dnsmasq(dnsmasq_pid_file
)
3705 check_output('systemctl stop systemd-networkd.socket')
3706 check_output('systemctl stop systemd-networkd.service')
3708 output
= check_output('ip address show dev veth99 scope global')
3710 self
.assertRegex(output
, r
'192.168.5.*')
3713 self
.wait_online(['veth-peer:routable'])
3715 output
= check_output('ip address show dev veth99 scope global')
3717 self
.assertNotRegex(output
, r
'192.168.5.*')
3719 def test_dhcp_client_reuse_address_as_static(self
):
3720 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
3722 self
.wait_online(['veth-peer:carrier'])
3724 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3726 # link become 'routable' when at least one protocol provide an valid address.
3727 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3728 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3730 output
= check_output('ip address show dev veth99 scope global')
3732 self
.assertRegex(output
, '192.168.5')
3733 self
.assertRegex(output
, '2600::')
3735 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
3736 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
3737 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
3738 print(static_network
)
3740 remove_unit_from_networkd_path(['dhcp-client.network'])
3742 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
3743 f
.write(static_network
)
3745 # When networkd started, the links are already configured, so let's wait for 5 seconds
3746 # the links to be re-configured.
3748 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3750 output
= check_output('ip -4 address show dev veth99 scope global')
3752 self
.assertRegex(output
, '192.168.5')
3753 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3755 output
= check_output('ip -6 address show dev veth99 scope global')
3757 self
.assertRegex(output
, '2600::')
3758 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3760 @expectedFailureIfModuleIsNotAvailable('vrf')
3761 def test_dhcp_client_vrf(self
):
3762 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
3763 '25-vrf.netdev', '25-vrf.network')
3765 self
.wait_online(['veth-peer:carrier'])
3767 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
3769 # link become 'routable' when at least one protocol provide an valid address.
3770 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3771 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3773 print('## ip -d link show dev vrf99')
3774 output
= check_output('ip -d link show dev vrf99')
3776 self
.assertRegex(output
, 'vrf table 42')
3778 print('## ip address show vrf vrf99')
3779 output
= check_output('ip address show vrf vrf99')
3781 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3782 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3783 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3784 self
.assertRegex(output
, 'inet6 .* scope link')
3786 print('## ip address show dev veth99')
3787 output
= check_output('ip address show dev veth99')
3789 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3790 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3791 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3792 self
.assertRegex(output
, 'inet6 .* scope link')
3794 print('## ip route show vrf vrf99')
3795 output
= check_output('ip route show vrf vrf99')
3797 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
3798 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
3799 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
3800 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
3801 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
3803 print('## ip route show table main dev veth99')
3804 output
= check_output('ip route show table main dev veth99')
3806 self
.assertEqual(output
, '')
3808 def test_dhcp_client_gateway_ipv4(self
):
3809 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3810 'dhcp-client-gateway-ipv4.network')
3812 self
.wait_online(['veth-peer:carrier'])
3814 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3816 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3818 self
.assertRegex(output
, '10.0.0.0/8 via 192.168.5.1 proto static')
3820 def test_dhcp_client_gateway_ipv6(self
):
3821 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3822 'dhcp-client-gateway-ipv6.network')
3824 self
.wait_online(['veth-peer:carrier'])
3826 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3828 output
= check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
3830 self
.assertRegex(output
, 'via fe80::1034:56ff:fe78:9abd')
3832 def test_dhcp_client_gateway_onlink_implicit(self
):
3833 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3834 'dhcp-client-gateway-onlink-implicit.network')
3836 self
.wait_online(['veth-peer:carrier'])
3838 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3840 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3842 self
.assertRegex(output
, '192.168.5')
3844 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3846 self
.assertRegex(output
, 'onlink')
3847 output
= check_output('ip route list dev veth99 192.168.100.0/24')
3849 self
.assertRegex(output
, 'onlink')
3851 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
3852 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3853 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
3855 self
.wait_online(['veth-peer:carrier'])
3856 start_dnsmasq(lease_time
='2m')
3857 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3859 output
= check_output('ip address show dev veth99')
3862 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3863 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3864 output
= check_output('ip -6 address show dev veth99 scope link')
3865 self
.assertRegex(output
, 'inet6 .* scope link')
3866 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3867 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3868 output
= check_output('ip -4 address show dev veth99 scope link')
3869 self
.assertNotRegex(output
, 'inet .* scope link')
3871 print('Wait for the dynamic address to be expired')
3874 output
= check_output('ip address show dev veth99')
3877 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3878 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3879 output
= check_output('ip -6 address show dev veth99 scope link')
3880 self
.assertRegex(output
, 'inet6 .* scope link')
3881 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3882 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3883 output
= check_output('ip -4 address show dev veth99 scope link')
3884 self
.assertNotRegex(output
, 'inet .* scope link')
3886 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
3888 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
3889 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3890 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
3892 self
.wait_online(['veth99:degraded', 'veth-peer:routable'])
3894 output
= check_output('ip address show dev veth99')
3897 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3898 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3899 output
= check_output('ip -6 address show dev veth99 scope link')
3900 self
.assertRegex(output
, 'inet6 .* scope link')
3901 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3902 self
.assertNotRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3903 output
= check_output('ip -4 address show dev veth99 scope link')
3904 self
.assertRegex(output
, 'inet .* scope link')
3906 def test_dhcp_client_route_remove_on_renew(self
):
3907 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3908 'dhcp-client-ipv4-only-ipv6-disabled.network')
3910 self
.wait_online(['veth-peer:carrier'])
3911 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
3912 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3914 # test for issue #12490
3916 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3918 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3920 for line
in output
.splitlines():
3921 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3922 address1
= line
.split()[1].split('/')[0]
3925 output
= check_output('ip -4 route show dev veth99')
3927 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3928 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3930 stop_dnsmasq(dnsmasq_pid_file
)
3931 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
3933 print('Wait for the dynamic address to be expired')
3936 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3938 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3940 for line
in output
.splitlines():
3941 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3942 address2
= line
.split()[1].split('/')[0]
3945 self
.assertNotEqual(address1
, address2
)
3947 output
= check_output('ip -4 route show dev veth99')
3949 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3950 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3951 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
3952 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
3954 def test_dhcp_client_use_dns_yes(self
):
3955 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-yes.network')
3958 self
.wait_online(['veth-peer:carrier'])
3959 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3960 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3962 # link become 'routable' when at least one protocol provide an valid address.
3963 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3964 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3967 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3969 self
.assertRegex(output
, '192.168.5.1')
3970 self
.assertRegex(output
, '2600::1')
3972 def test_dhcp_client_use_dns_no(self
):
3973 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-no.network')
3976 self
.wait_online(['veth-peer:carrier'])
3977 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3978 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3980 # link become 'routable' when at least one protocol provide an valid address.
3981 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3982 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3985 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3987 self
.assertNotRegex(output
, '192.168.5.1')
3988 self
.assertNotRegex(output
, '2600::1')
3990 def test_dhcp_client_use_dns_ipv4(self
):
3991 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4.network')
3994 self
.wait_online(['veth-peer:carrier'])
3995 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3996 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3998 # link become 'routable' when at least one protocol provide an valid address.
3999 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4000 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4003 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
4005 self
.assertRegex(output
, '192.168.5.1')
4006 self
.assertNotRegex(output
, '2600::1')
4008 def test_dhcp_client_use_dns_ipv4_and_ra(self
):
4009 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4-and-ra.network')
4012 self
.wait_online(['veth-peer:carrier'])
4013 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
4014 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4016 # link become 'routable' when at least one protocol provide an valid address.
4017 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4018 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4021 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
4023 self
.assertRegex(output
, '192.168.5.1')
4024 self
.assertRegex(output
, '2600::1')
4026 def test_dhcp_client_use_domains(self
):
4027 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-domains.network')
4030 self
.wait_online(['veth-peer:carrier'])
4031 start_dnsmasq('--dhcp-option=option:domain-search,example.com')
4032 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4034 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4036 self
.assertRegex(output
, 'Search Domains: example.com')
4039 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
4041 self
.assertRegex(output
, 'example.com')
4043 def test_dhcp_client_decline(self
):
4044 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-decline.network', 'dhcp-client-decline.network')
4047 self
.wait_online(['veth-peer:carrier'])
4048 rc
= call(*wait_online_cmd
, '--timeout=10s', '--interface=veth99:routable', env
=env
)
4049 self
.assertTrue(rc
== 1)
4051 class NetworkdIPv6PrefixTests(unittest
.TestCase
, Utilities
):
4056 'ipv6ra-prefix-client.network',
4057 'ipv6ra-prefix.network'
4061 remove_links(self
.links
)
4062 stop_networkd(show_logs
=False)
4066 remove_links(self
.links
)
4067 remove_unit_from_networkd_path(self
.units
)
4068 stop_networkd(show_logs
=True)
4070 def test_ipv6_route_prefix(self
):
4071 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client.network', 'ipv6ra-prefix.network')
4074 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4076 output
= check_output('ip -6 route show dev veth-peer')
4078 self
.assertRegex(output
, '2001:db8:0:1::/64 proto ra')
4080 output
= check_output('ip addr show dev veth99')
4082 self
.assertNotRegex(output
, '2001:db8:0:1')
4083 self
.assertRegex(output
, '2001:db8:0:2')
4085 class NetworkdMTUTests(unittest
.TestCase
, Utilities
):
4090 '12-dummy-mtu.netdev',
4091 '12-dummy-mtu.link',
4096 remove_links(self
.links
)
4097 stop_networkd(show_logs
=False)
4101 remove_links(self
.links
)
4102 remove_unit_from_networkd_path(self
.units
)
4103 stop_networkd(show_logs
=True)
4105 def check_mtu(self
, mtu
, ipv6_mtu
=None, reset
=True):
4111 self
.wait_online(['dummy98:routable'])
4112 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
4113 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
4115 # test normal restart
4117 self
.wait_online(['dummy98:routable'])
4118 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
4119 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
4122 self
.reset_check_mtu(mtu
, ipv6_mtu
)
4124 def reset_check_mtu(self
, mtu
, ipv6_mtu
=None):
4125 ''' test setting mtu/ipv6_mtu with interface already up '''
4128 # note - changing the device mtu resets the ipv6 mtu
4129 run('ip link set up mtu 1501 dev dummy98')
4130 run('ip link set up mtu 1500 dev dummy98')
4131 self
.assertEqual(read_link_attr('dummy98', 'mtu'), '1500')
4132 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), '1500')
4134 self
.check_mtu(mtu
, ipv6_mtu
, reset
=False)
4136 def test_mtu_network(self
):
4137 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
4138 self
.check_mtu('1600')
4140 def test_mtu_netdev(self
):
4141 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network', dropins
=False)
4142 # note - MTU set by .netdev happens ONLY at device creation!
4143 self
.check_mtu('1600', reset
=False)
4145 def test_mtu_link(self
):
4146 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', dropins
=False)
4147 # must reload udev because it only picks up new files after 3 second delay
4148 call('udevadm control --reload')
4149 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
4150 self
.check_mtu('1600', reset
=False)
4152 def test_ipv6_mtu(self
):
4153 ''' set ipv6 mtu without setting device mtu '''
4154 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
4155 self
.check_mtu('1500', '1400')
4157 def test_ipv6_mtu_toolarge(self
):
4158 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
4159 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
4160 self
.check_mtu('1500', '1500')
4162 def test_mtu_network_ipv6_mtu(self
):
4163 ''' set ipv6 mtu and set device mtu via network file '''
4164 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
4165 self
.check_mtu('1600', '1550')
4167 def test_mtu_netdev_ipv6_mtu(self
):
4168 ''' set ipv6 mtu and set device mtu via netdev file '''
4169 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
4170 self
.check_mtu('1600', '1550', reset
=False)
4172 def test_mtu_link_ipv6_mtu(self
):
4173 ''' set ipv6 mtu and set device mtu via link file '''
4174 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
4175 # must reload udev because it only picks up new files after 3 second delay
4176 call('udevadm control --reload')
4177 self
.check_mtu('1600', '1550', reset
=False)
4180 if __name__
== '__main__':
4181 parser
= argparse
.ArgumentParser()
4182 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
4183 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
4184 parser
.add_argument('--resolved', help='Path to systemd-resolved', dest
='resolved_bin')
4185 parser
.add_argument('--udevd', help='Path to systemd-udevd', dest
='udevd_bin')
4186 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
4187 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
4188 parser
.add_argument('--resolvectl', help='Path to resolvectl', dest
='resolvectl_bin')
4189 parser
.add_argument('--timedatectl', help='Path to timedatectl', dest
='timedatectl_bin')
4190 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
4191 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
4192 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
4193 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
4194 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
4195 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
4198 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
:
4199 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
4200 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
4201 resolved_bin
= os
.path
.join(ns
.build_dir
, 'systemd-resolved')
4202 udevd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-udevd')
4203 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
4204 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
4205 resolvectl_bin
= os
.path
.join(ns
.build_dir
, 'resolvectl')
4206 timedatectl_bin
= os
.path
.join(ns
.build_dir
, 'timedatectl')
4209 networkd_bin
= ns
.networkd_bin
4211 resolved_bin
= ns
.resolved_bin
4213 udevd_bin
= ns
.udevd_bin
4214 if ns
.wait_online_bin
:
4215 wait_online_bin
= ns
.wait_online_bin
4216 if ns
.networkctl_bin
:
4217 networkctl_bin
= ns
.networkctl_bin
4218 if ns
.resolvectl_bin
:
4219 resolvectl_bin
= ns
.resolvectl_bin
4220 if ns
.timedatectl_bin
:
4221 timedatectl_bin
= ns
.timedatectl_bin
4223 use_valgrind
= ns
.use_valgrind
4224 enable_debug
= ns
.enable_debug
4225 asan_options
= ns
.asan_options
4226 lsan_options
= ns
.lsan_options
4227 ubsan_options
= ns
.ubsan_options
4230 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
4231 resolvectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin
]
4232 timedatectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin
]
4233 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
4235 networkctl_cmd
= [networkctl_bin
]
4236 resolvectl_cmd
= [resolvectl_bin
]
4237 timedatectl_cmd
= [timedatectl_bin
]
4238 wait_online_cmd
= [wait_online_bin
]
4241 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
4243 env
.update({ 'ASAN_OPTIONS' : asan_options
})
4245 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
4247 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
4250 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,