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-preferred-lifetime-zero.network',
1757 '25-address-static.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-link-local-addressing-no.network',
1767 '25-link-local-addressing-yes.network',
1768 '25-link-section-unmanaged.network',
1769 '25-neighbor-section.network',
1770 '25-neighbor-next.network',
1771 '25-neighbor-ipv6.network',
1772 '25-neighbor-ip-dummy.network',
1773 '25-neighbor-ip.network',
1774 '25-nexthop.network',
1775 '25-qdisc-cake.network',
1776 '25-qdisc-clsact-and-htb.network',
1777 '25-qdisc-drr.network',
1778 '25-qdisc-ets.network',
1779 '25-qdisc-fq_pie.network',
1780 '25-qdisc-hhf.network',
1781 '25-qdisc-ingress-netem-compat.network',
1782 '25-qdisc-pie.network',
1783 '25-qdisc-qfq.network',
1784 '25-prefix-route-with-vrf.network',
1785 '25-prefix-route-without-vrf.network',
1786 '25-route-ipv6-src.network',
1787 '25-route-static.network',
1788 '25-route-via-ipv6.network',
1789 '25-route-vrf.network',
1790 '25-gateway-static.network',
1791 '25-gateway-next-static.network',
1793 '25-sysctl-disable-ipv6.network',
1794 '25-sysctl.network',
1796 '25-veth-peer.network',
1800 '26-link-local-addressing-ipv6.network',
1801 'routing-policy-rule-dummy98.network',
1802 'routing-policy-rule-test1.network',
1803 'routing-policy-rule-reconfigure1.network',
1804 'routing-policy-rule-reconfigure2.network',
1807 routing_policy_rule_tables
= ['7', '8', '9', '1011']
1808 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1811 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1812 remove_routes(self
.routes
)
1813 remove_links(self
.links
)
1814 stop_networkd(show_logs
=False)
1817 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1818 remove_routes(self
.routes
)
1819 remove_links(self
.links
)
1820 remove_unit_from_networkd_path(self
.units
)
1821 stop_networkd(show_logs
=True)
1823 def test_address_static(self
):
1824 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1827 self
.wait_online(['dummy98:routable'])
1829 output
= check_output('ip -4 address show dev dummy98')
1831 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1832 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1833 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1835 # test for ENOBUFS issue #17012
1836 for i
in range(1,254):
1837 self
.assertRegex(output
, f
'inet 10.3.3.{i}/16 brd 10.3.255.255')
1840 self
.assertNotRegex(output
, '10.10.0.1/16')
1841 self
.assertNotRegex(output
, '10.10.0.2/16')
1843 output
= check_output('ip -4 address show dev dummy98 label 32')
1844 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1846 output
= check_output('ip -4 address show dev dummy98 label 33')
1847 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1849 output
= check_output('ip -4 address show dev dummy98 label 34')
1850 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1852 output
= check_output('ip -4 address show dev dummy98 label 35')
1853 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1855 output
= check_output('ip -6 address show dev dummy98')
1857 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1858 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1859 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1860 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1861 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1862 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1865 self
.wait_online(['dummy98:routable'])
1867 # test for ENOBUFS issue #17012
1868 output
= check_output('ip -4 address show dev dummy98')
1869 for i
in range(1,254):
1870 self
.assertRegex(output
, f
'inet 10.3.3.{i}/16 brd 10.3.255.255')
1872 def test_address_preferred_lifetime_zero_ipv6(self
):
1873 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero.network', '12-dummy.netdev')
1876 self
.wait_online(['dummy98:routable'])
1878 output
= check_output('ip address show dummy98')
1880 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1881 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1883 output
= check_output('ip route show dev dummy98')
1885 self
.assertRegex(output
, 'default via 20.20.20.1 proto static')
1887 def test_address_dad(self
):
1888 copy_unit_to_networkd_unit_path('25-address-dad-veth99.network', '25-address-dad-veth-peer.network',
1891 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
1893 output
= check_output('ip -4 address show dev veth99')
1895 self
.assertRegex(output
, '192.168.100.10/24')
1897 output
= check_output('ip -4 address show dev veth-peer')
1899 self
.assertNotRegex(output
, '192.168.100.10/24')
1901 def test_address_peer_ipv4(self
):
1902 # test for issue #17304
1903 copy_unit_to_networkd_unit_path('25-address-peer-ipv4.network', '12-dummy.netdev')
1905 for trial
in range(2):
1911 self
.wait_online(['dummy98:routable'])
1913 output
= check_output('ip -4 address show dev dummy98')
1914 self
.assertIn('inet 100.64.0.1 peer 100.64.0.2/32 scope global', output
)
1916 @expectedFailureIfModuleIsNotAvailable('vrf')
1917 def test_prefix_route(self
):
1918 copy_unit_to_networkd_unit_path('25-prefix-route-with-vrf.network', '12-dummy.netdev',
1919 '25-prefix-route-without-vrf.network', '11-dummy.netdev',
1920 '25-vrf.netdev', '25-vrf.network')
1921 for trial
in range(2):
1927 self
.wait_online(['dummy98:routable', 'test1:routable', 'vrf99:carrier'])
1929 output
= check_output('ip route show table 42 dev dummy98')
1930 print('### ip route show table 42 dev dummy98')
1932 self
.assertRegex(output
, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1')
1933 self
.assertRegex(output
, 'broadcast 10.20.33.0 proto kernel scope link src 10.20.33.1')
1934 self
.assertRegex(output
, '10.20.33.0/24 proto kernel scope link src 10.20.33.1')
1935 self
.assertRegex(output
, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1')
1936 self
.assertRegex(output
, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1')
1937 self
.assertRegex(output
, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1')
1938 self
.assertRegex(output
, 'broadcast 10.20.55.0 proto kernel scope link src 10.20.55.1')
1939 self
.assertRegex(output
, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1')
1940 self
.assertRegex(output
, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1')
1941 output
= check_output('ip -6 route show table 42 dev dummy98')
1942 print('### ip -6 route show table 42 dev dummy98')
1946 self
.assertRegex(output
, 'local fdde:11:22::1 proto kernel metric 0 pref medium')
1947 #self.assertRegex(output, 'fdde:11:22::1 proto kernel metric 256 pref medium')
1948 self
.assertRegex(output
, 'local fdde:11:33::1 proto kernel metric 0 pref medium')
1949 self
.assertRegex(output
, 'fdde:11:33::/64 proto kernel metric 256 pref medium')
1950 self
.assertRegex(output
, 'local fdde:11:44::1 proto kernel metric 0 pref medium')
1951 self
.assertRegex(output
, 'local fdde:11:55::1 proto kernel metric 0 pref medium')
1952 self
.assertRegex(output
, 'fe80::/64 proto kernel metric 256 pref medium')
1953 self
.assertRegex(output
, 'ff00::/8 metric 256 pref medium')
1957 output
= check_output('ip route show dev test1')
1958 print('### ip route show dev test1')
1960 self
.assertRegex(output
, '10.21.33.0/24 proto kernel scope link src 10.21.33.1')
1961 output
= check_output('ip route show table local dev test1')
1962 print('### ip route show table local dev test1')
1964 self
.assertRegex(output
, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1')
1965 self
.assertRegex(output
, 'broadcast 10.21.33.0 proto kernel scope link src 10.21.33.1')
1966 self
.assertRegex(output
, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1')
1967 self
.assertRegex(output
, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1')
1968 self
.assertRegex(output
, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1')
1969 self
.assertRegex(output
, 'broadcast 10.21.55.0 proto kernel scope link src 10.21.55.1')
1970 self
.assertRegex(output
, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1')
1971 self
.assertRegex(output
, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1')
1972 output
= check_output('ip -6 route show dev test1')
1973 print('### ip -6 route show dev test1')
1975 self
.assertRegex(output
, 'fdde:12:22::1 proto kernel metric 256 pref medium')
1976 self
.assertRegex(output
, 'fdde:12:33::/64 proto kernel metric 256 pref medium')
1977 self
.assertRegex(output
, 'fe80::/64 proto kernel metric 256 pref medium')
1978 output
= check_output('ip -6 route show table local dev test1')
1979 print('### ip -6 route show table local dev test1')
1981 self
.assertRegex(output
, 'local fdde:12:22::1 proto kernel metric 0 pref medium')
1982 self
.assertRegex(output
, 'local fdde:12:33::1 proto kernel metric 0 pref medium')
1983 self
.assertRegex(output
, 'local fdde:12:44::1 proto kernel metric 0 pref medium')
1984 self
.assertRegex(output
, 'local fdde:12:55::1 proto kernel metric 0 pref medium')
1985 self
.assertRegex(output
, 'ff00::/8 metric 256 pref medium')
1987 def test_configure_without_carrier(self
):
1988 copy_unit_to_networkd_unit_path('11-dummy.netdev')
1990 self
.wait_operstate('test1', 'off', '')
1991 check_output('ip link set dev test1 up carrier off')
1993 copy_unit_to_networkd_unit_path('25-test1.network.d/configure-without-carrier.conf', dropins
=False)
1995 self
.wait_online(['test1:no-carrier'])
1997 carrier_map
= {'on': '1', 'off': '0'}
1998 routable_map
= {'on': 'routable', 'off': 'no-carrier'}
1999 for carrier
in ['off', 'on', 'off']:
2000 with self
.subTest(carrier
=carrier
):
2001 if carrier_map
[carrier
] != read_link_attr('test1', 'carrier'):
2002 check_output(f
'ip link set dev test1 carrier {carrier}')
2003 self
.wait_online([f
'test1:{routable_map[carrier]}'])
2005 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
2007 self
.assertRegex(output
, '192.168.0.15')
2008 self
.assertRegex(output
, '192.168.0.1')
2009 self
.assertRegex(output
, routable_map
[carrier
])
2011 def test_configure_without_carrier_yes_ignore_carrier_loss_no(self
):
2012 copy_unit_to_networkd_unit_path('11-dummy.netdev')
2014 self
.wait_operstate('test1', 'off', '')
2015 check_output('ip link set dev test1 up carrier off')
2017 copy_unit_to_networkd_unit_path('25-test1.network')
2019 self
.wait_online(['test1:no-carrier'])
2021 carrier_map
= {'on': '1', 'off': '0'}
2022 routable_map
= {'on': 'routable', 'off': 'no-carrier'}
2023 for (carrier
, have_config
) in [('off', True), ('on', True), ('off', False)]:
2024 with self
.subTest(carrier
=carrier
, have_config
=have_config
):
2025 if carrier_map
[carrier
] != read_link_attr('test1', 'carrier'):
2026 check_output(f
'ip link set dev test1 carrier {carrier}')
2027 self
.wait_online([f
'test1:{routable_map[carrier]}'])
2029 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
2032 self
.assertRegex(output
, '192.168.0.15')
2033 self
.assertRegex(output
, '192.168.0.1')
2035 self
.assertNotRegex(output
, '192.168.0.15')
2036 self
.assertNotRegex(output
, '192.168.0.1')
2037 self
.assertRegex(output
, routable_map
[carrier
])
2039 def test_routing_policy_rule(self
):
2040 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
2042 self
.wait_online(['test1:degraded'])
2044 output
= check_output('ip rule list iif test1 priority 111')
2046 self
.assertRegex(output
, '111:')
2047 self
.assertRegex(output
, 'from 192.168.100.18')
2048 self
.assertRegex(output
, r
'tos (0x08|throughput)\s')
2049 self
.assertRegex(output
, 'iif test1')
2050 self
.assertRegex(output
, 'oif test1')
2051 self
.assertRegex(output
, 'lookup 7')
2053 output
= check_output('ip rule list iif test1 priority 101')
2055 self
.assertRegex(output
, '101:')
2056 self
.assertRegex(output
, 'from all')
2057 self
.assertRegex(output
, 'iif test1')
2058 self
.assertRegex(output
, 'lookup 9')
2060 output
= check_output('ip -6 rule list iif test1 priority 100')
2062 self
.assertRegex(output
, '100:')
2063 self
.assertRegex(output
, 'from all')
2064 self
.assertRegex(output
, 'iif test1')
2065 self
.assertRegex(output
, 'lookup 8')
2067 def test_routing_policy_rule_issue_11280(self
):
2068 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
2069 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
2071 for trial
in range(3):
2072 # Remove state files only first time
2074 self
.wait_online(['test1:degraded', 'dummy98:degraded'])
2077 output
= check_output('ip rule list table 7')
2079 self
.assertRegex(output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
2081 output
= check_output('ip rule list table 8')
2083 self
.assertRegex(output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
2085 stop_networkd(remove_state_files
=False)
2087 def test_routing_policy_rule_reconfigure(self
):
2088 copy_unit_to_networkd_unit_path('routing-policy-rule-reconfigure2.network', '11-dummy.netdev')
2090 self
.wait_online(['test1:degraded'])
2092 output
= check_output('ip rule list table 1011')
2094 self
.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output
)
2095 self
.assertIn('10112: from all oif test1 lookup 1011', output
)
2096 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2097 self
.assertIn('10114: from 192.168.8.254 lookup 1011', output
)
2099 output
= check_output('ip -6 rule list table 1011')
2101 self
.assertIn('10112: from all oif test1 lookup 1011', output
)
2103 copy_unit_to_networkd_unit_path('routing-policy-rule-reconfigure1.network', '11-dummy.netdev')
2104 run(*networkctl_cmd
, 'reload', env
=env
)
2106 self
.wait_online(['test1:degraded'])
2108 output
= check_output('ip rule list table 1011')
2110 self
.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output
)
2111 self
.assertIn('10112: from all oif test1 lookup 1011', output
)
2112 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2113 self
.assertIn('10114: from 192.168.8.254 lookup 1011', output
)
2115 output
= check_output('ip -6 rule list table 1011')
2117 self
.assertNotIn('10112: from all oif test1 lookup 1011', output
)
2118 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2120 run('ip rule delete priority 10111')
2121 run('ip rule delete priority 10112')
2122 run('ip rule delete priority 10113')
2123 run('ip rule delete priority 10114')
2124 run('ip -6 rule delete priority 10113')
2126 output
= check_output('ip rule list table 1011')
2128 self
.assertEqual(output
, '')
2130 output
= check_output('ip -6 rule list table 1011')
2132 self
.assertEqual(output
, '')
2134 run(*networkctl_cmd
, 'reconfigure', 'test1', env
=env
)
2135 self
.wait_online(['test1:degraded'])
2137 output
= check_output('ip rule list table 1011')
2139 self
.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output
)
2140 self
.assertIn('10112: from all oif test1 lookup 1011', output
)
2141 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2142 self
.assertIn('10114: from 192.168.8.254 lookup 1011', output
)
2144 output
= check_output('ip -6 rule list table 1011')
2146 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2148 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
2149 def test_routing_policy_rule_port_range(self
):
2150 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
2152 self
.wait_online(['test1:degraded'])
2154 output
= check_output('ip rule')
2156 self
.assertRegex(output
, '111')
2157 self
.assertRegex(output
, 'from 192.168.100.18')
2158 self
.assertRegex(output
, '1123-1150')
2159 self
.assertRegex(output
, '3224-3290')
2160 self
.assertRegex(output
, 'tcp')
2161 self
.assertRegex(output
, 'lookup 7')
2163 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
2164 def test_routing_policy_rule_invert(self
):
2165 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
2167 self
.wait_online(['test1:degraded'])
2169 output
= check_output('ip rule')
2171 self
.assertRegex(output
, '111')
2172 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
2173 self
.assertRegex(output
, 'tcp')
2174 self
.assertRegex(output
, 'lookup 7')
2176 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable()
2177 def test_routing_policy_rule_uidrange(self
):
2178 copy_unit_to_networkd_unit_path('25-fibrule-uidrange.network', '11-dummy.netdev')
2180 self
.wait_online(['test1:degraded'])
2182 output
= check_output('ip rule')
2184 self
.assertRegex(output
, '111')
2185 self
.assertRegex(output
, 'from 192.168.100.18')
2186 self
.assertRegex(output
, 'lookup 7')
2187 self
.assertRegex(output
, 'uidrange 100-200')
2189 def test_route_static(self
):
2190 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
2192 self
.wait_online(['dummy98:routable'])
2194 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2197 print('### ip -6 route show dev dummy98')
2198 output
= check_output('ip -6 route show dev dummy98')
2200 self
.assertIn('2001:1234:5:8fff:ff:ff:ff:ff proto static', output
)
2201 self
.assertIn('2001:1234:5:8f63::1 proto kernel', output
)
2203 print('### ip -6 route show default')
2204 output
= check_output('ip -6 route show default')
2206 self
.assertIn('default', output
)
2207 self
.assertIn('via 2001:1234:5:8fff:ff:ff:ff:ff', output
)
2209 print('### ip -4 route show dev dummy98')
2210 output
= check_output('ip -4 route show dev dummy98')
2212 self
.assertIn('149.10.124.48/28 proto kernel scope link src 149.10.124.58', output
)
2213 self
.assertIn('149.10.124.64 proto static scope link', output
)
2214 self
.assertIn('169.254.0.0/16 proto static scope link metric 2048', output
)
2215 self
.assertIn('192.168.1.1 proto static initcwnd 20', output
)
2216 self
.assertIn('192.168.1.2 proto static initrwnd 30', output
)
2217 self
.assertIn('192.168.1.3 proto static advmss 30', output
)
2218 self
.assertIn('multicast 149.10.123.4 proto static', output
)
2220 print('### ip -4 route show dev dummy98 default')
2221 output
= check_output('ip -4 route show dev dummy98 default')
2223 self
.assertIn('default via 149.10.125.65 proto static onlink', output
)
2224 self
.assertIn('default via 149.10.124.64 proto static', output
)
2225 self
.assertIn('default proto static', output
)
2227 print('### ip -4 route show table local dev dummy98')
2228 output
= check_output('ip -4 route show table local dev dummy98')
2230 self
.assertIn('local 149.10.123.1 proto static scope host', output
)
2231 self
.assertIn('anycast 149.10.123.2 proto static scope link', output
)
2232 self
.assertIn('broadcast 149.10.123.3 proto static scope link', output
)
2234 print('### ip route show type blackhole')
2235 output
= check_output('ip route show type blackhole')
2237 self
.assertIn('blackhole 202.54.1.2 proto static', output
)
2239 print('### ip route show type unreachable')
2240 output
= check_output('ip route show type unreachable')
2242 self
.assertIn('unreachable 202.54.1.3 proto static', output
)
2244 print('### ip route show type prohibit')
2245 output
= check_output('ip route show type prohibit')
2247 self
.assertIn('prohibit 202.54.1.4 proto static', output
)
2249 print('### ip -6 route show type blackhole')
2250 output
= check_output('ip -6 route show type blackhole')
2252 self
.assertIn('blackhole 2001:1234:5678::2 dev lo proto static', output
)
2254 print('### ip -6 route show type unreachable')
2255 output
= check_output('ip -6 route show type unreachable')
2257 self
.assertIn('unreachable 2001:1234:5678::3 dev lo proto static', output
)
2259 print('### ip -6 route show type prohibit')
2260 output
= check_output('ip -6 route show type prohibit')
2262 self
.assertIn('prohibit 2001:1234:5678::4 dev lo proto static', output
)
2264 print('### ip route show 192.168.10.1')
2265 output
= check_output('ip route show 192.168.10.1')
2267 self
.assertIn('192.168.10.1 proto static', output
)
2268 self
.assertIn('nexthop via 149.10.124.59 dev dummy98 weight 10', output
)
2269 self
.assertIn('nexthop via 149.10.124.60 dev dummy98 weight 5', output
)
2271 print('### ip route show 192.168.10.2')
2272 output
= check_output('ip route show 192.168.10.2')
2274 # old ip command does not show IPv6 gateways...
2275 self
.assertIn('192.168.10.2 proto static', output
)
2276 self
.assertIn('nexthop', output
)
2277 self
.assertIn('dev dummy98 weight 10', output
)
2278 self
.assertIn('dev dummy98 weight 5', output
)
2280 print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2281 output
= check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2283 # old ip command does not show 'nexthop' keyword and weight...
2284 self
.assertIn('2001:1234:5:7fff:ff:ff:ff:ff', output
)
2285 self
.assertIn('via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98', output
)
2286 self
.assertIn('via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98', output
)
2288 copy_unit_to_networkd_unit_path('25-address-static.network')
2289 check_output(*networkctl_cmd
, 'reload', env
=env
)
2291 self
.wait_online(['dummy98:routable'])
2293 # check all routes managed by Manager are removed
2294 print('### ip route show type blackhole')
2295 output
= check_output('ip route show type blackhole')
2297 self
.assertEqual(output
, '')
2299 print('### ip route show type unreachable')
2300 output
= check_output('ip route show type unreachable')
2302 self
.assertEqual(output
, '')
2304 print('### ip route show type prohibit')
2305 output
= check_output('ip route show type prohibit')
2307 self
.assertEqual(output
, '')
2309 print('### ip -6 route show type blackhole')
2310 output
= check_output('ip -6 route show type blackhole')
2312 self
.assertEqual(output
, '')
2314 print('### ip -6 route show type unreachable')
2315 output
= check_output('ip -6 route show type unreachable')
2317 self
.assertEqual(output
, '')
2319 print('### ip -6 route show type prohibit')
2320 output
= check_output('ip -6 route show type prohibit')
2322 self
.assertEqual(output
, '')
2324 remove_unit_from_networkd_path(['25-address-static.network'])
2325 check_output(*networkctl_cmd
, 'reload', env
=env
)
2327 self
.wait_online(['dummy98:routable'])
2329 # check all routes managed by Manager are reconfigured
2330 print('### ip route show type blackhole')
2331 output
= check_output('ip route show type blackhole')
2333 self
.assertIn('blackhole 202.54.1.2 proto static', output
)
2335 print('### ip route show type unreachable')
2336 output
= check_output('ip route show type unreachable')
2338 self
.assertIn('unreachable 202.54.1.3 proto static', output
)
2340 print('### ip route show type prohibit')
2341 output
= check_output('ip route show type prohibit')
2343 self
.assertIn('prohibit 202.54.1.4 proto static', output
)
2345 print('### ip -6 route show type blackhole')
2346 output
= check_output('ip -6 route show type blackhole')
2348 self
.assertIn('blackhole 2001:1234:5678::2 dev lo proto static', output
)
2350 print('### ip -6 route show type unreachable')
2351 output
= check_output('ip -6 route show type unreachable')
2353 self
.assertIn('unreachable 2001:1234:5678::3 dev lo proto static', output
)
2355 print('### ip -6 route show type prohibit')
2356 output
= check_output('ip -6 route show type prohibit')
2358 self
.assertIn('prohibit 2001:1234:5678::4 dev lo proto static', output
)
2360 rc
= call("ip link del dummy98")
2361 self
.assertEqual(rc
, 0)
2364 # check all routes managed by Manager are removed
2365 print('### ip route show type blackhole')
2366 output
= check_output('ip route show type blackhole')
2368 self
.assertEqual(output
, '')
2370 print('### ip route show type unreachable')
2371 output
= check_output('ip route show type unreachable')
2373 self
.assertEqual(output
, '')
2375 print('### ip route show type prohibit')
2376 output
= check_output('ip route show type prohibit')
2378 self
.assertEqual(output
, '')
2380 print('### ip -6 route show type blackhole')
2381 output
= check_output('ip -6 route show type blackhole')
2383 self
.assertEqual(output
, '')
2385 print('### ip -6 route show type unreachable')
2386 output
= check_output('ip -6 route show type unreachable')
2388 self
.assertEqual(output
, '')
2390 print('### ip -6 route show type prohibit')
2391 output
= check_output('ip -6 route show type prohibit')
2393 self
.assertEqual(output
, '')
2395 @expectedFailureIfRTA_VIAIsNotSupported()
2396 def test_route_via_ipv6(self
):
2397 copy_unit_to_networkd_unit_path('25-route-via-ipv6.network', '12-dummy.netdev')
2399 self
.wait_online(['dummy98:routable'])
2401 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2404 print('### ip -6 route show dev dummy98')
2405 output
= check_output('ip -6 route show dev dummy98')
2407 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
2408 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
2410 print('### ip -4 route show dev dummy98')
2411 output
= check_output('ip -4 route show dev dummy98')
2413 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
2414 self
.assertRegex(output
, '149.10.124.66 via inet6 2001:1234:5:8fff:ff:ff:ff:ff proto static')
2416 @expectedFailureIfModuleIsNotAvailable('vrf')
2417 def test_route_vrf(self
):
2418 copy_unit_to_networkd_unit_path('25-route-vrf.network', '12-dummy.netdev',
2419 '25-vrf.netdev', '25-vrf.network')
2421 self
.wait_online(['dummy98:routable', 'vrf99:carrier'])
2423 output
= check_output('ip route show vrf vrf99')
2425 self
.assertRegex(output
, 'default via 192.168.100.1')
2427 output
= check_output('ip route show')
2429 self
.assertNotRegex(output
, 'default via 192.168.100.1')
2431 def test_gateway_reconfigure(self
):
2432 copy_unit_to_networkd_unit_path('25-gateway-static.network', '12-dummy.netdev')
2434 self
.wait_online(['dummy98:routable'])
2435 print('### ip -4 route show dev dummy98 default')
2436 output
= check_output('ip -4 route show dev dummy98 default')
2438 self
.assertRegex(output
, 'default via 149.10.124.59 proto static')
2439 self
.assertNotRegex(output
, '149.10.124.60')
2441 remove_unit_from_networkd_path(['25-gateway-static.network'])
2442 copy_unit_to_networkd_unit_path('25-gateway-next-static.network')
2444 self
.wait_online(['dummy98:routable'])
2445 print('### ip -4 route show dev dummy98 default')
2446 output
= check_output('ip -4 route show dev dummy98 default')
2448 self
.assertNotRegex(output
, '149.10.124.59')
2449 self
.assertRegex(output
, 'default via 149.10.124.60 proto static')
2451 def test_ip_route_ipv6_src_route(self
):
2452 # a dummy device does not make the addresses go through tentative state, so we
2453 # reuse a bond from an earlier test, which does make the addresses go through
2454 # tentative state, and do our test on that
2455 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2457 self
.wait_online(['dummy98:enslaved', 'bond199:routable'])
2459 output
= check_output('ip -6 route list dev bond199')
2461 self
.assertRegex(output
, 'abcd::/16')
2462 self
.assertRegex(output
, 'src')
2463 self
.assertRegex(output
, '2001:1234:56:8f63::2')
2465 def test_ip_link_mac_address(self
):
2466 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
2468 self
.wait_online(['dummy98:degraded'])
2470 output
= check_output('ip link show dummy98')
2472 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
2474 def test_ip_link_unmanaged(self
):
2475 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
2478 self
.check_link_exists('dummy98')
2480 self
.wait_operstate('dummy98', 'off', setup_state
='unmanaged')
2482 def test_ipv6_address_label(self
):
2483 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
2485 self
.wait_online(['dummy98:degraded'])
2487 output
= check_output('ip addrlabel list')
2489 self
.assertRegex(output
, '2004:da8:1::/64')
2491 def test_neighbor_section(self
):
2492 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2494 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2496 print('### ip neigh list dev dummy98')
2497 output
= check_output('ip neigh list dev dummy98')
2499 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2500 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2502 def test_neighbor_reconfigure(self
):
2503 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2505 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2507 print('### ip neigh list dev dummy98')
2508 output
= check_output('ip neigh list dev dummy98')
2510 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2511 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2513 remove_unit_from_networkd_path(['25-neighbor-section.network'])
2514 copy_unit_to_networkd_unit_path('25-neighbor-next.network')
2516 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2517 print('### ip neigh list dev dummy98')
2518 output
= check_output('ip neigh list dev dummy98')
2520 self
.assertNotRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2521 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT')
2522 self
.assertNotRegex(output
, '2004:da8:1::1.*PERMANENT')
2524 def test_neighbor_gre(self
):
2525 copy_unit_to_networkd_unit_path('25-neighbor-ip.network', '25-neighbor-ipv6.network', '25-neighbor-ip-dummy.network',
2526 '12-dummy.netdev', '25-gre-tunnel-remote-any.netdev', '25-ip6gre-tunnel-remote-any.netdev')
2528 self
.wait_online(['dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable'], timeout
='40s')
2530 output
= check_output('ip neigh list dev gretun97')
2532 self
.assertRegex(output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT')
2534 output
= check_output('ip neigh list dev ip6gretun97')
2536 self
.assertRegex(output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
2538 def test_link_local_addressing(self
):
2539 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
2540 '25-link-local-addressing-no.network', '12-dummy.netdev')
2542 self
.wait_online(['test1:degraded', 'dummy98:carrier'])
2544 output
= check_output('ip address show dev test1')
2546 self
.assertRegex(output
, 'inet .* scope link')
2547 self
.assertRegex(output
, 'inet6 .* scope link')
2549 output
= check_output('ip address show dev dummy98')
2551 self
.assertNotRegex(output
, 'inet6* .* scope link')
2554 Documentation/networking/ip-sysctl.txt
2556 addr_gen_mode - INTEGER
2557 Defines how link-local and autoconf addresses are generated.
2559 0: generate address based on EUI64 (default)
2560 1: do no generate a link-local address, use EUI64 for addresses generated
2562 2: generate stable privacy addresses, using the secret from
2563 stable_secret (RFC7217)
2564 3: generate stable privacy addresses, using a random secret if unset
2567 test1_addr_gen_mode
= ''
2568 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
2569 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
2573 # if stable_secret is unset, then EIO is returned
2574 test1_addr_gen_mode
= '0'
2576 test1_addr_gen_mode
= '2'
2578 test1_addr_gen_mode
= '0'
2580 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
2581 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
2583 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
2584 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
2586 def test_link_local_addressing_remove_ipv6ll(self
):
2587 copy_unit_to_networkd_unit_path('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
2589 self
.wait_online(['dummy98:degraded'])
2591 output
= check_output('ip address show dev dummy98')
2593 self
.assertRegex(output
, 'inet6 .* scope link')
2595 copy_unit_to_networkd_unit_path('25-link-local-addressing-no.network')
2597 self
.wait_online(['dummy98:carrier'])
2599 output
= check_output('ip address show dev dummy98')
2601 self
.assertNotRegex(output
, 'inet6* .* scope link')
2603 def test_sysctl(self
):
2604 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
2606 self
.wait_online(['dummy98:degraded'])
2608 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
2609 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
2610 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
2611 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
2612 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
2613 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
2614 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
2615 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'accept_local'), '1')
2617 def test_sysctl_disable_ipv6(self
):
2618 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
2620 print('## Disable ipv6')
2621 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
2622 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
2625 self
.wait_online(['dummy98:routable'])
2627 output
= check_output('ip -4 address show dummy98')
2629 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2630 output
= check_output('ip -6 address show dummy98')
2632 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2633 self
.assertRegex(output
, 'inet6 .* scope link')
2634 output
= check_output('ip -4 route show dev dummy98')
2636 self
.assertRegex(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2637 output
= check_output('ip -6 route show default')
2639 self
.assertRegex(output
, 'default')
2640 self
.assertRegex(output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff')
2642 check_output('ip link del dummy98')
2644 print('## Enable ipv6')
2645 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
2646 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
2649 self
.wait_online(['dummy98:routable'])
2651 output
= check_output('ip -4 address show dummy98')
2653 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2654 output
= check_output('ip -6 address show dummy98')
2656 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2657 self
.assertRegex(output
, 'inet6 .* scope link')
2658 output
= check_output('ip -4 route show dev dummy98')
2660 self
.assertRegex(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2661 output
= check_output('ip -6 route show default')
2663 self
.assertRegex(output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff')
2665 def test_bind_carrier(self
):
2666 check_output('ip link add dummy98 type dummy')
2667 check_output('ip link set dummy98 up')
2670 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
2672 self
.wait_online(['test1:routable'])
2674 output
= check_output('ip address show test1')
2676 self
.assertRegex(output
, 'UP,LOWER_UP')
2677 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2678 self
.wait_operstate('test1', 'routable')
2680 check_output('ip link add dummy99 type dummy')
2681 check_output('ip link set dummy99 up')
2683 output
= check_output('ip address show test1')
2685 self
.assertRegex(output
, 'UP,LOWER_UP')
2686 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2687 self
.wait_operstate('test1', 'routable')
2689 check_output('ip link del dummy98')
2691 output
= check_output('ip address show test1')
2693 self
.assertRegex(output
, 'UP,LOWER_UP')
2694 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2695 self
.wait_operstate('test1', 'routable')
2697 check_output('ip link set dummy99 down')
2699 output
= check_output('ip address show test1')
2701 self
.assertNotRegex(output
, 'UP,LOWER_UP')
2702 self
.assertRegex(output
, 'DOWN')
2703 self
.assertNotRegex(output
, '192.168.10')
2704 self
.wait_operstate('test1', 'off')
2706 check_output('ip link set dummy99 up')
2708 output
= check_output('ip address show test1')
2710 self
.assertRegex(output
, 'UP,LOWER_UP')
2711 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2712 self
.wait_operstate('test1', 'routable')
2714 def test_domain(self
):
2715 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
2717 self
.wait_online(['dummy98:routable'])
2719 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2721 self
.assertRegex(output
, 'Address: 192.168.42.100')
2722 self
.assertRegex(output
, 'DNS: 192.168.42.1')
2723 self
.assertRegex(output
, 'Search Domains: one')
2725 def test_keep_configuration_static(self
):
2726 check_output('systemctl stop systemd-networkd.socket')
2727 check_output('systemctl stop systemd-networkd.service')
2729 check_output('ip link add name dummy98 type dummy')
2730 check_output('ip address add 10.1.2.3/16 dev dummy98')
2731 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
2732 output
= check_output('ip address show dummy98')
2734 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2735 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2736 output
= check_output('ip route show dev dummy98')
2739 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
2741 self
.wait_online(['dummy98:routable'])
2743 output
= check_output('ip address show dummy98')
2745 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2746 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2748 @expectedFailureIfNexthopIsNotAvailable()
2749 def test_nexthop(self
):
2750 copy_unit_to_networkd_unit_path('25-nexthop.network', '25-veth.netdev', '25-veth-peer.network')
2752 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2754 output
= check_output('ip nexthop list dev veth99')
2756 self
.assertRegex(output
, '192.168.5.1')
2758 def test_qdisc(self
):
2759 copy_unit_to_networkd_unit_path('25-qdisc-clsact-and-htb.network', '12-dummy.netdev',
2760 '25-qdisc-ingress-netem-compat.network', '11-dummy.netdev')
2761 check_output('modprobe sch_teql max_equalizers=2')
2764 self
.wait_online(['dummy98:routable', 'test1:routable'])
2766 output
= check_output('tc qdisc show dev test1')
2768 self
.assertRegex(output
, 'qdisc netem')
2769 self
.assertRegex(output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
2770 self
.assertRegex(output
, 'qdisc ingress')
2772 output
= check_output('tc qdisc show dev dummy98')
2774 self
.assertRegex(output
, 'qdisc clsact')
2776 self
.assertRegex(output
, 'qdisc htb 2: root')
2777 self
.assertRegex(output
, r
'default (0x30|30)')
2779 self
.assertRegex(output
, 'qdisc netem 30: parent 2:30')
2780 self
.assertRegex(output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
2781 self
.assertRegex(output
, 'qdisc fq_codel')
2782 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')
2784 self
.assertRegex(output
, 'qdisc teql1 31: parent 2:31')
2786 self
.assertRegex(output
, 'qdisc fq 32: parent 2:32')
2787 self
.assertRegex(output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
2788 self
.assertRegex(output
, 'quantum 1500')
2789 self
.assertRegex(output
, 'initial_quantum 13000')
2790 self
.assertRegex(output
, 'maxrate 1Mbit')
2792 self
.assertRegex(output
, 'qdisc codel 33: parent 2:33')
2793 self
.assertRegex(output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn')
2795 self
.assertRegex(output
, 'qdisc fq_codel 34: parent 2:34')
2796 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')
2798 self
.assertRegex(output
, 'qdisc tbf 35: parent 2:35')
2799 self
.assertRegex(output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms')
2801 self
.assertRegex(output
, 'qdisc sfq 36: parent 2:36')
2802 self
.assertRegex(output
, 'perturb 5sec')
2804 self
.assertRegex(output
, 'qdisc pfifo 37: parent 2:37')
2805 self
.assertRegex(output
, 'limit 100000p')
2807 self
.assertRegex(output
, 'qdisc gred 38: parent 2:38')
2808 self
.assertRegex(output
, 'vqs 12 default 10 grio')
2810 self
.assertRegex(output
, 'qdisc sfb 39: parent 2:39')
2811 self
.assertRegex(output
, 'limit 200000')
2813 self
.assertRegex(output
, 'qdisc bfifo 3a: parent 2:3a')
2814 self
.assertRegex(output
, 'limit 1000000')
2816 self
.assertRegex(output
, 'qdisc pfifo_head_drop 3b: parent 2:3b')
2817 self
.assertRegex(output
, 'limit 1023p')
2819 self
.assertRegex(output
, 'qdisc pfifo_fast 3c: parent 2:3c')
2821 output
= check_output('tc -d class show dev dummy98')
2823 self
.assertRegex(output
, 'class htb 2:30 root leaf 30:')
2824 self
.assertRegex(output
, 'class htb 2:31 root leaf 31:')
2825 self
.assertRegex(output
, 'class htb 2:32 root leaf 32:')
2826 self
.assertRegex(output
, 'class htb 2:33 root leaf 33:')
2827 self
.assertRegex(output
, 'class htb 2:34 root leaf 34:')
2828 self
.assertRegex(output
, 'class htb 2:35 root leaf 35:')
2829 self
.assertRegex(output
, 'class htb 2:36 root leaf 36:')
2830 self
.assertRegex(output
, 'class htb 2:37 root leaf 37:')
2831 self
.assertRegex(output
, 'class htb 2:38 root leaf 38:')
2832 self
.assertRegex(output
, 'class htb 2:39 root leaf 39:')
2833 self
.assertRegex(output
, 'class htb 2:3a root leaf 3a:')
2834 self
.assertRegex(output
, 'class htb 2:3b root leaf 3b:')
2835 self
.assertRegex(output
, 'class htb 2:3c root leaf 3c:')
2836 self
.assertRegex(output
, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit')
2837 self
.assertRegex(output
, 'burst 123456')
2838 self
.assertRegex(output
, 'cburst 123457')
2840 def test_qdisc2(self
):
2841 copy_unit_to_networkd_unit_path('25-qdisc-drr.network', '12-dummy.netdev',
2842 '25-qdisc-qfq.network', '11-dummy.netdev')
2845 self
.wait_online(['dummy98:routable', 'test1:routable'])
2847 output
= check_output('tc qdisc show dev dummy98')
2849 self
.assertRegex(output
, 'qdisc drr 2: root')
2850 output
= check_output('tc class show dev dummy98')
2852 self
.assertRegex(output
, 'class drr 2:30 root quantum 2000b')
2854 output
= check_output('tc qdisc show dev test1')
2856 self
.assertRegex(output
, 'qdisc qfq 2: root')
2857 output
= check_output('tc class show dev test1')
2859 self
.assertRegex(output
, 'class qfq 2:30 root weight 2 maxpkt 16000')
2860 self
.assertRegex(output
, 'class qfq 2:31 root weight 10 maxpkt 8000')
2862 @expectedFailureIfCAKEIsNotAvailable()
2863 def test_qdisc_cake(self
):
2864 copy_unit_to_networkd_unit_path('25-qdisc-cake.network', '12-dummy.netdev')
2866 self
.wait_online(['dummy98:routable'])
2868 output
= check_output('tc qdisc show dev dummy98')
2870 self
.assertRegex(output
, 'qdisc cake 3a: root')
2871 self
.assertRegex(output
, 'bandwidth 500Mbit')
2872 self
.assertRegex(output
, 'overhead 128')
2874 @expectedFailureIfPIEIsNotAvailable()
2875 def test_qdisc_pie(self
):
2876 copy_unit_to_networkd_unit_path('25-qdisc-pie.network', '12-dummy.netdev')
2878 self
.wait_online(['dummy98:routable'])
2880 output
= check_output('tc qdisc show dev dummy98')
2882 self
.assertRegex(output
, 'qdisc pie 3a: root')
2883 self
.assertRegex(output
, 'limit 200000')
2885 @expectedFailureIfHHFIsNotAvailable()
2886 def test_qdisc_hhf(self
):
2887 copy_unit_to_networkd_unit_path('25-qdisc-hhf.network', '12-dummy.netdev')
2889 self
.wait_online(['dummy98:routable'])
2891 output
= check_output('tc qdisc show dev dummy98')
2893 self
.assertRegex(output
, 'qdisc hhf 3a: root')
2894 self
.assertRegex(output
, 'limit 1022p')
2896 @expectedFailureIfETSIsNotAvailable()
2897 def test_qdisc_ets(self
):
2898 copy_unit_to_networkd_unit_path('25-qdisc-ets.network', '12-dummy.netdev')
2900 self
.wait_online(['dummy98:routable'])
2902 output
= check_output('tc qdisc show dev dummy98')
2905 self
.assertRegex(output
, 'qdisc ets 3a: root')
2906 self
.assertRegex(output
, 'bands 10 strict 3')
2907 self
.assertRegex(output
, 'quanta 1 2 3 4 5')
2908 self
.assertRegex(output
, 'priomap 3 4 5 6 7')
2910 @expectedFailureIfFQPIEIsNotAvailable()
2911 def test_qdisc_fq_pie(self
):
2912 copy_unit_to_networkd_unit_path('25-qdisc-fq_pie.network', '12-dummy.netdev')
2914 self
.wait_online(['dummy98:routable'])
2916 output
= check_output('tc qdisc show dev dummy98')
2919 self
.assertRegex(output
, 'qdisc fq_pie 3a: root')
2920 self
.assertRegex(output
, 'limit 200000p')
2922 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable()
2923 def test_sriov(self
):
2924 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
2925 call('modprobe netdevsim', stderr
=subprocess
.DEVNULL
)
2926 with
open('/sys/bus/netdevsim/new_device', mode
='w') as f
:
2929 call('udevadm settle')
2930 call('udevadm info -w10s /sys/devices/netdevsim99/net/eni99np1', stderr
=subprocess
.DEVNULL
)
2931 with
open('/sys/class/net/eni99np1/device/sriov_numvfs', mode
='w') as f
:
2934 copy_unit_to_networkd_unit_path('25-sriov.network')
2936 self
.wait_online(['eni99np1:routable'])
2938 output
= check_output('ip link show dev eni99np1')
2940 self
.assertRegex(output
,
2941 '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 *'
2942 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
2943 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
2946 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
2948 class NetworkdStateFileTests(unittest
.TestCase
, Utilities
):
2955 'state-file-tests.network',
2959 remove_links(self
.links
)
2960 stop_networkd(show_logs
=False)
2963 remove_links(self
.links
)
2964 remove_unit_from_networkd_path(self
.units
)
2965 stop_networkd(show_logs
=True)
2967 def test_state_file(self
):
2968 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'state-file-tests.network')
2970 self
.wait_online(['dummy98:routable'])
2972 output
= check_output(*networkctl_cmd
, '--no-legend', 'list', 'dummy98', env
=env
)
2974 ifindex
= output
.split()[0]
2976 path
= os
.path
.join('/run/systemd/netif/links/', ifindex
)
2977 self
.assertTrue(os
.path
.exists(path
))
2979 # make link state file updated
2980 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
2982 with
open(path
) as f
:
2984 self
.assertRegex(data
, r
'ADMIN_STATE=configured')
2985 self
.assertRegex(data
, r
'OPER_STATE=routable')
2986 self
.assertRegex(data
, r
'REQUIRED_FOR_ONLINE=yes')
2987 self
.assertRegex(data
, r
'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
2988 self
.assertRegex(data
, r
'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
2989 self
.assertRegex(data
, r
'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
2990 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2991 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2992 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2993 self
.assertRegex(data
, r
'LLMNR=no')
2994 self
.assertRegex(data
, r
'MDNS=yes')
2995 self
.assertRegex(data
, r
'DNSSEC=no')
2997 check_output(*resolvectl_cmd
, 'dns', 'dummy98', '10.10.10.12#ccc.com', '10.10.10.13', '1111:2222::3333', env
=env
)
2998 check_output(*resolvectl_cmd
, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env
=env
)
2999 check_output(*resolvectl_cmd
, 'llmnr', 'dummy98', 'yes', env
=env
)
3000 check_output(*resolvectl_cmd
, 'mdns', 'dummy98', 'no', env
=env
)
3001 check_output(*resolvectl_cmd
, 'dnssec', 'dummy98', 'yes', env
=env
)
3002 check_output(*timedatectl_cmd
, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env
=env
)
3004 with
open(path
) as f
:
3006 self
.assertRegex(data
, r
'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333')
3007 self
.assertRegex(data
, r
'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org')
3008 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
3009 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
3010 self
.assertRegex(data
, r
'LLMNR=yes')
3011 self
.assertRegex(data
, r
'MDNS=no')
3012 self
.assertRegex(data
, r
'DNSSEC=yes')
3014 check_output(*timedatectl_cmd
, 'revert', 'dummy98', env
=env
)
3016 with
open(path
) as f
:
3018 self
.assertRegex(data
, r
'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333')
3019 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
3020 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
3021 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
3022 self
.assertRegex(data
, r
'LLMNR=yes')
3023 self
.assertRegex(data
, r
'MDNS=no')
3024 self
.assertRegex(data
, r
'DNSSEC=yes')
3026 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
3028 with
open(path
) as f
:
3030 self
.assertRegex(data
, r
'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
3031 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
3032 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
3033 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
3034 self
.assertRegex(data
, r
'LLMNR=no')
3035 self
.assertRegex(data
, r
'MDNS=yes')
3036 self
.assertRegex(data
, r
'DNSSEC=no')
3038 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
3048 '23-active-slave.network',
3049 '23-bond199.network',
3050 '23-primary-slave.network',
3051 '25-bond-active-backup-slave.netdev',
3054 'bond-slave.network']
3057 remove_links(self
.links
)
3058 stop_networkd(show_logs
=False)
3061 remove_links(self
.links
)
3062 remove_unit_from_networkd_path(self
.units
)
3063 stop_networkd(show_logs
=True)
3065 def test_bond_active_slave(self
):
3066 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
3068 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
3070 output
= check_output('ip -d link show bond199')
3072 self
.assertRegex(output
, 'active_slave dummy98')
3074 def test_bond_primary_slave(self
):
3075 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
3077 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
3079 output
= check_output('ip -d link show bond199')
3081 self
.assertRegex(output
, 'primary dummy98')
3083 def test_bond_operstate(self
):
3084 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
3085 'bond99.network','bond-slave.network')
3087 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
3089 output
= check_output('ip -d link show dummy98')
3091 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
3093 output
= check_output('ip -d link show test1')
3095 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
3097 output
= check_output('ip -d link show bond99')
3099 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
3101 self
.wait_operstate('dummy98', 'enslaved')
3102 self
.wait_operstate('test1', 'enslaved')
3103 self
.wait_operstate('bond99', 'routable')
3105 check_output('ip link set dummy98 down')
3107 self
.wait_operstate('dummy98', 'off')
3108 self
.wait_operstate('test1', 'enslaved')
3109 self
.wait_operstate('bond99', 'degraded-carrier')
3111 check_output('ip link set dummy98 up')
3113 self
.wait_operstate('dummy98', 'enslaved')
3114 self
.wait_operstate('test1', 'enslaved')
3115 self
.wait_operstate('bond99', 'routable')
3117 check_output('ip link set dummy98 down')
3118 check_output('ip link set test1 down')
3120 self
.wait_operstate('dummy98', 'off')
3121 self
.wait_operstate('test1', 'off')
3123 if not self
.wait_operstate('bond99', 'no-carrier', setup_timeout
=30, fail_assert
=False):
3124 # Huh? Kernel does not recognize that all slave interfaces are down?
3125 # Let's confirm that networkd's operstate is consistent with ip's result.
3126 self
.assertNotRegex(output
, 'NO-CARRIER')
3128 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
3138 '26-bridge-configure-without-carrier.network',
3139 '26-bridge-mdb-master.network',
3140 '26-bridge-mdb-slave.network',
3141 '26-bridge-slave-interface-1.network',
3142 '26-bridge-slave-interface-2.network',
3143 '26-bridge-vlan-master.network',
3144 '26-bridge-vlan-slave.network',
3145 'bridge99-ignore-carrier-loss.network',
3148 routing_policy_rule_tables
= ['100']
3151 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
3152 remove_links(self
.links
)
3153 stop_networkd(show_logs
=False)
3156 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
3157 remove_links(self
.links
)
3158 remove_unit_from_networkd_path(self
.units
)
3159 stop_networkd(show_logs
=True)
3161 def test_bridge_vlan(self
):
3162 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
3163 '26-bridge.netdev', '26-bridge-vlan-master.network')
3165 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
3167 output
= check_output('bridge vlan show dev test1')
3169 self
.assertNotRegex(output
, '4063')
3170 for i
in range(4064, 4095):
3171 self
.assertRegex(output
, f
'{i}')
3172 self
.assertNotRegex(output
, '4095')
3174 output
= check_output('bridge vlan show dev bridge99')
3176 self
.assertNotRegex(output
, '4059')
3177 for i
in range(4060, 4095):
3178 self
.assertRegex(output
, f
'{i}')
3179 self
.assertNotRegex(output
, '4095')
3181 def test_bridge_mdb(self
):
3182 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-mdb-slave.network',
3183 '26-bridge.netdev', '26-bridge-mdb-master.network')
3185 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
3187 output
= check_output('bridge mdb show dev bridge99')
3189 self
.assertRegex(output
, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064')
3190 self
.assertRegex(output
, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065')
3192 # Old kernel may not support bridge MDB entries on bridge master
3193 if call('bridge mdb add dev bridge99 port bridge99 grp 224.0.1.3 temp vid 4068', stderr
=subprocess
.DEVNULL
) == 0:
3194 self
.assertRegex(output
, 'dev bridge99 port bridge99 grp ff02:aaaa:fee5::1:4 temp *vid 4066')
3195 self
.assertRegex(output
, 'dev bridge99 port bridge99 grp 224.0.1.2 temp *vid 4067')
3197 def test_bridge_property(self
):
3198 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
3199 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
3202 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
3204 output
= check_output('ip -d link show test1')
3206 self
.assertRegex(output
, 'master')
3207 self
.assertRegex(output
, 'bridge')
3209 output
= check_output('ip -d link show dummy98')
3211 self
.assertRegex(output
, 'master')
3212 self
.assertRegex(output
, 'bridge')
3214 output
= check_output('ip addr show bridge99')
3216 self
.assertRegex(output
, '192.168.0.15/24')
3218 output
= check_output('bridge -d link show dummy98')
3220 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
3221 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
3222 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
3223 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
3224 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
3225 # CONFIG_BRIDGE_IGMP_SNOOPING=y
3226 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
3227 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
3228 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
3229 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
3230 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
3231 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'priority'), '23')
3232 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard'), '1')
3233 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'root_block'), '1')
3235 output
= check_output('bridge -d link show test1')
3237 self
.assertEqual(read_bridge_port_attr('bridge99', 'test1', 'priority'), '0')
3239 check_output('ip address add 192.168.0.16/24 dev bridge99')
3242 output
= check_output('ip addr show bridge99')
3244 self
.assertRegex(output
, '192.168.0.16/24')
3247 print('### ip -6 route list table all dev bridge99')
3248 output
= check_output('ip -6 route list table all dev bridge99')
3250 self
.assertRegex(output
, 'ff00::/8 table local metric 256 pref medium')
3252 self
.assertEqual(call('ip link del test1'), 0)
3254 self
.wait_operstate('bridge99', 'degraded-carrier')
3256 check_output('ip link del dummy98')
3258 self
.wait_operstate('bridge99', 'no-carrier')
3260 output
= check_output('ip address show bridge99')
3262 self
.assertRegex(output
, 'NO-CARRIER')
3263 self
.assertNotRegex(output
, '192.168.0.15/24')
3264 self
.assertNotRegex(output
, '192.168.0.16/24')
3266 print('### ip -6 route list table all dev bridge99')
3267 output
= check_output('ip -6 route list table all dev bridge99')
3269 self
.assertRegex(output
, 'ff00::/8 table local metric 256 (linkdown )?pref medium')
3271 def test_bridge_configure_without_carrier(self
):
3272 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-configure-without-carrier.network',
3276 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
3277 for test
in ['no-slave', 'add-slave', 'slave-up', 'slave-no-carrier', 'slave-carrier', 'slave-down']:
3278 with self
.subTest(test
=test
):
3279 if test
== 'no-slave':
3280 # bridge has no slaves; it's up but *might* not have carrier
3281 self
.wait_operstate('bridge99', operstate
=r
'(no-carrier|routable)', setup_state
=None, setup_timeout
=30)
3282 # due to a bug in the kernel, newly-created bridges are brought up
3283 # *with* carrier, unless they have had any setting changed; e.g.
3284 # their mac set, priority set, etc. Then, they will lose carrier
3285 # as soon as a (down) slave interface is added, and regain carrier
3286 # again once the slave interface is brought up.
3287 #self.check_link_attr('bridge99', 'carrier', '0')
3288 elif test
== 'add-slave':
3289 # add slave to bridge, but leave it down; bridge is definitely no-carrier
3290 self
.check_link_attr('test1', 'operstate', 'down')
3291 check_output('ip link set dev test1 master bridge99')
3292 self
.wait_operstate('bridge99', operstate
='no-carrier', setup_state
=None)
3293 self
.check_link_attr('bridge99', 'carrier', '0')
3294 elif test
== 'slave-up':
3295 # bring up slave, which will have carrier; bridge gains carrier
3296 check_output('ip link set dev test1 up')
3297 self
.wait_online(['bridge99:routable'])
3298 self
.check_link_attr('bridge99', 'carrier', '1')
3299 elif test
== 'slave-no-carrier':
3300 # drop slave carrier; bridge loses carrier
3301 check_output('ip link set dev test1 carrier off')
3302 self
.wait_online(['bridge99:no-carrier:no-carrier'])
3303 self
.check_link_attr('bridge99', 'carrier', '0')
3304 elif test
== 'slave-carrier':
3305 # restore slave carrier; bridge gains carrier
3306 check_output('ip link set dev test1 carrier on')
3307 self
.wait_online(['bridge99:routable'])
3308 self
.check_link_attr('bridge99', 'carrier', '1')
3309 elif test
== 'slave-down':
3310 # bring down slave; bridge loses carrier
3311 check_output('ip link set dev test1 down')
3312 self
.wait_online(['bridge99:no-carrier:no-carrier'])
3313 self
.check_link_attr('bridge99', 'carrier', '0')
3315 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
3316 self
.assertRegex(output
, '10.1.2.3')
3317 self
.assertRegex(output
, '10.1.2.1')
3319 def test_bridge_ignore_carrier_loss(self
):
3320 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
3321 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
3322 'bridge99-ignore-carrier-loss.network')
3324 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
3326 check_output('ip address add 192.168.0.16/24 dev bridge99')
3329 check_output('ip link del test1')
3330 check_output('ip link del dummy98')
3333 output
= check_output('ip address show bridge99')
3335 self
.assertRegex(output
, 'NO-CARRIER')
3336 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
3337 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
3339 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
3340 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
3341 'bridge99-ignore-carrier-loss.network')
3343 self
.wait_online(['bridge99:no-carrier'])
3345 for trial
in range(4):
3346 check_output('ip link add dummy98 type dummy')
3347 check_output('ip link set dummy98 up')
3349 check_output('ip link del dummy98')
3351 self
.wait_online(['bridge99:routable', 'dummy98:enslaved'])
3353 output
= check_output('ip address show bridge99')
3355 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
3357 output
= check_output('ip rule list table 100')
3359 self
.assertIn('0: from all to 8.8.8.8 lookup 100', output
)
3361 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
3365 '23-emit-lldp.network',
3370 remove_links(self
.links
)
3371 stop_networkd(show_logs
=False)
3374 remove_links(self
.links
)
3375 remove_unit_from_networkd_path(self
.units
)
3376 stop_networkd(show_logs
=True)
3378 def test_lldp(self
):
3379 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
3381 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
3383 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
3385 self
.assertRegex(output
, 'veth-peer')
3386 self
.assertRegex(output
, 'veth99')
3388 class NetworkdRATests(unittest
.TestCase
, Utilities
):
3393 'ipv6-prefix.network',
3394 'ipv6-prefix-veth.network',
3395 'ipv6-prefix-veth-token-static.network',
3396 'ipv6-prefix-veth-token-prefixstable.network',
3397 'ipv6-prefix-veth-token-prefixstable-without-address.network']
3400 remove_links(self
.links
)
3401 stop_networkd(show_logs
=False)
3404 remove_links(self
.links
)
3405 remove_unit_from_networkd_path(self
.units
)
3406 stop_networkd(show_logs
=True)
3408 def test_ipv6_prefix_delegation(self
):
3409 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
3411 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3413 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3415 self
.assertRegex(output
, 'fe80::')
3416 self
.assertRegex(output
, '2002:da8:1::1')
3418 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
3420 self
.assertIn('hogehoge.test', output
)
3422 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3424 self
.assertRegex(output
, '2002:da8:1:0')
3426 def test_ipv6_token_static(self
):
3427 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static.network')
3429 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3431 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3433 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
3434 self
.assertRegex(output
, '2002:da8:1:0:fa:de:ca:fe')
3435 self
.assertRegex(output
, '2002:da8:2:0:1a:2b:3c:4d')
3436 self
.assertRegex(output
, '2002:da8:2:0:fa:de:ca:fe')
3438 def test_ipv6_token_prefixstable(self
):
3439 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable.network')
3441 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3443 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3445 self
.assertRegex(output
, '2002:da8:1:0')
3446 self
.assertRegex(output
, '2002:da8:2:0.*78:9abc') # EUI
3448 def test_ipv6_token_prefixstable_without_address(self
):
3449 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable-without-address.network')
3451 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3453 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3455 self
.assertRegex(output
, '2002:da8:1:0')
3456 self
.assertRegex(output
, '2002:da8:2:0')
3458 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
3463 'dhcp-client.network',
3464 'dhcp-client-timezone-router.network',
3465 'dhcp-server.network',
3466 'dhcp-server-timezone-router.network']
3469 remove_links(self
.links
)
3470 stop_networkd(show_logs
=False)
3473 remove_links(self
.links
)
3474 remove_unit_from_networkd_path(self
.units
)
3475 stop_networkd(show_logs
=True)
3477 def test_dhcp_server(self
):
3478 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
3480 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3482 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3484 self
.assertRegex(output
, '192.168.5.*')
3485 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
3486 self
.assertRegex(output
, 'DNS: 192.168.5.1')
3487 self
.assertRegex(output
, 'NTP: 192.168.5.1')
3489 def test_emit_router_timezone(self
):
3490 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
3492 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3494 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3496 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
3497 self
.assertRegex(output
, '192.168.5.*')
3498 self
.assertRegex(output
, 'Europe/Berlin')
3500 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
3509 'dhcp-client-anonymize.network',
3510 'dhcp-client-decline.network',
3511 'dhcp-client-gateway-ipv4.network',
3512 'dhcp-client-gateway-ipv6.network',
3513 'dhcp-client-gateway-onlink-implicit.network',
3514 'dhcp-client-ipv4-dhcp-settings.network',
3515 'dhcp-client-ipv4-only-ipv6-disabled.network',
3516 'dhcp-client-ipv4-only.network',
3517 'dhcp-client-ipv4-use-routes-use-gateway.network',
3518 'dhcp-client-ipv6-only.network',
3519 'dhcp-client-ipv6-rapid-commit.network',
3520 'dhcp-client-keep-configuration-dhcp-on-stop.network',
3521 'dhcp-client-keep-configuration-dhcp.network',
3522 'dhcp-client-listen-port.network',
3523 'dhcp-client-reassign-static-routes-ipv4.network',
3524 'dhcp-client-reassign-static-routes-ipv6.network',
3525 'dhcp-client-route-metric.network',
3526 'dhcp-client-route-table.network',
3527 'dhcp-client-use-dns-ipv4-and-ra.network',
3528 'dhcp-client-use-dns-ipv4.network',
3529 'dhcp-client-use-dns-no.network',
3530 'dhcp-client-use-dns-yes.network',
3531 'dhcp-client-use-domains.network',
3532 'dhcp-client-vrf.network',
3533 'dhcp-client-with-ipv4ll.network',
3534 'dhcp-client-with-static-address.network',
3535 'dhcp-client.network',
3536 'dhcp-server-decline.network',
3537 'dhcp-server-veth-peer.network',
3538 'dhcp-v4-server-veth-peer.network',
3542 stop_dnsmasq(dnsmasq_pid_file
)
3543 remove_links(self
.links
)
3544 stop_networkd(show_logs
=False)
3547 stop_dnsmasq(dnsmasq_pid_file
)
3550 remove_links(self
.links
)
3551 remove_unit_from_networkd_path(self
.units
)
3552 stop_networkd(show_logs
=True)
3554 def test_dhcp_client_ipv6_only(self
):
3555 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3558 self
.wait_online(['veth-peer:carrier'])
3560 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3562 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3564 self
.assertRegex(output
, '2600::')
3565 self
.assertNotRegex(output
, '192.168.5')
3567 output
= check_output('ip addr show dev veth99')
3569 self
.assertRegex(output
, '2600::')
3570 self
.assertNotRegex(output
, '192.168.5')
3571 self
.assertNotRegex(output
, 'tentative')
3573 # Confirm that ipv6 token is not set in the kernel
3574 output
= check_output('ip token show dev veth99')
3576 self
.assertRegex(output
, 'token :: dev veth99')
3578 def test_dhcp_client_ipv4_only(self
):
3579 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
3582 self
.wait_online(['veth-peer:carrier'])
3583 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
3584 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3586 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3588 self
.assertNotRegex(output
, '2600::')
3589 self
.assertRegex(output
, '192.168.5')
3590 self
.assertRegex(output
, '192.168.5.6')
3591 self
.assertRegex(output
, '192.168.5.7')
3593 # checking routes to DNS servers
3594 output
= check_output('ip route show dev veth99')
3596 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3597 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3598 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3600 stop_dnsmasq(dnsmasq_pid_file
)
3601 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8', lease_time
='2m')
3603 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3604 print('Wait for the dynamic address to be renewed')
3607 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3609 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3611 self
.assertNotRegex(output
, '2600::')
3612 self
.assertRegex(output
, '192.168.5')
3613 self
.assertNotRegex(output
, '192.168.5.6')
3614 self
.assertRegex(output
, '192.168.5.7')
3615 self
.assertRegex(output
, '192.168.5.8')
3617 # checking routes to DNS servers
3618 output
= check_output('ip route show dev veth99')
3620 self
.assertNotRegex(output
, r
'192.168.5.6')
3621 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3622 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3623 self
.assertRegex(output
, r
'192.168.5.8 proto dhcp scope link src 192.168.5.181 metric 1024')
3625 def test_dhcp_client_ipv4_use_routes_gateway(self
):
3626 for (routes
, gateway
, dnsroutes
) in itertools
.product([True, False, None], repeat
=3):
3628 with self
.subTest(routes
=routes
, gateway
=gateway
, dnsroutes
=dnsroutes
):
3629 self
._test
_dhcp
_client
_ipv
4_use
_routes
_gateway
(routes
, gateway
, dnsroutes
)
3632 def _test_dhcp_client_ipv4_use_routes_gateway(self
, routes
, gateway
, dnsroutes
):
3633 testunit
= 'dhcp-client-ipv4-use-routes-use-gateway.network'
3634 testunits
= ['25-veth.netdev', 'dhcp-server-veth-peer.network', testunit
]
3636 testunits
.append(f
'{testunit}.d/use-routes-{routes}.conf');
3638 testunits
.append(f
'{testunit}.d/use-gateway-{gateway}.conf');
3639 if dnsroutes
!= None:
3640 testunits
.append(f
'{testunit}.d/use-dns-routes-{dnsroutes}.conf');
3641 copy_unit_to_networkd_unit_path(*testunits
, dropins
=False)
3644 self
.wait_online(['veth-peer:carrier'])
3645 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
3646 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3648 output
= check_output('ip route show dev veth99')
3651 # UseRoutes= defaults to true
3652 useroutes
= routes
in [True, None]
3653 # UseGateway= defaults to useroutes
3654 usegateway
= useroutes
if gateway
== None else gateway
3658 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.181 metric 1024')
3660 self
.assertNotRegex(output
, r
'192.168.5.5')
3664 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.181 metric 1024')
3666 self
.assertNotRegex(output
, r
'default via 192.168.5.1')
3668 # Check RoutesToDNS=, which defaults to false
3670 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3671 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3673 self
.assertNotRegex(output
, r
'192.168.5.6')
3674 self
.assertNotRegex(output
, r
'192.168.5.7')
3676 def test_dhcp_client_ipv4_ipv6(self
):
3677 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
3678 'dhcp-client-ipv4-only.network')
3680 self
.wait_online(['veth-peer:carrier'])
3682 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3684 # link become 'routable' when at least one protocol provide an valid address.
3685 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3686 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3688 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3690 self
.assertRegex(output
, '2600::')
3691 self
.assertRegex(output
, '192.168.5')
3693 def test_dhcp_client_settings(self
):
3694 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
3697 self
.wait_online(['veth-peer:carrier'])
3699 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3701 print('## ip address show dev veth99')
3702 output
= check_output('ip address show dev veth99')
3704 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3705 self
.assertRegex(output
, '192.168.5')
3706 self
.assertRegex(output
, '1492')
3708 print('## ip route show table main dev veth99')
3709 output
= check_output('ip route show table main dev veth99')
3712 main_table_is_empty
= output
== ''
3713 if not main_table_is_empty
:
3714 self
.assertNotRegex(output
, 'proto dhcp')
3716 print('## ip route show table 211 dev veth99')
3717 output
= check_output('ip route show table 211 dev veth99')
3719 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
3720 if main_table_is_empty
:
3721 self
.assertRegex(output
, '192.168.5.0/24 proto dhcp')
3722 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
3723 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
3725 print('## dnsmasq log')
3726 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
3727 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
3728 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
3729 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
3731 def test_dhcp6_client_settings_rapidcommit_true(self
):
3732 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3734 self
.wait_online(['veth-peer:carrier'])
3736 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3738 output
= check_output('ip address show dev veth99')
3740 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3741 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
3743 def test_dhcp6_client_settings_rapidcommit_false(self
):
3744 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
3746 self
.wait_online(['veth-peer:carrier'])
3748 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3750 output
= check_output('ip address show dev veth99')
3752 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3753 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
3755 def test_dhcp_client_settings_anonymize(self
):
3756 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
3758 self
.wait_online(['veth-peer:carrier'])
3760 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3762 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
3763 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
3764 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
3766 def test_dhcp_client_listen_port(self
):
3767 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
3769 self
.wait_online(['veth-peer:carrier'])
3770 start_dnsmasq('--dhcp-alternate-port=67,5555')
3771 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3773 output
= check_output('ip -4 address show dev veth99')
3775 self
.assertRegex(output
, '192.168.5.* dynamic')
3777 def test_dhcp_client_with_static_address(self
):
3778 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
3779 'dhcp-client-with-static-address.network')
3781 self
.wait_online(['veth-peer:carrier'])
3783 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3785 output
= check_output('ip address show dev veth99 scope global')
3787 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
3788 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
3790 output
= check_output('ip route show dev veth99')
3792 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
3793 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
3794 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
3795 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
3797 def test_dhcp_route_table_id(self
):
3798 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
3800 self
.wait_online(['veth-peer:carrier'])
3802 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3804 output
= check_output('ip route show table 12')
3806 self
.assertRegex(output
, 'veth99 proto dhcp')
3807 self
.assertRegex(output
, '192.168.5.1')
3809 def test_dhcp_route_metric(self
):
3810 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
3812 self
.wait_online(['veth-peer:carrier'])
3814 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3816 output
= check_output('ip route show dev veth99')
3818 self
.assertRegex(output
, 'metric 24')
3820 def test_dhcp_client_reassign_static_routes_ipv4(self
):
3821 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3822 'dhcp-client-reassign-static-routes-ipv4.network')
3824 self
.wait_online(['veth-peer:carrier'])
3825 start_dnsmasq(lease_time
='2m')
3826 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3828 output
= check_output('ip address show dev veth99 scope global')
3830 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3832 output
= check_output('ip route show dev veth99')
3834 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3835 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3836 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3837 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3839 stop_dnsmasq(dnsmasq_pid_file
)
3840 start_dnsmasq(ipv4_range
='192.168.5.210,192.168.5.220', lease_time
='2m')
3842 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3843 print('Wait for the dynamic address to be renewed')
3846 self
.wait_online(['veth99:routable'])
3848 output
= check_output('ip route show dev veth99')
3850 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3851 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3852 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3853 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3855 def test_dhcp_client_reassign_static_routes_ipv6(self
):
3856 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3857 'dhcp-client-reassign-static-routes-ipv6.network')
3859 self
.wait_online(['veth-peer:carrier'])
3860 start_dnsmasq(lease_time
='2m')
3861 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3863 output
= check_output('ip address show dev veth99 scope global')
3865 self
.assertRegex(output
, r
'inet6 2600::[0-9a-f]*/128 scope global (noprefixroute dynamic|dynamic noprefixroute)')
3867 output
= check_output('ip -6 route show dev veth99')
3869 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3870 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3872 stop_dnsmasq(dnsmasq_pid_file
)
3873 start_dnsmasq(ipv6_range
='2600::30,2600::40', lease_time
='2m')
3875 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3876 print('Wait for the dynamic address to be renewed')
3879 self
.wait_online(['veth99:routable'])
3881 output
= check_output('ip -6 route show dev veth99')
3883 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3884 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3886 def test_dhcp_keep_configuration_dhcp(self
):
3887 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
3889 self
.wait_online(['veth-peer:carrier'])
3890 start_dnsmasq(lease_time
='2m')
3891 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3893 output
= check_output('ip address show dev veth99 scope global')
3895 self
.assertRegex(output
, r
'192.168.5.*')
3897 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3899 self
.assertRegex(output
, r
'192.168.5.*')
3901 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
3902 stop_dnsmasq(dnsmasq_pid_file
)
3904 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3905 print('Wait for the dynamic address to be expired')
3908 print('The lease address should be kept after lease expired')
3909 output
= check_output('ip address show dev veth99 scope global')
3911 self
.assertRegex(output
, r
'192.168.5.*')
3913 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3915 self
.assertRegex(output
, r
'192.168.5.*')
3917 check_output('systemctl stop systemd-networkd.socket')
3918 check_output('systemctl stop systemd-networkd.service')
3920 print('The lease address should be kept after networkd stopped')
3921 output
= check_output('ip address show dev veth99 scope global')
3923 self
.assertRegex(output
, r
'192.168.5.*')
3925 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3927 self
.assertRegex(output
, r
'192.168.5.*')
3930 self
.wait_online(['veth-peer:routable'])
3932 print('Still the lease address should be kept after networkd restarted')
3933 output
= check_output('ip address show dev veth99 scope global')
3935 self
.assertRegex(output
, r
'192.168.5.*')
3937 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3939 self
.assertRegex(output
, r
'192.168.5.*')
3941 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
3942 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
3944 self
.wait_online(['veth-peer:carrier'])
3945 start_dnsmasq(lease_time
='2m')
3946 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3948 output
= check_output('ip address show dev veth99 scope global')
3950 self
.assertRegex(output
, r
'192.168.5.*')
3952 stop_dnsmasq(dnsmasq_pid_file
)
3953 check_output('systemctl stop systemd-networkd.socket')
3954 check_output('systemctl stop systemd-networkd.service')
3956 output
= check_output('ip address show dev veth99 scope global')
3958 self
.assertRegex(output
, r
'192.168.5.*')
3961 self
.wait_online(['veth-peer:routable'])
3963 output
= check_output('ip address show dev veth99 scope global')
3965 self
.assertNotRegex(output
, r
'192.168.5.*')
3967 def test_dhcp_client_reuse_address_as_static(self
):
3968 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
3970 self
.wait_online(['veth-peer:carrier'])
3972 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3974 # link become 'routable' when at least one protocol provide an valid address.
3975 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3976 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3978 output
= check_output('ip address show dev veth99 scope global')
3980 self
.assertRegex(output
, '192.168.5')
3981 self
.assertRegex(output
, '2600::')
3983 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
3984 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
3985 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
3986 print(static_network
)
3988 remove_unit_from_networkd_path(['dhcp-client.network'])
3990 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
3991 f
.write(static_network
)
3993 # When networkd started, the links are already configured, so let's wait for 5 seconds
3994 # the links to be re-configured.
3996 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3998 output
= check_output('ip -4 address show dev veth99 scope global')
4000 self
.assertRegex(output
, '192.168.5')
4001 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
4003 output
= check_output('ip -6 address show dev veth99 scope global')
4005 self
.assertRegex(output
, '2600::')
4006 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
4008 @expectedFailureIfModuleIsNotAvailable('vrf')
4009 def test_dhcp_client_vrf(self
):
4010 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
4011 '25-vrf.netdev', '25-vrf.network')
4013 self
.wait_online(['veth-peer:carrier'])
4015 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
4017 # link become 'routable' when at least one protocol provide an valid address.
4018 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4019 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4021 print('## ip -d link show dev vrf99')
4022 output
= check_output('ip -d link show dev vrf99')
4024 self
.assertRegex(output
, 'vrf table 42')
4026 print('## ip address show vrf vrf99')
4027 output
= check_output('ip address show vrf vrf99')
4029 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
4030 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
4031 self
.assertRegex(output
, 'inet6 .* scope link')
4033 print('## ip address show dev veth99')
4034 output
= check_output('ip address show dev veth99')
4036 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
4037 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
4038 self
.assertRegex(output
, 'inet6 .* scope link')
4040 print('## ip route show vrf vrf99')
4041 output
= check_output('ip route show vrf vrf99')
4043 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
4044 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
4045 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
4046 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
4048 print('## ip route show table main dev veth99')
4049 output
= check_output('ip route show table main dev veth99')
4051 self
.assertEqual(output
, '')
4053 def test_dhcp_client_gateway_ipv4(self
):
4054 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4055 'dhcp-client-gateway-ipv4.network')
4057 self
.wait_online(['veth-peer:carrier'])
4059 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4061 output
= check_output('ip route list dev veth99 10.0.0.0/8')
4063 self
.assertRegex(output
, '10.0.0.0/8 via 192.168.5.1 proto dhcp')
4065 def test_dhcp_client_gateway_ipv6(self
):
4066 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4067 'dhcp-client-gateway-ipv6.network')
4069 self
.wait_online(['veth-peer:carrier'])
4071 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4073 output
= check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
4075 self
.assertRegex(output
, 'via fe80::1034:56ff:fe78:9abd')
4077 def test_dhcp_client_gateway_onlink_implicit(self
):
4078 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4079 'dhcp-client-gateway-onlink-implicit.network')
4081 self
.wait_online(['veth-peer:carrier'])
4083 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4085 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4087 self
.assertRegex(output
, '192.168.5')
4089 output
= check_output('ip route list dev veth99 10.0.0.0/8')
4091 self
.assertRegex(output
, 'onlink')
4092 output
= check_output('ip route list dev veth99 192.168.100.0/24')
4094 self
.assertRegex(output
, 'onlink')
4096 def test_dhcp_client_with_ipv4ll_with_dhcp_server(self
):
4097 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4098 'dhcp-client-with-ipv4ll.network')
4100 self
.wait_online(['veth-peer:carrier'])
4101 start_dnsmasq(lease_time
='2m')
4102 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4104 output
= check_output('ip address show dev veth99')
4107 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
4108 self
.assertNotRegex(output
, r
'inet6 2600::[0-9a-f]+/128 scope global dynamic')
4109 output
= check_output('ip -6 address show dev veth99 scope link')
4110 self
.assertRegex(output
, r
'inet6 .* scope link')
4111 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
4112 self
.assertRegex(output
, r
'inet 192\.168\.5\.\d+/24 brd 192\.168\.5\.255 scope global dynamic veth99')
4113 output
= check_output('ip -4 address show dev veth99 scope link')
4114 self
.assertNotRegex(output
, r
'inet 169\.254\.\d+\.\d+/16 brd 169\.254\.255\.255 scope link')
4116 print('Wait for the dynamic address to be expired')
4119 output
= check_output('ip address show dev veth99')
4122 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
4123 self
.assertNotRegex(output
, r
'inet6 2600::[0-9a-f]+/128 scope global dynamic')
4124 output
= check_output('ip -6 address show dev veth99 scope link')
4125 self
.assertRegex(output
, r
'inet6 .* scope link')
4126 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
4127 self
.assertRegex(output
, r
'inet 192\.168\.5\.\d+/24 brd 192\.168\.5\.255 scope global dynamic veth99')
4128 output
= check_output('ip -4 address show dev veth99 scope link')
4129 self
.assertNotRegex(output
, r
'inet 169\.254\.\d+\.\d+/16 brd 169\.254\.255\.255 scope link')
4131 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
4133 def test_dhcp_client_with_ipv4ll_without_dhcp_server(self
):
4134 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4135 'dhcp-client-with-ipv4ll.network')
4137 # we need to increase timeout above default, as this will need to wait for
4138 # systemd-networkd to get the dhcpv4 transient failure event
4139 self
.wait_online(['veth99:degraded', 'veth-peer:routable'], timeout
='60s')
4141 output
= check_output('ip address show dev veth99')
4144 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
4145 self
.assertNotRegex(output
, r
'inet6 2600::[0-9a-f]+/128 scope global dynamic')
4146 output
= check_output('ip -6 address show dev veth99 scope link')
4147 self
.assertRegex(output
, r
'inet6 .* scope link')
4148 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
4149 self
.assertNotRegex(output
, r
'inet 192\.168\.5\.\d+/24 brd 192\.168\.5\.255 scope global dynamic veth99')
4150 output
= check_output('ip -4 address show dev veth99 scope link')
4151 self
.assertRegex(output
, r
'inet 169\.254\.\d+\.\d+/16 brd 169\.254\.255\.255 scope link')
4153 start_dnsmasq(lease_time
='2m')
4154 self
.wait_address('veth99', r
'inet 192\.168\.5\.\d+/24 brd 192\.168\.5\.255 scope global dynamic', ipv
='-4')
4155 self
.wait_address_dropped('veth99', r
'inet 169\.254\.\d+\.\d+/16 brd 169\.255\.255\.255 scope link', scope
='link', ipv
='-4')
4157 def test_dhcp_client_route_remove_on_renew(self
):
4158 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4159 'dhcp-client-ipv4-only-ipv6-disabled.network')
4161 self
.wait_online(['veth-peer:carrier'])
4162 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
4163 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4165 # test for issue #12490
4167 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
4169 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
4171 for line
in output
.splitlines():
4172 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
4173 address1
= line
.split()[1].split('/')[0]
4176 output
= check_output('ip -4 route show dev veth99')
4178 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
4179 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
4181 stop_dnsmasq(dnsmasq_pid_file
)
4182 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
4184 print('Wait for the dynamic address to be expired')
4187 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
4189 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
4191 for line
in output
.splitlines():
4192 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
4193 address2
= line
.split()[1].split('/')[0]
4196 self
.assertNotEqual(address1
, address2
)
4198 output
= check_output('ip -4 route show dev veth99')
4200 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
4201 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
4202 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
4203 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
4205 def test_dhcp_client_use_dns_yes(self
):
4206 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-yes.network')
4209 self
.wait_online(['veth-peer:carrier'])
4210 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
4211 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4213 # link become 'routable' when at least one protocol provide an valid address.
4214 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4215 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4218 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
4220 self
.assertRegex(output
, '192.168.5.1')
4221 self
.assertRegex(output
, '2600::1')
4223 def test_dhcp_client_use_dns_no(self
):
4224 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-no.network')
4227 self
.wait_online(['veth-peer:carrier'])
4228 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
4229 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4231 # link become 'routable' when at least one protocol provide an valid address.
4232 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4233 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4236 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
4238 self
.assertNotRegex(output
, '192.168.5.1')
4239 self
.assertNotRegex(output
, '2600::1')
4241 def test_dhcp_client_use_dns_ipv4(self
):
4242 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4.network')
4245 self
.wait_online(['veth-peer:carrier'])
4246 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
4247 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4249 # link become 'routable' when at least one protocol provide an valid address.
4250 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4251 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4254 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
4256 self
.assertRegex(output
, '192.168.5.1')
4257 self
.assertNotRegex(output
, '2600::1')
4259 def test_dhcp_client_use_dns_ipv4_and_ra(self
):
4260 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4-and-ra.network')
4263 self
.wait_online(['veth-peer:carrier'])
4264 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
4265 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4267 # link become 'routable' when at least one protocol provide an valid address.
4268 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4269 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4272 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
4274 self
.assertRegex(output
, '192.168.5.1')
4275 self
.assertRegex(output
, '2600::1')
4277 def test_dhcp_client_use_domains(self
):
4278 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-domains.network')
4281 self
.wait_online(['veth-peer:carrier'])
4282 start_dnsmasq('--dhcp-option=option:domain-search,example.com')
4283 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4285 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4287 self
.assertRegex(output
, 'Search Domains: example.com')
4290 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
4292 self
.assertRegex(output
, 'example.com')
4294 def test_dhcp_client_decline(self
):
4295 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-decline.network', 'dhcp-client-decline.network')
4298 self
.wait_online(['veth-peer:carrier'])
4299 rc
= call(*wait_online_cmd
, '--timeout=10s', '--interface=veth99:routable', env
=env
)
4300 self
.assertTrue(rc
== 1)
4302 class NetworkdIPv6PrefixTests(unittest
.TestCase
, Utilities
):
4307 'ipv6ra-prefix-client-deny-list.network',
4308 'ipv6ra-prefix-client.network',
4309 'ipv6ra-prefix.network'
4313 remove_links(self
.links
)
4314 stop_networkd(show_logs
=False)
4318 remove_links(self
.links
)
4319 remove_unit_from_networkd_path(self
.units
)
4320 stop_networkd(show_logs
=True)
4322 def test_ipv6_route_prefix(self
):
4323 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client.network', 'ipv6ra-prefix.network')
4326 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4328 output
= check_output('ip address show dev veth-peer')
4330 self
.assertIn('inet6 2001:db8:0:1:', output
)
4331 self
.assertNotIn('inet6 2001:db8:0:2:', output
)
4333 output
= check_output('ip -6 route show dev veth-peer')
4335 self
.assertIn('2001:db8:0:1::/64 proto ra', output
)
4336 self
.assertNotIn('2001:db8:0:2::/64 proto ra', output
)
4337 self
.assertIn('2001:db0:fff::/64 via ', output
)
4338 self
.assertNotIn('2001:db1:fff::/64 via ', output
)
4340 output
= check_output('ip address show dev veth99')
4342 self
.assertNotIn('inet6 2001:db8:0:1:', output
)
4343 self
.assertIn('inet6 2001:db8:0:2:', output
)
4345 def test_ipv6_route_prefix_deny_list(self
):
4346 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client-deny-list.network', 'ipv6ra-prefix.network')
4349 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4351 output
= check_output('ip address show dev veth-peer')
4353 self
.assertIn('inet6 2001:db8:0:1:', output
)
4354 self
.assertNotIn('inet6 2001:db8:0:2:', output
)
4356 output
= check_output('ip -6 route show dev veth-peer')
4358 self
.assertIn('2001:db8:0:1::/64 proto ra', output
)
4359 self
.assertNotIn('2001:db8:0:2::/64 proto ra', output
)
4360 self
.assertIn('2001:db0:fff::/64 via ', output
)
4361 self
.assertNotIn('2001:db1:fff::/64 via ', output
)
4363 output
= check_output('ip address show dev veth99')
4365 self
.assertNotIn('inet6 2001:db8:0:1:', output
)
4366 self
.assertIn('inet6 2001:db8:0:2:', output
)
4368 class NetworkdMTUTests(unittest
.TestCase
, Utilities
):
4373 '12-dummy-mtu.netdev',
4374 '12-dummy-mtu.link',
4379 remove_links(self
.links
)
4380 stop_networkd(show_logs
=False)
4384 remove_links(self
.links
)
4385 remove_unit_from_networkd_path(self
.units
)
4386 stop_networkd(show_logs
=True)
4388 def check_mtu(self
, mtu
, ipv6_mtu
=None, reset
=True):
4394 self
.wait_online(['dummy98:routable'])
4395 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
4396 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
4398 # test normal restart
4400 self
.wait_online(['dummy98:routable'])
4401 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
4402 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
4405 self
.reset_check_mtu(mtu
, ipv6_mtu
)
4407 def reset_check_mtu(self
, mtu
, ipv6_mtu
=None):
4408 ''' test setting mtu/ipv6_mtu with interface already up '''
4411 # note - changing the device mtu resets the ipv6 mtu
4412 run('ip link set up mtu 1501 dev dummy98')
4413 run('ip link set up mtu 1500 dev dummy98')
4414 self
.assertEqual(read_link_attr('dummy98', 'mtu'), '1500')
4415 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), '1500')
4417 self
.check_mtu(mtu
, ipv6_mtu
, reset
=False)
4419 def test_mtu_network(self
):
4420 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
4421 self
.check_mtu('1600')
4423 def test_mtu_netdev(self
):
4424 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network', dropins
=False)
4425 # note - MTU set by .netdev happens ONLY at device creation!
4426 self
.check_mtu('1600', reset
=False)
4428 def test_mtu_link(self
):
4429 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', dropins
=False)
4430 # must reload udev because it only picks up new files after 3 second delay
4431 call('udevadm control --reload')
4432 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
4433 self
.check_mtu('1600', reset
=False)
4435 def test_ipv6_mtu(self
):
4436 ''' set ipv6 mtu without setting device mtu '''
4437 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
4438 self
.check_mtu('1500', '1400')
4440 def test_ipv6_mtu_toolarge(self
):
4441 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
4442 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
4443 self
.check_mtu('1500', '1500')
4445 def test_mtu_network_ipv6_mtu(self
):
4446 ''' set ipv6 mtu and set device mtu via network file '''
4447 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
4448 self
.check_mtu('1600', '1550')
4450 def test_mtu_netdev_ipv6_mtu(self
):
4451 ''' set ipv6 mtu and set device mtu via netdev file '''
4452 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
4453 self
.check_mtu('1600', '1550', reset
=False)
4455 def test_mtu_link_ipv6_mtu(self
):
4456 ''' set ipv6 mtu and set device mtu via link file '''
4457 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
4458 # must reload udev because it only picks up new files after 3 second delay
4459 call('udevadm control --reload')
4460 self
.check_mtu('1600', '1550', reset
=False)
4463 if __name__
== '__main__':
4464 parser
= argparse
.ArgumentParser()
4465 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
4466 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
4467 parser
.add_argument('--resolved', help='Path to systemd-resolved', dest
='resolved_bin')
4468 parser
.add_argument('--udevd', help='Path to systemd-udevd', dest
='udevd_bin')
4469 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
4470 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
4471 parser
.add_argument('--resolvectl', help='Path to resolvectl', dest
='resolvectl_bin')
4472 parser
.add_argument('--timedatectl', help='Path to timedatectl', dest
='timedatectl_bin')
4473 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
4474 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
4475 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
4476 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
4477 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
4478 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
4481 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
:
4482 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
4483 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
4484 resolved_bin
= os
.path
.join(ns
.build_dir
, 'systemd-resolved')
4485 udevd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-udevd')
4486 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
4487 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
4488 resolvectl_bin
= os
.path
.join(ns
.build_dir
, 'resolvectl')
4489 timedatectl_bin
= os
.path
.join(ns
.build_dir
, 'timedatectl')
4492 networkd_bin
= ns
.networkd_bin
4494 resolved_bin
= ns
.resolved_bin
4496 udevd_bin
= ns
.udevd_bin
4497 if ns
.wait_online_bin
:
4498 wait_online_bin
= ns
.wait_online_bin
4499 if ns
.networkctl_bin
:
4500 networkctl_bin
= ns
.networkctl_bin
4501 if ns
.resolvectl_bin
:
4502 resolvectl_bin
= ns
.resolvectl_bin
4503 if ns
.timedatectl_bin
:
4504 timedatectl_bin
= ns
.timedatectl_bin
4506 use_valgrind
= ns
.use_valgrind
4507 enable_debug
= ns
.enable_debug
4508 asan_options
= ns
.asan_options
4509 lsan_options
= ns
.lsan_options
4510 ubsan_options
= ns
.ubsan_options
4513 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
4514 resolvectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin
]
4515 timedatectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin
]
4516 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
4518 networkctl_cmd
= [networkctl_bin
]
4519 resolvectl_cmd
= [resolvectl_bin
]
4520 timedatectl_cmd
= [timedatectl_bin
]
4521 wait_online_cmd
= [wait_online_bin
]
4524 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
4526 env
.update({ 'ASAN_OPTIONS' : asan_options
})
4528 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
4530 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
4533 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,