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
= [
795 '10-dropin-test.netdev',
799 '13-not-match-udev-property.network',
800 '14-match-udev-property.network',
801 '15-name-conflict-test.netdev',
804 '21-vlan-test1.network',
807 '25-6rd-tunnel.netdev',
809 '25-bond-balanced-tlb.netdev',
811 '25-bridge-configure-without-carrier.network',
813 '25-erspan-tunnel-local-any.netdev',
814 '25-erspan-tunnel.netdev',
815 '25-fou-gretap.netdev',
817 '25-fou-ipip.netdev',
818 '25-fou-ipproto-gre.netdev',
819 '25-fou-ipproto-ipip.netdev',
822 '25-gretap-tunnel-local-any.netdev',
823 '25-gretap-tunnel.netdev',
824 '25-gre-tunnel-any-any.netdev',
825 '25-gre-tunnel-local-any.netdev',
826 '25-gre-tunnel-remote-any.netdev',
827 '25-gre-tunnel.netdev',
829 '25-ip6gretap-tunnel-local-any.netdev',
830 '25-ip6gretap-tunnel.netdev',
831 '25-ip6gre-tunnel-any-any.netdev',
832 '25-ip6gre-tunnel-local-any.netdev',
833 '25-ip6gre-tunnel-remote-any.netdev',
834 '25-ip6gre-tunnel.netdev',
835 '25-ip6tnl-tunnel-any-any.netdev',
836 '25-ip6tnl-tunnel-local-any.netdev',
837 '25-ip6tnl-tunnel-remote-any.netdev',
838 '25-ip6tnl-tunnel.netdev',
839 '25-ipip-tunnel-any-any.netdev',
840 '25-ipip-tunnel-independent.netdev',
841 '25-ipip-tunnel-independent-loopback.netdev',
842 '25-ipip-tunnel-local-any.netdev',
843 '25-ipip-tunnel-remote-any.netdev',
844 '25-ipip-tunnel.netdev',
847 '25-isatap-tunnel.netdev',
852 '25-sit-tunnel-any-any.netdev',
853 '25-sit-tunnel-local-any.netdev',
854 '25-sit-tunnel-remote-any.netdev',
855 '25-sit-tunnel.netdev',
858 '25-tunnel-local-any.network',
859 '25-tunnel-remote-any.network',
864 '25-vti6-tunnel-any-any.netdev',
865 '25-vti6-tunnel-local-any.netdev',
866 '25-vti6-tunnel-remote-any.netdev',
867 '25-vti6-tunnel.netdev',
868 '25-vti-tunnel-any-any.netdev',
869 '25-vti-tunnel-local-any.netdev',
870 '25-vti-tunnel-remote-any.netdev',
871 '25-vti-tunnel.netdev',
874 '25-wireguard-23-peers.netdev',
875 '25-wireguard-23-peers.network',
876 '25-wireguard-no-peer.netdev',
877 '25-wireguard-no-peer.network',
878 '25-wireguard-preshared-key.txt',
879 '25-wireguard-private-key.txt',
880 '25-wireguard.netdev',
881 '25-wireguard.network',
883 '25-xfrm-independent.netdev',
899 'netdev-link-local-addressing-yes.network',
903 'vxlan-test1.network',
913 remove_fou_ports(self
.fou_ports
)
914 remove_links(self
.links_remove_earlier
)
915 remove_links(self
.links
)
916 stop_networkd(show_logs
=False)
919 remove_fou_ports(self
.fou_ports
)
920 remove_links(self
.links_remove_earlier
)
921 remove_links(self
.links
)
922 remove_unit_from_networkd_path(self
.units
)
923 stop_networkd(show_logs
=True)
925 def test_dropin_and_name_conflict(self
):
926 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
929 self
.wait_online(['dropin-test:off'], setup_state
='unmanaged')
931 output
= check_output('ip link show dropin-test')
933 self
.assertRegex(output
, '00:50:56:c0:00:28')
935 def test_match_udev_property(self
):
936 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
938 self
.wait_online(['dummy98:routable'])
940 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
942 self
.assertRegex(output
, 'Network File: /run/systemd/network/14-match-udev-property')
944 def test_wait_online_any(self
):
945 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
948 self
.wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
950 self
.wait_operstate('bridge99', '(off|no-carrier)', setup_state
='configuring')
951 self
.wait_operstate('test1', 'degraded')
953 def test_bridge(self
):
954 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
957 self
.wait_online(['bridge99:no-carrier'])
959 tick
= os
.sysconf('SC_CLK_TCK')
960 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
961 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
962 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'forward_delay')) / tick
))
963 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'ageing_time')) / tick
))
964 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge', 'priority')))
965 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_querier')))
966 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_snooping')))
967 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'stp_state')))
968 self
.assertEqual(3, int(read_link_attr('bridge99', 'bridge', 'multicast_igmp_version')))
970 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
972 self
.assertRegex(output
, 'Priority: 9')
973 self
.assertRegex(output
, 'STP: yes')
974 self
.assertRegex(output
, 'Multicast IGMP Version: 3')
977 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
980 self
.wait_online(['bond99:off', 'bond98:off'], setup_state
='unmanaged')
982 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
983 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
984 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
985 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
986 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
987 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
988 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
989 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
990 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
991 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
992 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
994 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
995 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
998 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
999 '21-vlan.network', '21-vlan-test1.network')
1002 self
.wait_online(['test1:degraded', 'vlan99:routable'])
1004 output
= check_output('ip -d link show test1')
1006 self
.assertRegex(output
, ' mtu 2000 ')
1008 output
= check_output('ip -d link show vlan99')
1010 self
.assertRegex(output
, ' mtu 2000 ')
1011 self
.assertRegex(output
, 'REORDER_HDR')
1012 self
.assertRegex(output
, 'LOOSE_BINDING')
1013 self
.assertRegex(output
, 'GVRP')
1014 self
.assertRegex(output
, 'MVRP')
1015 self
.assertRegex(output
, ' id 99 ')
1017 output
= check_output('ip -4 address show dev test1')
1019 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
1020 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
1022 output
= check_output('ip -4 address show dev vlan99')
1024 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
1026 def test_macvtap(self
):
1027 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
1028 with self
.subTest(mode
=mode
):
1029 if mode
!= 'private':
1031 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
1032 '11-dummy.netdev', 'macvtap.network')
1033 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
1034 f
.write('[MACVTAP]\nMode=' + mode
)
1037 self
.wait_online(['macvtap99:degraded', 'test1:degraded'])
1039 output
= check_output('ip -d link show macvtap99')
1041 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
1043 def test_macvlan(self
):
1044 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
1045 with self
.subTest(mode
=mode
):
1046 if mode
!= 'private':
1048 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
1049 '11-dummy.netdev', 'macvlan.network')
1050 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
1051 f
.write('[MACVLAN]\nMode=' + mode
)
1054 self
.wait_online(['macvlan99:degraded', 'test1:degraded'])
1056 output
= check_output('ip -d link show test1')
1058 self
.assertRegex(output
, ' mtu 2000 ')
1060 output
= check_output('ip -d link show macvlan99')
1062 self
.assertRegex(output
, ' mtu 2000 ')
1063 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
1065 @expectedFailureIfModuleIsNotAvailable('ipvlan')
1066 def test_ipvlan(self
):
1067 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1068 with self
.subTest(mode
=mode
, flag
=flag
):
1071 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
1072 '11-dummy.netdev', 'ipvlan.network')
1073 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
1074 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
1077 self
.wait_online(['ipvlan99:degraded', 'test1:degraded'])
1079 output
= check_output('ip -d link show ipvlan99')
1081 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
1083 @expectedFailureIfModuleIsNotAvailable('ipvtap')
1084 def test_ipvtap(self
):
1085 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1086 with self
.subTest(mode
=mode
, flag
=flag
):
1089 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
1090 '11-dummy.netdev', 'ipvtap.network')
1091 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
1092 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
1095 self
.wait_online(['ipvtap99:degraded', 'test1:degraded'])
1097 output
= check_output('ip -d link show ipvtap99')
1099 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
1101 def test_veth(self
):
1102 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
1105 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
1107 output
= check_output('ip -d link show veth99')
1109 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
1110 output
= check_output('ip -d link show veth-peer')
1112 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
1115 copy_unit_to_networkd_unit_path('25-tun.netdev')
1118 self
.wait_online(['tun99:off'], setup_state
='unmanaged')
1120 output
= check_output('ip -d link show tun99')
1122 # Old ip command does not support IFF_ flags
1123 self
.assertRegex(output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
1126 copy_unit_to_networkd_unit_path('25-tap.netdev')
1129 self
.wait_online(['tap99:off'], setup_state
='unmanaged')
1131 output
= check_output('ip -d link show tap99')
1133 # Old ip command does not support IFF_ flags
1134 self
.assertRegex(output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
1136 @expectedFailureIfModuleIsNotAvailable('vrf')
1138 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
1141 self
.wait_online(['vrf99:carrier'])
1143 @expectedFailureIfModuleIsNotAvailable('vcan')
1144 def test_vcan(self
):
1145 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
1148 self
.wait_online(['vcan99:carrier'])
1150 @expectedFailureIfModuleIsNotAvailable('vxcan')
1151 def test_vxcan(self
):
1152 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
1155 self
.wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
1157 @expectedFailureIfModuleIsNotAvailable('wireguard')
1158 def test_wireguard(self
):
1159 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
1160 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
1161 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt',
1162 '25-wireguard-no-peer.netdev', '25-wireguard-no-peer.network')
1164 self
.wait_online(['wg99:carrier', 'wg98:routable', 'wg97:carrier'])
1166 if shutil
.which('wg'):
1169 output
= check_output('wg show wg99 listen-port')
1170 self
.assertRegex(output
, '51820')
1171 output
= check_output('wg show wg99 fwmark')
1172 self
.assertRegex(output
, '0x4d2')
1173 output
= check_output('wg show wg99 allowed-ips')
1174 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
1175 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
1176 output
= check_output('wg show wg99 persistent-keepalive')
1177 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
1178 output
= check_output('wg show wg99 endpoints')
1179 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
1180 output
= check_output('wg show wg99 private-key')
1181 self
.assertRegex(output
, r
'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
1182 output
= check_output('wg show wg99 preshared-keys')
1183 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
1184 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
1186 output
= check_output('wg show wg98 private-key')
1187 self
.assertRegex(output
, r
'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
1189 output
= check_output('wg show wg97 listen-port')
1190 self
.assertRegex(output
, '51821')
1191 output
= check_output('wg show wg97 fwmark')
1192 self
.assertRegex(output
, '0x4d3')
1194 def test_geneve(self
):
1195 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
1198 self
.wait_online(['geneve99:degraded'])
1200 output
= check_output('ip -d link show geneve99')
1202 self
.assertRegex(output
, '192.168.22.1')
1203 self
.assertRegex(output
, '6082')
1204 self
.assertRegex(output
, 'udpcsum')
1205 self
.assertRegex(output
, 'udp6zerocsumrx')
1207 def test_ipip_tunnel(self
):
1208 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
1209 '25-ipip-tunnel.netdev', '25-tunnel.network',
1210 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1211 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1212 '25-ipip-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1214 self
.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'ipiptun96:routable', 'dummy98:degraded'])
1216 output
= check_output('ip -d link show ipiptun99')
1218 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98')
1219 output
= check_output('ip -d link show ipiptun98')
1221 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98')
1222 output
= check_output('ip -d link show ipiptun97')
1224 self
.assertRegex(output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98')
1225 output
= check_output('ip -d link show ipiptun96')
1227 self
.assertRegex(output
, 'ipip (ipip )?remote any local any dev dummy98')
1229 def test_gre_tunnel(self
):
1230 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
1231 '25-gre-tunnel.netdev', '25-tunnel.network',
1232 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1233 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1234 '25-gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1236 self
.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'gretun96:routable', 'dummy98:degraded'])
1238 output
= check_output('ip -d link show gretun99')
1240 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1241 self
.assertRegex(output
, 'ikey 1.2.3.103')
1242 self
.assertRegex(output
, 'okey 1.2.4.103')
1243 self
.assertRegex(output
, 'iseq')
1244 self
.assertRegex(output
, 'oseq')
1245 output
= check_output('ip -d link show gretun98')
1247 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
1248 self
.assertRegex(output
, 'ikey 0.0.0.104')
1249 self
.assertRegex(output
, 'okey 0.0.0.104')
1250 self
.assertNotRegex(output
, 'iseq')
1251 self
.assertNotRegex(output
, 'oseq')
1252 output
= check_output('ip -d link show gretun97')
1254 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
1255 self
.assertRegex(output
, 'ikey 0.0.0.105')
1256 self
.assertRegex(output
, 'okey 0.0.0.105')
1257 self
.assertNotRegex(output
, 'iseq')
1258 self
.assertNotRegex(output
, 'oseq')
1259 output
= check_output('ip -d link show gretun96')
1261 self
.assertRegex(output
, 'gre remote any local any dev dummy98')
1262 self
.assertRegex(output
, 'ikey 0.0.0.106')
1263 self
.assertRegex(output
, 'okey 0.0.0.106')
1264 self
.assertNotRegex(output
, 'iseq')
1265 self
.assertNotRegex(output
, 'oseq')
1267 def test_ip6gre_tunnel(self
):
1268 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
1269 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
1270 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1271 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1272 '25-ip6gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1275 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1277 self
.check_link_exists('dummy98')
1278 self
.check_link_exists('ip6gretun99')
1279 self
.check_link_exists('ip6gretun98')
1280 self
.check_link_exists('ip6gretun97')
1281 self
.check_link_exists('ip6gretun96')
1283 output
= check_output('ip -d link show ip6gretun99')
1285 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1286 output
= check_output('ip -d link show ip6gretun98')
1288 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
1289 output
= check_output('ip -d link show ip6gretun97')
1291 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
1292 output
= check_output('ip -d link show ip6gretun96')
1294 self
.assertRegex(output
, 'ip6gre remote any local any dev dummy98')
1296 def test_gretap_tunnel(self
):
1297 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
1298 '25-gretap-tunnel.netdev', '25-tunnel.network',
1299 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1301 self
.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
1303 output
= check_output('ip -d link show gretap99')
1305 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1306 self
.assertRegex(output
, 'ikey 0.0.0.106')
1307 self
.assertRegex(output
, 'okey 0.0.0.106')
1308 self
.assertRegex(output
, 'iseq')
1309 self
.assertRegex(output
, 'oseq')
1310 output
= check_output('ip -d link show gretap98')
1312 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
1313 self
.assertRegex(output
, 'ikey 0.0.0.107')
1314 self
.assertRegex(output
, 'okey 0.0.0.107')
1315 self
.assertRegex(output
, 'iseq')
1316 self
.assertRegex(output
, 'oseq')
1318 def test_ip6gretap_tunnel(self
):
1319 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
1320 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1321 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1323 self
.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
1325 output
= check_output('ip -d link show ip6gretap99')
1327 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1328 output
= check_output('ip -d link show ip6gretap98')
1330 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1332 def test_vti_tunnel(self
):
1333 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
1334 '25-vti-tunnel.netdev', '25-tunnel.network',
1335 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1336 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1337 '25-vti-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1339 self
.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'vtitun96:routable', 'dummy98:degraded'])
1341 output
= check_output('ip -d link show vtitun99')
1343 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1344 output
= check_output('ip -d link show vtitun98')
1346 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
1347 output
= check_output('ip -d link show vtitun97')
1349 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
1350 output
= check_output('ip -d link show vtitun96')
1352 self
.assertRegex(output
, 'vti remote any local any dev dummy98')
1354 def test_vti6_tunnel(self
):
1355 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
1356 '25-vti6-tunnel.netdev', '25-tunnel.network',
1357 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1358 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1360 self
.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
1362 output
= check_output('ip -d link show vti6tun99')
1364 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1365 output
= check_output('ip -d link show vti6tun98')
1367 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1368 output
= check_output('ip -d link show vti6tun97')
1370 self
.assertRegex(output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1372 def test_ip6tnl_tunnel(self
):
1373 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
1374 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1375 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1376 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1378 self
.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
1380 output
= check_output('ip -d link show ip6tnl99')
1382 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1383 output
= check_output('ip -d link show ip6tnl98')
1385 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1386 output
= check_output('ip -d link show ip6tnl97')
1388 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1390 def test_sit_tunnel(self
):
1391 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1392 '25-sit-tunnel.netdev', '25-tunnel.network',
1393 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1394 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1395 '25-sit-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1397 self
.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'sittun96:routable', 'dummy98:degraded'])
1399 output
= check_output('ip -d link show sittun99')
1401 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1402 output
= check_output('ip -d link show sittun98')
1404 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98")
1405 output
= check_output('ip -d link show sittun97')
1407 self
.assertRegex(output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98")
1408 output
= check_output('ip -d link show sittun96')
1410 self
.assertRegex(output
, "sit (ip6ip )?remote any local any dev dummy98")
1412 def test_isatap_tunnel(self
):
1413 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1414 '25-isatap-tunnel.netdev', '25-tunnel.network')
1416 self
.wait_online(['isataptun99:routable', 'dummy98:degraded'])
1418 output
= check_output('ip -d link show isataptun99')
1420 self
.assertRegex(output
, "isatap ")
1422 def test_6rd_tunnel(self
):
1423 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1424 '25-6rd-tunnel.netdev', '25-tunnel.network')
1426 self
.wait_online(['sittun99:routable', 'dummy98:degraded'])
1428 output
= check_output('ip -d link show sittun99')
1430 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1432 @expectedFailureIfERSPANModuleIsNotAvailable()
1433 def test_erspan_tunnel(self
):
1434 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1435 '25-erspan-tunnel.netdev', '25-tunnel.network',
1436 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1438 self
.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1440 output
= check_output('ip -d link show erspan99')
1442 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1443 self
.assertRegex(output
, 'ikey 0.0.0.101')
1444 self
.assertRegex(output
, 'okey 0.0.0.101')
1445 self
.assertRegex(output
, 'iseq')
1446 self
.assertRegex(output
, 'oseq')
1447 output
= check_output('ip -d link show erspan98')
1449 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1450 self
.assertRegex(output
, '102')
1451 self
.assertRegex(output
, 'ikey 0.0.0.102')
1452 self
.assertRegex(output
, 'okey 0.0.0.102')
1453 self
.assertRegex(output
, 'iseq')
1454 self
.assertRegex(output
, 'oseq')
1456 def test_tunnel_independent(self
):
1457 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1460 self
.wait_online(['ipiptun99:carrier'])
1462 def test_tunnel_independent_loopback(self
):
1463 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent-loopback.netdev', 'netdev-link-local-addressing-yes.network')
1466 self
.wait_online(['ipiptun99:carrier'])
1468 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1469 def test_xfrm(self
):
1470 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'xfrm.network',
1471 '25-xfrm.netdev', 'netdev-link-local-addressing-yes.network')
1474 self
.wait_online(['xfrm99:degraded', 'dummy98:degraded'])
1476 output
= check_output('ip link show dev xfrm99')
1479 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1480 def test_xfrm_independent(self
):
1481 copy_unit_to_networkd_unit_path('25-xfrm-independent.netdev', 'netdev-link-local-addressing-yes.network')
1484 self
.wait_online(['xfrm99:degraded'])
1486 @expectedFailureIfModuleIsNotAvailable('fou')
1488 # The following redundant check is necessary for CentOS CI.
1489 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1490 self
.assertTrue(is_module_available('fou'))
1492 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1493 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1494 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1497 self
.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'], setup_state
='unmanaged')
1499 output
= check_output('ip fou show')
1501 self
.assertRegex(output
, 'port 55555 ipproto 4')
1502 self
.assertRegex(output
, 'port 55556 ipproto 47')
1504 output
= check_output('ip -d link show ipiptun96')
1506 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1507 output
= check_output('ip -d link show sittun96')
1509 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1510 output
= check_output('ip -d link show gretun96')
1512 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1513 output
= check_output('ip -d link show gretap96')
1515 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1517 def test_vxlan(self
):
1518 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1519 '11-dummy.netdev', 'vxlan-test1.network')
1522 self
.wait_online(['test1:degraded', 'vxlan99:degraded'])
1524 output
= check_output('ip -d link show vxlan99')
1526 self
.assertRegex(output
, '999')
1527 self
.assertRegex(output
, '5555')
1528 self
.assertRegex(output
, 'l2miss')
1529 self
.assertRegex(output
, 'l3miss')
1530 self
.assertRegex(output
, 'udpcsum')
1531 self
.assertRegex(output
, 'udp6zerocsumtx')
1532 self
.assertRegex(output
, 'udp6zerocsumrx')
1533 self
.assertRegex(output
, 'remcsumtx')
1534 self
.assertRegex(output
, 'remcsumrx')
1535 self
.assertRegex(output
, 'gbp')
1537 output
= check_output('bridge fdb show dev vxlan99')
1539 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1540 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1541 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1543 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'vxlan99', env
=env
)
1545 self
.assertRegex(output
, 'VNI: 999')
1546 self
.assertRegex(output
, 'Destination Port: 5555')
1547 self
.assertRegex(output
, 'Underlying Device: test1')
1549 def test_macsec(self
):
1550 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1551 'macsec.network', '12-dummy.netdev')
1554 self
.wait_online(['dummy98:degraded', 'macsec99:routable'])
1556 output
= check_output('ip -d link show macsec99')
1558 self
.assertRegex(output
, 'macsec99@dummy98')
1559 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1560 self
.assertRegex(output
, 'encrypt on')
1562 output
= check_output('ip macsec show macsec99')
1564 self
.assertRegex(output
, 'encrypt on')
1565 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1566 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1567 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1568 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1569 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1570 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1571 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1572 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1573 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1574 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1575 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1577 def test_nlmon(self
):
1578 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1581 self
.wait_online(['nlmon99:carrier'])
1583 @expectedFailureIfModuleIsNotAvailable('ifb')
1585 copy_unit_to_networkd_unit_path('25-ifb.netdev', 'netdev-link-local-addressing-yes.network')
1588 self
.wait_online(['ifb99:degraded'])
1590 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1601 '25-l2tp-dummy.network',
1603 '25-l2tp-ip.netdev',
1604 '25-l2tp-udp.netdev']
1606 l2tp_tunnel_ids
= [ '10' ]
1609 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1610 remove_links(self
.links
)
1611 stop_networkd(show_logs
=False)
1614 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1615 remove_links(self
.links
)
1616 remove_unit_from_networkd_path(self
.units
)
1617 stop_networkd(show_logs
=True)
1619 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1620 def test_l2tp_udp(self
):
1621 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1622 '25-l2tp-udp.netdev', '25-l2tp.network')
1625 self
.wait_online(['test1:routable', 'l2tp-ses1:degraded', 'l2tp-ses2:degraded'])
1627 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1629 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1630 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1631 self
.assertRegex(output
, "Peer tunnel 11")
1632 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1633 self
.assertRegex(output
, "UDP checksum: enabled")
1635 output
= check_output('ip l2tp show session tid 10 session_id 15')
1637 self
.assertRegex(output
, "Session 15 in tunnel 10")
1638 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1639 self
.assertRegex(output
, "interface name: l2tp-ses1")
1641 output
= check_output('ip l2tp show session tid 10 session_id 17')
1643 self
.assertRegex(output
, "Session 17 in tunnel 10")
1644 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1645 self
.assertRegex(output
, "interface name: l2tp-ses2")
1647 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1648 def test_l2tp_ip(self
):
1649 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1650 '25-l2tp-ip.netdev', '25-l2tp.network')
1653 self
.wait_online(['test1:routable', 'l2tp-ses3:degraded', 'l2tp-ses4:degraded'])
1655 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1657 self
.assertRegex(output
, "Tunnel 10, encap IP")
1658 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1659 self
.assertRegex(output
, "Peer tunnel 12")
1661 output
= check_output('ip l2tp show session tid 10 session_id 25')
1663 self
.assertRegex(output
, "Session 25 in tunnel 10")
1664 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1665 self
.assertRegex(output
, "interface name: l2tp-ses3")
1667 output
= check_output('ip l2tp show session tid 10 session_id 27')
1669 self
.assertRegex(output
, "Session 27 in tunnel 10")
1670 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1671 self
.assertRegex(output
, "interface name: l2tp-ses4")
1673 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1688 '23-active-slave.network',
1689 '24-keep-configuration-static.network',
1690 '24-search-domain.network',
1691 '25-address-dad-veth-peer.network',
1692 '25-address-dad-veth99.network',
1693 '25-address-link-section.network',
1694 '25-address-preferred-lifetime-zero.network',
1695 '25-address-static.network',
1696 '25-bind-carrier.network',
1697 '25-bond-active-backup-slave.netdev',
1698 '25-fibrule-invert.network',
1699 '25-fibrule-port-range.network',
1700 '25-fibrule-uidrange.network',
1701 '25-gre-tunnel-remote-any.netdev',
1702 '25-ip6gre-tunnel-remote-any.netdev',
1703 '25-ipv6-address-label-section.network',
1704 '25-link-local-addressing-no.network',
1705 '25-link-local-addressing-yes.network',
1706 '25-link-section-unmanaged.network',
1707 '25-neighbor-section.network',
1708 '25-neighbor-next.network',
1709 '25-neighbor-ipv6.network',
1710 '25-neighbor-ip-dummy.network',
1711 '25-neighbor-ip.network',
1712 '25-nexthop.network',
1713 '25-qdisc-cake.network',
1714 '25-qdisc-clsact-and-htb.network',
1715 '25-qdisc-drr.network',
1716 '25-qdisc-ets.network',
1717 '25-qdisc-hhf.network',
1718 '25-qdisc-ingress-netem-compat.network',
1719 '25-qdisc-pie.network',
1720 '25-qdisc-qfq.network',
1721 '25-prefix-route-with-vrf.network',
1722 '25-prefix-route-without-vrf.network',
1723 '25-route-ipv6-src.network',
1724 '25-route-static.network',
1725 '25-route-vrf.network',
1726 '25-gateway-static.network',
1727 '25-gateway-next-static.network',
1729 '25-sysctl-disable-ipv6.network',
1730 '25-sysctl.network',
1732 '25-veth-peer.network',
1736 '26-link-local-addressing-ipv6.network',
1737 'routing-policy-rule-dummy98.network',
1738 'routing-policy-rule-test1.network',
1739 'routing-policy-rule-reconfigure.network',
1742 routing_policy_rule_tables
= ['7', '8', '9', '1011']
1743 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1746 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1747 remove_routes(self
.routes
)
1748 remove_links(self
.links
)
1749 stop_networkd(show_logs
=False)
1752 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1753 remove_routes(self
.routes
)
1754 remove_links(self
.links
)
1755 remove_unit_from_networkd_path(self
.units
)
1756 stop_networkd(show_logs
=True)
1758 def test_address_static(self
):
1759 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1762 self
.wait_online(['dummy98:routable'])
1764 output
= check_output('ip -4 address show dev dummy98')
1766 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1767 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1768 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1770 # test for ENOBUFS issue #17012
1771 for i
in range(1,254):
1772 self
.assertRegex(output
, f
'inet 10.3.3.{i}/16 brd 10.3.255.255')
1775 self
.assertNotRegex(output
, '10.10.0.1/16')
1776 self
.assertNotRegex(output
, '10.10.0.2/16')
1778 output
= check_output('ip -4 address show dev dummy98 label 32')
1779 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1781 output
= check_output('ip -4 address show dev dummy98 label 33')
1782 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1784 output
= check_output('ip -4 address show dev dummy98 label 34')
1785 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1787 output
= check_output('ip -4 address show dev dummy98 label 35')
1788 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1790 output
= check_output('ip -6 address show dev dummy98')
1792 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1793 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1794 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1795 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1796 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1797 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1800 self
.wait_online(['dummy98:routable'])
1802 # test for ENOBUFS issue #17012
1803 output
= check_output('ip -4 address show dev dummy98')
1804 for i
in range(1,254):
1805 self
.assertRegex(output
, f
'inet 10.3.3.{i}/16 brd 10.3.255.255')
1807 def test_address_preferred_lifetime_zero_ipv6(self
):
1808 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero.network', '12-dummy.netdev')
1811 self
.wait_online(['dummy98:routable'])
1813 output
= check_output('ip address show dummy98')
1815 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1816 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1818 output
= check_output('ip route show dev dummy98')
1820 self
.assertRegex(output
, 'default via 20.20.20.1 proto static')
1822 def test_address_dad(self
):
1823 copy_unit_to_networkd_unit_path('25-address-dad-veth99.network', '25-address-dad-veth-peer.network',
1826 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
1828 output
= check_output('ip -4 address show dev veth99')
1830 self
.assertRegex(output
, '192.168.100.10/24')
1832 output
= check_output('ip -4 address show dev veth-peer')
1834 self
.assertNotRegex(output
, '192.168.100.10/24')
1836 @expectedFailureIfModuleIsNotAvailable('vrf')
1837 def test_prefix_route(self
):
1838 copy_unit_to_networkd_unit_path('25-prefix-route-with-vrf.network', '12-dummy.netdev',
1839 '25-prefix-route-without-vrf.network', '11-dummy.netdev',
1840 '25-vrf.netdev', '25-vrf.network')
1841 for trial
in range(2):
1847 self
.wait_online(['dummy98:routable', 'test1:routable', 'vrf99:carrier'])
1849 output
= check_output('ip route show table 42 dev dummy98')
1850 print('### ip route show table 42 dev dummy98')
1852 self
.assertRegex(output
, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1')
1853 self
.assertRegex(output
, 'broadcast 10.20.33.0 proto kernel scope link src 10.20.33.1')
1854 self
.assertRegex(output
, '10.20.33.0/24 proto kernel scope link src 10.20.33.1')
1855 self
.assertRegex(output
, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1')
1856 self
.assertRegex(output
, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1')
1857 self
.assertRegex(output
, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1')
1858 self
.assertRegex(output
, 'broadcast 10.20.55.0 proto kernel scope link src 10.20.55.1')
1859 self
.assertRegex(output
, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1')
1860 self
.assertRegex(output
, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1')
1861 output
= check_output('ip -6 route show table 42 dev dummy98')
1862 print('### ip -6 route show table 42 dev dummy98')
1866 self
.assertRegex(output
, 'local fdde:11:22::1 proto kernel metric 0 pref medium')
1867 #self.assertRegex(output, 'fdde:11:22::1 proto kernel metric 256 pref medium')
1868 self
.assertRegex(output
, 'local fdde:11:33::1 proto kernel metric 0 pref medium')
1869 self
.assertRegex(output
, 'fdde:11:33::/64 proto kernel metric 256 pref medium')
1870 self
.assertRegex(output
, 'local fdde:11:44::1 proto kernel metric 0 pref medium')
1871 self
.assertRegex(output
, 'local fdde:11:55::1 proto kernel metric 0 pref medium')
1872 self
.assertRegex(output
, 'fe80::/64 proto kernel metric 256 pref medium')
1873 self
.assertRegex(output
, 'ff00::/8 metric 256 pref medium')
1877 output
= check_output('ip route show dev test1')
1878 print('### ip route show dev test1')
1880 self
.assertRegex(output
, '10.21.33.0/24 proto kernel scope link src 10.21.33.1')
1881 output
= check_output('ip route show table local dev test1')
1882 print('### ip route show table local dev test1')
1884 self
.assertRegex(output
, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1')
1885 self
.assertRegex(output
, 'broadcast 10.21.33.0 proto kernel scope link src 10.21.33.1')
1886 self
.assertRegex(output
, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1')
1887 self
.assertRegex(output
, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1')
1888 self
.assertRegex(output
, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1')
1889 self
.assertRegex(output
, 'broadcast 10.21.55.0 proto kernel scope link src 10.21.55.1')
1890 self
.assertRegex(output
, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1')
1891 self
.assertRegex(output
, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1')
1892 output
= check_output('ip -6 route show dev test1')
1893 print('### ip -6 route show dev test1')
1895 self
.assertRegex(output
, 'fdde:12:22::1 proto kernel metric 256 pref medium')
1896 self
.assertRegex(output
, 'fdde:12:33::/64 proto kernel metric 256 pref medium')
1897 self
.assertRegex(output
, 'fe80::/64 proto kernel metric 256 pref medium')
1898 output
= check_output('ip -6 route show table local dev test1')
1899 print('### ip -6 route show table local dev test1')
1901 self
.assertRegex(output
, 'local fdde:12:22::1 proto kernel metric 0 pref medium')
1902 self
.assertRegex(output
, 'local fdde:12:33::1 proto kernel metric 0 pref medium')
1903 self
.assertRegex(output
, 'local fdde:12:44::1 proto kernel metric 0 pref medium')
1904 self
.assertRegex(output
, 'local fdde:12:55::1 proto kernel metric 0 pref medium')
1905 self
.assertRegex(output
, 'ff00::/8 metric 256 pref medium')
1907 def test_configure_without_carrier(self
):
1908 copy_unit_to_networkd_unit_path('11-dummy.netdev')
1910 self
.wait_operstate('test1', 'off', '')
1911 check_output('ip link set dev test1 up carrier off')
1913 copy_unit_to_networkd_unit_path('25-test1.network.d/configure-without-carrier.conf', dropins
=False)
1915 self
.wait_online(['test1:no-carrier'])
1917 carrier_map
= {'on': '1', 'off': '0'}
1918 routable_map
= {'on': 'routable', 'off': 'no-carrier'}
1919 for carrier
in ['off', 'on', 'off']:
1920 with self
.subTest(carrier
=carrier
):
1921 if carrier_map
[carrier
] != read_link_attr('test1', 'carrier'):
1922 check_output(f
'ip link set dev test1 carrier {carrier}')
1923 self
.wait_online([f
'test1:{routable_map[carrier]}'])
1925 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
1927 self
.assertRegex(output
, '192.168.0.15')
1928 self
.assertRegex(output
, '192.168.0.1')
1929 self
.assertRegex(output
, routable_map
[carrier
])
1931 def test_configure_without_carrier_yes_ignore_carrier_loss_no(self
):
1932 copy_unit_to_networkd_unit_path('11-dummy.netdev')
1934 self
.wait_operstate('test1', 'off', '')
1935 check_output('ip link set dev test1 up carrier off')
1937 copy_unit_to_networkd_unit_path('25-test1.network')
1939 self
.wait_online(['test1:no-carrier'])
1941 carrier_map
= {'on': '1', 'off': '0'}
1942 routable_map
= {'on': 'routable', 'off': 'no-carrier'}
1943 for (carrier
, have_config
) in [('off', True), ('on', True), ('off', False)]:
1944 with self
.subTest(carrier
=carrier
, have_config
=have_config
):
1945 if carrier_map
[carrier
] != read_link_attr('test1', 'carrier'):
1946 check_output(f
'ip link set dev test1 carrier {carrier}')
1947 self
.wait_online([f
'test1:{routable_map[carrier]}'])
1949 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
1952 self
.assertRegex(output
, '192.168.0.15')
1953 self
.assertRegex(output
, '192.168.0.1')
1955 self
.assertNotRegex(output
, '192.168.0.15')
1956 self
.assertNotRegex(output
, '192.168.0.1')
1957 self
.assertRegex(output
, routable_map
[carrier
])
1959 def test_routing_policy_rule(self
):
1960 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1962 self
.wait_online(['test1:degraded'])
1964 output
= check_output('ip rule list iif test1 priority 111')
1966 self
.assertRegex(output
, '111:')
1967 self
.assertRegex(output
, 'from 192.168.100.18')
1968 self
.assertRegex(output
, r
'tos (0x08|throughput)\s')
1969 self
.assertRegex(output
, 'iif test1')
1970 self
.assertRegex(output
, 'oif test1')
1971 self
.assertRegex(output
, 'lookup 7')
1973 output
= check_output('ip rule list iif test1 priority 101')
1975 self
.assertRegex(output
, '101:')
1976 self
.assertRegex(output
, 'from all')
1977 self
.assertRegex(output
, 'iif test1')
1978 self
.assertRegex(output
, 'lookup 9')
1980 output
= check_output('ip -6 rule list iif test1 priority 100')
1982 self
.assertRegex(output
, '100:')
1983 self
.assertRegex(output
, 'from all')
1984 self
.assertRegex(output
, 'iif test1')
1985 self
.assertRegex(output
, 'lookup 8')
1987 def test_routing_policy_rule_issue_11280(self
):
1988 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1989 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1991 for trial
in range(3):
1992 # Remove state files only first time
1994 self
.wait_online(['test1:degraded', 'dummy98:degraded'])
1997 output
= check_output('ip rule list table 7')
1999 self
.assertRegex(output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
2001 output
= check_output('ip rule list table 8')
2003 self
.assertRegex(output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
2005 stop_networkd(remove_state_files
=False)
2007 def test_routing_policy_rule_reconfigure(self
):
2008 copy_unit_to_networkd_unit_path('routing-policy-rule-reconfigure.network', '11-dummy.netdev')
2010 self
.wait_online(['test1:degraded'])
2012 output
= check_output('ip rule list table 1011')
2014 self
.assertRegex(output
, '10111: from all fwmark 0x3f3 lookup 1011')
2015 self
.assertRegex(output
, '10112: from all oif test1 lookup 1011')
2016 self
.assertRegex(output
, '10113: from all iif test1 lookup 1011')
2017 self
.assertRegex(output
, '10114: from 192.168.8.254 lookup 1011')
2019 run('ip rule delete priority 10111')
2020 run('ip rule delete priority 10112')
2021 run('ip rule delete priority 10113')
2022 run('ip rule delete priority 10114')
2023 run('ip rule delete priority 10115')
2025 output
= check_output('ip rule list table 1011')
2027 self
.assertEqual(output
, '')
2029 run(*networkctl_cmd
, 'reconfigure', 'test1', env
=env
)
2031 self
.wait_online(['test1:degraded'])
2033 output
= check_output('ip rule list table 1011')
2035 self
.assertRegex(output
, '10111: from all fwmark 0x3f3 lookup 1011')
2036 self
.assertRegex(output
, '10112: from all oif test1 lookup 1011')
2037 self
.assertRegex(output
, '10113: from all iif test1 lookup 1011')
2038 self
.assertRegex(output
, '10114: from 192.168.8.254 lookup 1011')
2040 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
2041 def test_routing_policy_rule_port_range(self
):
2042 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
2044 self
.wait_online(['test1:degraded'])
2046 output
= check_output('ip rule')
2048 self
.assertRegex(output
, '111')
2049 self
.assertRegex(output
, 'from 192.168.100.18')
2050 self
.assertRegex(output
, '1123-1150')
2051 self
.assertRegex(output
, '3224-3290')
2052 self
.assertRegex(output
, 'tcp')
2053 self
.assertRegex(output
, 'lookup 7')
2055 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
2056 def test_routing_policy_rule_invert(self
):
2057 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
2059 self
.wait_online(['test1:degraded'])
2061 output
= check_output('ip rule')
2063 self
.assertRegex(output
, '111')
2064 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
2065 self
.assertRegex(output
, 'tcp')
2066 self
.assertRegex(output
, 'lookup 7')
2068 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable()
2069 def test_routing_policy_rule_uidrange(self
):
2070 copy_unit_to_networkd_unit_path('25-fibrule-uidrange.network', '11-dummy.netdev')
2072 self
.wait_online(['test1:degraded'])
2074 output
= check_output('ip rule')
2076 self
.assertRegex(output
, '111')
2077 self
.assertRegex(output
, 'from 192.168.100.18')
2078 self
.assertRegex(output
, 'lookup 7')
2079 self
.assertRegex(output
, 'uidrange 100-200')
2081 def test_route_static(self
):
2082 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
2084 self
.wait_online(['dummy98:routable'])
2086 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2089 print('### ip -6 route show dev dummy98')
2090 output
= check_output('ip -6 route show dev dummy98')
2092 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
2093 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
2095 print('### ip -6 route show dev dummy98 default')
2096 output
= check_output('ip -6 route show dev dummy98 default')
2098 self
.assertRegex(output
, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
2100 print('### ip -4 route show dev dummy98')
2101 output
= check_output('ip -4 route show dev dummy98')
2103 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
2104 self
.assertRegex(output
, '149.10.124.64 proto static scope link')
2105 self
.assertRegex(output
, '169.254.0.0/16 proto static scope link metric 2048')
2106 self
.assertRegex(output
, '192.168.1.1 proto static initcwnd 20')
2107 self
.assertRegex(output
, '192.168.1.2 proto static initrwnd 30')
2108 self
.assertRegex(output
, 'multicast 149.10.123.4 proto static')
2110 print('### ip -4 route show dev dummy98 default')
2111 output
= check_output('ip -4 route show dev dummy98 default')
2113 self
.assertRegex(output
, 'default via 149.10.125.65 proto static onlink')
2114 self
.assertRegex(output
, 'default via 149.10.124.64 proto static')
2115 self
.assertRegex(output
, 'default proto static')
2117 print('### ip -4 route show table local dev dummy98')
2118 output
= check_output('ip -4 route show table local dev dummy98')
2120 self
.assertRegex(output
, 'local 149.10.123.1 proto static scope host')
2121 self
.assertRegex(output
, 'anycast 149.10.123.2 proto static scope link')
2122 self
.assertRegex(output
, 'broadcast 149.10.123.3 proto static scope link')
2124 print('### ip route show type blackhole')
2125 output
= check_output('ip route show type blackhole')
2127 self
.assertRegex(output
, 'blackhole 202.54.1.2 proto static')
2129 print('### ip route show type unreachable')
2130 output
= check_output('ip route show type unreachable')
2132 self
.assertRegex(output
, 'unreachable 202.54.1.3 proto static')
2134 print('### ip route show type prohibit')
2135 output
= check_output('ip route show type prohibit')
2137 self
.assertRegex(output
, 'prohibit 202.54.1.4 proto static')
2139 print('### ip route show 192.168.10.1')
2140 output
= check_output('ip route show 192.168.10.1')
2142 self
.assertRegex(output
, '192.168.10.1 proto static')
2143 self
.assertRegex(output
, 'nexthop via 149.10.124.59 dev dummy98 weight 10')
2144 self
.assertRegex(output
, 'nexthop via 149.10.124.60 dev dummy98 weight 5')
2146 print('### ip route show 192.168.10.2')
2147 output
= check_output('ip route show 192.168.10.2')
2149 # old ip command does not show IPv6 gateways...
2150 self
.assertRegex(output
, '192.168.10.2 proto static')
2151 self
.assertRegex(output
, 'nexthop')
2152 self
.assertRegex(output
, 'dev dummy98 weight 10')
2153 self
.assertRegex(output
, 'dev dummy98 weight 5')
2155 print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2156 output
= check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2158 # old ip command does not show 'nexthop' keyword and weight...
2159 self
.assertRegex(output
, '2001:1234:5:7fff:ff:ff:ff:ff')
2160 self
.assertRegex(output
, 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98')
2161 self
.assertRegex(output
, 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98')
2163 @expectedFailureIfModuleIsNotAvailable('vrf')
2164 def test_route_vrf(self
):
2165 copy_unit_to_networkd_unit_path('25-route-vrf.network', '12-dummy.netdev',
2166 '25-vrf.netdev', '25-vrf.network')
2168 self
.wait_online(['dummy98:routable', 'vrf99:carrier'])
2170 output
= check_output('ip route show vrf vrf99')
2172 self
.assertRegex(output
, 'default via 192.168.100.1')
2174 output
= check_output('ip route show')
2176 self
.assertNotRegex(output
, 'default via 192.168.100.1')
2178 def test_gateway_reconfigure(self
):
2179 copy_unit_to_networkd_unit_path('25-gateway-static.network', '12-dummy.netdev')
2181 self
.wait_online(['dummy98:routable'])
2182 print('### ip -4 route show dev dummy98 default')
2183 output
= check_output('ip -4 route show dev dummy98 default')
2185 self
.assertRegex(output
, 'default via 149.10.124.59 proto static')
2186 self
.assertNotRegex(output
, '149.10.124.60')
2188 remove_unit_from_networkd_path(['25-gateway-static.network'])
2189 copy_unit_to_networkd_unit_path('25-gateway-next-static.network')
2191 self
.wait_online(['dummy98:routable'])
2192 print('### ip -4 route show dev dummy98 default')
2193 output
= check_output('ip -4 route show dev dummy98 default')
2195 self
.assertNotRegex(output
, '149.10.124.59')
2196 self
.assertRegex(output
, 'default via 149.10.124.60 proto static')
2198 def test_ip_route_ipv6_src_route(self
):
2199 # a dummy device does not make the addresses go through tentative state, so we
2200 # reuse a bond from an earlier test, which does make the addresses go through
2201 # tentative state, and do our test on that
2202 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2204 self
.wait_online(['dummy98:enslaved', 'bond199:routable'])
2206 output
= check_output('ip -6 route list dev bond199')
2208 self
.assertRegex(output
, 'abcd::/16')
2209 self
.assertRegex(output
, 'src')
2210 self
.assertRegex(output
, '2001:1234:56:8f63::2')
2212 def test_ip_link_mac_address(self
):
2213 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
2215 self
.wait_online(['dummy98:degraded'])
2217 output
= check_output('ip link show dummy98')
2219 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
2221 def test_ip_link_unmanaged(self
):
2222 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
2225 self
.check_link_exists('dummy98')
2227 self
.wait_operstate('dummy98', 'off', setup_state
='unmanaged')
2229 def test_ipv6_address_label(self
):
2230 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
2232 self
.wait_online(['dummy98:degraded'])
2234 output
= check_output('ip addrlabel list')
2236 self
.assertRegex(output
, '2004:da8:1::/64')
2238 def test_neighbor_section(self
):
2239 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2241 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2243 print('### ip neigh list dev dummy98')
2244 output
= check_output('ip neigh list dev dummy98')
2246 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2247 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2249 def test_neighbor_reconfigure(self
):
2250 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2252 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2254 print('### ip neigh list dev dummy98')
2255 output
= check_output('ip neigh list dev dummy98')
2257 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2258 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2260 remove_unit_from_networkd_path(['25-neighbor-section.network'])
2261 copy_unit_to_networkd_unit_path('25-neighbor-next.network')
2263 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2264 print('### ip neigh list dev dummy98')
2265 output
= check_output('ip neigh list dev dummy98')
2267 self
.assertNotRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2268 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT')
2269 self
.assertNotRegex(output
, '2004:da8:1::1.*PERMANENT')
2271 def test_neighbor_gre(self
):
2272 copy_unit_to_networkd_unit_path('25-neighbor-ip.network', '25-neighbor-ipv6.network', '25-neighbor-ip-dummy.network',
2273 '12-dummy.netdev', '25-gre-tunnel-remote-any.netdev', '25-ip6gre-tunnel-remote-any.netdev')
2275 self
.wait_online(['dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable'], timeout
='40s')
2277 output
= check_output('ip neigh list dev gretun97')
2279 self
.assertRegex(output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT')
2281 output
= check_output('ip neigh list dev ip6gretun97')
2283 self
.assertRegex(output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
2285 def test_link_local_addressing(self
):
2286 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
2287 '25-link-local-addressing-no.network', '12-dummy.netdev')
2289 self
.wait_online(['test1:degraded', 'dummy98:carrier'])
2291 output
= check_output('ip address show dev test1')
2293 self
.assertRegex(output
, 'inet .* scope link')
2294 self
.assertRegex(output
, 'inet6 .* scope link')
2296 output
= check_output('ip address show dev dummy98')
2298 self
.assertNotRegex(output
, 'inet6* .* scope link')
2301 Documentation/networking/ip-sysctl.txt
2303 addr_gen_mode - INTEGER
2304 Defines how link-local and autoconf addresses are generated.
2306 0: generate address based on EUI64 (default)
2307 1: do no generate a link-local address, use EUI64 for addresses generated
2309 2: generate stable privacy addresses, using the secret from
2310 stable_secret (RFC7217)
2311 3: generate stable privacy addresses, using a random secret if unset
2314 test1_addr_gen_mode
= ''
2315 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
2316 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
2320 # if stable_secret is unset, then EIO is returned
2321 test1_addr_gen_mode
= '0'
2323 test1_addr_gen_mode
= '2'
2325 test1_addr_gen_mode
= '0'
2327 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
2328 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
2330 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
2331 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
2333 def test_link_local_addressing_remove_ipv6ll(self
):
2334 copy_unit_to_networkd_unit_path('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
2336 self
.wait_online(['dummy98:degraded'])
2338 output
= check_output('ip address show dev dummy98')
2340 self
.assertRegex(output
, 'inet6 .* scope link')
2342 copy_unit_to_networkd_unit_path('25-link-local-addressing-no.network')
2344 self
.wait_online(['dummy98:carrier'])
2346 output
= check_output('ip address show dev dummy98')
2348 self
.assertNotRegex(output
, 'inet6* .* scope link')
2350 def test_sysctl(self
):
2351 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
2353 self
.wait_online(['dummy98:degraded'])
2355 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
2356 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
2357 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
2358 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
2359 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
2360 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
2361 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
2362 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'accept_local'), '1')
2364 def test_sysctl_disable_ipv6(self
):
2365 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
2367 print('## Disable ipv6')
2368 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
2369 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
2372 self
.wait_online(['dummy98:routable'])
2374 output
= check_output('ip -4 address show dummy98')
2376 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2377 output
= check_output('ip -6 address show dummy98')
2379 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2380 self
.assertRegex(output
, 'inet6 .* scope link')
2381 output
= check_output('ip -4 route show dev dummy98')
2383 self
.assertRegex(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2384 output
= check_output('ip -6 route show dev dummy98')
2386 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2388 check_output('ip link del dummy98')
2390 print('## Enable ipv6')
2391 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
2392 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
2395 self
.wait_online(['dummy98:routable'])
2397 output
= check_output('ip -4 address show dummy98')
2399 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2400 output
= check_output('ip -6 address show dummy98')
2402 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2403 self
.assertRegex(output
, 'inet6 .* scope link')
2404 output
= check_output('ip -4 route show dev dummy98')
2406 self
.assertRegex(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2407 output
= check_output('ip -6 route show dev dummy98')
2409 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2411 def test_bind_carrier(self
):
2412 check_output('ip link add dummy98 type dummy')
2413 check_output('ip link set dummy98 up')
2416 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
2418 self
.wait_online(['test1:routable'])
2420 output
= check_output('ip address show test1')
2422 self
.assertRegex(output
, 'UP,LOWER_UP')
2423 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2424 self
.wait_operstate('test1', 'routable')
2426 check_output('ip link add dummy99 type dummy')
2427 check_output('ip link set dummy99 up')
2429 output
= check_output('ip address show test1')
2431 self
.assertRegex(output
, 'UP,LOWER_UP')
2432 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2433 self
.wait_operstate('test1', 'routable')
2435 check_output('ip link del dummy98')
2437 output
= check_output('ip address show test1')
2439 self
.assertRegex(output
, 'UP,LOWER_UP')
2440 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2441 self
.wait_operstate('test1', 'routable')
2443 check_output('ip link set dummy99 down')
2445 output
= check_output('ip address show test1')
2447 self
.assertNotRegex(output
, 'UP,LOWER_UP')
2448 self
.assertRegex(output
, 'DOWN')
2449 self
.assertNotRegex(output
, '192.168.10')
2450 self
.wait_operstate('test1', 'off')
2452 check_output('ip link set dummy99 up')
2454 output
= check_output('ip address show test1')
2456 self
.assertRegex(output
, 'UP,LOWER_UP')
2457 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2458 self
.wait_operstate('test1', 'routable')
2460 def test_domain(self
):
2461 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
2463 self
.wait_online(['dummy98:routable'])
2465 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2467 self
.assertRegex(output
, 'Address: 192.168.42.100')
2468 self
.assertRegex(output
, 'DNS: 192.168.42.1')
2469 self
.assertRegex(output
, 'Search Domains: one')
2471 def test_keep_configuration_static(self
):
2472 check_output('systemctl stop systemd-networkd.socket')
2473 check_output('systemctl stop systemd-networkd.service')
2475 check_output('ip link add name dummy98 type dummy')
2476 check_output('ip address add 10.1.2.3/16 dev dummy98')
2477 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
2478 output
= check_output('ip address show dummy98')
2480 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2481 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2482 output
= check_output('ip route show dev dummy98')
2485 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
2487 self
.wait_online(['dummy98:routable'])
2489 output
= check_output('ip address show dummy98')
2491 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2492 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2494 @expectedFailureIfNexthopIsNotAvailable()
2495 def test_nexthop(self
):
2496 copy_unit_to_networkd_unit_path('25-nexthop.network', '25-veth.netdev', '25-veth-peer.network')
2498 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2500 output
= check_output('ip nexthop list dev veth99')
2502 self
.assertRegex(output
, '192.168.5.1')
2504 def test_qdisc(self
):
2505 copy_unit_to_networkd_unit_path('25-qdisc-clsact-and-htb.network', '12-dummy.netdev',
2506 '25-qdisc-ingress-netem-compat.network', '11-dummy.netdev')
2507 check_output('modprobe sch_teql max_equalizers=2')
2510 self
.wait_online(['dummy98:routable', 'test1:routable'])
2512 output
= check_output('tc qdisc show dev test1')
2514 self
.assertRegex(output
, 'qdisc netem')
2515 self
.assertRegex(output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
2516 self
.assertRegex(output
, 'qdisc ingress')
2518 output
= check_output('tc qdisc show dev dummy98')
2520 self
.assertRegex(output
, 'qdisc clsact')
2522 self
.assertRegex(output
, 'qdisc htb 2: root')
2523 self
.assertRegex(output
, r
'default (0x30|30)')
2525 self
.assertRegex(output
, 'qdisc netem 30: parent 2:30')
2526 self
.assertRegex(output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
2527 self
.assertRegex(output
, 'qdisc fq_codel')
2528 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')
2530 self
.assertRegex(output
, 'qdisc teql1 31: parent 2:31')
2532 self
.assertRegex(output
, 'qdisc fq 32: parent 2:32')
2533 self
.assertRegex(output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
2534 self
.assertRegex(output
, 'quantum 1500')
2535 self
.assertRegex(output
, 'initial_quantum 13000')
2536 self
.assertRegex(output
, 'maxrate 1Mbit')
2538 self
.assertRegex(output
, 'qdisc codel 33: parent 2:33')
2539 self
.assertRegex(output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn')
2541 self
.assertRegex(output
, 'qdisc fq_codel 34: parent 2:34')
2542 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')
2544 self
.assertRegex(output
, 'qdisc tbf 35: parent 2:35')
2545 self
.assertRegex(output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms')
2547 self
.assertRegex(output
, 'qdisc sfq 36: parent 2:36')
2548 self
.assertRegex(output
, 'perturb 5sec')
2550 self
.assertRegex(output
, 'qdisc pfifo 37: parent 2:37')
2551 self
.assertRegex(output
, 'limit 100000p')
2553 self
.assertRegex(output
, 'qdisc gred 38: parent 2:38')
2554 self
.assertRegex(output
, 'vqs 12 default 10 grio')
2556 self
.assertRegex(output
, 'qdisc sfb 39: parent 2:39')
2557 self
.assertRegex(output
, 'limit 200000')
2559 self
.assertRegex(output
, 'qdisc bfifo 3a: parent 2:3a')
2560 self
.assertRegex(output
, 'limit 1000000')
2562 self
.assertRegex(output
, 'qdisc pfifo_head_drop 3b: parent 2:3b')
2563 self
.assertRegex(output
, 'limit 1023p')
2565 self
.assertRegex(output
, 'qdisc pfifo_fast 3c: parent 2:3c')
2567 output
= check_output('tc -d class show dev dummy98')
2569 self
.assertRegex(output
, 'class htb 2:30 root leaf 30:')
2570 self
.assertRegex(output
, 'class htb 2:31 root leaf 31:')
2571 self
.assertRegex(output
, 'class htb 2:32 root leaf 32:')
2572 self
.assertRegex(output
, 'class htb 2:33 root leaf 33:')
2573 self
.assertRegex(output
, 'class htb 2:34 root leaf 34:')
2574 self
.assertRegex(output
, 'class htb 2:35 root leaf 35:')
2575 self
.assertRegex(output
, 'class htb 2:36 root leaf 36:')
2576 self
.assertRegex(output
, 'class htb 2:37 root leaf 37:')
2577 self
.assertRegex(output
, 'class htb 2:38 root leaf 38:')
2578 self
.assertRegex(output
, 'class htb 2:39 root leaf 39:')
2579 self
.assertRegex(output
, 'class htb 2:3a root leaf 3a:')
2580 self
.assertRegex(output
, 'class htb 2:3b root leaf 3b:')
2581 self
.assertRegex(output
, 'class htb 2:3c root leaf 3c:')
2582 self
.assertRegex(output
, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit')
2583 self
.assertRegex(output
, 'burst 123456')
2584 self
.assertRegex(output
, 'cburst 123457')
2586 def test_qdisc2(self
):
2587 copy_unit_to_networkd_unit_path('25-qdisc-drr.network', '12-dummy.netdev',
2588 '25-qdisc-qfq.network', '11-dummy.netdev')
2591 self
.wait_online(['dummy98:routable', 'test1:routable'])
2593 output
= check_output('tc qdisc show dev dummy98')
2595 self
.assertRegex(output
, 'qdisc drr 2: root')
2596 output
= check_output('tc class show dev dummy98')
2598 self
.assertRegex(output
, 'class drr 2:30 root quantum 2000b')
2600 output
= check_output('tc qdisc show dev test1')
2602 self
.assertRegex(output
, 'qdisc qfq 2: root')
2603 output
= check_output('tc class show dev test1')
2605 self
.assertRegex(output
, 'class qfq 2:30 root weight 2 maxpkt 16000')
2606 self
.assertRegex(output
, 'class qfq 2:31 root weight 10 maxpkt 8000')
2608 @expectedFailureIfCAKEIsNotAvailable()
2609 def test_qdisc_cake(self
):
2610 copy_unit_to_networkd_unit_path('25-qdisc-cake.network', '12-dummy.netdev')
2612 self
.wait_online(['dummy98:routable'])
2614 output
= check_output('tc qdisc show dev dummy98')
2616 self
.assertRegex(output
, 'qdisc cake 3a: root')
2617 self
.assertRegex(output
, 'bandwidth 500Mbit')
2618 self
.assertRegex(output
, 'overhead 128')
2620 @expectedFailureIfPIEIsNotAvailable()
2621 def test_qdisc_pie(self
):
2622 copy_unit_to_networkd_unit_path('25-qdisc-pie.network', '12-dummy.netdev')
2624 self
.wait_online(['dummy98:routable'])
2626 output
= check_output('tc qdisc show dev dummy98')
2628 self
.assertRegex(output
, 'qdisc pie 3a: root')
2629 self
.assertRegex(output
, 'limit 200000')
2631 @expectedFailureIfHHFIsNotAvailable()
2632 def test_qdisc_hhf(self
):
2633 copy_unit_to_networkd_unit_path('25-qdisc-hhf.network', '12-dummy.netdev')
2635 self
.wait_online(['dummy98:routable'])
2637 output
= check_output('tc qdisc show dev dummy98')
2639 self
.assertRegex(output
, 'qdisc hhf 3a: root')
2640 self
.assertRegex(output
, 'limit 1022p')
2642 @expectedFailureIfETSIsNotAvailable()
2643 def test_qdisc_ets(self
):
2644 copy_unit_to_networkd_unit_path('25-qdisc-ets.network', '12-dummy.netdev')
2646 self
.wait_online(['dummy98:routable'])
2648 output
= check_output('tc qdisc show dev dummy98')
2650 self
.assertRegex(output
, 'qdisc ets 3a: root')
2651 self
.assertRegex(output
, 'bands 10 strict 3')
2652 self
.assertRegex(output
, 'quanta 1 2 3 4 5')
2653 self
.assertRegex(output
, 'priomap 3 4 5 6 7')
2655 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable()
2656 def test_sriov(self
):
2657 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
2658 call('modprobe netdevsim', stderr
=subprocess
.DEVNULL
)
2659 with
open('/sys/bus/netdevsim/new_device', mode
='w') as f
:
2662 call('udevadm settle')
2663 call('udevadm info -w10s /sys/devices/netdevsim99/net/eni99np1', stderr
=subprocess
.DEVNULL
)
2664 with
open('/sys/class/net/eni99np1/device/sriov_numvfs', mode
='w') as f
:
2667 copy_unit_to_networkd_unit_path('25-sriov.network')
2669 self
.wait_online(['eni99np1:routable'])
2671 output
= check_output('ip link show dev eni99np1')
2673 self
.assertRegex(output
,
2674 '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 *'
2675 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
2676 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
2679 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
2681 class NetworkdStateFileTests(unittest
.TestCase
, Utilities
):
2688 'state-file-tests.network',
2692 remove_links(self
.links
)
2693 stop_networkd(show_logs
=False)
2696 remove_links(self
.links
)
2697 remove_unit_from_networkd_path(self
.units
)
2698 stop_networkd(show_logs
=True)
2700 def test_state_file(self
):
2701 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'state-file-tests.network')
2703 self
.wait_online(['dummy98:routable'])
2705 output
= check_output(*networkctl_cmd
, '--no-legend', 'list', 'dummy98', env
=env
)
2707 ifindex
= output
.split()[0]
2709 path
= os
.path
.join('/run/systemd/netif/links/', ifindex
)
2710 self
.assertTrue(os
.path
.exists(path
))
2712 # make link state file updated
2713 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
2715 with
open(path
) as f
:
2717 self
.assertRegex(data
, r
'ADMIN_STATE=configured')
2718 self
.assertRegex(data
, r
'OPER_STATE=routable')
2719 self
.assertRegex(data
, r
'REQUIRED_FOR_ONLINE=yes')
2720 self
.assertRegex(data
, r
'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
2721 self
.assertRegex(data
, r
'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
2722 self
.assertRegex(data
, r
'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
2723 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2724 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2725 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2726 self
.assertRegex(data
, r
'LLMNR=no')
2727 self
.assertRegex(data
, r
'MDNS=yes')
2728 self
.assertRegex(data
, r
'DNSSEC=no')
2729 self
.assertRegex(data
, r
'ADDRESSES=192.168.(10.10|12.12)/24 192.168.(12.12|10.10)/24')
2731 check_output(*resolvectl_cmd
, 'dns', 'dummy98', '10.10.10.12#ccc.com', '10.10.10.13', '1111:2222::3333', env
=env
)
2732 check_output(*resolvectl_cmd
, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env
=env
)
2733 check_output(*resolvectl_cmd
, 'llmnr', 'dummy98', 'yes', env
=env
)
2734 check_output(*resolvectl_cmd
, 'mdns', 'dummy98', 'no', env
=env
)
2735 check_output(*resolvectl_cmd
, 'dnssec', 'dummy98', 'yes', env
=env
)
2736 check_output(*timedatectl_cmd
, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env
=env
)
2738 with
open(path
) as f
:
2740 self
.assertRegex(data
, r
'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333')
2741 self
.assertRegex(data
, r
'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org')
2742 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2743 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2744 self
.assertRegex(data
, r
'LLMNR=yes')
2745 self
.assertRegex(data
, r
'MDNS=no')
2746 self
.assertRegex(data
, r
'DNSSEC=yes')
2748 check_output(*timedatectl_cmd
, 'revert', 'dummy98', env
=env
)
2750 with
open(path
) as f
:
2752 self
.assertRegex(data
, r
'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333')
2753 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2754 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2755 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2756 self
.assertRegex(data
, r
'LLMNR=yes')
2757 self
.assertRegex(data
, r
'MDNS=no')
2758 self
.assertRegex(data
, r
'DNSSEC=yes')
2760 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
2762 with
open(path
) as f
:
2764 self
.assertRegex(data
, r
'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
2765 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2766 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2767 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2768 self
.assertRegex(data
, r
'LLMNR=no')
2769 self
.assertRegex(data
, r
'MDNS=yes')
2770 self
.assertRegex(data
, r
'DNSSEC=no')
2772 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
2782 '23-active-slave.network',
2783 '23-bond199.network',
2784 '23-primary-slave.network',
2785 '25-bond-active-backup-slave.netdev',
2788 'bond-slave.network']
2791 remove_links(self
.links
)
2792 stop_networkd(show_logs
=False)
2795 remove_links(self
.links
)
2796 remove_unit_from_networkd_path(self
.units
)
2797 stop_networkd(show_logs
=True)
2799 def test_bond_active_slave(self
):
2800 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2802 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2804 output
= check_output('ip -d link show bond199')
2806 self
.assertRegex(output
, 'active_slave dummy98')
2808 def test_bond_primary_slave(self
):
2809 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2811 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2813 output
= check_output('ip -d link show bond199')
2815 self
.assertRegex(output
, 'primary dummy98')
2817 def test_bond_operstate(self
):
2818 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
2819 'bond99.network','bond-slave.network')
2821 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
2823 output
= check_output('ip -d link show dummy98')
2825 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2827 output
= check_output('ip -d link show test1')
2829 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2831 output
= check_output('ip -d link show bond99')
2833 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
2835 self
.wait_operstate('dummy98', 'enslaved')
2836 self
.wait_operstate('test1', 'enslaved')
2837 self
.wait_operstate('bond99', 'routable')
2839 check_output('ip link set dummy98 down')
2841 self
.wait_operstate('dummy98', 'off')
2842 self
.wait_operstate('test1', 'enslaved')
2843 self
.wait_operstate('bond99', 'degraded-carrier')
2845 check_output('ip link set dummy98 up')
2847 self
.wait_operstate('dummy98', 'enslaved')
2848 self
.wait_operstate('test1', 'enslaved')
2849 self
.wait_operstate('bond99', 'routable')
2851 check_output('ip link set dummy98 down')
2852 check_output('ip link set test1 down')
2854 self
.wait_operstate('dummy98', 'off')
2855 self
.wait_operstate('test1', 'off')
2857 if not self
.wait_operstate('bond99', 'no-carrier', setup_timeout
=30, fail_assert
=False):
2858 # Huh? Kernel does not recognize that all slave interfaces are down?
2859 # Let's confirm that networkd's operstate is consistent with ip's result.
2860 self
.assertNotRegex(output
, 'NO-CARRIER')
2862 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
2872 '26-bridge-configure-without-carrier.network',
2873 '26-bridge-mdb-master.network',
2874 '26-bridge-mdb-slave.network',
2875 '26-bridge-slave-interface-1.network',
2876 '26-bridge-slave-interface-2.network',
2877 '26-bridge-vlan-master.network',
2878 '26-bridge-vlan-slave.network',
2879 'bridge99-ignore-carrier-loss.network',
2882 routing_policy_rule_tables
= ['100']
2885 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2886 remove_links(self
.links
)
2887 stop_networkd(show_logs
=False)
2890 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2891 remove_links(self
.links
)
2892 remove_unit_from_networkd_path(self
.units
)
2893 stop_networkd(show_logs
=True)
2895 def test_bridge_vlan(self
):
2896 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
2897 '26-bridge.netdev', '26-bridge-vlan-master.network')
2899 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
2901 output
= check_output('bridge vlan show dev test1')
2903 self
.assertNotRegex(output
, '4063')
2904 for i
in range(4064, 4095):
2905 self
.assertRegex(output
, f
'{i}')
2906 self
.assertNotRegex(output
, '4095')
2908 output
= check_output('bridge vlan show dev bridge99')
2910 self
.assertNotRegex(output
, '4059')
2911 for i
in range(4060, 4095):
2912 self
.assertRegex(output
, f
'{i}')
2913 self
.assertNotRegex(output
, '4095')
2915 def test_bridge_mdb(self
):
2916 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-mdb-slave.network',
2917 '26-bridge.netdev', '26-bridge-mdb-master.network')
2919 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
2921 output
= check_output('bridge mdb show dev bridge99')
2923 self
.assertRegex(output
, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064')
2924 self
.assertRegex(output
, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065')
2926 def test_bridge_property(self
):
2927 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2928 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2931 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2933 output
= check_output('ip -d link show test1')
2935 self
.assertRegex(output
, 'master')
2936 self
.assertRegex(output
, 'bridge')
2938 output
= check_output('ip -d link show dummy98')
2940 self
.assertRegex(output
, 'master')
2941 self
.assertRegex(output
, 'bridge')
2943 output
= check_output('ip addr show bridge99')
2945 self
.assertRegex(output
, '192.168.0.15/24')
2947 output
= check_output('bridge -d link show dummy98')
2949 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
2950 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
2951 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
2952 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
2953 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
2954 # CONFIG_BRIDGE_IGMP_SNOOPING=y
2955 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
2956 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
2957 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
2958 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
2959 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
2960 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'priority'), '23')
2961 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard'), '1')
2962 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'root_block'), '1')
2964 output
= check_output('bridge -d link show test1')
2966 self
.assertEqual(read_bridge_port_attr('bridge99', 'test1', 'priority'), '0')
2968 check_output('ip address add 192.168.0.16/24 dev bridge99')
2971 output
= check_output('ip addr show bridge99')
2973 self
.assertRegex(output
, '192.168.0.16/24')
2976 print('### ip -6 route list table all dev bridge99')
2977 output
= check_output('ip -6 route list table all dev bridge99')
2979 self
.assertRegex(output
, 'ff00::/8 table local metric 256 pref medium')
2981 self
.assertEqual(call('ip link del test1'), 0)
2983 self
.wait_operstate('bridge99', 'degraded-carrier')
2985 check_output('ip link del dummy98')
2987 self
.wait_operstate('bridge99', 'no-carrier')
2989 output
= check_output('ip address show bridge99')
2991 self
.assertRegex(output
, 'NO-CARRIER')
2992 self
.assertNotRegex(output
, '192.168.0.15/24')
2993 self
.assertNotRegex(output
, '192.168.0.16/24')
2995 print('### ip -6 route list table all dev bridge99')
2996 output
= check_output('ip -6 route list table all dev bridge99')
2998 self
.assertRegex(output
, 'ff00::/8 table local metric 256 (linkdown )?pref medium')
3000 def test_bridge_configure_without_carrier(self
):
3001 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-configure-without-carrier.network',
3005 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
3006 for test
in ['no-slave', 'add-slave', 'slave-up', 'slave-no-carrier', 'slave-carrier', 'slave-down']:
3007 with self
.subTest(test
=test
):
3008 if test
== 'no-slave':
3009 # bridge has no slaves; it's up but *might* not have carrier
3010 self
.wait_operstate('bridge99', operstate
=r
'(no-carrier|routable)', setup_state
=None, setup_timeout
=30)
3011 # due to a bug in the kernel, newly-created bridges are brought up
3012 # *with* carrier, unless they have had any setting changed; e.g.
3013 # their mac set, priority set, etc. Then, they will lose carrier
3014 # as soon as a (down) slave interface is added, and regain carrier
3015 # again once the slave interface is brought up.
3016 #self.check_link_attr('bridge99', 'carrier', '0')
3017 elif test
== 'add-slave':
3018 # add slave to bridge, but leave it down; bridge is definitely no-carrier
3019 self
.check_link_attr('test1', 'operstate', 'down')
3020 check_output('ip link set dev test1 master bridge99')
3021 self
.wait_operstate('bridge99', operstate
='no-carrier', setup_state
=None)
3022 self
.check_link_attr('bridge99', 'carrier', '0')
3023 elif test
== 'slave-up':
3024 # bring up slave, which will have carrier; bridge gains carrier
3025 check_output('ip link set dev test1 up')
3026 self
.wait_online(['bridge99:routable'])
3027 self
.check_link_attr('bridge99', 'carrier', '1')
3028 elif test
== 'slave-no-carrier':
3029 # drop slave carrier; bridge loses carrier
3030 check_output('ip link set dev test1 carrier off')
3031 self
.wait_online(['bridge99:no-carrier:no-carrier'])
3032 self
.check_link_attr('bridge99', 'carrier', '0')
3033 elif test
== 'slave-carrier':
3034 # restore slave carrier; bridge gains carrier
3035 check_output('ip link set dev test1 carrier on')
3036 self
.wait_online(['bridge99:routable'])
3037 self
.check_link_attr('bridge99', 'carrier', '1')
3038 elif test
== 'slave-down':
3039 # bring down slave; bridge loses carrier
3040 check_output('ip link set dev test1 down')
3041 self
.wait_online(['bridge99:no-carrier:no-carrier'])
3042 self
.check_link_attr('bridge99', 'carrier', '0')
3044 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
3045 self
.assertRegex(output
, '10.1.2.3')
3046 self
.assertRegex(output
, '10.1.2.1')
3048 def test_bridge_ignore_carrier_loss(self
):
3049 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
3050 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
3051 'bridge99-ignore-carrier-loss.network')
3053 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
3055 check_output('ip address add 192.168.0.16/24 dev bridge99')
3058 check_output('ip link del test1')
3059 check_output('ip link del dummy98')
3062 output
= check_output('ip address show bridge99')
3064 self
.assertRegex(output
, 'NO-CARRIER')
3065 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
3066 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
3068 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
3069 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
3070 'bridge99-ignore-carrier-loss.network')
3072 self
.wait_online(['bridge99:no-carrier'])
3074 for trial
in range(4):
3075 check_output('ip link add dummy98 type dummy')
3076 check_output('ip link set dummy98 up')
3078 check_output('ip link del dummy98')
3080 self
.wait_online(['bridge99:routable', 'dummy98:enslaved'])
3082 output
= check_output('ip address show bridge99')
3084 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
3086 output
= check_output('ip rule list table 100')
3088 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
3090 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
3094 '23-emit-lldp.network',
3099 remove_links(self
.links
)
3100 stop_networkd(show_logs
=False)
3103 remove_links(self
.links
)
3104 remove_unit_from_networkd_path(self
.units
)
3105 stop_networkd(show_logs
=True)
3107 def test_lldp(self
):
3108 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
3110 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
3112 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
3114 self
.assertRegex(output
, 'veth-peer')
3115 self
.assertRegex(output
, 'veth99')
3117 class NetworkdRATests(unittest
.TestCase
, Utilities
):
3122 'ipv6-prefix.network',
3123 'ipv6-prefix-veth.network',
3124 'ipv6-prefix-veth-token-static.network',
3125 'ipv6-prefix-veth-token-prefixstable.network',
3126 'ipv6-prefix-veth-token-prefixstable-without-address.network']
3129 remove_links(self
.links
)
3130 stop_networkd(show_logs
=False)
3133 remove_links(self
.links
)
3134 remove_unit_from_networkd_path(self
.units
)
3135 stop_networkd(show_logs
=True)
3137 def test_ipv6_prefix_delegation(self
):
3138 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
3140 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3142 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3144 self
.assertRegex(output
, 'fe80::')
3145 self
.assertRegex(output
, '2002:da8:1::1')
3147 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3149 self
.assertRegex(output
, '2002:da8:1:0')
3151 def test_ipv6_token_static(self
):
3152 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static.network')
3154 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3156 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3158 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
3159 self
.assertRegex(output
, '2002:da8:1:0:fa:de:ca:fe')
3160 self
.assertRegex(output
, '2002:da8:2:0:1a:2b:3c:4d')
3161 self
.assertRegex(output
, '2002:da8:2:0:fa:de:ca:fe')
3163 def test_ipv6_token_prefixstable(self
):
3164 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable.network')
3166 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3168 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3170 self
.assertRegex(output
, '2002:da8:1:0')
3171 self
.assertRegex(output
, '2002:da8:2:0.*78:9abc') # EUI
3173 def test_ipv6_token_prefixstable_without_address(self
):
3174 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable-without-address.network')
3176 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3178 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3180 self
.assertRegex(output
, '2002:da8:1:0')
3181 self
.assertRegex(output
, '2002:da8:2:0')
3183 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
3188 'dhcp-client.network',
3189 'dhcp-client-timezone-router.network',
3190 'dhcp-server.network',
3191 'dhcp-server-timezone-router.network']
3194 remove_links(self
.links
)
3195 stop_networkd(show_logs
=False)
3198 remove_links(self
.links
)
3199 remove_unit_from_networkd_path(self
.units
)
3200 stop_networkd(show_logs
=True)
3202 def test_dhcp_server(self
):
3203 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
3205 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3207 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3209 self
.assertRegex(output
, '192.168.5.*')
3210 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
3211 self
.assertRegex(output
, 'DNS: 192.168.5.1')
3212 self
.assertRegex(output
, 'NTP: 192.168.5.1')
3214 def test_emit_router_timezone(self
):
3215 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
3217 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3219 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3221 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
3222 self
.assertRegex(output
, '192.168.5.*')
3223 self
.assertRegex(output
, 'Europe/Berlin')
3225 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
3234 'dhcp-client-anonymize.network',
3235 'dhcp-client-decline.network',
3236 'dhcp-client-gateway-ipv4.network',
3237 'dhcp-client-gateway-ipv6.network',
3238 'dhcp-client-gateway-onlink-implicit.network',
3239 'dhcp-client-ipv4-dhcp-settings.network',
3240 'dhcp-client-ipv4-only-ipv6-disabled.network',
3241 'dhcp-client-ipv4-only.network',
3242 'dhcp-client-ipv4-use-routes-use-gateway.network',
3243 'dhcp-client-ipv6-only.network',
3244 'dhcp-client-ipv6-rapid-commit.network',
3245 'dhcp-client-keep-configuration-dhcp-on-stop.network',
3246 'dhcp-client-keep-configuration-dhcp.network',
3247 'dhcp-client-listen-port.network',
3248 'dhcp-client-reassign-static-routes-ipv4.network',
3249 'dhcp-client-reassign-static-routes-ipv6.network',
3250 'dhcp-client-route-metric.network',
3251 'dhcp-client-route-table.network',
3252 'dhcp-client-use-dns-ipv4-and-ra.network',
3253 'dhcp-client-use-dns-ipv4.network',
3254 'dhcp-client-use-dns-no.network',
3255 'dhcp-client-use-dns-yes.network',
3256 'dhcp-client-use-domains.network',
3257 'dhcp-client-vrf.network',
3258 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
3259 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
3260 'dhcp-client-with-static-address.network',
3261 'dhcp-client.network',
3262 'dhcp-server-decline.network',
3263 'dhcp-server-veth-peer.network',
3264 'dhcp-v4-server-veth-peer.network',
3268 stop_dnsmasq(dnsmasq_pid_file
)
3269 remove_links(self
.links
)
3270 stop_networkd(show_logs
=False)
3273 stop_dnsmasq(dnsmasq_pid_file
)
3276 remove_links(self
.links
)
3277 remove_unit_from_networkd_path(self
.units
)
3278 stop_networkd(show_logs
=True)
3280 def test_dhcp_client_ipv6_only(self
):
3281 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3284 self
.wait_online(['veth-peer:carrier'])
3286 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3288 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3290 self
.assertRegex(output
, '2600::')
3291 self
.assertNotRegex(output
, '192.168.5')
3293 output
= check_output('ip addr show dev veth99')
3295 self
.assertRegex(output
, '2600::')
3296 self
.assertNotRegex(output
, '192.168.5')
3297 self
.assertNotRegex(output
, 'tentative')
3299 # Confirm that ipv6 token is not set in the kernel
3300 output
= check_output('ip token show dev veth99')
3302 self
.assertRegex(output
, 'token :: dev veth99')
3304 def test_dhcp_client_ipv4_only(self
):
3305 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
3308 self
.wait_online(['veth-peer:carrier'])
3309 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
3310 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3312 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3314 self
.assertNotRegex(output
, '2600::')
3315 self
.assertRegex(output
, '192.168.5')
3316 self
.assertRegex(output
, '192.168.5.6')
3317 self
.assertRegex(output
, '192.168.5.7')
3319 # checking routes to DNS servers
3320 output
= check_output('ip route show dev veth99')
3322 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3323 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3324 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3326 stop_dnsmasq(dnsmasq_pid_file
)
3327 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8', lease_time
='2m')
3329 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3330 print('Wait for the dynamic address to be renewed')
3333 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3335 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3337 self
.assertNotRegex(output
, '2600::')
3338 self
.assertRegex(output
, '192.168.5')
3339 self
.assertNotRegex(output
, '192.168.5.6')
3340 self
.assertRegex(output
, '192.168.5.7')
3341 self
.assertRegex(output
, '192.168.5.8')
3343 # checking routes to DNS servers
3344 output
= check_output('ip route show dev veth99')
3346 self
.assertNotRegex(output
, r
'192.168.5.6')
3347 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3348 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3349 self
.assertRegex(output
, r
'192.168.5.8 proto dhcp scope link src 192.168.5.181 metric 1024')
3351 def test_dhcp_client_ipv4_use_routes_gateway(self
):
3352 for (routes
, gateway
, dnsroutes
) in itertools
.product([True, False, None], repeat
=3):
3354 with self
.subTest(routes
=routes
, gateway
=gateway
, dnsroutes
=dnsroutes
):
3355 self
._test
_dhcp
_client
_ipv
4_use
_routes
_gateway
(routes
, gateway
, dnsroutes
)
3358 def _test_dhcp_client_ipv4_use_routes_gateway(self
, routes
, gateway
, dnsroutes
):
3359 testunit
= 'dhcp-client-ipv4-use-routes-use-gateway.network'
3360 testunits
= ['25-veth.netdev', 'dhcp-server-veth-peer.network', testunit
]
3362 testunits
.append(f
'{testunit}.d/use-routes-{routes}.conf');
3364 testunits
.append(f
'{testunit}.d/use-gateway-{gateway}.conf');
3365 if dnsroutes
!= None:
3366 testunits
.append(f
'{testunit}.d/use-dns-routes-{dnsroutes}.conf');
3367 copy_unit_to_networkd_unit_path(*testunits
, dropins
=False)
3370 self
.wait_online(['veth-peer:carrier'])
3371 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
3372 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3374 output
= check_output('ip route show dev veth99')
3377 # UseRoutes= defaults to true
3378 useroutes
= routes
in [True, None]
3379 # UseGateway= defaults to useroutes
3380 usegateway
= useroutes
if gateway
== None else gateway
3384 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.181 metric 1024')
3386 self
.assertNotRegex(output
, r
'192.168.5.5')
3390 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.181 metric 1024')
3392 self
.assertNotRegex(output
, r
'default via 192.168.5.1')
3394 # Check RoutesToDNS=, which defaults to false
3396 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3397 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3399 self
.assertNotRegex(output
, r
'192.168.5.6')
3400 self
.assertNotRegex(output
, r
'192.168.5.7')
3402 def test_dhcp_client_ipv4_ipv6(self
):
3403 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
3404 'dhcp-client-ipv4-only.network')
3406 self
.wait_online(['veth-peer:carrier'])
3408 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3410 # link become 'routable' when at least one protocol provide an valid address.
3411 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3412 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3414 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3416 self
.assertRegex(output
, '2600::')
3417 self
.assertRegex(output
, '192.168.5')
3419 def test_dhcp_client_settings(self
):
3420 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
3423 self
.wait_online(['veth-peer:carrier'])
3425 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3427 print('## ip address show dev veth99')
3428 output
= check_output('ip address show dev veth99')
3430 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3431 self
.assertRegex(output
, '192.168.5')
3432 self
.assertRegex(output
, '1492')
3434 print('## ip route show table main dev veth99')
3435 output
= check_output('ip route show table main dev veth99')
3438 main_table_is_empty
= output
== ''
3439 if not main_table_is_empty
:
3440 self
.assertNotRegex(output
, 'proto dhcp')
3442 print('## ip route show table 211 dev veth99')
3443 output
= check_output('ip route show table 211 dev veth99')
3445 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
3446 if main_table_is_empty
:
3447 self
.assertRegex(output
, '192.168.5.0/24 proto dhcp')
3448 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
3449 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
3451 print('## dnsmasq log')
3452 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
3453 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
3454 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
3455 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
3457 def test_dhcp6_client_settings_rapidcommit_true(self
):
3458 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3460 self
.wait_online(['veth-peer:carrier'])
3462 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3464 output
= check_output('ip address show dev veth99')
3466 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3467 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
3469 def test_dhcp6_client_settings_rapidcommit_false(self
):
3470 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
3472 self
.wait_online(['veth-peer:carrier'])
3474 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3476 output
= check_output('ip address show dev veth99')
3478 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3479 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
3481 def test_dhcp_client_settings_anonymize(self
):
3482 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
3484 self
.wait_online(['veth-peer:carrier'])
3486 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3488 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
3489 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
3490 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
3492 def test_dhcp_client_listen_port(self
):
3493 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
3495 self
.wait_online(['veth-peer:carrier'])
3496 start_dnsmasq('--dhcp-alternate-port=67,5555')
3497 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3499 output
= check_output('ip -4 address show dev veth99')
3501 self
.assertRegex(output
, '192.168.5.* dynamic')
3503 def test_dhcp_client_with_static_address(self
):
3504 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
3505 'dhcp-client-with-static-address.network')
3507 self
.wait_online(['veth-peer:carrier'])
3509 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3511 output
= check_output('ip address show dev veth99 scope global')
3513 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
3514 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
3516 output
= check_output('ip route show dev veth99')
3518 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
3519 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
3520 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
3521 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
3523 def test_dhcp_route_table_id(self
):
3524 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
3526 self
.wait_online(['veth-peer:carrier'])
3528 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3530 output
= check_output('ip route show table 12')
3532 self
.assertRegex(output
, 'veth99 proto dhcp')
3533 self
.assertRegex(output
, '192.168.5.1')
3535 def test_dhcp_route_metric(self
):
3536 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
3538 self
.wait_online(['veth-peer:carrier'])
3540 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3542 output
= check_output('ip route show dev veth99')
3544 self
.assertRegex(output
, 'metric 24')
3546 def test_dhcp_client_reassign_static_routes_ipv4(self
):
3547 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3548 'dhcp-client-reassign-static-routes-ipv4.network')
3550 self
.wait_online(['veth-peer:carrier'])
3551 start_dnsmasq(lease_time
='2m')
3552 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3554 output
= check_output('ip address show dev veth99 scope global')
3556 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3558 output
= check_output('ip route show dev veth99')
3560 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3561 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3562 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3563 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3565 stop_dnsmasq(dnsmasq_pid_file
)
3566 start_dnsmasq(ipv4_range
='192.168.5.210,192.168.5.220', lease_time
='2m')
3568 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3569 print('Wait for the dynamic address to be renewed')
3572 self
.wait_online(['veth99:routable'])
3574 output
= check_output('ip route show dev veth99')
3576 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3577 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3578 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3579 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3581 def test_dhcp_client_reassign_static_routes_ipv6(self
):
3582 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3583 'dhcp-client-reassign-static-routes-ipv6.network')
3585 self
.wait_online(['veth-peer:carrier'])
3586 start_dnsmasq(lease_time
='2m')
3587 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3589 output
= check_output('ip address show dev veth99 scope global')
3591 self
.assertRegex(output
, r
'inet6 2600::[0-9a-f]*/128 scope global (noprefixroute dynamic|dynamic noprefixroute)')
3593 output
= check_output('ip -6 route show dev veth99')
3595 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3596 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3598 stop_dnsmasq(dnsmasq_pid_file
)
3599 start_dnsmasq(ipv6_range
='2600::30,2600::40', lease_time
='2m')
3601 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3602 print('Wait for the dynamic address to be renewed')
3605 self
.wait_online(['veth99:routable'])
3607 output
= check_output('ip -6 route show dev veth99')
3609 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3610 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3612 def test_dhcp_keep_configuration_dhcp(self
):
3613 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
3615 self
.wait_online(['veth-peer:carrier'])
3616 start_dnsmasq(lease_time
='2m')
3617 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3619 output
= check_output('ip address show dev veth99 scope global')
3621 self
.assertRegex(output
, r
'192.168.5.*')
3623 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3625 self
.assertRegex(output
, r
'192.168.5.*')
3627 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
3628 stop_dnsmasq(dnsmasq_pid_file
)
3630 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3631 print('Wait for the dynamic address to be expired')
3634 print('The lease address should be kept after lease expired')
3635 output
= check_output('ip address show dev veth99 scope global')
3637 self
.assertRegex(output
, r
'192.168.5.*')
3639 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3641 self
.assertRegex(output
, r
'192.168.5.*')
3643 check_output('systemctl stop systemd-networkd.socket')
3644 check_output('systemctl stop systemd-networkd.service')
3646 print('The lease address should be kept after networkd stopped')
3647 output
= check_output('ip address show dev veth99 scope global')
3649 self
.assertRegex(output
, r
'192.168.5.*')
3651 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3653 self
.assertRegex(output
, r
'192.168.5.*')
3656 self
.wait_online(['veth-peer:routable'])
3658 print('Still the lease address should be kept after networkd restarted')
3659 output
= check_output('ip address show dev veth99 scope global')
3661 self
.assertRegex(output
, r
'192.168.5.*')
3663 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3665 self
.assertRegex(output
, r
'192.168.5.*')
3667 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
3668 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
3670 self
.wait_online(['veth-peer:carrier'])
3671 start_dnsmasq(lease_time
='2m')
3672 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3674 output
= check_output('ip address show dev veth99 scope global')
3676 self
.assertRegex(output
, r
'192.168.5.*')
3678 stop_dnsmasq(dnsmasq_pid_file
)
3679 check_output('systemctl stop systemd-networkd.socket')
3680 check_output('systemctl stop systemd-networkd.service')
3682 output
= check_output('ip address show dev veth99 scope global')
3684 self
.assertRegex(output
, r
'192.168.5.*')
3687 self
.wait_online(['veth-peer:routable'])
3689 output
= check_output('ip address show dev veth99 scope global')
3691 self
.assertNotRegex(output
, r
'192.168.5.*')
3693 def test_dhcp_client_reuse_address_as_static(self
):
3694 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
3696 self
.wait_online(['veth-peer:carrier'])
3698 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3700 # link become 'routable' when at least one protocol provide an valid address.
3701 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3702 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3704 output
= check_output('ip address show dev veth99 scope global')
3706 self
.assertRegex(output
, '192.168.5')
3707 self
.assertRegex(output
, '2600::')
3709 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
3710 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
3711 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
3712 print(static_network
)
3714 remove_unit_from_networkd_path(['dhcp-client.network'])
3716 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
3717 f
.write(static_network
)
3719 # When networkd started, the links are already configured, so let's wait for 5 seconds
3720 # the links to be re-configured.
3722 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3724 output
= check_output('ip -4 address show dev veth99 scope global')
3726 self
.assertRegex(output
, '192.168.5')
3727 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3729 output
= check_output('ip -6 address show dev veth99 scope global')
3731 self
.assertRegex(output
, '2600::')
3732 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3734 @expectedFailureIfModuleIsNotAvailable('vrf')
3735 def test_dhcp_client_vrf(self
):
3736 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
3737 '25-vrf.netdev', '25-vrf.network')
3739 self
.wait_online(['veth-peer:carrier'])
3741 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
3743 # link become 'routable' when at least one protocol provide an valid address.
3744 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3745 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3747 print('## ip -d link show dev vrf99')
3748 output
= check_output('ip -d link show dev vrf99')
3750 self
.assertRegex(output
, 'vrf table 42')
3752 print('## ip address show vrf vrf99')
3753 output
= check_output('ip address show vrf vrf99')
3755 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3756 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3757 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3758 self
.assertRegex(output
, 'inet6 .* scope link')
3760 print('## ip address show dev veth99')
3761 output
= check_output('ip address show dev veth99')
3763 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3764 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3765 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3766 self
.assertRegex(output
, 'inet6 .* scope link')
3768 print('## ip route show vrf vrf99')
3769 output
= check_output('ip route show vrf vrf99')
3771 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
3772 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
3773 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
3774 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
3775 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
3777 print('## ip route show table main dev veth99')
3778 output
= check_output('ip route show table main dev veth99')
3780 self
.assertEqual(output
, '')
3782 def test_dhcp_client_gateway_ipv4(self
):
3783 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3784 'dhcp-client-gateway-ipv4.network')
3786 self
.wait_online(['veth-peer:carrier'])
3788 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3790 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3792 self
.assertRegex(output
, '10.0.0.0/8 via 192.168.5.1 proto static')
3794 def test_dhcp_client_gateway_ipv6(self
):
3795 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3796 'dhcp-client-gateway-ipv6.network')
3798 self
.wait_online(['veth-peer:carrier'])
3800 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3802 output
= check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
3804 self
.assertRegex(output
, 'via fe80::1034:56ff:fe78:9abd')
3806 def test_dhcp_client_gateway_onlink_implicit(self
):
3807 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3808 'dhcp-client-gateway-onlink-implicit.network')
3810 self
.wait_online(['veth-peer:carrier'])
3812 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3814 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3816 self
.assertRegex(output
, '192.168.5')
3818 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3820 self
.assertRegex(output
, 'onlink')
3821 output
= check_output('ip route list dev veth99 192.168.100.0/24')
3823 self
.assertRegex(output
, 'onlink')
3825 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
3826 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3827 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
3829 self
.wait_online(['veth-peer:carrier'])
3830 start_dnsmasq(lease_time
='2m')
3831 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3833 output
= check_output('ip address show dev veth99')
3836 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3837 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3838 output
= check_output('ip -6 address show dev veth99 scope link')
3839 self
.assertRegex(output
, 'inet6 .* scope link')
3840 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3841 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3842 output
= check_output('ip -4 address show dev veth99 scope link')
3843 self
.assertNotRegex(output
, 'inet .* scope link')
3845 print('Wait for the dynamic address to be expired')
3848 output
= check_output('ip address show dev veth99')
3851 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3852 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3853 output
= check_output('ip -6 address show dev veth99 scope link')
3854 self
.assertRegex(output
, 'inet6 .* scope link')
3855 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3856 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3857 output
= check_output('ip -4 address show dev veth99 scope link')
3858 self
.assertNotRegex(output
, 'inet .* scope link')
3860 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
3862 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
3863 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3864 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
3866 self
.wait_online(['veth99:degraded', 'veth-peer:routable'])
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
.assertNotRegex(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
.assertRegex(output
, 'inet .* scope link')
3880 def test_dhcp_client_route_remove_on_renew(self
):
3881 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3882 'dhcp-client-ipv4-only-ipv6-disabled.network')
3884 self
.wait_online(['veth-peer:carrier'])
3885 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
3886 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3888 # test for issue #12490
3890 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3892 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3894 for line
in output
.splitlines():
3895 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3896 address1
= line
.split()[1].split('/')[0]
3899 output
= check_output('ip -4 route show dev veth99')
3901 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3902 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3904 stop_dnsmasq(dnsmasq_pid_file
)
3905 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
3907 print('Wait for the dynamic address to be expired')
3910 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3912 self
.assertRegex(output
, 'inet 192.168.5.2[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 address2
= line
.split()[1].split('/')[0]
3919 self
.assertNotEqual(address1
, address2
)
3921 output
= check_output('ip -4 route show dev veth99')
3923 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3924 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3925 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
3926 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
3928 def test_dhcp_client_use_dns_yes(self
):
3929 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-yes.network')
3932 self
.wait_online(['veth-peer:carrier'])
3933 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3934 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3936 # link become 'routable' when at least one protocol provide an valid address.
3937 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3938 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3941 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3943 self
.assertRegex(output
, '192.168.5.1')
3944 self
.assertRegex(output
, '2600::1')
3946 def test_dhcp_client_use_dns_no(self
):
3947 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-no.network')
3950 self
.wait_online(['veth-peer:carrier'])
3951 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3952 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3954 # link become 'routable' when at least one protocol provide an valid address.
3955 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3956 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3959 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3961 self
.assertNotRegex(output
, '192.168.5.1')
3962 self
.assertNotRegex(output
, '2600::1')
3964 def test_dhcp_client_use_dns_ipv4(self
):
3965 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4.network')
3968 self
.wait_online(['veth-peer:carrier'])
3969 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3970 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3972 # link become 'routable' when at least one protocol provide an valid address.
3973 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3974 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3977 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3979 self
.assertRegex(output
, '192.168.5.1')
3980 self
.assertNotRegex(output
, '2600::1')
3982 def test_dhcp_client_use_dns_ipv4_and_ra(self
):
3983 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4-and-ra.network')
3986 self
.wait_online(['veth-peer:carrier'])
3987 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3988 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3990 # link become 'routable' when at least one protocol provide an valid address.
3991 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3992 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3995 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3997 self
.assertRegex(output
, '192.168.5.1')
3998 self
.assertRegex(output
, '2600::1')
4000 def test_dhcp_client_use_domains(self
):
4001 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-domains.network')
4004 self
.wait_online(['veth-peer:carrier'])
4005 start_dnsmasq('--dhcp-option=option:domain-search,example.com')
4006 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4008 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4010 self
.assertRegex(output
, 'Search Domains: example.com')
4013 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
4015 self
.assertRegex(output
, 'example.com')
4017 def test_dhcp_client_decline(self
):
4018 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-decline.network', 'dhcp-client-decline.network')
4021 self
.wait_online(['veth-peer:carrier'])
4022 rc
= call(*wait_online_cmd
, '--timeout=10s', '--interface=veth99:routable', env
=env
)
4023 self
.assertTrue(rc
== 1)
4025 class NetworkdIPv6PrefixTests(unittest
.TestCase
, Utilities
):
4030 'ipv6ra-prefix-client.network',
4031 'ipv6ra-prefix.network'
4035 remove_links(self
.links
)
4036 stop_networkd(show_logs
=False)
4040 remove_links(self
.links
)
4041 remove_unit_from_networkd_path(self
.units
)
4042 stop_networkd(show_logs
=True)
4044 def test_ipv6_route_prefix(self
):
4045 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client.network', 'ipv6ra-prefix.network')
4048 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4050 output
= check_output('ip -6 route show dev veth-peer')
4052 self
.assertRegex(output
, '2001:db8:0:1::/64 proto ra')
4054 output
= check_output('ip addr show dev veth99')
4056 self
.assertNotRegex(output
, '2001:db8:0:1')
4057 self
.assertRegex(output
, '2001:db8:0:2')
4059 class NetworkdMTUTests(unittest
.TestCase
, Utilities
):
4064 '12-dummy-mtu.netdev',
4065 '12-dummy-mtu.link',
4070 remove_links(self
.links
)
4071 stop_networkd(show_logs
=False)
4075 remove_links(self
.links
)
4076 remove_unit_from_networkd_path(self
.units
)
4077 stop_networkd(show_logs
=True)
4079 def check_mtu(self
, mtu
, ipv6_mtu
=None, reset
=True):
4085 self
.wait_online(['dummy98:routable'])
4086 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
4087 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
4089 # test normal restart
4091 self
.wait_online(['dummy98:routable'])
4092 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
4093 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
4096 self
.reset_check_mtu(mtu
, ipv6_mtu
)
4098 def reset_check_mtu(self
, mtu
, ipv6_mtu
=None):
4099 ''' test setting mtu/ipv6_mtu with interface already up '''
4102 # note - changing the device mtu resets the ipv6 mtu
4103 run('ip link set up mtu 1501 dev dummy98')
4104 run('ip link set up mtu 1500 dev dummy98')
4105 self
.assertEqual(read_link_attr('dummy98', 'mtu'), '1500')
4106 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), '1500')
4108 self
.check_mtu(mtu
, ipv6_mtu
, reset
=False)
4110 def test_mtu_network(self
):
4111 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
4112 self
.check_mtu('1600')
4114 def test_mtu_netdev(self
):
4115 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network', dropins
=False)
4116 # note - MTU set by .netdev happens ONLY at device creation!
4117 self
.check_mtu('1600', reset
=False)
4119 def test_mtu_link(self
):
4120 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', dropins
=False)
4121 # must reload udev because it only picks up new files after 3 second delay
4122 call('udevadm control --reload')
4123 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
4124 self
.check_mtu('1600', reset
=False)
4126 def test_ipv6_mtu(self
):
4127 ''' set ipv6 mtu without setting device mtu '''
4128 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
4129 self
.check_mtu('1500', '1400')
4131 def test_ipv6_mtu_toolarge(self
):
4132 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
4133 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
4134 self
.check_mtu('1500', '1500')
4136 def test_mtu_network_ipv6_mtu(self
):
4137 ''' set ipv6 mtu and set device mtu via network file '''
4138 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
4139 self
.check_mtu('1600', '1550')
4141 def test_mtu_netdev_ipv6_mtu(self
):
4142 ''' set ipv6 mtu and set device mtu via netdev file '''
4143 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
4144 self
.check_mtu('1600', '1550', reset
=False)
4146 def test_mtu_link_ipv6_mtu(self
):
4147 ''' set ipv6 mtu and set device mtu via link file '''
4148 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
4149 # must reload udev because it only picks up new files after 3 second delay
4150 call('udevadm control --reload')
4151 self
.check_mtu('1600', '1550', reset
=False)
4154 if __name__
== '__main__':
4155 parser
= argparse
.ArgumentParser()
4156 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
4157 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
4158 parser
.add_argument('--resolved', help='Path to systemd-resolved', dest
='resolved_bin')
4159 parser
.add_argument('--udevd', help='Path to systemd-udevd', dest
='udevd_bin')
4160 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
4161 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
4162 parser
.add_argument('--resolvectl', help='Path to resolvectl', dest
='resolvectl_bin')
4163 parser
.add_argument('--timedatectl', help='Path to timedatectl', dest
='timedatectl_bin')
4164 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
4165 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
4166 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
4167 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
4168 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
4169 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
4172 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
:
4173 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
4174 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
4175 resolved_bin
= os
.path
.join(ns
.build_dir
, 'systemd-resolved')
4176 udevd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-udevd')
4177 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
4178 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
4179 resolvectl_bin
= os
.path
.join(ns
.build_dir
, 'resolvectl')
4180 timedatectl_bin
= os
.path
.join(ns
.build_dir
, 'timedatectl')
4183 networkd_bin
= ns
.networkd_bin
4185 resolved_bin
= ns
.resolved_bin
4187 udevd_bin
= ns
.udevd_bin
4188 if ns
.wait_online_bin
:
4189 wait_online_bin
= ns
.wait_online_bin
4190 if ns
.networkctl_bin
:
4191 networkctl_bin
= ns
.networkctl_bin
4192 if ns
.resolvectl_bin
:
4193 resolvectl_bin
= ns
.resolvectl_bin
4194 if ns
.timedatectl_bin
:
4195 timedatectl_bin
= ns
.timedatectl_bin
4197 use_valgrind
= ns
.use_valgrind
4198 enable_debug
= ns
.enable_debug
4199 asan_options
= ns
.asan_options
4200 lsan_options
= ns
.lsan_options
4201 ubsan_options
= ns
.ubsan_options
4204 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
4205 resolvectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin
]
4206 timedatectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin
]
4207 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
4209 networkctl_cmd
= [networkctl_bin
]
4210 resolvectl_cmd
= [resolvectl_bin
]
4211 timedatectl_cmd
= [timedatectl_bin
]
4212 wait_online_cmd
= [wait_online_bin
]
4215 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
4217 env
.update({ 'ASAN_OPTIONS' : asan_options
})
4219 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
4221 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
4224 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,