2 # SPDX-License-Identifier: LGPL-2.1+
3 # systemd-networkd tests
15 from shutil
import copytree
17 network_unit_file_path
='/run/systemd/network'
18 networkd_runtime_directory
='/run/systemd/netif'
19 networkd_ci_path
='/run/networkd-ci'
20 network_sysctl_ipv6_path
='/proc/sys/net/ipv6/conf'
21 network_sysctl_ipv4_path
='/proc/sys/net/ipv4/conf'
23 dnsmasq_pid_file
='/run/networkd-ci/test-test-dnsmasq.pid'
24 dnsmasq_log_file
='/run/networkd-ci/test-dnsmasq-log-file'
26 systemd_lib_paths
=['/usr/lib/systemd', '/lib/systemd']
27 which_paths
=':'.join(systemd_lib_paths
+ os
.getenv('PATH', os
.defpath
).lstrip(':').split(':'))
29 networkd_bin
=shutil
.which('systemd-networkd', path
=which_paths
)
30 resolved_bin
=shutil
.which('systemd-resolved', path
=which_paths
)
31 udevd_bin
=shutil
.which('systemd-udevd', path
=which_paths
)
32 wait_online_bin
=shutil
.which('systemd-networkd-wait-online', path
=which_paths
)
33 networkctl_bin
=shutil
.which('networkctl', path
=which_paths
)
34 resolvectl_bin
=shutil
.which('resolvectl', path
=which_paths
)
35 timedatectl_bin
=shutil
.which('timedatectl', path
=which_paths
)
46 def check_output(*command
, **kwargs
):
47 # This replaces both check_output and check_call (output can be ignored)
48 command
= command
[0].split() + list(command
[1:])
49 return subprocess
.check_output(command
, universal_newlines
=True, **kwargs
).rstrip()
51 def call(*command
, **kwargs
):
52 command
= command
[0].split() + list(command
[1:])
53 return subprocess
.call(command
, universal_newlines
=True, **kwargs
)
55 def run(*command
, **kwargs
):
56 command
= command
[0].split() + list(command
[1:])
57 return subprocess
.run(command
, universal_newlines
=True, **kwargs
)
59 def is_module_available(module_name
):
60 lsmod_output
= check_output('lsmod')
61 module_re
= re
.compile(rf
'^{re.escape(module_name)}\b', re
.MULTILINE
)
62 return module_re
.search(lsmod_output
) or not call('modprobe', module_name
, stderr
=subprocess
.DEVNULL
)
64 def expectedFailureIfModuleIsNotAvailable(module_name
):
66 if not is_module_available(module_name
):
67 return unittest
.expectedFailure(func
)
72 def expectedFailureIfERSPANModuleIsNotAvailable():
74 rc
= call('ip link add dev erspan99 type erspan seq key 30 local 192.168.1.4 remote 192.168.1.1 erspan_ver 1 erspan 123', stderr
=subprocess
.DEVNULL
)
76 call('ip link del erspan99')
79 return unittest
.expectedFailure(func
)
83 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable():
85 rc
= call('ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7', stderr
=subprocess
.DEVNULL
)
87 call('ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
90 return unittest
.expectedFailure(func
)
94 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
96 rc
= call('ip rule add not from 192.168.100.19 ipproto tcp table 7', stderr
=subprocess
.DEVNULL
)
98 call('ip rule del not from 192.168.100.19 ipproto tcp table 7')
101 return unittest
.expectedFailure(func
)
105 def expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable():
108 rc
= call('ip rule add from 192.168.100.19 table 7 uidrange 200-300', stderr
=subprocess
.DEVNULL
)
110 ret
= run('ip rule list from 192.168.100.19 table 7', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
111 if ret
.returncode
== 0 and 'uidrange 200-300' in ret
.stdout
.rstrip():
113 call('ip rule del from 192.168.100.19 table 7 uidrange 200-300')
118 return unittest
.expectedFailure(func
)
122 def expectedFailureIfLinkFileFieldIsNotSet():
125 rc
= call('ip link add name dummy99 type dummy', stderr
=subprocess
.DEVNULL
)
127 ret
= run('udevadm info -w10s /sys/class/net/dummy99', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
128 if ret
.returncode
== 0 and 'E: ID_NET_LINK_FILE=' in ret
.stdout
.rstrip():
130 call('ip link del dummy99')
135 return unittest
.expectedFailure(func
)
139 def expectedFailureIfNexthopIsNotAvailable():
141 rc
= call('ip nexthop list', stderr
=subprocess
.DEVNULL
)
145 return unittest
.expectedFailure(func
)
149 def expectedFailureIfAlternativeNameIsNotAvailable():
151 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
152 rc
= call('ip link prop add dev dummy98 altname hogehogehogehogehoge', stderr
=subprocess
.DEVNULL
)
153 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
157 return unittest
.expectedFailure(func
)
161 def expectedFailureIfNetdevsimWithSRIOVIsNotAvailable():
163 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
164 rc
= call('modprobe netdevsim', stderr
=subprocess
.DEVNULL
)
166 return unittest
.expectedFailure(func
)
169 with
open('/sys/bus/netdevsim/new_device', mode
='w') as f
:
171 except Exception as error
:
172 return unittest
.expectedFailure(func
)
174 call('udevadm settle')
175 call('udevadm info -w10s /sys/devices/netdevsim99/net/eni99np1', stderr
=subprocess
.DEVNULL
)
177 with
open('/sys/class/net/eni99np1/device/sriov_numvfs', mode
='w') as f
:
179 except Exception as error
:
180 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
181 return unittest
.expectedFailure(func
)
183 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
188 def expectedFailureIfCAKEIsNotAvailable():
190 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
191 rc
= call('tc qdisc add dev dummy98 parent root cake', stderr
=subprocess
.DEVNULL
)
192 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
196 return unittest
.expectedFailure(func
)
200 def expectedFailureIfPIEIsNotAvailable():
202 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
203 rc
= call('tc qdisc add dev dummy98 parent root pie', stderr
=subprocess
.DEVNULL
)
204 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
208 return unittest
.expectedFailure(func
)
212 def expectedFailureIfHHFIsNotAvailable():
214 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
215 rc
= call('tc qdisc add dev dummy98 parent root hhf', stderr
=subprocess
.DEVNULL
)
216 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
220 return unittest
.expectedFailure(func
)
224 def expectedFailureIfETSIsNotAvailable():
226 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
227 rc
= call('tc qdisc add dev dummy98 parent root ets bands 10', stderr
=subprocess
.DEVNULL
)
228 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
232 return unittest
.expectedFailure(func
)
239 os
.makedirs(network_unit_file_path
, exist_ok
=True)
240 os
.makedirs(networkd_ci_path
, exist_ok
=True)
242 shutil
.rmtree(networkd_ci_path
)
243 copytree(os
.path
.join(os
.path
.dirname(os
.path
.abspath(__file__
)), 'conf'), networkd_ci_path
)
245 for u
in ['systemd-networkd.socket', 'systemd-networkd.service', 'systemd-resolved.service',
246 'systemd-udevd-kernel.socket', 'systemd-udevd-control.socket', 'systemd-udevd.service',
247 'firewalld.service']:
248 if call(f
'systemctl is-active --quiet {u}') == 0:
249 check_output(f
'systemctl stop {u}')
250 running_units
.append(u
)
254 'StartLimitIntervalSec=0',
261 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin
,
265 drop_in
+= ['ExecStart=!!' + networkd_bin
]
267 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
269 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
271 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
273 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
274 if asan_options
or lsan_options
or ubsan_options
:
275 drop_in
+= ['SystemCallFilter=']
276 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
277 drop_in
+= ['MemoryDenyWriteExecute=no']
279 os
.makedirs('/run/systemd/system/systemd-networkd.service.d', exist_ok
=True)
280 with
open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode
='w') as f
:
281 f
.write('\n'.join(drop_in
))
289 drop_in
+= ['ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + resolved_bin
]
291 drop_in
+= ['ExecStart=!!' + resolved_bin
]
293 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
295 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
297 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
299 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
300 if asan_options
or lsan_options
or ubsan_options
:
301 drop_in
+= ['SystemCallFilter=']
302 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
303 drop_in
+= ['MemoryDenyWriteExecute=no']
305 os
.makedirs('/run/systemd/system/systemd-resolved.service.d', exist_ok
=True)
306 with
open('/run/systemd/system/systemd-resolved.service.d/00-override.conf', mode
='w') as f
:
307 f
.write('\n'.join(drop_in
))
312 'ExecStart=!!' + udevd_bin
,
315 os
.makedirs('/run/systemd/system/systemd-udevd.service.d', exist_ok
=True)
316 with
open('/run/systemd/system/systemd-udevd.service.d/00-override.conf', mode
='w') as f
:
317 f
.write('\n'.join(drop_in
))
319 check_output('systemctl daemon-reload')
320 print(check_output('systemctl cat systemd-networkd.service'))
321 print(check_output('systemctl cat systemd-resolved.service'))
322 print(check_output('systemctl cat systemd-udevd.service'))
323 check_output('systemctl restart systemd-resolved')
324 check_output('systemctl restart systemd-udevd')
326 def tearDownModule():
329 shutil
.rmtree(networkd_ci_path
)
331 for u
in ['systemd-networkd.socket', 'systemd-networkd.service', 'systemd-resolved.service']:
332 check_output(f
'systemctl stop {u}')
334 shutil
.rmtree('/run/systemd/system/systemd-networkd.service.d')
335 shutil
.rmtree('/run/systemd/system/systemd-resolved.service.d')
336 shutil
.rmtree('/run/systemd/system/systemd-udevd.service.d')
337 check_output('systemctl daemon-reload')
338 check_output('systemctl restart systemd-udevd.service')
340 for u
in running_units
:
341 check_output(f
'systemctl start {u}')
343 def read_link_attr(*args
):
344 with
open(os
.path
.join('/sys/class/net/', *args
)) as f
:
345 return f
.readline().strip()
347 def read_bridge_port_attr(bridge
, link
, attribute
):
348 path_bridge
= os
.path
.join('/sys/devices/virtual/net', bridge
)
349 path_port
= 'lower_' + link
+ '/brport'
350 path
= os
.path
.join(path_bridge
, path_port
)
352 with
open(os
.path
.join(path
, attribute
)) as f
:
353 return f
.readline().strip()
355 def link_exists(link
):
356 return os
.path
.exists(os
.path
.join('/sys/class/net', link
))
358 def remove_links(links
):
360 if link_exists(link
):
361 call('ip link del dev', link
)
364 def remove_fou_ports(ports
):
366 call('ip fou del port', port
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
368 def remove_routing_policy_rule_tables(tables
):
372 rc
= call('ip rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
374 def remove_routes(routes
):
375 for route_type
, addr
in routes
:
376 call('ip route del', route_type
, addr
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
378 def remove_l2tp_tunnels(tunnel_ids
):
379 output
= check_output('ip l2tp show tunnel')
380 for tid
in tunnel_ids
:
381 words
='Tunnel ' + tid
+ ', encap'
383 call('ip l2tp del tunnel tid', tid
)
386 def read_ipv6_sysctl_attr(link
, attribute
):
387 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, link
), attribute
)) as f
:
388 return f
.readline().strip()
390 def read_ipv4_sysctl_attr(link
, attribute
):
391 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv4_path
, link
), attribute
)) as f
:
392 return f
.readline().strip()
394 def copy_unit_to_networkd_unit_path(*units
, dropins
=True):
395 """Copy networkd unit files into the testbed.
397 Any networkd unit file type can be specified, as well as drop-in files.
399 By default, all drop-ins for a specified unit file are copied in;
400 to avoid that specify dropins=False.
402 When a drop-in file is specified, its unit file is also copied in automatically.
406 if dropins
and os
.path
.exists(os
.path
.join(networkd_ci_path
, unit
+ '.d')):
407 copytree(os
.path
.join(networkd_ci_path
, unit
+ '.d'), os
.path
.join(network_unit_file_path
, unit
+ '.d'))
408 if unit
.endswith('.conf'):
410 dropindir
= os
.path
.join(network_unit_file_path
, os
.path
.dirname(dropin
))
411 os
.makedirs(dropindir
, exist_ok
=True)
412 shutil
.copy(os
.path
.join(networkd_ci_path
, dropin
), dropindir
)
413 unit
= os
.path
.dirname(dropin
).rstrip('.d')
414 shutil
.copy(os
.path
.join(networkd_ci_path
, unit
), network_unit_file_path
)
416 def remove_unit_from_networkd_path(units
):
417 """Remove previously copied unit files from the testbed.
419 Drop-ins will be removed automatically.
422 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
))):
423 os
.remove(os
.path
.join(network_unit_file_path
, unit
))
424 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
+ '.d'))):
425 shutil
.rmtree(os
.path
.join(network_unit_file_path
, unit
+ '.d'))
427 def start_dnsmasq(additional_options
='', ipv4_range
='192.168.5.10,192.168.5.200', ipv6_range
='2600::10,2600::20', lease_time
='1h'):
428 dnsmasq_command
= f
'dnsmasq -8 /var/run/networkd-ci/test-dnsmasq-log-file --log-queries=extra --log-dhcp --pid-file=/var/run/networkd-ci/test-test-dnsmasq.pid --conf-file=/dev/null --interface=veth-peer --enable-ra --dhcp-range={ipv6_range},{lease_time} --dhcp-range={ipv4_range},{lease_time} -R --dhcp-leasefile=/var/run/networkd-ci/lease --dhcp-option=26,1492 --dhcp-option=option:router,192.168.5.1 --dhcp-option=33,192.168.5.4,192.168.5.5 --port=0 ' + additional_options
429 check_output(dnsmasq_command
)
431 def stop_dnsmasq(pid_file
):
432 if os
.path
.exists(pid_file
):
433 with
open(pid_file
, 'r') as f
:
434 pid
= f
.read().rstrip(' \t\r\n\0')
435 os
.kill(int(pid
), signal
.SIGTERM
)
439 def search_words_in_dnsmasq_log(words
, show_all
=False):
440 if os
.path
.exists(dnsmasq_log_file
):
441 with
open (dnsmasq_log_file
) as in_file
:
442 contents
= in_file
.read()
445 for line
in contents
.splitlines():
448 print("%s, %s" % (words
, line
))
452 def remove_lease_file():
453 if os
.path
.exists(os
.path
.join(networkd_ci_path
, 'lease')):
454 os
.remove(os
.path
.join(networkd_ci_path
, 'lease'))
456 def remove_log_file():
457 if os
.path
.exists(dnsmasq_log_file
):
458 os
.remove(dnsmasq_log_file
)
460 def remove_networkd_state_files():
461 if os
.path
.exists(os
.path
.join(networkd_runtime_directory
, 'state')):
462 os
.remove(os
.path
.join(networkd_runtime_directory
, 'state'))
464 def stop_networkd(show_logs
=True, remove_state_files
=True):
466 invocation_id
= check_output('systemctl show systemd-networkd -p InvocationID --value')
467 check_output('systemctl stop systemd-networkd.socket')
468 check_output('systemctl stop systemd-networkd.service')
470 print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
))
471 if remove_state_files
:
472 remove_networkd_state_files()
474 def start_networkd(sleep_sec
=0):
475 check_output('systemctl start systemd-networkd')
477 time
.sleep(sleep_sec
)
479 def restart_networkd(sleep_sec
=0, show_logs
=True, remove_state_files
=True):
480 stop_networkd(show_logs
, remove_state_files
)
481 start_networkd(sleep_sec
)
485 def check_link_exists(self
, link
):
486 self
.assertTrue(link_exists(link
))
488 def check_link_attr(self
, *args
):
489 self
.assertEqual(read_link_attr(*args
[:-1]), args
[-1]);
491 def wait_operstate(self
, link
, operstate
='degraded', setup_state
='configured', setup_timeout
=5, fail_assert
=True):
492 """Wait for the link to reach the specified operstate and/or setup state.
494 Specify None or '' for either operstate or setup_state to ignore that state.
495 This will recheck until the state conditions are met or the timeout expires.
497 If the link successfully matches the requested state, this returns True.
498 If this times out waiting for the link to match, the behavior depends on the
499 'fail_assert' parameter; if True, this causes a test assertion failure,
500 otherwise this returns False. The default is to cause assertion failure.
502 Note that this function matches on *exactly* the given operstate and setup_state.
503 To wait for a link to reach *or exceed* a given operstate, use wait_online().
510 for secs
in range(setup_timeout
+ 1):
511 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
, env
=env
)
513 if re
.search(rf
'(?m)^\s*State:\s+{operstate}\s+\({setup_state}\)\s*$', output
):
515 # don't bother sleeping if time is up
516 if secs
< setup_timeout
:
519 self
.fail(f
'Timed out waiting for {link} to reach state {operstate}/{setup_state}')
522 def wait_online(self
, links_with_operstate
, timeout
='20s', bool_any
=False, setup_state
='configured', setup_timeout
=5):
523 """Wait for the link(s) to reach the specified operstate and/or setup state.
525 This is similar to wait_operstate() but can be used for multiple links,
526 and it also calls systemd-networkd-wait-online to wait for the given operstate.
527 The operstate should be specified in the link name, like 'eth0:degraded'.
528 If just a link name is provided, wait-online's default operstate to wait for is degraded.
530 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
531 'setup_timeout' controls the per-link timeout waiting for the setup_state.
533 Set 'bool_any' to True to wait for any (instead of all) of the given links.
534 If this is set, no setup_state checks are done.
536 Note that this function waits for the link(s) to reach *or exceed* the given operstate.
537 However, the setup_state, if specified, must be matched *exactly*.
539 This returns if the link(s) reached the requested operstate/setup_state; otherwise it
540 raises CalledProcessError or fails test assertion.
542 args
= wait_online_cmd
+ [f
'--timeout={timeout}'] + [f
'--interface={link}' for link
in links_with_operstate
]
546 check_output(*args
, env
=env
)
547 except subprocess
.CalledProcessError
:
548 for link
in links_with_operstate
:
549 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
.split(':')[0], env
=env
)
552 if not bool_any
and setup_state
:
553 for link
in links_with_operstate
:
554 self
.wait_operstate(link
.split(':')[0], None, setup_state
, setup_timeout
)
556 def wait_address(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
557 for i
in range(timeout_sec
):
560 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
561 if re
.search(address_regex
, output
) and 'tentative' not in output
:
564 self
.assertRegex(output
, address_regex
)
566 class NetworkctlTests(unittest
.TestCase
, Utilities
):
576 '11-dummy-mtu.netdev',
580 '25-address-static.network',
582 'netdev-link-local-addressing-yes.network',
586 remove_links(self
.links
)
587 stop_networkd(show_logs
=False)
590 remove_links(self
.links
)
591 remove_unit_from_networkd_path(self
.units
)
592 stop_networkd(show_logs
=True)
594 @expectedFailureIfAlternativeNameIsNotAvailable()
595 def test_altname(self
):
596 copy_unit_to_networkd_unit_path('netdev-link-local-addressing-yes.network', '12-dummy.netdev', '12-dummy.link')
597 check_output('udevadm control --reload')
599 self
.wait_online(['dummy98:degraded'])
601 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
602 self
.assertRegex(output
, 'hogehogehogehogehogehoge')
604 def test_reconfigure(self
):
605 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
607 self
.wait_online(['dummy98:routable'])
609 output
= check_output('ip -4 address show dev dummy98')
611 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
612 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
613 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
615 check_output('ip address del 10.1.2.3/16 dev dummy98')
616 check_output('ip address del 10.1.2.4/16 dev dummy98')
617 check_output('ip address del 10.2.2.4/16 dev dummy98')
619 check_output(*networkctl_cmd
, 'reconfigure', 'dummy98', env
=env
)
620 self
.wait_online(['dummy98:routable'])
622 output
= check_output('ip -4 address show dev dummy98')
624 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
625 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
626 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
628 def test_reload(self
):
631 copy_unit_to_networkd_unit_path('11-dummy.netdev')
632 check_output(*networkctl_cmd
, 'reload', env
=env
)
633 self
.wait_operstate('test1', 'off', setup_state
='unmanaged')
635 copy_unit_to_networkd_unit_path('11-dummy.network')
636 check_output(*networkctl_cmd
, 'reload', env
=env
)
637 self
.wait_online(['test1:degraded'])
639 remove_unit_from_networkd_path(['11-dummy.network'])
640 check_output(*networkctl_cmd
, 'reload', env
=env
)
641 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
643 remove_unit_from_networkd_path(['11-dummy.netdev'])
644 check_output(*networkctl_cmd
, 'reload', env
=env
)
645 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
647 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
648 check_output(*networkctl_cmd
, 'reload', env
=env
)
649 self
.wait_operstate('test1', 'degraded')
652 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
655 self
.wait_online(['test1:degraded'])
657 output
= check_output(*networkctl_cmd
, 'list', env
=env
)
658 self
.assertRegex(output
, '1 lo ')
659 self
.assertRegex(output
, 'test1')
661 output
= check_output(*networkctl_cmd
, 'list', 'test1', env
=env
)
662 self
.assertNotRegex(output
, '1 lo ')
663 self
.assertRegex(output
, 'test1')
665 output
= check_output(*networkctl_cmd
, 'list', 'te*', env
=env
)
666 self
.assertNotRegex(output
, '1 lo ')
667 self
.assertRegex(output
, 'test1')
669 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'te*', env
=env
)
670 self
.assertNotRegex(output
, '1: lo ')
671 self
.assertRegex(output
, 'test1')
673 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'tes[a-z][0-9]', env
=env
)
674 self
.assertNotRegex(output
, '1: lo ')
675 self
.assertRegex(output
, 'test1')
678 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
681 self
.wait_online(['test1:degraded'])
683 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
684 self
.assertRegex(output
, 'MTU: 1600')
687 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
689 self
.wait_online(['test1:degraded'])
691 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
693 self
.assertRegex(output
, 'Type: ether')
695 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
697 self
.assertRegex(output
, 'Type: loopback')
699 @expectedFailureIfLinkFileFieldIsNotSet()
700 def test_udev_link_file(self
):
701 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
703 self
.wait_online(['test1:degraded'])
705 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
707 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
708 self
.assertRegex(output
, r
'Network File: /run/systemd/network/11-dummy.network')
710 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
712 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
713 self
.assertRegex(output
, r
'Network File: n/a')
715 def test_delete_links(self
):
716 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
717 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
720 self
.wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
722 check_output(*networkctl_cmd
, 'delete', 'test1', 'veth99', env
=env
)
723 self
.assertFalse(link_exists('test1'))
724 self
.assertFalse(link_exists('veth99'))
725 self
.assertFalse(link_exists('veth-peer'))
727 class NetworkdNetDevTests(unittest
.TestCase
, Utilities
):
729 links_remove_earlier
= [
797 '10-dropin-test.netdev',
801 '13-not-match-udev-property.network',
802 '14-match-udev-property.network',
803 '15-name-conflict-test.netdev',
806 '21-vlan-test1.network',
809 '25-6rd-tunnel.netdev',
812 '25-bond-balanced-tlb.netdev',
814 '25-bridge-configure-without-carrier.network',
816 '25-erspan-tunnel-local-any.netdev',
817 '25-erspan-tunnel.netdev',
818 '25-fou-gretap.netdev',
820 '25-fou-ipip.netdev',
821 '25-fou-ipproto-gre.netdev',
822 '25-fou-ipproto-ipip.netdev',
825 '25-gretap-tunnel-local-any.netdev',
826 '25-gretap-tunnel.netdev',
827 '25-gre-tunnel-any-any.netdev',
828 '25-gre-tunnel-local-any.netdev',
829 '25-gre-tunnel-remote-any.netdev',
830 '25-gre-tunnel.netdev',
832 '25-ip6gretap-tunnel-local-any.netdev',
833 '25-ip6gretap-tunnel.netdev',
834 '25-ip6gre-tunnel-any-any.netdev',
835 '25-ip6gre-tunnel-local-any.netdev',
836 '25-ip6gre-tunnel-remote-any.netdev',
837 '25-ip6gre-tunnel.netdev',
838 '25-ip6tnl-tunnel-any-any.netdev',
839 '25-ip6tnl-tunnel-local-any.netdev',
840 '25-ip6tnl-tunnel-remote-any.netdev',
841 '25-ip6tnl-tunnel.netdev',
842 '25-ipip-tunnel-any-any.netdev',
843 '25-ipip-tunnel-independent.netdev',
844 '25-ipip-tunnel-independent-loopback.netdev',
845 '25-ipip-tunnel-local-any.netdev',
846 '25-ipip-tunnel-remote-any.netdev',
847 '25-ipip-tunnel.netdev',
850 '25-isatap-tunnel.netdev',
855 '25-sit-tunnel-any-any.netdev',
856 '25-sit-tunnel-local-any.netdev',
857 '25-sit-tunnel-remote-any.netdev',
858 '25-sit-tunnel.netdev',
861 '25-tunnel-local-any.network',
862 '25-tunnel-remote-any.network',
867 '25-vti6-tunnel-any-any.netdev',
868 '25-vti6-tunnel-local-any.netdev',
869 '25-vti6-tunnel-remote-any.netdev',
870 '25-vti6-tunnel.netdev',
871 '25-vti-tunnel-any-any.netdev',
872 '25-vti-tunnel-local-any.netdev',
873 '25-vti-tunnel-remote-any.netdev',
874 '25-vti-tunnel.netdev',
876 '25-vxlan-independent.netdev',
878 '25-wireguard-23-peers.netdev',
879 '25-wireguard-23-peers.network',
880 '25-wireguard-no-peer.netdev',
881 '25-wireguard-no-peer.network',
882 '25-wireguard-preshared-key.txt',
883 '25-wireguard-private-key.txt',
884 '25-wireguard.netdev',
885 '25-wireguard.network',
887 '25-xfrm-independent.netdev',
903 'netdev-link-local-addressing-yes.network',
907 'vxlan-test1.network',
917 remove_fou_ports(self
.fou_ports
)
918 remove_links(self
.links_remove_earlier
)
919 remove_links(self
.links
)
920 stop_networkd(show_logs
=False)
923 remove_fou_ports(self
.fou_ports
)
924 remove_links(self
.links_remove_earlier
)
925 remove_links(self
.links
)
926 remove_unit_from_networkd_path(self
.units
)
927 stop_networkd(show_logs
=True)
929 def test_dropin_and_name_conflict(self
):
930 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
933 self
.wait_online(['dropin-test:off'], setup_state
='unmanaged')
935 output
= check_output('ip link show dropin-test')
937 self
.assertRegex(output
, '00:50:56:c0:00:28')
939 def test_match_udev_property(self
):
940 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
942 self
.wait_online(['dummy98:routable'])
944 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
946 self
.assertRegex(output
, 'Network File: /run/systemd/network/14-match-udev-property')
948 def test_wait_online_any(self
):
949 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
952 self
.wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
954 self
.wait_operstate('bridge99', '(off|no-carrier)', setup_state
='configuring')
955 self
.wait_operstate('test1', 'degraded')
957 @expectedFailureIfModuleIsNotAvailable('bareudp')
958 def test_bareudp(self
):
959 copy_unit_to_networkd_unit_path('25-bareudp.netdev', 'netdev-link-local-addressing-yes.network')
962 self
.wait_online(['bareudp99:degraded'])
964 output
= check_output('ip -d link show bareudp99')
966 self
.assertRegex(output
, 'dstport 1000 ')
967 self
.assertRegex(output
, 'ethertype ip ')
969 def test_bridge(self
):
970 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
973 self
.wait_online(['bridge99:no-carrier'])
975 tick
= os
.sysconf('SC_CLK_TCK')
976 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
977 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
978 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'forward_delay')) / tick
))
979 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'ageing_time')) / tick
))
980 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge', 'priority')))
981 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_querier')))
982 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_snooping')))
983 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'stp_state')))
984 self
.assertEqual(3, int(read_link_attr('bridge99', 'bridge', 'multicast_igmp_version')))
986 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
988 self
.assertRegex(output
, 'Priority: 9')
989 self
.assertRegex(output
, 'STP: yes')
990 self
.assertRegex(output
, 'Multicast IGMP Version: 3')
993 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
996 self
.wait_online(['bond99:off', 'bond98:off'], setup_state
='unmanaged')
998 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
999 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
1000 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
1001 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
1002 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
1003 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
1004 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
1005 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
1006 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
1007 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
1008 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
1010 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
1011 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
1013 def test_vlan(self
):
1014 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
1015 '21-vlan.network', '21-vlan-test1.network')
1018 self
.wait_online(['test1:degraded', 'vlan99:routable'])
1020 output
= check_output('ip -d link show test1')
1022 self
.assertRegex(output
, ' mtu 2000 ')
1024 output
= check_output('ip -d link show vlan99')
1026 self
.assertRegex(output
, ' mtu 2000 ')
1027 self
.assertRegex(output
, 'REORDER_HDR')
1028 self
.assertRegex(output
, 'LOOSE_BINDING')
1029 self
.assertRegex(output
, 'GVRP')
1030 self
.assertRegex(output
, 'MVRP')
1031 self
.assertRegex(output
, ' id 99 ')
1033 output
= check_output('ip -4 address show dev test1')
1035 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
1036 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
1038 output
= check_output('ip -4 address show dev vlan99')
1040 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
1042 def test_macvtap(self
):
1043 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
1044 with self
.subTest(mode
=mode
):
1045 if mode
!= 'private':
1047 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
1048 '11-dummy.netdev', 'macvtap.network')
1049 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
1050 f
.write('[MACVTAP]\nMode=' + mode
)
1053 self
.wait_online(['macvtap99:degraded', 'test1:degraded'])
1055 output
= check_output('ip -d link show macvtap99')
1057 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
1059 def test_macvlan(self
):
1060 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
1061 with self
.subTest(mode
=mode
):
1062 if mode
!= 'private':
1064 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
1065 '11-dummy.netdev', 'macvlan.network')
1066 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
1067 f
.write('[MACVLAN]\nMode=' + mode
)
1070 self
.wait_online(['macvlan99:degraded', 'test1:degraded'])
1072 output
= check_output('ip -d link show test1')
1074 self
.assertRegex(output
, ' mtu 2000 ')
1076 output
= check_output('ip -d link show macvlan99')
1078 self
.assertRegex(output
, ' mtu 2000 ')
1079 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
1081 @expectedFailureIfModuleIsNotAvailable('ipvlan')
1082 def test_ipvlan(self
):
1083 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1084 with self
.subTest(mode
=mode
, flag
=flag
):
1087 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
1088 '11-dummy.netdev', 'ipvlan.network')
1089 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
1090 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
1093 self
.wait_online(['ipvlan99:degraded', 'test1:degraded'])
1095 output
= check_output('ip -d link show ipvlan99')
1097 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
1099 @expectedFailureIfModuleIsNotAvailable('ipvtap')
1100 def test_ipvtap(self
):
1101 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1102 with self
.subTest(mode
=mode
, flag
=flag
):
1105 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
1106 '11-dummy.netdev', 'ipvtap.network')
1107 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
1108 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
1111 self
.wait_online(['ipvtap99:degraded', 'test1:degraded'])
1113 output
= check_output('ip -d link show ipvtap99')
1115 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
1117 def test_veth(self
):
1118 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
1121 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
1123 output
= check_output('ip -d link show veth99')
1125 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
1126 output
= check_output('ip -d link show veth-peer')
1128 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
1131 copy_unit_to_networkd_unit_path('25-tun.netdev')
1134 self
.wait_online(['tun99:off'], setup_state
='unmanaged')
1136 output
= check_output('ip -d link show tun99')
1138 # Old ip command does not support IFF_ flags
1139 self
.assertRegex(output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
1142 copy_unit_to_networkd_unit_path('25-tap.netdev')
1145 self
.wait_online(['tap99:off'], setup_state
='unmanaged')
1147 output
= check_output('ip -d link show tap99')
1149 # Old ip command does not support IFF_ flags
1150 self
.assertRegex(output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
1152 @expectedFailureIfModuleIsNotAvailable('vrf')
1154 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
1157 self
.wait_online(['vrf99:carrier'])
1159 @expectedFailureIfModuleIsNotAvailable('vcan')
1160 def test_vcan(self
):
1161 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
1164 self
.wait_online(['vcan99:carrier'])
1166 @expectedFailureIfModuleIsNotAvailable('vxcan')
1167 def test_vxcan(self
):
1168 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
1171 self
.wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
1173 @expectedFailureIfModuleIsNotAvailable('wireguard')
1174 def test_wireguard(self
):
1175 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
1176 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
1177 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt',
1178 '25-wireguard-no-peer.netdev', '25-wireguard-no-peer.network')
1180 self
.wait_online(['wg99:carrier', 'wg98:routable', 'wg97:carrier'])
1182 if shutil
.which('wg'):
1185 output
= check_output('wg show wg99 listen-port')
1186 self
.assertRegex(output
, '51820')
1187 output
= check_output('wg show wg99 fwmark')
1188 self
.assertRegex(output
, '0x4d2')
1189 output
= check_output('wg show wg99 allowed-ips')
1190 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
1191 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
1192 output
= check_output('wg show wg99 persistent-keepalive')
1193 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
1194 output
= check_output('wg show wg99 endpoints')
1195 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
1196 output
= check_output('wg show wg99 private-key')
1197 self
.assertRegex(output
, r
'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
1198 output
= check_output('wg show wg99 preshared-keys')
1199 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
1200 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
1202 output
= check_output('wg show wg98 private-key')
1203 self
.assertRegex(output
, r
'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
1205 output
= check_output('wg show wg97 listen-port')
1206 self
.assertRegex(output
, '51821')
1207 output
= check_output('wg show wg97 fwmark')
1208 self
.assertRegex(output
, '0x4d3')
1210 def test_geneve(self
):
1211 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
1214 self
.wait_online(['geneve99:degraded'])
1216 output
= check_output('ip -d link show geneve99')
1218 self
.assertRegex(output
, '192.168.22.1')
1219 self
.assertRegex(output
, '6082')
1220 self
.assertRegex(output
, 'udpcsum')
1221 self
.assertRegex(output
, 'udp6zerocsumrx')
1223 def test_ipip_tunnel(self
):
1224 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
1225 '25-ipip-tunnel.netdev', '25-tunnel.network',
1226 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1227 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1228 '25-ipip-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1230 self
.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'ipiptun96:routable', 'dummy98:degraded'])
1232 output
= check_output('ip -d link show ipiptun99')
1234 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98')
1235 output
= check_output('ip -d link show ipiptun98')
1237 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98')
1238 output
= check_output('ip -d link show ipiptun97')
1240 self
.assertRegex(output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98')
1241 output
= check_output('ip -d link show ipiptun96')
1243 self
.assertRegex(output
, 'ipip (ipip )?remote any local any dev dummy98')
1245 def test_gre_tunnel(self
):
1246 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
1247 '25-gre-tunnel.netdev', '25-tunnel.network',
1248 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1249 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1250 '25-gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1252 self
.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'gretun96:routable', 'dummy98:degraded'])
1254 output
= check_output('ip -d link show gretun99')
1256 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1257 self
.assertRegex(output
, 'ikey 1.2.3.103')
1258 self
.assertRegex(output
, 'okey 1.2.4.103')
1259 self
.assertRegex(output
, 'iseq')
1260 self
.assertRegex(output
, 'oseq')
1261 output
= check_output('ip -d link show gretun98')
1263 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
1264 self
.assertRegex(output
, 'ikey 0.0.0.104')
1265 self
.assertRegex(output
, 'okey 0.0.0.104')
1266 self
.assertNotRegex(output
, 'iseq')
1267 self
.assertNotRegex(output
, 'oseq')
1268 output
= check_output('ip -d link show gretun97')
1270 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
1271 self
.assertRegex(output
, 'ikey 0.0.0.105')
1272 self
.assertRegex(output
, 'okey 0.0.0.105')
1273 self
.assertNotRegex(output
, 'iseq')
1274 self
.assertNotRegex(output
, 'oseq')
1275 output
= check_output('ip -d link show gretun96')
1277 self
.assertRegex(output
, 'gre remote any local any dev dummy98')
1278 self
.assertRegex(output
, 'ikey 0.0.0.106')
1279 self
.assertRegex(output
, 'okey 0.0.0.106')
1280 self
.assertNotRegex(output
, 'iseq')
1281 self
.assertNotRegex(output
, 'oseq')
1283 def test_ip6gre_tunnel(self
):
1284 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
1285 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
1286 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1287 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1288 '25-ip6gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1291 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1293 self
.check_link_exists('dummy98')
1294 self
.check_link_exists('ip6gretun99')
1295 self
.check_link_exists('ip6gretun98')
1296 self
.check_link_exists('ip6gretun97')
1297 self
.check_link_exists('ip6gretun96')
1299 output
= check_output('ip -d link show ip6gretun99')
1301 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1302 output
= check_output('ip -d link show ip6gretun98')
1304 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
1305 output
= check_output('ip -d link show ip6gretun97')
1307 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
1308 output
= check_output('ip -d link show ip6gretun96')
1310 self
.assertRegex(output
, 'ip6gre remote any local any dev dummy98')
1312 def test_gretap_tunnel(self
):
1313 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
1314 '25-gretap-tunnel.netdev', '25-tunnel.network',
1315 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1317 self
.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
1319 output
= check_output('ip -d link show gretap99')
1321 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1322 self
.assertRegex(output
, 'ikey 0.0.0.106')
1323 self
.assertRegex(output
, 'okey 0.0.0.106')
1324 self
.assertRegex(output
, 'iseq')
1325 self
.assertRegex(output
, 'oseq')
1326 output
= check_output('ip -d link show gretap98')
1328 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
1329 self
.assertRegex(output
, 'ikey 0.0.0.107')
1330 self
.assertRegex(output
, 'okey 0.0.0.107')
1331 self
.assertRegex(output
, 'iseq')
1332 self
.assertRegex(output
, 'oseq')
1334 def test_ip6gretap_tunnel(self
):
1335 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
1336 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1337 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1339 self
.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
1341 output
= check_output('ip -d link show ip6gretap99')
1343 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1344 output
= check_output('ip -d link show ip6gretap98')
1346 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1348 def test_vti_tunnel(self
):
1349 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
1350 '25-vti-tunnel.netdev', '25-tunnel.network',
1351 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1352 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1353 '25-vti-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1355 self
.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'vtitun96:routable', 'dummy98:degraded'])
1357 output
= check_output('ip -d link show vtitun99')
1359 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1360 output
= check_output('ip -d link show vtitun98')
1362 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
1363 output
= check_output('ip -d link show vtitun97')
1365 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
1366 output
= check_output('ip -d link show vtitun96')
1368 self
.assertRegex(output
, 'vti remote any local any dev dummy98')
1370 def test_vti6_tunnel(self
):
1371 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
1372 '25-vti6-tunnel.netdev', '25-tunnel.network',
1373 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1374 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1376 self
.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
1378 output
= check_output('ip -d link show vti6tun99')
1380 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1381 output
= check_output('ip -d link show vti6tun98')
1383 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1384 output
= check_output('ip -d link show vti6tun97')
1386 self
.assertRegex(output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1388 def test_ip6tnl_tunnel(self
):
1389 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
1390 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1391 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1392 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1394 self
.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
1396 output
= check_output('ip -d link show ip6tnl99')
1398 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1399 output
= check_output('ip -d link show ip6tnl98')
1401 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1402 output
= check_output('ip -d link show ip6tnl97')
1404 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1406 def test_sit_tunnel(self
):
1407 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1408 '25-sit-tunnel.netdev', '25-tunnel.network',
1409 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1410 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1411 '25-sit-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1413 self
.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'sittun96:routable', 'dummy98:degraded'])
1415 output
= check_output('ip -d link show sittun99')
1417 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1418 output
= check_output('ip -d link show sittun98')
1420 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98")
1421 output
= check_output('ip -d link show sittun97')
1423 self
.assertRegex(output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98")
1424 output
= check_output('ip -d link show sittun96')
1426 self
.assertRegex(output
, "sit (ip6ip )?remote any local any dev dummy98")
1428 def test_isatap_tunnel(self
):
1429 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1430 '25-isatap-tunnel.netdev', '25-tunnel.network')
1432 self
.wait_online(['isataptun99:routable', 'dummy98:degraded'])
1434 output
= check_output('ip -d link show isataptun99')
1436 self
.assertRegex(output
, "isatap ")
1438 def test_6rd_tunnel(self
):
1439 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1440 '25-6rd-tunnel.netdev', '25-tunnel.network')
1442 self
.wait_online(['sittun99:routable', 'dummy98:degraded'])
1444 output
= check_output('ip -d link show sittun99')
1446 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1448 @expectedFailureIfERSPANModuleIsNotAvailable()
1449 def test_erspan_tunnel(self
):
1450 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1451 '25-erspan-tunnel.netdev', '25-tunnel.network',
1452 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1454 self
.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1456 output
= check_output('ip -d link show erspan99')
1458 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1459 self
.assertRegex(output
, 'ikey 0.0.0.101')
1460 self
.assertRegex(output
, 'okey 0.0.0.101')
1461 self
.assertRegex(output
, 'iseq')
1462 self
.assertRegex(output
, 'oseq')
1463 output
= check_output('ip -d link show erspan98')
1465 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1466 self
.assertRegex(output
, '102')
1467 self
.assertRegex(output
, 'ikey 0.0.0.102')
1468 self
.assertRegex(output
, 'okey 0.0.0.102')
1469 self
.assertRegex(output
, 'iseq')
1470 self
.assertRegex(output
, 'oseq')
1472 def test_tunnel_independent(self
):
1473 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1476 self
.wait_online(['ipiptun99:carrier'])
1478 def test_tunnel_independent_loopback(self
):
1479 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent-loopback.netdev', 'netdev-link-local-addressing-yes.network')
1482 self
.wait_online(['ipiptun99:carrier'])
1484 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1485 def test_xfrm(self
):
1486 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'xfrm.network',
1487 '25-xfrm.netdev', 'netdev-link-local-addressing-yes.network')
1490 self
.wait_online(['xfrm99:degraded', 'dummy98:degraded'])
1492 output
= check_output('ip link show dev xfrm99')
1495 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1496 def test_xfrm_independent(self
):
1497 copy_unit_to_networkd_unit_path('25-xfrm-independent.netdev', 'netdev-link-local-addressing-yes.network')
1500 self
.wait_online(['xfrm99:degraded'])
1502 @expectedFailureIfModuleIsNotAvailable('fou')
1504 # The following redundant check is necessary for CentOS CI.
1505 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1506 self
.assertTrue(is_module_available('fou'))
1508 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1509 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1510 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1513 self
.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'], setup_state
='unmanaged')
1515 output
= check_output('ip fou show')
1517 self
.assertRegex(output
, 'port 55555 ipproto 4')
1518 self
.assertRegex(output
, 'port 55556 ipproto 47')
1520 output
= check_output('ip -d link show ipiptun96')
1522 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1523 output
= check_output('ip -d link show sittun96')
1525 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1526 output
= check_output('ip -d link show gretun96')
1528 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1529 output
= check_output('ip -d link show gretap96')
1531 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1533 def test_vxlan(self
):
1534 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1535 '25-vxlan-independent.netdev', 'netdev-link-local-addressing-yes.network',
1536 '11-dummy.netdev', 'vxlan-test1.network')
1539 self
.wait_online(['test1:degraded', 'vxlan99:degraded', 'vxlan98:degraded'])
1541 output
= check_output('ip -d link show vxlan99')
1543 self
.assertRegex(output
, '999')
1544 self
.assertRegex(output
, '5555')
1545 self
.assertRegex(output
, 'l2miss')
1546 self
.assertRegex(output
, 'l3miss')
1547 self
.assertRegex(output
, 'udpcsum')
1548 self
.assertRegex(output
, 'udp6zerocsumtx')
1549 self
.assertRegex(output
, 'udp6zerocsumrx')
1550 self
.assertRegex(output
, 'remcsumtx')
1551 self
.assertRegex(output
, 'remcsumrx')
1552 self
.assertRegex(output
, 'gbp')
1554 output
= check_output('bridge fdb show dev vxlan99')
1556 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1557 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1558 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1560 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'vxlan99', env
=env
)
1562 self
.assertRegex(output
, 'VNI: 999')
1563 self
.assertRegex(output
, 'Destination Port: 5555')
1564 self
.assertRegex(output
, 'Underlying Device: test1')
1566 output
= check_output('ip -d link show vxlan98')
1569 def test_macsec(self
):
1570 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1571 'macsec.network', '12-dummy.netdev')
1574 self
.wait_online(['dummy98:degraded', 'macsec99:routable'])
1576 output
= check_output('ip -d link show macsec99')
1578 self
.assertRegex(output
, 'macsec99@dummy98')
1579 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1580 self
.assertRegex(output
, 'encrypt on')
1582 output
= check_output('ip macsec show macsec99')
1584 self
.assertRegex(output
, 'encrypt on')
1585 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1586 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1587 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1588 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1589 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1590 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1591 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1592 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1593 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1594 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1595 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1597 def test_nlmon(self
):
1598 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1601 self
.wait_online(['nlmon99:carrier'])
1603 @expectedFailureIfModuleIsNotAvailable('ifb')
1605 copy_unit_to_networkd_unit_path('25-ifb.netdev', 'netdev-link-local-addressing-yes.network')
1608 self
.wait_online(['ifb99:degraded'])
1610 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1621 '25-l2tp-dummy.network',
1623 '25-l2tp-ip.netdev',
1624 '25-l2tp-udp.netdev']
1626 l2tp_tunnel_ids
= [ '10' ]
1629 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1630 remove_links(self
.links
)
1631 stop_networkd(show_logs
=False)
1634 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1635 remove_links(self
.links
)
1636 remove_unit_from_networkd_path(self
.units
)
1637 stop_networkd(show_logs
=True)
1639 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1640 def test_l2tp_udp(self
):
1641 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1642 '25-l2tp-udp.netdev', '25-l2tp.network')
1645 self
.wait_online(['test1:routable', 'l2tp-ses1:degraded', 'l2tp-ses2:degraded'])
1647 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1649 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1650 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1651 self
.assertRegex(output
, "Peer tunnel 11")
1652 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1653 self
.assertRegex(output
, "UDP checksum: enabled")
1655 output
= check_output('ip l2tp show session tid 10 session_id 15')
1657 self
.assertRegex(output
, "Session 15 in tunnel 10")
1658 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1659 self
.assertRegex(output
, "interface name: l2tp-ses1")
1661 output
= check_output('ip l2tp show session tid 10 session_id 17')
1663 self
.assertRegex(output
, "Session 17 in tunnel 10")
1664 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1665 self
.assertRegex(output
, "interface name: l2tp-ses2")
1667 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1668 def test_l2tp_ip(self
):
1669 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1670 '25-l2tp-ip.netdev', '25-l2tp.network')
1673 self
.wait_online(['test1:routable', 'l2tp-ses3:degraded', 'l2tp-ses4:degraded'])
1675 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1677 self
.assertRegex(output
, "Tunnel 10, encap IP")
1678 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1679 self
.assertRegex(output
, "Peer tunnel 12")
1681 output
= check_output('ip l2tp show session tid 10 session_id 25')
1683 self
.assertRegex(output
, "Session 25 in tunnel 10")
1684 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1685 self
.assertRegex(output
, "interface name: l2tp-ses3")
1687 output
= check_output('ip l2tp show session tid 10 session_id 27')
1689 self
.assertRegex(output
, "Session 27 in tunnel 10")
1690 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1691 self
.assertRegex(output
, "interface name: l2tp-ses4")
1693 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1708 '23-active-slave.network',
1709 '24-keep-configuration-static.network',
1710 '24-search-domain.network',
1711 '25-address-dad-veth-peer.network',
1712 '25-address-dad-veth99.network',
1713 '25-address-link-section.network',
1714 '25-address-preferred-lifetime-zero.network',
1715 '25-address-static.network',
1716 '25-bind-carrier.network',
1717 '25-bond-active-backup-slave.netdev',
1718 '25-fibrule-invert.network',
1719 '25-fibrule-port-range.network',
1720 '25-fibrule-uidrange.network',
1721 '25-gre-tunnel-remote-any.netdev',
1722 '25-ip6gre-tunnel-remote-any.netdev',
1723 '25-ipv6-address-label-section.network',
1724 '25-link-local-addressing-no.network',
1725 '25-link-local-addressing-yes.network',
1726 '25-link-section-unmanaged.network',
1727 '25-neighbor-section.network',
1728 '25-neighbor-next.network',
1729 '25-neighbor-ipv6.network',
1730 '25-neighbor-ip-dummy.network',
1731 '25-neighbor-ip.network',
1732 '25-nexthop.network',
1733 '25-qdisc-cake.network',
1734 '25-qdisc-clsact-and-htb.network',
1735 '25-qdisc-drr.network',
1736 '25-qdisc-ets.network',
1737 '25-qdisc-hhf.network',
1738 '25-qdisc-ingress-netem-compat.network',
1739 '25-qdisc-pie.network',
1740 '25-qdisc-qfq.network',
1741 '25-prefix-route-with-vrf.network',
1742 '25-prefix-route-without-vrf.network',
1743 '25-route-ipv6-src.network',
1744 '25-route-static.network',
1745 '25-route-vrf.network',
1746 '25-gateway-static.network',
1747 '25-gateway-next-static.network',
1749 '25-sysctl-disable-ipv6.network',
1750 '25-sysctl.network',
1752 '25-veth-peer.network',
1756 '26-link-local-addressing-ipv6.network',
1757 'routing-policy-rule-dummy98.network',
1758 'routing-policy-rule-test1.network',
1759 'routing-policy-rule-reconfigure.network',
1762 routing_policy_rule_tables
= ['7', '8', '9', '1011']
1763 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1766 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1767 remove_routes(self
.routes
)
1768 remove_links(self
.links
)
1769 stop_networkd(show_logs
=False)
1772 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1773 remove_routes(self
.routes
)
1774 remove_links(self
.links
)
1775 remove_unit_from_networkd_path(self
.units
)
1776 stop_networkd(show_logs
=True)
1778 def test_address_static(self
):
1779 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1782 self
.wait_online(['dummy98:routable'])
1784 output
= check_output('ip -4 address show dev dummy98')
1786 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1787 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1788 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1790 # test for ENOBUFS issue #17012
1791 for i
in range(1,254):
1792 self
.assertRegex(output
, f
'inet 10.3.3.{i}/16 brd 10.3.255.255')
1795 self
.assertNotRegex(output
, '10.10.0.1/16')
1796 self
.assertNotRegex(output
, '10.10.0.2/16')
1798 output
= check_output('ip -4 address show dev dummy98 label 32')
1799 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1801 output
= check_output('ip -4 address show dev dummy98 label 33')
1802 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1804 output
= check_output('ip -4 address show dev dummy98 label 34')
1805 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1807 output
= check_output('ip -4 address show dev dummy98 label 35')
1808 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1810 output
= check_output('ip -6 address show dev dummy98')
1812 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1813 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1814 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1815 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1816 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1817 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1820 self
.wait_online(['dummy98:routable'])
1822 # test for ENOBUFS issue #17012
1823 output
= check_output('ip -4 address show dev dummy98')
1824 for i
in range(1,254):
1825 self
.assertRegex(output
, f
'inet 10.3.3.{i}/16 brd 10.3.255.255')
1827 def test_address_preferred_lifetime_zero_ipv6(self
):
1828 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero.network', '12-dummy.netdev')
1831 self
.wait_online(['dummy98:routable'])
1833 output
= check_output('ip address show dummy98')
1835 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1836 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1838 output
= check_output('ip route show dev dummy98')
1840 self
.assertRegex(output
, 'default via 20.20.20.1 proto static')
1842 def test_address_dad(self
):
1843 copy_unit_to_networkd_unit_path('25-address-dad-veth99.network', '25-address-dad-veth-peer.network',
1846 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
1848 output
= check_output('ip -4 address show dev veth99')
1850 self
.assertRegex(output
, '192.168.100.10/24')
1852 output
= check_output('ip -4 address show dev veth-peer')
1854 self
.assertNotRegex(output
, '192.168.100.10/24')
1856 @expectedFailureIfModuleIsNotAvailable('vrf')
1857 def test_prefix_route(self
):
1858 copy_unit_to_networkd_unit_path('25-prefix-route-with-vrf.network', '12-dummy.netdev',
1859 '25-prefix-route-without-vrf.network', '11-dummy.netdev',
1860 '25-vrf.netdev', '25-vrf.network')
1861 for trial
in range(2):
1867 self
.wait_online(['dummy98:routable', 'test1:routable', 'vrf99:carrier'])
1869 output
= check_output('ip route show table 42 dev dummy98')
1870 print('### ip route show table 42 dev dummy98')
1872 self
.assertRegex(output
, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1')
1873 self
.assertRegex(output
, 'broadcast 10.20.33.0 proto kernel scope link src 10.20.33.1')
1874 self
.assertRegex(output
, '10.20.33.0/24 proto kernel scope link src 10.20.33.1')
1875 self
.assertRegex(output
, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1')
1876 self
.assertRegex(output
, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1')
1877 self
.assertRegex(output
, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1')
1878 self
.assertRegex(output
, 'broadcast 10.20.55.0 proto kernel scope link src 10.20.55.1')
1879 self
.assertRegex(output
, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1')
1880 self
.assertRegex(output
, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1')
1881 output
= check_output('ip -6 route show table 42 dev dummy98')
1882 print('### ip -6 route show table 42 dev dummy98')
1886 self
.assertRegex(output
, 'local fdde:11:22::1 proto kernel metric 0 pref medium')
1887 #self.assertRegex(output, 'fdde:11:22::1 proto kernel metric 256 pref medium')
1888 self
.assertRegex(output
, 'local fdde:11:33::1 proto kernel metric 0 pref medium')
1889 self
.assertRegex(output
, 'fdde:11:33::/64 proto kernel metric 256 pref medium')
1890 self
.assertRegex(output
, 'local fdde:11:44::1 proto kernel metric 0 pref medium')
1891 self
.assertRegex(output
, 'local fdde:11:55::1 proto kernel metric 0 pref medium')
1892 self
.assertRegex(output
, 'fe80::/64 proto kernel metric 256 pref medium')
1893 self
.assertRegex(output
, 'ff00::/8 metric 256 pref medium')
1897 output
= check_output('ip route show dev test1')
1898 print('### ip route show dev test1')
1900 self
.assertRegex(output
, '10.21.33.0/24 proto kernel scope link src 10.21.33.1')
1901 output
= check_output('ip route show table local dev test1')
1902 print('### ip route show table local dev test1')
1904 self
.assertRegex(output
, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1')
1905 self
.assertRegex(output
, 'broadcast 10.21.33.0 proto kernel scope link src 10.21.33.1')
1906 self
.assertRegex(output
, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1')
1907 self
.assertRegex(output
, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1')
1908 self
.assertRegex(output
, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1')
1909 self
.assertRegex(output
, 'broadcast 10.21.55.0 proto kernel scope link src 10.21.55.1')
1910 self
.assertRegex(output
, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1')
1911 self
.assertRegex(output
, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1')
1912 output
= check_output('ip -6 route show dev test1')
1913 print('### ip -6 route show dev test1')
1915 self
.assertRegex(output
, 'fdde:12:22::1 proto kernel metric 256 pref medium')
1916 self
.assertRegex(output
, 'fdde:12:33::/64 proto kernel metric 256 pref medium')
1917 self
.assertRegex(output
, 'fe80::/64 proto kernel metric 256 pref medium')
1918 output
= check_output('ip -6 route show table local dev test1')
1919 print('### ip -6 route show table local dev test1')
1921 self
.assertRegex(output
, 'local fdde:12:22::1 proto kernel metric 0 pref medium')
1922 self
.assertRegex(output
, 'local fdde:12:33::1 proto kernel metric 0 pref medium')
1923 self
.assertRegex(output
, 'local fdde:12:44::1 proto kernel metric 0 pref medium')
1924 self
.assertRegex(output
, 'local fdde:12:55::1 proto kernel metric 0 pref medium')
1925 self
.assertRegex(output
, 'ff00::/8 metric 256 pref medium')
1927 def test_configure_without_carrier(self
):
1928 copy_unit_to_networkd_unit_path('11-dummy.netdev')
1930 self
.wait_operstate('test1', 'off', '')
1931 check_output('ip link set dev test1 up carrier off')
1933 copy_unit_to_networkd_unit_path('25-test1.network.d/configure-without-carrier.conf', dropins
=False)
1935 self
.wait_online(['test1:no-carrier'])
1937 carrier_map
= {'on': '1', 'off': '0'}
1938 routable_map
= {'on': 'routable', 'off': 'no-carrier'}
1939 for carrier
in ['off', 'on', 'off']:
1940 with self
.subTest(carrier
=carrier
):
1941 if carrier_map
[carrier
] != read_link_attr('test1', 'carrier'):
1942 check_output(f
'ip link set dev test1 carrier {carrier}')
1943 self
.wait_online([f
'test1:{routable_map[carrier]}'])
1945 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
1947 self
.assertRegex(output
, '192.168.0.15')
1948 self
.assertRegex(output
, '192.168.0.1')
1949 self
.assertRegex(output
, routable_map
[carrier
])
1951 def test_configure_without_carrier_yes_ignore_carrier_loss_no(self
):
1952 copy_unit_to_networkd_unit_path('11-dummy.netdev')
1954 self
.wait_operstate('test1', 'off', '')
1955 check_output('ip link set dev test1 up carrier off')
1957 copy_unit_to_networkd_unit_path('25-test1.network')
1959 self
.wait_online(['test1:no-carrier'])
1961 carrier_map
= {'on': '1', 'off': '0'}
1962 routable_map
= {'on': 'routable', 'off': 'no-carrier'}
1963 for (carrier
, have_config
) in [('off', True), ('on', True), ('off', False)]:
1964 with self
.subTest(carrier
=carrier
, have_config
=have_config
):
1965 if carrier_map
[carrier
] != read_link_attr('test1', 'carrier'):
1966 check_output(f
'ip link set dev test1 carrier {carrier}')
1967 self
.wait_online([f
'test1:{routable_map[carrier]}'])
1969 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
1972 self
.assertRegex(output
, '192.168.0.15')
1973 self
.assertRegex(output
, '192.168.0.1')
1975 self
.assertNotRegex(output
, '192.168.0.15')
1976 self
.assertNotRegex(output
, '192.168.0.1')
1977 self
.assertRegex(output
, routable_map
[carrier
])
1979 def test_routing_policy_rule(self
):
1980 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1982 self
.wait_online(['test1:degraded'])
1984 output
= check_output('ip rule list iif test1 priority 111')
1986 self
.assertRegex(output
, '111:')
1987 self
.assertRegex(output
, 'from 192.168.100.18')
1988 self
.assertRegex(output
, r
'tos (0x08|throughput)\s')
1989 self
.assertRegex(output
, 'iif test1')
1990 self
.assertRegex(output
, 'oif test1')
1991 self
.assertRegex(output
, 'lookup 7')
1993 output
= check_output('ip rule list iif test1 priority 101')
1995 self
.assertRegex(output
, '101:')
1996 self
.assertRegex(output
, 'from all')
1997 self
.assertRegex(output
, 'iif test1')
1998 self
.assertRegex(output
, 'lookup 9')
2000 output
= check_output('ip -6 rule list iif test1 priority 100')
2002 self
.assertRegex(output
, '100:')
2003 self
.assertRegex(output
, 'from all')
2004 self
.assertRegex(output
, 'iif test1')
2005 self
.assertRegex(output
, 'lookup 8')
2007 def test_routing_policy_rule_issue_11280(self
):
2008 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
2009 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
2011 for trial
in range(3):
2012 # Remove state files only first time
2014 self
.wait_online(['test1:degraded', 'dummy98:degraded'])
2017 output
= check_output('ip rule list table 7')
2019 self
.assertRegex(output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
2021 output
= check_output('ip rule list table 8')
2023 self
.assertRegex(output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
2025 stop_networkd(remove_state_files
=False)
2027 def test_routing_policy_rule_reconfigure(self
):
2028 copy_unit_to_networkd_unit_path('routing-policy-rule-reconfigure.network', '11-dummy.netdev')
2030 self
.wait_online(['test1:degraded'])
2032 output
= check_output('ip rule list table 1011')
2034 self
.assertRegex(output
, '10111: from all fwmark 0x3f3 lookup 1011')
2035 self
.assertRegex(output
, '10112: from all oif test1 lookup 1011')
2036 self
.assertRegex(output
, '10113: from all iif test1 lookup 1011')
2037 self
.assertRegex(output
, '10114: from 192.168.8.254 lookup 1011')
2039 run('ip rule delete priority 10111')
2040 run('ip rule delete priority 10112')
2041 run('ip rule delete priority 10113')
2042 run('ip rule delete priority 10114')
2043 run('ip rule delete priority 10115')
2045 output
= check_output('ip rule list table 1011')
2047 self
.assertEqual(output
, '')
2049 run(*networkctl_cmd
, 'reconfigure', 'test1', env
=env
)
2051 self
.wait_online(['test1:degraded'])
2053 output
= check_output('ip rule list table 1011')
2055 self
.assertRegex(output
, '10111: from all fwmark 0x3f3 lookup 1011')
2056 self
.assertRegex(output
, '10112: from all oif test1 lookup 1011')
2057 self
.assertRegex(output
, '10113: from all iif test1 lookup 1011')
2058 self
.assertRegex(output
, '10114: from 192.168.8.254 lookup 1011')
2060 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
2061 def test_routing_policy_rule_port_range(self
):
2062 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
2064 self
.wait_online(['test1:degraded'])
2066 output
= check_output('ip rule')
2068 self
.assertRegex(output
, '111')
2069 self
.assertRegex(output
, 'from 192.168.100.18')
2070 self
.assertRegex(output
, '1123-1150')
2071 self
.assertRegex(output
, '3224-3290')
2072 self
.assertRegex(output
, 'tcp')
2073 self
.assertRegex(output
, 'lookup 7')
2075 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
2076 def test_routing_policy_rule_invert(self
):
2077 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
2079 self
.wait_online(['test1:degraded'])
2081 output
= check_output('ip rule')
2083 self
.assertRegex(output
, '111')
2084 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
2085 self
.assertRegex(output
, 'tcp')
2086 self
.assertRegex(output
, 'lookup 7')
2088 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable()
2089 def test_routing_policy_rule_uidrange(self
):
2090 copy_unit_to_networkd_unit_path('25-fibrule-uidrange.network', '11-dummy.netdev')
2092 self
.wait_online(['test1:degraded'])
2094 output
= check_output('ip rule')
2096 self
.assertRegex(output
, '111')
2097 self
.assertRegex(output
, 'from 192.168.100.18')
2098 self
.assertRegex(output
, 'lookup 7')
2099 self
.assertRegex(output
, 'uidrange 100-200')
2101 def test_route_static(self
):
2102 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
2104 self
.wait_online(['dummy98:routable'])
2106 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2109 print('### ip -6 route show dev dummy98')
2110 output
= check_output('ip -6 route show dev dummy98')
2112 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
2113 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
2115 print('### ip -6 route show dev dummy98 default')
2116 output
= check_output('ip -6 route show dev dummy98 default')
2118 self
.assertRegex(output
, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
2120 print('### ip -4 route show dev dummy98')
2121 output
= check_output('ip -4 route show dev dummy98')
2123 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
2124 self
.assertRegex(output
, '149.10.124.64 proto static scope link')
2125 self
.assertRegex(output
, '169.254.0.0/16 proto static scope link metric 2048')
2126 self
.assertRegex(output
, '192.168.1.1 proto static initcwnd 20')
2127 self
.assertRegex(output
, '192.168.1.2 proto static initrwnd 30')
2128 self
.assertRegex(output
, 'multicast 149.10.123.4 proto static')
2130 print('### ip -4 route show dev dummy98 default')
2131 output
= check_output('ip -4 route show dev dummy98 default')
2133 self
.assertRegex(output
, 'default via 149.10.125.65 proto static onlink')
2134 self
.assertRegex(output
, 'default via 149.10.124.64 proto static')
2135 self
.assertRegex(output
, 'default proto static')
2137 print('### ip -4 route show table local dev dummy98')
2138 output
= check_output('ip -4 route show table local dev dummy98')
2140 self
.assertRegex(output
, 'local 149.10.123.1 proto static scope host')
2141 self
.assertRegex(output
, 'anycast 149.10.123.2 proto static scope link')
2142 self
.assertRegex(output
, 'broadcast 149.10.123.3 proto static scope link')
2144 print('### ip route show type blackhole')
2145 output
= check_output('ip route show type blackhole')
2147 self
.assertRegex(output
, 'blackhole 202.54.1.2 proto static')
2149 print('### ip route show type unreachable')
2150 output
= check_output('ip route show type unreachable')
2152 self
.assertRegex(output
, 'unreachable 202.54.1.3 proto static')
2154 print('### ip route show type prohibit')
2155 output
= check_output('ip route show type prohibit')
2157 self
.assertRegex(output
, 'prohibit 202.54.1.4 proto static')
2159 print('### ip route show 192.168.10.1')
2160 output
= check_output('ip route show 192.168.10.1')
2162 self
.assertRegex(output
, '192.168.10.1 proto static')
2163 self
.assertRegex(output
, 'nexthop via 149.10.124.59 dev dummy98 weight 10')
2164 self
.assertRegex(output
, 'nexthop via 149.10.124.60 dev dummy98 weight 5')
2166 print('### ip route show 192.168.10.2')
2167 output
= check_output('ip route show 192.168.10.2')
2169 # old ip command does not show IPv6 gateways...
2170 self
.assertRegex(output
, '192.168.10.2 proto static')
2171 self
.assertRegex(output
, 'nexthop')
2172 self
.assertRegex(output
, 'dev dummy98 weight 10')
2173 self
.assertRegex(output
, 'dev dummy98 weight 5')
2175 print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2176 output
= check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2178 # old ip command does not show 'nexthop' keyword and weight...
2179 self
.assertRegex(output
, '2001:1234:5:7fff:ff:ff:ff:ff')
2180 self
.assertRegex(output
, 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98')
2181 self
.assertRegex(output
, 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98')
2183 @expectedFailureIfModuleIsNotAvailable('vrf')
2184 def test_route_vrf(self
):
2185 copy_unit_to_networkd_unit_path('25-route-vrf.network', '12-dummy.netdev',
2186 '25-vrf.netdev', '25-vrf.network')
2188 self
.wait_online(['dummy98:routable', 'vrf99:carrier'])
2190 output
= check_output('ip route show vrf vrf99')
2192 self
.assertRegex(output
, 'default via 192.168.100.1')
2194 output
= check_output('ip route show')
2196 self
.assertNotRegex(output
, 'default via 192.168.100.1')
2198 def test_gateway_reconfigure(self
):
2199 copy_unit_to_networkd_unit_path('25-gateway-static.network', '12-dummy.netdev')
2201 self
.wait_online(['dummy98:routable'])
2202 print('### ip -4 route show dev dummy98 default')
2203 output
= check_output('ip -4 route show dev dummy98 default')
2205 self
.assertRegex(output
, 'default via 149.10.124.59 proto static')
2206 self
.assertNotRegex(output
, '149.10.124.60')
2208 remove_unit_from_networkd_path(['25-gateway-static.network'])
2209 copy_unit_to_networkd_unit_path('25-gateway-next-static.network')
2211 self
.wait_online(['dummy98:routable'])
2212 print('### ip -4 route show dev dummy98 default')
2213 output
= check_output('ip -4 route show dev dummy98 default')
2215 self
.assertNotRegex(output
, '149.10.124.59')
2216 self
.assertRegex(output
, 'default via 149.10.124.60 proto static')
2218 def test_ip_route_ipv6_src_route(self
):
2219 # a dummy device does not make the addresses go through tentative state, so we
2220 # reuse a bond from an earlier test, which does make the addresses go through
2221 # tentative state, and do our test on that
2222 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2224 self
.wait_online(['dummy98:enslaved', 'bond199:routable'])
2226 output
= check_output('ip -6 route list dev bond199')
2228 self
.assertRegex(output
, 'abcd::/16')
2229 self
.assertRegex(output
, 'src')
2230 self
.assertRegex(output
, '2001:1234:56:8f63::2')
2232 def test_ip_link_mac_address(self
):
2233 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
2235 self
.wait_online(['dummy98:degraded'])
2237 output
= check_output('ip link show dummy98')
2239 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
2241 def test_ip_link_unmanaged(self
):
2242 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
2245 self
.check_link_exists('dummy98')
2247 self
.wait_operstate('dummy98', 'off', setup_state
='unmanaged')
2249 def test_ipv6_address_label(self
):
2250 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
2252 self
.wait_online(['dummy98:degraded'])
2254 output
= check_output('ip addrlabel list')
2256 self
.assertRegex(output
, '2004:da8:1::/64')
2258 def test_neighbor_section(self
):
2259 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2261 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2263 print('### ip neigh list dev dummy98')
2264 output
= check_output('ip neigh list dev dummy98')
2266 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2267 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2269 def test_neighbor_reconfigure(self
):
2270 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2272 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2274 print('### ip neigh list dev dummy98')
2275 output
= check_output('ip neigh list dev dummy98')
2277 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2278 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2280 remove_unit_from_networkd_path(['25-neighbor-section.network'])
2281 copy_unit_to_networkd_unit_path('25-neighbor-next.network')
2283 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2284 print('### ip neigh list dev dummy98')
2285 output
= check_output('ip neigh list dev dummy98')
2287 self
.assertNotRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2288 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT')
2289 self
.assertNotRegex(output
, '2004:da8:1::1.*PERMANENT')
2291 def test_neighbor_gre(self
):
2292 copy_unit_to_networkd_unit_path('25-neighbor-ip.network', '25-neighbor-ipv6.network', '25-neighbor-ip-dummy.network',
2293 '12-dummy.netdev', '25-gre-tunnel-remote-any.netdev', '25-ip6gre-tunnel-remote-any.netdev')
2295 self
.wait_online(['dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable'], timeout
='40s')
2297 output
= check_output('ip neigh list dev gretun97')
2299 self
.assertRegex(output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT')
2301 output
= check_output('ip neigh list dev ip6gretun97')
2303 self
.assertRegex(output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
2305 def test_link_local_addressing(self
):
2306 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
2307 '25-link-local-addressing-no.network', '12-dummy.netdev')
2309 self
.wait_online(['test1:degraded', 'dummy98:carrier'])
2311 output
= check_output('ip address show dev test1')
2313 self
.assertRegex(output
, 'inet .* scope link')
2314 self
.assertRegex(output
, 'inet6 .* scope link')
2316 output
= check_output('ip address show dev dummy98')
2318 self
.assertNotRegex(output
, 'inet6* .* scope link')
2321 Documentation/networking/ip-sysctl.txt
2323 addr_gen_mode - INTEGER
2324 Defines how link-local and autoconf addresses are generated.
2326 0: generate address based on EUI64 (default)
2327 1: do no generate a link-local address, use EUI64 for addresses generated
2329 2: generate stable privacy addresses, using the secret from
2330 stable_secret (RFC7217)
2331 3: generate stable privacy addresses, using a random secret if unset
2334 test1_addr_gen_mode
= ''
2335 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
2336 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
2340 # if stable_secret is unset, then EIO is returned
2341 test1_addr_gen_mode
= '0'
2343 test1_addr_gen_mode
= '2'
2345 test1_addr_gen_mode
= '0'
2347 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
2348 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
2350 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
2351 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
2353 def test_link_local_addressing_remove_ipv6ll(self
):
2354 copy_unit_to_networkd_unit_path('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
2356 self
.wait_online(['dummy98:degraded'])
2358 output
= check_output('ip address show dev dummy98')
2360 self
.assertRegex(output
, 'inet6 .* scope link')
2362 copy_unit_to_networkd_unit_path('25-link-local-addressing-no.network')
2364 self
.wait_online(['dummy98:carrier'])
2366 output
= check_output('ip address show dev dummy98')
2368 self
.assertNotRegex(output
, 'inet6* .* scope link')
2370 def test_sysctl(self
):
2371 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
2373 self
.wait_online(['dummy98:degraded'])
2375 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
2376 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
2377 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
2378 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
2379 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
2380 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
2381 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
2382 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'accept_local'), '1')
2384 def test_sysctl_disable_ipv6(self
):
2385 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
2387 print('## Disable ipv6')
2388 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
2389 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
2392 self
.wait_online(['dummy98:routable'])
2394 output
= check_output('ip -4 address show dummy98')
2396 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2397 output
= check_output('ip -6 address show dummy98')
2399 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2400 self
.assertRegex(output
, 'inet6 .* scope link')
2401 output
= check_output('ip -4 route show dev dummy98')
2403 self
.assertRegex(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2404 output
= check_output('ip -6 route show dev dummy98')
2406 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2408 check_output('ip link del dummy98')
2410 print('## Enable ipv6')
2411 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
2412 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
2415 self
.wait_online(['dummy98:routable'])
2417 output
= check_output('ip -4 address show dummy98')
2419 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2420 output
= check_output('ip -6 address show dummy98')
2422 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2423 self
.assertRegex(output
, 'inet6 .* scope link')
2424 output
= check_output('ip -4 route show dev dummy98')
2426 self
.assertRegex(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2427 output
= check_output('ip -6 route show dev dummy98')
2429 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2431 def test_bind_carrier(self
):
2432 check_output('ip link add dummy98 type dummy')
2433 check_output('ip link set dummy98 up')
2436 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
2438 self
.wait_online(['test1:routable'])
2440 output
= check_output('ip address show test1')
2442 self
.assertRegex(output
, 'UP,LOWER_UP')
2443 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2444 self
.wait_operstate('test1', 'routable')
2446 check_output('ip link add dummy99 type dummy')
2447 check_output('ip link set dummy99 up')
2449 output
= check_output('ip address show test1')
2451 self
.assertRegex(output
, 'UP,LOWER_UP')
2452 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2453 self
.wait_operstate('test1', 'routable')
2455 check_output('ip link del dummy98')
2457 output
= check_output('ip address show test1')
2459 self
.assertRegex(output
, 'UP,LOWER_UP')
2460 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2461 self
.wait_operstate('test1', 'routable')
2463 check_output('ip link set dummy99 down')
2465 output
= check_output('ip address show test1')
2467 self
.assertNotRegex(output
, 'UP,LOWER_UP')
2468 self
.assertRegex(output
, 'DOWN')
2469 self
.assertNotRegex(output
, '192.168.10')
2470 self
.wait_operstate('test1', 'off')
2472 check_output('ip link set dummy99 up')
2474 output
= check_output('ip address show test1')
2476 self
.assertRegex(output
, 'UP,LOWER_UP')
2477 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2478 self
.wait_operstate('test1', 'routable')
2480 def test_domain(self
):
2481 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
2483 self
.wait_online(['dummy98:routable'])
2485 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2487 self
.assertRegex(output
, 'Address: 192.168.42.100')
2488 self
.assertRegex(output
, 'DNS: 192.168.42.1')
2489 self
.assertRegex(output
, 'Search Domains: one')
2491 def test_keep_configuration_static(self
):
2492 check_output('systemctl stop systemd-networkd.socket')
2493 check_output('systemctl stop systemd-networkd.service')
2495 check_output('ip link add name dummy98 type dummy')
2496 check_output('ip address add 10.1.2.3/16 dev dummy98')
2497 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
2498 output
= check_output('ip address show dummy98')
2500 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2501 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2502 output
= check_output('ip route show dev dummy98')
2505 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
2507 self
.wait_online(['dummy98:routable'])
2509 output
= check_output('ip address show dummy98')
2511 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2512 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2514 @expectedFailureIfNexthopIsNotAvailable()
2515 def test_nexthop(self
):
2516 copy_unit_to_networkd_unit_path('25-nexthop.network', '25-veth.netdev', '25-veth-peer.network')
2518 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2520 output
= check_output('ip nexthop list dev veth99')
2522 self
.assertRegex(output
, '192.168.5.1')
2524 def test_qdisc(self
):
2525 copy_unit_to_networkd_unit_path('25-qdisc-clsact-and-htb.network', '12-dummy.netdev',
2526 '25-qdisc-ingress-netem-compat.network', '11-dummy.netdev')
2527 check_output('modprobe sch_teql max_equalizers=2')
2530 self
.wait_online(['dummy98:routable', 'test1:routable'])
2532 output
= check_output('tc qdisc show dev test1')
2534 self
.assertRegex(output
, 'qdisc netem')
2535 self
.assertRegex(output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
2536 self
.assertRegex(output
, 'qdisc ingress')
2538 output
= check_output('tc qdisc show dev dummy98')
2540 self
.assertRegex(output
, 'qdisc clsact')
2542 self
.assertRegex(output
, 'qdisc htb 2: root')
2543 self
.assertRegex(output
, r
'default (0x30|30)')
2545 self
.assertRegex(output
, 'qdisc netem 30: parent 2:30')
2546 self
.assertRegex(output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
2547 self
.assertRegex(output
, 'qdisc fq_codel')
2548 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')
2550 self
.assertRegex(output
, 'qdisc teql1 31: parent 2:31')
2552 self
.assertRegex(output
, 'qdisc fq 32: parent 2:32')
2553 self
.assertRegex(output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
2554 self
.assertRegex(output
, 'quantum 1500')
2555 self
.assertRegex(output
, 'initial_quantum 13000')
2556 self
.assertRegex(output
, 'maxrate 1Mbit')
2558 self
.assertRegex(output
, 'qdisc codel 33: parent 2:33')
2559 self
.assertRegex(output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn')
2561 self
.assertRegex(output
, 'qdisc fq_codel 34: parent 2:34')
2562 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')
2564 self
.assertRegex(output
, 'qdisc tbf 35: parent 2:35')
2565 self
.assertRegex(output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms')
2567 self
.assertRegex(output
, 'qdisc sfq 36: parent 2:36')
2568 self
.assertRegex(output
, 'perturb 5sec')
2570 self
.assertRegex(output
, 'qdisc pfifo 37: parent 2:37')
2571 self
.assertRegex(output
, 'limit 100000p')
2573 self
.assertRegex(output
, 'qdisc gred 38: parent 2:38')
2574 self
.assertRegex(output
, 'vqs 12 default 10 grio')
2576 self
.assertRegex(output
, 'qdisc sfb 39: parent 2:39')
2577 self
.assertRegex(output
, 'limit 200000')
2579 self
.assertRegex(output
, 'qdisc bfifo 3a: parent 2:3a')
2580 self
.assertRegex(output
, 'limit 1000000')
2582 self
.assertRegex(output
, 'qdisc pfifo_head_drop 3b: parent 2:3b')
2583 self
.assertRegex(output
, 'limit 1023p')
2585 self
.assertRegex(output
, 'qdisc pfifo_fast 3c: parent 2:3c')
2587 output
= check_output('tc -d class show dev dummy98')
2589 self
.assertRegex(output
, 'class htb 2:30 root leaf 30:')
2590 self
.assertRegex(output
, 'class htb 2:31 root leaf 31:')
2591 self
.assertRegex(output
, 'class htb 2:32 root leaf 32:')
2592 self
.assertRegex(output
, 'class htb 2:33 root leaf 33:')
2593 self
.assertRegex(output
, 'class htb 2:34 root leaf 34:')
2594 self
.assertRegex(output
, 'class htb 2:35 root leaf 35:')
2595 self
.assertRegex(output
, 'class htb 2:36 root leaf 36:')
2596 self
.assertRegex(output
, 'class htb 2:37 root leaf 37:')
2597 self
.assertRegex(output
, 'class htb 2:38 root leaf 38:')
2598 self
.assertRegex(output
, 'class htb 2:39 root leaf 39:')
2599 self
.assertRegex(output
, 'class htb 2:3a root leaf 3a:')
2600 self
.assertRegex(output
, 'class htb 2:3b root leaf 3b:')
2601 self
.assertRegex(output
, 'class htb 2:3c root leaf 3c:')
2602 self
.assertRegex(output
, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit')
2603 self
.assertRegex(output
, 'burst 123456')
2604 self
.assertRegex(output
, 'cburst 123457')
2606 def test_qdisc2(self
):
2607 copy_unit_to_networkd_unit_path('25-qdisc-drr.network', '12-dummy.netdev',
2608 '25-qdisc-qfq.network', '11-dummy.netdev')
2611 self
.wait_online(['dummy98:routable', 'test1:routable'])
2613 output
= check_output('tc qdisc show dev dummy98')
2615 self
.assertRegex(output
, 'qdisc drr 2: root')
2616 output
= check_output('tc class show dev dummy98')
2618 self
.assertRegex(output
, 'class drr 2:30 root quantum 2000b')
2620 output
= check_output('tc qdisc show dev test1')
2622 self
.assertRegex(output
, 'qdisc qfq 2: root')
2623 output
= check_output('tc class show dev test1')
2625 self
.assertRegex(output
, 'class qfq 2:30 root weight 2 maxpkt 16000')
2626 self
.assertRegex(output
, 'class qfq 2:31 root weight 10 maxpkt 8000')
2628 @expectedFailureIfCAKEIsNotAvailable()
2629 def test_qdisc_cake(self
):
2630 copy_unit_to_networkd_unit_path('25-qdisc-cake.network', '12-dummy.netdev')
2632 self
.wait_online(['dummy98:routable'])
2634 output
= check_output('tc qdisc show dev dummy98')
2636 self
.assertRegex(output
, 'qdisc cake 3a: root')
2637 self
.assertRegex(output
, 'bandwidth 500Mbit')
2638 self
.assertRegex(output
, 'overhead 128')
2640 @expectedFailureIfPIEIsNotAvailable()
2641 def test_qdisc_pie(self
):
2642 copy_unit_to_networkd_unit_path('25-qdisc-pie.network', '12-dummy.netdev')
2644 self
.wait_online(['dummy98:routable'])
2646 output
= check_output('tc qdisc show dev dummy98')
2648 self
.assertRegex(output
, 'qdisc pie 3a: root')
2649 self
.assertRegex(output
, 'limit 200000')
2651 @expectedFailureIfHHFIsNotAvailable()
2652 def test_qdisc_hhf(self
):
2653 copy_unit_to_networkd_unit_path('25-qdisc-hhf.network', '12-dummy.netdev')
2655 self
.wait_online(['dummy98:routable'])
2657 output
= check_output('tc qdisc show dev dummy98')
2659 self
.assertRegex(output
, 'qdisc hhf 3a: root')
2660 self
.assertRegex(output
, 'limit 1022p')
2662 @expectedFailureIfETSIsNotAvailable()
2663 def test_qdisc_ets(self
):
2664 copy_unit_to_networkd_unit_path('25-qdisc-ets.network', '12-dummy.netdev')
2666 self
.wait_online(['dummy98:routable'])
2668 output
= check_output('tc qdisc show dev dummy98')
2670 self
.assertRegex(output
, 'qdisc ets 3a: root')
2671 self
.assertRegex(output
, 'bands 10 strict 3')
2672 self
.assertRegex(output
, 'quanta 1 2 3 4 5')
2673 self
.assertRegex(output
, 'priomap 3 4 5 6 7')
2675 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable()
2676 def test_sriov(self
):
2677 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
2678 call('modprobe netdevsim', stderr
=subprocess
.DEVNULL
)
2679 with
open('/sys/bus/netdevsim/new_device', mode
='w') as f
:
2682 call('udevadm settle')
2683 call('udevadm info -w10s /sys/devices/netdevsim99/net/eni99np1', stderr
=subprocess
.DEVNULL
)
2684 with
open('/sys/class/net/eni99np1/device/sriov_numvfs', mode
='w') as f
:
2687 copy_unit_to_networkd_unit_path('25-sriov.network')
2689 self
.wait_online(['eni99np1:routable'])
2691 output
= check_output('ip link show dev eni99np1')
2693 self
.assertRegex(output
,
2694 '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 *'
2695 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
2696 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
2699 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
2701 class NetworkdStateFileTests(unittest
.TestCase
, Utilities
):
2708 'state-file-tests.network',
2712 remove_links(self
.links
)
2713 stop_networkd(show_logs
=False)
2716 remove_links(self
.links
)
2717 remove_unit_from_networkd_path(self
.units
)
2718 stop_networkd(show_logs
=True)
2720 def test_state_file(self
):
2721 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'state-file-tests.network')
2723 self
.wait_online(['dummy98:routable'])
2725 output
= check_output(*networkctl_cmd
, '--no-legend', 'list', 'dummy98', env
=env
)
2727 ifindex
= output
.split()[0]
2729 path
= os
.path
.join('/run/systemd/netif/links/', ifindex
)
2730 self
.assertTrue(os
.path
.exists(path
))
2732 # make link state file updated
2733 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
2735 with
open(path
) as f
:
2737 self
.assertRegex(data
, r
'ADMIN_STATE=configured')
2738 self
.assertRegex(data
, r
'OPER_STATE=routable')
2739 self
.assertRegex(data
, r
'REQUIRED_FOR_ONLINE=yes')
2740 self
.assertRegex(data
, r
'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
2741 self
.assertRegex(data
, r
'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
2742 self
.assertRegex(data
, r
'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
2743 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2744 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2745 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2746 self
.assertRegex(data
, r
'LLMNR=no')
2747 self
.assertRegex(data
, r
'MDNS=yes')
2748 self
.assertRegex(data
, r
'DNSSEC=no')
2749 self
.assertRegex(data
, r
'ADDRESSES=192.168.(10.10|12.12)/24 192.168.(12.12|10.10)/24')
2751 check_output(*resolvectl_cmd
, 'dns', 'dummy98', '10.10.10.12#ccc.com', '10.10.10.13', '1111:2222::3333', env
=env
)
2752 check_output(*resolvectl_cmd
, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env
=env
)
2753 check_output(*resolvectl_cmd
, 'llmnr', 'dummy98', 'yes', env
=env
)
2754 check_output(*resolvectl_cmd
, 'mdns', 'dummy98', 'no', env
=env
)
2755 check_output(*resolvectl_cmd
, 'dnssec', 'dummy98', 'yes', env
=env
)
2756 check_output(*timedatectl_cmd
, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env
=env
)
2758 with
open(path
) as f
:
2760 self
.assertRegex(data
, r
'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333')
2761 self
.assertRegex(data
, r
'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org')
2762 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2763 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2764 self
.assertRegex(data
, r
'LLMNR=yes')
2765 self
.assertRegex(data
, r
'MDNS=no')
2766 self
.assertRegex(data
, r
'DNSSEC=yes')
2768 check_output(*timedatectl_cmd
, 'revert', 'dummy98', env
=env
)
2770 with
open(path
) as f
:
2772 self
.assertRegex(data
, r
'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333')
2773 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2774 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2775 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2776 self
.assertRegex(data
, r
'LLMNR=yes')
2777 self
.assertRegex(data
, r
'MDNS=no')
2778 self
.assertRegex(data
, r
'DNSSEC=yes')
2780 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
2782 with
open(path
) as f
:
2784 self
.assertRegex(data
, r
'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
2785 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2786 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2787 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2788 self
.assertRegex(data
, r
'LLMNR=no')
2789 self
.assertRegex(data
, r
'MDNS=yes')
2790 self
.assertRegex(data
, r
'DNSSEC=no')
2792 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
2802 '23-active-slave.network',
2803 '23-bond199.network',
2804 '23-primary-slave.network',
2805 '25-bond-active-backup-slave.netdev',
2808 'bond-slave.network']
2811 remove_links(self
.links
)
2812 stop_networkd(show_logs
=False)
2815 remove_links(self
.links
)
2816 remove_unit_from_networkd_path(self
.units
)
2817 stop_networkd(show_logs
=True)
2819 def test_bond_active_slave(self
):
2820 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2822 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2824 output
= check_output('ip -d link show bond199')
2826 self
.assertRegex(output
, 'active_slave dummy98')
2828 def test_bond_primary_slave(self
):
2829 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2831 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2833 output
= check_output('ip -d link show bond199')
2835 self
.assertRegex(output
, 'primary dummy98')
2837 def test_bond_operstate(self
):
2838 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
2839 'bond99.network','bond-slave.network')
2841 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
2843 output
= check_output('ip -d link show dummy98')
2845 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2847 output
= check_output('ip -d link show test1')
2849 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2851 output
= check_output('ip -d link show bond99')
2853 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
2855 self
.wait_operstate('dummy98', 'enslaved')
2856 self
.wait_operstate('test1', 'enslaved')
2857 self
.wait_operstate('bond99', 'routable')
2859 check_output('ip link set dummy98 down')
2861 self
.wait_operstate('dummy98', 'off')
2862 self
.wait_operstate('test1', 'enslaved')
2863 self
.wait_operstate('bond99', 'degraded-carrier')
2865 check_output('ip link set dummy98 up')
2867 self
.wait_operstate('dummy98', 'enslaved')
2868 self
.wait_operstate('test1', 'enslaved')
2869 self
.wait_operstate('bond99', 'routable')
2871 check_output('ip link set dummy98 down')
2872 check_output('ip link set test1 down')
2874 self
.wait_operstate('dummy98', 'off')
2875 self
.wait_operstate('test1', 'off')
2877 if not self
.wait_operstate('bond99', 'no-carrier', setup_timeout
=30, fail_assert
=False):
2878 # Huh? Kernel does not recognize that all slave interfaces are down?
2879 # Let's confirm that networkd's operstate is consistent with ip's result.
2880 self
.assertNotRegex(output
, 'NO-CARRIER')
2882 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
2892 '26-bridge-configure-without-carrier.network',
2893 '26-bridge-mdb-master.network',
2894 '26-bridge-mdb-slave.network',
2895 '26-bridge-slave-interface-1.network',
2896 '26-bridge-slave-interface-2.network',
2897 '26-bridge-vlan-master.network',
2898 '26-bridge-vlan-slave.network',
2899 'bridge99-ignore-carrier-loss.network',
2902 routing_policy_rule_tables
= ['100']
2905 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2906 remove_links(self
.links
)
2907 stop_networkd(show_logs
=False)
2910 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2911 remove_links(self
.links
)
2912 remove_unit_from_networkd_path(self
.units
)
2913 stop_networkd(show_logs
=True)
2915 def test_bridge_vlan(self
):
2916 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
2917 '26-bridge.netdev', '26-bridge-vlan-master.network')
2919 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
2921 output
= check_output('bridge vlan show dev test1')
2923 self
.assertNotRegex(output
, '4063')
2924 for i
in range(4064, 4095):
2925 self
.assertRegex(output
, f
'{i}')
2926 self
.assertNotRegex(output
, '4095')
2928 output
= check_output('bridge vlan show dev bridge99')
2930 self
.assertNotRegex(output
, '4059')
2931 for i
in range(4060, 4095):
2932 self
.assertRegex(output
, f
'{i}')
2933 self
.assertNotRegex(output
, '4095')
2935 def test_bridge_mdb(self
):
2936 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-mdb-slave.network',
2937 '26-bridge.netdev', '26-bridge-mdb-master.network')
2939 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
2941 output
= check_output('bridge mdb show dev bridge99')
2943 self
.assertRegex(output
, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064')
2944 self
.assertRegex(output
, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065')
2946 def test_bridge_property(self
):
2947 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2948 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2951 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2953 output
= check_output('ip -d link show test1')
2955 self
.assertRegex(output
, 'master')
2956 self
.assertRegex(output
, 'bridge')
2958 output
= check_output('ip -d link show dummy98')
2960 self
.assertRegex(output
, 'master')
2961 self
.assertRegex(output
, 'bridge')
2963 output
= check_output('ip addr show bridge99')
2965 self
.assertRegex(output
, '192.168.0.15/24')
2967 output
= check_output('bridge -d link show dummy98')
2969 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
2970 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
2971 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
2972 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
2973 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
2974 # CONFIG_BRIDGE_IGMP_SNOOPING=y
2975 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
2976 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
2977 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
2978 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
2979 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
2980 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'priority'), '23')
2981 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard'), '1')
2982 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'root_block'), '1')
2984 output
= check_output('bridge -d link show test1')
2986 self
.assertEqual(read_bridge_port_attr('bridge99', 'test1', 'priority'), '0')
2988 check_output('ip address add 192.168.0.16/24 dev bridge99')
2991 output
= check_output('ip addr show bridge99')
2993 self
.assertRegex(output
, '192.168.0.16/24')
2996 print('### ip -6 route list table all dev bridge99')
2997 output
= check_output('ip -6 route list table all dev bridge99')
2999 self
.assertRegex(output
, 'ff00::/8 table local metric 256 pref medium')
3001 self
.assertEqual(call('ip link del test1'), 0)
3003 self
.wait_operstate('bridge99', 'degraded-carrier')
3005 check_output('ip link del dummy98')
3007 self
.wait_operstate('bridge99', 'no-carrier')
3009 output
= check_output('ip address show bridge99')
3011 self
.assertRegex(output
, 'NO-CARRIER')
3012 self
.assertNotRegex(output
, '192.168.0.15/24')
3013 self
.assertNotRegex(output
, '192.168.0.16/24')
3015 print('### ip -6 route list table all dev bridge99')
3016 output
= check_output('ip -6 route list table all dev bridge99')
3018 self
.assertRegex(output
, 'ff00::/8 table local metric 256 (linkdown )?pref medium')
3020 def test_bridge_configure_without_carrier(self
):
3021 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-configure-without-carrier.network',
3025 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
3026 for test
in ['no-slave', 'add-slave', 'slave-up', 'slave-no-carrier', 'slave-carrier', 'slave-down']:
3027 with self
.subTest(test
=test
):
3028 if test
== 'no-slave':
3029 # bridge has no slaves; it's up but *might* not have carrier
3030 self
.wait_operstate('bridge99', operstate
=r
'(no-carrier|routable)', setup_state
=None, setup_timeout
=30)
3031 # due to a bug in the kernel, newly-created bridges are brought up
3032 # *with* carrier, unless they have had any setting changed; e.g.
3033 # their mac set, priority set, etc. Then, they will lose carrier
3034 # as soon as a (down) slave interface is added, and regain carrier
3035 # again once the slave interface is brought up.
3036 #self.check_link_attr('bridge99', 'carrier', '0')
3037 elif test
== 'add-slave':
3038 # add slave to bridge, but leave it down; bridge is definitely no-carrier
3039 self
.check_link_attr('test1', 'operstate', 'down')
3040 check_output('ip link set dev test1 master bridge99')
3041 self
.wait_operstate('bridge99', operstate
='no-carrier', setup_state
=None)
3042 self
.check_link_attr('bridge99', 'carrier', '0')
3043 elif test
== 'slave-up':
3044 # bring up slave, which will have carrier; bridge gains carrier
3045 check_output('ip link set dev test1 up')
3046 self
.wait_online(['bridge99:routable'])
3047 self
.check_link_attr('bridge99', 'carrier', '1')
3048 elif test
== 'slave-no-carrier':
3049 # drop slave carrier; bridge loses carrier
3050 check_output('ip link set dev test1 carrier off')
3051 self
.wait_online(['bridge99:no-carrier:no-carrier'])
3052 self
.check_link_attr('bridge99', 'carrier', '0')
3053 elif test
== 'slave-carrier':
3054 # restore slave carrier; bridge gains carrier
3055 check_output('ip link set dev test1 carrier on')
3056 self
.wait_online(['bridge99:routable'])
3057 self
.check_link_attr('bridge99', 'carrier', '1')
3058 elif test
== 'slave-down':
3059 # bring down slave; bridge loses carrier
3060 check_output('ip link set dev test1 down')
3061 self
.wait_online(['bridge99:no-carrier:no-carrier'])
3062 self
.check_link_attr('bridge99', 'carrier', '0')
3064 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
3065 self
.assertRegex(output
, '10.1.2.3')
3066 self
.assertRegex(output
, '10.1.2.1')
3068 def test_bridge_ignore_carrier_loss(self
):
3069 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
3070 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
3071 'bridge99-ignore-carrier-loss.network')
3073 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
3075 check_output('ip address add 192.168.0.16/24 dev bridge99')
3078 check_output('ip link del test1')
3079 check_output('ip link del dummy98')
3082 output
= check_output('ip address show bridge99')
3084 self
.assertRegex(output
, 'NO-CARRIER')
3085 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
3086 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
3088 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
3089 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
3090 'bridge99-ignore-carrier-loss.network')
3092 self
.wait_online(['bridge99:no-carrier'])
3094 for trial
in range(4):
3095 check_output('ip link add dummy98 type dummy')
3096 check_output('ip link set dummy98 up')
3098 check_output('ip link del dummy98')
3100 self
.wait_online(['bridge99:routable', 'dummy98:enslaved'])
3102 output
= check_output('ip address show bridge99')
3104 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
3106 output
= check_output('ip rule list table 100')
3108 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
3110 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
3114 '23-emit-lldp.network',
3119 remove_links(self
.links
)
3120 stop_networkd(show_logs
=False)
3123 remove_links(self
.links
)
3124 remove_unit_from_networkd_path(self
.units
)
3125 stop_networkd(show_logs
=True)
3127 def test_lldp(self
):
3128 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
3130 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
3132 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
3134 self
.assertRegex(output
, 'veth-peer')
3135 self
.assertRegex(output
, 'veth99')
3137 class NetworkdRATests(unittest
.TestCase
, Utilities
):
3142 'ipv6-prefix.network',
3143 'ipv6-prefix-veth.network',
3144 'ipv6-prefix-veth-token-static.network',
3145 'ipv6-prefix-veth-token-prefixstable.network',
3146 'ipv6-prefix-veth-token-prefixstable-without-address.network']
3149 remove_links(self
.links
)
3150 stop_networkd(show_logs
=False)
3153 remove_links(self
.links
)
3154 remove_unit_from_networkd_path(self
.units
)
3155 stop_networkd(show_logs
=True)
3157 def test_ipv6_prefix_delegation(self
):
3158 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
3160 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3162 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3164 self
.assertRegex(output
, 'fe80::')
3165 self
.assertRegex(output
, '2002:da8:1::1')
3167 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3169 self
.assertRegex(output
, '2002:da8:1:0')
3171 def test_ipv6_token_static(self
):
3172 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static.network')
3174 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3176 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3178 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
3179 self
.assertRegex(output
, '2002:da8:1:0:fa:de:ca:fe')
3180 self
.assertRegex(output
, '2002:da8:2:0:1a:2b:3c:4d')
3181 self
.assertRegex(output
, '2002:da8:2:0:fa:de:ca:fe')
3183 def test_ipv6_token_prefixstable(self
):
3184 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable.network')
3186 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3188 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3190 self
.assertRegex(output
, '2002:da8:1:0')
3191 self
.assertRegex(output
, '2002:da8:2:0.*78:9abc') # EUI
3193 def test_ipv6_token_prefixstable_without_address(self
):
3194 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable-without-address.network')
3196 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3198 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3200 self
.assertRegex(output
, '2002:da8:1:0')
3201 self
.assertRegex(output
, '2002:da8:2:0')
3203 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
3208 'dhcp-client.network',
3209 'dhcp-client-timezone-router.network',
3210 'dhcp-server.network',
3211 'dhcp-server-timezone-router.network']
3214 remove_links(self
.links
)
3215 stop_networkd(show_logs
=False)
3218 remove_links(self
.links
)
3219 remove_unit_from_networkd_path(self
.units
)
3220 stop_networkd(show_logs
=True)
3222 def test_dhcp_server(self
):
3223 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
3225 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3227 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3229 self
.assertRegex(output
, '192.168.5.*')
3230 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
3231 self
.assertRegex(output
, 'DNS: 192.168.5.1')
3232 self
.assertRegex(output
, 'NTP: 192.168.5.1')
3234 def test_emit_router_timezone(self
):
3235 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
3237 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3239 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3241 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
3242 self
.assertRegex(output
, '192.168.5.*')
3243 self
.assertRegex(output
, 'Europe/Berlin')
3245 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
3254 'dhcp-client-anonymize.network',
3255 'dhcp-client-decline.network',
3256 'dhcp-client-gateway-ipv4.network',
3257 'dhcp-client-gateway-ipv6.network',
3258 'dhcp-client-gateway-onlink-implicit.network',
3259 'dhcp-client-ipv4-dhcp-settings.network',
3260 'dhcp-client-ipv4-only-ipv6-disabled.network',
3261 'dhcp-client-ipv4-only.network',
3262 'dhcp-client-ipv4-use-routes-use-gateway.network',
3263 'dhcp-client-ipv6-only.network',
3264 'dhcp-client-ipv6-rapid-commit.network',
3265 'dhcp-client-keep-configuration-dhcp-on-stop.network',
3266 'dhcp-client-keep-configuration-dhcp.network',
3267 'dhcp-client-listen-port.network',
3268 'dhcp-client-reassign-static-routes-ipv4.network',
3269 'dhcp-client-reassign-static-routes-ipv6.network',
3270 'dhcp-client-route-metric.network',
3271 'dhcp-client-route-table.network',
3272 'dhcp-client-use-dns-ipv4-and-ra.network',
3273 'dhcp-client-use-dns-ipv4.network',
3274 'dhcp-client-use-dns-no.network',
3275 'dhcp-client-use-dns-yes.network',
3276 'dhcp-client-use-domains.network',
3277 'dhcp-client-vrf.network',
3278 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
3279 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
3280 'dhcp-client-with-static-address.network',
3281 'dhcp-client.network',
3282 'dhcp-server-decline.network',
3283 'dhcp-server-veth-peer.network',
3284 'dhcp-v4-server-veth-peer.network',
3288 stop_dnsmasq(dnsmasq_pid_file
)
3289 remove_links(self
.links
)
3290 stop_networkd(show_logs
=False)
3293 stop_dnsmasq(dnsmasq_pid_file
)
3296 remove_links(self
.links
)
3297 remove_unit_from_networkd_path(self
.units
)
3298 stop_networkd(show_logs
=True)
3300 def test_dhcp_client_ipv6_only(self
):
3301 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3304 self
.wait_online(['veth-peer:carrier'])
3306 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3308 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3310 self
.assertRegex(output
, '2600::')
3311 self
.assertNotRegex(output
, '192.168.5')
3313 output
= check_output('ip addr show dev veth99')
3315 self
.assertRegex(output
, '2600::')
3316 self
.assertNotRegex(output
, '192.168.5')
3317 self
.assertNotRegex(output
, 'tentative')
3319 # Confirm that ipv6 token is not set in the kernel
3320 output
= check_output('ip token show dev veth99')
3322 self
.assertRegex(output
, 'token :: dev veth99')
3324 def test_dhcp_client_ipv4_only(self
):
3325 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
3328 self
.wait_online(['veth-peer:carrier'])
3329 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
3330 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3332 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3334 self
.assertNotRegex(output
, '2600::')
3335 self
.assertRegex(output
, '192.168.5')
3336 self
.assertRegex(output
, '192.168.5.6')
3337 self
.assertRegex(output
, '192.168.5.7')
3339 # checking routes to DNS servers
3340 output
= check_output('ip route show dev veth99')
3342 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3343 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3344 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3346 stop_dnsmasq(dnsmasq_pid_file
)
3347 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8', lease_time
='2m')
3349 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3350 print('Wait for the dynamic address to be renewed')
3353 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3355 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3357 self
.assertNotRegex(output
, '2600::')
3358 self
.assertRegex(output
, '192.168.5')
3359 self
.assertNotRegex(output
, '192.168.5.6')
3360 self
.assertRegex(output
, '192.168.5.7')
3361 self
.assertRegex(output
, '192.168.5.8')
3363 # checking routes to DNS servers
3364 output
= check_output('ip route show dev veth99')
3366 self
.assertNotRegex(output
, r
'192.168.5.6')
3367 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3368 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3369 self
.assertRegex(output
, r
'192.168.5.8 proto dhcp scope link src 192.168.5.181 metric 1024')
3371 def test_dhcp_client_ipv4_use_routes_gateway(self
):
3372 for (routes
, gateway
, dnsroutes
) in itertools
.product([True, False, None], repeat
=3):
3374 with self
.subTest(routes
=routes
, gateway
=gateway
, dnsroutes
=dnsroutes
):
3375 self
._test
_dhcp
_client
_ipv
4_use
_routes
_gateway
(routes
, gateway
, dnsroutes
)
3378 def _test_dhcp_client_ipv4_use_routes_gateway(self
, routes
, gateway
, dnsroutes
):
3379 testunit
= 'dhcp-client-ipv4-use-routes-use-gateway.network'
3380 testunits
= ['25-veth.netdev', 'dhcp-server-veth-peer.network', testunit
]
3382 testunits
.append(f
'{testunit}.d/use-routes-{routes}.conf');
3384 testunits
.append(f
'{testunit}.d/use-gateway-{gateway}.conf');
3385 if dnsroutes
!= None:
3386 testunits
.append(f
'{testunit}.d/use-dns-routes-{dnsroutes}.conf');
3387 copy_unit_to_networkd_unit_path(*testunits
, dropins
=False)
3390 self
.wait_online(['veth-peer:carrier'])
3391 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
3392 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3394 output
= check_output('ip route show dev veth99')
3397 # UseRoutes= defaults to true
3398 useroutes
= routes
in [True, None]
3399 # UseGateway= defaults to useroutes
3400 usegateway
= useroutes
if gateway
== None else gateway
3404 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.181 metric 1024')
3406 self
.assertNotRegex(output
, r
'192.168.5.5')
3410 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.181 metric 1024')
3412 self
.assertNotRegex(output
, r
'default via 192.168.5.1')
3414 # Check RoutesToDNS=, which defaults to false
3416 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3417 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3419 self
.assertNotRegex(output
, r
'192.168.5.6')
3420 self
.assertNotRegex(output
, r
'192.168.5.7')
3422 def test_dhcp_client_ipv4_ipv6(self
):
3423 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
3424 'dhcp-client-ipv4-only.network')
3426 self
.wait_online(['veth-peer:carrier'])
3428 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3430 # link become 'routable' when at least one protocol provide an valid address.
3431 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3432 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3434 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3436 self
.assertRegex(output
, '2600::')
3437 self
.assertRegex(output
, '192.168.5')
3439 def test_dhcp_client_settings(self
):
3440 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
3443 self
.wait_online(['veth-peer:carrier'])
3445 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3447 print('## ip address show dev veth99')
3448 output
= check_output('ip address show dev veth99')
3450 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3451 self
.assertRegex(output
, '192.168.5')
3452 self
.assertRegex(output
, '1492')
3454 print('## ip route show table main dev veth99')
3455 output
= check_output('ip route show table main dev veth99')
3458 main_table_is_empty
= output
== ''
3459 if not main_table_is_empty
:
3460 self
.assertNotRegex(output
, 'proto dhcp')
3462 print('## ip route show table 211 dev veth99')
3463 output
= check_output('ip route show table 211 dev veth99')
3465 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
3466 if main_table_is_empty
:
3467 self
.assertRegex(output
, '192.168.5.0/24 proto dhcp')
3468 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
3469 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
3471 print('## dnsmasq log')
3472 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
3473 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
3474 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
3475 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
3477 def test_dhcp6_client_settings_rapidcommit_true(self
):
3478 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3480 self
.wait_online(['veth-peer:carrier'])
3482 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3484 output
= check_output('ip address show dev veth99')
3486 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3487 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
3489 def test_dhcp6_client_settings_rapidcommit_false(self
):
3490 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
3492 self
.wait_online(['veth-peer:carrier'])
3494 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3496 output
= check_output('ip address show dev veth99')
3498 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3499 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
3501 def test_dhcp_client_settings_anonymize(self
):
3502 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
3504 self
.wait_online(['veth-peer:carrier'])
3506 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3508 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
3509 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
3510 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
3512 def test_dhcp_client_listen_port(self
):
3513 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
3515 self
.wait_online(['veth-peer:carrier'])
3516 start_dnsmasq('--dhcp-alternate-port=67,5555')
3517 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3519 output
= check_output('ip -4 address show dev veth99')
3521 self
.assertRegex(output
, '192.168.5.* dynamic')
3523 def test_dhcp_client_with_static_address(self
):
3524 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
3525 'dhcp-client-with-static-address.network')
3527 self
.wait_online(['veth-peer:carrier'])
3529 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3531 output
= check_output('ip address show dev veth99 scope global')
3533 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
3534 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
3536 output
= check_output('ip route show dev veth99')
3538 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
3539 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
3540 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
3541 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
3543 def test_dhcp_route_table_id(self
):
3544 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
3546 self
.wait_online(['veth-peer:carrier'])
3548 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3550 output
= check_output('ip route show table 12')
3552 self
.assertRegex(output
, 'veth99 proto dhcp')
3553 self
.assertRegex(output
, '192.168.5.1')
3555 def test_dhcp_route_metric(self
):
3556 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
3558 self
.wait_online(['veth-peer:carrier'])
3560 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3562 output
= check_output('ip route show dev veth99')
3564 self
.assertRegex(output
, 'metric 24')
3566 def test_dhcp_client_reassign_static_routes_ipv4(self
):
3567 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3568 'dhcp-client-reassign-static-routes-ipv4.network')
3570 self
.wait_online(['veth-peer:carrier'])
3571 start_dnsmasq(lease_time
='2m')
3572 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3574 output
= check_output('ip address show dev veth99 scope global')
3576 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3578 output
= check_output('ip route show dev veth99')
3580 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3581 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3582 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3583 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3585 stop_dnsmasq(dnsmasq_pid_file
)
3586 start_dnsmasq(ipv4_range
='192.168.5.210,192.168.5.220', lease_time
='2m')
3588 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3589 print('Wait for the dynamic address to be renewed')
3592 self
.wait_online(['veth99:routable'])
3594 output
= check_output('ip route show dev veth99')
3596 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3597 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3598 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3599 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3601 def test_dhcp_client_reassign_static_routes_ipv6(self
):
3602 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3603 'dhcp-client-reassign-static-routes-ipv6.network')
3605 self
.wait_online(['veth-peer:carrier'])
3606 start_dnsmasq(lease_time
='2m')
3607 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3609 output
= check_output('ip address show dev veth99 scope global')
3611 self
.assertRegex(output
, r
'inet6 2600::[0-9a-f]*/128 scope global (noprefixroute dynamic|dynamic noprefixroute)')
3613 output
= check_output('ip -6 route show dev veth99')
3615 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3616 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3618 stop_dnsmasq(dnsmasq_pid_file
)
3619 start_dnsmasq(ipv6_range
='2600::30,2600::40', lease_time
='2m')
3621 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3622 print('Wait for the dynamic address to be renewed')
3625 self
.wait_online(['veth99:routable'])
3627 output
= check_output('ip -6 route show dev veth99')
3629 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3630 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3632 def test_dhcp_keep_configuration_dhcp(self
):
3633 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
3635 self
.wait_online(['veth-peer:carrier'])
3636 start_dnsmasq(lease_time
='2m')
3637 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3639 output
= check_output('ip address show dev veth99 scope global')
3641 self
.assertRegex(output
, r
'192.168.5.*')
3643 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3645 self
.assertRegex(output
, r
'192.168.5.*')
3647 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
3648 stop_dnsmasq(dnsmasq_pid_file
)
3650 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3651 print('Wait for the dynamic address to be expired')
3654 print('The lease address should be kept after lease expired')
3655 output
= check_output('ip address show dev veth99 scope global')
3657 self
.assertRegex(output
, r
'192.168.5.*')
3659 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3661 self
.assertRegex(output
, r
'192.168.5.*')
3663 check_output('systemctl stop systemd-networkd.socket')
3664 check_output('systemctl stop systemd-networkd.service')
3666 print('The lease address should be kept after networkd stopped')
3667 output
= check_output('ip address show dev veth99 scope global')
3669 self
.assertRegex(output
, r
'192.168.5.*')
3671 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3673 self
.assertRegex(output
, r
'192.168.5.*')
3676 self
.wait_online(['veth-peer:routable'])
3678 print('Still the lease address should be kept after networkd restarted')
3679 output
= check_output('ip address show dev veth99 scope global')
3681 self
.assertRegex(output
, r
'192.168.5.*')
3683 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3685 self
.assertRegex(output
, r
'192.168.5.*')
3687 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
3688 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
3690 self
.wait_online(['veth-peer:carrier'])
3691 start_dnsmasq(lease_time
='2m')
3692 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3694 output
= check_output('ip address show dev veth99 scope global')
3696 self
.assertRegex(output
, r
'192.168.5.*')
3698 stop_dnsmasq(dnsmasq_pid_file
)
3699 check_output('systemctl stop systemd-networkd.socket')
3700 check_output('systemctl stop systemd-networkd.service')
3702 output
= check_output('ip address show dev veth99 scope global')
3704 self
.assertRegex(output
, r
'192.168.5.*')
3707 self
.wait_online(['veth-peer:routable'])
3709 output
= check_output('ip address show dev veth99 scope global')
3711 self
.assertNotRegex(output
, r
'192.168.5.*')
3713 def test_dhcp_client_reuse_address_as_static(self
):
3714 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
3716 self
.wait_online(['veth-peer:carrier'])
3718 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3720 # link become 'routable' when at least one protocol provide an valid address.
3721 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3722 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3724 output
= check_output('ip address show dev veth99 scope global')
3726 self
.assertRegex(output
, '192.168.5')
3727 self
.assertRegex(output
, '2600::')
3729 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
3730 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
3731 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
3732 print(static_network
)
3734 remove_unit_from_networkd_path(['dhcp-client.network'])
3736 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
3737 f
.write(static_network
)
3739 # When networkd started, the links are already configured, so let's wait for 5 seconds
3740 # the links to be re-configured.
3742 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3744 output
= check_output('ip -4 address show dev veth99 scope global')
3746 self
.assertRegex(output
, '192.168.5')
3747 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3749 output
= check_output('ip -6 address show dev veth99 scope global')
3751 self
.assertRegex(output
, '2600::')
3752 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3754 @expectedFailureIfModuleIsNotAvailable('vrf')
3755 def test_dhcp_client_vrf(self
):
3756 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
3757 '25-vrf.netdev', '25-vrf.network')
3759 self
.wait_online(['veth-peer:carrier'])
3761 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
3763 # link become 'routable' when at least one protocol provide an valid address.
3764 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3765 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3767 print('## ip -d link show dev vrf99')
3768 output
= check_output('ip -d link show dev vrf99')
3770 self
.assertRegex(output
, 'vrf table 42')
3772 print('## ip address show vrf vrf99')
3773 output
= check_output('ip address show vrf vrf99')
3775 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3776 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3777 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3778 self
.assertRegex(output
, 'inet6 .* scope link')
3780 print('## ip address show dev veth99')
3781 output
= check_output('ip address show dev veth99')
3783 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3784 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3785 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3786 self
.assertRegex(output
, 'inet6 .* scope link')
3788 print('## ip route show vrf vrf99')
3789 output
= check_output('ip route show vrf vrf99')
3791 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
3792 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
3793 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
3794 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
3795 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
3797 print('## ip route show table main dev veth99')
3798 output
= check_output('ip route show table main dev veth99')
3800 self
.assertEqual(output
, '')
3802 def test_dhcp_client_gateway_ipv4(self
):
3803 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3804 'dhcp-client-gateway-ipv4.network')
3806 self
.wait_online(['veth-peer:carrier'])
3808 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3810 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3812 self
.assertRegex(output
, '10.0.0.0/8 via 192.168.5.1 proto static')
3814 def test_dhcp_client_gateway_ipv6(self
):
3815 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3816 'dhcp-client-gateway-ipv6.network')
3818 self
.wait_online(['veth-peer:carrier'])
3820 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3822 output
= check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
3824 self
.assertRegex(output
, 'via fe80::1034:56ff:fe78:9abd')
3826 def test_dhcp_client_gateway_onlink_implicit(self
):
3827 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3828 'dhcp-client-gateway-onlink-implicit.network')
3830 self
.wait_online(['veth-peer:carrier'])
3832 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3834 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3836 self
.assertRegex(output
, '192.168.5')
3838 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3840 self
.assertRegex(output
, 'onlink')
3841 output
= check_output('ip route list dev veth99 192.168.100.0/24')
3843 self
.assertRegex(output
, 'onlink')
3845 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
3846 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3847 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
3849 self
.wait_online(['veth-peer:carrier'])
3850 start_dnsmasq(lease_time
='2m')
3851 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3853 output
= check_output('ip address show dev veth99')
3856 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3857 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3858 output
= check_output('ip -6 address show dev veth99 scope link')
3859 self
.assertRegex(output
, 'inet6 .* scope link')
3860 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3861 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3862 output
= check_output('ip -4 address show dev veth99 scope link')
3863 self
.assertNotRegex(output
, 'inet .* scope link')
3865 print('Wait for the dynamic address to be expired')
3868 output
= check_output('ip address show dev veth99')
3871 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3872 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3873 output
= check_output('ip -6 address show dev veth99 scope link')
3874 self
.assertRegex(output
, 'inet6 .* scope link')
3875 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3876 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3877 output
= check_output('ip -4 address show dev veth99 scope link')
3878 self
.assertNotRegex(output
, 'inet .* scope link')
3880 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
3882 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
3883 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3884 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
3886 self
.wait_online(['veth99:degraded', 'veth-peer:routable'])
3888 output
= check_output('ip address show dev veth99')
3891 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3892 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3893 output
= check_output('ip -6 address show dev veth99 scope link')
3894 self
.assertRegex(output
, 'inet6 .* scope link')
3895 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3896 self
.assertNotRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3897 output
= check_output('ip -4 address show dev veth99 scope link')
3898 self
.assertRegex(output
, 'inet .* scope link')
3900 def test_dhcp_client_route_remove_on_renew(self
):
3901 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3902 'dhcp-client-ipv4-only-ipv6-disabled.network')
3904 self
.wait_online(['veth-peer:carrier'])
3905 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
3906 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3908 # test for issue #12490
3910 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3912 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3914 for line
in output
.splitlines():
3915 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3916 address1
= line
.split()[1].split('/')[0]
3919 output
= check_output('ip -4 route show dev veth99')
3921 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3922 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3924 stop_dnsmasq(dnsmasq_pid_file
)
3925 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
3927 print('Wait for the dynamic address to be expired')
3930 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3932 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3934 for line
in output
.splitlines():
3935 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3936 address2
= line
.split()[1].split('/')[0]
3939 self
.assertNotEqual(address1
, address2
)
3941 output
= check_output('ip -4 route show dev veth99')
3943 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3944 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3945 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
3946 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
3948 def test_dhcp_client_use_dns_yes(self
):
3949 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-yes.network')
3952 self
.wait_online(['veth-peer:carrier'])
3953 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3954 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3956 # link become 'routable' when at least one protocol provide an valid address.
3957 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3958 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3961 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3963 self
.assertRegex(output
, '192.168.5.1')
3964 self
.assertRegex(output
, '2600::1')
3966 def test_dhcp_client_use_dns_no(self
):
3967 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-no.network')
3970 self
.wait_online(['veth-peer:carrier'])
3971 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3972 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3974 # link become 'routable' when at least one protocol provide an valid address.
3975 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3976 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3979 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3981 self
.assertNotRegex(output
, '192.168.5.1')
3982 self
.assertNotRegex(output
, '2600::1')
3984 def test_dhcp_client_use_dns_ipv4(self
):
3985 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4.network')
3988 self
.wait_online(['veth-peer:carrier'])
3989 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3990 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3992 # link become 'routable' when at least one protocol provide an valid address.
3993 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3994 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3997 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3999 self
.assertRegex(output
, '192.168.5.1')
4000 self
.assertNotRegex(output
, '2600::1')
4002 def test_dhcp_client_use_dns_ipv4_and_ra(self
):
4003 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4-and-ra.network')
4006 self
.wait_online(['veth-peer:carrier'])
4007 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
4008 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4010 # link become 'routable' when at least one protocol provide an valid address.
4011 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4012 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4015 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
4017 self
.assertRegex(output
, '192.168.5.1')
4018 self
.assertRegex(output
, '2600::1')
4020 def test_dhcp_client_use_domains(self
):
4021 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-domains.network')
4024 self
.wait_online(['veth-peer:carrier'])
4025 start_dnsmasq('--dhcp-option=option:domain-search,example.com')
4026 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4028 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4030 self
.assertRegex(output
, 'Search Domains: example.com')
4033 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
4035 self
.assertRegex(output
, 'example.com')
4037 def test_dhcp_client_decline(self
):
4038 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-decline.network', 'dhcp-client-decline.network')
4041 self
.wait_online(['veth-peer:carrier'])
4042 rc
= call(*wait_online_cmd
, '--timeout=10s', '--interface=veth99:routable', env
=env
)
4043 self
.assertTrue(rc
== 1)
4045 class NetworkdIPv6PrefixTests(unittest
.TestCase
, Utilities
):
4050 'ipv6ra-prefix-client.network',
4051 'ipv6ra-prefix.network'
4055 remove_links(self
.links
)
4056 stop_networkd(show_logs
=False)
4060 remove_links(self
.links
)
4061 remove_unit_from_networkd_path(self
.units
)
4062 stop_networkd(show_logs
=True)
4064 def test_ipv6_route_prefix(self
):
4065 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client.network', 'ipv6ra-prefix.network')
4068 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4070 output
= check_output('ip -6 route show dev veth-peer')
4072 self
.assertRegex(output
, '2001:db8:0:1::/64 proto ra')
4074 output
= check_output('ip addr show dev veth99')
4076 self
.assertNotRegex(output
, '2001:db8:0:1')
4077 self
.assertRegex(output
, '2001:db8:0:2')
4079 class NetworkdMTUTests(unittest
.TestCase
, Utilities
):
4084 '12-dummy-mtu.netdev',
4085 '12-dummy-mtu.link',
4090 remove_links(self
.links
)
4091 stop_networkd(show_logs
=False)
4095 remove_links(self
.links
)
4096 remove_unit_from_networkd_path(self
.units
)
4097 stop_networkd(show_logs
=True)
4099 def check_mtu(self
, mtu
, ipv6_mtu
=None, reset
=True):
4105 self
.wait_online(['dummy98:routable'])
4106 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
4107 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
4109 # test normal restart
4111 self
.wait_online(['dummy98:routable'])
4112 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
4113 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
4116 self
.reset_check_mtu(mtu
, ipv6_mtu
)
4118 def reset_check_mtu(self
, mtu
, ipv6_mtu
=None):
4119 ''' test setting mtu/ipv6_mtu with interface already up '''
4122 # note - changing the device mtu resets the ipv6 mtu
4123 run('ip link set up mtu 1501 dev dummy98')
4124 run('ip link set up mtu 1500 dev dummy98')
4125 self
.assertEqual(read_link_attr('dummy98', 'mtu'), '1500')
4126 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), '1500')
4128 self
.check_mtu(mtu
, ipv6_mtu
, reset
=False)
4130 def test_mtu_network(self
):
4131 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
4132 self
.check_mtu('1600')
4134 def test_mtu_netdev(self
):
4135 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network', dropins
=False)
4136 # note - MTU set by .netdev happens ONLY at device creation!
4137 self
.check_mtu('1600', reset
=False)
4139 def test_mtu_link(self
):
4140 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', dropins
=False)
4141 # must reload udev because it only picks up new files after 3 second delay
4142 call('udevadm control --reload')
4143 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
4144 self
.check_mtu('1600', reset
=False)
4146 def test_ipv6_mtu(self
):
4147 ''' set ipv6 mtu without setting device mtu '''
4148 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
4149 self
.check_mtu('1500', '1400')
4151 def test_ipv6_mtu_toolarge(self
):
4152 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
4153 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
4154 self
.check_mtu('1500', '1500')
4156 def test_mtu_network_ipv6_mtu(self
):
4157 ''' set ipv6 mtu and set device mtu via network file '''
4158 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
4159 self
.check_mtu('1600', '1550')
4161 def test_mtu_netdev_ipv6_mtu(self
):
4162 ''' set ipv6 mtu and set device mtu via netdev file '''
4163 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
4164 self
.check_mtu('1600', '1550', reset
=False)
4166 def test_mtu_link_ipv6_mtu(self
):
4167 ''' set ipv6 mtu and set device mtu via link file '''
4168 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
4169 # must reload udev because it only picks up new files after 3 second delay
4170 call('udevadm control --reload')
4171 self
.check_mtu('1600', '1550', reset
=False)
4174 if __name__
== '__main__':
4175 parser
= argparse
.ArgumentParser()
4176 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
4177 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
4178 parser
.add_argument('--resolved', help='Path to systemd-resolved', dest
='resolved_bin')
4179 parser
.add_argument('--udevd', help='Path to systemd-udevd', dest
='udevd_bin')
4180 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
4181 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
4182 parser
.add_argument('--resolvectl', help='Path to resolvectl', dest
='resolvectl_bin')
4183 parser
.add_argument('--timedatectl', help='Path to timedatectl', dest
='timedatectl_bin')
4184 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
4185 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
4186 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
4187 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
4188 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
4189 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
4192 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
:
4193 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
4194 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
4195 resolved_bin
= os
.path
.join(ns
.build_dir
, 'systemd-resolved')
4196 udevd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-udevd')
4197 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
4198 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
4199 resolvectl_bin
= os
.path
.join(ns
.build_dir
, 'resolvectl')
4200 timedatectl_bin
= os
.path
.join(ns
.build_dir
, 'timedatectl')
4203 networkd_bin
= ns
.networkd_bin
4205 resolved_bin
= ns
.resolved_bin
4207 udevd_bin
= ns
.udevd_bin
4208 if ns
.wait_online_bin
:
4209 wait_online_bin
= ns
.wait_online_bin
4210 if ns
.networkctl_bin
:
4211 networkctl_bin
= ns
.networkctl_bin
4212 if ns
.resolvectl_bin
:
4213 resolvectl_bin
= ns
.resolvectl_bin
4214 if ns
.timedatectl_bin
:
4215 timedatectl_bin
= ns
.timedatectl_bin
4217 use_valgrind
= ns
.use_valgrind
4218 enable_debug
= ns
.enable_debug
4219 asan_options
= ns
.asan_options
4220 lsan_options
= ns
.lsan_options
4221 ubsan_options
= ns
.ubsan_options
4224 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
4225 resolvectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin
]
4226 timedatectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin
]
4227 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
4229 networkctl_cmd
= [networkctl_bin
]
4230 resolvectl_cmd
= [resolvectl_bin
]
4231 timedatectl_cmd
= [timedatectl_bin
]
4232 wait_online_cmd
= [wait_online_bin
]
4235 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
4237 env
.update({ 'ASAN_OPTIONS' : asan_options
})
4239 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
4241 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
4244 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,