2 # SPDX-License-Identifier: LGPL-2.1-or-later
3 # systemd-networkd tests
15 from shutil
import copytree
17 network_unit_file_path
='/run/systemd/network'
18 networkd_runtime_directory
='/run/systemd/netif'
19 networkd_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 expectedFailureIfRTA_VIAIsNotSupported():
151 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
152 call('ip link set up dev dummy98', stderr
=subprocess
.DEVNULL
)
153 call('ip route add 2001:1234:5:8fff:ff:ff:ff:fe/128 dev dummy98', stderr
=subprocess
.DEVNULL
)
154 rc
= call('ip route add 10.10.10.10 via inet6 2001:1234:5:8fff:ff:ff:ff:fe dev dummy98', stderr
=subprocess
.DEVNULL
)
155 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
159 return unittest
.expectedFailure(func
)
163 def expectedFailureIfAlternativeNameIsNotAvailable():
165 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
166 rc
= call('ip link prop add dev dummy98 altname hogehogehogehogehoge', stderr
=subprocess
.DEVNULL
)
167 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
171 return unittest
.expectedFailure(func
)
175 def expectedFailureIfNetdevsimWithSRIOVIsNotAvailable():
177 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
178 rc
= call('modprobe netdevsim', stderr
=subprocess
.DEVNULL
)
180 return unittest
.expectedFailure(func
)
183 with
open('/sys/bus/netdevsim/new_device', mode
='w') as f
:
185 except Exception as error
:
186 return unittest
.expectedFailure(func
)
188 call('udevadm settle')
189 call('udevadm info -w10s /sys/devices/netdevsim99/net/eni99np1', stderr
=subprocess
.DEVNULL
)
191 with
open('/sys/class/net/eni99np1/device/sriov_numvfs', mode
='w') as f
:
193 except Exception as error
:
194 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
195 return unittest
.expectedFailure(func
)
197 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
202 def expectedFailureIfCAKEIsNotAvailable():
204 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
205 rc
= call('tc qdisc add dev dummy98 parent root cake', stderr
=subprocess
.DEVNULL
)
206 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
210 return unittest
.expectedFailure(func
)
214 def expectedFailureIfPIEIsNotAvailable():
216 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
217 rc
= call('tc qdisc add dev dummy98 parent root pie', stderr
=subprocess
.DEVNULL
)
218 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
222 return unittest
.expectedFailure(func
)
226 def expectedFailureIfHHFIsNotAvailable():
228 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
229 rc
= call('tc qdisc add dev dummy98 parent root hhf', stderr
=subprocess
.DEVNULL
)
230 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
234 return unittest
.expectedFailure(func
)
238 def expectedFailureIfETSIsNotAvailable():
240 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
241 rc
= call('tc qdisc add dev dummy98 parent root ets bands 10', stderr
=subprocess
.DEVNULL
)
242 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
246 return unittest
.expectedFailure(func
)
250 def expectedFailureIfFQPIEIsNotAvailable():
252 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
253 rc
= call('tc qdisc add dev dummy98 parent root fq_pie', stderr
=subprocess
.DEVNULL
)
254 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
258 return unittest
.expectedFailure(func
)
265 os
.makedirs(network_unit_file_path
, exist_ok
=True)
266 os
.makedirs(networkd_ci_path
, exist_ok
=True)
268 shutil
.rmtree(networkd_ci_path
)
269 copytree(os
.path
.join(os
.path
.dirname(os
.path
.abspath(__file__
)), 'conf'), networkd_ci_path
)
271 for u
in ['systemd-networkd.socket', 'systemd-networkd.service', 'systemd-resolved.service',
272 'systemd-udevd-kernel.socket', 'systemd-udevd-control.socket', 'systemd-udevd.service',
273 'firewalld.service']:
274 if call(f
'systemctl is-active --quiet {u}') == 0:
275 check_output(f
'systemctl stop {u}')
276 running_units
.append(u
)
280 'StartLimitIntervalSec=0',
287 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin
,
291 drop_in
+= ['ExecStart=!!' + networkd_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-networkd.service.d', exist_ok
=True)
306 with
open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode
='w') as f
:
307 f
.write('\n'.join(drop_in
))
315 drop_in
+= ['ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + resolved_bin
]
317 drop_in
+= ['ExecStart=!!' + resolved_bin
]
319 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
321 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
323 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
325 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
326 if asan_options
or lsan_options
or ubsan_options
:
327 drop_in
+= ['SystemCallFilter=']
328 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
329 drop_in
+= ['MemoryDenyWriteExecute=no']
331 os
.makedirs('/run/systemd/system/systemd-resolved.service.d', exist_ok
=True)
332 with
open('/run/systemd/system/systemd-resolved.service.d/00-override.conf', mode
='w') as f
:
333 f
.write('\n'.join(drop_in
))
338 'ExecStart=!!' + udevd_bin
,
341 os
.makedirs('/run/systemd/system/systemd-udevd.service.d', exist_ok
=True)
342 with
open('/run/systemd/system/systemd-udevd.service.d/00-override.conf', mode
='w') as f
:
343 f
.write('\n'.join(drop_in
))
345 check_output('systemctl daemon-reload')
346 print(check_output('systemctl cat systemd-networkd.service'))
347 print(check_output('systemctl cat systemd-resolved.service'))
348 print(check_output('systemctl cat systemd-udevd.service'))
349 check_output('systemctl restart systemd-resolved')
350 check_output('systemctl restart systemd-udevd')
352 def tearDownModule():
355 shutil
.rmtree(networkd_ci_path
)
357 for u
in ['systemd-networkd.socket', 'systemd-networkd.service', 'systemd-resolved.service']:
358 check_output(f
'systemctl stop {u}')
360 shutil
.rmtree('/run/systemd/system/systemd-networkd.service.d')
361 shutil
.rmtree('/run/systemd/system/systemd-resolved.service.d')
362 shutil
.rmtree('/run/systemd/system/systemd-udevd.service.d')
363 check_output('systemctl daemon-reload')
364 check_output('systemctl restart systemd-udevd.service')
366 for u
in running_units
:
367 check_output(f
'systemctl start {u}')
369 def read_link_attr(*args
):
370 with
open(os
.path
.join('/sys/class/net/', *args
)) as f
:
371 return f
.readline().strip()
373 def read_bridge_port_attr(bridge
, link
, attribute
):
374 path_bridge
= os
.path
.join('/sys/devices/virtual/net', bridge
)
375 path_port
= 'lower_' + link
+ '/brport'
376 path
= os
.path
.join(path_bridge
, path_port
)
378 with
open(os
.path
.join(path
, attribute
)) as f
:
379 return f
.readline().strip()
381 def link_exists(link
):
382 return os
.path
.exists(os
.path
.join('/sys/class/net', link
))
384 def remove_links(links
):
386 if link_exists(link
):
387 call('ip link del dev', link
)
390 def remove_fou_ports(ports
):
392 call('ip fou del port', port
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
394 def remove_routing_policy_rule_tables(tables
):
398 rc
= call('ip rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
401 rc
= call('ip -6 rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
403 def remove_routes(routes
):
404 for route_type
, addr
in routes
:
405 call('ip route del', route_type
, addr
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
407 def remove_l2tp_tunnels(tunnel_ids
):
408 output
= check_output('ip l2tp show tunnel')
409 for tid
in tunnel_ids
:
410 words
='Tunnel ' + tid
+ ', encap'
412 call('ip l2tp del tunnel tid', tid
)
415 def read_ipv6_sysctl_attr(link
, attribute
):
416 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, link
), attribute
)) as f
:
417 return f
.readline().strip()
419 def read_ipv4_sysctl_attr(link
, attribute
):
420 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv4_path
, link
), attribute
)) as f
:
421 return f
.readline().strip()
423 def copy_unit_to_networkd_unit_path(*units
, dropins
=True):
424 """Copy networkd unit files into the testbed.
426 Any networkd unit file type can be specified, as well as drop-in files.
428 By default, all drop-ins for a specified unit file are copied in;
429 to avoid that specify dropins=False.
431 When a drop-in file is specified, its unit file is also copied in automatically.
435 if dropins
and os
.path
.exists(os
.path
.join(networkd_ci_path
, unit
+ '.d')):
436 copytree(os
.path
.join(networkd_ci_path
, unit
+ '.d'), os
.path
.join(network_unit_file_path
, unit
+ '.d'))
437 if unit
.endswith('.conf'):
439 dropindir
= os
.path
.join(network_unit_file_path
, os
.path
.dirname(dropin
))
440 os
.makedirs(dropindir
, exist_ok
=True)
441 shutil
.copy(os
.path
.join(networkd_ci_path
, dropin
), dropindir
)
442 unit
= os
.path
.dirname(dropin
).rstrip('.d')
443 shutil
.copy(os
.path
.join(networkd_ci_path
, unit
), network_unit_file_path
)
445 def remove_unit_from_networkd_path(units
):
446 """Remove previously copied unit files from the testbed.
448 Drop-ins will be removed automatically.
451 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
))):
452 os
.remove(os
.path
.join(network_unit_file_path
, unit
))
453 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
+ '.d'))):
454 shutil
.rmtree(os
.path
.join(network_unit_file_path
, unit
+ '.d'))
456 def start_dnsmasq(additional_options
='', ipv4_range
='192.168.5.10,192.168.5.200', ipv6_range
='2600::10,2600::20', lease_time
='1h'):
457 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
458 check_output(dnsmasq_command
)
460 def stop_dnsmasq(pid_file
):
461 if os
.path
.exists(pid_file
):
462 with
open(pid_file
, 'r') as f
:
463 pid
= f
.read().rstrip(' \t\r\n\0')
464 os
.kill(int(pid
), signal
.SIGTERM
)
468 def search_words_in_dnsmasq_log(words
, show_all
=False):
469 if os
.path
.exists(dnsmasq_log_file
):
470 with
open (dnsmasq_log_file
) as in_file
:
471 contents
= in_file
.read()
474 for line
in contents
.splitlines():
477 print("%s, %s" % (words
, line
))
481 def remove_lease_file():
482 if os
.path
.exists(os
.path
.join(networkd_ci_path
, 'lease')):
483 os
.remove(os
.path
.join(networkd_ci_path
, 'lease'))
485 def remove_log_file():
486 if os
.path
.exists(dnsmasq_log_file
):
487 os
.remove(dnsmasq_log_file
)
489 def remove_networkd_state_files():
490 if os
.path
.exists(os
.path
.join(networkd_runtime_directory
, 'state')):
491 os
.remove(os
.path
.join(networkd_runtime_directory
, 'state'))
493 def stop_networkd(show_logs
=True, remove_state_files
=True):
495 invocation_id
= check_output('systemctl show systemd-networkd -p InvocationID --value')
496 check_output('systemctl stop systemd-networkd.socket')
497 check_output('systemctl stop systemd-networkd.service')
499 print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
))
500 if remove_state_files
:
501 remove_networkd_state_files()
503 def start_networkd(sleep_sec
=0):
504 check_output('systemctl start systemd-networkd')
506 time
.sleep(sleep_sec
)
508 def restart_networkd(sleep_sec
=0, show_logs
=True, remove_state_files
=True):
509 stop_networkd(show_logs
, remove_state_files
)
510 start_networkd(sleep_sec
)
514 def check_link_exists(self
, link
):
515 self
.assertTrue(link_exists(link
))
517 def check_link_attr(self
, *args
):
518 self
.assertEqual(read_link_attr(*args
[:-1]), args
[-1]);
520 def wait_operstate(self
, link
, operstate
='degraded', setup_state
='configured', setup_timeout
=5, fail_assert
=True):
521 """Wait for the link to reach the specified operstate and/or setup state.
523 Specify None or '' for either operstate or setup_state to ignore that state.
524 This will recheck until the state conditions are met or the timeout expires.
526 If the link successfully matches the requested state, this returns True.
527 If this times out waiting for the link to match, the behavior depends on the
528 'fail_assert' parameter; if True, this causes a test assertion failure,
529 otherwise this returns False. The default is to cause assertion failure.
531 Note that this function matches on *exactly* the given operstate and setup_state.
532 To wait for a link to reach *or exceed* a given operstate, use wait_online().
539 for secs
in range(setup_timeout
+ 1):
540 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
, env
=env
)
542 if re
.search(rf
'(?m)^\s*State:\s+{operstate}\s+\({setup_state}\)\s*$', output
):
544 # don't bother sleeping if time is up
545 if secs
< setup_timeout
:
548 self
.fail(f
'Timed out waiting for {link} to reach state {operstate}/{setup_state}')
551 def wait_online(self
, links_with_operstate
, timeout
='20s', bool_any
=False, setup_state
='configured', setup_timeout
=5):
552 """Wait for the link(s) to reach the specified operstate and/or setup state.
554 This is similar to wait_operstate() but can be used for multiple links,
555 and it also calls systemd-networkd-wait-online to wait for the given operstate.
556 The operstate should be specified in the link name, like 'eth0:degraded'.
557 If just a link name is provided, wait-online's default operstate to wait for is degraded.
559 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
560 'setup_timeout' controls the per-link timeout waiting for the setup_state.
562 Set 'bool_any' to True to wait for any (instead of all) of the given links.
563 If this is set, no setup_state checks are done.
565 Note that this function waits for the link(s) to reach *or exceed* the given operstate.
566 However, the setup_state, if specified, must be matched *exactly*.
568 This returns if the link(s) reached the requested operstate/setup_state; otherwise it
569 raises CalledProcessError or fails test assertion.
571 args
= wait_online_cmd
+ [f
'--timeout={timeout}'] + [f
'--interface={link}' for link
in links_with_operstate
]
575 check_output(*args
, env
=env
)
576 except subprocess
.CalledProcessError
:
577 for link
in links_with_operstate
:
578 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
.split(':')[0], env
=env
)
581 if not bool_any
and setup_state
:
582 for link
in links_with_operstate
:
583 self
.wait_operstate(link
.split(':')[0], None, setup_state
, setup_timeout
)
585 def wait_address(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
586 for i
in range(timeout_sec
):
589 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
590 if re
.search(address_regex
, output
) and 'tentative' not in output
:
593 self
.assertRegex(output
, address_regex
)
595 def wait_address_dropped(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
596 for i
in range(timeout_sec
):
599 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
600 if not re
.search(address_regex
, output
):
603 self
.assertNotRegex(output
, address_regex
)
605 class NetworkctlTests(unittest
.TestCase
, Utilities
):
615 '11-dummy-mtu.netdev',
619 '25-address-static.network',
621 'netdev-link-local-addressing-yes.network',
625 remove_links(self
.links
)
626 stop_networkd(show_logs
=False)
629 remove_links(self
.links
)
630 remove_unit_from_networkd_path(self
.units
)
631 stop_networkd(show_logs
=True)
633 @expectedFailureIfAlternativeNameIsNotAvailable()
634 def test_altname(self
):
635 copy_unit_to_networkd_unit_path('netdev-link-local-addressing-yes.network', '12-dummy.netdev', '12-dummy.link')
636 check_output('udevadm control --reload')
638 self
.wait_online(['dummy98:degraded'])
640 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
641 self
.assertRegex(output
, 'hogehogehogehogehogehoge')
643 def test_reconfigure(self
):
644 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
646 self
.wait_online(['dummy98:routable'])
648 output
= check_output('ip -4 address show dev dummy98')
650 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
651 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
652 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
654 check_output('ip address del 10.1.2.3/16 dev dummy98')
655 check_output('ip address del 10.1.2.4/16 dev dummy98')
656 check_output('ip address del 10.2.2.4/16 dev dummy98')
658 check_output(*networkctl_cmd
, 'reconfigure', 'dummy98', env
=env
)
659 self
.wait_online(['dummy98:routable'])
661 output
= check_output('ip -4 address show dev dummy98')
663 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
664 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
665 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
667 def test_reload(self
):
670 copy_unit_to_networkd_unit_path('11-dummy.netdev')
671 check_output(*networkctl_cmd
, 'reload', env
=env
)
672 self
.wait_operstate('test1', 'off', setup_state
='unmanaged')
674 copy_unit_to_networkd_unit_path('11-dummy.network')
675 check_output(*networkctl_cmd
, 'reload', env
=env
)
676 self
.wait_online(['test1:degraded'])
678 remove_unit_from_networkd_path(['11-dummy.network'])
679 check_output(*networkctl_cmd
, 'reload', env
=env
)
680 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
682 remove_unit_from_networkd_path(['11-dummy.netdev'])
683 check_output(*networkctl_cmd
, 'reload', env
=env
)
684 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
686 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
687 check_output(*networkctl_cmd
, 'reload', env
=env
)
688 self
.wait_operstate('test1', 'degraded')
691 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
694 self
.wait_online(['test1:degraded'])
696 output
= check_output(*networkctl_cmd
, 'list', env
=env
)
697 self
.assertRegex(output
, '1 lo ')
698 self
.assertRegex(output
, 'test1')
700 output
= check_output(*networkctl_cmd
, 'list', 'test1', env
=env
)
701 self
.assertNotRegex(output
, '1 lo ')
702 self
.assertRegex(output
, 'test1')
704 output
= check_output(*networkctl_cmd
, 'list', 'te*', env
=env
)
705 self
.assertNotRegex(output
, '1 lo ')
706 self
.assertRegex(output
, 'test1')
708 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'te*', env
=env
)
709 self
.assertNotRegex(output
, '1: lo ')
710 self
.assertRegex(output
, 'test1')
712 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'tes[a-z][0-9]', env
=env
)
713 self
.assertNotRegex(output
, '1: lo ')
714 self
.assertRegex(output
, 'test1')
717 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
720 self
.wait_online(['test1:degraded'])
722 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
723 self
.assertRegex(output
, 'MTU: 1600')
726 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
728 self
.wait_online(['test1:degraded'])
730 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
732 self
.assertRegex(output
, 'Type: ether')
734 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
736 self
.assertRegex(output
, 'Type: loopback')
738 @expectedFailureIfLinkFileFieldIsNotSet()
739 def test_udev_link_file(self
):
740 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
742 self
.wait_online(['test1:degraded'])
744 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
746 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
747 self
.assertRegex(output
, r
'Network File: /run/systemd/network/11-dummy.network')
749 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
751 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
752 self
.assertRegex(output
, r
'Network File: n/a')
754 def test_delete_links(self
):
755 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
756 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
759 self
.wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
761 check_output(*networkctl_cmd
, 'delete', 'test1', 'veth99', env
=env
)
762 self
.assertFalse(link_exists('test1'))
763 self
.assertFalse(link_exists('veth99'))
764 self
.assertFalse(link_exists('veth-peer'))
766 class NetworkdNetDevTests(unittest
.TestCase
, Utilities
):
768 links_remove_earlier
= [
837 '10-dropin-test.netdev',
841 '13-not-match-udev-property.network',
842 '14-match-udev-property.network',
843 '15-name-conflict-test.netdev',
846 '21-vlan-test1.network',
849 '25-6rd-tunnel.netdev',
852 '25-bond-balanced-tlb.netdev',
854 '25-bridge-configure-without-carrier.network',
856 '25-erspan-tunnel-local-any.netdev',
857 '25-erspan-tunnel.netdev',
858 '25-fou-gretap.netdev',
860 '25-fou-ipip.netdev',
861 '25-fou-ipproto-gre.netdev',
862 '25-fou-ipproto-ipip.netdev',
865 '25-gretap-tunnel-local-any.netdev',
866 '25-gretap-tunnel.netdev',
867 '25-gre-tunnel-any-any.netdev',
868 '25-gre-tunnel-local-any.netdev',
869 '25-gre-tunnel-remote-any.netdev',
870 '25-gre-tunnel.netdev',
872 '25-ip6gretap-tunnel-local-any.netdev',
873 '25-ip6gretap-tunnel.netdev',
874 '25-ip6gre-tunnel-any-any.netdev',
875 '25-ip6gre-tunnel-local-any.netdev',
876 '25-ip6gre-tunnel-remote-any.netdev',
877 '25-ip6gre-tunnel.netdev',
878 '25-ip6tnl-tunnel-any-any.netdev',
879 '25-ip6tnl-tunnel-local-any.netdev',
880 '25-ip6tnl-tunnel-remote-any.netdev',
881 '25-ip6tnl-tunnel.netdev',
882 '25-ipip-tunnel-any-any.netdev',
883 '25-ipip-tunnel-independent.netdev',
884 '25-ipip-tunnel-independent-loopback.netdev',
885 '25-ipip-tunnel-local-any.netdev',
886 '25-ipip-tunnel-remote-any.netdev',
887 '25-ipip-tunnel.netdev',
890 '25-isatap-tunnel.netdev',
895 '25-sit-tunnel-any-any.netdev',
896 '25-sit-tunnel-local-any.netdev',
897 '25-sit-tunnel-remote-any.netdev',
898 '25-sit-tunnel.netdev',
901 '25-tunnel-any-any.network',
902 '25-tunnel-local-any.network',
903 '25-tunnel-remote-any.network',
908 '25-vti6-tunnel-any-any.netdev',
909 '25-vti6-tunnel-local-any.netdev',
910 '25-vti6-tunnel-remote-any.netdev',
911 '25-vti6-tunnel.netdev',
912 '25-vti-tunnel-any-any.netdev',
913 '25-vti-tunnel-local-any.netdev',
914 '25-vti-tunnel-remote-any.netdev',
915 '25-vti-tunnel.netdev',
917 '25-vxlan-independent.netdev',
919 '25-wireguard-23-peers.netdev',
920 '25-wireguard-23-peers.network',
921 '25-wireguard-no-peer.netdev',
922 '25-wireguard-no-peer.network',
923 '25-wireguard-preshared-key.txt',
924 '25-wireguard-private-key.txt',
925 '25-wireguard.netdev',
926 '25-wireguard.network',
928 '25-xfrm-independent.netdev',
944 'netdev-link-local-addressing-yes.network',
948 'vxlan-test1.network',
958 remove_fou_ports(self
.fou_ports
)
959 remove_links(self
.links_remove_earlier
)
960 remove_links(self
.links
)
961 stop_networkd(show_logs
=False)
964 remove_fou_ports(self
.fou_ports
)
965 remove_links(self
.links_remove_earlier
)
966 remove_links(self
.links
)
967 remove_unit_from_networkd_path(self
.units
)
968 stop_networkd(show_logs
=True)
970 def test_dropin_and_name_conflict(self
):
971 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
974 self
.wait_online(['dropin-test:off'], setup_state
='unmanaged')
976 output
= check_output('ip link show dropin-test')
978 self
.assertRegex(output
, '00:50:56:c0:00:28')
980 def test_match_udev_property(self
):
981 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
983 self
.wait_online(['dummy98:routable'])
985 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
987 self
.assertRegex(output
, 'Network File: /run/systemd/network/14-match-udev-property')
989 def test_wait_online_any(self
):
990 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
993 self
.wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
995 self
.wait_operstate('bridge99', '(off|no-carrier)', setup_state
='configuring')
996 self
.wait_operstate('test1', 'degraded')
998 @expectedFailureIfModuleIsNotAvailable('bareudp')
999 def test_bareudp(self
):
1000 copy_unit_to_networkd_unit_path('25-bareudp.netdev', 'netdev-link-local-addressing-yes.network')
1003 self
.wait_online(['bareudp99:degraded'])
1005 output
= check_output('ip -d link show bareudp99')
1007 self
.assertRegex(output
, 'dstport 1000 ')
1008 self
.assertRegex(output
, 'ethertype ip ')
1010 def test_bridge(self
):
1011 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
1014 self
.wait_online(['bridge99:no-carrier'])
1016 tick
= os
.sysconf('SC_CLK_TCK')
1017 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
1018 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
1019 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'forward_delay')) / tick
))
1020 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'ageing_time')) / tick
))
1021 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge', 'priority')))
1022 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_querier')))
1023 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_snooping')))
1024 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'stp_state')))
1025 self
.assertEqual(3, int(read_link_attr('bridge99', 'bridge', 'multicast_igmp_version')))
1027 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
1029 self
.assertRegex(output
, 'Priority: 9')
1030 self
.assertRegex(output
, 'STP: yes')
1031 self
.assertRegex(output
, 'Multicast IGMP Version: 3')
1033 def test_bond(self
):
1034 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
1037 self
.wait_online(['bond99:off', 'bond98:off'], setup_state
='unmanaged')
1039 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
1040 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
1041 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
1042 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
1043 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
1044 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
1045 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
1046 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
1047 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
1048 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
1049 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
1051 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
1052 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
1054 def test_vlan(self
):
1055 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
1056 '21-vlan.network', '21-vlan-test1.network')
1059 self
.wait_online(['test1:degraded', 'vlan99:routable'])
1061 output
= check_output('ip -d link show test1')
1063 self
.assertRegex(output
, ' mtu 2000 ')
1065 output
= check_output('ip -d link show vlan99')
1067 self
.assertRegex(output
, ' mtu 2000 ')
1068 self
.assertRegex(output
, 'REORDER_HDR')
1069 self
.assertRegex(output
, 'LOOSE_BINDING')
1070 self
.assertRegex(output
, 'GVRP')
1071 self
.assertRegex(output
, 'MVRP')
1072 self
.assertRegex(output
, ' id 99 ')
1074 output
= check_output('ip -4 address show dev test1')
1076 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
1077 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
1079 output
= check_output('ip -4 address show dev vlan99')
1081 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
1083 def test_macvtap(self
):
1084 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
1085 with self
.subTest(mode
=mode
):
1086 if mode
!= 'private':
1088 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
1089 '11-dummy.netdev', 'macvtap.network')
1090 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
1091 f
.write('[MACVTAP]\nMode=' + mode
)
1094 self
.wait_online(['macvtap99:degraded', 'test1:degraded'])
1096 output
= check_output('ip -d link show macvtap99')
1098 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
1100 def test_macvlan(self
):
1101 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
1102 with self
.subTest(mode
=mode
):
1103 if mode
!= 'private':
1105 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
1106 '11-dummy.netdev', 'macvlan.network')
1107 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
1108 f
.write('[MACVLAN]\nMode=' + mode
)
1111 self
.wait_online(['macvlan99:degraded', 'test1:degraded'])
1113 output
= check_output('ip -d link show test1')
1115 self
.assertRegex(output
, ' mtu 2000 ')
1117 output
= check_output('ip -d link show macvlan99')
1119 self
.assertRegex(output
, ' mtu 2000 ')
1120 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
1122 @expectedFailureIfModuleIsNotAvailable('ipvlan')
1123 def test_ipvlan(self
):
1124 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1125 with self
.subTest(mode
=mode
, flag
=flag
):
1128 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
1129 '11-dummy.netdev', 'ipvlan.network')
1130 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
1131 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
1134 self
.wait_online(['ipvlan99:degraded', 'test1:degraded'])
1136 output
= check_output('ip -d link show ipvlan99')
1138 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
1140 @expectedFailureIfModuleIsNotAvailable('ipvtap')
1141 def test_ipvtap(self
):
1142 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1143 with self
.subTest(mode
=mode
, flag
=flag
):
1146 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
1147 '11-dummy.netdev', 'ipvtap.network')
1148 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
1149 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
1152 self
.wait_online(['ipvtap99:degraded', 'test1:degraded'])
1154 output
= check_output('ip -d link show ipvtap99')
1156 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
1158 def test_veth(self
):
1159 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
1162 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
1164 output
= check_output('ip -d link show veth99')
1166 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
1167 output
= check_output('ip -d link show veth-peer')
1169 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
1172 copy_unit_to_networkd_unit_path('25-tun.netdev')
1175 self
.wait_online(['tun99:off'], setup_state
='unmanaged')
1177 output
= check_output('ip -d link show tun99')
1179 # Old ip command does not support IFF_ flags
1180 self
.assertRegex(output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
1183 copy_unit_to_networkd_unit_path('25-tap.netdev')
1186 self
.wait_online(['tap99:off'], setup_state
='unmanaged')
1188 output
= check_output('ip -d link show tap99')
1190 # Old ip command does not support IFF_ flags
1191 self
.assertRegex(output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
1193 @expectedFailureIfModuleIsNotAvailable('vrf')
1195 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
1198 self
.wait_online(['vrf99:carrier'])
1200 @expectedFailureIfModuleIsNotAvailable('vcan')
1201 def test_vcan(self
):
1202 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
1205 self
.wait_online(['vcan99:carrier'])
1207 @expectedFailureIfModuleIsNotAvailable('vxcan')
1208 def test_vxcan(self
):
1209 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
1212 self
.wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
1214 @expectedFailureIfModuleIsNotAvailable('wireguard')
1215 def test_wireguard(self
):
1216 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
1217 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
1218 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt',
1219 '25-wireguard-no-peer.netdev', '25-wireguard-no-peer.network')
1221 self
.wait_online(['wg99:carrier', 'wg98:routable', 'wg97:carrier'])
1223 if shutil
.which('wg'):
1226 output
= check_output('wg show wg99 listen-port')
1227 self
.assertRegex(output
, '51820')
1228 output
= check_output('wg show wg99 fwmark')
1229 self
.assertRegex(output
, '0x4d2')
1230 output
= check_output('wg show wg99 allowed-ips')
1231 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
1232 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
1233 output
= check_output('wg show wg99 persistent-keepalive')
1234 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
1235 output
= check_output('wg show wg99 endpoints')
1236 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
1237 output
= check_output('wg show wg99 private-key')
1238 self
.assertRegex(output
, r
'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
1239 output
= check_output('wg show wg99 preshared-keys')
1240 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
1241 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
1243 output
= check_output('wg show wg98 private-key')
1244 self
.assertRegex(output
, r
'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
1246 output
= check_output('wg show wg97 listen-port')
1247 self
.assertRegex(output
, '51821')
1248 output
= check_output('wg show wg97 fwmark')
1249 self
.assertRegex(output
, '0x4d3')
1251 def test_geneve(self
):
1252 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
1255 self
.wait_online(['geneve99:degraded'])
1257 output
= check_output('ip -d link show geneve99')
1259 self
.assertRegex(output
, '192.168.22.1')
1260 self
.assertRegex(output
, '6082')
1261 self
.assertRegex(output
, 'udpcsum')
1262 self
.assertRegex(output
, 'udp6zerocsumrx')
1264 def test_ipip_tunnel(self
):
1265 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
1266 '25-ipip-tunnel.netdev', '25-tunnel.network',
1267 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1268 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1269 '25-ipip-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1271 self
.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'ipiptun96:routable', 'dummy98:degraded'])
1273 output
= check_output('ip -d link show ipiptun99')
1275 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98')
1276 output
= check_output('ip -d link show ipiptun98')
1278 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98')
1279 output
= check_output('ip -d link show ipiptun97')
1281 self
.assertRegex(output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98')
1282 output
= check_output('ip -d link show ipiptun96')
1284 self
.assertRegex(output
, 'ipip (ipip )?remote any local any dev dummy98')
1286 def test_gre_tunnel(self
):
1287 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
1288 '25-gre-tunnel.netdev', '25-tunnel.network',
1289 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1290 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1291 '25-gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1293 self
.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'gretun96:routable', 'dummy98:degraded'])
1295 output
= check_output('ip -d link show gretun99')
1297 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1298 self
.assertRegex(output
, 'ikey 1.2.3.103')
1299 self
.assertRegex(output
, 'okey 1.2.4.103')
1300 self
.assertRegex(output
, 'iseq')
1301 self
.assertRegex(output
, 'oseq')
1302 output
= check_output('ip -d link show gretun98')
1304 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
1305 self
.assertRegex(output
, 'ikey 0.0.0.104')
1306 self
.assertRegex(output
, 'okey 0.0.0.104')
1307 self
.assertNotRegex(output
, 'iseq')
1308 self
.assertNotRegex(output
, 'oseq')
1309 output
= check_output('ip -d link show gretun97')
1311 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
1312 self
.assertRegex(output
, 'ikey 0.0.0.105')
1313 self
.assertRegex(output
, 'okey 0.0.0.105')
1314 self
.assertNotRegex(output
, 'iseq')
1315 self
.assertNotRegex(output
, 'oseq')
1316 output
= check_output('ip -d link show gretun96')
1318 self
.assertRegex(output
, 'gre remote any local any dev dummy98')
1319 self
.assertRegex(output
, 'ikey 0.0.0.106')
1320 self
.assertRegex(output
, 'okey 0.0.0.106')
1321 self
.assertNotRegex(output
, 'iseq')
1322 self
.assertNotRegex(output
, 'oseq')
1324 def test_ip6gre_tunnel(self
):
1325 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
1326 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
1327 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1328 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1329 '25-ip6gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1332 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1334 self
.check_link_exists('dummy98')
1335 self
.check_link_exists('ip6gretun99')
1336 self
.check_link_exists('ip6gretun98')
1337 self
.check_link_exists('ip6gretun97')
1338 self
.check_link_exists('ip6gretun96')
1340 output
= check_output('ip -d link show ip6gretun99')
1342 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1343 output
= check_output('ip -d link show ip6gretun98')
1345 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
1346 output
= check_output('ip -d link show ip6gretun97')
1348 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
1349 output
= check_output('ip -d link show ip6gretun96')
1351 self
.assertRegex(output
, 'ip6gre remote any local any dev dummy98')
1353 def test_gretap_tunnel(self
):
1354 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
1355 '25-gretap-tunnel.netdev', '25-tunnel.network',
1356 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1358 self
.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
1360 output
= check_output('ip -d link show gretap99')
1362 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1363 self
.assertRegex(output
, 'ikey 0.0.0.106')
1364 self
.assertRegex(output
, 'okey 0.0.0.106')
1365 self
.assertRegex(output
, 'iseq')
1366 self
.assertRegex(output
, 'oseq')
1367 output
= check_output('ip -d link show gretap98')
1369 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
1370 self
.assertRegex(output
, 'ikey 0.0.0.107')
1371 self
.assertRegex(output
, 'okey 0.0.0.107')
1372 self
.assertRegex(output
, 'iseq')
1373 self
.assertRegex(output
, 'oseq')
1375 def test_ip6gretap_tunnel(self
):
1376 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
1377 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1378 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1380 self
.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
1382 output
= check_output('ip -d link show ip6gretap99')
1384 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1385 output
= check_output('ip -d link show ip6gretap98')
1387 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1389 def test_vti_tunnel(self
):
1390 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
1391 '25-vti-tunnel.netdev', '25-tunnel.network',
1392 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1393 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1394 '25-vti-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1396 self
.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'vtitun96:routable', 'dummy98:degraded'])
1398 output
= check_output('ip -d link show vtitun99')
1400 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1401 output
= check_output('ip -d link show vtitun98')
1403 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
1404 output
= check_output('ip -d link show vtitun97')
1406 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
1407 output
= check_output('ip -d link show vtitun96')
1409 self
.assertRegex(output
, 'vti remote any local any dev dummy98')
1411 def test_vti6_tunnel(self
):
1412 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
1413 '25-vti6-tunnel.netdev', '25-tunnel.network',
1414 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1415 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1417 self
.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
1419 output
= check_output('ip -d link show vti6tun99')
1421 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1422 output
= check_output('ip -d link show vti6tun98')
1424 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1425 output
= check_output('ip -d link show vti6tun97')
1427 self
.assertRegex(output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1429 def test_ip6tnl_tunnel(self
):
1430 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
1431 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1432 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1433 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1435 self
.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
1437 output
= check_output('ip -d link show ip6tnl99')
1439 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1440 output
= check_output('ip -d link show ip6tnl98')
1442 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1443 output
= check_output('ip -d link show ip6tnl97')
1445 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1447 def test_sit_tunnel(self
):
1448 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1449 '25-sit-tunnel.netdev', '25-tunnel.network',
1450 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1451 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1452 '25-sit-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1454 self
.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'sittun96:routable', 'dummy98:degraded'])
1456 output
= check_output('ip -d link show sittun99')
1458 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1459 output
= check_output('ip -d link show sittun98')
1461 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98")
1462 output
= check_output('ip -d link show sittun97')
1464 self
.assertRegex(output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98")
1465 output
= check_output('ip -d link show sittun96')
1467 self
.assertRegex(output
, "sit (ip6ip )?remote any local any dev dummy98")
1469 def test_isatap_tunnel(self
):
1470 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1471 '25-isatap-tunnel.netdev', '25-tunnel.network')
1473 self
.wait_online(['isataptun99:routable', 'dummy98:degraded'])
1475 output
= check_output('ip -d link show isataptun99')
1477 self
.assertRegex(output
, "isatap ")
1479 def test_6rd_tunnel(self
):
1480 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1481 '25-6rd-tunnel.netdev', '25-tunnel.network')
1483 self
.wait_online(['sittun99:routable', 'dummy98:degraded'])
1485 output
= check_output('ip -d link show sittun99')
1487 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1489 @expectedFailureIfERSPANModuleIsNotAvailable()
1490 def test_erspan_tunnel(self
):
1491 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1492 '25-erspan-tunnel.netdev', '25-tunnel.network',
1493 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1495 self
.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1497 output
= check_output('ip -d link show erspan99')
1499 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1500 self
.assertRegex(output
, 'ikey 0.0.0.101')
1501 self
.assertRegex(output
, 'okey 0.0.0.101')
1502 self
.assertRegex(output
, 'iseq')
1503 self
.assertRegex(output
, 'oseq')
1504 output
= check_output('ip -d link show erspan98')
1506 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1507 self
.assertRegex(output
, '102')
1508 self
.assertRegex(output
, 'ikey 0.0.0.102')
1509 self
.assertRegex(output
, 'okey 0.0.0.102')
1510 self
.assertRegex(output
, 'iseq')
1511 self
.assertRegex(output
, 'oseq')
1513 def test_tunnel_independent(self
):
1514 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1517 self
.wait_online(['ipiptun99:carrier'])
1519 def test_tunnel_independent_loopback(self
):
1520 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent-loopback.netdev', 'netdev-link-local-addressing-yes.network')
1523 self
.wait_online(['ipiptun99:carrier'])
1525 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1526 def test_xfrm(self
):
1527 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'xfrm.network',
1528 '25-xfrm.netdev', 'netdev-link-local-addressing-yes.network')
1531 self
.wait_online(['xfrm99:degraded', 'dummy98:degraded'])
1533 output
= check_output('ip link show dev xfrm99')
1536 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1537 def test_xfrm_independent(self
):
1538 copy_unit_to_networkd_unit_path('25-xfrm-independent.netdev', 'netdev-link-local-addressing-yes.network')
1541 self
.wait_online(['xfrm99:degraded'])
1543 @expectedFailureIfModuleIsNotAvailable('fou')
1545 # The following redundant check is necessary for CentOS CI.
1546 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1547 self
.assertTrue(is_module_available('fou'))
1549 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1550 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1551 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1554 self
.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'], setup_state
='unmanaged')
1556 output
= check_output('ip fou show')
1558 self
.assertRegex(output
, 'port 55555 ipproto 4')
1559 self
.assertRegex(output
, 'port 55556 ipproto 47')
1561 output
= check_output('ip -d link show ipiptun96')
1563 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1564 output
= check_output('ip -d link show sittun96')
1566 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1567 output
= check_output('ip -d link show gretun96')
1569 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1570 output
= check_output('ip -d link show gretap96')
1572 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1574 def test_vxlan(self
):
1575 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1576 '25-vxlan-independent.netdev', 'netdev-link-local-addressing-yes.network',
1577 '11-dummy.netdev', 'vxlan-test1.network')
1580 self
.wait_online(['test1:degraded', 'vxlan99:degraded', 'vxlan98:degraded'])
1582 output
= check_output('ip -d link show vxlan99')
1584 self
.assertRegex(output
, '999')
1585 self
.assertRegex(output
, '5555')
1586 self
.assertRegex(output
, 'l2miss')
1587 self
.assertRegex(output
, 'l3miss')
1588 self
.assertRegex(output
, 'udpcsum')
1589 self
.assertRegex(output
, 'udp6zerocsumtx')
1590 self
.assertRegex(output
, 'udp6zerocsumrx')
1591 self
.assertRegex(output
, 'remcsumtx')
1592 self
.assertRegex(output
, 'remcsumrx')
1593 self
.assertRegex(output
, 'gbp')
1595 output
= check_output('bridge fdb show dev vxlan99')
1597 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1598 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1599 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1601 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'vxlan99', env
=env
)
1603 self
.assertRegex(output
, 'VNI: 999')
1604 self
.assertRegex(output
, 'Destination Port: 5555')
1605 self
.assertRegex(output
, 'Underlying Device: test1')
1607 output
= check_output('ip -d link show vxlan98')
1610 def test_macsec(self
):
1611 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1612 'macsec.network', '12-dummy.netdev')
1615 self
.wait_online(['dummy98:degraded', 'macsec99:routable'])
1617 output
= check_output('ip -d link show macsec99')
1619 self
.assertRegex(output
, 'macsec99@dummy98')
1620 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1621 self
.assertRegex(output
, 'encrypt on')
1623 output
= check_output('ip macsec show macsec99')
1625 self
.assertRegex(output
, 'encrypt on')
1626 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1627 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1628 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1629 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1630 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1631 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1632 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1633 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1634 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1635 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1636 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1638 def test_nlmon(self
):
1639 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1642 self
.wait_online(['nlmon99:carrier'])
1644 @expectedFailureIfModuleIsNotAvailable('ifb')
1646 copy_unit_to_networkd_unit_path('25-ifb.netdev', 'netdev-link-local-addressing-yes.network')
1649 self
.wait_online(['ifb99:degraded'])
1651 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1662 '25-l2tp-dummy.network',
1664 '25-l2tp-ip.netdev',
1665 '25-l2tp-udp.netdev']
1667 l2tp_tunnel_ids
= [ '10' ]
1670 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1671 remove_links(self
.links
)
1672 stop_networkd(show_logs
=False)
1675 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1676 remove_links(self
.links
)
1677 remove_unit_from_networkd_path(self
.units
)
1678 stop_networkd(show_logs
=True)
1680 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1681 def test_l2tp_udp(self
):
1682 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1683 '25-l2tp-udp.netdev', '25-l2tp.network')
1686 self
.wait_online(['test1:routable', 'l2tp-ses1:degraded', 'l2tp-ses2:degraded'])
1688 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1690 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1691 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1692 self
.assertRegex(output
, "Peer tunnel 11")
1693 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1694 self
.assertRegex(output
, "UDP checksum: enabled")
1696 output
= check_output('ip l2tp show session tid 10 session_id 15')
1698 self
.assertRegex(output
, "Session 15 in tunnel 10")
1699 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1700 self
.assertRegex(output
, "interface name: l2tp-ses1")
1702 output
= check_output('ip l2tp show session tid 10 session_id 17')
1704 self
.assertRegex(output
, "Session 17 in tunnel 10")
1705 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1706 self
.assertRegex(output
, "interface name: l2tp-ses2")
1708 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1709 def test_l2tp_ip(self
):
1710 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1711 '25-l2tp-ip.netdev', '25-l2tp.network')
1714 self
.wait_online(['test1:routable', 'l2tp-ses3:degraded', 'l2tp-ses4:degraded'])
1716 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1718 self
.assertRegex(output
, "Tunnel 10, encap IP")
1719 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1720 self
.assertRegex(output
, "Peer tunnel 12")
1722 output
= check_output('ip l2tp show session tid 10 session_id 25')
1724 self
.assertRegex(output
, "Session 25 in tunnel 10")
1725 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1726 self
.assertRegex(output
, "interface name: l2tp-ses3")
1728 output
= check_output('ip l2tp show session tid 10 session_id 27')
1730 self
.assertRegex(output
, "Session 27 in tunnel 10")
1731 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1732 self
.assertRegex(output
, "interface name: l2tp-ses4")
1734 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1749 '23-active-slave.network',
1750 '24-keep-configuration-static.network',
1751 '24-search-domain.network',
1752 '25-address-dad-veth-peer.network',
1753 '25-address-dad-veth99.network',
1754 '25-address-link-section.network',
1755 '25-address-peer-ipv4.network',
1756 '25-address-static.network',
1757 '25-activation-policy.network',
1758 '25-bind-carrier.network',
1759 '25-bond-active-backup-slave.netdev',
1760 '25-fibrule-invert.network',
1761 '25-fibrule-port-range.network',
1762 '25-fibrule-uidrange.network',
1763 '25-gre-tunnel-remote-any.netdev',
1764 '25-ip6gre-tunnel-remote-any.netdev',
1765 '25-ipv6-address-label-section.network',
1766 '25-ipv6-proxy-ndp.network',
1767 '25-link-local-addressing-no.network',
1768 '25-link-local-addressing-yes.network',
1769 '25-link-section-unmanaged.network',
1770 '25-neighbor-section.network',
1771 '25-neighbor-next.network',
1772 '25-neighbor-ipv6.network',
1773 '25-neighbor-ip-dummy.network',
1774 '25-neighbor-ip.network',
1775 '25-nexthop.network',
1776 '25-qdisc-cake.network',
1777 '25-qdisc-clsact-and-htb.network',
1778 '25-qdisc-drr.network',
1779 '25-qdisc-ets.network',
1780 '25-qdisc-fq_pie.network',
1781 '25-qdisc-hhf.network',
1782 '25-qdisc-ingress-netem-compat.network',
1783 '25-qdisc-pie.network',
1784 '25-qdisc-qfq.network',
1785 '25-prefix-route-with-vrf.network',
1786 '25-prefix-route-without-vrf.network',
1787 '25-route-ipv6-src.network',
1788 '25-route-static.network',
1789 '25-route-via-ipv6.network',
1790 '25-route-vrf.network',
1791 '25-gateway-static.network',
1792 '25-gateway-next-static.network',
1794 '25-sysctl-disable-ipv6.network',
1795 '25-sysctl.network',
1797 '25-veth-peer.network',
1801 '26-link-local-addressing-ipv6.network',
1802 'routing-policy-rule-dummy98.network',
1803 'routing-policy-rule-test1.network',
1804 'routing-policy-rule-reconfigure1.network',
1805 'routing-policy-rule-reconfigure2.network',
1808 routing_policy_rule_tables
= ['7', '8', '9', '1011']
1809 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1812 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1813 remove_routes(self
.routes
)
1814 remove_links(self
.links
)
1815 stop_networkd(show_logs
=False)
1818 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1819 remove_routes(self
.routes
)
1820 remove_links(self
.links
)
1821 remove_unit_from_networkd_path(self
.units
)
1822 stop_networkd(show_logs
=True)
1824 def test_address_static(self
):
1825 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1828 self
.wait_online(['dummy98:routable'])
1830 output
= check_output('ip -4 address show dev dummy98')
1832 self
.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output
)
1833 self
.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output
)
1834 self
.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output
)
1835 self
.assertIn('inet 10.7.8.9/16 brd 10.7.255.255 scope link deprecated dummy98', output
)
1837 # test for ENOBUFS issue #17012
1838 for i
in range(1,254):
1839 self
.assertIn(f
'inet 10.3.3.{i}/16 brd 10.3.255.255', output
)
1842 self
.assertNotIn('10.10.0.1/16', output
)
1843 self
.assertNotIn('10.10.0.2/16', output
)
1845 output
= check_output('ip -4 address show dev dummy98 label 32')
1846 self
.assertIn('inet 10.3.2.3/16 brd 10.3.255.255 scope global 32', output
)
1848 output
= check_output('ip -4 address show dev dummy98 label 33')
1849 self
.assertIn('inet 10.4.2.3 peer 10.4.2.4/16 scope global 33', output
)
1851 output
= check_output('ip -4 address show dev dummy98 label 34')
1852 self
.assertRegex(output
, r
'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1854 output
= check_output('ip -4 address show dev dummy98 label 35')
1855 self
.assertRegex(output
, r
'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1857 output
= check_output('ip -6 address show dev dummy98')
1859 self
.assertIn('inet6 2001:db8:0:f101::15/64 scope global', output
)
1860 self
.assertIn('inet6 2001:db8:0:f101::16/64 scope global', output
)
1861 self
.assertIn('inet6 2001:db8:0:f102::15/64 scope global', output
)
1862 self
.assertIn('inet6 2001:db8:0:f102::16/64 scope global', output
)
1863 self
.assertIn('inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global', output
)
1864 self
.assertIn('inet6 2001:db8:1:f101::1/64 scope global deprecated', output
)
1865 self
.assertRegex(output
, r
'inet6 fd[0-9a-f:]*1/64 scope global')
1868 self
.wait_online(['dummy98:routable'])
1870 # test for ENOBUFS issue #17012
1871 output
= check_output('ip -4 address show dev dummy98')
1872 for i
in range(1,254):
1873 self
.assertIn(f
'inet 10.3.3.{i}/16 brd 10.3.255.255', output
)
1875 def test_address_dad(self
):
1876 copy_unit_to_networkd_unit_path('25-address-dad-veth99.network', '25-address-dad-veth-peer.network',
1879 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
1881 output
= check_output('ip -4 address show dev veth99')
1883 self
.assertRegex(output
, '192.168.100.10/24')
1885 output
= check_output('ip -4 address show dev veth-peer')
1887 self
.assertNotRegex(output
, '192.168.100.10/24')
1889 def test_address_peer_ipv4(self
):
1890 # test for issue #17304
1891 copy_unit_to_networkd_unit_path('25-address-peer-ipv4.network', '12-dummy.netdev')
1893 for trial
in range(2):
1899 self
.wait_online(['dummy98:routable'])
1901 output
= check_output('ip -4 address show dev dummy98')
1902 self
.assertIn('inet 100.64.0.1 peer 100.64.0.2/32 scope global', output
)
1904 @expectedFailureIfModuleIsNotAvailable('vrf')
1905 def test_prefix_route(self
):
1906 copy_unit_to_networkd_unit_path('25-prefix-route-with-vrf.network', '12-dummy.netdev',
1907 '25-prefix-route-without-vrf.network', '11-dummy.netdev',
1908 '25-vrf.netdev', '25-vrf.network')
1909 for trial
in range(2):
1915 self
.wait_online(['dummy98:routable', 'test1:routable', 'vrf99:carrier'])
1917 output
= check_output('ip route show table 42 dev dummy98')
1918 print('### ip route show table 42 dev dummy98')
1920 self
.assertRegex(output
, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1')
1921 self
.assertRegex(output
, 'broadcast 10.20.33.0 proto kernel scope link src 10.20.33.1')
1922 self
.assertRegex(output
, '10.20.33.0/24 proto kernel scope link src 10.20.33.1')
1923 self
.assertRegex(output
, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1')
1924 self
.assertRegex(output
, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1')
1925 self
.assertRegex(output
, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1')
1926 self
.assertRegex(output
, 'broadcast 10.20.55.0 proto kernel scope link src 10.20.55.1')
1927 self
.assertRegex(output
, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1')
1928 self
.assertRegex(output
, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1')
1929 output
= check_output('ip -6 route show table 42 dev dummy98')
1930 print('### ip -6 route show table 42 dev dummy98')
1934 self
.assertRegex(output
, 'local fdde:11:22::1 proto kernel metric 0 pref medium')
1935 #self.assertRegex(output, 'fdde:11:22::1 proto kernel metric 256 pref medium')
1936 self
.assertRegex(output
, 'local fdde:11:33::1 proto kernel metric 0 pref medium')
1937 self
.assertRegex(output
, 'fdde:11:33::/64 proto kernel metric 256 pref medium')
1938 self
.assertRegex(output
, 'local fdde:11:44::1 proto kernel metric 0 pref medium')
1939 self
.assertRegex(output
, 'local fdde:11:55::1 proto kernel metric 0 pref medium')
1940 self
.assertRegex(output
, 'fe80::/64 proto kernel metric 256 pref medium')
1941 self
.assertRegex(output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium')
1945 output
= check_output('ip route show dev test1')
1946 print('### ip route show dev test1')
1948 self
.assertRegex(output
, '10.21.33.0/24 proto kernel scope link src 10.21.33.1')
1949 output
= check_output('ip route show table local dev test1')
1950 print('### ip route show table local dev test1')
1952 self
.assertRegex(output
, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1')
1953 self
.assertRegex(output
, 'broadcast 10.21.33.0 proto kernel scope link src 10.21.33.1')
1954 self
.assertRegex(output
, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1')
1955 self
.assertRegex(output
, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1')
1956 self
.assertRegex(output
, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1')
1957 self
.assertRegex(output
, 'broadcast 10.21.55.0 proto kernel scope link src 10.21.55.1')
1958 self
.assertRegex(output
, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1')
1959 self
.assertRegex(output
, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1')
1960 output
= check_output('ip -6 route show dev test1')
1961 print('### ip -6 route show dev test1')
1963 self
.assertRegex(output
, 'fdde:12:22::1 proto kernel metric 256 pref medium')
1964 self
.assertRegex(output
, 'fdde:12:33::/64 proto kernel metric 256 pref medium')
1965 self
.assertRegex(output
, 'fe80::/64 proto kernel metric 256 pref medium')
1966 output
= check_output('ip -6 route show table local dev test1')
1967 print('### ip -6 route show table local dev test1')
1969 self
.assertRegex(output
, 'local fdde:12:22::1 proto kernel metric 0 pref medium')
1970 self
.assertRegex(output
, 'local fdde:12:33::1 proto kernel metric 0 pref medium')
1971 self
.assertRegex(output
, 'local fdde:12:44::1 proto kernel metric 0 pref medium')
1972 self
.assertRegex(output
, 'local fdde:12:55::1 proto kernel metric 0 pref medium')
1973 self
.assertRegex(output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium')
1975 def test_configure_without_carrier(self
):
1976 copy_unit_to_networkd_unit_path('11-dummy.netdev')
1978 self
.wait_operstate('test1', 'off', '')
1979 check_output('ip link set dev test1 up carrier off')
1981 copy_unit_to_networkd_unit_path('25-test1.network.d/configure-without-carrier.conf', dropins
=False)
1983 self
.wait_online(['test1:no-carrier'])
1985 carrier_map
= {'on': '1', 'off': '0'}
1986 routable_map
= {'on': 'routable', 'off': 'no-carrier'}
1987 for carrier
in ['off', 'on', 'off']:
1988 with self
.subTest(carrier
=carrier
):
1989 if carrier_map
[carrier
] != read_link_attr('test1', 'carrier'):
1990 check_output(f
'ip link set dev test1 carrier {carrier}')
1991 self
.wait_online([f
'test1:{routable_map[carrier]}'])
1993 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
1995 self
.assertRegex(output
, '192.168.0.15')
1996 self
.assertRegex(output
, '192.168.0.1')
1997 self
.assertRegex(output
, routable_map
[carrier
])
1999 def test_configure_without_carrier_yes_ignore_carrier_loss_no(self
):
2000 copy_unit_to_networkd_unit_path('11-dummy.netdev')
2002 self
.wait_operstate('test1', 'off', '')
2003 check_output('ip link set dev test1 up carrier off')
2005 copy_unit_to_networkd_unit_path('25-test1.network')
2007 self
.wait_online(['test1:no-carrier'])
2009 carrier_map
= {'on': '1', 'off': '0'}
2010 routable_map
= {'on': 'routable', 'off': 'no-carrier'}
2011 for (carrier
, have_config
) in [('off', True), ('on', True), ('off', False)]:
2012 with self
.subTest(carrier
=carrier
, have_config
=have_config
):
2013 if carrier_map
[carrier
] != read_link_attr('test1', 'carrier'):
2014 check_output(f
'ip link set dev test1 carrier {carrier}')
2015 self
.wait_online([f
'test1:{routable_map[carrier]}'])
2017 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
2020 self
.assertRegex(output
, '192.168.0.15')
2021 self
.assertRegex(output
, '192.168.0.1')
2023 self
.assertNotRegex(output
, '192.168.0.15')
2024 self
.assertNotRegex(output
, '192.168.0.1')
2025 self
.assertRegex(output
, routable_map
[carrier
])
2027 def test_routing_policy_rule(self
):
2028 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
2030 self
.wait_online(['test1:degraded'])
2032 output
= check_output('ip rule list iif test1 priority 111')
2034 self
.assertRegex(output
, '111:')
2035 self
.assertRegex(output
, 'from 192.168.100.18')
2036 self
.assertRegex(output
, r
'tos (0x08|throughput)\s')
2037 self
.assertRegex(output
, 'iif test1')
2038 self
.assertRegex(output
, 'oif test1')
2039 self
.assertRegex(output
, 'lookup 7')
2041 output
= check_output('ip rule list iif test1 priority 101')
2043 self
.assertRegex(output
, '101:')
2044 self
.assertRegex(output
, 'from all')
2045 self
.assertRegex(output
, 'iif test1')
2046 self
.assertRegex(output
, 'lookup 9')
2048 output
= check_output('ip -6 rule list iif test1 priority 100')
2050 self
.assertRegex(output
, '100:')
2051 self
.assertRegex(output
, 'from all')
2052 self
.assertRegex(output
, 'iif test1')
2053 self
.assertRegex(output
, 'lookup 8')
2055 def test_routing_policy_rule_issue_11280(self
):
2056 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
2057 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
2059 for trial
in range(3):
2060 # Remove state files only first time
2062 self
.wait_online(['test1:degraded', 'dummy98:degraded'])
2065 output
= check_output('ip rule list table 7')
2067 self
.assertRegex(output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
2069 output
= check_output('ip rule list table 8')
2071 self
.assertRegex(output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
2073 stop_networkd(remove_state_files
=False)
2075 def test_routing_policy_rule_reconfigure(self
):
2076 copy_unit_to_networkd_unit_path('routing-policy-rule-reconfigure2.network', '11-dummy.netdev')
2078 self
.wait_online(['test1:degraded'])
2080 output
= check_output('ip rule list table 1011')
2082 self
.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output
)
2083 self
.assertIn('10112: from all oif test1 lookup 1011', output
)
2084 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2085 self
.assertIn('10114: from 192.168.8.254 lookup 1011', output
)
2087 output
= check_output('ip -6 rule list table 1011')
2089 self
.assertIn('10112: from all oif test1 lookup 1011', output
)
2091 copy_unit_to_networkd_unit_path('routing-policy-rule-reconfigure1.network', '11-dummy.netdev')
2092 run(*networkctl_cmd
, 'reload', env
=env
)
2094 self
.wait_online(['test1:degraded'])
2096 output
= check_output('ip rule list table 1011')
2098 self
.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output
)
2099 self
.assertIn('10112: from all oif test1 lookup 1011', output
)
2100 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2101 self
.assertIn('10114: from 192.168.8.254 lookup 1011', output
)
2103 output
= check_output('ip -6 rule list table 1011')
2105 self
.assertNotIn('10112: from all oif test1 lookup 1011', output
)
2106 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2108 run('ip rule delete priority 10111')
2109 run('ip rule delete priority 10112')
2110 run('ip rule delete priority 10113')
2111 run('ip rule delete priority 10114')
2112 run('ip -6 rule delete priority 10113')
2114 output
= check_output('ip rule list table 1011')
2116 self
.assertEqual(output
, '')
2118 output
= check_output('ip -6 rule list table 1011')
2120 self
.assertEqual(output
, '')
2122 run(*networkctl_cmd
, 'reconfigure', 'test1', env
=env
)
2123 self
.wait_online(['test1:degraded'])
2125 output
= check_output('ip rule list table 1011')
2127 self
.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output
)
2128 self
.assertIn('10112: from all oif test1 lookup 1011', output
)
2129 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2130 self
.assertIn('10114: from 192.168.8.254 lookup 1011', output
)
2132 output
= check_output('ip -6 rule list table 1011')
2134 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2136 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
2137 def test_routing_policy_rule_port_range(self
):
2138 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
2140 self
.wait_online(['test1:degraded'])
2142 output
= check_output('ip rule')
2144 self
.assertRegex(output
, '111')
2145 self
.assertRegex(output
, 'from 192.168.100.18')
2146 self
.assertRegex(output
, '1123-1150')
2147 self
.assertRegex(output
, '3224-3290')
2148 self
.assertRegex(output
, 'tcp')
2149 self
.assertRegex(output
, 'lookup 7')
2151 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
2152 def test_routing_policy_rule_invert(self
):
2153 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
2155 self
.wait_online(['test1:degraded'])
2157 output
= check_output('ip rule')
2159 self
.assertRegex(output
, '111')
2160 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
2161 self
.assertRegex(output
, 'tcp')
2162 self
.assertRegex(output
, 'lookup 7')
2164 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable()
2165 def test_routing_policy_rule_uidrange(self
):
2166 copy_unit_to_networkd_unit_path('25-fibrule-uidrange.network', '11-dummy.netdev')
2168 self
.wait_online(['test1:degraded'])
2170 output
= check_output('ip rule')
2172 self
.assertRegex(output
, '111')
2173 self
.assertRegex(output
, 'from 192.168.100.18')
2174 self
.assertRegex(output
, 'lookup 7')
2175 self
.assertRegex(output
, 'uidrange 100-200')
2177 def test_route_static(self
):
2178 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
2180 self
.wait_online(['dummy98:routable'])
2182 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2185 print('### ip -6 route show dev dummy98')
2186 output
= check_output('ip -6 route show dev dummy98')
2188 self
.assertIn('2001:1234:5:8fff:ff:ff:ff:ff proto static', output
)
2189 self
.assertIn('2001:1234:5:8f63::1 proto kernel', output
)
2191 print('### ip -6 route show default')
2192 output
= check_output('ip -6 route show default')
2194 self
.assertIn('default', output
)
2195 self
.assertIn('via 2001:1234:5:8fff:ff:ff:ff:ff', output
)
2197 print('### ip -4 route show dev dummy98')
2198 output
= check_output('ip -4 route show dev dummy98')
2200 self
.assertIn('149.10.124.48/28 proto kernel scope link src 149.10.124.58', output
)
2201 self
.assertIn('149.10.124.64 proto static scope link', output
)
2202 self
.assertIn('169.254.0.0/16 proto static scope link metric 2048', output
)
2203 self
.assertIn('192.168.1.1 proto static initcwnd 20', output
)
2204 self
.assertIn('192.168.1.2 proto static initrwnd 30', output
)
2205 self
.assertIn('192.168.1.3 proto static advmss 30', output
)
2206 self
.assertIn('multicast 149.10.123.4 proto static', output
)
2208 print('### ip -4 route show dev dummy98 default')
2209 output
= check_output('ip -4 route show dev dummy98 default')
2211 self
.assertIn('default via 149.10.125.65 proto static onlink', output
)
2212 self
.assertIn('default via 149.10.124.64 proto static', output
)
2213 self
.assertIn('default proto static', output
)
2215 print('### ip -4 route show table local dev dummy98')
2216 output
= check_output('ip -4 route show table local dev dummy98')
2218 self
.assertIn('local 149.10.123.1 proto static scope host', output
)
2219 self
.assertIn('anycast 149.10.123.2 proto static scope link', output
)
2220 self
.assertIn('broadcast 149.10.123.3 proto static scope link', output
)
2222 print('### ip route show type blackhole')
2223 output
= check_output('ip route show type blackhole')
2225 self
.assertIn('blackhole 202.54.1.2 proto static', output
)
2227 print('### ip route show type unreachable')
2228 output
= check_output('ip route show type unreachable')
2230 self
.assertIn('unreachable 202.54.1.3 proto static', output
)
2232 print('### ip route show type prohibit')
2233 output
= check_output('ip route show type prohibit')
2235 self
.assertIn('prohibit 202.54.1.4 proto static', output
)
2237 print('### ip -6 route show type blackhole')
2238 output
= check_output('ip -6 route show type blackhole')
2240 self
.assertIn('blackhole 2001:1234:5678::2 dev lo proto static', output
)
2242 print('### ip -6 route show type unreachable')
2243 output
= check_output('ip -6 route show type unreachable')
2245 self
.assertIn('unreachable 2001:1234:5678::3 dev lo proto static', output
)
2247 print('### ip -6 route show type prohibit')
2248 output
= check_output('ip -6 route show type prohibit')
2250 self
.assertIn('prohibit 2001:1234:5678::4 dev lo proto static', output
)
2252 print('### ip route show 192.168.10.1')
2253 output
= check_output('ip route show 192.168.10.1')
2255 self
.assertIn('192.168.10.1 proto static', output
)
2256 self
.assertIn('nexthop via 149.10.124.59 dev dummy98 weight 10', output
)
2257 self
.assertIn('nexthop via 149.10.124.60 dev dummy98 weight 5', output
)
2259 print('### ip route show 192.168.10.2')
2260 output
= check_output('ip route show 192.168.10.2')
2262 # old ip command does not show IPv6 gateways...
2263 self
.assertIn('192.168.10.2 proto static', output
)
2264 self
.assertIn('nexthop', output
)
2265 self
.assertIn('dev dummy98 weight 10', output
)
2266 self
.assertIn('dev dummy98 weight 5', output
)
2268 print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2269 output
= check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2271 # old ip command does not show 'nexthop' keyword and weight...
2272 self
.assertIn('2001:1234:5:7fff:ff:ff:ff:ff', output
)
2273 self
.assertIn('via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98', output
)
2274 self
.assertIn('via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98', output
)
2276 copy_unit_to_networkd_unit_path('25-address-static.network')
2277 check_output(*networkctl_cmd
, 'reload', env
=env
)
2279 self
.wait_online(['dummy98:routable'])
2281 # check all routes managed by Manager are removed
2282 print('### ip route show type blackhole')
2283 output
= check_output('ip route show type blackhole')
2285 self
.assertEqual(output
, '')
2287 print('### ip route show type unreachable')
2288 output
= check_output('ip route show type unreachable')
2290 self
.assertEqual(output
, '')
2292 print('### ip route show type prohibit')
2293 output
= check_output('ip route show type prohibit')
2295 self
.assertEqual(output
, '')
2297 print('### ip -6 route show type blackhole')
2298 output
= check_output('ip -6 route show type blackhole')
2300 self
.assertEqual(output
, '')
2302 print('### ip -6 route show type unreachable')
2303 output
= check_output('ip -6 route show type unreachable')
2305 self
.assertEqual(output
, '')
2307 print('### ip -6 route show type prohibit')
2308 output
= check_output('ip -6 route show type prohibit')
2310 self
.assertEqual(output
, '')
2312 remove_unit_from_networkd_path(['25-address-static.network'])
2313 check_output(*networkctl_cmd
, 'reload', env
=env
)
2315 self
.wait_online(['dummy98:routable'])
2317 # check all routes managed by Manager are reconfigured
2318 print('### ip route show type blackhole')
2319 output
= check_output('ip route show type blackhole')
2321 self
.assertIn('blackhole 202.54.1.2 proto static', output
)
2323 print('### ip route show type unreachable')
2324 output
= check_output('ip route show type unreachable')
2326 self
.assertIn('unreachable 202.54.1.3 proto static', output
)
2328 print('### ip route show type prohibit')
2329 output
= check_output('ip route show type prohibit')
2331 self
.assertIn('prohibit 202.54.1.4 proto static', output
)
2333 print('### ip -6 route show type blackhole')
2334 output
= check_output('ip -6 route show type blackhole')
2336 self
.assertIn('blackhole 2001:1234:5678::2 dev lo proto static', output
)
2338 print('### ip -6 route show type unreachable')
2339 output
= check_output('ip -6 route show type unreachable')
2341 self
.assertIn('unreachable 2001:1234:5678::3 dev lo proto static', output
)
2343 print('### ip -6 route show type prohibit')
2344 output
= check_output('ip -6 route show type prohibit')
2346 self
.assertIn('prohibit 2001:1234:5678::4 dev lo proto static', output
)
2348 rc
= call("ip link del dummy98")
2349 self
.assertEqual(rc
, 0)
2352 # check all routes managed by Manager are removed
2353 print('### ip route show type blackhole')
2354 output
= check_output('ip route show type blackhole')
2356 self
.assertEqual(output
, '')
2358 print('### ip route show type unreachable')
2359 output
= check_output('ip route show type unreachable')
2361 self
.assertEqual(output
, '')
2363 print('### ip route show type prohibit')
2364 output
= check_output('ip route show type prohibit')
2366 self
.assertEqual(output
, '')
2368 print('### ip -6 route show type blackhole')
2369 output
= check_output('ip -6 route show type blackhole')
2371 self
.assertEqual(output
, '')
2373 print('### ip -6 route show type unreachable')
2374 output
= check_output('ip -6 route show type unreachable')
2376 self
.assertEqual(output
, '')
2378 print('### ip -6 route show type prohibit')
2379 output
= check_output('ip -6 route show type prohibit')
2381 self
.assertEqual(output
, '')
2383 @expectedFailureIfRTA_VIAIsNotSupported()
2384 def test_route_via_ipv6(self
):
2385 copy_unit_to_networkd_unit_path('25-route-via-ipv6.network', '12-dummy.netdev')
2387 self
.wait_online(['dummy98:routable'])
2389 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2392 print('### ip -6 route show dev dummy98')
2393 output
= check_output('ip -6 route show dev dummy98')
2395 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
2396 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
2398 print('### ip -4 route show dev dummy98')
2399 output
= check_output('ip -4 route show dev dummy98')
2401 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
2402 self
.assertRegex(output
, '149.10.124.66 via inet6 2001:1234:5:8fff:ff:ff:ff:ff proto static')
2404 @expectedFailureIfModuleIsNotAvailable('vrf')
2405 def test_route_vrf(self
):
2406 copy_unit_to_networkd_unit_path('25-route-vrf.network', '12-dummy.netdev',
2407 '25-vrf.netdev', '25-vrf.network')
2409 self
.wait_online(['dummy98:routable', 'vrf99:carrier'])
2411 output
= check_output('ip route show vrf vrf99')
2413 self
.assertRegex(output
, 'default via 192.168.100.1')
2415 output
= check_output('ip route show')
2417 self
.assertNotRegex(output
, 'default via 192.168.100.1')
2419 def test_gateway_reconfigure(self
):
2420 copy_unit_to_networkd_unit_path('25-gateway-static.network', '12-dummy.netdev')
2422 self
.wait_online(['dummy98:routable'])
2423 print('### ip -4 route show dev dummy98 default')
2424 output
= check_output('ip -4 route show dev dummy98 default')
2426 self
.assertRegex(output
, 'default via 149.10.124.59 proto static')
2427 self
.assertNotRegex(output
, '149.10.124.60')
2429 remove_unit_from_networkd_path(['25-gateway-static.network'])
2430 copy_unit_to_networkd_unit_path('25-gateway-next-static.network')
2432 self
.wait_online(['dummy98:routable'])
2433 print('### ip -4 route show dev dummy98 default')
2434 output
= check_output('ip -4 route show dev dummy98 default')
2436 self
.assertNotRegex(output
, '149.10.124.59')
2437 self
.assertRegex(output
, 'default via 149.10.124.60 proto static')
2439 def test_ip_route_ipv6_src_route(self
):
2440 # a dummy device does not make the addresses go through tentative state, so we
2441 # reuse a bond from an earlier test, which does make the addresses go through
2442 # tentative state, and do our test on that
2443 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2445 self
.wait_online(['dummy98:enslaved', 'bond199:routable'])
2447 output
= check_output('ip -6 route list dev bond199')
2449 self
.assertRegex(output
, 'abcd::/16')
2450 self
.assertRegex(output
, 'src')
2451 self
.assertRegex(output
, '2001:1234:56:8f63::2')
2453 def test_ip_link_mac_address(self
):
2454 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
2456 self
.wait_online(['dummy98:degraded'])
2458 output
= check_output('ip link show dummy98')
2460 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
2462 def test_ip_link_unmanaged(self
):
2463 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
2466 self
.check_link_exists('dummy98')
2468 self
.wait_operstate('dummy98', 'off', setup_state
='unmanaged')
2470 def test_ipv6_address_label(self
):
2471 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
2473 self
.wait_online(['dummy98:degraded'])
2475 output
= check_output('ip addrlabel list')
2477 self
.assertRegex(output
, '2004:da8:1::/64')
2479 def test_ipv6_proxy_ndp(self
):
2480 copy_unit_to_networkd_unit_path('25-ipv6-proxy-ndp.network', '12-dummy.netdev')
2483 self
.wait_online(['dummy98:routable'])
2485 output
= check_output('ip neighbor show proxy dev dummy98')
2487 for i
in range(1,5):
2488 self
.assertRegex(output
, f
'2607:5300:203:5215:{i}::1 *proxy')
2490 def test_neighbor_section(self
):
2491 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2493 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2495 print('### ip neigh list dev dummy98')
2496 output
= check_output('ip neigh list dev dummy98')
2498 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2499 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2501 def test_neighbor_reconfigure(self
):
2502 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2504 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2506 print('### ip neigh list dev dummy98')
2507 output
= check_output('ip neigh list dev dummy98')
2509 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2510 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2512 remove_unit_from_networkd_path(['25-neighbor-section.network'])
2513 copy_unit_to_networkd_unit_path('25-neighbor-next.network')
2515 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2516 print('### ip neigh list dev dummy98')
2517 output
= check_output('ip neigh list dev dummy98')
2519 self
.assertNotRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2520 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT')
2521 self
.assertNotRegex(output
, '2004:da8:1::1.*PERMANENT')
2523 def test_neighbor_gre(self
):
2524 copy_unit_to_networkd_unit_path('25-neighbor-ip.network', '25-neighbor-ipv6.network', '25-neighbor-ip-dummy.network',
2525 '12-dummy.netdev', '25-gre-tunnel-remote-any.netdev', '25-ip6gre-tunnel-remote-any.netdev')
2527 self
.wait_online(['dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable'], timeout
='40s')
2529 output
= check_output('ip neigh list dev gretun97')
2531 self
.assertRegex(output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT')
2533 output
= check_output('ip neigh list dev ip6gretun97')
2535 self
.assertRegex(output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
2537 def test_link_local_addressing(self
):
2538 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
2539 '25-link-local-addressing-no.network', '12-dummy.netdev')
2541 self
.wait_online(['test1:degraded', 'dummy98:carrier'])
2543 output
= check_output('ip address show dev test1')
2545 self
.assertRegex(output
, 'inet .* scope link')
2546 self
.assertRegex(output
, 'inet6 .* scope link')
2548 output
= check_output('ip address show dev dummy98')
2550 self
.assertNotRegex(output
, 'inet6* .* scope link')
2553 Documentation/networking/ip-sysctl.txt
2555 addr_gen_mode - INTEGER
2556 Defines how link-local and autoconf addresses are generated.
2558 0: generate address based on EUI64 (default)
2559 1: do no generate a link-local address, use EUI64 for addresses generated
2561 2: generate stable privacy addresses, using the secret from
2562 stable_secret (RFC7217)
2563 3: generate stable privacy addresses, using a random secret if unset
2566 test1_addr_gen_mode
= ''
2567 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
2568 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
2572 # if stable_secret is unset, then EIO is returned
2573 test1_addr_gen_mode
= '0'
2575 test1_addr_gen_mode
= '2'
2577 test1_addr_gen_mode
= '0'
2579 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
2580 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
2582 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
2583 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
2585 def test_link_local_addressing_remove_ipv6ll(self
):
2586 copy_unit_to_networkd_unit_path('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
2588 self
.wait_online(['dummy98:degraded'])
2590 output
= check_output('ip address show dev dummy98')
2592 self
.assertRegex(output
, 'inet6 .* scope link')
2594 copy_unit_to_networkd_unit_path('25-link-local-addressing-no.network')
2596 self
.wait_online(['dummy98:carrier'])
2598 output
= check_output('ip address show dev dummy98')
2600 self
.assertNotRegex(output
, 'inet6* .* scope link')
2602 def test_sysctl(self
):
2603 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
2605 self
.wait_online(['dummy98:degraded'])
2607 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
2608 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
2609 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
2610 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
2611 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
2612 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
2613 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
2614 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'accept_local'), '1')
2616 def test_sysctl_disable_ipv6(self
):
2617 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
2619 print('## Disable ipv6')
2620 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
2621 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
2624 self
.wait_online(['dummy98:routable'])
2626 output
= check_output('ip -4 address show dummy98')
2628 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2629 output
= check_output('ip -6 address show dummy98')
2631 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2632 self
.assertRegex(output
, 'inet6 .* scope link')
2633 output
= check_output('ip -4 route show dev dummy98')
2635 self
.assertRegex(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2636 output
= check_output('ip -6 route show default')
2638 self
.assertRegex(output
, 'default')
2639 self
.assertRegex(output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff')
2641 check_output('ip link del dummy98')
2643 print('## Enable ipv6')
2644 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
2645 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
2648 self
.wait_online(['dummy98:routable'])
2650 output
= check_output('ip -4 address show dummy98')
2652 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2653 output
= check_output('ip -6 address show dummy98')
2655 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2656 self
.assertRegex(output
, 'inet6 .* scope link')
2657 output
= check_output('ip -4 route show dev dummy98')
2659 self
.assertRegex(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2660 output
= check_output('ip -6 route show default')
2662 self
.assertRegex(output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff')
2664 def test_bind_carrier(self
):
2665 check_output('ip link add dummy98 type dummy')
2666 check_output('ip link set dummy98 up')
2669 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
2671 self
.wait_online(['test1:routable'])
2673 output
= check_output('ip address show test1')
2675 self
.assertRegex(output
, 'UP,LOWER_UP')
2676 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2677 self
.wait_operstate('test1', 'routable')
2679 check_output('ip link add dummy99 type dummy')
2680 check_output('ip link set dummy99 up')
2682 output
= check_output('ip address show test1')
2684 self
.assertRegex(output
, 'UP,LOWER_UP')
2685 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2686 self
.wait_operstate('test1', 'routable')
2688 check_output('ip link del dummy98')
2690 output
= check_output('ip address show test1')
2692 self
.assertRegex(output
, 'UP,LOWER_UP')
2693 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2694 self
.wait_operstate('test1', 'routable')
2696 check_output('ip link set dummy99 down')
2698 output
= check_output('ip address show test1')
2700 self
.assertNotRegex(output
, 'UP,LOWER_UP')
2701 self
.assertRegex(output
, 'DOWN')
2702 self
.assertNotRegex(output
, '192.168.10')
2703 self
.wait_operstate('test1', 'off')
2705 check_output('ip link set dummy99 up')
2707 output
= check_output('ip address show test1')
2709 self
.assertRegex(output
, 'UP,LOWER_UP')
2710 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2711 self
.wait_operstate('test1', 'routable')
2713 def _test_activation_policy(self
, test
):
2715 conffile
= '25-activation-policy.network'
2717 conffile
= f
'{conffile}.d/{test}.conf'
2718 copy_unit_to_networkd_unit_path('11-dummy.netdev', conffile
, dropins
=False)
2721 always
= test
.startswith('always')
2722 if test
== 'manual':
2723 initial_up
= 'UP' in check_output('ip link show test1')
2725 initial_up
= not test
.endswith('down') # note: default is up
2726 expect_up
= initial_up
2727 next_up
= not expect_up
2729 # if initial expected state is down, must wait for setup_state to reach configuring
2730 # so systemd-networkd considers it 'activated'
2731 setup_state
= None if initial_up
else 'configuring'
2733 for iteration
in range(4):
2734 with self
.subTest(iteration
=iteration
, expect_up
=expect_up
):
2735 operstate
= 'routable' if expect_up
else 'off'
2736 self
.wait_operstate('test1', operstate
, setup_state
=setup_state
, setup_timeout
=20)
2740 self
.assertIn('UP', check_output('ip link show test1'))
2741 self
.assertIn('192.168.10.30/24', check_output('ip address show test1'))
2742 self
.assertIn('default via 192.168.10.1', check_output('ip route show'))
2744 self
.assertIn('DOWN', check_output('ip link show test1'))
2747 check_output('ip link set dev test1 up')
2749 check_output('ip link set dev test1 down')
2750 expect_up
= initial_up
if always
else next_up
2751 next_up
= not next_up
2755 def test_activation_policy(self
):
2756 for test
in ['up', 'always-up', 'manual', 'always-down', 'down', '']:
2757 with self
.subTest(test
=test
):
2758 self
._test
_activation
_policy
(test
)
2760 def test_domain(self
):
2761 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
2763 self
.wait_online(['dummy98:routable'])
2765 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2767 self
.assertRegex(output
, 'Address: 192.168.42.100')
2768 self
.assertRegex(output
, 'DNS: 192.168.42.1')
2769 self
.assertRegex(output
, 'Search Domains: one')
2771 def test_keep_configuration_static(self
):
2772 check_output('systemctl stop systemd-networkd.socket')
2773 check_output('systemctl stop systemd-networkd.service')
2775 check_output('ip link add name dummy98 type dummy')
2776 check_output('ip address add 10.1.2.3/16 dev dummy98')
2777 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
2778 output
= check_output('ip address show dummy98')
2780 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2781 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2782 output
= check_output('ip route show dev dummy98')
2785 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
2787 self
.wait_online(['dummy98:routable'])
2789 output
= check_output('ip address show dummy98')
2791 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2792 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2794 @expectedFailureIfNexthopIsNotAvailable()
2795 def test_nexthop(self
):
2796 copy_unit_to_networkd_unit_path('25-nexthop.network', '25-veth.netdev', '25-veth-peer.network')
2798 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2800 output
= check_output('ip nexthop list dev veth99')
2802 self
.assertRegex(output
, '192.168.5.1')
2804 def test_qdisc(self
):
2805 copy_unit_to_networkd_unit_path('25-qdisc-clsact-and-htb.network', '12-dummy.netdev',
2806 '25-qdisc-ingress-netem-compat.network', '11-dummy.netdev')
2807 check_output('modprobe sch_teql max_equalizers=2')
2810 self
.wait_online(['dummy98:routable', 'test1:routable'])
2812 output
= check_output('tc qdisc show dev test1')
2814 self
.assertRegex(output
, 'qdisc netem')
2815 self
.assertRegex(output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
2816 self
.assertRegex(output
, 'qdisc ingress')
2818 output
= check_output('tc qdisc show dev dummy98')
2820 self
.assertRegex(output
, 'qdisc clsact')
2822 self
.assertRegex(output
, 'qdisc htb 2: root')
2823 self
.assertRegex(output
, r
'default (0x30|30)')
2825 self
.assertRegex(output
, 'qdisc netem 30: parent 2:30')
2826 self
.assertRegex(output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
2827 self
.assertRegex(output
, 'qdisc fq_codel')
2828 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')
2830 self
.assertRegex(output
, 'qdisc teql1 31: parent 2:31')
2832 self
.assertRegex(output
, 'qdisc fq 32: parent 2:32')
2833 self
.assertRegex(output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
2834 self
.assertRegex(output
, 'quantum 1500')
2835 self
.assertRegex(output
, 'initial_quantum 13000')
2836 self
.assertRegex(output
, 'maxrate 1Mbit')
2838 self
.assertRegex(output
, 'qdisc codel 33: parent 2:33')
2839 self
.assertRegex(output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn')
2841 self
.assertRegex(output
, 'qdisc fq_codel 34: parent 2:34')
2842 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')
2844 self
.assertRegex(output
, 'qdisc tbf 35: parent 2:35')
2845 self
.assertRegex(output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms')
2847 self
.assertRegex(output
, 'qdisc sfq 36: parent 2:36')
2848 self
.assertRegex(output
, 'perturb 5sec')
2850 self
.assertRegex(output
, 'qdisc pfifo 37: parent 2:37')
2851 self
.assertRegex(output
, 'limit 100000p')
2853 self
.assertRegex(output
, 'qdisc gred 38: parent 2:38')
2854 self
.assertRegex(output
, 'vqs 12 default 10 grio')
2856 self
.assertRegex(output
, 'qdisc sfb 39: parent 2:39')
2857 self
.assertRegex(output
, 'limit 200000')
2859 self
.assertRegex(output
, 'qdisc bfifo 3a: parent 2:3a')
2860 self
.assertRegex(output
, 'limit 1000000')
2862 self
.assertRegex(output
, 'qdisc pfifo_head_drop 3b: parent 2:3b')
2863 self
.assertRegex(output
, 'limit 1023p')
2865 self
.assertRegex(output
, 'qdisc pfifo_fast 3c: parent 2:3c')
2867 output
= check_output('tc -d class show dev dummy98')
2869 self
.assertRegex(output
, 'class htb 2:30 root leaf 30:')
2870 self
.assertRegex(output
, 'class htb 2:31 root leaf 31:')
2871 self
.assertRegex(output
, 'class htb 2:32 root leaf 32:')
2872 self
.assertRegex(output
, 'class htb 2:33 root leaf 33:')
2873 self
.assertRegex(output
, 'class htb 2:34 root leaf 34:')
2874 self
.assertRegex(output
, 'class htb 2:35 root leaf 35:')
2875 self
.assertRegex(output
, 'class htb 2:36 root leaf 36:')
2876 self
.assertRegex(output
, 'class htb 2:37 root leaf 37:')
2877 self
.assertRegex(output
, 'class htb 2:38 root leaf 38:')
2878 self
.assertRegex(output
, 'class htb 2:39 root leaf 39:')
2879 self
.assertRegex(output
, 'class htb 2:3a root leaf 3a:')
2880 self
.assertRegex(output
, 'class htb 2:3b root leaf 3b:')
2881 self
.assertRegex(output
, 'class htb 2:3c root leaf 3c:')
2882 self
.assertRegex(output
, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit')
2883 self
.assertRegex(output
, 'burst 123456')
2884 self
.assertRegex(output
, 'cburst 123457')
2886 def test_qdisc2(self
):
2887 copy_unit_to_networkd_unit_path('25-qdisc-drr.network', '12-dummy.netdev',
2888 '25-qdisc-qfq.network', '11-dummy.netdev')
2891 self
.wait_online(['dummy98:routable', 'test1:routable'])
2893 output
= check_output('tc qdisc show dev dummy98')
2895 self
.assertRegex(output
, 'qdisc drr 2: root')
2896 output
= check_output('tc class show dev dummy98')
2898 self
.assertRegex(output
, 'class drr 2:30 root quantum 2000b')
2900 output
= check_output('tc qdisc show dev test1')
2902 self
.assertRegex(output
, 'qdisc qfq 2: root')
2903 output
= check_output('tc class show dev test1')
2905 self
.assertRegex(output
, 'class qfq 2:30 root weight 2 maxpkt 16000')
2906 self
.assertRegex(output
, 'class qfq 2:31 root weight 10 maxpkt 8000')
2908 @expectedFailureIfCAKEIsNotAvailable()
2909 def test_qdisc_cake(self
):
2910 copy_unit_to_networkd_unit_path('25-qdisc-cake.network', '12-dummy.netdev')
2912 self
.wait_online(['dummy98:routable'])
2914 output
= check_output('tc qdisc show dev dummy98')
2916 self
.assertRegex(output
, 'qdisc cake 3a: root')
2917 self
.assertRegex(output
, 'bandwidth 500Mbit')
2918 self
.assertRegex(output
, 'overhead 128')
2920 @expectedFailureIfPIEIsNotAvailable()
2921 def test_qdisc_pie(self
):
2922 copy_unit_to_networkd_unit_path('25-qdisc-pie.network', '12-dummy.netdev')
2924 self
.wait_online(['dummy98:routable'])
2926 output
= check_output('tc qdisc show dev dummy98')
2928 self
.assertRegex(output
, 'qdisc pie 3a: root')
2929 self
.assertRegex(output
, 'limit 200000')
2931 @expectedFailureIfHHFIsNotAvailable()
2932 def test_qdisc_hhf(self
):
2933 copy_unit_to_networkd_unit_path('25-qdisc-hhf.network', '12-dummy.netdev')
2935 self
.wait_online(['dummy98:routable'])
2937 output
= check_output('tc qdisc show dev dummy98')
2939 self
.assertRegex(output
, 'qdisc hhf 3a: root')
2940 self
.assertRegex(output
, 'limit 1022p')
2942 @expectedFailureIfETSIsNotAvailable()
2943 def test_qdisc_ets(self
):
2944 copy_unit_to_networkd_unit_path('25-qdisc-ets.network', '12-dummy.netdev')
2946 self
.wait_online(['dummy98:routable'])
2948 output
= check_output('tc qdisc show dev dummy98')
2951 self
.assertRegex(output
, 'qdisc ets 3a: root')
2952 self
.assertRegex(output
, 'bands 10 strict 3')
2953 self
.assertRegex(output
, 'quanta 1 2 3 4 5')
2954 self
.assertRegex(output
, 'priomap 3 4 5 6 7')
2956 @expectedFailureIfFQPIEIsNotAvailable()
2957 def test_qdisc_fq_pie(self
):
2958 copy_unit_to_networkd_unit_path('25-qdisc-fq_pie.network', '12-dummy.netdev')
2960 self
.wait_online(['dummy98:routable'])
2962 output
= check_output('tc qdisc show dev dummy98')
2965 self
.assertRegex(output
, 'qdisc fq_pie 3a: root')
2966 self
.assertRegex(output
, 'limit 200000p')
2968 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable()
2969 def test_sriov(self
):
2970 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
2971 call('modprobe netdevsim', stderr
=subprocess
.DEVNULL
)
2972 with
open('/sys/bus/netdevsim/new_device', mode
='w') as f
:
2975 call('udevadm settle')
2976 call('udevadm info -w10s /sys/devices/netdevsim99/net/eni99np1', stderr
=subprocess
.DEVNULL
)
2977 with
open('/sys/class/net/eni99np1/device/sriov_numvfs', mode
='w') as f
:
2980 copy_unit_to_networkd_unit_path('25-sriov.network')
2982 self
.wait_online(['eni99np1:routable'])
2984 output
= check_output('ip link show dev eni99np1')
2986 self
.assertRegex(output
,
2987 '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 *'
2988 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
2989 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
2992 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
2994 class NetworkdStateFileTests(unittest
.TestCase
, Utilities
):
3001 'state-file-tests.network',
3005 remove_links(self
.links
)
3006 stop_networkd(show_logs
=False)
3009 remove_links(self
.links
)
3010 remove_unit_from_networkd_path(self
.units
)
3011 stop_networkd(show_logs
=True)
3013 def test_state_file(self
):
3014 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'state-file-tests.network')
3016 self
.wait_online(['dummy98:routable'])
3018 output
= check_output(*networkctl_cmd
, '--no-legend', 'list', 'dummy98', env
=env
)
3020 ifindex
= output
.split()[0]
3022 path
= os
.path
.join('/run/systemd/netif/links/', ifindex
)
3023 self
.assertTrue(os
.path
.exists(path
))
3025 # make link state file updated
3026 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
3028 with
open(path
) as f
:
3030 self
.assertRegex(data
, r
'ADMIN_STATE=configured')
3031 self
.assertRegex(data
, r
'OPER_STATE=routable')
3032 self
.assertRegex(data
, r
'REQUIRED_FOR_ONLINE=yes')
3033 self
.assertRegex(data
, r
'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
3034 self
.assertRegex(data
, r
'ACTIVATION_POLICY=up')
3035 self
.assertRegex(data
, r
'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
3036 self
.assertRegex(data
, r
'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
3037 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
3038 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
3039 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
3040 self
.assertRegex(data
, r
'LLMNR=no')
3041 self
.assertRegex(data
, r
'MDNS=yes')
3042 self
.assertRegex(data
, r
'DNSSEC=no')
3044 check_output(*resolvectl_cmd
, 'dns', 'dummy98', '10.10.10.12#ccc.com', '10.10.10.13', '1111:2222::3333', env
=env
)
3045 check_output(*resolvectl_cmd
, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env
=env
)
3046 check_output(*resolvectl_cmd
, 'llmnr', 'dummy98', 'yes', env
=env
)
3047 check_output(*resolvectl_cmd
, 'mdns', 'dummy98', 'no', env
=env
)
3048 check_output(*resolvectl_cmd
, 'dnssec', 'dummy98', 'yes', env
=env
)
3049 check_output(*timedatectl_cmd
, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env
=env
)
3051 with
open(path
) as f
:
3053 self
.assertRegex(data
, r
'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333')
3054 self
.assertRegex(data
, r
'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org')
3055 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
3056 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
3057 self
.assertRegex(data
, r
'LLMNR=yes')
3058 self
.assertRegex(data
, r
'MDNS=no')
3059 self
.assertRegex(data
, r
'DNSSEC=yes')
3061 check_output(*timedatectl_cmd
, 'revert', 'dummy98', env
=env
)
3063 with
open(path
) as f
:
3065 self
.assertRegex(data
, r
'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333')
3066 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
3067 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
3068 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
3069 self
.assertRegex(data
, r
'LLMNR=yes')
3070 self
.assertRegex(data
, r
'MDNS=no')
3071 self
.assertRegex(data
, r
'DNSSEC=yes')
3073 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
3075 with
open(path
) as f
:
3077 self
.assertRegex(data
, r
'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
3078 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
3079 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
3080 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
3081 self
.assertRegex(data
, r
'LLMNR=no')
3082 self
.assertRegex(data
, r
'MDNS=yes')
3083 self
.assertRegex(data
, r
'DNSSEC=no')
3085 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
3095 '23-active-slave.network',
3096 '23-bond199.network',
3097 '23-primary-slave.network',
3098 '25-bond-active-backup-slave.netdev',
3101 'bond-slave.network']
3104 remove_links(self
.links
)
3105 stop_networkd(show_logs
=False)
3108 remove_links(self
.links
)
3109 remove_unit_from_networkd_path(self
.units
)
3110 stop_networkd(show_logs
=True)
3112 def test_bond_active_slave(self
):
3113 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
3115 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
3117 output
= check_output('ip -d link show bond199')
3119 self
.assertRegex(output
, 'active_slave dummy98')
3121 def test_bond_primary_slave(self
):
3122 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
3124 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
3126 output
= check_output('ip -d link show bond199')
3128 self
.assertRegex(output
, 'primary dummy98')
3130 def test_bond_operstate(self
):
3131 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
3132 'bond99.network','bond-slave.network')
3134 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
3136 output
= check_output('ip -d link show dummy98')
3138 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
3140 output
= check_output('ip -d link show test1')
3142 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
3144 output
= check_output('ip -d link show bond99')
3146 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
3148 self
.wait_operstate('dummy98', 'enslaved')
3149 self
.wait_operstate('test1', 'enslaved')
3150 self
.wait_operstate('bond99', 'routable')
3152 check_output('ip link set dummy98 down')
3154 self
.wait_operstate('dummy98', 'off')
3155 self
.wait_operstate('test1', 'enslaved')
3156 self
.wait_operstate('bond99', 'degraded-carrier')
3158 check_output('ip link set dummy98 up')
3160 self
.wait_operstate('dummy98', 'enslaved')
3161 self
.wait_operstate('test1', 'enslaved')
3162 self
.wait_operstate('bond99', 'routable')
3164 check_output('ip link set dummy98 down')
3165 check_output('ip link set test1 down')
3167 self
.wait_operstate('dummy98', 'off')
3168 self
.wait_operstate('test1', 'off')
3170 if not self
.wait_operstate('bond99', 'no-carrier', setup_timeout
=30, fail_assert
=False):
3171 # Huh? Kernel does not recognize that all slave interfaces are down?
3172 # Let's confirm that networkd's operstate is consistent with ip's result.
3173 self
.assertNotRegex(output
, 'NO-CARRIER')
3175 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
3185 '26-bridge-configure-without-carrier.network',
3186 '26-bridge-mdb-master.network',
3187 '26-bridge-mdb-slave.network',
3188 '26-bridge-slave-interface-1.network',
3189 '26-bridge-slave-interface-2.network',
3190 '26-bridge-vlan-master.network',
3191 '26-bridge-vlan-slave.network',
3192 'bridge99-ignore-carrier-loss.network',
3195 routing_policy_rule_tables
= ['100']
3198 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
3199 remove_links(self
.links
)
3200 stop_networkd(show_logs
=False)
3203 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
3204 remove_links(self
.links
)
3205 remove_unit_from_networkd_path(self
.units
)
3206 stop_networkd(show_logs
=True)
3208 def test_bridge_vlan(self
):
3209 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
3210 '26-bridge.netdev', '26-bridge-vlan-master.network')
3212 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
3214 output
= check_output('bridge vlan show dev test1')
3216 self
.assertNotRegex(output
, '4063')
3217 for i
in range(4064, 4095):
3218 self
.assertRegex(output
, f
'{i}')
3219 self
.assertNotRegex(output
, '4095')
3221 output
= check_output('bridge vlan show dev bridge99')
3223 self
.assertNotRegex(output
, '4059')
3224 for i
in range(4060, 4095):
3225 self
.assertRegex(output
, f
'{i}')
3226 self
.assertNotRegex(output
, '4095')
3228 def test_bridge_mdb(self
):
3229 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-mdb-slave.network',
3230 '26-bridge.netdev', '26-bridge-mdb-master.network')
3232 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
3234 output
= check_output('bridge mdb show dev bridge99')
3236 self
.assertRegex(output
, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064')
3237 self
.assertRegex(output
, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065')
3239 # Old kernel may not support bridge MDB entries on bridge master
3240 if call('bridge mdb add dev bridge99 port bridge99 grp 224.0.1.3 temp vid 4068', stderr
=subprocess
.DEVNULL
) == 0:
3241 self
.assertRegex(output
, 'dev bridge99 port bridge99 grp ff02:aaaa:fee5::1:4 temp *vid 4066')
3242 self
.assertRegex(output
, 'dev bridge99 port bridge99 grp 224.0.1.2 temp *vid 4067')
3244 def test_bridge_property(self
):
3245 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
3246 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
3249 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
3251 output
= check_output('ip -d link show test1')
3253 self
.assertRegex(output
, 'master')
3254 self
.assertRegex(output
, 'bridge')
3256 output
= check_output('ip -d link show dummy98')
3258 self
.assertRegex(output
, 'master')
3259 self
.assertRegex(output
, 'bridge')
3261 output
= check_output('ip addr show bridge99')
3263 self
.assertRegex(output
, '192.168.0.15/24')
3265 output
= check_output('bridge -d link show dummy98')
3267 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
3268 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
3269 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
3270 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
3271 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
3272 # CONFIG_BRIDGE_IGMP_SNOOPING=y
3273 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
3274 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
3275 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
3276 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
3277 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
3278 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'priority'), '23')
3279 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard'), '1')
3280 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'root_block'), '1')
3282 output
= check_output('bridge -d link show test1')
3284 self
.assertEqual(read_bridge_port_attr('bridge99', 'test1', 'priority'), '0')
3286 check_output('ip address add 192.168.0.16/24 dev bridge99')
3289 output
= check_output('ip addr show bridge99')
3291 self
.assertRegex(output
, '192.168.0.16/24')
3294 print('### ip -6 route list table all dev bridge99')
3295 output
= check_output('ip -6 route list table all dev bridge99')
3297 self
.assertRegex(output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
3299 self
.assertEqual(call('ip link del test1'), 0)
3301 self
.wait_operstate('bridge99', 'degraded-carrier')
3303 check_output('ip link del dummy98')
3305 self
.wait_operstate('bridge99', 'no-carrier')
3307 output
= check_output('ip address show bridge99')
3309 self
.assertRegex(output
, 'NO-CARRIER')
3310 self
.assertNotRegex(output
, '192.168.0.15/24')
3311 self
.assertNotRegex(output
, '192.168.0.16/24')
3313 print('### ip -6 route list table all dev bridge99')
3314 output
= check_output('ip -6 route list table all dev bridge99')
3316 self
.assertRegex(output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
3318 def test_bridge_configure_without_carrier(self
):
3319 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-configure-without-carrier.network',
3323 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
3324 for test
in ['no-slave', 'add-slave', 'slave-up', 'slave-no-carrier', 'slave-carrier', 'slave-down']:
3325 with self
.subTest(test
=test
):
3326 if test
== 'no-slave':
3327 # bridge has no slaves; it's up but *might* not have carrier
3328 self
.wait_operstate('bridge99', operstate
=r
'(no-carrier|routable)', setup_state
=None, setup_timeout
=30)
3329 # due to a bug in the kernel, newly-created bridges are brought up
3330 # *with* carrier, unless they have had any setting changed; e.g.
3331 # their mac set, priority set, etc. Then, they will lose carrier
3332 # as soon as a (down) slave interface is added, and regain carrier
3333 # again once the slave interface is brought up.
3334 #self.check_link_attr('bridge99', 'carrier', '0')
3335 elif test
== 'add-slave':
3336 # add slave to bridge, but leave it down; bridge is definitely no-carrier
3337 self
.check_link_attr('test1', 'operstate', 'down')
3338 check_output('ip link set dev test1 master bridge99')
3339 self
.wait_operstate('bridge99', operstate
='no-carrier', setup_state
=None)
3340 self
.check_link_attr('bridge99', 'carrier', '0')
3341 elif test
== 'slave-up':
3342 # bring up slave, which will have carrier; bridge gains carrier
3343 check_output('ip link set dev test1 up')
3344 self
.wait_online(['bridge99:routable'])
3345 self
.check_link_attr('bridge99', 'carrier', '1')
3346 elif test
== 'slave-no-carrier':
3347 # drop slave carrier; bridge loses carrier
3348 check_output('ip link set dev test1 carrier off')
3349 self
.wait_online(['bridge99:no-carrier:no-carrier'])
3350 self
.check_link_attr('bridge99', 'carrier', '0')
3351 elif test
== 'slave-carrier':
3352 # restore slave carrier; bridge gains carrier
3353 check_output('ip link set dev test1 carrier on')
3354 self
.wait_online(['bridge99:routable'])
3355 self
.check_link_attr('bridge99', 'carrier', '1')
3356 elif test
== 'slave-down':
3357 # bring down slave; bridge loses carrier
3358 check_output('ip link set dev test1 down')
3359 self
.wait_online(['bridge99:no-carrier:no-carrier'])
3360 self
.check_link_attr('bridge99', 'carrier', '0')
3362 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
3363 self
.assertRegex(output
, '10.1.2.3')
3364 self
.assertRegex(output
, '10.1.2.1')
3366 def test_bridge_ignore_carrier_loss(self
):
3367 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
3368 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
3369 'bridge99-ignore-carrier-loss.network')
3371 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
3373 check_output('ip address add 192.168.0.16/24 dev bridge99')
3376 check_output('ip link del test1')
3377 check_output('ip link del dummy98')
3380 output
= check_output('ip address show bridge99')
3382 self
.assertRegex(output
, 'NO-CARRIER')
3383 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
3384 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
3386 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
3387 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
3388 'bridge99-ignore-carrier-loss.network')
3390 self
.wait_online(['bridge99:no-carrier'])
3392 for trial
in range(4):
3393 check_output('ip link add dummy98 type dummy')
3394 check_output('ip link set dummy98 up')
3396 check_output('ip link del dummy98')
3398 self
.wait_online(['bridge99:routable', 'dummy98:enslaved'])
3400 output
= check_output('ip address show bridge99')
3402 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
3404 output
= check_output('ip rule list table 100')
3406 self
.assertIn('0: from all to 8.8.8.8 lookup 100', output
)
3408 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
3412 '23-emit-lldp.network',
3417 remove_links(self
.links
)
3418 stop_networkd(show_logs
=False)
3421 remove_links(self
.links
)
3422 remove_unit_from_networkd_path(self
.units
)
3423 stop_networkd(show_logs
=True)
3425 def test_lldp(self
):
3426 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
3428 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
3430 for trial
in range(10):
3434 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
3436 if re
.search(r
'veth99 .* veth-peer', output
):
3441 class NetworkdRATests(unittest
.TestCase
, Utilities
):
3446 'ipv6-prefix.network',
3447 'ipv6-prefix-veth.network',
3448 'ipv6-prefix-veth-token-static.network',
3449 'ipv6-prefix-veth-token-prefixstable.network',
3450 'ipv6-prefix-veth-token-prefixstable-without-address.network']
3453 remove_links(self
.links
)
3454 stop_networkd(show_logs
=False)
3457 remove_links(self
.links
)
3458 remove_unit_from_networkd_path(self
.units
)
3459 stop_networkd(show_logs
=True)
3461 def test_ipv6_prefix_delegation(self
):
3462 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
3464 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3466 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3468 self
.assertRegex(output
, 'fe80::')
3469 self
.assertRegex(output
, '2002:da8:1::1')
3471 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
3473 self
.assertIn('hogehoge.test', output
)
3475 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3477 self
.assertRegex(output
, '2002:da8:1:0')
3479 def test_ipv6_token_static(self
):
3480 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static.network')
3482 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3484 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3486 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
3487 self
.assertRegex(output
, '2002:da8:1:0:fa:de:ca:fe')
3488 self
.assertRegex(output
, '2002:da8:2:0:1a:2b:3c:4d')
3489 self
.assertRegex(output
, '2002:da8:2:0:fa:de:ca:fe')
3491 def test_ipv6_token_prefixstable(self
):
3492 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable.network')
3494 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3496 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3498 self
.assertRegex(output
, '2002:da8:1:0')
3499 self
.assertRegex(output
, '2002:da8:2:0.*78:9abc') # EUI
3501 def test_ipv6_token_prefixstable_without_address(self
):
3502 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable-without-address.network')
3504 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3506 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3508 self
.assertRegex(output
, '2002:da8:1:0')
3509 self
.assertRegex(output
, '2002:da8:2:0')
3511 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
3516 'dhcp-client.network',
3517 'dhcp-client-timezone-router.network',
3518 'dhcp-server.network',
3519 'dhcp-server-timezone-router.network']
3522 remove_links(self
.links
)
3523 stop_networkd(show_logs
=False)
3526 remove_links(self
.links
)
3527 remove_unit_from_networkd_path(self
.units
)
3528 stop_networkd(show_logs
=True)
3530 def test_dhcp_server(self
):
3531 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
3533 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3535 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3537 self
.assertRegex(output
, '192.168.5.*')
3538 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
3539 self
.assertRegex(output
, 'DNS: 192.168.5.1')
3540 self
.assertRegex(output
, 'NTP: 192.168.5.1')
3542 def test_emit_router_timezone(self
):
3543 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
3545 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3547 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3549 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
3550 self
.assertRegex(output
, '192.168.5.*')
3551 self
.assertRegex(output
, 'Europe/Berlin')
3553 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
3562 'dhcp-client-anonymize.network',
3563 'dhcp-client-decline.network',
3564 'dhcp-client-gateway-ipv4.network',
3565 'dhcp-client-gateway-ipv6.network',
3566 'dhcp-client-gateway-onlink-implicit.network',
3567 'dhcp-client-ipv4-dhcp-settings.network',
3568 'dhcp-client-ipv4-only-ipv6-disabled.network',
3569 'dhcp-client-ipv4-only.network',
3570 'dhcp-client-ipv4-use-routes-use-gateway.network',
3571 'dhcp-client-ipv6-only.network',
3572 'dhcp-client-ipv6-rapid-commit.network',
3573 'dhcp-client-keep-configuration-dhcp-on-stop.network',
3574 'dhcp-client-keep-configuration-dhcp.network',
3575 'dhcp-client-listen-port.network',
3576 'dhcp-client-reassign-static-routes-ipv4.network',
3577 'dhcp-client-reassign-static-routes-ipv6.network',
3578 'dhcp-client-route-metric.network',
3579 'dhcp-client-route-table.network',
3580 'dhcp-client-use-dns-ipv4-and-ra.network',
3581 'dhcp-client-use-dns-ipv4.network',
3582 'dhcp-client-use-dns-no.network',
3583 'dhcp-client-use-dns-yes.network',
3584 'dhcp-client-use-domains.network',
3585 'dhcp-client-vrf.network',
3586 'dhcp-client-with-ipv4ll.network',
3587 'dhcp-client-with-static-address.network',
3588 'dhcp-client.network',
3589 'dhcp-server-decline.network',
3590 'dhcp-server-veth-peer.network',
3591 'dhcp-v4-server-veth-peer.network',
3595 stop_dnsmasq(dnsmasq_pid_file
)
3596 remove_links(self
.links
)
3597 stop_networkd(show_logs
=False)
3600 stop_dnsmasq(dnsmasq_pid_file
)
3603 remove_links(self
.links
)
3604 remove_unit_from_networkd_path(self
.units
)
3605 stop_networkd(show_logs
=True)
3607 def test_dhcp_client_ipv6_only(self
):
3608 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3611 self
.wait_online(['veth-peer:carrier'])
3613 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3615 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3617 self
.assertRegex(output
, '2600::')
3618 self
.assertNotRegex(output
, '192.168.5')
3620 output
= check_output('ip addr show dev veth99')
3622 self
.assertRegex(output
, '2600::')
3623 self
.assertNotRegex(output
, '192.168.5')
3624 self
.assertNotRegex(output
, 'tentative')
3626 # Confirm that ipv6 token is not set in the kernel
3627 output
= check_output('ip token show dev veth99')
3629 self
.assertRegex(output
, 'token :: dev veth99')
3631 def test_dhcp_client_ipv4_only(self
):
3632 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
3635 self
.wait_online(['veth-peer:carrier'])
3636 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
3637 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3639 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3641 self
.assertNotRegex(output
, '2600::')
3642 self
.assertRegex(output
, '192.168.5')
3643 self
.assertRegex(output
, '192.168.5.6')
3644 self
.assertRegex(output
, '192.168.5.7')
3646 # checking routes to DNS servers
3647 output
= check_output('ip route show dev veth99')
3649 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3650 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3651 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3653 stop_dnsmasq(dnsmasq_pid_file
)
3654 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8', lease_time
='2m')
3656 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3657 print('Wait for the dynamic address to be renewed')
3660 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3662 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3664 self
.assertNotRegex(output
, '2600::')
3665 self
.assertRegex(output
, '192.168.5')
3666 self
.assertNotRegex(output
, '192.168.5.6')
3667 self
.assertRegex(output
, '192.168.5.7')
3668 self
.assertRegex(output
, '192.168.5.8')
3670 # checking routes to DNS servers
3671 output
= check_output('ip route show dev veth99')
3673 self
.assertNotRegex(output
, r
'192.168.5.6')
3674 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3675 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3676 self
.assertRegex(output
, r
'192.168.5.8 proto dhcp scope link src 192.168.5.181 metric 1024')
3678 def test_dhcp_client_ipv4_use_routes_gateway(self
):
3679 for (routes
, gateway
, dnsroutes
) in itertools
.product([True, False, None], repeat
=3):
3681 with self
.subTest(routes
=routes
, gateway
=gateway
, dnsroutes
=dnsroutes
):
3682 self
._test
_dhcp
_client
_ipv
4_use
_routes
_gateway
(routes
, gateway
, dnsroutes
)
3685 def _test_dhcp_client_ipv4_use_routes_gateway(self
, routes
, gateway
, dnsroutes
):
3686 testunit
= 'dhcp-client-ipv4-use-routes-use-gateway.network'
3687 testunits
= ['25-veth.netdev', 'dhcp-server-veth-peer.network', testunit
]
3689 testunits
.append(f
'{testunit}.d/use-routes-{routes}.conf');
3691 testunits
.append(f
'{testunit}.d/use-gateway-{gateway}.conf');
3692 if dnsroutes
!= None:
3693 testunits
.append(f
'{testunit}.d/use-dns-routes-{dnsroutes}.conf');
3694 copy_unit_to_networkd_unit_path(*testunits
, dropins
=False)
3697 self
.wait_online(['veth-peer:carrier'])
3698 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
3699 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3701 output
= check_output('ip route show dev veth99')
3704 # UseRoutes= defaults to true
3705 useroutes
= routes
in [True, None]
3706 # UseGateway= defaults to useroutes
3707 usegateway
= useroutes
if gateway
== None else gateway
3711 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.181 metric 1024')
3713 self
.assertNotRegex(output
, r
'192.168.5.5')
3717 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.181 metric 1024')
3719 self
.assertNotRegex(output
, r
'default via 192.168.5.1')
3721 # Check RoutesToDNS=, which defaults to false
3723 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3724 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3726 self
.assertNotRegex(output
, r
'192.168.5.6')
3727 self
.assertNotRegex(output
, r
'192.168.5.7')
3729 def test_dhcp_client_ipv4_ipv6(self
):
3730 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
3731 'dhcp-client-ipv4-only.network')
3733 self
.wait_online(['veth-peer:carrier'])
3735 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3737 # link become 'routable' when at least one protocol provide an valid address.
3738 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3739 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3741 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3743 self
.assertRegex(output
, '2600::')
3744 self
.assertRegex(output
, '192.168.5')
3746 def test_dhcp_client_settings(self
):
3747 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
3750 self
.wait_online(['veth-peer:carrier'])
3752 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3754 print('## ip address show dev veth99')
3755 output
= check_output('ip address show dev veth99')
3757 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3758 self
.assertRegex(output
, '192.168.5')
3759 self
.assertRegex(output
, '1492')
3761 print('## ip route show table main dev veth99')
3762 output
= check_output('ip route show table main dev veth99')
3765 main_table_is_empty
= output
== ''
3766 if not main_table_is_empty
:
3767 self
.assertNotRegex(output
, 'proto dhcp')
3769 print('## ip route show table 211 dev veth99')
3770 output
= check_output('ip route show table 211 dev veth99')
3772 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
3773 if main_table_is_empty
:
3774 self
.assertRegex(output
, '192.168.5.0/24 proto dhcp')
3775 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
3776 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
3778 print('## dnsmasq log')
3779 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
3780 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
3781 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
3782 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
3784 def test_dhcp6_client_settings_rapidcommit_true(self
):
3785 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3787 self
.wait_online(['veth-peer:carrier'])
3789 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3791 output
= check_output('ip address show dev veth99')
3793 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3794 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
3796 def test_dhcp6_client_settings_rapidcommit_false(self
):
3797 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
3799 self
.wait_online(['veth-peer:carrier'])
3801 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3803 output
= check_output('ip address show dev veth99')
3805 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3806 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
3808 def test_dhcp_client_settings_anonymize(self
):
3809 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
3811 self
.wait_online(['veth-peer:carrier'])
3813 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3815 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
3816 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
3817 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
3819 def test_dhcp_client_listen_port(self
):
3820 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
3822 self
.wait_online(['veth-peer:carrier'])
3823 start_dnsmasq('--dhcp-alternate-port=67,5555')
3824 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3826 output
= check_output('ip -4 address show dev veth99')
3828 self
.assertRegex(output
, '192.168.5.* dynamic')
3830 def test_dhcp_client_with_static_address(self
):
3831 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
3832 'dhcp-client-with-static-address.network')
3834 self
.wait_online(['veth-peer:carrier'])
3836 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3838 output
= check_output('ip address show dev veth99 scope global')
3840 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
3841 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
3843 output
= check_output('ip route show dev veth99')
3845 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
3846 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
3847 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
3848 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
3850 def test_dhcp_route_table_id(self
):
3851 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
3853 self
.wait_online(['veth-peer:carrier'])
3855 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3857 output
= check_output('ip route show table 12')
3859 self
.assertRegex(output
, 'veth99 proto dhcp')
3860 self
.assertRegex(output
, '192.168.5.1')
3862 def test_dhcp_route_metric(self
):
3863 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
3865 self
.wait_online(['veth-peer:carrier'])
3867 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3869 output
= check_output('ip route show dev veth99')
3871 self
.assertRegex(output
, 'metric 24')
3873 def test_dhcp_client_reassign_static_routes_ipv4(self
):
3874 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3875 'dhcp-client-reassign-static-routes-ipv4.network')
3877 self
.wait_online(['veth-peer:carrier'])
3878 start_dnsmasq(lease_time
='2m')
3879 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3881 output
= check_output('ip address show dev veth99 scope global')
3883 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3885 output
= check_output('ip route show dev veth99')
3887 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3888 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3889 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3890 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3892 stop_dnsmasq(dnsmasq_pid_file
)
3893 start_dnsmasq(ipv4_range
='192.168.5.210,192.168.5.220', lease_time
='2m')
3895 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3896 print('Wait for the dynamic address to be renewed')
3899 self
.wait_online(['veth99:routable'])
3901 output
= check_output('ip route show dev veth99')
3903 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3904 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3905 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3906 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3908 def test_dhcp_client_reassign_static_routes_ipv6(self
):
3909 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3910 'dhcp-client-reassign-static-routes-ipv6.network')
3912 self
.wait_online(['veth-peer:carrier'])
3913 start_dnsmasq(lease_time
='2m')
3914 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3916 output
= check_output('ip address show dev veth99 scope global')
3918 self
.assertRegex(output
, r
'inet6 2600::[0-9a-f]*/128 scope global (noprefixroute dynamic|dynamic noprefixroute)')
3920 output
= check_output('ip -6 route show dev veth99')
3922 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3923 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3925 stop_dnsmasq(dnsmasq_pid_file
)
3926 start_dnsmasq(ipv6_range
='2600::30,2600::40', lease_time
='2m')
3928 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3929 print('Wait for the dynamic address to be renewed')
3932 self
.wait_online(['veth99:routable'])
3934 output
= check_output('ip -6 route show dev veth99')
3936 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3937 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3939 def test_dhcp_keep_configuration_dhcp(self
):
3940 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
3942 self
.wait_online(['veth-peer:carrier'])
3943 start_dnsmasq(lease_time
='2m')
3944 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3946 output
= check_output('ip address show dev veth99 scope global')
3948 self
.assertRegex(output
, r
'192.168.5.*')
3950 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3952 self
.assertRegex(output
, r
'192.168.5.*')
3954 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
3955 stop_dnsmasq(dnsmasq_pid_file
)
3957 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3958 print('Wait for the dynamic address to be expired')
3961 print('The lease address should be kept after lease expired')
3962 output
= check_output('ip address show dev veth99 scope global')
3964 self
.assertRegex(output
, r
'192.168.5.*')
3966 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3968 self
.assertRegex(output
, r
'192.168.5.*')
3970 check_output('systemctl stop systemd-networkd.socket')
3971 check_output('systemctl stop systemd-networkd.service')
3973 print('The lease address should be kept after networkd stopped')
3974 output
= check_output('ip address show dev veth99 scope global')
3976 self
.assertRegex(output
, r
'192.168.5.*')
3978 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3980 self
.assertRegex(output
, r
'192.168.5.*')
3983 self
.wait_online(['veth-peer:routable'])
3985 print('Still the lease address should be kept after networkd restarted')
3986 output
= check_output('ip address show dev veth99 scope global')
3988 self
.assertRegex(output
, r
'192.168.5.*')
3990 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3992 self
.assertRegex(output
, r
'192.168.5.*')
3994 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
3995 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
3997 self
.wait_online(['veth-peer:carrier'])
3998 start_dnsmasq(lease_time
='2m')
3999 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4001 output
= check_output('ip address show dev veth99 scope global')
4003 self
.assertRegex(output
, r
'192.168.5.*')
4005 stop_dnsmasq(dnsmasq_pid_file
)
4006 check_output('systemctl stop systemd-networkd.socket')
4007 check_output('systemctl stop systemd-networkd.service')
4009 output
= check_output('ip address show dev veth99 scope global')
4011 self
.assertRegex(output
, r
'192.168.5.*')
4014 self
.wait_online(['veth-peer:routable'])
4016 output
= check_output('ip address show dev veth99 scope global')
4018 self
.assertNotRegex(output
, r
'192.168.5.*')
4020 def test_dhcp_client_reuse_address_as_static(self
):
4021 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
4023 self
.wait_online(['veth-peer:carrier'])
4025 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4027 # link become 'routable' when at least one protocol provide an valid address.
4028 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4029 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4031 output
= check_output('ip address show dev veth99 scope global')
4033 self
.assertRegex(output
, '192.168.5')
4034 self
.assertRegex(output
, '2600::')
4036 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
4037 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
4038 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
4039 print(static_network
)
4041 remove_unit_from_networkd_path(['dhcp-client.network'])
4043 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
4044 f
.write(static_network
)
4046 # When networkd started, the links are already configured, so let's wait for 5 seconds
4047 # the links to be re-configured.
4049 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4051 output
= check_output('ip -4 address show dev veth99 scope global')
4053 self
.assertRegex(output
, '192.168.5')
4054 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
4056 output
= check_output('ip -6 address show dev veth99 scope global')
4058 self
.assertRegex(output
, '2600::')
4059 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
4061 @expectedFailureIfModuleIsNotAvailable('vrf')
4062 def test_dhcp_client_vrf(self
):
4063 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
4064 '25-vrf.netdev', '25-vrf.network')
4066 self
.wait_online(['veth-peer:carrier'])
4068 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
4070 # link become 'routable' when at least one protocol provide an valid address.
4071 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4072 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4074 print('## ip -d link show dev vrf99')
4075 output
= check_output('ip -d link show dev vrf99')
4077 self
.assertRegex(output
, 'vrf table 42')
4079 print('## ip address show vrf vrf99')
4080 output
= check_output('ip address show vrf vrf99')
4082 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
4083 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
4084 self
.assertRegex(output
, 'inet6 .* scope link')
4086 print('## ip address show dev veth99')
4087 output
= check_output('ip address show dev veth99')
4089 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
4090 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
4091 self
.assertRegex(output
, 'inet6 .* scope link')
4093 print('## ip route show vrf vrf99')
4094 output
= check_output('ip route show vrf vrf99')
4096 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
4097 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
4098 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
4099 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
4101 print('## ip route show table main dev veth99')
4102 output
= check_output('ip route show table main dev veth99')
4104 self
.assertEqual(output
, '')
4106 def test_dhcp_client_gateway_ipv4(self
):
4107 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4108 'dhcp-client-gateway-ipv4.network')
4110 self
.wait_online(['veth-peer:carrier'])
4112 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4114 output
= check_output('ip route list dev veth99 10.0.0.0/8')
4116 self
.assertRegex(output
, '10.0.0.0/8 via 192.168.5.1 proto dhcp')
4118 def test_dhcp_client_gateway_ipv6(self
):
4119 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4120 'dhcp-client-gateway-ipv6.network')
4122 self
.wait_online(['veth-peer:carrier'])
4124 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4126 output
= check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
4128 self
.assertRegex(output
, 'via fe80::1034:56ff:fe78:9abd')
4130 def test_dhcp_client_gateway_onlink_implicit(self
):
4131 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4132 'dhcp-client-gateway-onlink-implicit.network')
4134 self
.wait_online(['veth-peer:carrier'])
4136 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4138 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4140 self
.assertRegex(output
, '192.168.5')
4142 output
= check_output('ip route list dev veth99 10.0.0.0/8')
4144 self
.assertRegex(output
, 'onlink')
4145 output
= check_output('ip route list dev veth99 192.168.100.0/24')
4147 self
.assertRegex(output
, 'onlink')
4149 def test_dhcp_client_with_ipv4ll_with_dhcp_server(self
):
4150 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4151 'dhcp-client-with-ipv4ll.network')
4153 self
.wait_online(['veth-peer:carrier'])
4154 start_dnsmasq(lease_time
='2m')
4155 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4157 output
= check_output('ip address show dev veth99')
4160 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
4161 self
.assertNotRegex(output
, r
'inet6 2600::[0-9a-f]+/128 scope global dynamic')
4162 output
= check_output('ip -6 address show dev veth99 scope link')
4163 self
.assertRegex(output
, r
'inet6 .* scope link')
4164 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
4165 self
.assertRegex(output
, r
'inet 192\.168\.5\.\d+/24 brd 192\.168\.5\.255 scope global dynamic veth99')
4166 output
= check_output('ip -4 address show dev veth99 scope link')
4167 self
.assertNotRegex(output
, r
'inet 169\.254\.\d+\.\d+/16 brd 169\.254\.255\.255 scope link')
4169 print('Wait for the dynamic address to be expired')
4172 output
= check_output('ip address show dev veth99')
4175 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
4176 self
.assertNotRegex(output
, r
'inet6 2600::[0-9a-f]+/128 scope global dynamic')
4177 output
= check_output('ip -6 address show dev veth99 scope link')
4178 self
.assertRegex(output
, r
'inet6 .* scope link')
4179 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
4180 self
.assertRegex(output
, r
'inet 192\.168\.5\.\d+/24 brd 192\.168\.5\.255 scope global dynamic veth99')
4181 output
= check_output('ip -4 address show dev veth99 scope link')
4182 self
.assertNotRegex(output
, r
'inet 169\.254\.\d+\.\d+/16 brd 169\.254\.255\.255 scope link')
4184 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
4186 def test_dhcp_client_with_ipv4ll_without_dhcp_server(self
):
4187 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4188 'dhcp-client-with-ipv4ll.network')
4190 # we need to increase timeout above default, as this will need to wait for
4191 # systemd-networkd to get the dhcpv4 transient failure event
4192 self
.wait_online(['veth99:degraded', 'veth-peer:routable'], timeout
='60s')
4194 output
= check_output('ip address show dev veth99')
4197 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
4198 self
.assertNotRegex(output
, r
'inet6 2600::[0-9a-f]+/128 scope global dynamic')
4199 output
= check_output('ip -6 address show dev veth99 scope link')
4200 self
.assertRegex(output
, r
'inet6 .* scope link')
4201 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
4202 self
.assertNotRegex(output
, r
'inet 192\.168\.5\.\d+/24 brd 192\.168\.5\.255 scope global dynamic veth99')
4203 output
= check_output('ip -4 address show dev veth99 scope link')
4204 self
.assertRegex(output
, r
'inet 169\.254\.\d+\.\d+/16 brd 169\.254\.255\.255 scope link')
4206 start_dnsmasq(lease_time
='2m')
4207 self
.wait_address('veth99', r
'inet 192\.168\.5\.\d+/24 brd 192\.168\.5\.255 scope global dynamic', ipv
='-4')
4208 self
.wait_address_dropped('veth99', r
'inet 169\.254\.\d+\.\d+/16 brd 169\.255\.255\.255 scope link', scope
='link', ipv
='-4')
4210 def test_dhcp_client_route_remove_on_renew(self
):
4211 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4212 'dhcp-client-ipv4-only-ipv6-disabled.network')
4214 self
.wait_online(['veth-peer:carrier'])
4215 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
4216 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4218 # test for issue #12490
4220 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
4222 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
4224 for line
in output
.splitlines():
4225 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
4226 address1
= line
.split()[1].split('/')[0]
4229 output
= check_output('ip -4 route show dev veth99')
4231 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
4232 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
4234 stop_dnsmasq(dnsmasq_pid_file
)
4235 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
4237 print('Wait for the dynamic address to be expired')
4240 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
4242 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
4244 for line
in output
.splitlines():
4245 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
4246 address2
= line
.split()[1].split('/')[0]
4249 self
.assertNotEqual(address1
, address2
)
4251 output
= check_output('ip -4 route show dev veth99')
4253 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
4254 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
4255 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
4256 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
4258 def test_dhcp_client_use_dns_yes(self
):
4259 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-yes.network')
4262 self
.wait_online(['veth-peer:carrier'])
4263 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
4264 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4266 # link become 'routable' when at least one protocol provide an valid address.
4267 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4268 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4271 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
4273 self
.assertRegex(output
, '192.168.5.1')
4274 self
.assertRegex(output
, '2600::1')
4276 def test_dhcp_client_use_dns_no(self
):
4277 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-no.network')
4280 self
.wait_online(['veth-peer:carrier'])
4281 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
4282 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4284 # link become 'routable' when at least one protocol provide an valid address.
4285 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4286 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4289 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
4291 self
.assertNotRegex(output
, '192.168.5.1')
4292 self
.assertNotRegex(output
, '2600::1')
4294 def test_dhcp_client_use_dns_ipv4(self
):
4295 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4.network')
4298 self
.wait_online(['veth-peer:carrier'])
4299 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
4300 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4302 # link become 'routable' when at least one protocol provide an valid address.
4303 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4304 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4307 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
4309 self
.assertRegex(output
, '192.168.5.1')
4310 self
.assertNotRegex(output
, '2600::1')
4312 def test_dhcp_client_use_dns_ipv4_and_ra(self
):
4313 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4-and-ra.network')
4316 self
.wait_online(['veth-peer:carrier'])
4317 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
4318 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4320 # link become 'routable' when at least one protocol provide an valid address.
4321 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4322 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4325 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
4327 self
.assertRegex(output
, '192.168.5.1')
4328 self
.assertRegex(output
, '2600::1')
4330 def test_dhcp_client_use_domains(self
):
4331 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-domains.network')
4334 self
.wait_online(['veth-peer:carrier'])
4335 start_dnsmasq('--dhcp-option=option:domain-search,example.com')
4336 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4338 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4340 self
.assertRegex(output
, 'Search Domains: example.com')
4343 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
4345 self
.assertRegex(output
, 'example.com')
4347 def test_dhcp_client_decline(self
):
4348 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-decline.network', 'dhcp-client-decline.network')
4351 self
.wait_online(['veth-peer:carrier'])
4352 rc
= call(*wait_online_cmd
, '--timeout=10s', '--interface=veth99:routable', env
=env
)
4353 self
.assertTrue(rc
== 1)
4355 class NetworkdIPv6PrefixTests(unittest
.TestCase
, Utilities
):
4360 'ipv6ra-prefix-client-deny-list.network',
4361 'ipv6ra-prefix-client.network',
4362 'ipv6ra-prefix.network'
4366 remove_links(self
.links
)
4367 stop_networkd(show_logs
=False)
4371 remove_links(self
.links
)
4372 remove_unit_from_networkd_path(self
.units
)
4373 stop_networkd(show_logs
=True)
4375 def test_ipv6_route_prefix(self
):
4376 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client.network', 'ipv6ra-prefix.network')
4379 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4381 output
= check_output('ip address show dev veth-peer')
4383 self
.assertIn('inet6 2001:db8:0:1:', output
)
4384 self
.assertNotIn('inet6 2001:db8:0:2:', output
)
4386 output
= check_output('ip -6 route show dev veth-peer')
4388 self
.assertIn('2001:db8:0:1::/64 proto ra', output
)
4389 self
.assertNotIn('2001:db8:0:2::/64 proto ra', output
)
4390 self
.assertIn('2001:db0:fff::/64 via ', output
)
4391 self
.assertNotIn('2001:db1:fff::/64 via ', output
)
4393 output
= check_output('ip address show dev veth99')
4395 self
.assertNotIn('inet6 2001:db8:0:1:', output
)
4396 self
.assertIn('inet6 2001:db8:0:2:', output
)
4398 def test_ipv6_route_prefix_deny_list(self
):
4399 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client-deny-list.network', 'ipv6ra-prefix.network')
4402 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4404 output
= check_output('ip address show dev veth-peer')
4406 self
.assertIn('inet6 2001:db8:0:1:', output
)
4407 self
.assertNotIn('inet6 2001:db8:0:2:', output
)
4409 output
= check_output('ip -6 route show dev veth-peer')
4411 self
.assertIn('2001:db8:0:1::/64 proto ra', output
)
4412 self
.assertNotIn('2001:db8:0:2::/64 proto ra', output
)
4413 self
.assertIn('2001:db0:fff::/64 via ', output
)
4414 self
.assertNotIn('2001:db1:fff::/64 via ', output
)
4416 output
= check_output('ip address show dev veth99')
4418 self
.assertNotIn('inet6 2001:db8:0:1:', output
)
4419 self
.assertIn('inet6 2001:db8:0:2:', output
)
4421 class NetworkdMTUTests(unittest
.TestCase
, Utilities
):
4426 '12-dummy-mtu.netdev',
4427 '12-dummy-mtu.link',
4432 remove_links(self
.links
)
4433 stop_networkd(show_logs
=False)
4437 remove_links(self
.links
)
4438 remove_unit_from_networkd_path(self
.units
)
4439 stop_networkd(show_logs
=True)
4441 def check_mtu(self
, mtu
, ipv6_mtu
=None, reset
=True):
4447 self
.wait_online(['dummy98:routable'])
4448 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
4449 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
4451 # test normal restart
4453 self
.wait_online(['dummy98:routable'])
4454 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
4455 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
4458 self
.reset_check_mtu(mtu
, ipv6_mtu
)
4460 def reset_check_mtu(self
, mtu
, ipv6_mtu
=None):
4461 ''' test setting mtu/ipv6_mtu with interface already up '''
4464 # note - changing the device mtu resets the ipv6 mtu
4465 run('ip link set up mtu 1501 dev dummy98')
4466 run('ip link set up mtu 1500 dev dummy98')
4467 self
.assertEqual(read_link_attr('dummy98', 'mtu'), '1500')
4468 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), '1500')
4470 self
.check_mtu(mtu
, ipv6_mtu
, reset
=False)
4472 def test_mtu_network(self
):
4473 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
4474 self
.check_mtu('1600')
4476 def test_mtu_netdev(self
):
4477 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network', dropins
=False)
4478 # note - MTU set by .netdev happens ONLY at device creation!
4479 self
.check_mtu('1600', reset
=False)
4481 def test_mtu_link(self
):
4482 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', dropins
=False)
4483 # must reload udev because it only picks up new files after 3 second delay
4484 call('udevadm control --reload')
4485 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
4486 self
.check_mtu('1600', reset
=False)
4488 def test_ipv6_mtu(self
):
4489 ''' set ipv6 mtu without setting device mtu '''
4490 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
4491 self
.check_mtu('1500', '1400')
4493 def test_ipv6_mtu_toolarge(self
):
4494 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
4495 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
4496 self
.check_mtu('1500', '1500')
4498 def test_mtu_network_ipv6_mtu(self
):
4499 ''' set ipv6 mtu and set device mtu via network file '''
4500 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
4501 self
.check_mtu('1600', '1550')
4503 def test_mtu_netdev_ipv6_mtu(self
):
4504 ''' set ipv6 mtu and set device mtu via netdev file '''
4505 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
4506 self
.check_mtu('1600', '1550', reset
=False)
4508 def test_mtu_link_ipv6_mtu(self
):
4509 ''' set ipv6 mtu and set device mtu via link file '''
4510 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
4511 # must reload udev because it only picks up new files after 3 second delay
4512 call('udevadm control --reload')
4513 self
.check_mtu('1600', '1550', reset
=False)
4516 if __name__
== '__main__':
4517 parser
= argparse
.ArgumentParser()
4518 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
4519 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
4520 parser
.add_argument('--resolved', help='Path to systemd-resolved', dest
='resolved_bin')
4521 parser
.add_argument('--udevd', help='Path to systemd-udevd', dest
='udevd_bin')
4522 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
4523 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
4524 parser
.add_argument('--resolvectl', help='Path to resolvectl', dest
='resolvectl_bin')
4525 parser
.add_argument('--timedatectl', help='Path to timedatectl', dest
='timedatectl_bin')
4526 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
4527 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
4528 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
4529 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
4530 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
4531 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
4534 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
:
4535 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
4536 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
4537 resolved_bin
= os
.path
.join(ns
.build_dir
, 'systemd-resolved')
4538 udevd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-udevd')
4539 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
4540 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
4541 resolvectl_bin
= os
.path
.join(ns
.build_dir
, 'resolvectl')
4542 timedatectl_bin
= os
.path
.join(ns
.build_dir
, 'timedatectl')
4545 networkd_bin
= ns
.networkd_bin
4547 resolved_bin
= ns
.resolved_bin
4549 udevd_bin
= ns
.udevd_bin
4550 if ns
.wait_online_bin
:
4551 wait_online_bin
= ns
.wait_online_bin
4552 if ns
.networkctl_bin
:
4553 networkctl_bin
= ns
.networkctl_bin
4554 if ns
.resolvectl_bin
:
4555 resolvectl_bin
= ns
.resolvectl_bin
4556 if ns
.timedatectl_bin
:
4557 timedatectl_bin
= ns
.timedatectl_bin
4559 use_valgrind
= ns
.use_valgrind
4560 enable_debug
= ns
.enable_debug
4561 asan_options
= ns
.asan_options
4562 lsan_options
= ns
.lsan_options
4563 ubsan_options
= ns
.ubsan_options
4566 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
4567 resolvectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin
]
4568 timedatectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin
]
4569 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
4571 networkctl_cmd
= [networkctl_bin
]
4572 resolvectl_cmd
= [resolvectl_bin
]
4573 timedatectl_cmd
= [timedatectl_bin
]
4574 wait_online_cmd
= [wait_online_bin
]
4577 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
4579 env
.update({ 'ASAN_OPTIONS' : asan_options
})
4581 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
4583 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
4586 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,