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_blackhole_nexthops():
408 ret
= run('ip nexthop show dev lo', stdout
=subprocess
.PIPE
, stderr
=subprocess
.DEVNULL
)
409 if ret
.returncode
== 0:
410 for line
in ret
.stdout
.rstrip().splitlines():
412 call(f
'ip nexthop del id {id}')
414 def remove_l2tp_tunnels(tunnel_ids
):
415 output
= check_output('ip l2tp show tunnel')
416 for tid
in tunnel_ids
:
417 words
='Tunnel ' + tid
+ ', encap'
419 call('ip l2tp del tunnel tid', tid
)
422 def read_ipv6_sysctl_attr(link
, attribute
):
423 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, link
), attribute
)) as f
:
424 return f
.readline().strip()
426 def read_ipv4_sysctl_attr(link
, attribute
):
427 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv4_path
, link
), attribute
)) as f
:
428 return f
.readline().strip()
430 def copy_unit_to_networkd_unit_path(*units
, dropins
=True):
431 """Copy networkd unit files into the testbed.
433 Any networkd unit file type can be specified, as well as drop-in files.
435 By default, all drop-ins for a specified unit file are copied in;
436 to avoid that specify dropins=False.
438 When a drop-in file is specified, its unit file is also copied in automatically.
442 if dropins
and os
.path
.exists(os
.path
.join(networkd_ci_path
, unit
+ '.d')):
443 copytree(os
.path
.join(networkd_ci_path
, unit
+ '.d'), os
.path
.join(network_unit_file_path
, unit
+ '.d'))
444 if unit
.endswith('.conf'):
446 dropindir
= os
.path
.join(network_unit_file_path
, os
.path
.dirname(dropin
))
447 os
.makedirs(dropindir
, exist_ok
=True)
448 shutil
.copy(os
.path
.join(networkd_ci_path
, dropin
), dropindir
)
449 unit
= os
.path
.dirname(dropin
).rstrip('.d')
450 shutil
.copy(os
.path
.join(networkd_ci_path
, unit
), network_unit_file_path
)
452 def remove_unit_from_networkd_path(units
):
453 """Remove previously copied unit files from the testbed.
455 Drop-ins will be removed automatically.
458 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
))):
459 os
.remove(os
.path
.join(network_unit_file_path
, unit
))
460 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
+ '.d'))):
461 shutil
.rmtree(os
.path
.join(network_unit_file_path
, unit
+ '.d'))
463 def start_dnsmasq(additional_options
='', ipv4_range
='192.168.5.10,192.168.5.200', ipv6_range
='2600::10,2600::20', lease_time
='1h'):
464 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
465 check_output(dnsmasq_command
)
467 def stop_dnsmasq(pid_file
):
468 if os
.path
.exists(pid_file
):
469 with
open(pid_file
, 'r') as f
:
470 pid
= f
.read().rstrip(' \t\r\n\0')
471 os
.kill(int(pid
), signal
.SIGTERM
)
475 def search_words_in_dnsmasq_log(words
, show_all
=False):
476 if os
.path
.exists(dnsmasq_log_file
):
477 with
open (dnsmasq_log_file
) as in_file
:
478 contents
= in_file
.read()
481 for line
in contents
.splitlines():
484 print("%s, %s" % (words
, line
))
488 def remove_lease_file():
489 if os
.path
.exists(os
.path
.join(networkd_ci_path
, 'lease')):
490 os
.remove(os
.path
.join(networkd_ci_path
, 'lease'))
492 def remove_log_file():
493 if os
.path
.exists(dnsmasq_log_file
):
494 os
.remove(dnsmasq_log_file
)
496 def remove_networkd_state_files():
497 if os
.path
.exists(os
.path
.join(networkd_runtime_directory
, 'state')):
498 os
.remove(os
.path
.join(networkd_runtime_directory
, 'state'))
500 def stop_networkd(show_logs
=True, remove_state_files
=True):
502 invocation_id
= check_output('systemctl show systemd-networkd -p InvocationID --value')
503 check_output('systemctl stop systemd-networkd.socket')
504 check_output('systemctl stop systemd-networkd.service')
506 print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
))
507 if remove_state_files
:
508 remove_networkd_state_files()
510 def start_networkd(sleep_sec
=0):
511 check_output('systemctl start systemd-networkd')
513 time
.sleep(sleep_sec
)
515 def restart_networkd(sleep_sec
=0, show_logs
=True, remove_state_files
=True):
516 stop_networkd(show_logs
, remove_state_files
)
517 start_networkd(sleep_sec
)
521 def check_link_exists(self
, link
):
522 self
.assertTrue(link_exists(link
))
524 def check_link_attr(self
, *args
):
525 self
.assertEqual(read_link_attr(*args
[:-1]), args
[-1]);
527 def wait_operstate(self
, link
, operstate
='degraded', setup_state
='configured', setup_timeout
=5, fail_assert
=True):
528 """Wait for the link to reach the specified operstate and/or setup state.
530 Specify None or '' for either operstate or setup_state to ignore that state.
531 This will recheck until the state conditions are met or the timeout expires.
533 If the link successfully matches the requested state, this returns True.
534 If this times out waiting for the link to match, the behavior depends on the
535 'fail_assert' parameter; if True, this causes a test assertion failure,
536 otherwise this returns False. The default is to cause assertion failure.
538 Note that this function matches on *exactly* the given operstate and setup_state.
539 To wait for a link to reach *or exceed* a given operstate, use wait_online().
546 for secs
in range(setup_timeout
+ 1):
547 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
, env
=env
)
549 if re
.search(rf
'(?m)^\s*State:\s+{operstate}\s+\({setup_state}\)\s*$', output
):
551 # don't bother sleeping if time is up
552 if secs
< setup_timeout
:
555 self
.fail(f
'Timed out waiting for {link} to reach state {operstate}/{setup_state}')
558 def wait_online(self
, links_with_operstate
, timeout
='20s', bool_any
=False, setup_state
='configured', setup_timeout
=5):
559 """Wait for the link(s) to reach the specified operstate and/or setup state.
561 This is similar to wait_operstate() but can be used for multiple links,
562 and it also calls systemd-networkd-wait-online to wait for the given operstate.
563 The operstate should be specified in the link name, like 'eth0:degraded'.
564 If just a link name is provided, wait-online's default operstate to wait for is degraded.
566 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
567 'setup_timeout' controls the per-link timeout waiting for the setup_state.
569 Set 'bool_any' to True to wait for any (instead of all) of the given links.
570 If this is set, no setup_state checks are done.
572 Note that this function waits for the link(s) to reach *or exceed* the given operstate.
573 However, the setup_state, if specified, must be matched *exactly*.
575 This returns if the link(s) reached the requested operstate/setup_state; otherwise it
576 raises CalledProcessError or fails test assertion.
578 args
= wait_online_cmd
+ [f
'--timeout={timeout}'] + [f
'--interface={link}' for link
in links_with_operstate
]
582 check_output(*args
, env
=env
)
583 except subprocess
.CalledProcessError
:
584 for link
in links_with_operstate
:
585 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
.split(':')[0], env
=env
)
588 if not bool_any
and setup_state
:
589 for link
in links_with_operstate
:
590 self
.wait_operstate(link
.split(':')[0], None, setup_state
, setup_timeout
)
592 def wait_address(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
593 for i
in range(timeout_sec
):
596 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
597 if re
.search(address_regex
, output
) and 'tentative' not in output
:
600 self
.assertRegex(output
, address_regex
)
602 def wait_address_dropped(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
603 for i
in range(timeout_sec
):
606 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
607 if not re
.search(address_regex
, output
):
610 self
.assertNotRegex(output
, address_regex
)
612 class NetworkctlTests(unittest
.TestCase
, Utilities
):
622 '11-dummy-mtu.netdev',
626 '25-address-static.network',
628 'netdev-link-local-addressing-yes.network',
632 remove_links(self
.links
)
633 stop_networkd(show_logs
=False)
636 remove_links(self
.links
)
637 remove_unit_from_networkd_path(self
.units
)
638 stop_networkd(show_logs
=True)
640 @expectedFailureIfAlternativeNameIsNotAvailable()
641 def test_altname(self
):
642 copy_unit_to_networkd_unit_path('netdev-link-local-addressing-yes.network', '12-dummy.netdev', '12-dummy.link')
643 check_output('udevadm control --reload')
645 self
.wait_online(['dummy98:degraded'])
647 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
648 self
.assertRegex(output
, 'hogehogehogehogehogehoge')
650 def test_reconfigure(self
):
651 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
653 self
.wait_online(['dummy98:routable'])
655 output
= check_output('ip -4 address show dev dummy98')
657 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
658 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
659 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
661 check_output('ip address del 10.1.2.3/16 dev dummy98')
662 check_output('ip address del 10.1.2.4/16 dev dummy98')
663 check_output('ip address del 10.2.2.4/16 dev dummy98')
665 check_output(*networkctl_cmd
, 'reconfigure', 'dummy98', env
=env
)
666 self
.wait_online(['dummy98:routable'])
668 output
= check_output('ip -4 address show dev dummy98')
670 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
671 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
672 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
674 def test_reload(self
):
677 copy_unit_to_networkd_unit_path('11-dummy.netdev')
678 check_output(*networkctl_cmd
, 'reload', env
=env
)
679 self
.wait_operstate('test1', 'off', setup_state
='unmanaged')
681 copy_unit_to_networkd_unit_path('11-dummy.network')
682 check_output(*networkctl_cmd
, 'reload', env
=env
)
683 self
.wait_online(['test1:degraded'])
685 remove_unit_from_networkd_path(['11-dummy.network'])
686 check_output(*networkctl_cmd
, 'reload', env
=env
)
687 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
689 remove_unit_from_networkd_path(['11-dummy.netdev'])
690 check_output(*networkctl_cmd
, 'reload', env
=env
)
691 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
693 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
694 check_output(*networkctl_cmd
, 'reload', env
=env
)
695 self
.wait_operstate('test1', 'degraded')
698 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
701 self
.wait_online(['test1:degraded'])
703 output
= check_output(*networkctl_cmd
, 'list', env
=env
)
704 self
.assertRegex(output
, '1 lo ')
705 self
.assertRegex(output
, 'test1')
707 output
= check_output(*networkctl_cmd
, 'list', 'test1', env
=env
)
708 self
.assertNotRegex(output
, '1 lo ')
709 self
.assertRegex(output
, 'test1')
711 output
= check_output(*networkctl_cmd
, 'list', 'te*', env
=env
)
712 self
.assertNotRegex(output
, '1 lo ')
713 self
.assertRegex(output
, 'test1')
715 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'te*', env
=env
)
716 self
.assertNotRegex(output
, '1: lo ')
717 self
.assertRegex(output
, 'test1')
719 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'tes[a-z][0-9]', env
=env
)
720 self
.assertNotRegex(output
, '1: lo ')
721 self
.assertRegex(output
, 'test1')
724 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
727 self
.wait_online(['test1:degraded'])
729 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
730 self
.assertRegex(output
, 'MTU: 1600')
733 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
735 self
.wait_online(['test1:degraded'])
737 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
739 self
.assertRegex(output
, 'Type: ether')
741 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
743 self
.assertRegex(output
, 'Type: loopback')
745 @expectedFailureIfLinkFileFieldIsNotSet()
746 def test_udev_link_file(self
):
747 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
749 self
.wait_online(['test1:degraded'])
751 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
753 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
754 self
.assertRegex(output
, r
'Network File: /run/systemd/network/11-dummy.network')
756 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
758 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
759 self
.assertRegex(output
, r
'Network File: n/a')
761 def test_delete_links(self
):
762 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
763 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
766 self
.wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
768 check_output(*networkctl_cmd
, 'delete', 'test1', 'veth99', env
=env
)
769 self
.assertFalse(link_exists('test1'))
770 self
.assertFalse(link_exists('veth99'))
771 self
.assertFalse(link_exists('veth-peer'))
773 class NetworkdNetDevTests(unittest
.TestCase
, Utilities
):
775 links_remove_earlier
= [
845 '10-dropin-test.netdev',
849 '13-not-match-udev-property.network',
850 '14-match-udev-property.network',
851 '15-name-conflict-test.netdev',
854 '21-vlan-test1.network',
857 '25-6rd-tunnel.netdev',
861 '25-bond-balanced-tlb.netdev',
863 '25-bridge-configure-without-carrier.network',
865 '25-erspan-tunnel-local-any.netdev',
866 '25-erspan-tunnel.netdev',
867 '25-fou-gretap.netdev',
869 '25-fou-ipip.netdev',
870 '25-fou-ipproto-gre.netdev',
871 '25-fou-ipproto-ipip.netdev',
874 '25-gretap-tunnel-local-any.netdev',
875 '25-gretap-tunnel.netdev',
876 '25-gre-tunnel-any-any.netdev',
877 '25-gre-tunnel-local-any.netdev',
878 '25-gre-tunnel-remote-any.netdev',
879 '25-gre-tunnel.netdev',
881 '25-ip6gretap-tunnel-local-any.netdev',
882 '25-ip6gretap-tunnel.netdev',
883 '25-ip6gre-tunnel-any-any.netdev',
884 '25-ip6gre-tunnel-local-any.netdev',
885 '25-ip6gre-tunnel-remote-any.netdev',
886 '25-ip6gre-tunnel.netdev',
887 '25-ip6tnl-tunnel-any-any.netdev',
888 '25-ip6tnl-tunnel-local-any.netdev',
889 '25-ip6tnl-tunnel-remote-any.netdev',
890 '25-ip6tnl-tunnel.netdev',
891 '25-ipip-tunnel-any-any.netdev',
892 '25-ipip-tunnel-independent.netdev',
893 '25-ipip-tunnel-independent-loopback.netdev',
894 '25-ipip-tunnel-local-any.netdev',
895 '25-ipip-tunnel-remote-any.netdev',
896 '25-ipip-tunnel.netdev',
899 '25-isatap-tunnel.netdev',
904 '25-sit-tunnel-any-any.netdev',
905 '25-sit-tunnel-local-any.netdev',
906 '25-sit-tunnel-remote-any.netdev',
907 '25-sit-tunnel.netdev',
910 '25-tunnel-any-any.network',
911 '25-tunnel-local-any.network',
912 '25-tunnel-remote-any.network',
917 '25-vti6-tunnel-any-any.netdev',
918 '25-vti6-tunnel-local-any.netdev',
919 '25-vti6-tunnel-remote-any.netdev',
920 '25-vti6-tunnel.netdev',
921 '25-vti-tunnel-any-any.netdev',
922 '25-vti-tunnel-local-any.netdev',
923 '25-vti-tunnel-remote-any.netdev',
924 '25-vti-tunnel.netdev',
926 '25-vxlan-independent.netdev',
928 '25-wireguard-23-peers.netdev',
929 '25-wireguard-23-peers.network',
930 '25-wireguard-no-peer.netdev',
931 '25-wireguard-no-peer.network',
932 '25-wireguard-preshared-key.txt',
933 '25-wireguard-private-key.txt',
934 '25-wireguard.netdev',
935 '25-wireguard.network',
937 '25-xfrm-independent.netdev',
953 'netdev-link-local-addressing-yes.network',
957 'vxlan-test1.network',
967 remove_fou_ports(self
.fou_ports
)
968 remove_links(self
.links_remove_earlier
)
969 remove_links(self
.links
)
970 stop_networkd(show_logs
=False)
973 remove_fou_ports(self
.fou_ports
)
974 remove_links(self
.links_remove_earlier
)
975 remove_links(self
.links
)
976 remove_unit_from_networkd_path(self
.units
)
977 stop_networkd(show_logs
=True)
979 def test_dropin_and_name_conflict(self
):
980 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
983 self
.wait_online(['dropin-test:off'], setup_state
='unmanaged')
985 output
= check_output('ip link show dropin-test')
987 self
.assertRegex(output
, '00:50:56:c0:00:28')
989 def test_match_udev_property(self
):
990 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
992 self
.wait_online(['dummy98:routable'])
994 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
996 self
.assertRegex(output
, 'Network File: /run/systemd/network/14-match-udev-property')
998 def test_wait_online_any(self
):
999 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
1002 self
.wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
1004 self
.wait_operstate('bridge99', '(off|no-carrier)', setup_state
='configuring')
1005 self
.wait_operstate('test1', 'degraded')
1007 @expectedFailureIfModuleIsNotAvailable('bareudp')
1008 def test_bareudp(self
):
1009 copy_unit_to_networkd_unit_path('25-bareudp.netdev', 'netdev-link-local-addressing-yes.network')
1012 self
.wait_online(['bareudp99:degraded'])
1014 output
= check_output('ip -d link show bareudp99')
1016 self
.assertRegex(output
, 'dstport 1000 ')
1017 self
.assertRegex(output
, 'ethertype ip ')
1019 @expectedFailureIfModuleIsNotAvailable('batman-adv')
1020 def test_batadv(self
):
1021 copy_unit_to_networkd_unit_path('25-batadv.netdev', 'netdev-link-local-addressing-yes.network')
1024 self
.wait_online(['batadv99:degraded'])
1026 output
= check_output('ip -d link show batadv99')
1028 self
.assertRegex(output
, 'batadv')
1030 def test_bridge(self
):
1031 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
1034 self
.wait_online(['bridge99:no-carrier'])
1036 tick
= os
.sysconf('SC_CLK_TCK')
1037 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
1038 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
1039 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'forward_delay')) / tick
))
1040 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'ageing_time')) / tick
))
1041 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge', 'priority')))
1042 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_querier')))
1043 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_snooping')))
1044 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'stp_state')))
1045 self
.assertEqual(3, int(read_link_attr('bridge99', 'bridge', 'multicast_igmp_version')))
1047 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
1049 self
.assertRegex(output
, 'Priority: 9')
1050 self
.assertRegex(output
, 'STP: yes')
1051 self
.assertRegex(output
, 'Multicast IGMP Version: 3')
1053 def test_bond(self
):
1054 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
1057 self
.wait_online(['bond99:off', 'bond98:off'], setup_state
='unmanaged')
1059 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
1060 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
1061 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
1062 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
1063 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
1064 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
1065 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
1066 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
1067 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
1068 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
1069 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
1071 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
1072 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
1074 def test_vlan(self
):
1075 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
1076 '21-vlan.network', '21-vlan-test1.network')
1079 self
.wait_online(['test1:degraded', 'vlan99:routable'])
1081 output
= check_output('ip -d link show test1')
1083 self
.assertRegex(output
, ' mtu 2000 ')
1085 output
= check_output('ip -d link show vlan99')
1087 self
.assertRegex(output
, ' mtu 2000 ')
1088 self
.assertRegex(output
, 'REORDER_HDR')
1089 self
.assertRegex(output
, 'LOOSE_BINDING')
1090 self
.assertRegex(output
, 'GVRP')
1091 self
.assertRegex(output
, 'MVRP')
1092 self
.assertRegex(output
, ' id 99 ')
1094 output
= check_output('ip -4 address show dev test1')
1096 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
1097 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
1099 output
= check_output('ip -4 address show dev vlan99')
1101 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
1103 def test_macvtap(self
):
1104 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
1105 with self
.subTest(mode
=mode
):
1106 if mode
!= 'private':
1108 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
1109 '11-dummy.netdev', 'macvtap.network')
1110 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
1111 f
.write('[MACVTAP]\nMode=' + mode
)
1114 self
.wait_online(['macvtap99:degraded', 'test1:degraded'])
1116 output
= check_output('ip -d link show macvtap99')
1118 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
1120 def test_macvlan(self
):
1121 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
1122 with self
.subTest(mode
=mode
):
1123 if mode
!= 'private':
1125 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
1126 '11-dummy.netdev', 'macvlan.network')
1127 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
1128 f
.write('[MACVLAN]\nMode=' + mode
)
1131 self
.wait_online(['macvlan99:degraded', 'test1:degraded'])
1133 output
= check_output('ip -d link show test1')
1135 self
.assertRegex(output
, ' mtu 2000 ')
1137 output
= check_output('ip -d link show macvlan99')
1139 self
.assertRegex(output
, ' mtu 2000 ')
1140 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
1142 @expectedFailureIfModuleIsNotAvailable('ipvlan')
1143 def test_ipvlan(self
):
1144 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1145 with self
.subTest(mode
=mode
, flag
=flag
):
1148 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
1149 '11-dummy.netdev', 'ipvlan.network')
1150 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
1151 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
1154 self
.wait_online(['ipvlan99:degraded', 'test1:degraded'])
1156 output
= check_output('ip -d link show ipvlan99')
1158 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
1160 @expectedFailureIfModuleIsNotAvailable('ipvtap')
1161 def test_ipvtap(self
):
1162 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1163 with self
.subTest(mode
=mode
, flag
=flag
):
1166 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
1167 '11-dummy.netdev', 'ipvtap.network')
1168 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
1169 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
1172 self
.wait_online(['ipvtap99:degraded', 'test1:degraded'])
1174 output
= check_output('ip -d link show ipvtap99')
1176 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
1178 def test_veth(self
):
1179 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
1182 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
1184 output
= check_output('ip -d link show veth99')
1186 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
1187 output
= check_output('ip -d link show veth-peer')
1189 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
1192 copy_unit_to_networkd_unit_path('25-tun.netdev')
1195 self
.wait_online(['tun99:off'], setup_state
='unmanaged')
1197 output
= check_output('ip -d link show tun99')
1199 # Old ip command does not support IFF_ flags
1200 self
.assertRegex(output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
1203 copy_unit_to_networkd_unit_path('25-tap.netdev')
1206 self
.wait_online(['tap99:off'], setup_state
='unmanaged')
1208 output
= check_output('ip -d link show tap99')
1210 # Old ip command does not support IFF_ flags
1211 self
.assertRegex(output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
1213 @expectedFailureIfModuleIsNotAvailable('vrf')
1215 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
1218 self
.wait_online(['vrf99:carrier'])
1220 @expectedFailureIfModuleIsNotAvailable('vcan')
1221 def test_vcan(self
):
1222 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
1225 self
.wait_online(['vcan99:carrier'])
1227 @expectedFailureIfModuleIsNotAvailable('vxcan')
1228 def test_vxcan(self
):
1229 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
1232 self
.wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
1234 @expectedFailureIfModuleIsNotAvailable('wireguard')
1235 def test_wireguard(self
):
1236 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
1237 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
1238 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt',
1239 '25-wireguard-no-peer.netdev', '25-wireguard-no-peer.network')
1241 self
.wait_online(['wg99:routable', 'wg98:routable', 'wg97:carrier'])
1243 output
= check_output('ip -4 address show dev wg99')
1245 self
.assertIn('inet 192.168.124.1/24 scope global wg99', output
)
1247 output
= check_output('ip -4 address show dev wg98')
1249 self
.assertIn('inet 192.168.123.123/24 scope global wg98', output
)
1251 output
= check_output('ip -6 address show dev wg98')
1253 self
.assertIn('inet6 fd8d:4d6d:3ccb:500::1/64 scope global', output
)
1255 if shutil
.which('wg'):
1258 output
= check_output('wg show wg99 listen-port')
1259 self
.assertEqual(output
, '51820')
1260 output
= check_output('wg show wg99 fwmark')
1261 self
.assertEqual(output
, '0x4d2')
1262 output
= check_output('wg show wg99 private-key')
1263 self
.assertEqual(output
, 'EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=')
1264 output
= check_output('wg show wg99 allowed-ips')
1265 self
.assertIn('9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c=\t192.168.124.3/32', output
)
1266 self
.assertIn('TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10=\t192.168.124.2/32', output
)
1267 self
.assertIn('lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128', output
)
1268 self
.assertIn('RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48', output
)
1269 output
= check_output('wg show wg99 persistent-keepalive')
1270 self
.assertIn('9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c=\toff', output
)
1271 self
.assertIn('TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10=\toff', output
)
1272 self
.assertIn('lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\toff', output
)
1273 self
.assertIn('RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t20', output
)
1274 output
= check_output('wg show wg99 endpoints')
1275 self
.assertIn('9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c=\t(none)', output
)
1276 self
.assertIn('TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10=\t(none)', output
)
1277 self
.assertIn('lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\t(none)', output
)
1278 self
.assertIn('RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t192.168.27.3:51820', output
)
1279 output
= check_output('wg show wg99 preshared-keys')
1280 self
.assertIn('9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c=\t6Fsg8XN0DE6aPQgAX4r2oazEYJOGqyHUz3QRH/jCB+I=', output
)
1281 self
.assertIn('TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10=\tit7nd33chCT/tKT2ZZWfYyp43Zs+6oif72hexnSNMqA=', output
)
1282 self
.assertIn('lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tcPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=', output
)
1283 self
.assertIn('RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\tIIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=', output
)
1285 output
= check_output('wg show wg98 private-key')
1286 self
.assertEqual(output
, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr+WHtZLZ90FU=')
1288 output
= check_output('wg show wg97 listen-port')
1289 self
.assertEqual(output
, '51821')
1290 output
= check_output('wg show wg97 fwmark')
1291 self
.assertEqual(output
, '0x4d3')
1293 def test_geneve(self
):
1294 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
1297 self
.wait_online(['geneve99:degraded'])
1299 output
= check_output('ip -d link show geneve99')
1301 self
.assertRegex(output
, '192.168.22.1')
1302 self
.assertRegex(output
, '6082')
1303 self
.assertRegex(output
, 'udpcsum')
1304 self
.assertRegex(output
, 'udp6zerocsumrx')
1306 def test_ipip_tunnel(self
):
1307 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
1308 '25-ipip-tunnel.netdev', '25-tunnel.network',
1309 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1310 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1311 '25-ipip-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1313 self
.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'ipiptun96:routable', 'dummy98:degraded'])
1315 output
= check_output('ip -d link show ipiptun99')
1317 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98')
1318 output
= check_output('ip -d link show ipiptun98')
1320 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98')
1321 output
= check_output('ip -d link show ipiptun97')
1323 self
.assertRegex(output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98')
1324 output
= check_output('ip -d link show ipiptun96')
1326 self
.assertRegex(output
, 'ipip (ipip )?remote any local any dev dummy98')
1328 def test_gre_tunnel(self
):
1329 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
1330 '25-gre-tunnel.netdev', '25-tunnel.network',
1331 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1332 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1333 '25-gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1335 self
.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'gretun96:routable', 'dummy98:degraded'])
1337 output
= check_output('ip -d link show gretun99')
1339 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1340 self
.assertRegex(output
, 'ikey 1.2.3.103')
1341 self
.assertRegex(output
, 'okey 1.2.4.103')
1342 self
.assertRegex(output
, 'iseq')
1343 self
.assertRegex(output
, 'oseq')
1344 output
= check_output('ip -d link show gretun98')
1346 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
1347 self
.assertRegex(output
, 'ikey 0.0.0.104')
1348 self
.assertRegex(output
, 'okey 0.0.0.104')
1349 self
.assertNotRegex(output
, 'iseq')
1350 self
.assertNotRegex(output
, 'oseq')
1351 output
= check_output('ip -d link show gretun97')
1353 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
1354 self
.assertRegex(output
, 'ikey 0.0.0.105')
1355 self
.assertRegex(output
, 'okey 0.0.0.105')
1356 self
.assertNotRegex(output
, 'iseq')
1357 self
.assertNotRegex(output
, 'oseq')
1358 output
= check_output('ip -d link show gretun96')
1360 self
.assertRegex(output
, 'gre remote any local any dev dummy98')
1361 self
.assertRegex(output
, 'ikey 0.0.0.106')
1362 self
.assertRegex(output
, 'okey 0.0.0.106')
1363 self
.assertNotRegex(output
, 'iseq')
1364 self
.assertNotRegex(output
, 'oseq')
1366 def test_ip6gre_tunnel(self
):
1367 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
1368 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
1369 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1370 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1371 '25-ip6gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1374 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1376 self
.check_link_exists('dummy98')
1377 self
.check_link_exists('ip6gretun99')
1378 self
.check_link_exists('ip6gretun98')
1379 self
.check_link_exists('ip6gretun97')
1380 self
.check_link_exists('ip6gretun96')
1382 output
= check_output('ip -d link show ip6gretun99')
1384 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1385 output
= check_output('ip -d link show ip6gretun98')
1387 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
1388 output
= check_output('ip -d link show ip6gretun97')
1390 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
1391 output
= check_output('ip -d link show ip6gretun96')
1393 self
.assertRegex(output
, 'ip6gre remote any local any dev dummy98')
1395 def test_gretap_tunnel(self
):
1396 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
1397 '25-gretap-tunnel.netdev', '25-tunnel.network',
1398 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1400 self
.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
1402 output
= check_output('ip -d link show gretap99')
1404 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1405 self
.assertRegex(output
, 'ikey 0.0.0.106')
1406 self
.assertRegex(output
, 'okey 0.0.0.106')
1407 self
.assertRegex(output
, 'iseq')
1408 self
.assertRegex(output
, 'oseq')
1409 output
= check_output('ip -d link show gretap98')
1411 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
1412 self
.assertRegex(output
, 'ikey 0.0.0.107')
1413 self
.assertRegex(output
, 'okey 0.0.0.107')
1414 self
.assertRegex(output
, 'iseq')
1415 self
.assertRegex(output
, 'oseq')
1417 def test_ip6gretap_tunnel(self
):
1418 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
1419 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1420 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1422 self
.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
1424 output
= check_output('ip -d link show ip6gretap99')
1426 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1427 output
= check_output('ip -d link show ip6gretap98')
1429 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1431 def test_vti_tunnel(self
):
1432 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
1433 '25-vti-tunnel.netdev', '25-tunnel.network',
1434 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1435 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1436 '25-vti-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1438 self
.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'vtitun96:routable', 'dummy98:degraded'])
1440 output
= check_output('ip -d link show vtitun99')
1442 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1443 output
= check_output('ip -d link show vtitun98')
1445 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
1446 output
= check_output('ip -d link show vtitun97')
1448 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
1449 output
= check_output('ip -d link show vtitun96')
1451 self
.assertRegex(output
, 'vti remote any local any dev dummy98')
1453 def test_vti6_tunnel(self
):
1454 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
1455 '25-vti6-tunnel.netdev', '25-tunnel.network',
1456 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1457 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1459 self
.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
1461 output
= check_output('ip -d link show vti6tun99')
1463 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1464 output
= check_output('ip -d link show vti6tun98')
1466 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1467 output
= check_output('ip -d link show vti6tun97')
1469 self
.assertRegex(output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1471 def test_ip6tnl_tunnel(self
):
1472 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
1473 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1474 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1475 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1477 self
.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
1479 output
= check_output('ip -d link show ip6tnl99')
1481 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1482 output
= check_output('ip -d link show ip6tnl98')
1484 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1485 output
= check_output('ip -d link show ip6tnl97')
1487 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1489 def test_sit_tunnel(self
):
1490 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1491 '25-sit-tunnel.netdev', '25-tunnel.network',
1492 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1493 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1494 '25-sit-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1496 self
.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'sittun96:routable', 'dummy98:degraded'])
1498 output
= check_output('ip -d link show sittun99')
1500 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1501 output
= check_output('ip -d link show sittun98')
1503 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98")
1504 output
= check_output('ip -d link show sittun97')
1506 self
.assertRegex(output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98")
1507 output
= check_output('ip -d link show sittun96')
1509 self
.assertRegex(output
, "sit (ip6ip )?remote any local any dev dummy98")
1511 def test_isatap_tunnel(self
):
1512 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1513 '25-isatap-tunnel.netdev', '25-tunnel.network')
1515 self
.wait_online(['isataptun99:routable', 'dummy98:degraded'])
1517 output
= check_output('ip -d link show isataptun99')
1519 self
.assertRegex(output
, "isatap ")
1521 def test_6rd_tunnel(self
):
1522 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1523 '25-6rd-tunnel.netdev', '25-tunnel.network')
1525 self
.wait_online(['sittun99:routable', 'dummy98:degraded'])
1527 output
= check_output('ip -d link show sittun99')
1529 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1531 @expectedFailureIfERSPANModuleIsNotAvailable()
1532 def test_erspan_tunnel(self
):
1533 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1534 '25-erspan-tunnel.netdev', '25-tunnel.network',
1535 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1537 self
.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1539 output
= check_output('ip -d link show erspan99')
1541 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1542 self
.assertRegex(output
, 'ikey 0.0.0.101')
1543 self
.assertRegex(output
, 'okey 0.0.0.101')
1544 self
.assertRegex(output
, 'iseq')
1545 self
.assertRegex(output
, 'oseq')
1546 output
= check_output('ip -d link show erspan98')
1548 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1549 self
.assertRegex(output
, '102')
1550 self
.assertRegex(output
, 'ikey 0.0.0.102')
1551 self
.assertRegex(output
, 'okey 0.0.0.102')
1552 self
.assertRegex(output
, 'iseq')
1553 self
.assertRegex(output
, 'oseq')
1555 def test_tunnel_independent(self
):
1556 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1559 self
.wait_online(['ipiptun99:carrier'])
1561 def test_tunnel_independent_loopback(self
):
1562 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent-loopback.netdev', 'netdev-link-local-addressing-yes.network')
1565 self
.wait_online(['ipiptun99:carrier'])
1567 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1568 def test_xfrm(self
):
1569 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'xfrm.network',
1570 '25-xfrm.netdev', 'netdev-link-local-addressing-yes.network')
1573 self
.wait_online(['xfrm99:degraded', 'dummy98:degraded'])
1575 output
= check_output('ip link show dev xfrm99')
1578 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1579 def test_xfrm_independent(self
):
1580 copy_unit_to_networkd_unit_path('25-xfrm-independent.netdev', 'netdev-link-local-addressing-yes.network')
1583 self
.wait_online(['xfrm99:degraded'])
1585 @expectedFailureIfModuleIsNotAvailable('fou')
1587 # The following redundant check is necessary for CentOS CI.
1588 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1589 self
.assertTrue(is_module_available('fou'))
1591 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1592 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1593 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1596 self
.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'], setup_state
='unmanaged')
1598 output
= check_output('ip fou show')
1600 self
.assertRegex(output
, 'port 55555 ipproto 4')
1601 self
.assertRegex(output
, 'port 55556 ipproto 47')
1603 output
= check_output('ip -d link show ipiptun96')
1605 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1606 output
= check_output('ip -d link show sittun96')
1608 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1609 output
= check_output('ip -d link show gretun96')
1611 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1612 output
= check_output('ip -d link show gretap96')
1614 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1616 def test_vxlan(self
):
1617 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1618 '25-vxlan-independent.netdev', 'netdev-link-local-addressing-yes.network',
1619 '11-dummy.netdev', 'vxlan-test1.network')
1622 self
.wait_online(['test1:degraded', 'vxlan99:degraded', 'vxlan98:degraded'])
1624 output
= check_output('ip -d link show vxlan99')
1626 self
.assertRegex(output
, '999')
1627 self
.assertRegex(output
, '5555')
1628 self
.assertRegex(output
, 'l2miss')
1629 self
.assertRegex(output
, 'l3miss')
1630 self
.assertRegex(output
, 'udpcsum')
1631 self
.assertRegex(output
, 'udp6zerocsumtx')
1632 self
.assertRegex(output
, 'udp6zerocsumrx')
1633 self
.assertRegex(output
, 'remcsumtx')
1634 self
.assertRegex(output
, 'remcsumrx')
1635 self
.assertRegex(output
, 'gbp')
1637 output
= check_output('bridge fdb show dev vxlan99')
1639 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1640 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1641 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1643 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'vxlan99', env
=env
)
1645 self
.assertRegex(output
, 'VNI: 999')
1646 self
.assertRegex(output
, 'Destination Port: 5555')
1647 self
.assertRegex(output
, 'Underlying Device: test1')
1649 output
= check_output('ip -d link show vxlan98')
1652 def test_macsec(self
):
1653 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1654 'macsec.network', '12-dummy.netdev')
1657 self
.wait_online(['dummy98:degraded', 'macsec99:routable'])
1659 output
= check_output('ip -d link show macsec99')
1661 self
.assertRegex(output
, 'macsec99@dummy98')
1662 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1663 self
.assertRegex(output
, 'encrypt on')
1665 output
= check_output('ip macsec show macsec99')
1667 self
.assertRegex(output
, 'encrypt on')
1668 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1669 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1670 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1671 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1672 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1673 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1674 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1675 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1676 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1677 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1678 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1680 def test_nlmon(self
):
1681 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1684 self
.wait_online(['nlmon99:carrier'])
1686 @expectedFailureIfModuleIsNotAvailable('ifb')
1688 copy_unit_to_networkd_unit_path('25-ifb.netdev', 'netdev-link-local-addressing-yes.network')
1691 self
.wait_online(['ifb99:degraded'])
1693 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1704 '25-l2tp-dummy.network',
1706 '25-l2tp-ip.netdev',
1707 '25-l2tp-udp.netdev']
1709 l2tp_tunnel_ids
= [ '10' ]
1712 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1713 remove_links(self
.links
)
1714 stop_networkd(show_logs
=False)
1717 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1718 remove_links(self
.links
)
1719 remove_unit_from_networkd_path(self
.units
)
1720 stop_networkd(show_logs
=True)
1722 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1723 def test_l2tp_udp(self
):
1724 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1725 '25-l2tp-udp.netdev', '25-l2tp.network')
1728 self
.wait_online(['test1:routable', 'l2tp-ses1:degraded', 'l2tp-ses2:degraded'])
1730 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1732 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1733 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1734 self
.assertRegex(output
, "Peer tunnel 11")
1735 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1736 self
.assertRegex(output
, "UDP checksum: enabled")
1738 output
= check_output('ip l2tp show session tid 10 session_id 15')
1740 self
.assertRegex(output
, "Session 15 in tunnel 10")
1741 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1742 self
.assertRegex(output
, "interface name: l2tp-ses1")
1744 output
= check_output('ip l2tp show session tid 10 session_id 17')
1746 self
.assertRegex(output
, "Session 17 in tunnel 10")
1747 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1748 self
.assertRegex(output
, "interface name: l2tp-ses2")
1750 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1751 def test_l2tp_ip(self
):
1752 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1753 '25-l2tp-ip.netdev', '25-l2tp.network')
1756 self
.wait_online(['test1:routable', 'l2tp-ses3:degraded', 'l2tp-ses4:degraded'])
1758 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1760 self
.assertRegex(output
, "Tunnel 10, encap IP")
1761 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1762 self
.assertRegex(output
, "Peer tunnel 12")
1764 output
= check_output('ip l2tp show session tid 10 session_id 25')
1766 self
.assertRegex(output
, "Session 25 in tunnel 10")
1767 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1768 self
.assertRegex(output
, "interface name: l2tp-ses3")
1770 output
= check_output('ip l2tp show session tid 10 session_id 27')
1772 self
.assertRegex(output
, "Session 27 in tunnel 10")
1773 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1774 self
.assertRegex(output
, "interface name: l2tp-ses4")
1776 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1791 '23-active-slave.network',
1792 '24-keep-configuration-static.network',
1793 '24-search-domain.network',
1794 '25-address-dad-veth-peer.network',
1795 '25-address-dad-veth99.network',
1796 '25-address-link-section.network',
1797 '25-address-peer-ipv4.network',
1798 '25-address-static.network',
1799 '25-activation-policy.network',
1800 '25-bind-carrier.network',
1801 '25-bond-active-backup-slave.netdev',
1802 '25-fibrule-invert.network',
1803 '25-fibrule-port-range.network',
1804 '25-fibrule-uidrange.network',
1805 '25-gre-tunnel-remote-any.netdev',
1806 '25-ip6gre-tunnel-remote-any.netdev',
1807 '25-ipv6-address-label-section.network',
1808 '25-ipv6-proxy-ndp.network',
1809 '25-link-local-addressing-no.network',
1810 '25-link-local-addressing-yes.network',
1811 '25-link-section-unmanaged.network',
1812 '25-neighbor-section.network',
1813 '25-neighbor-next.network',
1814 '25-neighbor-ipv6.network',
1815 '25-neighbor-ip-dummy.network',
1816 '25-neighbor-ip.network',
1817 '25-nexthop-nothing.network',
1818 '25-nexthop.network',
1819 '25-qdisc-cake.network',
1820 '25-qdisc-clsact-and-htb.network',
1821 '25-qdisc-drr.network',
1822 '25-qdisc-ets.network',
1823 '25-qdisc-fq_pie.network',
1824 '25-qdisc-hhf.network',
1825 '25-qdisc-ingress-netem-compat.network',
1826 '25-qdisc-pie.network',
1827 '25-qdisc-qfq.network',
1828 '25-prefix-route-with-vrf.network',
1829 '25-prefix-route-without-vrf.network',
1830 '25-route-ipv6-src.network',
1831 '25-route-static.network',
1832 '25-route-via-ipv6.network',
1833 '25-route-vrf.network',
1834 '25-gateway-static.network',
1835 '25-gateway-next-static.network',
1837 '25-sysctl-disable-ipv6.network',
1838 '25-sysctl.network',
1840 '25-veth-peer.network',
1844 '26-link-local-addressing-ipv6.network',
1845 'routing-policy-rule-dummy98.network',
1846 'routing-policy-rule-test1.network',
1847 'routing-policy-rule-reconfigure1.network',
1848 'routing-policy-rule-reconfigure2.network',
1851 routing_policy_rule_tables
= ['7', '8', '9', '1011']
1852 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1855 remove_blackhole_nexthops()
1856 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1857 remove_routes(self
.routes
)
1858 remove_links(self
.links
)
1859 stop_networkd(show_logs
=False)
1862 remove_blackhole_nexthops()
1863 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1864 remove_routes(self
.routes
)
1865 remove_links(self
.links
)
1866 remove_unit_from_networkd_path(self
.units
)
1867 stop_networkd(show_logs
=True)
1869 def test_address_static(self
):
1870 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1873 self
.wait_online(['dummy98:routable'])
1875 output
= check_output('ip -4 address show dev dummy98')
1877 self
.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output
)
1878 self
.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output
)
1879 self
.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output
)
1880 self
.assertIn('inet 10.7.8.9/16 brd 10.7.255.255 scope link deprecated dummy98', output
)
1881 self
.assertIn('inet 10.8.8.1/16 scope global dummy98', output
)
1883 # test for ENOBUFS issue #17012
1884 for i
in range(1,254):
1885 self
.assertIn(f
'inet 10.3.3.{i}/16 brd 10.3.255.255', output
)
1888 self
.assertNotIn('10.10.0.1/16', output
)
1889 self
.assertNotIn('10.10.0.2/16', output
)
1891 output
= check_output('ip -4 address show dev dummy98 label 32')
1892 self
.assertIn('inet 10.3.2.3/16 brd 10.3.255.255 scope global 32', output
)
1894 output
= check_output('ip -4 address show dev dummy98 label 33')
1895 self
.assertIn('inet 10.4.2.3 peer 10.4.2.4/16 scope global 33', output
)
1897 output
= check_output('ip -4 address show dev dummy98 label 34')
1898 self
.assertRegex(output
, r
'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1900 output
= check_output('ip -4 address show dev dummy98 label 35')
1901 self
.assertRegex(output
, r
'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1903 output
= check_output('ip -6 address show dev dummy98')
1905 self
.assertIn('inet6 2001:db8:0:f101::15/64 scope global', output
)
1906 self
.assertIn('inet6 2001:db8:0:f101::16/64 scope global', output
)
1907 self
.assertIn('inet6 2001:db8:0:f102::15/64 scope global', output
)
1908 self
.assertIn('inet6 2001:db8:0:f102::16/64 scope global', output
)
1909 self
.assertIn('inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global', output
)
1910 self
.assertIn('inet6 2001:db8:1:f101::1/64 scope global deprecated', output
)
1911 self
.assertRegex(output
, r
'inet6 fd[0-9a-f:]*1/64 scope global')
1914 self
.wait_online(['dummy98:routable'])
1916 # test for ENOBUFS issue #17012
1917 output
= check_output('ip -4 address show dev dummy98')
1918 for i
in range(1,254):
1919 self
.assertIn(f
'inet 10.3.3.{i}/16 brd 10.3.255.255', output
)
1921 def test_address_dad(self
):
1922 copy_unit_to_networkd_unit_path('25-address-dad-veth99.network', '25-address-dad-veth-peer.network',
1925 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
1927 output
= check_output('ip -4 address show dev veth99')
1929 self
.assertRegex(output
, '192.168.100.10/24')
1931 output
= check_output('ip -4 address show dev veth-peer')
1933 self
.assertNotRegex(output
, '192.168.100.10/24')
1935 def test_address_peer_ipv4(self
):
1936 # test for issue #17304
1937 copy_unit_to_networkd_unit_path('25-address-peer-ipv4.network', '12-dummy.netdev')
1939 for trial
in range(2):
1945 self
.wait_online(['dummy98:routable'])
1947 output
= check_output('ip -4 address show dev dummy98')
1948 self
.assertIn('inet 100.64.0.1 peer 100.64.0.2/32 scope global', output
)
1950 @expectedFailureIfModuleIsNotAvailable('vrf')
1951 def test_prefix_route(self
):
1952 copy_unit_to_networkd_unit_path('25-prefix-route-with-vrf.network', '12-dummy.netdev',
1953 '25-prefix-route-without-vrf.network', '11-dummy.netdev',
1954 '25-vrf.netdev', '25-vrf.network')
1955 for trial
in range(2):
1961 self
.wait_online(['dummy98:routable', 'test1:routable', 'vrf99:carrier'])
1963 output
= check_output('ip route show table 42 dev dummy98')
1964 print('### ip route show table 42 dev dummy98')
1966 self
.assertRegex(output
, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1')
1967 self
.assertRegex(output
, 'broadcast 10.20.33.0 proto kernel scope link src 10.20.33.1')
1968 self
.assertRegex(output
, '10.20.33.0/24 proto kernel scope link src 10.20.33.1')
1969 self
.assertRegex(output
, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1')
1970 self
.assertRegex(output
, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1')
1971 self
.assertRegex(output
, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1')
1972 self
.assertRegex(output
, 'broadcast 10.20.55.0 proto kernel scope link src 10.20.55.1')
1973 self
.assertRegex(output
, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1')
1974 self
.assertRegex(output
, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1')
1975 output
= check_output('ip -6 route show table 42 dev dummy98')
1976 print('### ip -6 route show table 42 dev dummy98')
1980 self
.assertRegex(output
, 'local fdde:11:22::1 proto kernel metric 0 pref medium')
1981 #self.assertRegex(output, 'fdde:11:22::1 proto kernel metric 256 pref medium')
1982 self
.assertRegex(output
, 'local fdde:11:33::1 proto kernel metric 0 pref medium')
1983 self
.assertRegex(output
, 'fdde:11:33::/64 proto kernel metric 256 pref medium')
1984 self
.assertRegex(output
, 'local fdde:11:44::1 proto kernel metric 0 pref medium')
1985 self
.assertRegex(output
, 'local fdde:11:55::1 proto kernel metric 0 pref medium')
1986 self
.assertRegex(output
, 'fe80::/64 proto kernel metric 256 pref medium')
1987 self
.assertRegex(output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium')
1991 output
= check_output('ip route show dev test1')
1992 print('### ip route show dev test1')
1994 self
.assertRegex(output
, '10.21.33.0/24 proto kernel scope link src 10.21.33.1')
1995 output
= check_output('ip route show table local dev test1')
1996 print('### ip route show table local dev test1')
1998 self
.assertRegex(output
, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1')
1999 self
.assertRegex(output
, 'broadcast 10.21.33.0 proto kernel scope link src 10.21.33.1')
2000 self
.assertRegex(output
, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1')
2001 self
.assertRegex(output
, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1')
2002 self
.assertRegex(output
, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1')
2003 self
.assertRegex(output
, 'broadcast 10.21.55.0 proto kernel scope link src 10.21.55.1')
2004 self
.assertRegex(output
, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1')
2005 self
.assertRegex(output
, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1')
2006 output
= check_output('ip -6 route show dev test1')
2007 print('### ip -6 route show dev test1')
2009 self
.assertRegex(output
, 'fdde:12:22::1 proto kernel metric 256 pref medium')
2010 self
.assertRegex(output
, 'fdde:12:33::/64 proto kernel metric 256 pref medium')
2011 self
.assertRegex(output
, 'fe80::/64 proto kernel metric 256 pref medium')
2012 output
= check_output('ip -6 route show table local dev test1')
2013 print('### ip -6 route show table local dev test1')
2015 self
.assertRegex(output
, 'local fdde:12:22::1 proto kernel metric 0 pref medium')
2016 self
.assertRegex(output
, 'local fdde:12:33::1 proto kernel metric 0 pref medium')
2017 self
.assertRegex(output
, 'local fdde:12:44::1 proto kernel metric 0 pref medium')
2018 self
.assertRegex(output
, 'local fdde:12:55::1 proto kernel metric 0 pref medium')
2019 self
.assertRegex(output
, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium')
2021 def test_configure_without_carrier(self
):
2022 copy_unit_to_networkd_unit_path('11-dummy.netdev')
2024 self
.wait_operstate('test1', 'off', '')
2025 check_output('ip link set dev test1 up carrier off')
2027 copy_unit_to_networkd_unit_path('25-test1.network.d/configure-without-carrier.conf', dropins
=False)
2029 self
.wait_online(['test1:no-carrier'])
2031 carrier_map
= {'on': '1', 'off': '0'}
2032 routable_map
= {'on': 'routable', 'off': 'no-carrier'}
2033 for carrier
in ['off', 'on', 'off']:
2034 with self
.subTest(carrier
=carrier
):
2035 if carrier_map
[carrier
] != read_link_attr('test1', 'carrier'):
2036 check_output(f
'ip link set dev test1 carrier {carrier}')
2037 self
.wait_online([f
'test1:{routable_map[carrier]}'])
2039 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
2041 self
.assertRegex(output
, '192.168.0.15')
2042 self
.assertRegex(output
, '192.168.0.1')
2043 self
.assertRegex(output
, routable_map
[carrier
])
2045 def test_configure_without_carrier_yes_ignore_carrier_loss_no(self
):
2046 copy_unit_to_networkd_unit_path('11-dummy.netdev')
2048 self
.wait_operstate('test1', 'off', '')
2049 check_output('ip link set dev test1 up carrier off')
2051 copy_unit_to_networkd_unit_path('25-test1.network')
2053 self
.wait_online(['test1:no-carrier'])
2055 carrier_map
= {'on': '1', 'off': '0'}
2056 routable_map
= {'on': 'routable', 'off': 'no-carrier'}
2057 for (carrier
, have_config
) in [('off', True), ('on', True), ('off', False)]:
2058 with self
.subTest(carrier
=carrier
, have_config
=have_config
):
2059 if carrier_map
[carrier
] != read_link_attr('test1', 'carrier'):
2060 check_output(f
'ip link set dev test1 carrier {carrier}')
2061 self
.wait_online([f
'test1:{routable_map[carrier]}'])
2063 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
2066 self
.assertRegex(output
, '192.168.0.15')
2067 self
.assertRegex(output
, '192.168.0.1')
2069 self
.assertNotRegex(output
, '192.168.0.15')
2070 self
.assertNotRegex(output
, '192.168.0.1')
2071 self
.assertRegex(output
, routable_map
[carrier
])
2073 def test_routing_policy_rule(self
):
2074 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
2076 self
.wait_online(['test1:degraded'])
2078 output
= check_output('ip rule list iif test1 priority 111')
2080 self
.assertRegex(output
, '111:')
2081 self
.assertRegex(output
, 'from 192.168.100.18')
2082 self
.assertRegex(output
, r
'tos (0x08|throughput)\s')
2083 self
.assertRegex(output
, 'iif test1')
2084 self
.assertRegex(output
, 'oif test1')
2085 self
.assertRegex(output
, 'lookup 7')
2087 output
= check_output('ip rule list iif test1 priority 101')
2089 self
.assertRegex(output
, '101:')
2090 self
.assertRegex(output
, 'from all')
2091 self
.assertRegex(output
, 'iif test1')
2092 self
.assertRegex(output
, 'lookup 9')
2094 output
= check_output('ip -6 rule list iif test1 priority 100')
2096 self
.assertRegex(output
, '100:')
2097 self
.assertRegex(output
, 'from all')
2098 self
.assertRegex(output
, 'iif test1')
2099 self
.assertRegex(output
, 'lookup 8')
2101 def test_routing_policy_rule_issue_11280(self
):
2102 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
2103 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
2105 for trial
in range(3):
2106 # Remove state files only first time
2108 self
.wait_online(['test1:degraded', 'dummy98:degraded'])
2111 output
= check_output('ip rule list table 7')
2113 self
.assertRegex(output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
2115 output
= check_output('ip rule list table 8')
2117 self
.assertRegex(output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
2119 stop_networkd(remove_state_files
=False)
2121 def test_routing_policy_rule_reconfigure(self
):
2122 copy_unit_to_networkd_unit_path('routing-policy-rule-reconfigure2.network', '11-dummy.netdev')
2124 self
.wait_online(['test1:degraded'])
2126 output
= check_output('ip rule list table 1011')
2128 self
.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output
)
2129 self
.assertIn('10112: from all oif test1 lookup 1011', output
)
2130 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2131 self
.assertIn('10114: from 192.168.8.254 lookup 1011', output
)
2133 output
= check_output('ip -6 rule list table 1011')
2135 self
.assertIn('10112: from all oif test1 lookup 1011', output
)
2137 copy_unit_to_networkd_unit_path('routing-policy-rule-reconfigure1.network', '11-dummy.netdev')
2138 run(*networkctl_cmd
, 'reload', env
=env
)
2140 self
.wait_online(['test1:degraded'])
2142 output
= check_output('ip rule list table 1011')
2144 self
.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output
)
2145 self
.assertIn('10112: from all oif test1 lookup 1011', output
)
2146 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2147 self
.assertIn('10114: from 192.168.8.254 lookup 1011', output
)
2149 output
= check_output('ip -6 rule list table 1011')
2151 self
.assertNotIn('10112: from all oif test1 lookup 1011', output
)
2152 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2154 run('ip rule delete priority 10111')
2155 run('ip rule delete priority 10112')
2156 run('ip rule delete priority 10113')
2157 run('ip rule delete priority 10114')
2158 run('ip -6 rule delete priority 10113')
2160 output
= check_output('ip rule list table 1011')
2162 self
.assertEqual(output
, '')
2164 output
= check_output('ip -6 rule list table 1011')
2166 self
.assertEqual(output
, '')
2168 run(*networkctl_cmd
, 'reconfigure', 'test1', env
=env
)
2169 self
.wait_online(['test1:degraded'])
2171 output
= check_output('ip rule list table 1011')
2173 self
.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output
)
2174 self
.assertIn('10112: from all oif test1 lookup 1011', output
)
2175 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2176 self
.assertIn('10114: from 192.168.8.254 lookup 1011', output
)
2178 output
= check_output('ip -6 rule list table 1011')
2180 self
.assertIn('10113: from all iif test1 lookup 1011', output
)
2182 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
2183 def test_routing_policy_rule_port_range(self
):
2184 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
2186 self
.wait_online(['test1:degraded'])
2188 output
= check_output('ip rule')
2190 self
.assertRegex(output
, '111')
2191 self
.assertRegex(output
, 'from 192.168.100.18')
2192 self
.assertRegex(output
, '1123-1150')
2193 self
.assertRegex(output
, '3224-3290')
2194 self
.assertRegex(output
, 'tcp')
2195 self
.assertRegex(output
, 'lookup 7')
2197 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
2198 def test_routing_policy_rule_invert(self
):
2199 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
2201 self
.wait_online(['test1:degraded'])
2203 output
= check_output('ip rule')
2205 self
.assertRegex(output
, '111')
2206 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
2207 self
.assertRegex(output
, 'tcp')
2208 self
.assertRegex(output
, 'lookup 7')
2210 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable()
2211 def test_routing_policy_rule_uidrange(self
):
2212 copy_unit_to_networkd_unit_path('25-fibrule-uidrange.network', '11-dummy.netdev')
2214 self
.wait_online(['test1:degraded'])
2216 output
= check_output('ip rule')
2218 self
.assertRegex(output
, '111')
2219 self
.assertRegex(output
, 'from 192.168.100.18')
2220 self
.assertRegex(output
, 'lookup 7')
2221 self
.assertRegex(output
, 'uidrange 100-200')
2223 def test_route_static(self
):
2224 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
2226 self
.wait_online(['dummy98:routable'])
2228 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2231 print('### ip -6 route show dev dummy98')
2232 output
= check_output('ip -6 route show dev dummy98')
2234 self
.assertIn('2001:1234:5:8fff:ff:ff:ff:ff proto static', output
)
2235 self
.assertIn('2001:1234:5:8f63::1 proto kernel', output
)
2237 print('### ip -6 route show default')
2238 output
= check_output('ip -6 route show default')
2240 self
.assertIn('default', output
)
2241 self
.assertIn('via 2001:1234:5:8fff:ff:ff:ff:ff', output
)
2243 print('### ip -4 route show dev dummy98')
2244 output
= check_output('ip -4 route show dev dummy98')
2246 self
.assertIn('149.10.124.48/28 proto kernel scope link src 149.10.124.58', output
)
2247 self
.assertIn('149.10.124.64 proto static scope link', output
)
2248 self
.assertIn('169.254.0.0/16 proto static scope link metric 2048', output
)
2249 self
.assertIn('192.168.1.1 proto static initcwnd 20', output
)
2250 self
.assertIn('192.168.1.2 proto static initrwnd 30', output
)
2251 self
.assertIn('192.168.1.3 proto static advmss 30', output
)
2252 self
.assertIn('multicast 149.10.123.4 proto static', output
)
2254 print('### ip -4 route show dev dummy98 default')
2255 output
= check_output('ip -4 route show dev dummy98 default')
2257 self
.assertIn('default via 149.10.125.65 proto static onlink', output
)
2258 self
.assertIn('default via 149.10.124.64 proto static', output
)
2259 self
.assertIn('default proto static', output
)
2261 print('### ip -4 route show table local dev dummy98')
2262 output
= check_output('ip -4 route show table local dev dummy98')
2264 self
.assertIn('local 149.10.123.1 proto static scope host', output
)
2265 self
.assertIn('anycast 149.10.123.2 proto static scope link', output
)
2266 self
.assertIn('broadcast 149.10.123.3 proto static scope link', output
)
2268 print('### ip route show type blackhole')
2269 output
= check_output('ip route show type blackhole')
2271 self
.assertIn('blackhole 202.54.1.2 proto static', output
)
2273 print('### ip route show type unreachable')
2274 output
= check_output('ip route show type unreachable')
2276 self
.assertIn('unreachable 202.54.1.3 proto static', output
)
2278 print('### ip route show type prohibit')
2279 output
= check_output('ip route show type prohibit')
2281 self
.assertIn('prohibit 202.54.1.4 proto static', output
)
2283 print('### ip -6 route show type blackhole')
2284 output
= check_output('ip -6 route show type blackhole')
2286 self
.assertIn('blackhole 2001:1234:5678::2 dev lo proto static', output
)
2288 print('### ip -6 route show type unreachable')
2289 output
= check_output('ip -6 route show type unreachable')
2291 self
.assertIn('unreachable 2001:1234:5678::3 dev lo proto static', output
)
2293 print('### ip -6 route show type prohibit')
2294 output
= check_output('ip -6 route show type prohibit')
2296 self
.assertIn('prohibit 2001:1234:5678::4 dev lo proto static', output
)
2298 print('### ip route show 192.168.10.1')
2299 output
= check_output('ip route show 192.168.10.1')
2301 self
.assertIn('192.168.10.1 proto static', output
)
2302 self
.assertIn('nexthop via 149.10.124.59 dev dummy98 weight 10', output
)
2303 self
.assertIn('nexthop via 149.10.124.60 dev dummy98 weight 5', output
)
2305 print('### ip route show 192.168.10.2')
2306 output
= check_output('ip route show 192.168.10.2')
2308 # old ip command does not show IPv6 gateways...
2309 self
.assertIn('192.168.10.2 proto static', output
)
2310 self
.assertIn('nexthop', output
)
2311 self
.assertIn('dev dummy98 weight 10', output
)
2312 self
.assertIn('dev dummy98 weight 5', output
)
2314 print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2315 output
= check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2317 # old ip command does not show 'nexthop' keyword and weight...
2318 self
.assertIn('2001:1234:5:7fff:ff:ff:ff:ff', output
)
2319 self
.assertIn('via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98', output
)
2320 self
.assertIn('via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98', output
)
2322 copy_unit_to_networkd_unit_path('25-address-static.network')
2323 check_output(*networkctl_cmd
, 'reload', env
=env
)
2325 self
.wait_online(['dummy98:routable'])
2327 # check all routes managed by Manager are removed
2328 print('### ip route show type blackhole')
2329 output
= check_output('ip route show type blackhole')
2331 self
.assertEqual(output
, '')
2333 print('### ip route show type unreachable')
2334 output
= check_output('ip route show type unreachable')
2336 self
.assertEqual(output
, '')
2338 print('### ip route show type prohibit')
2339 output
= check_output('ip route show type prohibit')
2341 self
.assertEqual(output
, '')
2343 print('### ip -6 route show type blackhole')
2344 output
= check_output('ip -6 route show type blackhole')
2346 self
.assertEqual(output
, '')
2348 print('### ip -6 route show type unreachable')
2349 output
= check_output('ip -6 route show type unreachable')
2351 self
.assertEqual(output
, '')
2353 print('### ip -6 route show type prohibit')
2354 output
= check_output('ip -6 route show type prohibit')
2356 self
.assertEqual(output
, '')
2358 remove_unit_from_networkd_path(['25-address-static.network'])
2359 check_output(*networkctl_cmd
, 'reload', env
=env
)
2361 self
.wait_online(['dummy98:routable'])
2363 # check all routes managed by Manager are reconfigured
2364 print('### ip route show type blackhole')
2365 output
= check_output('ip route show type blackhole')
2367 self
.assertIn('blackhole 202.54.1.2 proto static', output
)
2369 print('### ip route show type unreachable')
2370 output
= check_output('ip route show type unreachable')
2372 self
.assertIn('unreachable 202.54.1.3 proto static', output
)
2374 print('### ip route show type prohibit')
2375 output
= check_output('ip route show type prohibit')
2377 self
.assertIn('prohibit 202.54.1.4 proto static', output
)
2379 print('### ip -6 route show type blackhole')
2380 output
= check_output('ip -6 route show type blackhole')
2382 self
.assertIn('blackhole 2001:1234:5678::2 dev lo proto static', output
)
2384 print('### ip -6 route show type unreachable')
2385 output
= check_output('ip -6 route show type unreachable')
2387 self
.assertIn('unreachable 2001:1234:5678::3 dev lo proto static', output
)
2389 print('### ip -6 route show type prohibit')
2390 output
= check_output('ip -6 route show type prohibit')
2392 self
.assertIn('prohibit 2001:1234:5678::4 dev lo proto static', output
)
2394 rc
= call("ip link del dummy98")
2395 self
.assertEqual(rc
, 0)
2398 # check all routes managed by Manager are removed
2399 print('### ip route show type blackhole')
2400 output
= check_output('ip route show type blackhole')
2402 self
.assertEqual(output
, '')
2404 print('### ip route show type unreachable')
2405 output
= check_output('ip route show type unreachable')
2407 self
.assertEqual(output
, '')
2409 print('### ip route show type prohibit')
2410 output
= check_output('ip route show type prohibit')
2412 self
.assertEqual(output
, '')
2414 print('### ip -6 route show type blackhole')
2415 output
= check_output('ip -6 route show type blackhole')
2417 self
.assertEqual(output
, '')
2419 print('### ip -6 route show type unreachable')
2420 output
= check_output('ip -6 route show type unreachable')
2422 self
.assertEqual(output
, '')
2424 print('### ip -6 route show type prohibit')
2425 output
= check_output('ip -6 route show type prohibit')
2427 self
.assertEqual(output
, '')
2429 @expectedFailureIfRTA_VIAIsNotSupported()
2430 def test_route_via_ipv6(self
):
2431 copy_unit_to_networkd_unit_path('25-route-via-ipv6.network', '12-dummy.netdev')
2433 self
.wait_online(['dummy98:routable'])
2435 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2438 print('### ip -6 route show dev dummy98')
2439 output
= check_output('ip -6 route show dev dummy98')
2441 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
2442 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
2444 print('### ip -4 route show dev dummy98')
2445 output
= check_output('ip -4 route show dev dummy98')
2447 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
2448 self
.assertRegex(output
, '149.10.124.66 via inet6 2001:1234:5:8fff:ff:ff:ff:ff proto static')
2450 @expectedFailureIfModuleIsNotAvailable('vrf')
2451 def test_route_vrf(self
):
2452 copy_unit_to_networkd_unit_path('25-route-vrf.network', '12-dummy.netdev',
2453 '25-vrf.netdev', '25-vrf.network')
2455 self
.wait_online(['dummy98:routable', 'vrf99:carrier'])
2457 output
= check_output('ip route show vrf vrf99')
2459 self
.assertRegex(output
, 'default via 192.168.100.1')
2461 output
= check_output('ip route show')
2463 self
.assertNotRegex(output
, 'default via 192.168.100.1')
2465 def test_gateway_reconfigure(self
):
2466 copy_unit_to_networkd_unit_path('25-gateway-static.network', '12-dummy.netdev')
2468 self
.wait_online(['dummy98:routable'])
2469 print('### ip -4 route show dev dummy98 default')
2470 output
= check_output('ip -4 route show dev dummy98 default')
2472 self
.assertRegex(output
, 'default via 149.10.124.59 proto static')
2473 self
.assertNotRegex(output
, '149.10.124.60')
2475 remove_unit_from_networkd_path(['25-gateway-static.network'])
2476 copy_unit_to_networkd_unit_path('25-gateway-next-static.network')
2478 self
.wait_online(['dummy98:routable'])
2479 print('### ip -4 route show dev dummy98 default')
2480 output
= check_output('ip -4 route show dev dummy98 default')
2482 self
.assertNotRegex(output
, '149.10.124.59')
2483 self
.assertRegex(output
, 'default via 149.10.124.60 proto static')
2485 def test_ip_route_ipv6_src_route(self
):
2486 # a dummy device does not make the addresses go through tentative state, so we
2487 # reuse a bond from an earlier test, which does make the addresses go through
2488 # tentative state, and do our test on that
2489 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2491 self
.wait_online(['dummy98:enslaved', 'bond199:routable'])
2493 output
= check_output('ip -6 route list dev bond199')
2495 self
.assertRegex(output
, 'abcd::/16')
2496 self
.assertRegex(output
, 'src')
2497 self
.assertRegex(output
, '2001:1234:56:8f63::2')
2499 def test_ip_link_mac_address(self
):
2500 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
2502 self
.wait_online(['dummy98:degraded'])
2504 output
= check_output('ip link show dummy98')
2506 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
2508 def test_ip_link_unmanaged(self
):
2509 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
2512 self
.check_link_exists('dummy98')
2514 self
.wait_operstate('dummy98', 'off', setup_state
='unmanaged')
2516 def test_ipv6_address_label(self
):
2517 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
2519 self
.wait_online(['dummy98:degraded'])
2521 output
= check_output('ip addrlabel list')
2523 self
.assertRegex(output
, '2004:da8:1::/64')
2525 def test_ipv6_proxy_ndp(self
):
2526 copy_unit_to_networkd_unit_path('25-ipv6-proxy-ndp.network', '12-dummy.netdev')
2529 self
.wait_online(['dummy98:routable'])
2531 output
= check_output('ip neighbor show proxy dev dummy98')
2533 for i
in range(1,5):
2534 self
.assertRegex(output
, f
'2607:5300:203:5215:{i}::1 *proxy')
2536 def test_neighbor_section(self
):
2537 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2539 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2541 print('### ip neigh list dev dummy98')
2542 output
= check_output('ip neigh list dev dummy98')
2544 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2545 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2547 def test_neighbor_reconfigure(self
):
2548 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2550 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2552 print('### ip neigh list dev dummy98')
2553 output
= check_output('ip neigh list dev dummy98')
2555 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2556 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2558 remove_unit_from_networkd_path(['25-neighbor-section.network'])
2559 copy_unit_to_networkd_unit_path('25-neighbor-next.network')
2561 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2562 print('### ip neigh list dev dummy98')
2563 output
= check_output('ip neigh list dev dummy98')
2565 self
.assertNotRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2566 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT')
2567 self
.assertNotRegex(output
, '2004:da8:1::1.*PERMANENT')
2569 def test_neighbor_gre(self
):
2570 copy_unit_to_networkd_unit_path('25-neighbor-ip.network', '25-neighbor-ipv6.network', '25-neighbor-ip-dummy.network',
2571 '12-dummy.netdev', '25-gre-tunnel-remote-any.netdev', '25-ip6gre-tunnel-remote-any.netdev')
2573 self
.wait_online(['dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable'], timeout
='40s')
2575 output
= check_output('ip neigh list dev gretun97')
2577 self
.assertRegex(output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT')
2579 output
= check_output('ip neigh list dev ip6gretun97')
2581 self
.assertRegex(output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
2583 def test_link_local_addressing(self
):
2584 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
2585 '25-link-local-addressing-no.network', '12-dummy.netdev')
2587 self
.wait_online(['test1:degraded', 'dummy98:carrier'])
2589 output
= check_output('ip address show dev test1')
2591 self
.assertRegex(output
, 'inet .* scope link')
2592 self
.assertRegex(output
, 'inet6 .* scope link')
2594 output
= check_output('ip address show dev dummy98')
2596 self
.assertNotRegex(output
, 'inet6* .* scope link')
2599 Documentation/networking/ip-sysctl.txt
2601 addr_gen_mode - INTEGER
2602 Defines how link-local and autoconf addresses are generated.
2604 0: generate address based on EUI64 (default)
2605 1: do no generate a link-local address, use EUI64 for addresses generated
2607 2: generate stable privacy addresses, using the secret from
2608 stable_secret (RFC7217)
2609 3: generate stable privacy addresses, using a random secret if unset
2612 test1_addr_gen_mode
= ''
2613 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
2614 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
2618 # if stable_secret is unset, then EIO is returned
2619 test1_addr_gen_mode
= '0'
2621 test1_addr_gen_mode
= '2'
2623 test1_addr_gen_mode
= '0'
2625 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
2626 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
2628 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
2629 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
2631 def test_link_local_addressing_remove_ipv6ll(self
):
2632 copy_unit_to_networkd_unit_path('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
2634 self
.wait_online(['dummy98:degraded'])
2636 output
= check_output('ip address show dev dummy98')
2638 self
.assertRegex(output
, 'inet6 .* scope link')
2640 copy_unit_to_networkd_unit_path('25-link-local-addressing-no.network')
2642 self
.wait_online(['dummy98:carrier'])
2644 output
= check_output('ip address show dev dummy98')
2646 self
.assertNotRegex(output
, 'inet6* .* scope link')
2648 def test_sysctl(self
):
2649 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
2651 self
.wait_online(['dummy98:degraded'])
2653 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
2654 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
2655 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
2656 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
2657 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
2658 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
2659 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
2660 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'accept_local'), '1')
2662 def test_sysctl_disable_ipv6(self
):
2663 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
2665 print('## Disable ipv6')
2666 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
2667 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
2670 self
.wait_online(['dummy98:routable'])
2672 output
= check_output('ip -4 address show dummy98')
2674 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2675 output
= check_output('ip -6 address show dummy98')
2677 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2678 self
.assertRegex(output
, 'inet6 .* scope link')
2679 output
= check_output('ip -4 route show dev dummy98')
2681 self
.assertRegex(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2682 output
= check_output('ip -6 route show default')
2684 self
.assertRegex(output
, 'default')
2685 self
.assertRegex(output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff')
2687 check_output('ip link del dummy98')
2689 print('## Enable ipv6')
2690 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
2691 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
2694 self
.wait_online(['dummy98:routable'])
2696 output
= check_output('ip -4 address show dummy98')
2698 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2699 output
= check_output('ip -6 address show dummy98')
2701 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2702 self
.assertRegex(output
, 'inet6 .* scope link')
2703 output
= check_output('ip -4 route show dev dummy98')
2705 self
.assertRegex(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2706 output
= check_output('ip -6 route show default')
2708 self
.assertRegex(output
, 'via 2607:5300:203:39ff:ff:ff:ff:ff')
2710 def test_bind_carrier(self
):
2711 check_output('ip link add dummy98 type dummy')
2712 check_output('ip link set dummy98 up')
2715 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
2717 self
.wait_online(['test1:routable'])
2719 output
= check_output('ip address show test1')
2721 self
.assertRegex(output
, 'UP,LOWER_UP')
2722 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2723 self
.wait_operstate('test1', 'routable')
2725 check_output('ip link add dummy99 type dummy')
2726 check_output('ip link set dummy99 up')
2728 output
= check_output('ip address show test1')
2730 self
.assertRegex(output
, 'UP,LOWER_UP')
2731 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2732 self
.wait_operstate('test1', 'routable')
2734 check_output('ip link del dummy98')
2736 output
= check_output('ip address show test1')
2738 self
.assertRegex(output
, 'UP,LOWER_UP')
2739 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2740 self
.wait_operstate('test1', 'routable')
2742 check_output('ip link set dummy99 down')
2744 output
= check_output('ip address show test1')
2746 self
.assertNotRegex(output
, 'UP,LOWER_UP')
2747 self
.assertRegex(output
, 'DOWN')
2748 self
.assertNotRegex(output
, '192.168.10')
2749 self
.wait_operstate('test1', 'off')
2751 check_output('ip link set dummy99 up')
2753 output
= check_output('ip address show test1')
2755 self
.assertRegex(output
, 'UP,LOWER_UP')
2756 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2757 self
.wait_operstate('test1', 'routable')
2759 def _test_activation_policy(self
, test
):
2761 conffile
= '25-activation-policy.network'
2763 conffile
= f
'{conffile}.d/{test}.conf'
2764 copy_unit_to_networkd_unit_path('11-dummy.netdev', conffile
, dropins
=False)
2767 always
= test
.startswith('always')
2768 if test
== 'manual':
2769 initial_up
= 'UP' in check_output('ip link show test1')
2771 initial_up
= not test
.endswith('down') # note: default is up
2772 expect_up
= initial_up
2773 next_up
= not expect_up
2775 # if initial expected state is down, must wait for setup_state to reach configuring
2776 # so systemd-networkd considers it 'activated'
2777 setup_state
= None if initial_up
else 'configuring'
2779 for iteration
in range(4):
2780 with self
.subTest(iteration
=iteration
, expect_up
=expect_up
):
2781 operstate
= 'routable' if expect_up
else 'off'
2782 self
.wait_operstate('test1', operstate
, setup_state
=setup_state
, setup_timeout
=20)
2786 self
.assertIn('UP', check_output('ip link show test1'))
2787 self
.assertIn('192.168.10.30/24', check_output('ip address show test1'))
2788 self
.assertIn('default via 192.168.10.1', check_output('ip route show'))
2790 self
.assertIn('DOWN', check_output('ip link show test1'))
2793 check_output('ip link set dev test1 up')
2795 check_output('ip link set dev test1 down')
2796 expect_up
= initial_up
if always
else next_up
2797 next_up
= not next_up
2801 def test_activation_policy(self
):
2802 for test
in ['up', 'always-up', 'manual', 'always-down', 'down', '']:
2803 with self
.subTest(test
=test
):
2804 self
._test
_activation
_policy
(test
)
2806 def test_domain(self
):
2807 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
2809 self
.wait_online(['dummy98:routable'])
2811 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2813 self
.assertRegex(output
, 'Address: 192.168.42.100')
2814 self
.assertRegex(output
, 'DNS: 192.168.42.1')
2815 self
.assertRegex(output
, 'Search Domains: one')
2817 def test_keep_configuration_static(self
):
2818 check_output('systemctl stop systemd-networkd.socket')
2819 check_output('systemctl stop systemd-networkd.service')
2821 check_output('ip link add name dummy98 type dummy')
2822 check_output('ip address add 10.1.2.3/16 dev dummy98')
2823 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
2824 output
= check_output('ip address show dummy98')
2826 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2827 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2828 output
= check_output('ip route show dev dummy98')
2831 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
2833 self
.wait_online(['dummy98:routable'])
2835 output
= check_output('ip address show dummy98')
2837 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2838 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2840 @expectedFailureIfNexthopIsNotAvailable()
2841 def test_nexthop(self
):
2842 copy_unit_to_networkd_unit_path('25-nexthop.network', '25-veth.netdev', '25-veth-peer.network')
2844 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2846 output
= check_output('ip nexthop list dev veth99')
2848 self
.assertIn('id 1 via 192.168.5.1 dev veth99', output
)
2849 self
.assertIn('id 2 via 2001:1234:5:8f63::2 dev veth99', output
)
2850 self
.assertIn('id 3 dev veth99', output
)
2851 self
.assertIn('id 4 dev veth99', output
)
2852 self
.assertRegex(output
, 'id 5 via 192.168.10.1 dev veth99 .*onlink')
2853 self
.assertRegex(output
, r
'id [0-9]* via 192.168.5.2 dev veth99')
2855 # kernel manages blackhole nexthops on lo
2856 output
= check_output('ip nexthop list dev lo')
2858 self
.assertIn('id 6 blackhole', output
)
2859 self
.assertIn('id 7 blackhole', output
)
2861 output
= check_output('ip route show dev veth99 10.10.10.10')
2863 self
.assertEqual('10.10.10.10 nhid 1 via 192.168.5.1 proto static', output
)
2865 output
= check_output('ip route show dev veth99 10.10.10.11')
2867 self
.assertEqual('10.10.10.11 nhid 2 via inet6 2001:1234:5:8f63::2 proto static', output
)
2869 output
= check_output('ip route show dev veth99 10.10.10.12')
2871 self
.assertEqual('10.10.10.12 nhid 5 via 192.168.10.1 proto static onlink', output
)
2873 output
= check_output('ip -6 route show dev veth99 2001:1234:5:8f62::1')
2875 self
.assertEqual('2001:1234:5:8f62::1 nhid 2 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium', output
)
2877 output
= check_output('ip route show 10.10.10.13')
2879 self
.assertEqual('blackhole 10.10.10.13 nhid 6 dev lo proto static', output
)
2881 output
= check_output('ip -6 route show 2001:1234:5:8f62::2')
2883 self
.assertEqual('blackhole 2001:1234:5:8f62::2 nhid 7 dev lo proto static metric 1024 pref medium', output
)
2885 remove_unit_from_networkd_path(['25-nexthop.network'])
2886 copy_unit_to_networkd_unit_path('25-nexthop-nothing.network')
2887 rc
= call(*networkctl_cmd
, 'reload', env
=env
)
2888 self
.assertEqual(rc
, 0)
2891 output
= check_output('ip nexthop list dev veth99')
2893 self
.assertEqual(output
, '')
2894 output
= check_output('ip nexthop list dev lo')
2896 self
.assertEqual(output
, '')
2898 remove_unit_from_networkd_path(['25-nexthop-nothing.network'])
2899 copy_unit_to_networkd_unit_path('25-nexthop.network')
2900 rc
= call(*networkctl_cmd
, 'reload', env
=env
)
2901 self
.assertEqual(rc
, 0)
2904 rc
= call('ip link del veth99')
2905 self
.assertEqual(rc
, 0)
2908 output
= check_output('ip nexthop list dev lo')
2910 self
.assertEqual(output
, '')
2912 def test_qdisc(self
):
2913 copy_unit_to_networkd_unit_path('25-qdisc-clsact-and-htb.network', '12-dummy.netdev',
2914 '25-qdisc-ingress-netem-compat.network', '11-dummy.netdev')
2915 check_output('modprobe sch_teql max_equalizers=2')
2918 self
.wait_online(['dummy98:routable', 'test1:routable'])
2920 output
= check_output('tc qdisc show dev test1')
2922 self
.assertRegex(output
, 'qdisc netem')
2923 self
.assertRegex(output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
2924 self
.assertRegex(output
, 'qdisc ingress')
2926 output
= check_output('tc qdisc show dev dummy98')
2928 self
.assertRegex(output
, 'qdisc clsact')
2930 self
.assertRegex(output
, 'qdisc htb 2: root')
2931 self
.assertRegex(output
, r
'default (0x30|30)')
2933 self
.assertRegex(output
, 'qdisc netem 30: parent 2:30')
2934 self
.assertRegex(output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
2935 self
.assertRegex(output
, 'qdisc fq_codel')
2936 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')
2938 self
.assertRegex(output
, 'qdisc teql1 31: parent 2:31')
2940 self
.assertRegex(output
, 'qdisc fq 32: parent 2:32')
2941 self
.assertRegex(output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
2942 self
.assertRegex(output
, 'quantum 1500')
2943 self
.assertRegex(output
, 'initial_quantum 13000')
2944 self
.assertRegex(output
, 'maxrate 1Mbit')
2946 self
.assertRegex(output
, 'qdisc codel 33: parent 2:33')
2947 self
.assertRegex(output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn')
2949 self
.assertRegex(output
, 'qdisc fq_codel 34: parent 2:34')
2950 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')
2952 self
.assertRegex(output
, 'qdisc tbf 35: parent 2:35')
2953 self
.assertRegex(output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms')
2955 self
.assertRegex(output
, 'qdisc sfq 36: parent 2:36')
2956 self
.assertRegex(output
, 'perturb 5sec')
2958 self
.assertRegex(output
, 'qdisc pfifo 37: parent 2:37')
2959 self
.assertRegex(output
, 'limit 100000p')
2961 self
.assertRegex(output
, 'qdisc gred 38: parent 2:38')
2962 self
.assertRegex(output
, 'vqs 12 default 10 grio')
2964 self
.assertRegex(output
, 'qdisc sfb 39: parent 2:39')
2965 self
.assertRegex(output
, 'limit 200000')
2967 self
.assertRegex(output
, 'qdisc bfifo 3a: parent 2:3a')
2968 self
.assertRegex(output
, 'limit 1000000')
2970 self
.assertRegex(output
, 'qdisc pfifo_head_drop 3b: parent 2:3b')
2971 self
.assertRegex(output
, 'limit 1023p')
2973 self
.assertRegex(output
, 'qdisc pfifo_fast 3c: parent 2:3c')
2975 output
= check_output('tc -d class show dev dummy98')
2977 self
.assertRegex(output
, 'class htb 2:30 root leaf 30:')
2978 self
.assertRegex(output
, 'class htb 2:31 root leaf 31:')
2979 self
.assertRegex(output
, 'class htb 2:32 root leaf 32:')
2980 self
.assertRegex(output
, 'class htb 2:33 root leaf 33:')
2981 self
.assertRegex(output
, 'class htb 2:34 root leaf 34:')
2982 self
.assertRegex(output
, 'class htb 2:35 root leaf 35:')
2983 self
.assertRegex(output
, 'class htb 2:36 root leaf 36:')
2984 self
.assertRegex(output
, 'class htb 2:37 root leaf 37:')
2985 self
.assertRegex(output
, 'class htb 2:38 root leaf 38:')
2986 self
.assertRegex(output
, 'class htb 2:39 root leaf 39:')
2987 self
.assertRegex(output
, 'class htb 2:3a root leaf 3a:')
2988 self
.assertRegex(output
, 'class htb 2:3b root leaf 3b:')
2989 self
.assertRegex(output
, 'class htb 2:3c root leaf 3c:')
2990 self
.assertRegex(output
, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit')
2991 self
.assertRegex(output
, 'burst 123456')
2992 self
.assertRegex(output
, 'cburst 123457')
2994 def test_qdisc2(self
):
2995 copy_unit_to_networkd_unit_path('25-qdisc-drr.network', '12-dummy.netdev',
2996 '25-qdisc-qfq.network', '11-dummy.netdev')
2999 self
.wait_online(['dummy98:routable', 'test1:routable'])
3001 output
= check_output('tc qdisc show dev dummy98')
3003 self
.assertRegex(output
, 'qdisc drr 2: root')
3004 output
= check_output('tc class show dev dummy98')
3006 self
.assertRegex(output
, 'class drr 2:30 root quantum 2000b')
3008 output
= check_output('tc qdisc show dev test1')
3010 self
.assertRegex(output
, 'qdisc qfq 2: root')
3011 output
= check_output('tc class show dev test1')
3013 self
.assertRegex(output
, 'class qfq 2:30 root weight 2 maxpkt 16000')
3014 self
.assertRegex(output
, 'class qfq 2:31 root weight 10 maxpkt 8000')
3016 @expectedFailureIfCAKEIsNotAvailable()
3017 def test_qdisc_cake(self
):
3018 copy_unit_to_networkd_unit_path('25-qdisc-cake.network', '12-dummy.netdev')
3020 self
.wait_online(['dummy98:routable'])
3022 output
= check_output('tc qdisc show dev dummy98')
3024 self
.assertRegex(output
, 'qdisc cake 3a: root')
3025 self
.assertRegex(output
, 'bandwidth 500Mbit')
3026 self
.assertRegex(output
, 'overhead 128')
3028 @expectedFailureIfPIEIsNotAvailable()
3029 def test_qdisc_pie(self
):
3030 copy_unit_to_networkd_unit_path('25-qdisc-pie.network', '12-dummy.netdev')
3032 self
.wait_online(['dummy98:routable'])
3034 output
= check_output('tc qdisc show dev dummy98')
3036 self
.assertRegex(output
, 'qdisc pie 3a: root')
3037 self
.assertRegex(output
, 'limit 200000')
3039 @expectedFailureIfHHFIsNotAvailable()
3040 def test_qdisc_hhf(self
):
3041 copy_unit_to_networkd_unit_path('25-qdisc-hhf.network', '12-dummy.netdev')
3043 self
.wait_online(['dummy98:routable'])
3045 output
= check_output('tc qdisc show dev dummy98')
3047 self
.assertRegex(output
, 'qdisc hhf 3a: root')
3048 self
.assertRegex(output
, 'limit 1022p')
3050 @expectedFailureIfETSIsNotAvailable()
3051 def test_qdisc_ets(self
):
3052 copy_unit_to_networkd_unit_path('25-qdisc-ets.network', '12-dummy.netdev')
3054 self
.wait_online(['dummy98:routable'])
3056 output
= check_output('tc qdisc show dev dummy98')
3059 self
.assertRegex(output
, 'qdisc ets 3a: root')
3060 self
.assertRegex(output
, 'bands 10 strict 3')
3061 self
.assertRegex(output
, 'quanta 1 2 3 4 5')
3062 self
.assertRegex(output
, 'priomap 3 4 5 6 7')
3064 @expectedFailureIfFQPIEIsNotAvailable()
3065 def test_qdisc_fq_pie(self
):
3066 copy_unit_to_networkd_unit_path('25-qdisc-fq_pie.network', '12-dummy.netdev')
3068 self
.wait_online(['dummy98:routable'])
3070 output
= check_output('tc qdisc show dev dummy98')
3073 self
.assertRegex(output
, 'qdisc fq_pie 3a: root')
3074 self
.assertRegex(output
, 'limit 200000p')
3076 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable()
3077 def test_sriov(self
):
3078 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
3079 call('modprobe netdevsim', stderr
=subprocess
.DEVNULL
)
3080 with
open('/sys/bus/netdevsim/new_device', mode
='w') as f
:
3083 call('udevadm settle')
3084 call('udevadm info -w10s /sys/devices/netdevsim99/net/eni99np1', stderr
=subprocess
.DEVNULL
)
3085 with
open('/sys/class/net/eni99np1/device/sriov_numvfs', mode
='w') as f
:
3088 copy_unit_to_networkd_unit_path('25-sriov.network')
3090 self
.wait_online(['eni99np1:routable'])
3092 output
= check_output('ip link show dev eni99np1')
3094 self
.assertRegex(output
,
3095 '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 *'
3096 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
3097 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
3100 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
3102 class NetworkdStateFileTests(unittest
.TestCase
, Utilities
):
3109 'state-file-tests.network',
3113 remove_links(self
.links
)
3114 stop_networkd(show_logs
=False)
3117 remove_links(self
.links
)
3118 remove_unit_from_networkd_path(self
.units
)
3119 stop_networkd(show_logs
=True)
3121 def test_state_file(self
):
3122 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'state-file-tests.network')
3124 self
.wait_online(['dummy98:routable'])
3126 output
= check_output(*networkctl_cmd
, '--no-legend', 'list', 'dummy98', env
=env
)
3128 ifindex
= output
.split()[0]
3130 path
= os
.path
.join('/run/systemd/netif/links/', ifindex
)
3131 self
.assertTrue(os
.path
.exists(path
))
3133 # make link state file updated
3134 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
3136 with
open(path
) as f
:
3138 self
.assertRegex(data
, r
'ADMIN_STATE=configured')
3139 self
.assertRegex(data
, r
'OPER_STATE=routable')
3140 self
.assertRegex(data
, r
'REQUIRED_FOR_ONLINE=yes')
3141 self
.assertRegex(data
, r
'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
3142 self
.assertRegex(data
, r
'ACTIVATION_POLICY=up')
3143 self
.assertRegex(data
, r
'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
3144 self
.assertRegex(data
, r
'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
3145 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
3146 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
3147 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
3148 self
.assertRegex(data
, r
'LLMNR=no')
3149 self
.assertRegex(data
, r
'MDNS=yes')
3150 self
.assertRegex(data
, r
'DNSSEC=no')
3152 check_output(*resolvectl_cmd
, 'dns', 'dummy98', '10.10.10.12#ccc.com', '10.10.10.13', '1111:2222::3333', env
=env
)
3153 check_output(*resolvectl_cmd
, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env
=env
)
3154 check_output(*resolvectl_cmd
, 'llmnr', 'dummy98', 'yes', env
=env
)
3155 check_output(*resolvectl_cmd
, 'mdns', 'dummy98', 'no', env
=env
)
3156 check_output(*resolvectl_cmd
, 'dnssec', 'dummy98', 'yes', env
=env
)
3157 check_output(*timedatectl_cmd
, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env
=env
)
3159 with
open(path
) as f
:
3161 self
.assertRegex(data
, r
'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333')
3162 self
.assertRegex(data
, r
'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org')
3163 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
3164 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
3165 self
.assertRegex(data
, r
'LLMNR=yes')
3166 self
.assertRegex(data
, r
'MDNS=no')
3167 self
.assertRegex(data
, r
'DNSSEC=yes')
3169 check_output(*timedatectl_cmd
, 'revert', 'dummy98', env
=env
)
3171 with
open(path
) as f
:
3173 self
.assertRegex(data
, r
'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333')
3174 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
3175 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
3176 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
3177 self
.assertRegex(data
, r
'LLMNR=yes')
3178 self
.assertRegex(data
, r
'MDNS=no')
3179 self
.assertRegex(data
, r
'DNSSEC=yes')
3181 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
3183 with
open(path
) as f
:
3185 self
.assertRegex(data
, r
'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
3186 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
3187 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
3188 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
3189 self
.assertRegex(data
, r
'LLMNR=no')
3190 self
.assertRegex(data
, r
'MDNS=yes')
3191 self
.assertRegex(data
, r
'DNSSEC=no')
3193 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
3203 '23-active-slave.network',
3204 '23-bond199.network',
3205 '23-primary-slave.network',
3206 '25-bond-active-backup-slave.netdev',
3209 'bond-slave.network']
3212 remove_links(self
.links
)
3213 stop_networkd(show_logs
=False)
3216 remove_links(self
.links
)
3217 remove_unit_from_networkd_path(self
.units
)
3218 stop_networkd(show_logs
=True)
3220 def test_bond_active_slave(self
):
3221 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
3223 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
3225 output
= check_output('ip -d link show bond199')
3227 self
.assertRegex(output
, 'active_slave dummy98')
3229 def test_bond_primary_slave(self
):
3230 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
3232 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
3234 output
= check_output('ip -d link show bond199')
3236 self
.assertRegex(output
, 'primary dummy98')
3238 def test_bond_operstate(self
):
3239 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
3240 'bond99.network','bond-slave.network')
3242 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
3244 output
= check_output('ip -d link show dummy98')
3246 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
3248 output
= check_output('ip -d link show test1')
3250 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
3252 output
= check_output('ip -d link show bond99')
3254 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
3256 self
.wait_operstate('dummy98', 'enslaved')
3257 self
.wait_operstate('test1', 'enslaved')
3258 self
.wait_operstate('bond99', 'routable')
3260 check_output('ip link set dummy98 down')
3262 self
.wait_operstate('dummy98', 'off')
3263 self
.wait_operstate('test1', 'enslaved')
3264 self
.wait_operstate('bond99', 'degraded-carrier')
3266 check_output('ip link set dummy98 up')
3268 self
.wait_operstate('dummy98', 'enslaved')
3269 self
.wait_operstate('test1', 'enslaved')
3270 self
.wait_operstate('bond99', 'routable')
3272 check_output('ip link set dummy98 down')
3273 check_output('ip link set test1 down')
3275 self
.wait_operstate('dummy98', 'off')
3276 self
.wait_operstate('test1', 'off')
3278 if not self
.wait_operstate('bond99', 'no-carrier', setup_timeout
=30, fail_assert
=False):
3279 # Huh? Kernel does not recognize that all slave interfaces are down?
3280 # Let's confirm that networkd's operstate is consistent with ip's result.
3281 self
.assertNotRegex(output
, 'NO-CARRIER')
3283 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
3293 '26-bridge-configure-without-carrier.network',
3294 '26-bridge-mdb-master.network',
3295 '26-bridge-mdb-slave.network',
3296 '26-bridge-slave-interface-1.network',
3297 '26-bridge-slave-interface-2.network',
3298 '26-bridge-vlan-master.network',
3299 '26-bridge-vlan-slave.network',
3300 'bridge99-ignore-carrier-loss.network',
3303 routing_policy_rule_tables
= ['100']
3306 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
3307 remove_links(self
.links
)
3308 stop_networkd(show_logs
=False)
3311 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
3312 remove_links(self
.links
)
3313 remove_unit_from_networkd_path(self
.units
)
3314 stop_networkd(show_logs
=True)
3316 def test_bridge_vlan(self
):
3317 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
3318 '26-bridge.netdev', '26-bridge-vlan-master.network')
3320 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
3322 output
= check_output('bridge vlan show dev test1')
3324 self
.assertNotRegex(output
, '4063')
3325 for i
in range(4064, 4095):
3326 self
.assertRegex(output
, f
'{i}')
3327 self
.assertNotRegex(output
, '4095')
3329 output
= check_output('bridge vlan show dev bridge99')
3331 self
.assertNotRegex(output
, '4059')
3332 for i
in range(4060, 4095):
3333 self
.assertRegex(output
, f
'{i}')
3334 self
.assertNotRegex(output
, '4095')
3336 def test_bridge_mdb(self
):
3337 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-mdb-slave.network',
3338 '26-bridge.netdev', '26-bridge-mdb-master.network')
3340 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
3342 output
= check_output('bridge mdb show dev bridge99')
3344 self
.assertRegex(output
, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064')
3345 self
.assertRegex(output
, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065')
3347 # Old kernel may not support bridge MDB entries on bridge master
3348 if call('bridge mdb add dev bridge99 port bridge99 grp 224.0.1.3 temp vid 4068', stderr
=subprocess
.DEVNULL
) == 0:
3349 self
.assertRegex(output
, 'dev bridge99 port bridge99 grp ff02:aaaa:fee5::1:4 temp *vid 4066')
3350 self
.assertRegex(output
, 'dev bridge99 port bridge99 grp 224.0.1.2 temp *vid 4067')
3352 def test_bridge_property(self
):
3353 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
3354 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
3357 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
3359 output
= check_output('ip -d link show test1')
3361 self
.assertRegex(output
, 'master')
3362 self
.assertRegex(output
, 'bridge')
3364 output
= check_output('ip -d link show dummy98')
3366 self
.assertRegex(output
, 'master')
3367 self
.assertRegex(output
, 'bridge')
3369 output
= check_output('ip addr show bridge99')
3371 self
.assertRegex(output
, '192.168.0.15/24')
3373 output
= check_output('bridge -d link show dummy98')
3375 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
3376 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
3377 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
3378 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
3379 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
3380 # CONFIG_BRIDGE_IGMP_SNOOPING=y
3381 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
3382 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
3383 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
3384 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
3385 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
3386 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'priority'), '23')
3387 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard'), '1')
3388 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'root_block'), '1')
3390 output
= check_output('bridge -d link show test1')
3392 self
.assertEqual(read_bridge_port_attr('bridge99', 'test1', 'priority'), '0')
3394 check_output('ip address add 192.168.0.16/24 dev bridge99')
3397 output
= check_output('ip addr show bridge99')
3399 self
.assertRegex(output
, '192.168.0.16/24')
3402 print('### ip -6 route list table all dev bridge99')
3403 output
= check_output('ip -6 route list table all dev bridge99')
3405 self
.assertRegex(output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
3407 self
.assertEqual(call('ip link del test1'), 0)
3409 self
.wait_operstate('bridge99', 'degraded-carrier')
3411 check_output('ip link del dummy98')
3413 self
.wait_operstate('bridge99', 'no-carrier')
3415 output
= check_output('ip address show bridge99')
3417 self
.assertRegex(output
, 'NO-CARRIER')
3418 self
.assertNotRegex(output
, '192.168.0.15/24')
3419 self
.assertNotRegex(output
, '192.168.0.16/24')
3421 print('### ip -6 route list table all dev bridge99')
3422 output
= check_output('ip -6 route list table all dev bridge99')
3424 self
.assertRegex(output
, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
3426 def test_bridge_configure_without_carrier(self
):
3427 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-configure-without-carrier.network',
3431 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
3432 for test
in ['no-slave', 'add-slave', 'slave-up', 'slave-no-carrier', 'slave-carrier', 'slave-down']:
3433 with self
.subTest(test
=test
):
3434 if test
== 'no-slave':
3435 # bridge has no slaves; it's up but *might* not have carrier
3436 self
.wait_operstate('bridge99', operstate
=r
'(no-carrier|routable)', setup_state
=None, setup_timeout
=30)
3437 # due to a bug in the kernel, newly-created bridges are brought up
3438 # *with* carrier, unless they have had any setting changed; e.g.
3439 # their mac set, priority set, etc. Then, they will lose carrier
3440 # as soon as a (down) slave interface is added, and regain carrier
3441 # again once the slave interface is brought up.
3442 #self.check_link_attr('bridge99', 'carrier', '0')
3443 elif test
== 'add-slave':
3444 # add slave to bridge, but leave it down; bridge is definitely no-carrier
3445 self
.check_link_attr('test1', 'operstate', 'down')
3446 check_output('ip link set dev test1 master bridge99')
3447 self
.wait_operstate('bridge99', operstate
='no-carrier', setup_state
=None)
3448 self
.check_link_attr('bridge99', 'carrier', '0')
3449 elif test
== 'slave-up':
3450 # bring up slave, which will have carrier; bridge gains carrier
3451 check_output('ip link set dev test1 up')
3452 self
.wait_online(['bridge99:routable'])
3453 self
.check_link_attr('bridge99', 'carrier', '1')
3454 elif test
== 'slave-no-carrier':
3455 # drop slave carrier; bridge loses carrier
3456 check_output('ip link set dev test1 carrier off')
3457 self
.wait_online(['bridge99:no-carrier:no-carrier'])
3458 self
.check_link_attr('bridge99', 'carrier', '0')
3459 elif test
== 'slave-carrier':
3460 # restore slave carrier; bridge gains carrier
3461 check_output('ip link set dev test1 carrier on')
3462 self
.wait_online(['bridge99:routable'])
3463 self
.check_link_attr('bridge99', 'carrier', '1')
3464 elif test
== 'slave-down':
3465 # bring down slave; bridge loses carrier
3466 check_output('ip link set dev test1 down')
3467 self
.wait_online(['bridge99:no-carrier:no-carrier'])
3468 self
.check_link_attr('bridge99', 'carrier', '0')
3470 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
3471 self
.assertRegex(output
, '10.1.2.3')
3472 self
.assertRegex(output
, '10.1.2.1')
3474 def test_bridge_ignore_carrier_loss(self
):
3475 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
3476 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
3477 'bridge99-ignore-carrier-loss.network')
3479 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
3481 check_output('ip address add 192.168.0.16/24 dev bridge99')
3484 check_output('ip link del test1')
3485 check_output('ip link del dummy98')
3488 output
= check_output('ip address show bridge99')
3490 self
.assertRegex(output
, 'NO-CARRIER')
3491 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
3492 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
3494 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
3495 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
3496 'bridge99-ignore-carrier-loss.network')
3498 self
.wait_online(['bridge99:no-carrier'])
3500 for trial
in range(4):
3501 check_output('ip link add dummy98 type dummy')
3502 check_output('ip link set dummy98 up')
3504 check_output('ip link del dummy98')
3506 self
.wait_online(['bridge99:routable', 'dummy98:enslaved'])
3508 output
= check_output('ip address show bridge99')
3510 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
3512 output
= check_output('ip rule list table 100')
3514 self
.assertIn('0: from all to 8.8.8.8 lookup 100', output
)
3516 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
3520 '23-emit-lldp.network',
3525 remove_links(self
.links
)
3526 stop_networkd(show_logs
=False)
3529 remove_links(self
.links
)
3530 remove_unit_from_networkd_path(self
.units
)
3531 stop_networkd(show_logs
=True)
3533 def test_lldp(self
):
3534 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
3536 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
3538 for trial
in range(10):
3542 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
3544 if re
.search(r
'veth99 .* veth-peer', output
):
3549 class NetworkdRATests(unittest
.TestCase
, Utilities
):
3554 'ipv6-prefix.network',
3555 'ipv6-prefix-veth.network',
3556 'ipv6-prefix-veth-token-static.network',
3557 'ipv6-prefix-veth-token-prefixstable.network',
3558 'ipv6-prefix-veth-token-prefixstable-without-address.network']
3561 remove_links(self
.links
)
3562 stop_networkd(show_logs
=False)
3565 remove_links(self
.links
)
3566 remove_unit_from_networkd_path(self
.units
)
3567 stop_networkd(show_logs
=True)
3569 def test_ipv6_prefix_delegation(self
):
3570 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
3572 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3574 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3576 self
.assertRegex(output
, 'fe80::')
3577 self
.assertRegex(output
, '2002:da8:1::1')
3579 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
3581 self
.assertIn('hogehoge.test', output
)
3583 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3585 self
.assertRegex(output
, '2002:da8:1:0')
3587 def test_ipv6_token_static(self
):
3588 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static.network')
3590 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3592 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3594 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
3595 self
.assertRegex(output
, '2002:da8:1:0:fa:de:ca:fe')
3596 self
.assertRegex(output
, '2002:da8:2:0:1a:2b:3c:4d')
3597 self
.assertRegex(output
, '2002:da8:2:0:fa:de:ca:fe')
3599 def test_ipv6_token_prefixstable(self
):
3600 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable.network')
3602 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3604 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3606 self
.assertRegex(output
, '2002:da8:1:0')
3607 self
.assertRegex(output
, '2002:da8:2:0.*78:9abc') # EUI
3609 def test_ipv6_token_prefixstable_without_address(self
):
3610 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable-without-address.network')
3612 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3614 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3616 self
.assertRegex(output
, '2002:da8:1:0')
3617 self
.assertRegex(output
, '2002:da8:2:0')
3619 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
3624 'dhcp-client.network',
3625 'dhcp-client-timezone-router.network',
3626 'dhcp-server.network',
3627 'dhcp-server-timezone-router.network']
3630 remove_links(self
.links
)
3631 stop_networkd(show_logs
=False)
3634 remove_links(self
.links
)
3635 remove_unit_from_networkd_path(self
.units
)
3636 stop_networkd(show_logs
=True)
3638 def test_dhcp_server(self
):
3639 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
3641 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3643 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3645 self
.assertRegex(output
, '192.168.5.*')
3646 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
3647 self
.assertRegex(output
, 'DNS: 192.168.5.1')
3648 self
.assertRegex(output
, 'NTP: 192.168.5.1')
3650 def test_emit_router_timezone(self
):
3651 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
3653 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3655 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3657 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
3658 self
.assertRegex(output
, '192.168.5.*')
3659 self
.assertRegex(output
, 'Europe/Berlin')
3661 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
3670 'dhcp-client-anonymize.network',
3671 'dhcp-client-decline.network',
3672 'dhcp-client-gateway-ipv4.network',
3673 'dhcp-client-gateway-ipv6.network',
3674 'dhcp-client-gateway-onlink-implicit.network',
3675 'dhcp-client-ipv4-dhcp-settings.network',
3676 'dhcp-client-ipv4-only-ipv6-disabled.network',
3677 'dhcp-client-ipv4-only.network',
3678 'dhcp-client-ipv4-use-routes-use-gateway.network',
3679 'dhcp-client-ipv6-only.network',
3680 'dhcp-client-ipv6-rapid-commit.network',
3681 'dhcp-client-keep-configuration-dhcp-on-stop.network',
3682 'dhcp-client-keep-configuration-dhcp.network',
3683 'dhcp-client-listen-port.network',
3684 'dhcp-client-reassign-static-routes-ipv4.network',
3685 'dhcp-client-reassign-static-routes-ipv6.network',
3686 'dhcp-client-route-metric.network',
3687 'dhcp-client-route-table.network',
3688 'dhcp-client-use-dns-ipv4-and-ra.network',
3689 'dhcp-client-use-dns-ipv4.network',
3690 'dhcp-client-use-dns-no.network',
3691 'dhcp-client-use-dns-yes.network',
3692 'dhcp-client-use-domains.network',
3693 'dhcp-client-vrf.network',
3694 'dhcp-client-with-ipv4ll.network',
3695 'dhcp-client-with-static-address.network',
3696 'dhcp-client.network',
3697 'dhcp-server-decline.network',
3698 'dhcp-server-veth-peer.network',
3699 'dhcp-v4-server-veth-peer.network',
3703 stop_dnsmasq(dnsmasq_pid_file
)
3704 remove_links(self
.links
)
3705 stop_networkd(show_logs
=False)
3708 stop_dnsmasq(dnsmasq_pid_file
)
3711 remove_links(self
.links
)
3712 remove_unit_from_networkd_path(self
.units
)
3713 stop_networkd(show_logs
=True)
3715 def test_dhcp_client_ipv6_only(self
):
3716 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3719 self
.wait_online(['veth-peer:carrier'])
3721 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3723 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3725 self
.assertRegex(output
, '2600::')
3726 self
.assertNotRegex(output
, '192.168.5')
3728 output
= check_output('ip addr show dev veth99')
3730 self
.assertRegex(output
, '2600::')
3731 self
.assertNotRegex(output
, '192.168.5')
3732 self
.assertNotRegex(output
, 'tentative')
3734 # Confirm that ipv6 token is not set in the kernel
3735 output
= check_output('ip token show dev veth99')
3737 self
.assertRegex(output
, 'token :: dev veth99')
3739 def test_dhcp_client_ipv4_only(self
):
3740 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
3743 self
.wait_online(['veth-peer:carrier'])
3744 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
3745 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3747 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3749 self
.assertNotRegex(output
, '2600::')
3750 self
.assertRegex(output
, '192.168.5')
3751 self
.assertRegex(output
, '192.168.5.6')
3752 self
.assertRegex(output
, '192.168.5.7')
3754 # checking routes to DNS servers
3755 output
= check_output('ip route show dev veth99')
3757 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3758 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3759 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3761 stop_dnsmasq(dnsmasq_pid_file
)
3762 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8', lease_time
='2m')
3764 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3765 print('Wait for the dynamic address to be renewed')
3768 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3770 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3772 self
.assertNotRegex(output
, '2600::')
3773 self
.assertRegex(output
, '192.168.5')
3774 self
.assertNotRegex(output
, '192.168.5.6')
3775 self
.assertRegex(output
, '192.168.5.7')
3776 self
.assertRegex(output
, '192.168.5.8')
3778 # checking routes to DNS servers
3779 output
= check_output('ip route show dev veth99')
3781 self
.assertNotRegex(output
, r
'192.168.5.6')
3782 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3783 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3784 self
.assertRegex(output
, r
'192.168.5.8 proto dhcp scope link src 192.168.5.181 metric 1024')
3786 def test_dhcp_client_ipv4_use_routes_gateway(self
):
3787 for (routes
, gateway
, dnsroutes
) in itertools
.product([True, False, None], repeat
=3):
3789 with self
.subTest(routes
=routes
, gateway
=gateway
, dnsroutes
=dnsroutes
):
3790 self
._test
_dhcp
_client
_ipv
4_use
_routes
_gateway
(routes
, gateway
, dnsroutes
)
3793 def _test_dhcp_client_ipv4_use_routes_gateway(self
, routes
, gateway
, dnsroutes
):
3794 testunit
= 'dhcp-client-ipv4-use-routes-use-gateway.network'
3795 testunits
= ['25-veth.netdev', 'dhcp-server-veth-peer.network', testunit
]
3797 testunits
.append(f
'{testunit}.d/use-routes-{routes}.conf');
3799 testunits
.append(f
'{testunit}.d/use-gateway-{gateway}.conf');
3800 if dnsroutes
!= None:
3801 testunits
.append(f
'{testunit}.d/use-dns-routes-{dnsroutes}.conf');
3802 copy_unit_to_networkd_unit_path(*testunits
, dropins
=False)
3805 self
.wait_online(['veth-peer:carrier'])
3806 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
3807 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3809 output
= check_output('ip route show dev veth99')
3812 # UseRoutes= defaults to true
3813 useroutes
= routes
in [True, None]
3814 # UseGateway= defaults to useroutes
3815 usegateway
= useroutes
if gateway
== None else gateway
3819 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.181 metric 1024')
3821 self
.assertNotRegex(output
, r
'192.168.5.5')
3825 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.181 metric 1024')
3827 self
.assertNotRegex(output
, r
'default via 192.168.5.1')
3829 # Check RoutesToDNS=, which defaults to false
3831 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3832 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3834 self
.assertNotRegex(output
, r
'192.168.5.6')
3835 self
.assertNotRegex(output
, r
'192.168.5.7')
3837 def test_dhcp_client_ipv4_ipv6(self
):
3838 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
3839 'dhcp-client-ipv4-only.network')
3841 self
.wait_online(['veth-peer:carrier'])
3843 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3845 # link become 'routable' when at least one protocol provide an valid address.
3846 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3847 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3849 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3851 self
.assertRegex(output
, '2600::')
3852 self
.assertRegex(output
, '192.168.5')
3854 def test_dhcp_client_settings(self
):
3855 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
3858 self
.wait_online(['veth-peer:carrier'])
3860 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3862 print('## ip address show dev veth99')
3863 output
= check_output('ip address show dev veth99')
3865 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3866 self
.assertRegex(output
, '192.168.5')
3867 self
.assertRegex(output
, '1492')
3869 print('## ip route show table main dev veth99')
3870 output
= check_output('ip route show table main dev veth99')
3873 main_table_is_empty
= output
== ''
3874 if not main_table_is_empty
:
3875 self
.assertNotRegex(output
, 'proto dhcp')
3877 print('## ip route show table 211 dev veth99')
3878 output
= check_output('ip route show table 211 dev veth99')
3880 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
3881 if main_table_is_empty
:
3882 self
.assertRegex(output
, '192.168.5.0/24 proto dhcp')
3883 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
3884 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
3886 print('## dnsmasq log')
3887 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
3888 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
3889 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
3890 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
3892 def test_dhcp6_client_settings_rapidcommit_true(self
):
3893 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3895 self
.wait_online(['veth-peer:carrier'])
3897 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3899 output
= check_output('ip address show dev veth99')
3901 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3902 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
3904 def test_dhcp6_client_settings_rapidcommit_false(self
):
3905 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
3907 self
.wait_online(['veth-peer:carrier'])
3909 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3911 output
= check_output('ip address show dev veth99')
3913 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3914 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
3916 def test_dhcp_client_settings_anonymize(self
):
3917 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
3919 self
.wait_online(['veth-peer:carrier'])
3921 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3923 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
3924 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
3925 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
3927 def test_dhcp_client_listen_port(self
):
3928 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
3930 self
.wait_online(['veth-peer:carrier'])
3931 start_dnsmasq('--dhcp-alternate-port=67,5555')
3932 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3934 output
= check_output('ip -4 address show dev veth99')
3936 self
.assertRegex(output
, '192.168.5.* dynamic')
3938 def test_dhcp_client_with_static_address(self
):
3939 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
3940 'dhcp-client-with-static-address.network')
3942 self
.wait_online(['veth-peer:carrier'])
3944 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3946 output
= check_output('ip address show dev veth99 scope global')
3948 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
3949 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
3951 output
= check_output('ip route show dev veth99')
3953 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
3954 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
3955 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
3956 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
3958 def test_dhcp_route_table_id(self
):
3959 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
3961 self
.wait_online(['veth-peer:carrier'])
3963 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3965 output
= check_output('ip route show table 12')
3967 self
.assertRegex(output
, 'veth99 proto dhcp')
3968 self
.assertRegex(output
, '192.168.5.1')
3970 def test_dhcp_route_metric(self
):
3971 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
3973 self
.wait_online(['veth-peer:carrier'])
3975 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3977 output
= check_output('ip route show dev veth99')
3979 self
.assertRegex(output
, 'metric 24')
3981 def test_dhcp_client_reassign_static_routes_ipv4(self
):
3982 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3983 'dhcp-client-reassign-static-routes-ipv4.network')
3985 self
.wait_online(['veth-peer:carrier'])
3986 start_dnsmasq(lease_time
='2m')
3987 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3989 output
= check_output('ip address show dev veth99 scope global')
3991 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3993 output
= check_output('ip route show dev veth99')
3995 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3996 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3997 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3998 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
4000 stop_dnsmasq(dnsmasq_pid_file
)
4001 start_dnsmasq(ipv4_range
='192.168.5.210,192.168.5.220', lease_time
='2m')
4003 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4004 print('Wait for the dynamic address to be renewed')
4007 self
.wait_online(['veth99:routable'])
4009 output
= check_output('ip route show dev veth99')
4011 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
4012 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
4013 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
4014 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
4016 def test_dhcp_client_reassign_static_routes_ipv6(self
):
4017 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4018 'dhcp-client-reassign-static-routes-ipv6.network')
4020 self
.wait_online(['veth-peer:carrier'])
4021 start_dnsmasq(lease_time
='2m')
4022 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4024 output
= check_output('ip address show dev veth99 scope global')
4026 self
.assertRegex(output
, r
'inet6 2600::[0-9a-f]*/128 scope global (noprefixroute dynamic|dynamic noprefixroute)')
4028 output
= check_output('ip -6 route show dev veth99')
4030 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
4031 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
4033 stop_dnsmasq(dnsmasq_pid_file
)
4034 start_dnsmasq(ipv6_range
='2600::30,2600::40', lease_time
='2m')
4036 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4037 print('Wait for the dynamic address to be renewed')
4040 self
.wait_online(['veth99:routable'])
4042 output
= check_output('ip -6 route show dev veth99')
4044 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
4045 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
4047 def test_dhcp_keep_configuration_dhcp(self
):
4048 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
4050 self
.wait_online(['veth-peer:carrier'])
4051 start_dnsmasq(lease_time
='2m')
4052 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4054 output
= check_output('ip address show dev veth99 scope global')
4056 self
.assertRegex(output
, r
'192.168.5.*')
4058 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4060 self
.assertRegex(output
, r
'192.168.5.*')
4062 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
4063 stop_dnsmasq(dnsmasq_pid_file
)
4065 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4066 print('Wait for the dynamic address to be expired')
4069 print('The lease address should be kept after lease expired')
4070 output
= check_output('ip address show dev veth99 scope global')
4072 self
.assertRegex(output
, r
'192.168.5.*')
4074 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4076 self
.assertRegex(output
, r
'192.168.5.*')
4078 check_output('systemctl stop systemd-networkd.socket')
4079 check_output('systemctl stop systemd-networkd.service')
4081 print('The lease address should be kept after networkd stopped')
4082 output
= check_output('ip address show dev veth99 scope global')
4084 self
.assertRegex(output
, r
'192.168.5.*')
4086 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4088 self
.assertRegex(output
, r
'192.168.5.*')
4091 self
.wait_online(['veth-peer:routable'])
4093 print('Still the lease address should be kept after networkd restarted')
4094 output
= check_output('ip address show dev veth99 scope global')
4096 self
.assertRegex(output
, r
'192.168.5.*')
4098 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4100 self
.assertRegex(output
, r
'192.168.5.*')
4102 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
4103 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
4105 self
.wait_online(['veth-peer:carrier'])
4106 start_dnsmasq(lease_time
='2m')
4107 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4109 output
= check_output('ip address show dev veth99 scope global')
4111 self
.assertRegex(output
, r
'192.168.5.*')
4113 stop_dnsmasq(dnsmasq_pid_file
)
4114 check_output('systemctl stop systemd-networkd.socket')
4115 check_output('systemctl stop systemd-networkd.service')
4117 output
= check_output('ip address show dev veth99 scope global')
4119 self
.assertRegex(output
, r
'192.168.5.*')
4122 self
.wait_online(['veth-peer:routable'])
4124 output
= check_output('ip address show dev veth99 scope global')
4126 self
.assertNotRegex(output
, r
'192.168.5.*')
4128 def test_dhcp_client_reuse_address_as_static(self
):
4129 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
4131 self
.wait_online(['veth-peer:carrier'])
4133 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4135 # link become 'routable' when at least one protocol provide an valid address.
4136 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4137 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4139 output
= check_output('ip address show dev veth99 scope global')
4141 self
.assertRegex(output
, '192.168.5')
4142 self
.assertRegex(output
, '2600::')
4144 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
4145 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
4146 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
4147 print(static_network
)
4149 remove_unit_from_networkd_path(['dhcp-client.network'])
4151 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
4152 f
.write(static_network
)
4154 # When networkd started, the links are already configured, so let's wait for 5 seconds
4155 # the links to be re-configured.
4157 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4159 output
= check_output('ip -4 address show dev veth99 scope global')
4161 self
.assertRegex(output
, '192.168.5')
4162 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
4164 output
= check_output('ip -6 address show dev veth99 scope global')
4166 self
.assertRegex(output
, '2600::')
4167 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
4169 @expectedFailureIfModuleIsNotAvailable('vrf')
4170 def test_dhcp_client_vrf(self
):
4171 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
4172 '25-vrf.netdev', '25-vrf.network')
4174 self
.wait_online(['veth-peer:carrier'])
4176 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
4178 # link become 'routable' when at least one protocol provide an valid address.
4179 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4180 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4182 print('## ip -d link show dev vrf99')
4183 output
= check_output('ip -d link show dev vrf99')
4185 self
.assertRegex(output
, 'vrf table 42')
4187 print('## ip address show vrf vrf99')
4188 output
= check_output('ip address show vrf vrf99')
4190 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
4191 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
4192 self
.assertRegex(output
, 'inet6 .* scope link')
4194 print('## ip address show dev veth99')
4195 output
= check_output('ip address show dev veth99')
4197 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
4198 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
4199 self
.assertRegex(output
, 'inet6 .* scope link')
4201 print('## ip route show vrf vrf99')
4202 output
= check_output('ip route show vrf vrf99')
4204 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
4205 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
4206 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
4207 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
4209 print('## ip route show table main dev veth99')
4210 output
= check_output('ip route show table main dev veth99')
4212 self
.assertEqual(output
, '')
4214 def test_dhcp_client_gateway_ipv4(self
):
4215 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4216 'dhcp-client-gateway-ipv4.network')
4218 self
.wait_online(['veth-peer:carrier'])
4220 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4222 output
= check_output('ip route list dev veth99 10.0.0.0/8')
4224 self
.assertRegex(output
, '10.0.0.0/8 via 192.168.5.1 proto dhcp')
4226 def test_dhcp_client_gateway_ipv6(self
):
4227 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4228 'dhcp-client-gateway-ipv6.network')
4230 self
.wait_online(['veth-peer:carrier'])
4232 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4234 output
= check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
4236 self
.assertRegex(output
, 'via fe80::1034:56ff:fe78:9abd')
4238 def test_dhcp_client_gateway_onlink_implicit(self
):
4239 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4240 'dhcp-client-gateway-onlink-implicit.network')
4242 self
.wait_online(['veth-peer:carrier'])
4244 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4246 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4248 self
.assertRegex(output
, '192.168.5')
4250 output
= check_output('ip route list dev veth99 10.0.0.0/8')
4252 self
.assertRegex(output
, 'onlink')
4253 output
= check_output('ip route list dev veth99 192.168.100.0/24')
4255 self
.assertRegex(output
, 'onlink')
4257 def test_dhcp_client_with_ipv4ll_with_dhcp_server(self
):
4258 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4259 'dhcp-client-with-ipv4ll.network')
4261 self
.wait_online(['veth-peer:carrier'])
4262 start_dnsmasq(lease_time
='2m')
4263 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4265 output
= check_output('ip address show dev veth99')
4268 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
4269 self
.assertNotRegex(output
, r
'inet6 2600::[0-9a-f]+/128 scope global dynamic')
4270 output
= check_output('ip -6 address show dev veth99 scope link')
4271 self
.assertRegex(output
, r
'inet6 .* scope link')
4272 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
4273 self
.assertRegex(output
, r
'inet 192\.168\.5\.\d+/24 brd 192\.168\.5\.255 scope global dynamic veth99')
4274 output
= check_output('ip -4 address show dev veth99 scope link')
4275 self
.assertNotRegex(output
, r
'inet 169\.254\.\d+\.\d+/16 brd 169\.254\.255\.255 scope link')
4277 print('Wait for the dynamic address to be expired')
4280 output
= check_output('ip address show dev veth99')
4283 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
4284 self
.assertNotRegex(output
, r
'inet6 2600::[0-9a-f]+/128 scope global dynamic')
4285 output
= check_output('ip -6 address show dev veth99 scope link')
4286 self
.assertRegex(output
, r
'inet6 .* scope link')
4287 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
4288 self
.assertRegex(output
, r
'inet 192\.168\.5\.\d+/24 brd 192\.168\.5\.255 scope global dynamic veth99')
4289 output
= check_output('ip -4 address show dev veth99 scope link')
4290 self
.assertNotRegex(output
, r
'inet 169\.254\.\d+\.\d+/16 brd 169\.254\.255\.255 scope link')
4292 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
4294 def test_dhcp_client_with_ipv4ll_without_dhcp_server(self
):
4295 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4296 'dhcp-client-with-ipv4ll.network')
4298 # we need to increase timeout above default, as this will need to wait for
4299 # systemd-networkd to get the dhcpv4 transient failure event
4300 self
.wait_online(['veth99:degraded', 'veth-peer:routable'], timeout
='60s')
4302 output
= check_output('ip address show dev veth99')
4305 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
4306 self
.assertNotRegex(output
, r
'inet6 2600::[0-9a-f]+/128 scope global dynamic')
4307 output
= check_output('ip -6 address show dev veth99 scope link')
4308 self
.assertRegex(output
, r
'inet6 .* scope link')
4309 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
4310 self
.assertNotRegex(output
, r
'inet 192\.168\.5\.\d+/24 brd 192\.168\.5\.255 scope global dynamic veth99')
4311 output
= check_output('ip -4 address show dev veth99 scope link')
4312 self
.assertRegex(output
, r
'inet 169\.254\.\d+\.\d+/16 brd 169\.254\.255\.255 scope link')
4314 start_dnsmasq(lease_time
='2m')
4315 self
.wait_address('veth99', r
'inet 192\.168\.5\.\d+/24 brd 192\.168\.5\.255 scope global dynamic', ipv
='-4')
4316 self
.wait_address_dropped('veth99', r
'inet 169\.254\.\d+\.\d+/16 brd 169\.255\.255\.255 scope link', scope
='link', ipv
='-4')
4318 def test_dhcp_client_route_remove_on_renew(self
):
4319 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
4320 'dhcp-client-ipv4-only-ipv6-disabled.network')
4322 self
.wait_online(['veth-peer:carrier'])
4323 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
4324 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4326 # test for issue #12490
4328 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
4330 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
4332 for line
in output
.splitlines():
4333 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
4334 address1
= line
.split()[1].split('/')[0]
4337 output
= check_output('ip -4 route show dev veth99')
4339 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
4340 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
4342 stop_dnsmasq(dnsmasq_pid_file
)
4343 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
4345 print('Wait for the dynamic address to be expired')
4348 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
4350 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
4352 for line
in output
.splitlines():
4353 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
4354 address2
= line
.split()[1].split('/')[0]
4357 self
.assertNotEqual(address1
, address2
)
4359 output
= check_output('ip -4 route show dev veth99')
4361 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
4362 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
4363 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
4364 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
4366 def test_dhcp_client_use_dns_yes(self
):
4367 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-yes.network')
4370 self
.wait_online(['veth-peer:carrier'])
4371 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
4372 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4374 # link become 'routable' when at least one protocol provide an valid address.
4375 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4376 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4379 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
4381 self
.assertRegex(output
, '192.168.5.1')
4382 self
.assertRegex(output
, '2600::1')
4384 def test_dhcp_client_use_dns_no(self
):
4385 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-no.network')
4388 self
.wait_online(['veth-peer:carrier'])
4389 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
4390 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4392 # link become 'routable' when at least one protocol provide an valid address.
4393 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4394 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4397 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
4399 self
.assertNotRegex(output
, '192.168.5.1')
4400 self
.assertNotRegex(output
, '2600::1')
4402 def test_dhcp_client_use_dns_ipv4(self
):
4403 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4.network')
4406 self
.wait_online(['veth-peer:carrier'])
4407 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
4408 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4410 # link become 'routable' when at least one protocol provide an valid address.
4411 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4412 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4415 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
4417 self
.assertRegex(output
, '192.168.5.1')
4418 self
.assertNotRegex(output
, '2600::1')
4420 def test_dhcp_client_use_dns_ipv4_and_ra(self
):
4421 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4-and-ra.network')
4424 self
.wait_online(['veth-peer:carrier'])
4425 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
4426 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4428 # link become 'routable' when at least one protocol provide an valid address.
4429 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
4430 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
4433 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
4435 self
.assertRegex(output
, '192.168.5.1')
4436 self
.assertRegex(output
, '2600::1')
4438 def test_dhcp_client_use_domains(self
):
4439 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-domains.network')
4442 self
.wait_online(['veth-peer:carrier'])
4443 start_dnsmasq('--dhcp-option=option:domain-search,example.com')
4444 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4446 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
4448 self
.assertRegex(output
, 'Search Domains: example.com')
4451 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
4453 self
.assertRegex(output
, 'example.com')
4455 def test_dhcp_client_decline(self
):
4456 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-decline.network', 'dhcp-client-decline.network')
4459 self
.wait_online(['veth-peer:carrier'])
4460 rc
= call(*wait_online_cmd
, '--timeout=10s', '--interface=veth99:routable', env
=env
)
4461 self
.assertTrue(rc
== 1)
4463 class NetworkdIPv6PrefixTests(unittest
.TestCase
, Utilities
):
4468 'ipv6ra-prefix-client-deny-list.network',
4469 'ipv6ra-prefix-client.network',
4470 'ipv6ra-prefix.network'
4474 remove_links(self
.links
)
4475 stop_networkd(show_logs
=False)
4479 remove_links(self
.links
)
4480 remove_unit_from_networkd_path(self
.units
)
4481 stop_networkd(show_logs
=True)
4483 def test_ipv6_route_prefix(self
):
4484 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client.network', 'ipv6ra-prefix.network')
4487 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4489 output
= check_output('ip address show dev veth-peer')
4491 self
.assertIn('inet6 2001:db8:0:1:', output
)
4492 self
.assertNotIn('inet6 2001:db8:0:2:', output
)
4494 output
= check_output('ip -6 route show dev veth-peer')
4496 self
.assertIn('2001:db8:0:1::/64 proto ra', output
)
4497 self
.assertNotIn('2001:db8:0:2::/64 proto ra', output
)
4498 self
.assertIn('2001:db0:fff::/64 via ', output
)
4499 self
.assertNotIn('2001:db1:fff::/64 via ', output
)
4501 output
= check_output('ip address show dev veth99')
4503 self
.assertNotIn('inet6 2001:db8:0:1:', output
)
4504 self
.assertIn('inet6 2001:db8:0:2:', output
)
4506 def test_ipv6_route_prefix_deny_list(self
):
4507 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client-deny-list.network', 'ipv6ra-prefix.network')
4510 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
4512 output
= check_output('ip address show dev veth-peer')
4514 self
.assertIn('inet6 2001:db8:0:1:', output
)
4515 self
.assertNotIn('inet6 2001:db8:0:2:', output
)
4517 output
= check_output('ip -6 route show dev veth-peer')
4519 self
.assertIn('2001:db8:0:1::/64 proto ra', output
)
4520 self
.assertNotIn('2001:db8:0:2::/64 proto ra', output
)
4521 self
.assertIn('2001:db0:fff::/64 via ', output
)
4522 self
.assertNotIn('2001:db1:fff::/64 via ', output
)
4524 output
= check_output('ip address show dev veth99')
4526 self
.assertNotIn('inet6 2001:db8:0:1:', output
)
4527 self
.assertIn('inet6 2001:db8:0:2:', output
)
4529 class NetworkdMTUTests(unittest
.TestCase
, Utilities
):
4534 '12-dummy-mtu.netdev',
4535 '12-dummy-mtu.link',
4540 remove_links(self
.links
)
4541 stop_networkd(show_logs
=False)
4545 remove_links(self
.links
)
4546 remove_unit_from_networkd_path(self
.units
)
4547 stop_networkd(show_logs
=True)
4549 def check_mtu(self
, mtu
, ipv6_mtu
=None, reset
=True):
4555 self
.wait_online(['dummy98:routable'])
4556 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
4557 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
4559 # test normal restart
4561 self
.wait_online(['dummy98:routable'])
4562 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
4563 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
4566 self
.reset_check_mtu(mtu
, ipv6_mtu
)
4568 def reset_check_mtu(self
, mtu
, ipv6_mtu
=None):
4569 ''' test setting mtu/ipv6_mtu with interface already up '''
4572 # note - changing the device mtu resets the ipv6 mtu
4573 run('ip link set up mtu 1501 dev dummy98')
4574 run('ip link set up mtu 1500 dev dummy98')
4575 self
.assertEqual(read_link_attr('dummy98', 'mtu'), '1500')
4576 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), '1500')
4578 self
.check_mtu(mtu
, ipv6_mtu
, reset
=False)
4580 def test_mtu_network(self
):
4581 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
4582 self
.check_mtu('1600')
4584 def test_mtu_netdev(self
):
4585 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network', dropins
=False)
4586 # note - MTU set by .netdev happens ONLY at device creation!
4587 self
.check_mtu('1600', reset
=False)
4589 def test_mtu_link(self
):
4590 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', dropins
=False)
4591 # must reload udev because it only picks up new files after 3 second delay
4592 call('udevadm control --reload')
4593 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
4594 self
.check_mtu('1600', reset
=False)
4596 def test_ipv6_mtu(self
):
4597 ''' set ipv6 mtu without setting device mtu '''
4598 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
4599 self
.check_mtu('1500', '1400')
4601 def test_ipv6_mtu_toolarge(self
):
4602 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
4603 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
4604 self
.check_mtu('1500', '1500')
4606 def test_mtu_network_ipv6_mtu(self
):
4607 ''' set ipv6 mtu and set device mtu via network file '''
4608 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
4609 self
.check_mtu('1600', '1550')
4611 def test_mtu_netdev_ipv6_mtu(self
):
4612 ''' set ipv6 mtu and set device mtu via netdev file '''
4613 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
4614 self
.check_mtu('1600', '1550', reset
=False)
4616 def test_mtu_link_ipv6_mtu(self
):
4617 ''' set ipv6 mtu and set device mtu via link file '''
4618 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
4619 # must reload udev because it only picks up new files after 3 second delay
4620 call('udevadm control --reload')
4621 self
.check_mtu('1600', '1550', reset
=False)
4624 if __name__
== '__main__':
4625 parser
= argparse
.ArgumentParser()
4626 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
4627 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
4628 parser
.add_argument('--resolved', help='Path to systemd-resolved', dest
='resolved_bin')
4629 parser
.add_argument('--udevd', help='Path to systemd-udevd', dest
='udevd_bin')
4630 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
4631 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
4632 parser
.add_argument('--resolvectl', help='Path to resolvectl', dest
='resolvectl_bin')
4633 parser
.add_argument('--timedatectl', help='Path to timedatectl', dest
='timedatectl_bin')
4634 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
4635 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
4636 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
4637 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
4638 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
4639 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
4642 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
:
4643 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
4644 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
4645 resolved_bin
= os
.path
.join(ns
.build_dir
, 'systemd-resolved')
4646 udevd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-udevd')
4647 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
4648 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
4649 resolvectl_bin
= os
.path
.join(ns
.build_dir
, 'resolvectl')
4650 timedatectl_bin
= os
.path
.join(ns
.build_dir
, 'timedatectl')
4653 networkd_bin
= ns
.networkd_bin
4655 resolved_bin
= ns
.resolved_bin
4657 udevd_bin
= ns
.udevd_bin
4658 if ns
.wait_online_bin
:
4659 wait_online_bin
= ns
.wait_online_bin
4660 if ns
.networkctl_bin
:
4661 networkctl_bin
= ns
.networkctl_bin
4662 if ns
.resolvectl_bin
:
4663 resolvectl_bin
= ns
.resolvectl_bin
4664 if ns
.timedatectl_bin
:
4665 timedatectl_bin
= ns
.timedatectl_bin
4667 use_valgrind
= ns
.use_valgrind
4668 enable_debug
= ns
.enable_debug
4669 asan_options
= ns
.asan_options
4670 lsan_options
= ns
.lsan_options
4671 ubsan_options
= ns
.ubsan_options
4674 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
4675 resolvectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin
]
4676 timedatectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin
]
4677 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
4679 networkctl_cmd
= [networkctl_bin
]
4680 resolvectl_cmd
= [resolvectl_bin
]
4681 timedatectl_cmd
= [timedatectl_bin
]
4682 wait_online_cmd
= [wait_online_bin
]
4685 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
4687 env
.update({ 'ASAN_OPTIONS' : asan_options
})
4689 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
4691 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
4694 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,