2 # SPDX-License-Identifier: LGPL-2.1-or-later
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_conf_dropin_path
='/run/systemd/networkd.conf.d'
20 networkd_ci_path
='/run/networkd-ci'
21 network_sysctl_ipv6_path
='/proc/sys/net/ipv6/conf'
22 network_sysctl_ipv4_path
='/proc/sys/net/ipv4/conf'
24 dnsmasq_pid_file
='/run/networkd-ci/test-test-dnsmasq.pid'
25 dnsmasq_log_file
='/run/networkd-ci/test-dnsmasq-log-file'
27 systemd_lib_paths
=['/usr/lib/systemd', '/lib/systemd']
28 which_paths
=':'.join(systemd_lib_paths
+ os
.getenv('PATH', os
.defpath
).lstrip(':').split(':'))
30 networkd_bin
=shutil
.which('systemd-networkd', path
=which_paths
)
31 resolved_bin
=shutil
.which('systemd-resolved', path
=which_paths
)
32 udevd_bin
=shutil
.which('systemd-udevd', path
=which_paths
)
33 wait_online_bin
=shutil
.which('systemd-networkd-wait-online', path
=which_paths
)
34 networkctl_bin
=shutil
.which('networkctl', path
=which_paths
)
35 resolvectl_bin
=shutil
.which('resolvectl', path
=which_paths
)
36 timedatectl_bin
=shutil
.which('timedatectl', path
=which_paths
)
47 def check_output(*command
, **kwargs
):
48 # This replaces both check_output and check_call (output can be ignored)
49 command
= command
[0].split() + list(command
[1:])
50 return subprocess
.check_output(command
, universal_newlines
=True, **kwargs
).rstrip()
52 def call(*command
, **kwargs
):
53 command
= command
[0].split() + list(command
[1:])
54 return subprocess
.call(command
, universal_newlines
=True, **kwargs
)
56 def run(*command
, **kwargs
):
57 command
= command
[0].split() + list(command
[1:])
58 return subprocess
.run(command
, universal_newlines
=True, **kwargs
)
60 def is_module_available(module_name
):
61 lsmod_output
= check_output('lsmod')
62 module_re
= re
.compile(rf
'^{re.escape(module_name)}\b', re
.MULTILINE
)
63 return module_re
.search(lsmod_output
) or not call('modprobe', module_name
, stderr
=subprocess
.DEVNULL
)
65 def expectedFailureIfModuleIsNotAvailable(module_name
):
67 if not is_module_available(module_name
):
68 return unittest
.expectedFailure(func
)
73 def expectedFailureIfERSPANModuleIsNotAvailable():
75 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
)
77 call('ip link del erspan99')
80 return unittest
.expectedFailure(func
)
84 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable():
86 rc
= call('ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7', stderr
=subprocess
.DEVNULL
)
88 call('ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
91 return unittest
.expectedFailure(func
)
95 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
97 rc
= call('ip rule add not from 192.168.100.19 ipproto tcp table 7', stderr
=subprocess
.DEVNULL
)
99 call('ip rule del not from 192.168.100.19 ipproto tcp table 7')
102 return unittest
.expectedFailure(func
)
106 def expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable():
109 rc
= call('ip rule add from 192.168.100.19 table 7 uidrange 200-300', stderr
=subprocess
.DEVNULL
)
111 ret
= run('ip rule list from 192.168.100.19 table 7', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
112 if ret
.returncode
== 0 and 'uidrange 200-300' in ret
.stdout
.rstrip():
114 call('ip rule del from 192.168.100.19 table 7 uidrange 200-300')
119 return unittest
.expectedFailure(func
)
123 def expectedFailureIfLinkFileFieldIsNotSet():
126 rc
= call('ip link add name dummy99 type dummy', stderr
=subprocess
.DEVNULL
)
128 ret
= run('udevadm info -w10s /sys/class/net/dummy99', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
129 if ret
.returncode
== 0 and 'E: ID_NET_LINK_FILE=' in ret
.stdout
.rstrip():
131 call('ip link del dummy99')
136 return unittest
.expectedFailure(func
)
140 def expectedFailureIfNexthopIsNotAvailable():
142 rc
= call('ip nexthop list', stderr
=subprocess
.DEVNULL
)
146 return unittest
.expectedFailure(func
)
150 def expectedFailureIfRTA_VIAIsNotSupported():
152 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
153 call('ip link set up dev dummy98', stderr
=subprocess
.DEVNULL
)
154 call('ip route add 2001:1234:5:8fff:ff:ff:ff:fe/128 dev dummy98', stderr
=subprocess
.DEVNULL
)
155 rc
= call('ip route add 10.10.10.10 via inet6 2001:1234:5:8fff:ff:ff:ff:fe dev dummy98', stderr
=subprocess
.DEVNULL
)
156 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
160 return unittest
.expectedFailure(func
)
164 def expectedFailureIfAlternativeNameIsNotAvailable():
166 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
167 rc
= call('ip link prop add dev dummy98 altname hogehogehogehogehoge', stderr
=subprocess
.DEVNULL
)
168 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
172 return unittest
.expectedFailure(func
)
176 def expectedFailureIfNetdevsimWithSRIOVIsNotAvailable():
178 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
179 rc
= call('modprobe netdevsim', stderr
=subprocess
.DEVNULL
)
181 return unittest
.expectedFailure(func
)
184 with
open('/sys/bus/netdevsim/new_device', mode
='w') as f
:
186 except Exception as error
:
187 return unittest
.expectedFailure(func
)
189 call('udevadm settle')
190 call('udevadm info -w10s /sys/devices/netdevsim99/net/eni99np1', stderr
=subprocess
.DEVNULL
)
192 with
open('/sys/class/net/eni99np1/device/sriov_numvfs', mode
='w') as f
:
194 except Exception as error
:
195 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
196 return unittest
.expectedFailure(func
)
198 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
203 def expectedFailureIfCAKEIsNotAvailable():
205 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
206 rc
= call('tc qdisc add dev dummy98 parent root cake', stderr
=subprocess
.DEVNULL
)
207 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
211 return unittest
.expectedFailure(func
)
215 def expectedFailureIfPIEIsNotAvailable():
217 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
218 rc
= call('tc qdisc add dev dummy98 parent root pie', stderr
=subprocess
.DEVNULL
)
219 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
223 return unittest
.expectedFailure(func
)
227 def expectedFailureIfHHFIsNotAvailable():
229 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
230 rc
= call('tc qdisc add dev dummy98 parent root hhf', stderr
=subprocess
.DEVNULL
)
231 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
235 return unittest
.expectedFailure(func
)
239 def expectedFailureIfETSIsNotAvailable():
241 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
242 rc
= call('tc qdisc add dev dummy98 parent root ets bands 10', stderr
=subprocess
.DEVNULL
)
243 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
247 return unittest
.expectedFailure(func
)
251 def expectedFailureIfFQPIEIsNotAvailable():
253 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
254 rc
= call('tc qdisc add dev dummy98 parent root fq_pie', stderr
=subprocess
.DEVNULL
)
255 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
259 return unittest
.expectedFailure(func
)
266 os
.makedirs(network_unit_file_path
, exist_ok
=True)
267 os
.makedirs(networkd_conf_dropin_path
, exist_ok
=True)
268 os
.makedirs(networkd_ci_path
, exist_ok
=True)
270 shutil
.rmtree(networkd_ci_path
)
271 copytree(os
.path
.join(os
.path
.dirname(os
.path
.abspath(__file__
)), 'conf'), networkd_ci_path
)
273 for u
in ['systemd-networkd.socket', 'systemd-networkd.service', 'systemd-resolved.service',
274 'systemd-udevd-kernel.socket', 'systemd-udevd-control.socket', 'systemd-udevd.service',
275 'firewalld.service']:
276 if call(f
'systemctl is-active --quiet {u}') == 0:
277 check_output(f
'systemctl stop {u}')
278 running_units
.append(u
)
282 'StartLimitIntervalSec=0',
289 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin
,
293 drop_in
+= ['ExecStart=!!' + networkd_bin
]
295 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
297 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
299 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
301 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
302 if asan_options
or lsan_options
or ubsan_options
:
303 drop_in
+= ['SystemCallFilter=']
304 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
305 drop_in
+= ['MemoryDenyWriteExecute=no']
307 os
.makedirs('/run/systemd/system/systemd-networkd.service.d', exist_ok
=True)
308 with
open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode
='w') as f
:
309 f
.write('\n'.join(drop_in
))
317 drop_in
+= ['ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + resolved_bin
]
319 drop_in
+= ['ExecStart=!!' + resolved_bin
]
321 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
323 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
325 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
327 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
328 if asan_options
or lsan_options
or ubsan_options
:
329 drop_in
+= ['SystemCallFilter=']
330 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
331 drop_in
+= ['MemoryDenyWriteExecute=no']
333 os
.makedirs('/run/systemd/system/systemd-resolved.service.d', exist_ok
=True)
334 with
open('/run/systemd/system/systemd-resolved.service.d/00-override.conf', mode
='w') as f
:
335 f
.write('\n'.join(drop_in
))
340 'ExecStart=!!' + udevd_bin
,
343 os
.makedirs('/run/systemd/system/systemd-udevd.service.d', exist_ok
=True)
344 with
open('/run/systemd/system/systemd-udevd.service.d/00-override.conf', mode
='w') as f
:
345 f
.write('\n'.join(drop_in
))
347 check_output('systemctl daemon-reload')
348 print(check_output('systemctl cat systemd-networkd.service'))
349 print(check_output('systemctl cat systemd-resolved.service'))
350 print(check_output('systemctl cat systemd-udevd.service'))
351 check_output('systemctl restart systemd-resolved')
352 check_output('systemctl restart systemd-udevd')
354 def tearDownModule():
357 shutil
.rmtree(networkd_ci_path
)
359 for u
in ['systemd-networkd.socket', 'systemd-networkd.service', 'systemd-resolved.service']:
360 check_output(f
'systemctl stop {u}')
362 shutil
.rmtree('/run/systemd/system/systemd-networkd.service.d')
363 shutil
.rmtree('/run/systemd/system/systemd-resolved.service.d')
364 shutil
.rmtree('/run/systemd/system/systemd-udevd.service.d')
365 check_output('systemctl daemon-reload')
366 check_output('systemctl restart systemd-udevd.service')
368 for u
in running_units
:
369 check_output(f
'systemctl start {u}')
371 def read_link_attr(*args
):
372 with
open(os
.path
.join('/sys/class/net/', *args
)) as f
:
373 return f
.readline().strip()
375 def read_bridge_port_attr(bridge
, link
, attribute
):
376 path_bridge
= os
.path
.join('/sys/devices/virtual/net', bridge
)
377 path_port
= 'lower_' + link
+ '/brport'
378 path
= os
.path
.join(path_bridge
, path_port
)
380 with
open(os
.path
.join(path
, attribute
)) as f
:
381 return f
.readline().strip()
383 def link_exists(link
):
384 return os
.path
.exists(os
.path
.join('/sys/class/net', link
))
386 def remove_links(links
):
388 if link_exists(link
):
389 call('ip link del dev', link
)
392 def remove_fou_ports(ports
):
394 call('ip fou del port', port
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
396 def remove_routing_policy_rule_tables(tables
):
400 rc
= call('ip rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
403 rc
= call('ip -6 rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
405 def remove_routes(routes
):
406 for route_type
, addr
in routes
:
407 call('ip route del', route_type
, addr
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
409 def remove_blackhole_nexthops():
410 ret
= run('ip nexthop show dev lo', stdout
=subprocess
.PIPE
, stderr
=subprocess
.DEVNULL
)
411 if ret
.returncode
== 0:
412 for line
in ret
.stdout
.rstrip().splitlines():
414 call(f
'ip nexthop del id {id}')
416 def remove_l2tp_tunnels(tunnel_ids
):
417 output
= check_output('ip l2tp show tunnel')
418 for tid
in tunnel_ids
:
419 words
='Tunnel ' + tid
+ ', encap'
421 call('ip l2tp del tunnel tid', tid
)
424 def read_ipv6_sysctl_attr(link
, attribute
):
425 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, link
), attribute
)) as f
:
426 return f
.readline().strip()
428 def read_ipv4_sysctl_attr(link
, attribute
):
429 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv4_path
, link
), attribute
)) as f
:
430 return f
.readline().strip()
432 def copy_unit_to_networkd_unit_path(*units
, dropins
=True):
433 """Copy networkd unit files into the testbed.
435 Any networkd unit file type can be specified, as well as drop-in files.
437 By default, all drop-ins for a specified unit file are copied in;
438 to avoid that specify dropins=False.
440 When a drop-in file is specified, its unit file is also copied in automatically.
444 if dropins
and os
.path
.exists(os
.path
.join(networkd_ci_path
, unit
+ '.d')):
445 copytree(os
.path
.join(networkd_ci_path
, unit
+ '.d'), os
.path
.join(network_unit_file_path
, unit
+ '.d'))
446 if unit
.endswith('.conf'):
448 dropindir
= os
.path
.join(network_unit_file_path
, os
.path
.dirname(dropin
))
449 os
.makedirs(dropindir
, exist_ok
=True)
450 shutil
.copy(os
.path
.join(networkd_ci_path
, dropin
), dropindir
)
451 unit
= os
.path
.dirname(dropin
).rstrip('.d')
452 shutil
.copy(os
.path
.join(networkd_ci_path
, unit
), network_unit_file_path
)
454 def remove_unit_from_networkd_path(units
):
455 """Remove previously copied unit files from the testbed.
457 Drop-ins will be removed automatically.
460 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
))):
461 os
.remove(os
.path
.join(network_unit_file_path
, unit
))
462 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
+ '.d'))):
463 shutil
.rmtree(os
.path
.join(network_unit_file_path
, unit
+ '.d'))
465 def copy_networkd_conf_dropin(*dropins
):
466 """Copy networkd.conf dropin files into the testbed."""
467 for dropin
in dropins
:
468 shutil
.copy(os
.path
.join(networkd_ci_path
, dropin
), networkd_conf_dropin_path
)
470 def remove_networkd_conf_dropin(dropins
):
471 """Remove previously copied networkd.conf dropin files from the testbed."""
472 for dropin
in dropins
:
473 if (os
.path
.exists(os
.path
.join(networkd_conf_dropin_path
, dropin
))):
474 os
.remove(os
.path
.join(networkd_conf_dropin_path
, dropin
))
476 def start_dnsmasq(additional_options
='', ipv4_range
='192.168.5.10,192.168.5.200', ipv6_range
='2600::10,2600::20', lease_time
='1h'):
477 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 --port=0 ' + additional_options
478 check_output(dnsmasq_command
)
480 def stop_dnsmasq(pid_file
):
481 if os
.path
.exists(pid_file
):
482 with
open(pid_file
, 'r') as f
:
483 pid
= f
.read().rstrip(' \t\r\n\0')
484 os
.kill(int(pid
), signal
.SIGTERM
)
488 def search_words_in_dnsmasq_log(words
, show_all
=False):
489 if os
.path
.exists(dnsmasq_log_file
):
490 with
open (dnsmasq_log_file
) as in_file
:
491 contents
= in_file
.read()
494 for line
in contents
.splitlines():
497 print("%s, %s" % (words
, line
))
501 def remove_lease_file():
502 if os
.path
.exists(os
.path
.join(networkd_ci_path
, 'lease')):
503 os
.remove(os
.path
.join(networkd_ci_path
, 'lease'))
505 def remove_log_file():
506 if os
.path
.exists(dnsmasq_log_file
):
507 os
.remove(dnsmasq_log_file
)
509 def remove_networkd_state_files():
510 if os
.path
.exists(os
.path
.join(networkd_runtime_directory
, 'state')):
511 os
.remove(os
.path
.join(networkd_runtime_directory
, 'state'))
513 def stop_networkd(show_logs
=True, remove_state_files
=True):
515 invocation_id
= check_output('systemctl show systemd-networkd -p InvocationID --value')
516 check_output('systemctl stop systemd-networkd.socket')
517 check_output('systemctl stop systemd-networkd.service')
519 print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
))
520 if remove_state_files
:
521 remove_networkd_state_files()
523 def start_networkd(sleep_sec
=0):
524 check_output('systemctl start systemd-networkd')
526 time
.sleep(sleep_sec
)
528 def restart_networkd(sleep_sec
=0, show_logs
=True, remove_state_files
=True):
529 stop_networkd(show_logs
, remove_state_files
)
530 start_networkd(sleep_sec
)
534 def check_link_exists(self
, link
):
535 self
.assertTrue(link_exists(link
))
537 def check_link_attr(self
, *args
):
538 self
.assertEqual(read_link_attr(*args
[:-1]), args
[-1]);
540 def wait_operstate(self
, link
, operstate
='degraded', setup_state
='configured', setup_timeout
=5, fail_assert
=True):
541 """Wait for the link to reach the specified operstate and/or setup state.
543 Specify None or '' for either operstate or setup_state to ignore that state.
544 This will recheck until the state conditions are met or the timeout expires.
546 If the link successfully matches the requested state, this returns True.
547 If this times out waiting for the link to match, the behavior depends on the
548 'fail_assert' parameter; if True, this causes a test assertion failure,
549 otherwise this returns False. The default is to cause assertion failure.
551 Note that this function matches on *exactly* the given operstate and setup_state.
552 To wait for a link to reach *or exceed* a given operstate, use wait_online().
559 for secs
in range(setup_timeout
+ 1):
560 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
, env
=env
)
562 if re
.search(rf
'(?m)^\s*State:\s+{operstate}\s+\({setup_state}\)\s*$', output
):
564 # don't bother sleeping if time is up
565 if secs
< setup_timeout
:
568 self
.fail(f
'Timed out waiting for {link} to reach state {operstate}/{setup_state}')
571 def wait_online(self
, links_with_operstate
, timeout
='20s', bool_any
=False, ipv4
=False, ipv6
=False, setup_state
='configured', setup_timeout
=5):
572 """Wait for the link(s) to reach the specified operstate and/or setup state.
574 This is similar to wait_operstate() but can be used for multiple links,
575 and it also calls systemd-networkd-wait-online to wait for the given operstate.
576 The operstate should be specified in the link name, like 'eth0:degraded'.
577 If just a link name is provided, wait-online's default operstate to wait for is degraded.
579 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
580 'setup_timeout' controls the per-link timeout waiting for the setup_state.
582 Set 'bool_any' to True to wait for any (instead of all) of the given links.
583 If this is set, no setup_state checks are done.
585 Set 'ipv4' or 'ipv6' to True to wait for IPv4 address or IPv6 address, respectively, of each of the given links.
586 This is applied only for the operational state 'degraded' or above.
588 Note that this function waits for the link(s) to reach *or exceed* the given operstate.
589 However, the setup_state, if specified, must be matched *exactly*.
591 This returns if the link(s) reached the requested operstate/setup_state; otherwise it
592 raises CalledProcessError or fails test assertion.
594 args
= wait_online_cmd
+ [f
'--timeout={timeout}'] + [f
'--interface={link}' for link
in links_with_operstate
]
602 check_output(*args
, env
=env
)
603 except subprocess
.CalledProcessError
:
604 for link
in links_with_operstate
:
605 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
.split(':')[0], env
=env
)
608 if not bool_any
and setup_state
:
609 for link
in links_with_operstate
:
610 self
.wait_operstate(link
.split(':')[0], None, setup_state
, setup_timeout
)
612 def wait_address(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
613 for i
in range(timeout_sec
):
616 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
617 if re
.search(address_regex
, output
) and 'tentative' not in output
:
620 self
.assertRegex(output
, address_regex
)
622 def wait_address_dropped(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
623 for i
in range(timeout_sec
):
626 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
627 if not re
.search(address_regex
, output
):
630 self
.assertNotRegex(output
, address_regex
)
632 class NetworkctlTests(unittest
.TestCase
, Utilities
):
642 '11-dummy-mtu.netdev',
646 '25-address-static.network',
648 'netdev-link-local-addressing-yes.network',
652 remove_links(self
.links
)
653 stop_networkd(show_logs
=False)
656 remove_links(self
.links
)
657 remove_unit_from_networkd_path(self
.units
)
658 stop_networkd(show_logs
=True)
660 @expectedFailureIfAlternativeNameIsNotAvailable()
661 def test_altname(self
):
662 copy_unit_to_networkd_unit_path('netdev-link-local-addressing-yes.network', '12-dummy.netdev', '12-dummy.link')
663 check_output('udevadm control --reload')
665 self
.wait_online(['dummy98:degraded'])
667 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
668 self
.assertRegex(output
, 'hogehogehogehogehogehoge')
670 def test_reconfigure(self
):
671 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
673 self
.wait_online(['dummy98:routable'])
675 output
= check_output('ip -4 address show dev dummy98')
677 self
.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output
)
678 self
.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output
)
679 self
.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output
)
681 check_output('ip address del 10.1.2.3/16 dev dummy98')
682 check_output('ip address del 10.1.2.4/16 dev dummy98')
683 check_output('ip address del 10.2.2.4/16 dev dummy98')
685 check_output(*networkctl_cmd
, 'reconfigure', 'dummy98', env
=env
)
686 self
.wait_online(['dummy98:routable'])
688 output
= check_output('ip -4 address show dev dummy98')
690 self
.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output
)
691 self
.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output
)
692 self
.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output
)
694 remove_unit_from_networkd_path(['25-address-static.network'])
696 check_output(*networkctl_cmd
, 'reload', env
=env
)
697 self
.wait_operstate('dummy98', 'degraded', setup_state
='unmanaged')
699 output
= check_output('ip -4 address show dev dummy98')
701 self
.assertNotIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output
)
702 self
.assertNotIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output
)
703 self
.assertNotIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output
)
705 copy_unit_to_networkd_unit_path('25-address-static.network')
706 check_output(*networkctl_cmd
, 'reload', env
=env
)
707 self
.wait_online(['dummy98:routable'])
709 output
= check_output('ip -4 address show dev dummy98')
711 self
.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output
)
712 self
.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output
)
713 self
.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output
)
715 def test_reload(self
):
718 copy_unit_to_networkd_unit_path('11-dummy.netdev')
719 check_output(*networkctl_cmd
, 'reload', env
=env
)
720 self
.wait_operstate('test1', 'off', setup_state
='unmanaged')
722 copy_unit_to_networkd_unit_path('11-dummy.network')
723 check_output(*networkctl_cmd
, 'reload', env
=env
)
724 self
.wait_online(['test1:degraded'])
726 remove_unit_from_networkd_path(['11-dummy.network'])
727 check_output(*networkctl_cmd
, 'reload', env
=env
)
728 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
730 remove_unit_from_networkd_path(['11-dummy.netdev'])
731 check_output(*networkctl_cmd
, 'reload', env
=env
)
732 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
734 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
735 check_output(*networkctl_cmd
, 'reload', env
=env
)
736 self
.wait_operstate('test1', 'degraded')
739 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
742 self
.wait_online(['test1:degraded'])
744 output
= check_output(*networkctl_cmd
, 'list', env
=env
)
745 self
.assertRegex(output
, '1 lo ')
746 self
.assertRegex(output
, 'test1')
748 output
= check_output(*networkctl_cmd
, 'list', 'test1', env
=env
)
749 self
.assertNotRegex(output
, '1 lo ')
750 self
.assertRegex(output
, 'test1')
752 output
= check_output(*networkctl_cmd
, 'list', 'te*', env
=env
)
753 self
.assertNotRegex(output
, '1 lo ')
754 self
.assertRegex(output
, 'test1')
756 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'te*', env
=env
)
757 self
.assertNotRegex(output
, '1: lo ')
758 self
.assertRegex(output
, 'test1')
760 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'tes[a-z][0-9]', env
=env
)
761 self
.assertNotRegex(output
, '1: lo ')
762 self
.assertRegex(output
, 'test1')
765 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
768 self
.wait_online(['test1:degraded'])
770 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
771 self
.assertRegex(output
, 'MTU: 1600')
774 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
776 self
.wait_online(['test1:degraded'])
778 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
780 self
.assertRegex(output
, 'Type: ether')
782 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
784 self
.assertRegex(output
, 'Type: loopback')
786 @expectedFailureIfLinkFileFieldIsNotSet()
787 def test_udev_link_file(self
):
788 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
790 self
.wait_online(['test1:degraded'])
792 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
794 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
795 self
.assertRegex(output
, r
'Network File: /run/systemd/network/11-dummy.network')
797 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
799 self
.assertRegex(output
, r
'Link File: n/a')
800 self
.assertRegex(output
, r
'Network File: n/a')
802 def test_delete_links(self
):
803 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
804 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
807 self
.wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
809 check_output(*networkctl_cmd
, 'delete', 'test1', 'veth99', env
=env
)
810 self
.assertFalse(link_exists('test1'))
811 self
.assertFalse(link_exists('veth99'))
812 self
.assertFalse(link_exists('veth-peer'))
814 class NetworkdNetDevTests(unittest
.TestCase
, Utilities
):
816 links_remove_earlier
= [
887 '10-dropin-test.netdev',
891 '13-not-match-udev-property.network',
892 '14-match-udev-property.network',
893 '15-name-conflict-test.netdev',
896 '21-vlan-test1.network',
899 '25-6rd-tunnel.netdev',
903 '25-bond-balanced-tlb.netdev',
905 '25-bridge-configure-without-carrier.network',
907 '25-erspan-tunnel-local-any.netdev',
908 '25-erspan-tunnel.netdev',
909 '25-fou-gretap.netdev',
911 '25-fou-ipip.netdev',
912 '25-fou-ipproto-gre.netdev',
913 '25-fou-ipproto-ipip.netdev',
916 '25-gretap-tunnel-local-any.netdev',
917 '25-gretap-tunnel.netdev',
918 '25-gre-tunnel-any-any.netdev',
919 '25-gre-tunnel-local-any.netdev',
920 '25-gre-tunnel-remote-any.netdev',
921 '25-gre-tunnel.netdev',
923 '25-ip6gretap-tunnel-local-any.netdev',
924 '25-ip6gretap-tunnel.netdev',
925 '25-ip6gre-tunnel-any-any.netdev',
926 '25-ip6gre-tunnel-local-any.netdev',
927 '25-ip6gre-tunnel-remote-any.netdev',
928 '25-ip6gre-tunnel.netdev',
929 '25-ip6tnl-tunnel-any-any.netdev',
930 '25-ip6tnl-tunnel-local-any.netdev',
931 '25-ip6tnl-tunnel-remote-any.netdev',
932 '25-ip6tnl-tunnel.netdev',
933 '25-ipip-tunnel-any-any.netdev',
934 '25-ipip-tunnel-independent.netdev',
935 '25-ipip-tunnel-independent-loopback.netdev',
936 '25-ipip-tunnel-local-any.netdev',
937 '25-ipip-tunnel-remote-any.netdev',
938 '25-ipip-tunnel.netdev',
941 '25-isatap-tunnel.netdev',
946 '25-sit-tunnel-any-any.netdev',
947 '25-sit-tunnel-local-any.netdev',
948 '25-sit-tunnel-remote-any.netdev',
949 '25-sit-tunnel.netdev',
952 '25-tunnel-any-any.network',
953 '25-tunnel-local-any.network',
954 '25-tunnel-remote-any.network',
959 '25-vti6-tunnel-any-any.netdev',
960 '25-vti6-tunnel-local-any.netdev',
961 '25-vti6-tunnel-remote-any.netdev',
962 '25-vti6-tunnel.netdev',
963 '25-vti-tunnel-any-any.netdev',
964 '25-vti-tunnel-local-any.netdev',
965 '25-vti-tunnel-remote-any.netdev',
966 '25-vti-tunnel.netdev',
968 '25-vxlan-independent.netdev',
969 '25-vxlan-ipv6.netdev',
971 '25-wireguard-23-peers.netdev',
972 '25-wireguard-23-peers.network',
973 '25-wireguard-no-peer.netdev',
974 '25-wireguard-no-peer.network',
975 '25-wireguard-preshared-key.txt',
976 '25-wireguard-private-key.txt',
977 '25-wireguard.netdev',
978 '25-wireguard.network',
980 '25-xfrm-independent.netdev',
996 'netdev-link-local-addressing-yes.network',
1000 'vxlan-ipv6.network',
1001 'vxlan-test1.network',
1011 remove_fou_ports(self
.fou_ports
)
1012 remove_links(self
.links_remove_earlier
)
1013 remove_links(self
.links
)
1014 stop_networkd(show_logs
=False)
1017 remove_fou_ports(self
.fou_ports
)
1018 remove_links(self
.links_remove_earlier
)
1019 remove_links(self
.links
)
1020 remove_unit_from_networkd_path(self
.units
)
1021 stop_networkd(show_logs
=True)
1023 def test_dropin_and_name_conflict(self
):
1024 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
1027 self
.wait_online(['dropin-test:off'], setup_state
='unmanaged')
1029 output
= check_output('ip link show dropin-test')
1031 self
.assertRegex(output
, '00:50:56:c0:00:28')
1033 def test_match_udev_property(self
):
1034 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
1036 self
.wait_online(['dummy98:routable'])
1038 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
1040 self
.assertRegex(output
, 'Network File: /run/systemd/network/14-match-udev-property')
1042 def test_wait_online_any(self
):
1043 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
1046 self
.wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
1048 self
.wait_operstate('bridge99', '(off|no-carrier)', setup_state
='configuring')
1049 self
.wait_operstate('test1', 'degraded')
1051 @expectedFailureIfModuleIsNotAvailable('bareudp')
1052 def test_bareudp(self
):
1053 copy_unit_to_networkd_unit_path('25-bareudp.netdev', 'netdev-link-local-addressing-yes.network')
1056 self
.wait_online(['bareudp99:degraded'])
1058 output
= check_output('ip -d link show bareudp99')
1060 self
.assertRegex(output
, 'dstport 1000 ')
1061 self
.assertRegex(output
, 'ethertype ip ')
1063 @expectedFailureIfModuleIsNotAvailable('batman-adv')
1064 def test_batadv(self
):
1065 copy_unit_to_networkd_unit_path('25-batadv.netdev', 'netdev-link-local-addressing-yes.network')
1068 self
.wait_online(['batadv99:degraded'])
1070 output
= check_output('ip -d link show batadv99')
1072 self
.assertRegex(output
, 'batadv')
1074 def test_bridge(self
):
1075 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
1078 self
.wait_online(['bridge99:no-carrier'])
1080 tick
= os
.sysconf('SC_CLK_TCK')
1081 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
1082 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
1083 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'forward_delay')) / tick
))
1084 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'ageing_time')) / tick
))
1085 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge', 'priority')))
1086 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_querier')))
1087 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_snooping')))
1088 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'stp_state')))
1089 self
.assertEqual(3, int(read_link_attr('bridge99', 'bridge', 'multicast_igmp_version')))
1091 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
1093 self
.assertRegex(output
, 'Priority: 9')
1094 self
.assertRegex(output
, 'STP: yes')
1095 self
.assertRegex(output
, 'Multicast IGMP Version: 3')
1097 def test_bond(self
):
1098 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
1101 self
.wait_online(['bond99:off', 'bond98:off'], setup_state
='unmanaged')
1103 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
1104 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
1105 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
1106 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
1107 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
1108 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
1109 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
1110 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
1111 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
1112 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
1113 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
1115 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
1116 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
1118 def test_vlan(self
):
1119 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
1120 '21-vlan.network', '21-vlan-test1.network')
1123 self
.wait_online(['test1:degraded', 'vlan99:routable'])
1125 output
= check_output('ip -d link show test1')
1127 self
.assertRegex(output
, ' mtu 2000 ')
1129 output
= check_output('ip -d link show vlan99')
1131 self
.assertRegex(output
, ' mtu 2000 ')
1132 self
.assertRegex(output
, 'REORDER_HDR')
1133 self
.assertRegex(output
, 'LOOSE_BINDING')
1134 self
.assertRegex(output
, 'GVRP')
1135 self
.assertRegex(output
, 'MVRP')
1136 self
.assertRegex(output
, ' id 99 ')
1138 output
= check_output('ip -4 address show dev test1')
1140 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
1141 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
1143 output
= check_output('ip -4 address show dev vlan99')
1145 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
1147 def test_macvtap(self
):
1148 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
1149 with self
.subTest(mode
=mode
):
1150 if mode
!= 'private':
1152 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
1153 '11-dummy.netdev', 'macvtap.network')
1154 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
1155 f
.write('[MACVTAP]\nMode=' + mode
)
1158 self
.wait_online(['macvtap99:degraded', 'test1:degraded'])
1160 output
= check_output('ip -d link show macvtap99')
1162 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
1164 def test_macvlan(self
):
1165 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
1166 with self
.subTest(mode
=mode
):
1167 if mode
!= 'private':
1169 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
1170 '11-dummy.netdev', 'macvlan.network')
1171 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
1172 f
.write('[MACVLAN]\nMode=' + mode
)
1175 self
.wait_online(['macvlan99:degraded', 'test1:degraded'])
1177 output
= check_output('ip -d link show test1')
1179 self
.assertRegex(output
, ' mtu 2000 ')
1181 output
= check_output('ip -d link show macvlan99')
1183 self
.assertRegex(output
, ' mtu 2000 ')
1184 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
1186 rc
= call("ip link del test1")
1187 self
.assertEqual(rc
, 0)
1190 rc
= call("ip link add test1 type dummy")
1191 self
.assertEqual(rc
, 0)
1194 self
.wait_online(['macvlan99:degraded', 'test1:degraded'])
1196 output
= check_output('ip -d link show test1')
1198 self
.assertRegex(output
, ' mtu 2000 ')
1200 output
= check_output('ip -d link show macvlan99')
1202 self
.assertRegex(output
, ' mtu 2000 ')
1203 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
1205 @expectedFailureIfModuleIsNotAvailable('ipvlan')
1206 def test_ipvlan(self
):
1207 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1208 with self
.subTest(mode
=mode
, flag
=flag
):
1211 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
1212 '11-dummy.netdev', 'ipvlan.network')
1213 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
1214 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
1217 self
.wait_online(['ipvlan99:degraded', 'test1:degraded'])
1219 output
= check_output('ip -d link show ipvlan99')
1221 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
1223 @expectedFailureIfModuleIsNotAvailable('ipvtap')
1224 def test_ipvtap(self
):
1225 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1226 with self
.subTest(mode
=mode
, flag
=flag
):
1229 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
1230 '11-dummy.netdev', 'ipvtap.network')
1231 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
1232 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
1235 self
.wait_online(['ipvtap99:degraded', 'test1:degraded'])
1237 output
= check_output('ip -d link show ipvtap99')
1239 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
1241 def test_veth(self
):
1242 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
1245 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
1247 output
= check_output('ip -d link show veth99')
1249 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
1250 output
= check_output('ip -d link show veth-peer')
1252 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
1255 copy_unit_to_networkd_unit_path('25-tun.netdev')
1258 self
.wait_online(['tun99:off'], setup_state
='unmanaged')
1260 output
= check_output('ip -d link show tun99')
1262 # Old ip command does not support IFF_ flags
1263 self
.assertRegex(output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
1266 copy_unit_to_networkd_unit_path('25-tap.netdev')
1269 self
.wait_online(['tap99:off'], setup_state
='unmanaged')
1271 output
= check_output('ip -d link show tap99')
1273 # Old ip command does not support IFF_ flags
1274 self
.assertRegex(output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
1276 @expectedFailureIfModuleIsNotAvailable('vrf')
1278 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
1281 self
.wait_online(['vrf99:carrier'])
1283 @expectedFailureIfModuleIsNotAvailable('vcan')
1284 def test_vcan(self
):
1285 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
1288 self
.wait_online(['vcan99:carrier'])
1290 @expectedFailureIfModuleIsNotAvailable('vxcan')
1291 def test_vxcan(self
):
1292 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
1295 self
.wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
1297 @expectedFailureIfModuleIsNotAvailable('wireguard')
1298 def test_wireguard(self
):
1299 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
1300 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
1301 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt',
1302 '25-wireguard-no-peer.netdev', '25-wireguard-no-peer.network')
1304 self
.wait_online(['wg99:routable', 'wg98:routable', 'wg97:carrier'])
1306 output
= check_output('ip -4 address show dev wg99')
1308 self
.assertIn('inet 192.168.124.1/24 scope global wg99', output
)
1310 output
= check_output('ip -4 address show dev wg98')
1312 self
.assertIn('inet 192.168.123.123/24 scope global wg98', output
)
1314 output
= check_output('ip -6 address show dev wg98')
1316 self
.assertIn('inet6 fd8d:4d6d:3ccb:500::1/64 scope global', output
)
1318 if shutil
.which('wg'):
1321 output
= check_output('wg show wg99 listen-port')
1322 self
.assertEqual(output
, '51820')
1323 output
= check_output('wg show wg99 fwmark')
1324 self
.assertEqual(output
, '0x4d2')
1325 output
= check_output('wg show wg99 private-key')
1326 self
.assertEqual(output
, 'EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=')
1327 output
= check_output('wg show wg99 allowed-ips')
1328 self
.assertIn('9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c=\t192.168.124.3/32', output
)
1329 self
.assertIn('TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10=\t192.168.124.2/32', output
)
1330 self
.assertIn('lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128', output
)
1331 self
.assertIn('RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48', output
)
1332 output
= check_output('wg show wg99 persistent-keepalive')
1333 self
.assertIn('9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c=\toff', output
)
1334 self
.assertIn('TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10=\toff', output
)
1335 self
.assertIn('lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\toff', output
)
1336 self
.assertIn('RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t20', output
)
1337 output
= check_output('wg show wg99 endpoints')
1338 self
.assertIn('9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c=\t(none)', output
)
1339 self
.assertIn('TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10=\t(none)', output
)
1340 self
.assertIn('lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\t(none)', output
)
1341 self
.assertIn('RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t192.168.27.3:51820', output
)
1342 output
= check_output('wg show wg99 preshared-keys')
1343 self
.assertIn('9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c=\t6Fsg8XN0DE6aPQgAX4r2oazEYJOGqyHUz3QRH/jCB+I=', output
)
1344 self
.assertIn('TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10=\tit7nd33chCT/tKT2ZZWfYyp43Zs+6oif72hexnSNMqA=', output
)
1345 self
.assertIn('lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tcPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=', output
)
1346 self
.assertIn('RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\tIIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=', output
)
1348 output
= check_output('wg show wg98 private-key')
1349 self
.assertEqual(output
, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr+WHtZLZ90FU=')
1351 output
= check_output('wg show wg97 listen-port')
1352 self
.assertEqual(output
, '51821')
1353 output
= check_output('wg show wg97 fwmark')
1354 self
.assertEqual(output
, '0x4d3')
1356 def test_geneve(self
):
1357 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
1360 self
.wait_online(['geneve99:degraded'])
1362 output
= check_output('ip -d link show geneve99')
1364 self
.assertRegex(output
, '192.168.22.1')
1365 self
.assertRegex(output
, '6082')
1366 self
.assertRegex(output
, 'udpcsum')
1367 self
.assertRegex(output
, 'udp6zerocsumrx')
1369 def test_ipip_tunnel(self
):
1370 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
1371 '25-ipip-tunnel.netdev', '25-tunnel.network',
1372 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1373 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1374 '25-ipip-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1376 self
.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'ipiptun96:routable', 'dummy98:degraded'])
1378 output
= check_output('ip -d link show ipiptun99')
1380 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98')
1381 output
= check_output('ip -d link show ipiptun98')
1383 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98')
1384 output
= check_output('ip -d link show ipiptun97')
1386 self
.assertRegex(output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98')
1387 output
= check_output('ip -d link show ipiptun96')
1389 self
.assertRegex(output
, 'ipip (ipip )?remote any local any dev dummy98')
1391 def test_gre_tunnel(self
):
1392 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
1393 '25-gre-tunnel.netdev', '25-tunnel.network',
1394 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1395 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1396 '25-gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1398 self
.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'gretun96:routable', 'dummy98:degraded'])
1400 output
= check_output('ip -d link show gretun99')
1402 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1403 self
.assertRegex(output
, 'ikey 1.2.3.103')
1404 self
.assertRegex(output
, 'okey 1.2.4.103')
1405 self
.assertRegex(output
, 'iseq')
1406 self
.assertRegex(output
, 'oseq')
1407 output
= check_output('ip -d link show gretun98')
1409 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
1410 self
.assertRegex(output
, 'ikey 0.0.0.104')
1411 self
.assertRegex(output
, 'okey 0.0.0.104')
1412 self
.assertNotRegex(output
, 'iseq')
1413 self
.assertNotRegex(output
, 'oseq')
1414 output
= check_output('ip -d link show gretun97')
1416 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
1417 self
.assertRegex(output
, 'ikey 0.0.0.105')
1418 self
.assertRegex(output
, 'okey 0.0.0.105')
1419 self
.assertNotRegex(output
, 'iseq')
1420 self
.assertNotRegex(output
, 'oseq')
1421 output
= check_output('ip -d link show gretun96')
1423 self
.assertRegex(output
, 'gre remote any local any dev dummy98')
1424 self
.assertRegex(output
, 'ikey 0.0.0.106')
1425 self
.assertRegex(output
, 'okey 0.0.0.106')
1426 self
.assertNotRegex(output
, 'iseq')
1427 self
.assertNotRegex(output
, 'oseq')
1429 def test_ip6gre_tunnel(self
):
1430 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
1431 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
1432 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1433 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1434 '25-ip6gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1437 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1439 self
.check_link_exists('dummy98')
1440 self
.check_link_exists('ip6gretun99')
1441 self
.check_link_exists('ip6gretun98')
1442 self
.check_link_exists('ip6gretun97')
1443 self
.check_link_exists('ip6gretun96')
1445 output
= check_output('ip -d link show ip6gretun99')
1447 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1448 output
= check_output('ip -d link show ip6gretun98')
1450 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
1451 output
= check_output('ip -d link show ip6gretun97')
1453 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
1454 output
= check_output('ip -d link show ip6gretun96')
1456 self
.assertRegex(output
, 'ip6gre remote any local any dev dummy98')
1458 def test_gretap_tunnel(self
):
1459 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
1460 '25-gretap-tunnel.netdev', '25-tunnel.network',
1461 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1463 self
.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
1465 output
= check_output('ip -d link show gretap99')
1467 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1468 self
.assertRegex(output
, 'ikey 0.0.0.106')
1469 self
.assertRegex(output
, 'okey 0.0.0.106')
1470 self
.assertRegex(output
, 'iseq')
1471 self
.assertRegex(output
, 'oseq')
1472 output
= check_output('ip -d link show gretap98')
1474 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
1475 self
.assertRegex(output
, 'ikey 0.0.0.107')
1476 self
.assertRegex(output
, 'okey 0.0.0.107')
1477 self
.assertRegex(output
, 'iseq')
1478 self
.assertRegex(output
, 'oseq')
1480 def test_ip6gretap_tunnel(self
):
1481 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
1482 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1483 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1485 self
.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
1487 output
= check_output('ip -d link show ip6gretap99')
1489 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1490 output
= check_output('ip -d link show ip6gretap98')
1492 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1494 def test_vti_tunnel(self
):
1495 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
1496 '25-vti-tunnel.netdev', '25-tunnel.network',
1497 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1498 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1499 '25-vti-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1501 self
.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'vtitun96:routable', 'dummy98:degraded'])
1503 output
= check_output('ip -d link show vtitun99')
1505 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1506 output
= check_output('ip -d link show vtitun98')
1508 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
1509 output
= check_output('ip -d link show vtitun97')
1511 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
1512 output
= check_output('ip -d link show vtitun96')
1514 self
.assertRegex(output
, 'vti remote any local any dev dummy98')
1516 def test_vti6_tunnel(self
):
1517 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
1518 '25-vti6-tunnel.netdev', '25-tunnel.network',
1519 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1520 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1522 self
.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
1524 output
= check_output('ip -d link show vti6tun99')
1526 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1527 output
= check_output('ip -d link show vti6tun98')
1529 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1530 output
= check_output('ip -d link show vti6tun97')
1532 self
.assertRegex(output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1534 def test_ip6tnl_tunnel(self
):
1535 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
1536 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1537 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1538 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1540 self
.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
1542 output
= check_output('ip -d link show ip6tnl99')
1544 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1545 output
= check_output('ip -d link show ip6tnl98')
1547 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1548 output
= check_output('ip -d link show ip6tnl97')
1550 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1552 def test_sit_tunnel(self
):
1553 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1554 '25-sit-tunnel.netdev', '25-tunnel.network',
1555 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1556 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1557 '25-sit-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1559 self
.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'sittun96:routable', 'dummy98:degraded'])
1561 output
= check_output('ip -d link show sittun99')
1563 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1564 output
= check_output('ip -d link show sittun98')
1566 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98")
1567 output
= check_output('ip -d link show sittun97')
1569 self
.assertRegex(output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98")
1570 output
= check_output('ip -d link show sittun96')
1572 self
.assertRegex(output
, "sit (ip6ip )?remote any local any dev dummy98")
1574 def test_isatap_tunnel(self
):
1575 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1576 '25-isatap-tunnel.netdev', '25-tunnel.network')
1578 self
.wait_online(['isataptun99:routable', 'dummy98:degraded'])
1580 output
= check_output('ip -d link show isataptun99')
1582 self
.assertRegex(output
, "isatap ")
1584 def test_6rd_tunnel(self
):
1585 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1586 '25-6rd-tunnel.netdev', '25-tunnel.network')
1588 self
.wait_online(['sittun99:routable', 'dummy98:degraded'])
1590 output
= check_output('ip -d link show sittun99')
1592 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1594 @expectedFailureIfERSPANModuleIsNotAvailable()
1595 def test_erspan_tunnel(self
):
1596 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1597 '25-erspan-tunnel.netdev', '25-tunnel.network',
1598 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1600 self
.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1602 output
= check_output('ip -d link show erspan99')
1604 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1605 self
.assertRegex(output
, 'ikey 0.0.0.101')
1606 self
.assertRegex(output
, 'okey 0.0.0.101')
1607 self
.assertRegex(output
, 'iseq')
1608 self
.assertRegex(output
, 'oseq')
1609 output
= check_output('ip -d link show erspan98')
1611 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1612 self
.assertRegex(output
, '102')
1613 self
.assertRegex(output
, 'ikey 0.0.0.102')
1614 self
.assertRegex(output
, 'okey 0.0.0.102')
1615 self
.assertRegex(output
, 'iseq')
1616 self
.assertRegex(output
, 'oseq')
1618 def test_tunnel_independent(self
):
1619 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1622 self
.wait_online(['ipiptun99:carrier'])
1624 def test_tunnel_independent_loopback(self
):
1625 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent-loopback.netdev', 'netdev-link-local-addressing-yes.network')
1628 self
.wait_online(['ipiptun99:carrier'])
1630 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1631 def test_xfrm(self
):
1632 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'xfrm.network',
1633 '25-xfrm.netdev', 'netdev-link-local-addressing-yes.network')
1636 self
.wait_online(['xfrm99:degraded', 'dummy98:degraded'])
1638 output
= check_output('ip link show dev xfrm99')
1641 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1642 def test_xfrm_independent(self
):
1643 copy_unit_to_networkd_unit_path('25-xfrm-independent.netdev', 'netdev-link-local-addressing-yes.network')
1646 self
.wait_online(['xfrm99:degraded'])
1648 @expectedFailureIfModuleIsNotAvailable('fou')
1650 # The following redundant check is necessary for CentOS CI.
1651 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1652 self
.assertTrue(is_module_available('fou'))
1654 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1655 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1656 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1659 self
.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'], setup_state
='unmanaged')
1661 output
= check_output('ip fou show')
1663 self
.assertRegex(output
, 'port 55555 ipproto 4')
1664 self
.assertRegex(output
, 'port 55556 ipproto 47')
1666 output
= check_output('ip -d link show ipiptun96')
1668 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1669 output
= check_output('ip -d link show sittun96')
1671 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1672 output
= check_output('ip -d link show gretun96')
1674 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1675 output
= check_output('ip -d link show gretap96')
1677 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1679 def test_vxlan(self
):
1680 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1681 '25-vxlan-ipv6.netdev', 'vxlan-ipv6.network',
1682 '25-vxlan-independent.netdev', 'netdev-link-local-addressing-yes.network',
1683 '11-dummy.netdev', 'vxlan-test1.network')
1686 self
.wait_online(['test1:degraded', 'vxlan99:degraded', 'vxlan98:degraded', 'vxlan97:degraded'])
1688 output
= check_output('ip -d link show vxlan99')
1690 self
.assertIn('999', output
)
1691 self
.assertIn('5555', output
)
1692 self
.assertIn('l2miss', output
)
1693 self
.assertIn('l3miss', output
)
1694 self
.assertIn('udpcsum', output
)
1695 self
.assertIn('udp6zerocsumtx', output
)
1696 self
.assertIn('udp6zerocsumrx', output
)
1697 self
.assertIn('remcsumtx', output
)
1698 self
.assertIn('remcsumrx', output
)
1699 self
.assertIn('gbp', output
)
1701 output
= check_output('bridge fdb show dev vxlan99')
1703 self
.assertIn('00:11:22:33:44:55 dst 10.0.0.5 self permanent', output
)
1704 self
.assertIn('00:11:22:33:44:66 dst 10.0.0.6 self permanent', output
)
1705 self
.assertIn('00:11:22:33:44:77 dst 10.0.0.7 via test1 self permanent', output
)
1707 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'vxlan99', env
=env
)
1709 self
.assertIn('VNI: 999', output
)
1710 self
.assertIn('Destination Port: 5555', output
)
1711 self
.assertIn('Underlying Device: test1', output
)
1713 output
= check_output('bridge fdb show dev vxlan97')
1715 self
.assertIn('00:00:00:00:00:00 dst fe80::23b:d2ff:fe95:967f via test1 self permanent', output
)
1716 self
.assertIn('00:00:00:00:00:00 dst fe80::27c:16ff:fec0:6c74 via test1 self permanent', output
)
1717 self
.assertIn('00:00:00:00:00:00 dst fe80::2a2:e4ff:fef9:2269 via test1 self permanent', output
)
1719 def test_macsec(self
):
1720 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1721 'macsec.network', '12-dummy.netdev')
1724 self
.wait_online(['dummy98:degraded', 'macsec99:routable'])
1726 output
= check_output('ip -d link show macsec99')
1728 self
.assertRegex(output
, 'macsec99@dummy98')
1729 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1730 self
.assertRegex(output
, 'encrypt on')
1732 output
= check_output('ip macsec show macsec99')
1734 self
.assertRegex(output
, 'encrypt on')
1735 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1736 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1737 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1738 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1739 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1740 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1741 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1742 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1743 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1744 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1745 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1747 def test_nlmon(self
):
1748 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1751 self
.wait_online(['nlmon99:carrier'])
1753 @expectedFailureIfModuleIsNotAvailable('ifb')
1755 copy_unit_to_networkd_unit_path('25-ifb.netdev', 'netdev-link-local-addressing-yes.network')
1758 self
.wait_online(['ifb99:degraded'])
1760 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1771 '25-l2tp-dummy.network',
1773 '25-l2tp-ip.netdev',
1774 '25-l2tp-udp.netdev']
1776 l2tp_tunnel_ids
= [ '10' ]
1779 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1780 remove_links(self
.links
)
1781 stop_networkd(show_logs
=False)
1784 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1785 remove_links(self
.links
)
1786 remove_unit_from_networkd_path(self
.units
)
1787 stop_networkd(show_logs
=True)
1789 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1790 def test_l2tp_udp(self
):
1791 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1792 '25-l2tp-udp.netdev', '25-l2tp.network')
1795 self
.wait_online(['test1:routable', 'l2tp-ses1:degraded', 'l2tp-ses2:degraded'])
1797 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1799 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1800 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1801 self
.assertRegex(output
, "Peer tunnel 11")
1802 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1803 self
.assertRegex(output
, "UDP checksum: enabled")
1805 output
= check_output('ip l2tp show session tid 10 session_id 15')
1807 self
.assertRegex(output
, "Session 15 in tunnel 10")
1808 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1809 self
.assertRegex(output
, "interface name: l2tp-ses1")
1811 output
= check_output('ip l2tp show session tid 10 session_id 17')
1813 self
.assertRegex(output
, "Session 17 in tunnel 10")
1814 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1815 self
.assertRegex(output
, "interface name: l2tp-ses2")
1817 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1818 def test_l2tp_ip(self
):
1819 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1820 '25-l2tp-ip.netdev', '25-l2tp.network')
1823 self
.wait_online(['test1:routable', 'l2tp-ses3:degraded', 'l2tp-ses4:degraded'])
1825 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1827 self
.assertRegex(output
, "Tunnel 10, encap IP")
1828 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1829 self
.assertRegex(output
, "Peer tunnel 12")
1831 output
= check_output('ip l2tp show session tid 10 session_id 25')
1833 self
.assertRegex(output
, "Session 25 in tunnel 10")
1834 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1835 self
.assertRegex(output
, "interface name: l2tp-ses3")
1837 output
= check_output('ip l2tp show session tid 10 session_id 27')
1839 self
.assertRegex(output
, "Session 27 in tunnel 10")
1840 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1841 self
.assertRegex(output
, "interface name: l2tp-ses4")
1843 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1860 '23-active-slave.network',
1861 '24-keep-configuration-static.network',
1862 '24-search-domain.network',
1863 '25-address-ipv4acd-veth99.network',
1864 '25-address-link-section.network',
1865 '25-address-peer-ipv4.network',
1866 '25-address-static.network',
1867 '25-activation-policy.network',
1868 '25-bind-carrier.network',
1869 '25-bond-active-backup-slave.netdev',
1870 '25-fibrule-invert.network',
1871 '25-fibrule-port-range.network',
1872 '25-fibrule-uidrange.network',
1873 '25-gre-tunnel-remote-any.netdev',
1874 '25-ip6gre-tunnel-remote-any.netdev',
1875 '25-ipv6-address-label-section.network',
1876 '25-ipv6-proxy-ndp.network',
1877 '25-link-local-addressing-no.network',
1878 '25-link-local-addressing-yes.network',
1879 '25-link-section-unmanaged.network',
1880 '25-neighbor-section.network',
1881 '25-neighbor-next.network',
1882 '25-neighbor-ipv6.network',
1883 '25-neighbor-ip-dummy.network',
1884 '25-neighbor-ip.network',
1885 '25-nexthop-dummy.network',
1886 '25-nexthop-nothing.network',
1887 '25-nexthop.network',
1888 '25-qdisc-cake.network',
1889 '25-qdisc-clsact-and-htb.network',
1890 '25-qdisc-drr.network',
1891 '25-qdisc-ets.network',
1892 '25-qdisc-fq_pie.network',
1893 '25-qdisc-hhf.network',
1894 '25-qdisc-ingress-netem-compat.network',
1895 '25-qdisc-pie.network',
1896 '25-qdisc-qfq.network',
1897 '25-prefix-route-with-vrf.network',
1898 '25-prefix-route-without-vrf.network',
1899 '25-route-ipv6-src.network',
1900 '25-route-static.network',
1901 '25-route-via-ipv6.network',
1902 '25-route-vrf.network',
1903 '25-gateway-static.network',
1904 '25-gateway-next-static.network',
1906 '25-sysctl-disable-ipv6.network',
1907 '25-sysctl.network',
1909 '25-veth-peer.network',
1913 '26-link-local-addressing-ipv6.network',
1914 'dhcp-client-ipv4-ipv6ra-prefix-client-with-delay.network',
1915 'dhcp-server-with-ipv6-prefix.network',
1916 'ipv6ra-prefix-client-with-static-ipv4-address.network',
1917 'ipv6-prefix-with-delay.network',
1918 'routing-policy-rule-dummy98.network',
1919 'routing-policy-rule-test1.network',
1920 'routing-policy-rule-reconfigure1.network',
1921 'routing-policy-rule-reconfigure2.network',
1924 networkd_conf_dropins
= [
1925 'networkd-manage-foreign-routes-no.conf',
1928 routing_policy_rule_tables
= ['7', '8', '9', '10', '1011']
1929 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1932 remove_blackhole_nexthops()
1933 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1934 remove_routes(self
.routes
)
1935 remove_links(self
.links
)
1936 stop_networkd(show_logs
=False)
1937 call('ip netns del ns99', stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
1940 remove_blackhole_nexthops()
1941 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1942 remove_routes(self
.routes
)
1943 remove_links(self
.links
)
1944 remove_unit_from_networkd_path(self
.units
)
1945 remove_networkd_conf_dropin(self
.networkd_conf_dropins
)
1946 stop_networkd(show_logs
=True)
1947 call('ip netns del ns99', stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
1949 def test_address_static(self
):
1950 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1953 self
.wait_online(['dummy98:routable'])
1955 output
= check_output('ip -4 address show dev dummy98')
1957 self
.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output
)
1958 self
.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output
)
1959 self
.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output
)
1960 self
.assertIn('inet 10.7.8.9/16 brd 10.7.255.255 scope link deprecated dummy98', output
)
1961 self
.assertIn('inet 10.8.8.1/16 scope global dummy98', output
)
1963 # test for ENOBUFS issue #17012
1964 for i
in range(1,254):
1965 self
.assertIn(f
'inet 10.3.3.{i}/16 brd 10.3.255.255', output
)
1968 self
.assertNotIn('10.10.0.1/16', output
)
1969 self
.assertNotIn('10.10.0.2/16', output
)
1971 output
= check_output('ip -4 address show dev dummy98 label 32')
1972 self
.assertIn('inet 10.3.2.3/16 brd 10.3.255.255 scope global 32', output
)
1974 output
= check_output('ip -4 address show dev dummy98 label 33')
1975 self
.assertIn('inet 10.4.2.3 peer 10.4.2.4/16 scope global 33', output
)
1977 output
= check_output('ip -4 address show dev dummy98 label 34')
1978 self
.assertRegex(output
, r
'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1980 output
= check_output('ip -4 address show dev dummy98 label 35')
1981 self
.assertRegex(output
, r
'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1983 output
= check_output('ip -6 address show dev dummy98')
1985 self
.assertIn('inet6 2001:db8:0:f101::15/64 scope global', output
)
1986 self
.assertIn('inet6 2001:db8:0:f101::16/64 scope global', output
)
1987 self
.assertIn('inet6 2001:db8:0:f102::15/64 scope global', output
)
1988 self
.assertIn('inet6 2001:db8:0:f102::16/64 scope global', output
)
1989 self
.assertIn('inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global', output
)
1990 self
.assertIn('inet6 2001:db8:1:f101::1/64 scope global deprecated', output
)
1991 self
.assertRegex(output
, r
'inet6 fd[0-9a-f:]*1/64 scope global')
1994 self
.wait_online(['dummy98:routable'])
1996 # test for ENOBUFS issue #17012
1997 output
= check_output('ip -4 address show dev dummy98')
1998 for i
in range(1,254):
1999 self
.assertIn(f
'inet 10.3.3.{i}/16 brd 10.3.255.255', output
)
2001 def test_address_ipv4acd(self
):
2002 check_output('ip netns add ns99')
2003 check_output('ip link add veth99 type veth peer veth-peer')
2004 check_output('ip link set veth-peer netns ns99')
2005 check_output('ip link set veth99 up')
2006 check_output('ip netns exec ns99 ip link set veth-peer up')
2007 check_output('ip netns exec ns99 ip address add 192.168.100.10/24 dev veth-peer')
2009 copy_unit_to_networkd_unit_path('25-address-ipv4acd-veth99.network', dropins
=False)
2011 self
.wait_online(['veth99:routable'])
2013 output
= check_output('ip -4 address show dev veth99')
2015 self
.assertNotIn('192.168.100.10/24', output
)
2016 self
.assertIn('192.168.100.11/24', output
)
2018 copy_unit_to_networkd_unit_path('25-address-ipv4acd-veth99.network.d/conflict-address.conf')
2019 run(*networkctl_cmd
, 'reload', env
=env
)
2021 rc
= call(*wait_online_cmd
, '--timeout=10s', '--interface=veth99:routable', env
=env
)
2022 self
.assertTrue(rc
== 1)
2024 output
= check_output('ip -4 address show dev veth99')
2026 self
.assertNotIn('192.168.100.10/24', output
)
2027 self
.assertIn('192.168.100.11/24', output
)
2029 def test_address_peer_ipv4(self
):
2030 # test for issue #17304
2031 copy_unit_to_networkd_unit_path('25-address-peer-ipv4.network', '12-dummy.netdev')
2033 for trial
in range(2):
2039 self
.wait_online(['dummy98:routable'])
2041 output
= check_output('ip -4 address show dev dummy98')
2042 self
.assertIn('inet 100.64.0.1 peer 100.64.0.2/32 scope global', output
)
2044 @expectedFailureIfModuleIsNotAvailable('vrf')
2045 def test_prefix_route(self
):
2046 copy_unit_to_networkd_unit_path('25-prefix-route-with-vrf.network', '12-dummy.netdev',
2047 '25-prefix-route-without-vrf.network', '11-dummy.netdev',
2048 '25-vrf.netdev', '25-vrf.network')
2049 for trial
in range(2):
2055 self
.wait_online(['dummy98:routable', 'test1:routable', 'vrf99:carrier'])
2057 output
= check_output('ip route show table 42 dev dummy98')
2058 print('### ip route show table 42 dev dummy98')
2060 self
.assertRegex(output
, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1')
2061 self
.assertRegex(output
, 'broadcast 10.20.33.0 proto kernel scope link src 10.20.33.1')
2062 self
.assertRegex(output
, '10.20.33.0/24 proto kernel scope link src 10.20.33.1')
2063 self
.assertRegex(output
, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1')
2064 self
.assertRegex(output
, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1')
2065 self
.assertRegex(output
, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1')
2066 self
.assertRegex(output
, 'broadcast 10.20.55.0 proto kernel scope link src 10.20.55.1')
2067 self
.assertRegex(output
, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1')
2068 self
.assertRegex(output
, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1')
2069 output
= check_output('ip -6 route show table 42 dev dummy98')
2070 print('### ip -6 route show table 42 dev dummy98')
2074 self
.assertRegex(output
, 'local fdde:11:22::1 proto kernel metric 0 pref medium')
2075 #self.assertRegex(output, 'fdde:11:22::1 proto kernel metric 256 pref medium')
2076 self
.assertRegex(output
, 'local fdde:11:33::1 proto kernel metric 0 pref medium')
2077 self
.assertRegex(output
, 'fdde:11:33::/64 proto kernel metric 256 pref medium')
2078 self
.assertRegex(output
, 'local fdde:11:44::1 proto kernel metric 0 pref medium')
2079 self
.assertRegex(output
, 'local fdde:11:55::1 proto kernel metric 0 pref medium')
2080 self
.assertRegex(output
, 'fe80::/64 proto kernel metric 256 pref medium')
2081 self
.assertRegex(output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium')
2085 output
= check_output('ip route show dev test1')
2086 print('### ip route show dev test1')
2088 self
.assertRegex(output
, '10.21.33.0/24 proto kernel scope link src 10.21.33.1')
2089 output
= check_output('ip route show table local dev test1')
2090 print('### ip route show table local dev test1')
2092 self
.assertRegex(output
, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1')
2093 self
.assertRegex(output
, 'broadcast 10.21.33.0 proto kernel scope link src 10.21.33.1')
2094 self
.assertRegex(output
, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1')
2095 self
.assertRegex(output
, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1')
2096 self
.assertRegex(output
, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1')
2097 self
.assertRegex(output
, 'broadcast 10.21.55.0 proto kernel scope link src 10.21.55.1')
2098 self
.assertRegex(output
, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1')
2099 self
.assertRegex(output
, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1')
2100 output
= check_output('ip -6 route show dev test1')
2101 print('### ip -6 route show dev test1')
2103 self
.assertRegex(output
, 'fdde:12:22::1 proto kernel metric 256 pref medium')
2104 self
.assertRegex(output
, 'fdde:12:33::/64 proto kernel metric 256 pref medium')
2105 self
.assertRegex(output
, 'fe80::/64 proto kernel metric 256 pref medium')
2106 output
= check_output('ip -6 route show table local dev test1')
2107 print('### ip -6 route show table local dev test1')
2109 self
.assertRegex(output
, 'local fdde:12:22::1 proto kernel metric 0 pref medium')
2110 self
.assertRegex(output
, 'local fdde:12:33::1 proto kernel metric 0 pref medium')
2111 self
.assertRegex(output
, 'local fdde:12:44::1 proto kernel metric 0 pref medium')
2112 self
.assertRegex(output
, 'local fdde:12:55::1 proto kernel metric 0 pref medium')
2113 self
.assertRegex(output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium')
2115 def test_configure_without_carrier(self
):
2116 copy_unit_to_networkd_unit_path('11-dummy.netdev')
2118 self
.wait_operstate('test1', 'off', '')
2119 check_output('ip link set dev test1 up carrier off')
2121 copy_unit_to_networkd_unit_path('25-test1.network.d/configure-without-carrier.conf', dropins
=False)
2123 self
.wait_online(['test1:no-carrier'])
2125 carrier_map
= {'on': '1', 'off': '0'}
2126 routable_map
= {'on': 'routable', 'off': 'no-carrier'}
2127 for carrier
in ['off', 'on', 'off']:
2128 with self
.subTest(carrier
=carrier
):
2129 if carrier_map
[carrier
] != read_link_attr('test1', 'carrier'):
2130 check_output(f
'ip link set dev test1 carrier {carrier}')
2131 self
.wait_online([f
'test1:{routable_map[carrier]}:{routable_map[carrier]}'])
2133 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
2135 self
.assertRegex(output
, '192.168.0.15')
2136 self
.assertRegex(output
, '192.168.0.1')
2137 self
.assertRegex(output
, routable_map
[carrier
])
2139 def test_configure_without_carrier_yes_ignore_carrier_loss_no(self
):
2140 copy_unit_to_networkd_unit_path('11-dummy.netdev')
2142 self
.wait_operstate('test1', 'off', '')
2143 check_output('ip link set dev test1 up carrier off')
2145 copy_unit_to_networkd_unit_path('25-test1.network')
2147 self
.wait_online(['test1:no-carrier'])
2149 carrier_map
= {'on': '1', 'off': '0'}
2150 routable_map
= {'on': 'routable', 'off': 'no-carrier'}
2151 for (carrier
, have_config
) in [('off', True), ('on', True), ('off', False)]:
2152 with self
.subTest(carrier
=carrier
, have_config
=have_config
):
2153 if carrier_map
[carrier
] != read_link_attr('test1', 'carrier'):
2154 check_output(f
'ip link set dev test1 carrier {carrier}')
2155 self
.wait_online([f
'test1:{routable_map[carrier]}:{routable_map[carrier]}'])
2157 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
2160 self
.assertRegex(output
, '192.168.0.15')
2161 self
.assertRegex(output
, '192.168.0.1')
2163 self
.assertNotRegex(output
, '192.168.0.15')
2164 self
.assertNotRegex(output
, '192.168.0.1')
2165 self
.assertRegex(output
, routable_map
[carrier
])
2167 def test_routing_policy_rule(self
):
2168 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
2170 self
.wait_online(['test1:degraded'])
2172 output
= check_output('ip rule list iif test1 priority 111')
2174 self
.assertRegex(output
, '111:')
2175 self
.assertRegex(output
, 'from 192.168.100.18')
2176 self
.assertRegex(output
, r
'tos (0x08|throughput)\s')
2177 self
.assertRegex(output
, 'iif test1')
2178 self
.assertRegex(output
, 'oif test1')
2179 self
.assertRegex(output
, 'lookup 7')
2181 output
= check_output('ip rule list iif test1 priority 101')
2183 self
.assertRegex(output
, '101:')
2184 self
.assertRegex(output
, 'from all')
2185 self
.assertRegex(output
, 'iif test1')
2186 self
.assertRegex(output
, 'lookup 9')
2188 output
= check_output('ip -6 rule list iif test1 priority 100')
2190 self
.assertRegex(output
, '100:')
2191 self
.assertRegex(output
, 'from all')
2192 self
.assertRegex(output
, 'iif test1')
2193 self
.assertRegex(output
, 'lookup 8')
2195 output
= check_output('ip rule list iif test1 priority 102')
2197 self
.assertRegex(output
, '102:')
2198 self
.assertRegex(output
, 'from 0.0.0.0/8')
2199 self
.assertRegex(output
, 'iif test1')
2200 self
.assertRegex(output
, 'lookup 10')
2202 def test_routing_policy_rule_issue_11280(self
):
2203 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
2204 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
2206 for trial
in range(3):
2207 # Remove state files only first time
2209 self
.wait_online(['test1:degraded', 'dummy98:degraded'])
2212 output
= check_output('ip rule list table 7')
2214 self
.assertRegex(output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
2216 output
= check_output('ip rule list table 8')
2218 self
.assertRegex(output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
2220 stop_networkd(remove_state_files
=False)
2222 def test_routing_policy_rule_reconfigure(self
):
2223 copy_unit_to_networkd_unit_path('routing-policy-rule-reconfigure2.network', '11-dummy.netdev')
2225 self
.wait_online(['test1:degraded'])
2227 output
= check_output('ip rule list table 1011')
2229 self
.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output
)
2230 self
.assertIn('10112: from all oif test1 lookup 1011', output
)
2231 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2232 self
.assertIn('10114: from 192.168.8.254 lookup 1011', output
)
2234 output
= check_output('ip -6 rule list table 1011')
2236 self
.assertIn('10112: from all oif test1 lookup 1011', output
)
2238 copy_unit_to_networkd_unit_path('routing-policy-rule-reconfigure1.network', '11-dummy.netdev')
2239 run(*networkctl_cmd
, 'reload', env
=env
)
2241 self
.wait_online(['test1:degraded'])
2243 output
= check_output('ip rule list table 1011')
2245 self
.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output
)
2246 self
.assertIn('10112: from all oif test1 lookup 1011', output
)
2247 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2248 self
.assertIn('10114: from 192.168.8.254 lookup 1011', output
)
2250 output
= check_output('ip -6 rule list table 1011')
2252 self
.assertNotIn('10112: from all oif test1 lookup 1011', output
)
2253 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2255 run('ip rule delete priority 10111')
2256 run('ip rule delete priority 10112')
2257 run('ip rule delete priority 10113')
2258 run('ip rule delete priority 10114')
2259 run('ip -6 rule delete priority 10113')
2261 output
= check_output('ip rule list table 1011')
2263 self
.assertEqual(output
, '')
2265 output
= check_output('ip -6 rule list table 1011')
2267 self
.assertEqual(output
, '')
2269 run(*networkctl_cmd
, 'reconfigure', 'test1', env
=env
)
2270 self
.wait_online(['test1:degraded'])
2272 output
= check_output('ip rule list table 1011')
2274 self
.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output
)
2275 self
.assertIn('10112: from all oif test1 lookup 1011', output
)
2276 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2277 self
.assertIn('10114: from 192.168.8.254 lookup 1011', output
)
2279 output
= check_output('ip -6 rule list table 1011')
2281 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2283 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
2284 def test_routing_policy_rule_port_range(self
):
2285 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
2287 self
.wait_online(['test1:degraded'])
2289 output
= check_output('ip rule')
2291 self
.assertRegex(output
, '111')
2292 self
.assertRegex(output
, 'from 192.168.100.18')
2293 self
.assertRegex(output
, '1123-1150')
2294 self
.assertRegex(output
, '3224-3290')
2295 self
.assertRegex(output
, 'tcp')
2296 self
.assertRegex(output
, 'lookup 7')
2298 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
2299 def test_routing_policy_rule_invert(self
):
2300 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
2302 self
.wait_online(['test1:degraded'])
2304 output
= check_output('ip rule')
2306 self
.assertRegex(output
, '111')
2307 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
2308 self
.assertRegex(output
, 'tcp')
2309 self
.assertRegex(output
, 'lookup 7')
2311 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable()
2312 def test_routing_policy_rule_uidrange(self
):
2313 copy_unit_to_networkd_unit_path('25-fibrule-uidrange.network', '11-dummy.netdev')
2315 self
.wait_online(['test1:degraded'])
2317 output
= check_output('ip rule')
2319 self
.assertRegex(output
, '111')
2320 self
.assertRegex(output
, 'from 192.168.100.18')
2321 self
.assertRegex(output
, 'lookup 7')
2322 self
.assertRegex(output
, 'uidrange 100-200')
2324 def _test_route_static(self
, manage_foreign_routes
):
2325 if not manage_foreign_routes
:
2326 copy_networkd_conf_dropin('networkd-manage-foreign-routes-no.conf')
2328 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
2330 self
.wait_online(['dummy98:routable'])
2332 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2335 print('### ip -6 route show dev dummy98')
2336 output
= check_output('ip -6 route show dev dummy98')
2338 self
.assertIn('2001:1234:5:8fff:ff:ff:ff:ff proto static', output
)
2339 self
.assertIn('2001:1234:5:8f63::1 proto kernel', output
)
2341 print('### ip -6 route show default')
2342 output
= check_output('ip -6 route show default')
2344 self
.assertIn('default', output
)
2345 self
.assertIn('via 2001:1234:5:8fff:ff:ff:ff:ff', output
)
2347 print('### ip -4 route show dev dummy98')
2348 output
= check_output('ip -4 route show dev dummy98')
2350 self
.assertIn('149.10.124.48/28 proto kernel scope link src 149.10.124.58', output
)
2351 self
.assertIn('149.10.124.64 proto static scope link', output
)
2352 self
.assertIn('169.254.0.0/16 proto static scope link metric 2048', output
)
2353 self
.assertIn('192.168.1.1 proto static initcwnd 20', output
)
2354 self
.assertIn('192.168.1.2 proto static initrwnd 30', output
)
2355 self
.assertIn('192.168.1.3 proto static advmss 30', output
)
2356 self
.assertIn('multicast 149.10.123.4 proto static', output
)
2358 print('### ip -4 route show dev dummy98 default')
2359 output
= check_output('ip -4 route show dev dummy98 default')
2361 self
.assertIn('default via 149.10.125.65 proto static onlink', output
)
2362 self
.assertIn('default via 149.10.124.64 proto static', output
)
2363 self
.assertIn('default proto static', output
)
2365 print('### ip -4 route show table local dev dummy98')
2366 output
= check_output('ip -4 route show table local dev dummy98')
2368 self
.assertIn('local 149.10.123.1 proto static scope host', output
)
2369 self
.assertIn('anycast 149.10.123.2 proto static scope link', output
)
2370 self
.assertIn('broadcast 149.10.123.3 proto static scope link', output
)
2372 print('### ip route show type blackhole')
2373 output
= check_output('ip route show type blackhole')
2375 self
.assertIn('blackhole 202.54.1.2 proto static', output
)
2377 print('### ip route show type unreachable')
2378 output
= check_output('ip route show type unreachable')
2380 self
.assertIn('unreachable 202.54.1.3 proto static', output
)
2382 print('### ip route show type prohibit')
2383 output
= check_output('ip route show type prohibit')
2385 self
.assertIn('prohibit 202.54.1.4 proto static', output
)
2387 print('### ip -6 route show type blackhole')
2388 output
= check_output('ip -6 route show type blackhole')
2390 self
.assertIn('blackhole 2001:1234:5678::2 dev lo proto static', output
)
2392 print('### ip -6 route show type unreachable')
2393 output
= check_output('ip -6 route show type unreachable')
2395 self
.assertIn('unreachable 2001:1234:5678::3 dev lo proto static', output
)
2397 print('### ip -6 route show type prohibit')
2398 output
= check_output('ip -6 route show type prohibit')
2400 self
.assertIn('prohibit 2001:1234:5678::4 dev lo proto static', output
)
2402 print('### ip route show 192.168.10.1')
2403 output
= check_output('ip route show 192.168.10.1')
2405 self
.assertIn('192.168.10.1 proto static', output
)
2406 self
.assertIn('nexthop via 149.10.124.59 dev dummy98 weight 10', output
)
2407 self
.assertIn('nexthop via 149.10.124.60 dev dummy98 weight 5', output
)
2409 print('### ip route show 192.168.10.2')
2410 output
= check_output('ip route show 192.168.10.2')
2412 # old ip command does not show IPv6 gateways...
2413 self
.assertIn('192.168.10.2 proto static', output
)
2414 self
.assertIn('nexthop', output
)
2415 self
.assertIn('dev dummy98 weight 10', output
)
2416 self
.assertIn('dev dummy98 weight 5', output
)
2418 print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2419 output
= check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2421 # old ip command does not show 'nexthop' keyword and weight...
2422 self
.assertIn('2001:1234:5:7fff:ff:ff:ff:ff', output
)
2423 self
.assertIn('via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98', output
)
2424 self
.assertIn('via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98', output
)
2426 copy_unit_to_networkd_unit_path('25-address-static.network')
2427 check_output(*networkctl_cmd
, 'reload', env
=env
)
2429 self
.wait_online(['dummy98:routable'])
2431 # check all routes managed by Manager are removed
2432 print('### ip route show type blackhole')
2433 output
= check_output('ip route show type blackhole')
2435 self
.assertEqual(output
, '')
2437 print('### ip route show type unreachable')
2438 output
= check_output('ip route show type unreachable')
2440 self
.assertEqual(output
, '')
2442 print('### ip route show type prohibit')
2443 output
= check_output('ip route show type prohibit')
2445 self
.assertEqual(output
, '')
2447 print('### ip -6 route show type blackhole')
2448 output
= check_output('ip -6 route show type blackhole')
2450 self
.assertEqual(output
, '')
2452 print('### ip -6 route show type unreachable')
2453 output
= check_output('ip -6 route show type unreachable')
2455 self
.assertEqual(output
, '')
2457 print('### ip -6 route show type prohibit')
2458 output
= check_output('ip -6 route show type prohibit')
2460 self
.assertEqual(output
, '')
2462 remove_unit_from_networkd_path(['25-address-static.network'])
2463 check_output(*networkctl_cmd
, 'reload', env
=env
)
2465 self
.wait_online(['dummy98:routable'])
2467 # check all routes managed by Manager are reconfigured
2468 print('### ip route show type blackhole')
2469 output
= check_output('ip route show type blackhole')
2471 self
.assertIn('blackhole 202.54.1.2 proto static', output
)
2473 print('### ip route show type unreachable')
2474 output
= check_output('ip route show type unreachable')
2476 self
.assertIn('unreachable 202.54.1.3 proto static', output
)
2478 print('### ip route show type prohibit')
2479 output
= check_output('ip route show type prohibit')
2481 self
.assertIn('prohibit 202.54.1.4 proto static', output
)
2483 print('### ip -6 route show type blackhole')
2484 output
= check_output('ip -6 route show type blackhole')
2486 self
.assertIn('blackhole 2001:1234:5678::2 dev lo proto static', output
)
2488 print('### ip -6 route show type unreachable')
2489 output
= check_output('ip -6 route show type unreachable')
2491 self
.assertIn('unreachable 2001:1234:5678::3 dev lo proto static', output
)
2493 print('### ip -6 route show type prohibit')
2494 output
= check_output('ip -6 route show type prohibit')
2496 self
.assertIn('prohibit 2001:1234:5678::4 dev lo proto static', output
)
2498 rc
= call("ip link del dummy98")
2499 self
.assertEqual(rc
, 0)
2502 # check all routes managed by Manager are removed
2503 print('### ip route show type blackhole')
2504 output
= check_output('ip route show type blackhole')
2506 self
.assertEqual(output
, '')
2508 print('### ip route show type unreachable')
2509 output
= check_output('ip route show type unreachable')
2511 self
.assertEqual(output
, '')
2513 print('### ip route show type prohibit')
2514 output
= check_output('ip route show type prohibit')
2516 self
.assertEqual(output
, '')
2518 print('### ip -6 route show type blackhole')
2519 output
= check_output('ip -6 route show type blackhole')
2521 self
.assertEqual(output
, '')
2523 print('### ip -6 route show type unreachable')
2524 output
= check_output('ip -6 route show type unreachable')
2526 self
.assertEqual(output
, '')
2528 print('### ip -6 route show type prohibit')
2529 output
= check_output('ip -6 route show type prohibit')
2531 self
.assertEqual(output
, '')
2535 def test_route_static(self
):
2536 for manage_foreign_routes
in [True, False]:
2537 with self
.subTest(manage_foreign_routes
=manage_foreign_routes
):
2538 self
._test
_route
_static
(manage_foreign_routes
)
2540 @expectedFailureIfRTA_VIAIsNotSupported()
2541 def test_route_via_ipv6(self
):
2542 copy_unit_to_networkd_unit_path('25-route-via-ipv6.network', '12-dummy.netdev')
2544 self
.wait_online(['dummy98:routable'])
2546 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2549 print('### ip -6 route show dev dummy98')
2550 output
= check_output('ip -6 route show dev dummy98')
2552 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
2553 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
2555 print('### ip -4 route show dev dummy98')
2556 output
= check_output('ip -4 route show dev dummy98')
2558 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
2559 self
.assertRegex(output
, '149.10.124.66 via inet6 2001:1234:5:8fff:ff:ff:ff:ff proto static')
2561 @expectedFailureIfModuleIsNotAvailable('vrf')
2562 def test_route_vrf(self
):
2563 copy_unit_to_networkd_unit_path('25-route-vrf.network', '12-dummy.netdev',
2564 '25-vrf.netdev', '25-vrf.network')
2566 self
.wait_online(['dummy98:routable', 'vrf99:carrier'])
2568 output
= check_output('ip route show vrf vrf99')
2570 self
.assertRegex(output
, 'default via 192.168.100.1')
2572 output
= check_output('ip route show')
2574 self
.assertNotRegex(output
, 'default via 192.168.100.1')
2576 def test_gateway_reconfigure(self
):
2577 copy_unit_to_networkd_unit_path('25-gateway-static.network', '12-dummy.netdev')
2579 self
.wait_online(['dummy98:routable'])
2580 print('### ip -4 route show dev dummy98 default')
2581 output
= check_output('ip -4 route show dev dummy98 default')
2583 self
.assertRegex(output
, 'default via 149.10.124.59 proto static')
2584 self
.assertNotRegex(output
, '149.10.124.60')
2586 remove_unit_from_networkd_path(['25-gateway-static.network'])
2587 copy_unit_to_networkd_unit_path('25-gateway-next-static.network')
2589 self
.wait_online(['dummy98:routable'])
2590 print('### ip -4 route show dev dummy98 default')
2591 output
= check_output('ip -4 route show dev dummy98 default')
2593 self
.assertNotRegex(output
, '149.10.124.59')
2594 self
.assertRegex(output
, 'default via 149.10.124.60 proto static')
2596 def test_ip_route_ipv6_src_route(self
):
2597 # a dummy device does not make the addresses go through tentative state, so we
2598 # reuse a bond from an earlier test, which does make the addresses go through
2599 # tentative state, and do our test on that
2600 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2602 self
.wait_online(['dummy98:enslaved', 'bond199:routable'])
2604 output
= check_output('ip -6 route list dev bond199')
2606 self
.assertRegex(output
, 'abcd::/16')
2607 self
.assertRegex(output
, 'src')
2608 self
.assertRegex(output
, '2001:1234:56:8f63::2')
2610 def test_ip_link_mac_address(self
):
2611 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
2613 self
.wait_online(['dummy98:degraded'])
2615 output
= check_output('ip link show dummy98')
2617 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
2619 def test_ip_link_unmanaged(self
):
2620 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
2623 self
.check_link_exists('dummy98')
2625 self
.wait_operstate('dummy98', 'off', setup_state
='unmanaged')
2627 def test_ipv6_address_label(self
):
2628 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
2630 self
.wait_online(['dummy98:degraded'])
2632 output
= check_output('ip addrlabel list')
2634 self
.assertRegex(output
, '2004:da8:1::/64')
2636 def test_ipv6_proxy_ndp(self
):
2637 copy_unit_to_networkd_unit_path('25-ipv6-proxy-ndp.network', '12-dummy.netdev')
2640 self
.wait_online(['dummy98:routable'])
2642 output
= check_output('ip neighbor show proxy dev dummy98')
2644 for i
in range(1,5):
2645 self
.assertRegex(output
, f
'2607:5300:203:5215:{i}::1 *proxy')
2647 def test_neighbor_section(self
):
2648 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2650 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2652 print('### ip neigh list dev dummy98')
2653 output
= check_output('ip neigh list dev dummy98')
2655 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2656 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2658 def test_neighbor_reconfigure(self
):
2659 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2661 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2663 print('### ip neigh list dev dummy98')
2664 output
= check_output('ip neigh list dev dummy98')
2666 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2667 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2669 remove_unit_from_networkd_path(['25-neighbor-section.network'])
2670 copy_unit_to_networkd_unit_path('25-neighbor-next.network')
2672 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2673 print('### ip neigh list dev dummy98')
2674 output
= check_output('ip neigh list dev dummy98')
2676 self
.assertNotRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2677 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT')
2678 self
.assertNotRegex(output
, '2004:da8:1::1.*PERMANENT')
2680 def test_neighbor_gre(self
):
2681 copy_unit_to_networkd_unit_path('25-neighbor-ip.network', '25-neighbor-ipv6.network', '25-neighbor-ip-dummy.network',
2682 '12-dummy.netdev', '25-gre-tunnel-remote-any.netdev', '25-ip6gre-tunnel-remote-any.netdev')
2684 self
.wait_online(['dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable'], timeout
='40s')
2686 output
= check_output('ip neigh list dev gretun97')
2688 self
.assertRegex(output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT')
2690 output
= check_output('ip neigh list dev ip6gretun97')
2692 self
.assertRegex(output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
2694 def test_link_local_addressing(self
):
2695 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
2696 '25-link-local-addressing-no.network', '12-dummy.netdev')
2698 self
.wait_online(['test1:degraded', 'dummy98:carrier'])
2700 output
= check_output('ip address show dev test1')
2702 self
.assertRegex(output
, 'inet .* scope link')
2703 self
.assertRegex(output
, 'inet6 .* scope link')
2705 output
= check_output('ip address show dev dummy98')
2707 self
.assertNotRegex(output
, 'inet6* .* scope link')
2710 Documentation/networking/ip-sysctl.txt
2712 addr_gen_mode - INTEGER
2713 Defines how link-local and autoconf addresses are generated.
2715 0: generate address based on EUI64 (default)
2716 1: do no generate a link-local address, use EUI64 for addresses generated
2718 2: generate stable privacy addresses, using the secret from
2719 stable_secret (RFC7217)
2720 3: generate stable privacy addresses, using a random secret if unset
2723 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'stable_secret'), '0123:4567:89ab:cdef:0123:4567:89ab:cdef')
2724 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), '2')
2725 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
2727 def test_link_local_addressing_remove_ipv6ll(self
):
2728 copy_unit_to_networkd_unit_path('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
2730 self
.wait_online(['dummy98:degraded'])
2732 output
= check_output('ip address show dev dummy98')
2734 self
.assertRegex(output
, 'inet6 .* scope link')
2736 copy_unit_to_networkd_unit_path('25-link-local-addressing-no.network')
2738 self
.wait_online(['dummy98:carrier'])
2740 output
= check_output('ip address show dev dummy98')
2742 self
.assertNotRegex(output
, 'inet6* .* scope link')
2744 def test_sysctl(self
):
2745 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
2747 self
.wait_online(['dummy98:degraded'])
2749 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
2750 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
2751 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
2752 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
2753 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
2754 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
2755 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
2756 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'accept_local'), '1')
2758 def test_sysctl_disable_ipv6(self
):
2759 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
2761 print('## Disable ipv6')
2762 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
2763 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
2766 self
.wait_online(['dummy98:routable'])
2768 output
= check_output('ip -4 address show dummy98')
2770 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2771 output
= check_output('ip -6 address show dummy98')
2773 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2774 self
.assertRegex(output
, 'inet6 .* scope link')
2775 output
= check_output('ip -4 route show dev dummy98')
2777 self
.assertRegex(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2778 output
= check_output('ip -6 route show default')
2780 self
.assertRegex(output
, 'default')
2781 self
.assertRegex(output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff')
2783 check_output('ip link del dummy98')
2785 print('## Enable ipv6')
2786 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
2787 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
2790 self
.wait_online(['dummy98:routable'])
2792 output
= check_output('ip -4 address show dummy98')
2794 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2795 output
= check_output('ip -6 address show dummy98')
2797 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2798 self
.assertRegex(output
, 'inet6 .* scope link')
2799 output
= check_output('ip -4 route show dev dummy98')
2801 self
.assertRegex(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2802 output
= check_output('ip -6 route show default')
2804 self
.assertRegex(output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff')
2806 def test_bind_carrier(self
):
2807 check_output('ip link add dummy98 type dummy')
2808 check_output('ip link set dummy98 up')
2811 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
2813 self
.wait_online(['test1:routable'])
2815 output
= check_output('ip address show test1')
2817 self
.assertRegex(output
, 'UP,LOWER_UP')
2818 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2819 self
.wait_operstate('test1', 'routable')
2821 check_output('ip link add dummy99 type dummy')
2822 check_output('ip link set dummy99 up')
2824 output
= check_output('ip address show test1')
2826 self
.assertRegex(output
, 'UP,LOWER_UP')
2827 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2828 self
.wait_operstate('test1', 'routable')
2830 check_output('ip link del dummy98')
2832 output
= check_output('ip address show test1')
2834 self
.assertRegex(output
, 'UP,LOWER_UP')
2835 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2836 self
.wait_operstate('test1', 'routable')
2838 check_output('ip link set dummy99 down')
2840 output
= check_output('ip address show test1')
2842 self
.assertNotRegex(output
, 'UP,LOWER_UP')
2843 self
.assertRegex(output
, 'DOWN')
2844 self
.assertNotRegex(output
, '192.168.10')
2845 self
.wait_operstate('test1', 'off')
2847 check_output('ip link set dummy99 up')
2849 output
= check_output('ip address show test1')
2851 self
.assertRegex(output
, 'UP,LOWER_UP')
2852 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2853 self
.wait_operstate('test1', 'routable')
2855 def _test_activation_policy(self
, test
):
2857 conffile
= '25-activation-policy.network'
2859 conffile
= f
'{conffile}.d/{test}.conf'
2860 copy_unit_to_networkd_unit_path('11-dummy.netdev', conffile
, dropins
=False)
2863 always
= test
.startswith('always')
2864 if test
== 'manual':
2865 initial_up
= 'UP' in check_output('ip link show test1')
2867 initial_up
= not test
.endswith('down') # note: default is up
2868 expect_up
= initial_up
2869 next_up
= not expect_up
2871 for iteration
in range(4):
2872 with self
.subTest(iteration
=iteration
, expect_up
=expect_up
):
2873 operstate
= 'routable' if expect_up
else 'off'
2874 setup_state
= 'configured' if expect_up
else ('configuring' if iteration
== 0 else None)
2875 self
.wait_operstate('test1', operstate
, setup_state
=setup_state
, setup_timeout
=20)
2878 self
.assertIn('UP', check_output('ip link show test1'))
2879 self
.assertIn('192.168.10.30/24', check_output('ip address show test1'))
2880 self
.assertIn('default via 192.168.10.1', check_output('ip route show dev test1'))
2882 self
.assertIn('DOWN', check_output('ip link show test1'))
2885 check_output('ip link set dev test1 up')
2887 check_output('ip link set dev test1 down')
2888 expect_up
= initial_up
if always
else next_up
2889 next_up
= not next_up
2893 def test_activation_policy(self
):
2894 for test
in ['up', 'always-up', 'manual', 'always-down', 'down', '']:
2895 with self
.subTest(test
=test
):
2896 self
._test
_activation
_policy
(test
)
2898 def _test_activation_policy_required_for_online(self
, policy
, required
):
2900 conffile
= '25-activation-policy.network'
2901 units
= ['11-dummy.netdev', '12-dummy.netdev', '12-dummy.network', conffile
]
2903 units
+= [f
'{conffile}.d/{policy}.conf']
2905 units
+= [f
'{conffile}.d/required-{required}.conf']
2906 copy_unit_to_networkd_unit_path(*units
, dropins
=False)
2909 if policy
.endswith('down') or policy
== 'manual':
2910 self
.wait_operstate('test1', 'off', setup_state
='configuring')
2912 self
.wait_online(['test1'])
2914 if policy
== 'always-down':
2915 # if always-down, required for online is forced to no
2918 # otherwise if required for online is specified, it should match that
2919 expected
= required
== 'yes'
2921 # otherwise if only policy specified, required for online defaults to
2922 # true if policy is up, always-up, or bound
2923 expected
= policy
.endswith('up') or policy
== 'bound'
2925 # default is true, if neither are specified
2928 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
2931 yesno
= 'yes' if expected
else 'no'
2932 self
.assertRegex(output
, f
'Required For Online: {yesno}')
2936 def test_activation_policy_required_for_online(self
):
2937 for policy
in ['up', 'always-up', 'manual', 'always-down', 'down', 'bound', '']:
2938 for required
in ['yes', 'no', '']:
2939 with self
.subTest(policy
=policy
, required
=required
):
2940 self
._test
_activation
_policy
_required
_for
_online
(policy
, required
)
2942 def test_domain(self
):
2943 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
2945 self
.wait_online(['dummy98:routable'])
2947 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2949 self
.assertRegex(output
, 'Address: 192.168.42.100')
2950 self
.assertRegex(output
, 'DNS: 192.168.42.1')
2951 self
.assertRegex(output
, 'Search Domains: one')
2953 def test_keep_configuration_static(self
):
2954 check_output('systemctl stop systemd-networkd.socket')
2955 check_output('systemctl stop systemd-networkd.service')
2957 check_output('ip link add name dummy98 type dummy')
2958 check_output('ip address add 10.1.2.3/16 dev dummy98')
2959 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
2960 output
= check_output('ip address show dummy98')
2962 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2963 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2964 output
= check_output('ip route show dev dummy98')
2967 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
2969 self
.wait_online(['dummy98:routable'])
2971 output
= check_output('ip address show dummy98')
2973 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2974 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2976 @expectedFailureIfNexthopIsNotAvailable()
2977 def test_nexthop(self
):
2978 def check_nexthop(self
):
2979 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'dummy98:routable'])
2981 output
= check_output('ip nexthop list dev veth99')
2983 self
.assertIn('id 1 via 192.168.5.1 dev veth99', output
)
2984 self
.assertIn('id 2 via 2001:1234:5:8f63::2 dev veth99', output
)
2985 self
.assertIn('id 3 dev veth99', output
)
2986 self
.assertIn('id 4 dev veth99', output
)
2987 self
.assertRegex(output
, 'id 5 via 192.168.10.1 dev veth99 .*onlink')
2988 self
.assertRegex(output
, r
'id [0-9]* via 192.168.5.2 dev veth99')
2990 output
= check_output('ip nexthop list dev dummy98')
2992 self
.assertIn('id 20 via 192.168.20.1 dev dummy98', output
)
2994 # kernel manages blackhole nexthops on lo
2995 output
= check_output('ip nexthop list dev lo')
2997 self
.assertIn('id 6 blackhole', output
)
2998 self
.assertIn('id 7 blackhole', output
)
3000 # group nexthops are shown with -0 option
3001 output
= check_output('ip -0 nexthop list id 21')
3003 self
.assertRegex(output
, r
'id 21 group (1,3/20|20/1,3)')
3005 output
= check_output('ip route show dev veth99 10.10.10.10')
3007 self
.assertEqual('10.10.10.10 nhid 1 via 192.168.5.1 proto static', output
)
3009 output
= check_output('ip route show dev veth99 10.10.10.11')
3011 self
.assertEqual('10.10.10.11 nhid 2 via inet6 2001:1234:5:8f63::2 proto static', output
)
3013 output
= check_output('ip route show dev veth99 10.10.10.12')
3015 self
.assertEqual('10.10.10.12 nhid 5 via 192.168.10.1 proto static onlink', output
)
3017 output
= check_output('ip -6 route show dev veth99 2001:1234:5:8f62::1')
3019 self
.assertEqual('2001:1234:5:8f62::1 nhid 2 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium', output
)
3021 output
= check_output('ip route show 10.10.10.13')
3023 self
.assertEqual('blackhole 10.10.10.13 nhid 6 dev lo proto static', output
)
3025 output
= check_output('ip -6 route show 2001:1234:5:8f62::2')
3027 self
.assertEqual('blackhole 2001:1234:5:8f62::2 nhid 7 dev lo proto static metric 1024 pref medium', output
)
3029 output
= check_output('ip route show 10.10.10.14')
3031 self
.assertIn('10.10.10.14 nhid 21 proto static', output
)
3032 self
.assertIn('nexthop via 192.168.20.1 dev dummy98 weight 1', output
)
3033 self
.assertIn('nexthop via 192.168.5.1 dev veth99 weight 3', output
)
3035 copy_unit_to_networkd_unit_path('25-nexthop.network', '25-veth.netdev', '25-veth-peer.network',
3036 '12-dummy.netdev', '25-nexthop-dummy.network')
3041 remove_unit_from_networkd_path(['25-nexthop.network'])
3042 copy_unit_to_networkd_unit_path('25-nexthop-nothing.network')
3043 rc
= call(*networkctl_cmd
, 'reload', env
=env
)
3044 self
.assertEqual(rc
, 0)
3047 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3049 output
= check_output('ip nexthop list dev veth99')
3051 self
.assertEqual(output
, '')
3052 output
= check_output('ip nexthop list dev lo')
3054 self
.assertEqual(output
, '')
3056 remove_unit_from_networkd_path(['25-nexthop-nothing.network'])
3057 copy_unit_to_networkd_unit_path('25-nexthop.network')
3058 rc
= call(*networkctl_cmd
, 'reconfigure', 'dummy98', env
=env
)
3059 self
.assertEqual(rc
, 0)
3060 rc
= call(*networkctl_cmd
, 'reload', env
=env
)
3061 self
.assertEqual(rc
, 0)
3066 rc
= call('ip link del veth99')
3067 self
.assertEqual(rc
, 0)
3070 output
= check_output('ip nexthop list dev lo')
3072 self
.assertEqual(output
, '')
3074 def test_qdisc(self
):
3075 copy_unit_to_networkd_unit_path('25-qdisc-clsact-and-htb.network', '12-dummy.netdev',
3076 '25-qdisc-ingress-netem-compat.network', '11-dummy.netdev')
3077 check_output('modprobe sch_teql max_equalizers=2')
3080 self
.wait_online(['dummy98:routable', 'test1:routable'])
3082 output
= check_output('tc qdisc show dev test1')
3084 self
.assertRegex(output
, 'qdisc netem')
3085 self
.assertRegex(output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
3086 self
.assertRegex(output
, 'qdisc ingress')
3088 output
= check_output('tc qdisc show dev dummy98')
3090 self
.assertRegex(output
, 'qdisc clsact')
3092 self
.assertRegex(output
, 'qdisc htb 2: root')
3093 self
.assertRegex(output
, r
'default (0x30|30)')
3095 self
.assertRegex(output
, 'qdisc netem 30: parent 2:30')
3096 self
.assertRegex(output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
3097 self
.assertRegex(output
, 'qdisc fq_codel')
3098 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')
3100 self
.assertRegex(output
, 'qdisc teql1 31: parent 2:31')
3102 self
.assertRegex(output
, 'qdisc fq 32: parent 2:32')
3103 self
.assertRegex(output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
3104 self
.assertRegex(output
, 'quantum 1500')
3105 self
.assertRegex(output
, 'initial_quantum 13000')
3106 self
.assertRegex(output
, 'maxrate 1Mbit')
3108 self
.assertRegex(output
, 'qdisc codel 33: parent 2:33')
3109 self
.assertRegex(output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn')
3111 self
.assertRegex(output
, 'qdisc fq_codel 34: parent 2:34')
3112 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')
3114 self
.assertRegex(output
, 'qdisc tbf 35: parent 2:35')
3115 self
.assertRegex(output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms')
3117 self
.assertRegex(output
, 'qdisc sfq 36: parent 2:36')
3118 self
.assertRegex(output
, 'perturb 5sec')
3120 self
.assertRegex(output
, 'qdisc pfifo 37: parent 2:37')
3121 self
.assertRegex(output
, 'limit 100000p')
3123 self
.assertRegex(output
, 'qdisc gred 38: parent 2:38')
3124 self
.assertRegex(output
, 'vqs 12 default 10 grio')
3126 self
.assertRegex(output
, 'qdisc sfb 39: parent 2:39')
3127 self
.assertRegex(output
, 'limit 200000')
3129 self
.assertRegex(output
, 'qdisc bfifo 3a: parent 2:3a')
3130 self
.assertRegex(output
, 'limit 1000000')
3132 self
.assertRegex(output
, 'qdisc pfifo_head_drop 3b: parent 2:3b')
3133 self
.assertRegex(output
, 'limit 1023p')
3135 self
.assertRegex(output
, 'qdisc pfifo_fast 3c: parent 2:3c')
3137 output
= check_output('tc -d class show dev dummy98')
3139 self
.assertRegex(output
, 'class htb 2:30 root leaf 30:')
3140 self
.assertRegex(output
, 'class htb 2:31 root leaf 31:')
3141 self
.assertRegex(output
, 'class htb 2:32 root leaf 32:')
3142 self
.assertRegex(output
, 'class htb 2:33 root leaf 33:')
3143 self
.assertRegex(output
, 'class htb 2:34 root leaf 34:')
3144 self
.assertRegex(output
, 'class htb 2:35 root leaf 35:')
3145 self
.assertRegex(output
, 'class htb 2:36 root leaf 36:')
3146 self
.assertRegex(output
, 'class htb 2:37 root leaf 37:')
3147 self
.assertRegex(output
, 'class htb 2:38 root leaf 38:')
3148 self
.assertRegex(output
, 'class htb 2:39 root leaf 39:')
3149 self
.assertRegex(output
, 'class htb 2:3a root leaf 3a:')
3150 self
.assertRegex(output
, 'class htb 2:3b root leaf 3b:')
3151 self
.assertRegex(output
, 'class htb 2:3c root leaf 3c:')
3152 self
.assertRegex(output
, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit')
3153 self
.assertRegex(output
, 'burst 123456')
3154 self
.assertRegex(output
, 'cburst 123457')
3156 def test_qdisc2(self
):
3157 copy_unit_to_networkd_unit_path('25-qdisc-drr.network', '12-dummy.netdev',
3158 '25-qdisc-qfq.network', '11-dummy.netdev')
3161 self
.wait_online(['dummy98:routable', 'test1:routable'])
3163 output
= check_output('tc qdisc show dev dummy98')
3165 self
.assertRegex(output
, 'qdisc drr 2: root')
3166 output
= check_output('tc class show dev dummy98')
3168 self
.assertRegex(output
, 'class drr 2:30 root quantum 2000b')
3170 output
= check_output('tc qdisc show dev test1')
3172 self
.assertRegex(output
, 'qdisc qfq 2: root')
3173 output
= check_output('tc class show dev test1')
3175 self
.assertRegex(output
, 'class qfq 2:30 root weight 2 maxpkt 16000')
3176 self
.assertRegex(output
, 'class qfq 2:31 root weight 10 maxpkt 8000')
3178 @expectedFailureIfCAKEIsNotAvailable()
3179 def test_qdisc_cake(self
):
3180 copy_unit_to_networkd_unit_path('25-qdisc-cake.network', '12-dummy.netdev')
3182 self
.wait_online(['dummy98:routable'])
3184 output
= check_output('tc qdisc show dev dummy98')
3186 self
.assertRegex(output
, 'qdisc cake 3a: root')
3187 self
.assertRegex(output
, 'bandwidth 500Mbit')
3188 self
.assertRegex(output
, 'overhead 128')
3190 @expectedFailureIfPIEIsNotAvailable()
3191 def test_qdisc_pie(self
):
3192 copy_unit_to_networkd_unit_path('25-qdisc-pie.network', '12-dummy.netdev')
3194 self
.wait_online(['dummy98:routable'])
3196 output
= check_output('tc qdisc show dev dummy98')
3198 self
.assertRegex(output
, 'qdisc pie 3a: root')
3199 self
.assertRegex(output
, 'limit 200000')
3201 @expectedFailureIfHHFIsNotAvailable()
3202 def test_qdisc_hhf(self
):
3203 copy_unit_to_networkd_unit_path('25-qdisc-hhf.network', '12-dummy.netdev')
3205 self
.wait_online(['dummy98:routable'])
3207 output
= check_output('tc qdisc show dev dummy98')
3209 self
.assertRegex(output
, 'qdisc hhf 3a: root')
3210 self
.assertRegex(output
, 'limit 1022p')
3212 @expectedFailureIfETSIsNotAvailable()
3213 def test_qdisc_ets(self
):
3214 copy_unit_to_networkd_unit_path('25-qdisc-ets.network', '12-dummy.netdev')
3216 self
.wait_online(['dummy98:routable'])
3218 output
= check_output('tc qdisc show dev dummy98')
3221 self
.assertRegex(output
, 'qdisc ets 3a: root')
3222 self
.assertRegex(output
, 'bands 10 strict 3')
3223 self
.assertRegex(output
, 'quanta 1 2 3 4 5')
3224 self
.assertRegex(output
, 'priomap 3 4 5 6 7')
3226 @expectedFailureIfFQPIEIsNotAvailable()
3227 def test_qdisc_fq_pie(self
):
3228 copy_unit_to_networkd_unit_path('25-qdisc-fq_pie.network', '12-dummy.netdev')
3230 self
.wait_online(['dummy98:routable'])
3232 output
= check_output('tc qdisc show dev dummy98')
3235 self
.assertRegex(output
, 'qdisc fq_pie 3a: root')
3236 self
.assertRegex(output
, 'limit 200000p')
3238 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable()
3239 def test_sriov(self
):
3240 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
3241 call('modprobe netdevsim', stderr
=subprocess
.DEVNULL
)
3242 with
open('/sys/bus/netdevsim/new_device', mode
='w') as f
:
3245 call('udevadm settle')
3246 call('udevadm info -w10s /sys/devices/netdevsim99/net/eni99np1', stderr
=subprocess
.DEVNULL
)
3247 with
open('/sys/class/net/eni99np1/device/sriov_numvfs', mode
='w') as f
:
3250 copy_unit_to_networkd_unit_path('25-sriov.network')
3252 self
.wait_online(['eni99np1:routable'])
3254 output
= check_output('ip link show dev eni99np1')
3256 self
.assertRegex(output
,
3257 '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 *'
3258 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
3259 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
3262 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
3264 def test_wait_online_ipv4(self
):
3265 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-with-ipv6-prefix.network', 'dhcp-client-ipv4-ipv6ra-prefix-client-with-delay.network')
3268 self
.wait_online(['veth99:routable'], ipv4
=True)
3270 self
.wait_address('veth99', r
'192.168.5.[0-9]+', ipv
='-4', timeout_sec
=1)
3272 def test_wait_online_ipv6(self
):
3273 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix-with-delay.network', 'ipv6ra-prefix-client-with-static-ipv4-address.network')
3276 self
.wait_online(['veth99:routable'], ipv6
=True)
3278 self
.wait_address('veth99', r
'2002:da8:1:0:1034:56ff:fe78:9abc', ipv
='-6', timeout_sec
=1)
3280 class NetworkdStateFileTests(unittest
.TestCase
, Utilities
):
3287 'state-file-tests.network',
3291 remove_links(self
.links
)
3292 stop_networkd(show_logs
=False)
3295 remove_links(self
.links
)
3296 remove_unit_from_networkd_path(self
.units
)
3297 stop_networkd(show_logs
=True)
3299 def test_state_file(self
):
3300 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'state-file-tests.network')
3302 self
.wait_online(['dummy98:routable'])
3304 output
= check_output(*networkctl_cmd
, '--no-legend', 'list', 'dummy98', env
=env
)
3306 ifindex
= output
.split()[0]
3308 path
= os
.path
.join('/run/systemd/netif/links/', ifindex
)
3309 self
.assertTrue(os
.path
.exists(path
))
3311 # make link state file updated
3312 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
3314 with
open(path
) as f
:
3316 self
.assertRegex(data
, r
'IPV4_ADDRESS_STATE=routable')
3317 self
.assertRegex(data
, r
'IPV6_ADDRESS_STATE=routable')
3318 self
.assertRegex(data
, r
'ADMIN_STATE=configured')
3319 self
.assertRegex(data
, r
'OPER_STATE=routable')
3320 self
.assertRegex(data
, r
'REQUIRED_FOR_ONLINE=yes')
3321 self
.assertRegex(data
, r
'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
3322 self
.assertRegex(data
, r
'REQUIRED_FAMILY_FOR_ONLINE=both')
3323 self
.assertRegex(data
, r
'ACTIVATION_POLICY=up')
3324 self
.assertRegex(data
, r
'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
3325 self
.assertRegex(data
, r
'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
3326 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
3327 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
3328 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
3329 self
.assertRegex(data
, r
'LLMNR=no')
3330 self
.assertRegex(data
, r
'MDNS=yes')
3331 self
.assertRegex(data
, r
'DNSSEC=no')
3333 check_output(*resolvectl_cmd
, 'dns', 'dummy98', '10.10.10.12#ccc.com', '10.10.10.13', '1111:2222::3333', env
=env
)
3334 check_output(*resolvectl_cmd
, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env
=env
)
3335 check_output(*resolvectl_cmd
, 'llmnr', 'dummy98', 'yes', env
=env
)
3336 check_output(*resolvectl_cmd
, 'mdns', 'dummy98', 'no', env
=env
)
3337 check_output(*resolvectl_cmd
, 'dnssec', 'dummy98', 'yes', env
=env
)
3338 check_output(*timedatectl_cmd
, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env
=env
)
3340 with
open(path
) as f
:
3342 self
.assertRegex(data
, r
'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333')
3343 self
.assertRegex(data
, r
'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org')
3344 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
3345 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
3346 self
.assertRegex(data
, r
'LLMNR=yes')
3347 self
.assertRegex(data
, r
'MDNS=no')
3348 self
.assertRegex(data
, r
'DNSSEC=yes')
3350 check_output(*timedatectl_cmd
, 'revert', 'dummy98', env
=env
)
3352 with
open(path
) as f
:
3354 self
.assertRegex(data
, r
'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333')
3355 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
3356 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
3357 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
3358 self
.assertRegex(data
, r
'LLMNR=yes')
3359 self
.assertRegex(data
, r
'MDNS=no')
3360 self
.assertRegex(data
, r
'DNSSEC=yes')
3362 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
3364 with
open(path
) as f
:
3366 self
.assertRegex(data
, r
'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
3367 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
3368 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
3369 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
3370 self
.assertRegex(data
, r
'LLMNR=no')
3371 self
.assertRegex(data
, r
'MDNS=yes')
3372 self
.assertRegex(data
, r
'DNSSEC=no')
3374 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
3384 '23-active-slave.network',
3385 '23-bond199.network',
3386 '23-primary-slave.network',
3387 '25-bond-active-backup-slave.netdev',
3390 'bond-slave.network']
3393 remove_links(self
.links
)
3394 stop_networkd(show_logs
=False)
3397 remove_links(self
.links
)
3398 remove_unit_from_networkd_path(self
.units
)
3399 stop_networkd(show_logs
=True)
3401 def test_bond_active_slave(self
):
3402 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
3404 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
3406 output
= check_output('ip -d link show bond199')
3408 self
.assertRegex(output
, 'active_slave dummy98')
3410 def test_bond_primary_slave(self
):
3411 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
3413 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
3415 output
= check_output('ip -d link show bond199')
3417 self
.assertRegex(output
, 'primary dummy98')
3419 def test_bond_operstate(self
):
3420 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
3421 'bond99.network','bond-slave.network')
3423 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
3425 output
= check_output('ip -d link show dummy98')
3427 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
3429 output
= check_output('ip -d link show test1')
3431 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
3433 output
= check_output('ip -d link show bond99')
3435 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
3437 self
.wait_operstate('dummy98', 'enslaved')
3438 self
.wait_operstate('test1', 'enslaved')
3439 self
.wait_operstate('bond99', 'routable')
3441 check_output('ip link set dummy98 down')
3443 self
.wait_operstate('dummy98', 'off')
3444 self
.wait_operstate('test1', 'enslaved')
3445 self
.wait_operstate('bond99', 'degraded-carrier')
3447 check_output('ip link set dummy98 up')
3449 self
.wait_operstate('dummy98', 'enslaved')
3450 self
.wait_operstate('test1', 'enslaved')
3451 self
.wait_operstate('bond99', 'routable')
3453 check_output('ip link set dummy98 down')
3454 check_output('ip link set test1 down')
3456 self
.wait_operstate('dummy98', 'off')
3457 self
.wait_operstate('test1', 'off')
3459 if not self
.wait_operstate('bond99', 'no-carrier', setup_timeout
=30, fail_assert
=False):
3460 # Huh? Kernel does not recognize that all slave interfaces are down?
3461 # Let's confirm that networkd's operstate is consistent with ip's result.
3462 self
.assertNotRegex(output
, 'NO-CARRIER')
3464 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
3478 '26-bridge-configure-without-carrier.network',
3479 '26-bridge-issue-20373.netdev',
3480 '26-bridge-mdb-master.network',
3481 '26-bridge-mdb-slave.network',
3482 '26-bridge-slave-interface-1.network',
3483 '26-bridge-slave-interface-2.network',
3484 '26-bridge-vlan-master-issue-20373.network',
3485 '26-bridge-vlan-master.network',
3486 '26-bridge-vlan-slave-issue-20373.network',
3487 '26-bridge-vlan-slave.network',
3488 'bridge99-ignore-carrier-loss.network',
3492 routing_policy_rule_tables
= ['100']
3495 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
3496 remove_links(self
.links
)
3497 stop_networkd(show_logs
=False)
3500 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
3501 remove_links(self
.links
)
3502 remove_unit_from_networkd_path(self
.units
)
3503 stop_networkd(show_logs
=True)
3505 def test_bridge_vlan(self
):
3506 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
3507 '26-bridge.netdev', '26-bridge-vlan-master.network')
3509 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
3511 output
= check_output('bridge vlan show dev test1')
3513 self
.assertNotRegex(output
, '4063')
3514 for i
in range(4064, 4095):
3515 self
.assertRegex(output
, f
'{i}')
3516 self
.assertNotRegex(output
, '4095')
3518 output
= check_output('bridge vlan show dev bridge99')
3520 self
.assertNotRegex(output
, '4059')
3521 for i
in range(4060, 4095):
3522 self
.assertRegex(output
, f
'{i}')
3523 self
.assertNotRegex(output
, '4095')
3525 def test_bridge_vlan_issue_20373(self
):
3526 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave-issue-20373.network',
3527 '26-bridge-issue-20373.netdev', '26-bridge-vlan-master-issue-20373.network',
3528 '21-vlan.netdev', '21-vlan.network')
3530 self
.wait_online(['test1:enslaved', 'bridge99:degraded', 'vlan99:routable'])
3532 output
= check_output('bridge vlan show dev test1')
3534 self
.assertIn('100 PVID Egress Untagged', output
)
3535 self
.assertIn('560', output
)
3536 self
.assertIn('600', output
)
3538 output
= check_output('bridge vlan show dev bridge99')
3540 self
.assertIn('1 PVID Egress Untagged', output
)
3541 self
.assertIn('100', output
)
3542 self
.assertIn('600', output
)
3544 def test_bridge_mdb(self
):
3545 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-mdb-slave.network',
3546 '26-bridge.netdev', '26-bridge-mdb-master.network')
3548 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
3550 output
= check_output('bridge mdb show dev bridge99')
3552 self
.assertRegex(output
, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064')
3553 self
.assertRegex(output
, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065')
3555 # Old kernel may not support bridge MDB entries on bridge master
3556 if call('bridge mdb add dev bridge99 port bridge99 grp 224.0.1.3 temp vid 4068', stderr
=subprocess
.DEVNULL
) == 0:
3557 self
.assertRegex(output
, 'dev bridge99 port bridge99 grp ff02:aaaa:fee5::1:4 temp *vid 4066')
3558 self
.assertRegex(output
, 'dev bridge99 port bridge99 grp 224.0.1.2 temp *vid 4067')
3560 def test_bridge_property(self
):
3561 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
3562 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
3565 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
3567 output
= check_output('ip -d link show test1')
3569 self
.assertRegex(output
, 'master')
3570 self
.assertRegex(output
, 'bridge')
3572 output
= check_output('ip -d link show dummy98')
3574 self
.assertRegex(output
, 'master')
3575 self
.assertRegex(output
, 'bridge')
3577 output
= check_output('ip addr show bridge99')
3579 self
.assertRegex(output
, '192.168.0.15/24')
3581 output
= check_output('bridge -d link show dummy98')
3583 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
3584 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
3585 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
3586 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
3587 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
3588 # CONFIG_BRIDGE_IGMP_SNOOPING=y
3589 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
3590 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
3591 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
3592 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
3593 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
3594 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'priority'), '23')
3595 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard'), '1')
3596 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'root_block'), '1')
3598 output
= check_output('bridge -d link show test1')
3600 self
.assertEqual(read_bridge_port_attr('bridge99', 'test1', 'priority'), '0')
3602 check_output('ip address add 192.168.0.16/24 dev bridge99')
3605 output
= check_output('ip addr show bridge99')
3607 self
.assertRegex(output
, '192.168.0.16/24')
3610 print('### ip -6 route list table all dev bridge99')
3611 output
= check_output('ip -6 route list table all dev bridge99')
3613 self
.assertRegex(output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
3615 self
.assertEqual(call('ip link del test1'), 0)
3617 self
.wait_operstate('bridge99', 'degraded-carrier')
3619 check_output('ip link del dummy98')
3621 self
.wait_operstate('bridge99', 'no-carrier')
3623 output
= check_output('ip address show bridge99')
3625 self
.assertRegex(output
, 'NO-CARRIER')
3626 self
.assertNotRegex(output
, '192.168.0.15/24')
3627 self
.assertNotRegex(output
, '192.168.0.16/24')
3629 print('### ip -6 route list table all dev bridge99')
3630 output
= check_output('ip -6 route list table all dev bridge99')
3632 self
.assertRegex(output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
3634 def test_bridge_configure_without_carrier(self
):
3635 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-configure-without-carrier.network',
3639 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
3640 for test
in ['no-slave', 'add-slave', 'slave-up', 'slave-no-carrier', 'slave-carrier', 'slave-down']:
3641 with self
.subTest(test
=test
):
3642 if test
== 'no-slave':
3643 # bridge has no slaves; it's up but *might* not have carrier
3644 self
.wait_operstate('bridge99', operstate
=r
'(no-carrier|routable)', setup_state
=None, setup_timeout
=30)
3645 # due to a bug in the kernel, newly-created bridges are brought up
3646 # *with* carrier, unless they have had any setting changed; e.g.
3647 # their mac set, priority set, etc. Then, they will lose carrier
3648 # as soon as a (down) slave interface is added, and regain carrier
3649 # again once the slave interface is brought up.
3650 #self.check_link_attr('bridge99', 'carrier', '0')
3651 elif test
== 'add-slave':
3652 # add slave to bridge, but leave it down; bridge is definitely no-carrier
3653 self
.check_link_attr('test1', 'operstate', 'down')
3654 check_output('ip link set dev test1 master bridge99')
3655 self
.wait_operstate('bridge99', operstate
='no-carrier', setup_state
=None)
3656 self
.check_link_attr('bridge99', 'carrier', '0')
3657 elif test
== 'slave-up':
3658 # bring up slave, which will have carrier; bridge gains carrier
3659 check_output('ip link set dev test1 up')
3660 self
.wait_online(['bridge99:routable'])
3661 self
.check_link_attr('bridge99', 'carrier', '1')
3662 elif test
== 'slave-no-carrier':
3663 # drop slave carrier; bridge loses carrier
3664 check_output('ip link set dev test1 carrier off')
3665 self
.wait_online(['bridge99:no-carrier:no-carrier'])
3666 self
.check_link_attr('bridge99', 'carrier', '0')
3667 elif test
== 'slave-carrier':
3668 # restore slave carrier; bridge gains carrier
3669 check_output('ip link set dev test1 carrier on')
3670 self
.wait_online(['bridge99:routable'])
3671 self
.check_link_attr('bridge99', 'carrier', '1')
3672 elif test
== 'slave-down':
3673 # bring down slave; bridge loses carrier
3674 check_output('ip link set dev test1 down')
3675 self
.wait_online(['bridge99:no-carrier:no-carrier'])
3676 self
.check_link_attr('bridge99', 'carrier', '0')
3678 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
3679 self
.assertRegex(output
, '10.1.2.3')
3680 self
.assertRegex(output
, '10.1.2.1')
3682 def test_bridge_ignore_carrier_loss(self
):
3683 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
3684 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
3685 'bridge99-ignore-carrier-loss.network')
3687 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
3689 check_output('ip address add 192.168.0.16/24 dev bridge99')
3692 check_output('ip link del test1')
3693 check_output('ip link del dummy98')
3696 output
= check_output('ip address show bridge99')
3698 self
.assertRegex(output
, 'NO-CARRIER')
3699 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
3700 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
3702 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
3703 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
3704 'bridge99-ignore-carrier-loss.network')
3706 self
.wait_online(['bridge99:no-carrier'])
3708 for trial
in range(4):
3709 check_output('ip link add dummy98 type dummy')
3710 check_output('ip link set dummy98 up')
3712 check_output('ip link del dummy98')
3714 self
.wait_online(['bridge99:routable', 'dummy98:enslaved'])
3716 output
= check_output('ip address show bridge99')
3718 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
3720 output
= check_output('ip rule list table 100')
3722 self
.assertIn('0: from all to 8.8.8.8 lookup 100', output
)
3724 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
3728 '23-emit-lldp.network',
3733 remove_links(self
.links
)
3734 stop_networkd(show_logs
=False)
3737 remove_links(self
.links
)
3738 remove_unit_from_networkd_path(self
.units
)
3739 stop_networkd(show_logs
=True)
3741 def test_lldp(self
):
3742 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
3744 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
3746 for trial
in range(10):
3750 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
3752 if re
.search(r
'veth99 .* veth-peer', output
):
3757 class NetworkdRATests(unittest
.TestCase
, Utilities
):
3762 'ipv6-prefix.network',
3763 'ipv6-prefix-veth.network',
3764 'ipv6-prefix-veth-token-static.network',
3765 'ipv6-prefix-veth-token-prefixstable.network',
3766 'ipv6-prefix-veth-token-prefixstable-without-address.network']
3769 remove_links(self
.links
)
3770 stop_networkd(show_logs
=False)
3773 remove_links(self
.links
)
3774 remove_unit_from_networkd_path(self
.units
)
3775 stop_networkd(show_logs
=True)
3777 def test_ipv6_prefix_delegation(self
):
3778 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
3780 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3782 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3784 self
.assertRegex(output
, 'fe80::')
3785 self
.assertRegex(output
, '2002:da8:1::1')
3787 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
3789 self
.assertIn('hogehoge.test', output
)
3791 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3793 self
.assertRegex(output
, '2002:da8:1:0')
3795 def test_ipv6_token_static(self
):
3796 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static.network')
3798 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3800 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3802 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
3803 self
.assertRegex(output
, '2002:da8:1:0:fa:de:ca:fe')
3804 self
.assertRegex(output
, '2002:da8:2:0:1a:2b:3c:4d')
3805 self
.assertRegex(output
, '2002:da8:2:0:fa:de:ca:fe')
3807 def test_ipv6_token_prefixstable(self
):
3808 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable.network')
3810 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3812 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3814 self
.assertRegex(output
, '2002:da8:1:0')
3815 self
.assertRegex(output
, '2002:da8:2:0.*78:9abc') # EUI
3817 def test_ipv6_token_prefixstable_without_address(self
):
3818 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable-without-address.network')
3820 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3822 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3824 self
.assertRegex(output
, '2002:da8:1:0')
3825 self
.assertRegex(output
, '2002:da8:2:0')
3827 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
3836 'dhcp-client.network',
3837 'dhcp-client-static-lease.network',
3838 'dhcp-client-timezone-router.network',
3839 'dhcp-server.network',
3840 'dhcp-server-static-lease.network',
3841 'dhcp-server-timezone-router.network',
3842 'dhcp-server-uplink.network',
3846 remove_links(self
.links
)
3847 stop_networkd(show_logs
=False)
3850 remove_links(self
.links
)
3851 remove_unit_from_networkd_path(self
.units
)
3852 stop_networkd(show_logs
=True)
3854 def test_dhcp_server(self
):
3855 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network',
3856 '12-dummy.netdev', 'dhcp-server-uplink.network')
3858 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3860 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3862 self
.assertRegex(output
, '192.168.5.*')
3863 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
3864 self
.assertRegex(output
, 'DNS: 192.168.5.1')
3865 self
.assertRegex(output
, 'NTP: 192.168.5.1')
3867 def test_emit_router_timezone(self
):
3868 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
3870 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3872 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3874 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
3875 self
.assertRegex(output
, '192.168.5.*')
3876 self
.assertRegex(output
, 'Europe/Berlin')
3878 def test_dhcp_server_static_lease(self
):
3879 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-static-lease.network', 'dhcp-server-static-lease.network')
3881 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3883 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3885 self
.assertIn('10.1.1.200 (DHCP4 via 10.1.1.1)', output
)
3887 class NetworkdDHCPServerRelayAgentTests(unittest
.TestCase
, Utilities
):
3896 'agent-veth-client.netdev',
3897 'agent-veth-server.netdev',
3898 'agent-client.network',
3899 'agent-server.network',
3900 'agent-client-peer.network',
3901 'agent-server-peer.network',
3905 remove_links(self
.links
)
3906 stop_networkd(show_logs
=False)
3909 remove_links(self
.links
)
3910 remove_unit_from_networkd_path(self
.units
)
3911 stop_networkd(show_logs
=True)
3913 def test_relay_agent(self
):
3914 copy_unit_to_networkd_unit_path(*self
.units
)
3917 self
.wait_online(['client:routable'])
3919 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'client', env
=env
)
3921 self
.assertRegex(output
, 'Address: 192.168.5.150 \(DHCP4 via 192.168.5.1\)')
3923 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
3932 'dhcp-client-anonymize.network',
3933 'dhcp-client-decline.network',
3934 'dhcp-client-gateway-ipv4.network',
3935 'dhcp-client-gateway-ipv6.network',
3936 'dhcp-client-gateway-onlink-implicit.network',
3937 'dhcp-client-ipv4-dhcp-settings.network',
3938 'dhcp-client-ipv4-only-ipv6-disabled.network',
3939 'dhcp-client-ipv4-only.network',
3940 'dhcp-client-ipv4-use-routes-use-gateway.network',
3941 'dhcp-client-ipv6-only.network',
3942 'dhcp-client-ipv6-rapid-commit.network',
3943 'dhcp-client-keep-configuration-dhcp-on-stop.network',
3944 'dhcp-client-keep-configuration-dhcp.network',
3945 'dhcp-client-listen-port.network',
3946 'dhcp-client-reassign-static-routes-ipv4.network',
3947 'dhcp-client-reassign-static-routes-ipv6.network',
3948 'dhcp-client-route-metric.network',
3949 'dhcp-client-route-table.network',
3950 'dhcp-client-use-dns-ipv4-and-ra.network',
3951 'dhcp-client-use-dns-ipv4.network',
3952 'dhcp-client-use-dns-no.network',
3953 'dhcp-client-use-dns-yes.network',
3954 'dhcp-client-use-domains.network',
3955 'dhcp-client-vrf.network',
3956 'dhcp-client-with-ipv4ll.network',
3957 'dhcp-client-with-static-address.network',
3958 'dhcp-client.network',
3959 'dhcp-server-decline.network',
3960 'dhcp-server-veth-peer.network',
3961 'dhcp-v4-server-veth-peer.network',
3965 stop_dnsmasq(dnsmasq_pid_file
)
3966 remove_links(self
.links
)
3967 stop_networkd(show_logs
=False)
3970 stop_dnsmasq(dnsmasq_pid_file
)
3973 remove_links(self
.links
)
3974 remove_unit_from_networkd_path(self
.units
)
3975 stop_networkd(show_logs
=True)
3977 def test_dhcp_client_ipv6_only(self
):
3978 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3981 self
.wait_online(['veth-peer:carrier'])
3983 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3985 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3987 self
.assertRegex(output
, '2600::')
3988 self
.assertNotRegex(output
, '192.168.5')
3990 output
= check_output('ip addr show dev veth99')
3992 self
.assertRegex(output
, '2600::')
3993 self
.assertNotRegex(output
, '192.168.5')
3994 self
.assertNotRegex(output
, 'tentative')
3996 # Confirm that ipv6 token is not set in the kernel
3997 output
= check_output('ip token show dev veth99')
3999 self
.assertRegex(output
, 'token :: dev veth99')
4001 def test_dhcp_client_ipv4_only(self
):
4002 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
4005 self
.wait_online(['veth-peer:carrier'])
4006 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
4007 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4009 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4011 self
.assertNotRegex(output
, '2600::')
4012 self
.assertRegex(output
, '192.168.5')
4013 self
.assertRegex(output
, '192.168.5.6')
4014 self
.assertRegex(output
, '192.168.5.7')
4016 # checking routes to DNS servers
4017 output
= check_output('ip route show dev veth99')
4019 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
4020 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
4021 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
4023 stop_dnsmasq(dnsmasq_pid_file
)
4024 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8', lease_time
='2m')
4026 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4027 print('Wait for the dynamic address to be renewed')
4030 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4032 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4034 self
.assertNotRegex(output
, '2600::')
4035 self
.assertRegex(output
, '192.168.5')
4036 self
.assertNotRegex(output
, '192.168.5.6')
4037 self
.assertRegex(output
, '192.168.5.7')
4038 self
.assertRegex(output
, '192.168.5.8')
4040 # checking routes to DNS servers
4041 output
= check_output('ip route show dev veth99')
4043 self
.assertNotRegex(output
, r
'192.168.5.6')
4044 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
4045 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
4046 self
.assertRegex(output
, r
'192.168.5.8 proto dhcp scope link src 192.168.5.181 metric 1024')
4048 def test_dhcp_client_ipv4_use_routes_gateway(self
):
4049 for (routes
, gateway
, dns_and_ntp_routes
, classless
) in itertools
.product([True, False], repeat
=4):
4051 with self
.subTest(routes
=routes
, gateway
=gateway
, dns_and_ntp_routes
=dns_and_ntp_routes
, classless
=classless
):
4052 self
._test
_dhcp
_client
_ipv
4_use
_routes
_gateway
(routes
, gateway
, dns_and_ntp_routes
, classless
)
4055 def _test_dhcp_client_ipv4_use_routes_gateway(self
, use_routes
, use_gateway
, dns_and_ntp_routes
, classless
):
4056 testunit
= 'dhcp-client-ipv4-use-routes-use-gateway.network'
4057 testunits
= ['25-veth.netdev', 'dhcp-server-veth-peer.network', testunit
]
4058 testunits
.append(f
'{testunit}.d/use-routes-{use_routes}.conf');
4059 testunits
.append(f
'{testunit}.d/use-gateway-{use_gateway}.conf');
4060 testunits
.append(f
'{testunit}.d/use-dns-and-ntp-routes-{dns_and_ntp_routes}.conf');
4061 copy_unit_to_networkd_unit_path(*testunits
, dropins
=False)
4064 self
.wait_online(['veth-peer:carrier'])
4065 additional_options
= '--dhcp-option=option:dns-server,192.168.5.10,8.8.8.8 --dhcp-option=option:ntp-server,192.168.5.11,9.9.9.9 --dhcp-option=option:static-route,192.168.5.100,192.168.5.2,8.8.8.8,192.168.5.3'
4067 additional_options
+= ' --dhcp-option=option:classless-static-route,0.0.0.0/0,192.168.5.4,8.0.0.0/8,192.168.5.5'
4068 start_dnsmasq(additional_options
=additional_options
, lease_time
='2m')
4069 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4071 output
= check_output('ip -4 route show dev veth99')
4077 self
.assertRegex(output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
4078 self
.assertRegex(output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
4079 self
.assertRegex(output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4080 self
.assertRegex(output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4082 self
.assertRegex(output
, r
'192.168.5.0/24 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4083 self
.assertRegex(output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024')
4084 self
.assertRegex(output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4086 self
.assertNotRegex(output
, r
'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
4087 self
.assertNotRegex(output
, r
'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
4088 self
.assertNotRegex(output
, r
'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4089 self
.assertNotRegex(output
, r
'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4090 self
.assertNotRegex(output
, r
'192.168.5.0/24 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4091 self
.assertNotRegex(output
, r
'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024')
4092 self
.assertNotRegex(output
, r
'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4095 if use_gateway
and (not classless
or not use_routes
):
4096 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
4098 self
.assertNotRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
4100 # Check route to gateway
4101 if (use_gateway
or dns_and_ntp_routes
) and (not classless
or not use_routes
):
4102 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4104 self
.assertNotRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4106 # Check RoutesToDNS= and RoutesToNTP=
4107 if dns_and_ntp_routes
:
4108 self
.assertRegex(output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4109 self
.assertRegex(output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4110 if classless
and use_routes
:
4111 self
.assertRegex(output
, r
'8.8.8.8 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
4112 self
.assertRegex(output
, r
'9.9.9.9 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
4114 self
.assertRegex(output
, r
'8.8.8.8 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
4115 self
.assertRegex(output
, r
'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
4117 self
.assertNotRegex(output
, r
'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4118 self
.assertNotRegex(output
, r
'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4119 self
.assertNotRegex(output
, r
'8.8.8.8 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024')
4120 self
.assertNotRegex(output
, r
'9.9.9.9 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024')
4122 def test_dhcp_client_ipv4_ipv6(self
):
4123 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
4124 'dhcp-client-ipv4-only.network')
4126 self
.wait_online(['veth-peer:carrier'])
4128 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4130 # link become 'routable' when at least one protocol provide an valid address.
4131 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4132 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4134 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4136 self
.assertRegex(output
, '2600::')
4137 self
.assertRegex(output
, '192.168.5')
4139 def test_dhcp_client_settings(self
):
4140 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
4143 self
.wait_online(['veth-peer:carrier'])
4145 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4147 print('## ip address show dev veth99')
4148 output
= check_output('ip address show dev veth99')
4150 self
.assertRegex(output
, '12:34:56:78:9a:bc')
4151 self
.assertRegex(output
, '192.168.5')
4152 self
.assertRegex(output
, '1492')
4153 self
.assertRegex(output
, 'test-label')
4155 print('## ip route show table main dev veth99')
4156 output
= check_output('ip route show table main dev veth99')
4159 main_table_is_empty
= output
== ''
4160 if not main_table_is_empty
:
4161 self
.assertNotRegex(output
, 'proto dhcp')
4163 print('## ip route show table 211 dev veth99')
4164 output
= check_output('ip route show table 211 dev veth99')
4166 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
4167 if main_table_is_empty
:
4168 self
.assertRegex(output
, '192.168.5.0/24 proto dhcp')
4169 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
4171 print('## dnsmasq log')
4172 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
4173 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
4174 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
4175 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
4177 def test_dhcp6_client_settings_rapidcommit_true(self
):
4178 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
4180 self
.wait_online(['veth-peer:carrier'])
4182 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4184 output
= check_output('ip address show dev veth99')
4186 self
.assertRegex(output
, '12:34:56:78:9a:bc')
4187 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
4189 def test_dhcp6_client_settings_rapidcommit_false(self
):
4190 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
4192 self
.wait_online(['veth-peer:carrier'])
4194 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4196 output
= check_output('ip address show dev veth99')
4198 self
.assertRegex(output
, '12:34:56:78:9a:bc')
4199 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
4201 def test_dhcp_client_settings_anonymize(self
):
4202 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
4204 self
.wait_online(['veth-peer:carrier'])
4206 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4208 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
4209 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
4210 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
4212 def test_dhcp_client_listen_port(self
):
4213 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
4215 self
.wait_online(['veth-peer:carrier'])
4216 start_dnsmasq('--dhcp-alternate-port=67,5555')
4217 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4219 output
= check_output('ip -4 address show dev veth99')
4221 self
.assertRegex(output
, '192.168.5.* dynamic')
4223 def test_dhcp_client_with_static_address(self
):
4224 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
4225 'dhcp-client-with-static-address.network')
4227 self
.wait_online(['veth-peer:carrier'])
4229 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4231 output
= check_output('ip address show dev veth99 scope global')
4233 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
4234 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global secondary dynamic veth99')
4236 output
= check_output('ip route show dev veth99')
4238 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
4239 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
4240 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4242 def test_dhcp_route_table_id(self
):
4243 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
4245 self
.wait_online(['veth-peer:carrier'])
4247 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4249 output
= check_output('ip route show table 12')
4251 self
.assertRegex(output
, 'veth99 proto dhcp')
4252 self
.assertRegex(output
, '192.168.5.1')
4254 def test_dhcp_route_metric(self
):
4255 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
4257 self
.wait_online(['veth-peer:carrier'])
4259 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4261 output
= check_output('ip route show dev veth99')
4263 self
.assertIn('default via 192.168.5.1 proto dhcp src 192.168.5.181 metric 24', output
)
4264 self
.assertIn('192.168.5.0/24 proto kernel scope link src 192.168.5.181 metric 24', output
)
4265 self
.assertIn('192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 24', output
)
4267 def test_dhcp_client_reassign_static_routes_ipv4(self
):
4268 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4269 'dhcp-client-reassign-static-routes-ipv4.network')
4271 self
.wait_online(['veth-peer:carrier'])
4272 start_dnsmasq(lease_time
='2m')
4273 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4275 output
= check_output('ip address show dev veth99 scope global')
4277 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
4279 output
= check_output('ip route show dev veth99')
4281 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
4282 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
4283 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
4284 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
4286 stop_dnsmasq(dnsmasq_pid_file
)
4287 start_dnsmasq(ipv4_range
='192.168.5.210,192.168.5.220', lease_time
='2m')
4289 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4290 print('Wait for the dynamic address to be renewed')
4293 self
.wait_online(['veth99:routable'])
4295 output
= check_output('ip route show dev veth99')
4297 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
4298 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
4299 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
4300 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
4302 def test_dhcp_client_reassign_static_routes_ipv6(self
):
4303 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4304 'dhcp-client-reassign-static-routes-ipv6.network')
4306 self
.wait_online(['veth-peer:carrier'])
4307 start_dnsmasq(lease_time
='2m')
4308 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4310 output
= check_output('ip address show dev veth99 scope global')
4312 self
.assertRegex(output
, r
'inet6 2600::[0-9a-f]*/128 scope global (noprefixroute dynamic|dynamic noprefixroute)')
4314 output
= check_output('ip -6 route show dev veth99')
4316 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
4317 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
4319 stop_dnsmasq(dnsmasq_pid_file
)
4320 start_dnsmasq(ipv6_range
='2600::30,2600::40', lease_time
='2m')
4322 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4323 print('Wait for the dynamic address to be renewed')
4326 self
.wait_online(['veth99:routable'])
4328 output
= check_output('ip -6 route show dev veth99')
4330 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
4331 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
4333 def test_dhcp_keep_configuration_dhcp(self
):
4334 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
4336 self
.wait_online(['veth-peer:carrier'])
4337 start_dnsmasq(lease_time
='2m')
4338 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4340 output
= check_output('ip address show dev veth99 scope global')
4342 self
.assertRegex(output
, r
'192.168.5.*')
4344 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4346 self
.assertRegex(output
, r
'192.168.5.*')
4348 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
4349 stop_dnsmasq(dnsmasq_pid_file
)
4351 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4352 print('Wait for the dynamic address to be expired')
4355 print('The lease address should be kept after lease expired')
4356 output
= check_output('ip address show dev veth99 scope global')
4358 self
.assertRegex(output
, r
'192.168.5.*')
4360 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4362 self
.assertRegex(output
, r
'192.168.5.*')
4364 check_output('systemctl stop systemd-networkd.socket')
4365 check_output('systemctl stop systemd-networkd.service')
4367 print('The lease address should be kept after networkd stopped')
4368 output
= check_output('ip address show dev veth99 scope global')
4370 self
.assertRegex(output
, r
'192.168.5.*')
4372 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4374 self
.assertRegex(output
, r
'192.168.5.*')
4377 self
.wait_online(['veth-peer:routable'])
4379 print('Still the lease address should be kept after networkd restarted')
4380 output
= check_output('ip address show dev veth99 scope global')
4382 self
.assertRegex(output
, r
'192.168.5.*')
4384 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4386 self
.assertRegex(output
, r
'192.168.5.*')
4388 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
4389 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
4391 self
.wait_online(['veth-peer:carrier'])
4392 start_dnsmasq(lease_time
='2m')
4393 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4395 output
= check_output('ip address show dev veth99 scope global')
4397 self
.assertRegex(output
, r
'192.168.5.*')
4399 stop_dnsmasq(dnsmasq_pid_file
)
4400 check_output('systemctl stop systemd-networkd.socket')
4401 check_output('systemctl stop systemd-networkd.service')
4403 output
= check_output('ip address show dev veth99 scope global')
4405 self
.assertRegex(output
, r
'192.168.5.*')
4408 self
.wait_online(['veth-peer:routable'])
4410 output
= check_output('ip address show dev veth99 scope global')
4412 self
.assertNotRegex(output
, r
'192.168.5.*')
4414 def test_dhcp_client_reuse_address_as_static(self
):
4415 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
4417 self
.wait_online(['veth-peer:carrier'])
4419 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4421 # link become 'routable' when at least one protocol provide an valid address.
4422 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4423 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4425 output
= check_output('ip address show dev veth99 scope global')
4427 self
.assertRegex(output
, '192.168.5')
4428 self
.assertRegex(output
, '2600::')
4430 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
4431 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
4432 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
4433 print(static_network
)
4435 remove_unit_from_networkd_path(['dhcp-client.network'])
4437 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
4438 f
.write(static_network
)
4440 # When networkd started, the links are already configured, so let's wait for 5 seconds
4441 # the links to be re-configured.
4443 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4445 output
= check_output('ip -4 address show dev veth99 scope global')
4447 self
.assertRegex(output
, '192.168.5')
4448 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
4450 output
= check_output('ip -6 address show dev veth99 scope global')
4452 self
.assertRegex(output
, '2600::')
4453 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
4455 @expectedFailureIfModuleIsNotAvailable('vrf')
4456 def test_dhcp_client_vrf(self
):
4457 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
4458 '25-vrf.netdev', '25-vrf.network')
4460 self
.wait_online(['veth-peer:carrier'])
4462 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
4464 # link become 'routable' when at least one protocol provide an valid address.
4465 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4466 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4468 print('## ip -d link show dev vrf99')
4469 output
= check_output('ip -d link show dev vrf99')
4471 self
.assertRegex(output
, 'vrf table 42')
4473 print('## ip address show vrf vrf99')
4474 output
= check_output('ip address show vrf vrf99')
4476 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
4477 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
4478 self
.assertRegex(output
, 'inet6 .* scope link')
4480 print('## ip address show dev veth99')
4481 output
= check_output('ip address show dev veth99')
4483 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
4484 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
4485 self
.assertRegex(output
, 'inet6 .* scope link')
4487 print('## ip route show vrf vrf99')
4488 output
= check_output('ip route show vrf vrf99')
4490 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
4491 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
4492 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
4494 print('## ip route show table main dev veth99')
4495 output
= check_output('ip route show table main dev veth99')
4497 self
.assertEqual(output
, '')
4499 def test_dhcp_client_gateway_ipv4(self
):
4500 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4501 'dhcp-client-gateway-ipv4.network')
4503 self
.wait_online(['veth-peer:carrier'])
4505 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4507 output
= check_output('ip route list dev veth99')
4509 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]*')
4510 self
.assertIn('10.0.0.0/8 via 192.168.5.1 proto dhcp', output
)
4512 with
open(os
.path
.join(network_unit_file_path
, 'dhcp-client-gateway-ipv4.network'), mode
='a') as f
:
4513 f
.write('[DHCPv4]\nUseGateway=no\n')
4515 rc
= call(*networkctl_cmd
, 'reload', env
=env
)
4516 self
.assertEqual(rc
, 0)
4519 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4521 output
= check_output('ip route list dev veth99')
4523 self
.assertNotRegex(output
, 'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]*')
4524 self
.assertIn('10.0.0.0/8 via 192.168.5.1 proto dhcp', output
)
4526 def test_dhcp_client_gateway_ipv6(self
):
4527 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4528 'dhcp-client-gateway-ipv6.network')
4530 self
.wait_online(['veth-peer:carrier'])
4532 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4534 output
= check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
4536 self
.assertRegex(output
, 'via fe80::1034:56ff:fe78:9abd')
4538 def test_dhcp_client_gateway_onlink_implicit(self
):
4539 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4540 'dhcp-client-gateway-onlink-implicit.network')
4542 self
.wait_online(['veth-peer:carrier'])
4544 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4546 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4548 self
.assertRegex(output
, '192.168.5')
4550 output
= check_output('ip route list dev veth99 10.0.0.0/8')
4552 self
.assertRegex(output
, 'onlink')
4553 output
= check_output('ip route list dev veth99 192.168.100.0/24')
4555 self
.assertRegex(output
, 'onlink')
4557 def test_dhcp_client_with_ipv4ll_with_dhcp_server(self
):
4558 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4559 'dhcp-client-with-ipv4ll.network')
4561 self
.wait_online(['veth-peer:carrier'])
4562 start_dnsmasq(lease_time
='2m')
4563 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4565 output
= check_output('ip address show dev veth99')
4568 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
4569 self
.assertNotRegex(output
, r
'inet6 2600::[0-9a-f]+/128 scope global dynamic')
4570 output
= check_output('ip -6 address show dev veth99 scope link')
4571 self
.assertRegex(output
, r
'inet6 .* scope link')
4572 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
4573 self
.assertRegex(output
, r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99')
4574 output
= check_output('ip -4 address show dev veth99 scope link')
4575 self
.assertNotRegex(output
, r
'inet 169\.254\.\d+\.\d+/16 metric 2048 brd 169\.254\.255\.255 scope link')
4577 print('Wait for the dynamic address to be expired')
4580 output
= check_output('ip address show dev veth99')
4583 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
4584 self
.assertNotRegex(output
, r
'inet6 2600::[0-9a-f]+/128 scope global dynamic')
4585 output
= check_output('ip -6 address show dev veth99 scope link')
4586 self
.assertRegex(output
, r
'inet6 .* scope link')
4587 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
4588 self
.assertRegex(output
, r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99')
4589 output
= check_output('ip -4 address show dev veth99 scope link')
4590 self
.assertNotRegex(output
, r
'inet 169\.254\.\d+\.\d+/16 metric 2048 brd 169\.254\.255\.255 scope link')
4592 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
4594 def test_dhcp_client_with_ipv4ll_without_dhcp_server(self
):
4595 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4596 'dhcp-client-with-ipv4ll.network')
4598 # we need to increase timeout above default, as this will need to wait for
4599 # systemd-networkd to get the dhcpv4 transient failure event
4600 self
.wait_online(['veth99:degraded', 'veth-peer:routable'], timeout
='60s')
4602 output
= check_output('ip address show dev veth99')
4605 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
4606 self
.assertNotRegex(output
, r
'inet6 2600::[0-9a-f]+/128 scope global dynamic')
4607 output
= check_output('ip -6 address show dev veth99 scope link')
4608 self
.assertRegex(output
, r
'inet6 .* scope link')
4609 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
4610 self
.assertNotRegex(output
, r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99')
4611 output
= check_output('ip -4 address show dev veth99 scope link')
4612 self
.assertRegex(output
, r
'inet 169\.254\.\d+\.\d+/16 metric 2048 brd 169\.254\.255\.255 scope link')
4614 start_dnsmasq(lease_time
='2m')
4615 self
.wait_address('veth99', r
'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic', ipv
='-4')
4616 self
.wait_address_dropped('veth99', r
'inet 169\.254\.\d+\.\d+/16 metric 2048 brd 169\.255\.255\.255 scope link', scope
='link', ipv
='-4')
4618 def test_dhcp_client_route_remove_on_renew(self
):
4619 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4620 'dhcp-client-ipv4-only-ipv6-disabled.network')
4622 self
.wait_online(['veth-peer:carrier'])
4623 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
4624 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4626 # test for issue #12490
4628 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
4630 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
4632 for line
in output
.splitlines():
4633 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
4634 address1
= line
.split()[1].split('/')[0]
4637 output
= check_output('ip -4 route show dev veth99')
4639 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
4640 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
4642 stop_dnsmasq(dnsmasq_pid_file
)
4643 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
4645 print('Wait for the dynamic address to be expired')
4648 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
4650 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
4652 for line
in output
.splitlines():
4653 if 'metric 1024 brd 192.168.5.255 scope global dynamic veth99' in line
:
4654 address2
= line
.split()[1].split('/')[0]
4657 self
.assertNotEqual(address1
, address2
)
4659 output
= check_output('ip -4 route show dev veth99')
4661 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
4662 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
4663 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
4664 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
4666 def test_dhcp_client_use_dns_yes(self
):
4667 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-yes.network')
4670 self
.wait_online(['veth-peer:carrier'])
4671 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
4672 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4674 # link become 'routable' when at least one protocol provide an valid address.
4675 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4676 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4679 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
4681 self
.assertRegex(output
, '192.168.5.1')
4682 self
.assertRegex(output
, '2600::1')
4684 def test_dhcp_client_use_dns_no(self
):
4685 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-no.network')
4688 self
.wait_online(['veth-peer:carrier'])
4689 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
4690 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4692 # link become 'routable' when at least one protocol provide an valid address.
4693 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4694 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4697 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
4699 self
.assertNotRegex(output
, '192.168.5.1')
4700 self
.assertNotRegex(output
, '2600::1')
4702 def test_dhcp_client_use_dns_ipv4(self
):
4703 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4.network')
4706 self
.wait_online(['veth-peer:carrier'])
4707 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
4708 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4710 # link become 'routable' when at least one protocol provide an valid address.
4711 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4712 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4715 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
4717 self
.assertRegex(output
, '192.168.5.1')
4718 self
.assertNotRegex(output
, '2600::1')
4720 def test_dhcp_client_use_dns_ipv4_and_ra(self
):
4721 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4-and-ra.network')
4724 self
.wait_online(['veth-peer:carrier'])
4725 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
4726 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4728 # link become 'routable' when at least one protocol provide an valid address.
4729 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4730 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4733 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
4735 self
.assertRegex(output
, '192.168.5.1')
4736 self
.assertRegex(output
, '2600::1')
4738 def test_dhcp_client_use_domains(self
):
4739 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-domains.network')
4742 self
.wait_online(['veth-peer:carrier'])
4743 start_dnsmasq('--dhcp-option=option:domain-search,example.com')
4744 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4746 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4748 self
.assertRegex(output
, 'Search Domains: example.com')
4751 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
4753 self
.assertRegex(output
, 'example.com')
4755 def test_dhcp_client_decline(self
):
4756 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-decline.network', 'dhcp-client-decline.network')
4759 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4761 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
4763 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
4765 class NetworkdIPv6PrefixTests(unittest
.TestCase
, Utilities
):
4774 'ipv6ra-prefix-client-deny-list.network',
4775 'ipv6ra-prefix-client.network',
4776 'ipv6ra-prefix.network',
4777 'ipv6ra-uplink.network',
4781 remove_links(self
.links
)
4782 stop_networkd(show_logs
=False)
4786 remove_links(self
.links
)
4787 remove_unit_from_networkd_path(self
.units
)
4788 stop_networkd(show_logs
=True)
4790 def test_ipv6_route_prefix(self
):
4791 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client.network', 'ipv6ra-prefix.network',
4792 '12-dummy.netdev', 'ipv6ra-uplink.network')
4795 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'dummy98:routable'])
4797 output
= check_output('ip address show dev veth-peer')
4799 self
.assertIn('inet6 2001:db8:0:1:', output
)
4800 self
.assertNotIn('inet6 2001:db8:0:2:', output
)
4802 output
= check_output('ip -6 route show dev veth-peer')
4804 self
.assertIn('2001:db8:0:1::/64 proto ra', output
)
4805 self
.assertNotIn('2001:db8:0:2::/64 proto ra', output
)
4806 self
.assertIn('2001:db0:fff::/64 via ', output
)
4807 self
.assertNotIn('2001:db1:fff::/64 via ', output
)
4809 output
= check_output('ip address show dev veth99')
4811 self
.assertNotIn('inet6 2001:db8:0:1:', output
)
4812 self
.assertIn('inet6 2001:db8:0:2:', output
)
4814 output
= check_output(*resolvectl_cmd
, 'dns', 'veth-peer', env
=env
)
4816 self
.assertRegex(output
, '2001:db8:1:1::2')
4818 output
= check_output(*resolvectl_cmd
, 'domain', 'veth-peer', env
=env
)
4820 self
.assertIn('example.com', output
)
4822 def test_ipv6_route_prefix_deny_list(self
):
4823 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client-deny-list.network', 'ipv6ra-prefix.network',
4824 '12-dummy.netdev', 'ipv6ra-uplink.network')
4827 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'dummy98:routable'])
4829 output
= check_output('ip address show dev veth-peer')
4831 self
.assertIn('inet6 2001:db8:0:1:', output
)
4832 self
.assertNotIn('inet6 2001:db8:0:2:', output
)
4834 output
= check_output('ip -6 route show dev veth-peer')
4836 self
.assertIn('2001:db8:0:1::/64 proto ra', output
)
4837 self
.assertNotIn('2001:db8:0:2::/64 proto ra', output
)
4838 self
.assertIn('2001:db0:fff::/64 via ', output
)
4839 self
.assertNotIn('2001:db1:fff::/64 via ', output
)
4841 output
= check_output('ip address show dev veth99')
4843 self
.assertNotIn('inet6 2001:db8:0:1:', output
)
4844 self
.assertIn('inet6 2001:db8:0:2:', output
)
4846 output
= check_output(*resolvectl_cmd
, 'dns', 'veth-peer', env
=env
)
4848 self
.assertRegex(output
, '2001:db8:1:1::2')
4850 output
= check_output(*resolvectl_cmd
, 'domain', 'veth-peer', env
=env
)
4852 self
.assertIn('example.com', output
)
4854 class NetworkdMTUTests(unittest
.TestCase
, Utilities
):
4859 '12-dummy-mtu.netdev',
4860 '12-dummy-mtu.link',
4865 remove_links(self
.links
)
4866 stop_networkd(show_logs
=False)
4870 remove_links(self
.links
)
4871 remove_unit_from_networkd_path(self
.units
)
4872 stop_networkd(show_logs
=True)
4874 def check_mtu(self
, mtu
, ipv6_mtu
=None, reset
=True):
4880 self
.wait_online(['dummy98:routable'])
4881 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
4882 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
4884 # test normal restart
4886 self
.wait_online(['dummy98:routable'])
4887 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
4888 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
4891 self
.reset_check_mtu(mtu
, ipv6_mtu
)
4893 def reset_check_mtu(self
, mtu
, ipv6_mtu
=None):
4894 ''' test setting mtu/ipv6_mtu with interface already up '''
4897 # note - changing the device mtu resets the ipv6 mtu
4898 run('ip link set up mtu 1501 dev dummy98')
4899 run('ip link set up mtu 1500 dev dummy98')
4900 self
.assertEqual(read_link_attr('dummy98', 'mtu'), '1500')
4901 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), '1500')
4903 self
.check_mtu(mtu
, ipv6_mtu
, reset
=False)
4905 def test_mtu_network(self
):
4906 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
4907 self
.check_mtu('1600')
4909 def test_mtu_netdev(self
):
4910 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network', dropins
=False)
4911 # note - MTU set by .netdev happens ONLY at device creation!
4912 self
.check_mtu('1600', reset
=False)
4914 def test_mtu_link(self
):
4915 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', dropins
=False)
4916 # must reload udev because it only picks up new files after 3 second delay
4917 call('udevadm control --reload')
4918 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
4919 self
.check_mtu('1600', reset
=False)
4921 def test_ipv6_mtu(self
):
4922 ''' set ipv6 mtu without setting device mtu '''
4923 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
4924 self
.check_mtu('1500', '1400')
4926 def test_ipv6_mtu_toolarge(self
):
4927 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
4928 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
4929 self
.check_mtu('1500', '1500')
4931 def test_mtu_network_ipv6_mtu(self
):
4932 ''' set ipv6 mtu and set device mtu via network file '''
4933 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
4934 self
.check_mtu('1600', '1550')
4936 def test_mtu_netdev_ipv6_mtu(self
):
4937 ''' set ipv6 mtu and set device mtu via netdev file '''
4938 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
4939 self
.check_mtu('1600', '1550', reset
=False)
4941 def test_mtu_link_ipv6_mtu(self
):
4942 ''' set ipv6 mtu and set device mtu via link file '''
4943 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
4944 # must reload udev because it only picks up new files after 3 second delay
4945 call('udevadm control --reload')
4946 self
.check_mtu('1600', '1550', reset
=False)
4949 if __name__
== '__main__':
4950 parser
= argparse
.ArgumentParser()
4951 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
4952 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
4953 parser
.add_argument('--resolved', help='Path to systemd-resolved', dest
='resolved_bin')
4954 parser
.add_argument('--udevd', help='Path to systemd-udevd', dest
='udevd_bin')
4955 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
4956 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
4957 parser
.add_argument('--resolvectl', help='Path to resolvectl', dest
='resolvectl_bin')
4958 parser
.add_argument('--timedatectl', help='Path to timedatectl', dest
='timedatectl_bin')
4959 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
4960 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
4961 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
4962 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
4963 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
4964 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
4967 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
:
4968 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
4969 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
4970 resolved_bin
= os
.path
.join(ns
.build_dir
, 'systemd-resolved')
4971 udevd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-udevd')
4972 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
4973 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
4974 resolvectl_bin
= os
.path
.join(ns
.build_dir
, 'resolvectl')
4975 timedatectl_bin
= os
.path
.join(ns
.build_dir
, 'timedatectl')
4978 networkd_bin
= ns
.networkd_bin
4980 resolved_bin
= ns
.resolved_bin
4982 udevd_bin
= ns
.udevd_bin
4983 if ns
.wait_online_bin
:
4984 wait_online_bin
= ns
.wait_online_bin
4985 if ns
.networkctl_bin
:
4986 networkctl_bin
= ns
.networkctl_bin
4987 if ns
.resolvectl_bin
:
4988 resolvectl_bin
= ns
.resolvectl_bin
4989 if ns
.timedatectl_bin
:
4990 timedatectl_bin
= ns
.timedatectl_bin
4992 use_valgrind
= ns
.use_valgrind
4993 enable_debug
= ns
.enable_debug
4994 asan_options
= ns
.asan_options
4995 lsan_options
= ns
.lsan_options
4996 ubsan_options
= ns
.ubsan_options
4999 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
5000 resolvectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin
]
5001 timedatectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin
]
5002 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
5004 networkctl_cmd
= [networkctl_bin
]
5005 resolvectl_cmd
= [resolvectl_bin
]
5006 timedatectl_cmd
= [timedatectl_bin
]
5007 wait_online_cmd
= [wait_online_bin
]
5010 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
5012 env
.update({ 'ASAN_OPTIONS' : asan_options
})
5014 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
5016 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
5019 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,