2 # SPDX-License-Identifier: LGPL-2.1+
3 # systemd-networkd tests
15 from shutil
import copytree
17 network_unit_file_path
='/run/systemd/network'
18 networkd_runtime_directory
='/run/systemd/netif'
19 networkd_ci_path
='/run/networkd-ci'
20 network_sysctl_ipv6_path
='/proc/sys/net/ipv6/conf'
21 network_sysctl_ipv4_path
='/proc/sys/net/ipv4/conf'
23 dnsmasq_pid_file
='/run/networkd-ci/test-test-dnsmasq.pid'
24 dnsmasq_log_file
='/run/networkd-ci/test-dnsmasq-log-file'
26 systemd_lib_paths
=['/usr/lib/systemd', '/lib/systemd']
27 which_paths
=':'.join(systemd_lib_paths
+ os
.getenv('PATH', os
.defpath
).lstrip(':').split(':'))
29 networkd_bin
=shutil
.which('systemd-networkd', path
=which_paths
)
30 resolved_bin
=shutil
.which('systemd-resolved', path
=which_paths
)
31 udevd_bin
=shutil
.which('systemd-udevd', path
=which_paths
)
32 wait_online_bin
=shutil
.which('systemd-networkd-wait-online', path
=which_paths
)
33 networkctl_bin
=shutil
.which('networkctl', path
=which_paths
)
34 resolvectl_bin
=shutil
.which('resolvectl', path
=which_paths
)
35 timedatectl_bin
=shutil
.which('timedatectl', path
=which_paths
)
46 def check_output(*command
, **kwargs
):
47 # This replaces both check_output and check_call (output can be ignored)
48 command
= command
[0].split() + list(command
[1:])
49 return subprocess
.check_output(command
, universal_newlines
=True, **kwargs
).rstrip()
51 def call(*command
, **kwargs
):
52 command
= command
[0].split() + list(command
[1:])
53 return subprocess
.call(command
, universal_newlines
=True, **kwargs
)
55 def run(*command
, **kwargs
):
56 command
= command
[0].split() + list(command
[1:])
57 return subprocess
.run(command
, universal_newlines
=True, **kwargs
)
59 def is_module_available(module_name
):
60 lsmod_output
= check_output('lsmod')
61 module_re
= re
.compile(rf
'^{re.escape(module_name)}\b', re
.MULTILINE
)
62 return module_re
.search(lsmod_output
) or not call('modprobe', module_name
, stderr
=subprocess
.DEVNULL
)
64 def expectedFailureIfModuleIsNotAvailable(module_name
):
66 if not is_module_available(module_name
):
67 return unittest
.expectedFailure(func
)
72 def expectedFailureIfERSPANModuleIsNotAvailable():
74 rc
= call('ip link add dev erspan99 type erspan seq key 30 local 192.168.1.4 remote 192.168.1.1 erspan_ver 1 erspan 123', stderr
=subprocess
.DEVNULL
)
76 call('ip link del erspan99')
79 return unittest
.expectedFailure(func
)
83 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable():
85 rc
= call('ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7', stderr
=subprocess
.DEVNULL
)
87 call('ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
90 return unittest
.expectedFailure(func
)
94 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
96 rc
= call('ip rule add not from 192.168.100.19 ipproto tcp table 7', stderr
=subprocess
.DEVNULL
)
98 call('ip rule del not from 192.168.100.19 ipproto tcp table 7')
101 return unittest
.expectedFailure(func
)
105 def expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable():
108 rc
= call('ip rule add from 192.168.100.19 table 7 uidrange 200-300', stderr
=subprocess
.DEVNULL
)
110 ret
= run('ip rule list from 192.168.100.19 table 7', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
111 if ret
.returncode
== 0 and 'uidrange 200-300' in ret
.stdout
.rstrip():
113 call('ip rule del from 192.168.100.19 table 7 uidrange 200-300')
118 return unittest
.expectedFailure(func
)
122 def expectedFailureIfLinkFileFieldIsNotSet():
125 rc
= call('ip link add name dummy99 type dummy', stderr
=subprocess
.DEVNULL
)
127 ret
= run('udevadm info -w10s /sys/class/net/dummy99', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
128 if ret
.returncode
== 0 and 'E: ID_NET_LINK_FILE=' in ret
.stdout
.rstrip():
130 call('ip link del dummy99')
135 return unittest
.expectedFailure(func
)
139 def expectedFailureIfNexthopIsNotAvailable():
141 rc
= call('ip nexthop list', stderr
=subprocess
.DEVNULL
)
145 return unittest
.expectedFailure(func
)
149 def expectedFailureIfAlternativeNameIsNotAvailable():
151 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
152 rc
= call('ip link prop add dev dummy98 altname hogehogehogehogehoge', stderr
=subprocess
.DEVNULL
)
153 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
157 return unittest
.expectedFailure(func
)
161 def expectedFailureIfNetdevsimWithSRIOVIsNotAvailable():
163 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
164 rc
= call('modprobe netdevsim', stderr
=subprocess
.DEVNULL
)
166 return unittest
.expectedFailure(func
)
169 with
open('/sys/bus/netdevsim/new_device', mode
='w') as f
:
171 except Exception as error
:
172 return unittest
.expectedFailure(func
)
174 call('udevadm settle')
175 call('udevadm info -w10s /sys/devices/netdevsim99/net/eni99np1', stderr
=subprocess
.DEVNULL
)
177 with
open('/sys/class/net/eni99np1/device/sriov_numvfs', mode
='w') as f
:
179 except Exception as error
:
180 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
181 return unittest
.expectedFailure(func
)
183 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
188 def expectedFailureIfCAKEIsNotAvailable():
190 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
191 rc
= call('tc qdisc add dev dummy98 parent root cake', stderr
=subprocess
.DEVNULL
)
192 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
196 return unittest
.expectedFailure(func
)
200 def expectedFailureIfPIEIsNotAvailable():
202 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
203 rc
= call('tc qdisc add dev dummy98 parent root pie', stderr
=subprocess
.DEVNULL
)
204 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
208 return unittest
.expectedFailure(func
)
212 def expectedFailureIfHHFIsNotAvailable():
214 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
215 rc
= call('tc qdisc add dev dummy98 parent root hhf', stderr
=subprocess
.DEVNULL
)
216 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
220 return unittest
.expectedFailure(func
)
224 def expectedFailureIfETSIsNotAvailable():
226 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
227 rc
= call('tc qdisc add dev dummy98 parent root ets bands 10', stderr
=subprocess
.DEVNULL
)
228 call('ip link del dummy98', stderr
=subprocess
.DEVNULL
)
232 return unittest
.expectedFailure(func
)
239 os
.makedirs(network_unit_file_path
, exist_ok
=True)
240 os
.makedirs(networkd_ci_path
, exist_ok
=True)
242 shutil
.rmtree(networkd_ci_path
)
243 copytree(os
.path
.join(os
.path
.dirname(os
.path
.abspath(__file__
)), 'conf'), networkd_ci_path
)
245 for u
in ['systemd-networkd.socket', 'systemd-networkd.service', 'systemd-resolved.service',
246 'systemd-udevd-kernel.socket', 'systemd-udevd-control.socket', 'systemd-udevd.service',
247 'firewalld.service']:
248 if call(f
'systemctl is-active --quiet {u}') == 0:
249 check_output(f
'systemctl stop {u}')
250 running_units
.append(u
)
254 'StartLimitIntervalSec=0',
261 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin
,
265 drop_in
+= ['ExecStart=!!' + networkd_bin
]
267 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
269 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
271 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
273 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
274 if asan_options
or lsan_options
or ubsan_options
:
275 drop_in
+= ['SystemCallFilter=']
276 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
277 drop_in
+= ['MemoryDenyWriteExecute=no']
279 os
.makedirs('/run/systemd/system/systemd-networkd.service.d', exist_ok
=True)
280 with
open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode
='w') as f
:
281 f
.write('\n'.join(drop_in
))
289 drop_in
+= ['ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + resolved_bin
]
291 drop_in
+= ['ExecStart=!!' + resolved_bin
]
293 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
295 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
297 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
299 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
300 if asan_options
or lsan_options
or ubsan_options
:
301 drop_in
+= ['SystemCallFilter=']
302 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
303 drop_in
+= ['MemoryDenyWriteExecute=no']
305 os
.makedirs('/run/systemd/system/systemd-resolved.service.d', exist_ok
=True)
306 with
open('/run/systemd/system/systemd-resolved.service.d/00-override.conf', mode
='w') as f
:
307 f
.write('\n'.join(drop_in
))
312 'ExecStart=!!' + udevd_bin
,
315 os
.makedirs('/run/systemd/system/systemd-udevd.service.d', exist_ok
=True)
316 with
open('/run/systemd/system/systemd-udevd.service.d/00-override.conf', mode
='w') as f
:
317 f
.write('\n'.join(drop_in
))
319 check_output('systemctl daemon-reload')
320 print(check_output('systemctl cat systemd-networkd.service'))
321 print(check_output('systemctl cat systemd-resolved.service'))
322 print(check_output('systemctl cat systemd-udevd.service'))
323 check_output('systemctl restart systemd-resolved')
324 check_output('systemctl restart systemd-udevd')
326 def tearDownModule():
329 shutil
.rmtree(networkd_ci_path
)
331 for u
in ['systemd-networkd.service', 'systemd-resolved.service']:
332 check_output(f
'systemctl stop {u}')
334 shutil
.rmtree('/run/systemd/system/systemd-networkd.service.d')
335 shutil
.rmtree('/run/systemd/system/systemd-resolved.service.d')
336 shutil
.rmtree('/run/systemd/system/systemd-udevd.service.d')
337 check_output('systemctl daemon-reload')
338 check_output('systemctl restart systemd-udevd.service')
340 for u
in running_units
:
341 check_output(f
'systemctl start {u}')
343 def read_link_attr(*args
):
344 with
open(os
.path
.join('/sys/class/net/', *args
)) as f
:
345 return f
.readline().strip()
347 def read_bridge_port_attr(bridge
, link
, attribute
):
348 path_bridge
= os
.path
.join('/sys/devices/virtual/net', bridge
)
349 path_port
= 'lower_' + link
+ '/brport'
350 path
= os
.path
.join(path_bridge
, path_port
)
352 with
open(os
.path
.join(path
, attribute
)) as f
:
353 return f
.readline().strip()
355 def link_exists(link
):
356 return os
.path
.exists(os
.path
.join('/sys/class/net', link
))
358 def remove_links(links
):
360 if link_exists(link
):
361 call('ip link del dev', link
)
364 def remove_fou_ports(ports
):
366 call('ip fou del port', port
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
368 def remove_routing_policy_rule_tables(tables
):
372 rc
= call('ip rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
374 def remove_routes(routes
):
375 for route_type
, addr
in routes
:
376 call('ip route del', route_type
, addr
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
378 def remove_l2tp_tunnels(tunnel_ids
):
379 output
= check_output('ip l2tp show tunnel')
380 for tid
in tunnel_ids
:
381 words
='Tunnel ' + tid
+ ', encap'
383 call('ip l2tp del tunnel tid', tid
)
386 def read_ipv6_sysctl_attr(link
, attribute
):
387 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, link
), attribute
)) as f
:
388 return f
.readline().strip()
390 def read_ipv4_sysctl_attr(link
, attribute
):
391 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv4_path
, link
), attribute
)) as f
:
392 return f
.readline().strip()
394 def copy_unit_to_networkd_unit_path(*units
, dropins
=True):
395 """Copy networkd unit files into the testbed.
397 Any networkd unit file type can be specified, as well as drop-in files.
399 By default, all drop-ins for a specified unit file are copied in;
400 to avoid that specify dropins=False.
402 When a drop-in file is specified, its unit file is also copied in automatically.
406 if dropins
and os
.path
.exists(os
.path
.join(networkd_ci_path
, unit
+ '.d')):
407 copytree(os
.path
.join(networkd_ci_path
, unit
+ '.d'), os
.path
.join(network_unit_file_path
, unit
+ '.d'))
408 if unit
.endswith('.conf'):
410 dropindir
= os
.path
.join(network_unit_file_path
, os
.path
.dirname(dropin
))
411 os
.makedirs(dropindir
, exist_ok
=True)
412 shutil
.copy(os
.path
.join(networkd_ci_path
, dropin
), dropindir
)
413 unit
= os
.path
.dirname(dropin
).rstrip('.d')
414 shutil
.copy(os
.path
.join(networkd_ci_path
, unit
), network_unit_file_path
)
416 def remove_unit_from_networkd_path(units
):
417 """Remove previously copied unit files from the testbed.
419 Drop-ins will be removed automatically.
422 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
))):
423 os
.remove(os
.path
.join(network_unit_file_path
, unit
))
424 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
+ '.d'))):
425 shutil
.rmtree(os
.path
.join(network_unit_file_path
, unit
+ '.d'))
427 def start_dnsmasq(additional_options
='', ipv4_range
='192.168.5.10,192.168.5.200', ipv6_range
='2600::10,2600::20', lease_time
='1h'):
428 dnsmasq_command
= f
'dnsmasq -8 /var/run/networkd-ci/test-dnsmasq-log-file --log-queries=extra --log-dhcp --pid-file=/var/run/networkd-ci/test-test-dnsmasq.pid --conf-file=/dev/null --interface=veth-peer --enable-ra --dhcp-range={ipv6_range},{lease_time} --dhcp-range={ipv4_range},{lease_time} -R --dhcp-leasefile=/var/run/networkd-ci/lease --dhcp-option=26,1492 --dhcp-option=option:router,192.168.5.1 --dhcp-option=33,192.168.5.4,192.168.5.5 --port=0 ' + additional_options
429 check_output(dnsmasq_command
)
431 def stop_dnsmasq(pid_file
):
432 if os
.path
.exists(pid_file
):
433 with
open(pid_file
, 'r') as f
:
434 pid
= f
.read().rstrip(' \t\r\n\0')
435 os
.kill(int(pid
), signal
.SIGTERM
)
439 def search_words_in_dnsmasq_log(words
, show_all
=False):
440 if os
.path
.exists(dnsmasq_log_file
):
441 with
open (dnsmasq_log_file
) as in_file
:
442 contents
= in_file
.read()
445 for line
in contents
.splitlines():
448 print("%s, %s" % (words
, line
))
452 def remove_lease_file():
453 if os
.path
.exists(os
.path
.join(networkd_ci_path
, 'lease')):
454 os
.remove(os
.path
.join(networkd_ci_path
, 'lease'))
456 def remove_log_file():
457 if os
.path
.exists(dnsmasq_log_file
):
458 os
.remove(dnsmasq_log_file
)
460 def remove_networkd_state_files():
461 if os
.path
.exists(os
.path
.join(networkd_runtime_directory
, 'state')):
462 os
.remove(os
.path
.join(networkd_runtime_directory
, 'state'))
464 def stop_networkd(show_logs
=True, remove_state_files
=True):
466 invocation_id
= check_output('systemctl show systemd-networkd -p InvocationID --value')
467 check_output('systemctl stop systemd-networkd')
469 print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
))
470 if remove_state_files
:
471 remove_networkd_state_files()
473 def start_networkd(sleep_sec
=0):
474 check_output('systemctl start systemd-networkd')
476 time
.sleep(sleep_sec
)
478 def restart_networkd(sleep_sec
=0, show_logs
=True, remove_state_files
=True):
479 stop_networkd(show_logs
, remove_state_files
)
480 start_networkd(sleep_sec
)
484 def check_link_exists(self
, link
):
485 self
.assertTrue(link_exists(link
))
487 def check_link_attr(self
, *args
):
488 self
.assertEqual(read_link_attr(*args
[:-1]), args
[-1]);
490 def wait_operstate(self
, link
, operstate
='degraded', setup_state
='configured', setup_timeout
=5, fail_assert
=True):
491 """Wait for the link to reach the specified operstate and/or setup state.
493 Specify None or '' for either operstate or setup_state to ignore that state.
494 This will recheck until the state conditions are met or the timeout expires.
496 If the link successfully matches the requested state, this returns True.
497 If this times out waiting for the link to match, the behavior depends on the
498 'fail_assert' parameter; if True, this causes a test assertion failure,
499 otherwise this returns False. The default is to cause assertion failure.
501 Note that this function matches on *exactly* the given operstate and setup_state.
502 To wait for a link to reach *or exceed* a given operstate, use wait_online().
509 for secs
in range(setup_timeout
+ 1):
510 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
, env
=env
)
512 if re
.search(rf
'(?m)^\s*State:\s+{operstate}\s+\({setup_state}\)\s*$', output
):
514 # don't bother sleeping if time is up
515 if secs
< setup_timeout
:
518 self
.fail(f
'Timed out waiting for {link} to reach state {operstate}/{setup_state}')
521 def wait_online(self
, links_with_operstate
, timeout
='20s', bool_any
=False, setup_state
='configured', setup_timeout
=5):
522 """Wait for the link(s) to reach the specified operstate and/or setup state.
524 This is similar to wait_operstate() but can be used for multiple links,
525 and it also calls systemd-networkd-wait-online to wait for the given operstate.
526 The operstate should be specified in the link name, like 'eth0:degraded'.
527 If just a link name is provided, wait-online's default operstate to wait for is degraded.
529 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
530 'setup_timeout' controls the per-link timeout waiting for the setup_state.
532 Set 'bool_any' to True to wait for any (instead of all) of the given links.
533 If this is set, no setup_state checks are done.
535 Note that this function waits for the link(s) to reach *or exceed* the given operstate.
536 However, the setup_state, if specified, must be matched *exactly*.
538 This returns if the link(s) reached the requested operstate/setup_state; otherwise it
539 raises CalledProcessError or fails test assertion.
541 args
= wait_online_cmd
+ [f
'--timeout={timeout}'] + [f
'--interface={link}' for link
in links_with_operstate
]
545 check_output(*args
, env
=env
)
546 except subprocess
.CalledProcessError
:
547 for link
in links_with_operstate
:
548 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', link
.split(':')[0], env
=env
)
551 if not bool_any
and setup_state
:
552 for link
in links_with_operstate
:
553 self
.wait_operstate(link
.split(':')[0], None, setup_state
, setup_timeout
)
555 def wait_address(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
556 for i
in range(timeout_sec
):
559 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
560 if re
.search(address_regex
, output
):
563 self
.assertRegex(output
, address_regex
)
565 class NetworkctlTests(unittest
.TestCase
, Utilities
):
575 '11-dummy-mtu.netdev',
579 '25-address-static.network',
581 'netdev-link-local-addressing-yes.network',
585 remove_links(self
.links
)
586 stop_networkd(show_logs
=False)
589 remove_links(self
.links
)
590 remove_unit_from_networkd_path(self
.units
)
591 stop_networkd(show_logs
=True)
593 @expectedFailureIfAlternativeNameIsNotAvailable()
594 def test_altname(self
):
595 copy_unit_to_networkd_unit_path('netdev-link-local-addressing-yes.network', '12-dummy.netdev', '12-dummy.link')
596 check_output('udevadm control --reload')
598 self
.wait_online(['dummy98:degraded'])
600 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
601 self
.assertRegex(output
, 'hogehogehogehogehogehoge')
603 def test_reconfigure(self
):
604 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
606 self
.wait_online(['dummy98:routable'])
608 output
= check_output('ip -4 address show dev dummy98')
610 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
611 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
612 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
614 check_output('ip address del 10.1.2.3/16 dev dummy98')
615 check_output('ip address del 10.1.2.4/16 dev dummy98')
616 check_output('ip address del 10.2.2.4/16 dev dummy98')
618 check_output(*networkctl_cmd
, 'reconfigure', 'dummy98', env
=env
)
619 self
.wait_online(['dummy98:routable'])
621 output
= check_output('ip -4 address show dev dummy98')
623 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
624 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
625 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
627 def test_reload(self
):
630 copy_unit_to_networkd_unit_path('11-dummy.netdev')
631 check_output(*networkctl_cmd
, 'reload', env
=env
)
632 self
.wait_operstate('test1', 'off', setup_state
='unmanaged')
634 copy_unit_to_networkd_unit_path('11-dummy.network')
635 check_output(*networkctl_cmd
, 'reload', env
=env
)
636 self
.wait_online(['test1:degraded'])
638 remove_unit_from_networkd_path(['11-dummy.network'])
639 check_output(*networkctl_cmd
, 'reload', env
=env
)
640 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
642 remove_unit_from_networkd_path(['11-dummy.netdev'])
643 check_output(*networkctl_cmd
, 'reload', env
=env
)
644 self
.wait_operstate('test1', 'degraded', setup_state
='unmanaged')
646 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
647 check_output(*networkctl_cmd
, 'reload', env
=env
)
648 self
.wait_operstate('test1', 'degraded')
651 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
654 self
.wait_online(['test1:degraded'])
656 output
= check_output(*networkctl_cmd
, 'list', env
=env
)
657 self
.assertRegex(output
, '1 lo ')
658 self
.assertRegex(output
, 'test1')
660 output
= check_output(*networkctl_cmd
, 'list', 'test1', env
=env
)
661 self
.assertNotRegex(output
, '1 lo ')
662 self
.assertRegex(output
, 'test1')
664 output
= check_output(*networkctl_cmd
, 'list', 'te*', env
=env
)
665 self
.assertNotRegex(output
, '1 lo ')
666 self
.assertRegex(output
, 'test1')
668 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'te*', env
=env
)
669 self
.assertNotRegex(output
, '1: lo ')
670 self
.assertRegex(output
, 'test1')
672 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'tes[a-z][0-9]', env
=env
)
673 self
.assertNotRegex(output
, '1: lo ')
674 self
.assertRegex(output
, 'test1')
677 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
680 self
.wait_online(['test1:degraded'])
682 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
683 self
.assertRegex(output
, 'MTU: 1600')
686 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
688 self
.wait_online(['test1:degraded'])
690 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
692 self
.assertRegex(output
, 'Type: ether')
694 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
696 self
.assertRegex(output
, 'Type: loopback')
698 @expectedFailureIfLinkFileFieldIsNotSet()
699 def test_udev_link_file(self
):
700 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
702 self
.wait_online(['test1:degraded'])
704 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
706 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
707 self
.assertRegex(output
, r
'Network File: /run/systemd/network/11-dummy.network')
709 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'lo', env
=env
)
711 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
712 self
.assertRegex(output
, r
'Network File: n/a')
714 def test_delete_links(self
):
715 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
716 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
719 self
.wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
721 check_output(*networkctl_cmd
, 'delete', 'test1', 'veth99', env
=env
)
722 self
.assertFalse(link_exists('test1'))
723 self
.assertFalse(link_exists('veth99'))
724 self
.assertFalse(link_exists('veth-peer'))
726 class NetworkdNetDevTests(unittest
.TestCase
, Utilities
):
728 links_remove_earlier
= [
794 '10-dropin-test.netdev',
798 '13-not-match-udev-property.network',
799 '14-match-udev-property.network',
800 '15-name-conflict-test.netdev',
803 '21-vlan-test1.network',
806 '25-6rd-tunnel.netdev',
808 '25-bond-balanced-tlb.netdev',
810 '25-bridge-configure-without-carrier.network',
812 '25-erspan-tunnel-local-any.netdev',
813 '25-erspan-tunnel.netdev',
814 '25-fou-gretap.netdev',
816 '25-fou-ipip.netdev',
817 '25-fou-ipproto-gre.netdev',
818 '25-fou-ipproto-ipip.netdev',
821 '25-gretap-tunnel-local-any.netdev',
822 '25-gretap-tunnel.netdev',
823 '25-gre-tunnel-any-any.netdev',
824 '25-gre-tunnel-local-any.netdev',
825 '25-gre-tunnel-remote-any.netdev',
826 '25-gre-tunnel.netdev',
828 '25-ip6gretap-tunnel-local-any.netdev',
829 '25-ip6gretap-tunnel.netdev',
830 '25-ip6gre-tunnel-any-any.netdev',
831 '25-ip6gre-tunnel-local-any.netdev',
832 '25-ip6gre-tunnel-remote-any.netdev',
833 '25-ip6gre-tunnel.netdev',
834 '25-ip6tnl-tunnel-any-any.netdev',
835 '25-ip6tnl-tunnel-local-any.netdev',
836 '25-ip6tnl-tunnel-remote-any.netdev',
837 '25-ip6tnl-tunnel.netdev',
838 '25-ipip-tunnel-any-any.netdev',
839 '25-ipip-tunnel-independent.netdev',
840 '25-ipip-tunnel-independent-loopback.netdev',
841 '25-ipip-tunnel-local-any.netdev',
842 '25-ipip-tunnel-remote-any.netdev',
843 '25-ipip-tunnel.netdev',
846 '25-isatap-tunnel.netdev',
851 '25-sit-tunnel-any-any.netdev',
852 '25-sit-tunnel-local-any.netdev',
853 '25-sit-tunnel-remote-any.netdev',
854 '25-sit-tunnel.netdev',
857 '25-tunnel-local-any.network',
858 '25-tunnel-remote-any.network',
863 '25-vti6-tunnel-any-any.netdev',
864 '25-vti6-tunnel-local-any.netdev',
865 '25-vti6-tunnel-remote-any.netdev',
866 '25-vti6-tunnel.netdev',
867 '25-vti-tunnel-any-any.netdev',
868 '25-vti-tunnel-local-any.netdev',
869 '25-vti-tunnel-remote-any.netdev',
870 '25-vti-tunnel.netdev',
873 '25-wireguard-23-peers.netdev',
874 '25-wireguard-23-peers.network',
875 '25-wireguard-no-peer.netdev',
876 '25-wireguard-no-peer.network',
877 '25-wireguard-preshared-key.txt',
878 '25-wireguard-private-key.txt',
879 '25-wireguard.netdev',
880 '25-wireguard.network',
882 '25-xfrm-independent.netdev',
898 'netdev-link-local-addressing-yes.network',
902 'vxlan-test1.network',
912 remove_fou_ports(self
.fou_ports
)
913 remove_links(self
.links_remove_earlier
)
914 remove_links(self
.links
)
915 stop_networkd(show_logs
=False)
918 remove_fou_ports(self
.fou_ports
)
919 remove_links(self
.links_remove_earlier
)
920 remove_links(self
.links
)
921 remove_unit_from_networkd_path(self
.units
)
922 stop_networkd(show_logs
=True)
924 def test_dropin_and_name_conflict(self
):
925 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
928 self
.wait_online(['dropin-test:off'], setup_state
='unmanaged')
930 output
= check_output('ip link show dropin-test')
932 self
.assertRegex(output
, '00:50:56:c0:00:28')
934 def test_match_udev_property(self
):
935 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
937 self
.wait_online(['dummy98:routable'])
939 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
941 self
.assertRegex(output
, 'Network File: /run/systemd/network/14-match-udev-property')
943 def test_wait_online_any(self
):
944 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
947 self
.wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
949 self
.wait_operstate('bridge99', '(off|no-carrier)', setup_state
='configuring')
950 self
.wait_operstate('test1', 'degraded')
952 def test_bridge(self
):
953 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
956 self
.wait_online(['bridge99:no-carrier'])
958 tick
= os
.sysconf('SC_CLK_TCK')
959 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
960 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
961 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'forward_delay')) / tick
))
962 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'ageing_time')) / tick
))
963 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge', 'priority')))
964 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_querier')))
965 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_snooping')))
966 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'stp_state')))
967 self
.assertEqual(3, int(read_link_attr('bridge99', 'bridge', 'multicast_igmp_version')))
969 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
971 self
.assertRegex(output
, 'Priority: 9')
972 self
.assertRegex(output
, 'STP: yes')
973 self
.assertRegex(output
, 'Multicast IGMP Version: 3')
976 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
979 self
.wait_online(['bond99:off', 'bond98:off'], setup_state
='unmanaged')
981 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
982 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
983 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
984 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
985 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
986 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
987 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
988 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
989 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
990 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
991 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
993 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
994 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
997 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
998 '21-vlan.network', '21-vlan-test1.network')
1001 self
.wait_online(['test1:degraded', 'vlan99:routable'])
1003 output
= check_output('ip -d link show test1')
1005 self
.assertRegex(output
, ' mtu 2000 ')
1007 output
= check_output('ip -d link show vlan99')
1009 self
.assertRegex(output
, ' mtu 2000 ')
1010 self
.assertRegex(output
, 'REORDER_HDR')
1011 self
.assertRegex(output
, 'LOOSE_BINDING')
1012 self
.assertRegex(output
, 'GVRP')
1013 self
.assertRegex(output
, 'MVRP')
1014 self
.assertRegex(output
, ' id 99 ')
1016 output
= check_output('ip -4 address show dev test1')
1018 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
1019 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
1021 output
= check_output('ip -4 address show dev vlan99')
1023 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
1025 def test_macvtap(self
):
1026 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
1027 with self
.subTest(mode
=mode
):
1028 if mode
!= 'private':
1030 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
1031 '11-dummy.netdev', 'macvtap.network')
1032 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
1033 f
.write('[MACVTAP]\nMode=' + mode
)
1036 self
.wait_online(['macvtap99:degraded', 'test1:degraded'])
1038 output
= check_output('ip -d link show macvtap99')
1040 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
1042 def test_macvlan(self
):
1043 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
1044 with self
.subTest(mode
=mode
):
1045 if mode
!= 'private':
1047 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
1048 '11-dummy.netdev', 'macvlan.network')
1049 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
1050 f
.write('[MACVLAN]\nMode=' + mode
)
1053 self
.wait_online(['macvlan99:degraded', 'test1:degraded'])
1055 output
= check_output('ip -d link show test1')
1057 self
.assertRegex(output
, ' mtu 2000 ')
1059 output
= check_output('ip -d link show macvlan99')
1061 self
.assertRegex(output
, ' mtu 2000 ')
1062 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
1064 @expectedFailureIfModuleIsNotAvailable('ipvlan')
1065 def test_ipvlan(self
):
1066 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1067 with self
.subTest(mode
=mode
, flag
=flag
):
1070 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
1071 '11-dummy.netdev', 'ipvlan.network')
1072 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
1073 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
1076 self
.wait_online(['ipvlan99:degraded', 'test1:degraded'])
1078 output
= check_output('ip -d link show ipvlan99')
1080 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
1082 @expectedFailureIfModuleIsNotAvailable('ipvtap')
1083 def test_ipvtap(self
):
1084 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1085 with self
.subTest(mode
=mode
, flag
=flag
):
1088 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
1089 '11-dummy.netdev', 'ipvtap.network')
1090 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
1091 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
1094 self
.wait_online(['ipvtap99:degraded', 'test1:degraded'])
1096 output
= check_output('ip -d link show ipvtap99')
1098 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
1100 def test_veth(self
):
1101 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
1104 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
1106 output
= check_output('ip -d link show veth99')
1108 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
1109 output
= check_output('ip -d link show veth-peer')
1111 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
1114 copy_unit_to_networkd_unit_path('25-tun.netdev')
1117 self
.wait_online(['tun99:off'], setup_state
='unmanaged')
1119 output
= check_output('ip -d link show tun99')
1121 # Old ip command does not support IFF_ flags
1122 self
.assertRegex(output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
1125 copy_unit_to_networkd_unit_path('25-tap.netdev')
1128 self
.wait_online(['tap99:off'], setup_state
='unmanaged')
1130 output
= check_output('ip -d link show tap99')
1132 # Old ip command does not support IFF_ flags
1133 self
.assertRegex(output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
1135 @expectedFailureIfModuleIsNotAvailable('vrf')
1137 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
1140 self
.wait_online(['vrf99:carrier'])
1142 @expectedFailureIfModuleIsNotAvailable('vcan')
1143 def test_vcan(self
):
1144 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
1147 self
.wait_online(['vcan99:carrier'])
1149 @expectedFailureIfModuleIsNotAvailable('vxcan')
1150 def test_vxcan(self
):
1151 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
1154 self
.wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
1156 @expectedFailureIfModuleIsNotAvailable('wireguard')
1157 def test_wireguard(self
):
1158 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
1159 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
1160 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt',
1161 '25-wireguard-no-peer.netdev', '25-wireguard-no-peer.network')
1163 self
.wait_online(['wg99:carrier', 'wg98:routable', 'wg97:carrier'])
1165 if shutil
.which('wg'):
1168 output
= check_output('wg show wg99 listen-port')
1169 self
.assertRegex(output
, '51820')
1170 output
= check_output('wg show wg99 fwmark')
1171 self
.assertRegex(output
, '0x4d2')
1172 output
= check_output('wg show wg99 allowed-ips')
1173 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
1174 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
1175 output
= check_output('wg show wg99 persistent-keepalive')
1176 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
1177 output
= check_output('wg show wg99 endpoints')
1178 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
1179 output
= check_output('wg show wg99 private-key')
1180 self
.assertRegex(output
, r
'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
1181 output
= check_output('wg show wg99 preshared-keys')
1182 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
1183 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
1185 output
= check_output('wg show wg98 private-key')
1186 self
.assertRegex(output
, r
'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
1188 output
= check_output('wg show wg97 listen-port')
1189 self
.assertRegex(output
, '51821')
1190 output
= check_output('wg show wg97 fwmark')
1191 self
.assertRegex(output
, '0x4d3')
1193 def test_geneve(self
):
1194 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
1197 self
.wait_online(['geneve99:degraded'])
1199 output
= check_output('ip -d link show geneve99')
1201 self
.assertRegex(output
, '192.168.22.1')
1202 self
.assertRegex(output
, '6082')
1203 self
.assertRegex(output
, 'udpcsum')
1204 self
.assertRegex(output
, 'udp6zerocsumrx')
1206 def test_ipip_tunnel(self
):
1207 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
1208 '25-ipip-tunnel.netdev', '25-tunnel.network',
1209 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1210 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1211 '25-ipip-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1213 self
.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'ipiptun96:routable', 'dummy98:degraded'])
1215 output
= check_output('ip -d link show ipiptun99')
1217 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98')
1218 output
= check_output('ip -d link show ipiptun98')
1220 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98')
1221 output
= check_output('ip -d link show ipiptun97')
1223 self
.assertRegex(output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98')
1224 output
= check_output('ip -d link show ipiptun96')
1226 self
.assertRegex(output
, 'ipip (ipip )?remote any local any dev dummy98')
1228 def test_gre_tunnel(self
):
1229 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
1230 '25-gre-tunnel.netdev', '25-tunnel.network',
1231 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1232 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1233 '25-gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1235 self
.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'gretun96:routable', 'dummy98:degraded'])
1237 output
= check_output('ip -d link show gretun99')
1239 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1240 self
.assertRegex(output
, 'ikey 1.2.3.103')
1241 self
.assertRegex(output
, 'okey 1.2.4.103')
1242 self
.assertRegex(output
, 'iseq')
1243 self
.assertRegex(output
, 'oseq')
1244 output
= check_output('ip -d link show gretun98')
1246 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
1247 self
.assertRegex(output
, 'ikey 0.0.0.104')
1248 self
.assertRegex(output
, 'okey 0.0.0.104')
1249 self
.assertNotRegex(output
, 'iseq')
1250 self
.assertNotRegex(output
, 'oseq')
1251 output
= check_output('ip -d link show gretun97')
1253 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
1254 self
.assertRegex(output
, 'ikey 0.0.0.105')
1255 self
.assertRegex(output
, 'okey 0.0.0.105')
1256 self
.assertNotRegex(output
, 'iseq')
1257 self
.assertNotRegex(output
, 'oseq')
1258 output
= check_output('ip -d link show gretun96')
1260 self
.assertRegex(output
, 'gre remote any local any dev dummy98')
1261 self
.assertRegex(output
, 'ikey 0.0.0.106')
1262 self
.assertRegex(output
, 'okey 0.0.0.106')
1263 self
.assertNotRegex(output
, 'iseq')
1264 self
.assertNotRegex(output
, 'oseq')
1266 def test_ip6gre_tunnel(self
):
1267 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
1268 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
1269 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1270 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1271 '25-ip6gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1274 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1276 self
.check_link_exists('dummy98')
1277 self
.check_link_exists('ip6gretun99')
1278 self
.check_link_exists('ip6gretun98')
1279 self
.check_link_exists('ip6gretun97')
1280 self
.check_link_exists('ip6gretun96')
1282 output
= check_output('ip -d link show ip6gretun99')
1284 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1285 output
= check_output('ip -d link show ip6gretun98')
1287 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
1288 output
= check_output('ip -d link show ip6gretun97')
1290 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
1291 output
= check_output('ip -d link show ip6gretun96')
1293 self
.assertRegex(output
, 'ip6gre remote any local any dev dummy98')
1295 def test_gretap_tunnel(self
):
1296 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
1297 '25-gretap-tunnel.netdev', '25-tunnel.network',
1298 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1300 self
.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
1302 output
= check_output('ip -d link show gretap99')
1304 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1305 self
.assertRegex(output
, 'ikey 0.0.0.106')
1306 self
.assertRegex(output
, 'okey 0.0.0.106')
1307 self
.assertRegex(output
, 'iseq')
1308 self
.assertRegex(output
, 'oseq')
1309 output
= check_output('ip -d link show gretap98')
1311 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
1312 self
.assertRegex(output
, 'ikey 0.0.0.107')
1313 self
.assertRegex(output
, 'okey 0.0.0.107')
1314 self
.assertRegex(output
, 'iseq')
1315 self
.assertRegex(output
, 'oseq')
1317 def test_ip6gretap_tunnel(self
):
1318 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
1319 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1320 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1322 self
.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
1324 output
= check_output('ip -d link show ip6gretap99')
1326 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1327 output
= check_output('ip -d link show ip6gretap98')
1329 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1331 def test_vti_tunnel(self
):
1332 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
1333 '25-vti-tunnel.netdev', '25-tunnel.network',
1334 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1335 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1336 '25-vti-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1338 self
.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'vtitun96:routable', 'dummy98:degraded'])
1340 output
= check_output('ip -d link show vtitun99')
1342 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1343 output
= check_output('ip -d link show vtitun98')
1345 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
1346 output
= check_output('ip -d link show vtitun97')
1348 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
1349 output
= check_output('ip -d link show vtitun96')
1351 self
.assertRegex(output
, 'vti remote any local any dev dummy98')
1353 def test_vti6_tunnel(self
):
1354 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
1355 '25-vti6-tunnel.netdev', '25-tunnel.network',
1356 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1357 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1359 self
.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
1361 output
= check_output('ip -d link show vti6tun99')
1363 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1364 output
= check_output('ip -d link show vti6tun98')
1366 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1367 output
= check_output('ip -d link show vti6tun97')
1369 self
.assertRegex(output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1371 def test_ip6tnl_tunnel(self
):
1372 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
1373 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1374 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1375 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1377 self
.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
1379 output
= check_output('ip -d link show ip6tnl99')
1381 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1382 output
= check_output('ip -d link show ip6tnl98')
1384 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1385 output
= check_output('ip -d link show ip6tnl97')
1387 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1389 def test_sit_tunnel(self
):
1390 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1391 '25-sit-tunnel.netdev', '25-tunnel.network',
1392 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1393 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1394 '25-sit-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1396 self
.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'sittun96:routable', 'dummy98:degraded'])
1398 output
= check_output('ip -d link show sittun99')
1400 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1401 output
= check_output('ip -d link show sittun98')
1403 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98")
1404 output
= check_output('ip -d link show sittun97')
1406 self
.assertRegex(output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98")
1407 output
= check_output('ip -d link show sittun96')
1409 self
.assertRegex(output
, "sit (ip6ip )?remote any local any dev dummy98")
1411 def test_isatap_tunnel(self
):
1412 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1413 '25-isatap-tunnel.netdev', '25-tunnel.network')
1415 self
.wait_online(['isataptun99:routable', 'dummy98:degraded'])
1417 output
= check_output('ip -d link show isataptun99')
1419 self
.assertRegex(output
, "isatap ")
1421 def test_6rd_tunnel(self
):
1422 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1423 '25-6rd-tunnel.netdev', '25-tunnel.network')
1425 self
.wait_online(['sittun99:routable', 'dummy98:degraded'])
1427 output
= check_output('ip -d link show sittun99')
1429 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1431 @expectedFailureIfERSPANModuleIsNotAvailable()
1432 def test_erspan_tunnel(self
):
1433 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1434 '25-erspan-tunnel.netdev', '25-tunnel.network',
1435 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1437 self
.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1439 output
= check_output('ip -d link show erspan99')
1441 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1442 self
.assertRegex(output
, 'ikey 0.0.0.101')
1443 self
.assertRegex(output
, 'okey 0.0.0.101')
1444 self
.assertRegex(output
, 'iseq')
1445 self
.assertRegex(output
, 'oseq')
1446 output
= check_output('ip -d link show erspan98')
1448 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1449 self
.assertRegex(output
, '102')
1450 self
.assertRegex(output
, 'ikey 0.0.0.102')
1451 self
.assertRegex(output
, 'okey 0.0.0.102')
1452 self
.assertRegex(output
, 'iseq')
1453 self
.assertRegex(output
, 'oseq')
1455 def test_tunnel_independent(self
):
1456 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1459 self
.wait_online(['ipiptun99:carrier'])
1461 def test_tunnel_independent_loopback(self
):
1462 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent-loopback.netdev', 'netdev-link-local-addressing-yes.network')
1465 self
.wait_online(['ipiptun99:carrier'])
1467 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1468 def test_xfrm(self
):
1469 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'xfrm.network',
1470 '25-xfrm.netdev', 'netdev-link-local-addressing-yes.network')
1473 self
.wait_online(['xfrm99:degraded', 'dummy98:degraded'])
1475 output
= check_output('ip link show dev xfrm99')
1478 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1479 def test_xfrm_independent(self
):
1480 copy_unit_to_networkd_unit_path('25-xfrm-independent.netdev', 'netdev-link-local-addressing-yes.network')
1483 self
.wait_online(['xfrm99:degraded'])
1485 @expectedFailureIfModuleIsNotAvailable('fou')
1487 # The following redundant check is necessary for CentOS CI.
1488 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1489 self
.assertTrue(is_module_available('fou'))
1491 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1492 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1493 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1496 self
.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'], setup_state
='unmanaged')
1498 output
= check_output('ip fou show')
1500 self
.assertRegex(output
, 'port 55555 ipproto 4')
1501 self
.assertRegex(output
, 'port 55556 ipproto 47')
1503 output
= check_output('ip -d link show ipiptun96')
1505 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1506 output
= check_output('ip -d link show sittun96')
1508 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1509 output
= check_output('ip -d link show gretun96')
1511 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1512 output
= check_output('ip -d link show gretap96')
1514 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1516 def test_vxlan(self
):
1517 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1518 '11-dummy.netdev', 'vxlan-test1.network')
1521 self
.wait_online(['test1:degraded', 'vxlan99:degraded'])
1523 output
= check_output('ip -d link show vxlan99')
1525 self
.assertRegex(output
, '999')
1526 self
.assertRegex(output
, '5555')
1527 self
.assertRegex(output
, 'l2miss')
1528 self
.assertRegex(output
, 'l3miss')
1529 self
.assertRegex(output
, 'udpcsum')
1530 self
.assertRegex(output
, 'udp6zerocsumtx')
1531 self
.assertRegex(output
, 'udp6zerocsumrx')
1532 self
.assertRegex(output
, 'remcsumtx')
1533 self
.assertRegex(output
, 'remcsumrx')
1534 self
.assertRegex(output
, 'gbp')
1536 output
= check_output('bridge fdb show dev vxlan99')
1538 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1539 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1540 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1542 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'vxlan99', env
=env
)
1544 self
.assertRegex(output
, 'VNI: 999')
1545 self
.assertRegex(output
, 'Destination Port: 5555')
1546 self
.assertRegex(output
, 'Underlying Device: test1')
1548 def test_macsec(self
):
1549 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1550 'macsec.network', '12-dummy.netdev')
1553 self
.wait_online(['dummy98:degraded', 'macsec99:routable'])
1555 output
= check_output('ip -d link show macsec99')
1557 self
.assertRegex(output
, 'macsec99@dummy98')
1558 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1559 self
.assertRegex(output
, 'encrypt on')
1561 output
= check_output('ip macsec show macsec99')
1563 self
.assertRegex(output
, 'encrypt on')
1564 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1565 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1566 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1567 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1568 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1569 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1570 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1571 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1572 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1573 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1574 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1576 def test_nlmon(self
):
1577 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1580 self
.wait_online(['nlmon99:carrier'])
1582 @expectedFailureIfModuleIsNotAvailable('ifb')
1584 copy_unit_to_networkd_unit_path('25-ifb.netdev', 'netdev-link-local-addressing-yes.network')
1587 self
.wait_online(['ifb99:degraded'])
1589 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1600 '25-l2tp-dummy.network',
1602 '25-l2tp-ip.netdev',
1603 '25-l2tp-udp.netdev']
1605 l2tp_tunnel_ids
= [ '10' ]
1608 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1609 remove_links(self
.links
)
1610 stop_networkd(show_logs
=False)
1613 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1614 remove_links(self
.links
)
1615 remove_unit_from_networkd_path(self
.units
)
1616 stop_networkd(show_logs
=True)
1618 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1619 def test_l2tp_udp(self
):
1620 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1621 '25-l2tp-udp.netdev', '25-l2tp.network')
1624 self
.wait_online(['test1:routable', 'l2tp-ses1:degraded', 'l2tp-ses2:degraded'])
1626 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1628 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1629 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1630 self
.assertRegex(output
, "Peer tunnel 11")
1631 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1632 self
.assertRegex(output
, "UDP checksum: enabled")
1634 output
= check_output('ip l2tp show session tid 10 session_id 15')
1636 self
.assertRegex(output
, "Session 15 in tunnel 10")
1637 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1638 self
.assertRegex(output
, "interface name: l2tp-ses1")
1640 output
= check_output('ip l2tp show session tid 10 session_id 17')
1642 self
.assertRegex(output
, "Session 17 in tunnel 10")
1643 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1644 self
.assertRegex(output
, "interface name: l2tp-ses2")
1646 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1647 def test_l2tp_ip(self
):
1648 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1649 '25-l2tp-ip.netdev', '25-l2tp.network')
1652 self
.wait_online(['test1:routable', 'l2tp-ses3:degraded', 'l2tp-ses4:degraded'])
1654 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1656 self
.assertRegex(output
, "Tunnel 10, encap IP")
1657 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1658 self
.assertRegex(output
, "Peer tunnel 12")
1660 output
= check_output('ip l2tp show session tid 10 session_id 25')
1662 self
.assertRegex(output
, "Session 25 in tunnel 10")
1663 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1664 self
.assertRegex(output
, "interface name: l2tp-ses3")
1666 output
= check_output('ip l2tp show session tid 10 session_id 27')
1668 self
.assertRegex(output
, "Session 27 in tunnel 10")
1669 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1670 self
.assertRegex(output
, "interface name: l2tp-ses4")
1672 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1687 '23-active-slave.network',
1688 '24-keep-configuration-static.network',
1689 '24-search-domain.network',
1690 '25-address-dad-veth-peer.network',
1691 '25-address-dad-veth99.network',
1692 '25-address-link-section.network',
1693 '25-address-preferred-lifetime-zero.network',
1694 '25-address-static.network',
1695 '25-bind-carrier.network',
1696 '25-bond-active-backup-slave.netdev',
1697 '25-fibrule-invert.network',
1698 '25-fibrule-port-range.network',
1699 '25-fibrule-uidrange.network',
1700 '25-gre-tunnel-remote-any.netdev',
1701 '25-ip6gre-tunnel-remote-any.netdev',
1702 '25-ipv6-address-label-section.network',
1703 '25-link-local-addressing-no.network',
1704 '25-link-local-addressing-yes.network',
1705 '25-link-section-unmanaged.network',
1706 '25-neighbor-section.network',
1707 '25-neighbor-next.network',
1708 '25-neighbor-ipv6.network',
1709 '25-neighbor-ip-dummy.network',
1710 '25-neighbor-ip.network',
1711 '25-nexthop.network',
1712 '25-qdisc-cake.network',
1713 '25-qdisc-clsact-and-htb.network',
1714 '25-qdisc-drr.network',
1715 '25-qdisc-ets.network',
1716 '25-qdisc-hhf.network',
1717 '25-qdisc-ingress-netem-compat.network',
1718 '25-qdisc-pie.network',
1719 '25-qdisc-qfq.network',
1720 '25-route-ipv6-src.network',
1721 '25-route-static.network',
1722 '25-route-vrf.network',
1723 '25-gateway-static.network',
1724 '25-gateway-next-static.network',
1726 '25-sysctl-disable-ipv6.network',
1727 '25-sysctl.network',
1729 '25-veth-peer.network',
1732 '26-link-local-addressing-ipv6.network',
1733 'routing-policy-rule-dummy98.network',
1734 'routing-policy-rule-test1.network']
1736 routing_policy_rule_tables
= ['7', '8', '9']
1737 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1740 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1741 remove_routes(self
.routes
)
1742 remove_links(self
.links
)
1743 stop_networkd(show_logs
=False)
1746 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1747 remove_routes(self
.routes
)
1748 remove_links(self
.links
)
1749 remove_unit_from_networkd_path(self
.units
)
1750 stop_networkd(show_logs
=True)
1752 def test_address_static(self
):
1753 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1756 self
.wait_online(['dummy98:routable'])
1758 output
= check_output('ip -4 address show dev dummy98')
1760 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1761 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1762 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1765 self
.assertNotRegex(output
, '10.10.0.1/16')
1766 self
.assertNotRegex(output
, '10.10.0.2/16')
1768 output
= check_output('ip -4 address show dev dummy98 label 32')
1769 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1771 output
= check_output('ip -4 address show dev dummy98 label 33')
1772 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1774 output
= check_output('ip -4 address show dev dummy98 label 34')
1775 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1777 output
= check_output('ip -4 address show dev dummy98 label 35')
1778 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1780 output
= check_output('ip -6 address show dev dummy98')
1782 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1783 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1784 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1785 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1786 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1787 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1789 def test_address_preferred_lifetime_zero_ipv6(self
):
1790 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero.network', '12-dummy.netdev')
1793 self
.wait_online(['dummy98:routable'])
1795 output
= check_output('ip address show dummy98')
1797 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1798 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1800 output
= check_output('ip route show dev dummy98')
1802 self
.assertRegex(output
, 'default via 20.20.20.1 proto static')
1804 def test_address_dad(self
):
1805 copy_unit_to_networkd_unit_path('25-address-dad-veth99.network', '25-address-dad-veth-peer.network',
1808 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
1810 output
= check_output('ip -4 address show dev veth99')
1812 self
.assertRegex(output
, '192.168.100.10/24')
1814 output
= check_output('ip -4 address show dev veth-peer')
1816 self
.assertNotRegex(output
, '192.168.100.10/24')
1818 def test_configure_without_carrier(self
):
1819 copy_unit_to_networkd_unit_path('11-dummy.netdev')
1821 self
.wait_operstate('test1', 'off', '')
1822 check_output('ip link set dev test1 up carrier off')
1824 copy_unit_to_networkd_unit_path('25-test1.network.d/configure-without-carrier.conf', dropins
=False)
1826 self
.wait_online(['test1:no-carrier'])
1828 carrier_map
= {'on': '1', 'off': '0'}
1829 routable_map
= {'on': 'routable', 'off': 'no-carrier'}
1830 for carrier
in ['off', 'on', 'off']:
1831 with self
.subTest(carrier
=carrier
):
1832 if carrier_map
[carrier
] != read_link_attr('test1', 'carrier'):
1833 check_output(f
'ip link set dev test1 carrier {carrier}')
1834 self
.wait_online([f
'test1:{routable_map[carrier]}'])
1836 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
1838 self
.assertRegex(output
, '192.168.0.15')
1839 self
.assertRegex(output
, '192.168.0.1')
1840 self
.assertRegex(output
, routable_map
[carrier
])
1842 def test_configure_without_carrier_yes_ignore_carrier_loss_no(self
):
1843 copy_unit_to_networkd_unit_path('11-dummy.netdev')
1845 self
.wait_operstate('test1', 'off', '')
1846 check_output('ip link set dev test1 up carrier off')
1848 copy_unit_to_networkd_unit_path('25-test1.network')
1850 self
.wait_online(['test1:no-carrier'])
1852 carrier_map
= {'on': '1', 'off': '0'}
1853 routable_map
= {'on': 'routable', 'off': 'no-carrier'}
1854 for (carrier
, have_config
) in [('off', True), ('on', True), ('off', False)]:
1855 with self
.subTest(carrier
=carrier
, have_config
=have_config
):
1856 if carrier_map
[carrier
] != read_link_attr('test1', 'carrier'):
1857 check_output(f
'ip link set dev test1 carrier {carrier}')
1858 self
.wait_online([f
'test1:{routable_map[carrier]}'])
1860 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'test1', env
=env
)
1863 self
.assertRegex(output
, '192.168.0.15')
1864 self
.assertRegex(output
, '192.168.0.1')
1866 self
.assertNotRegex(output
, '192.168.0.15')
1867 self
.assertNotRegex(output
, '192.168.0.1')
1868 self
.assertRegex(output
, routable_map
[carrier
])
1870 def test_routing_policy_rule(self
):
1871 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1873 self
.wait_online(['test1:degraded'])
1875 output
= check_output('ip rule list iif test1 priority 111')
1877 self
.assertRegex(output
, '111:')
1878 self
.assertRegex(output
, 'from 192.168.100.18')
1879 self
.assertRegex(output
, r
'tos (0x08|throughput)\s')
1880 self
.assertRegex(output
, 'iif test1')
1881 self
.assertRegex(output
, 'oif test1')
1882 self
.assertRegex(output
, 'lookup 7')
1884 output
= check_output('ip rule list iif test1 priority 101')
1886 self
.assertRegex(output
, '101:')
1887 self
.assertRegex(output
, 'from all')
1888 self
.assertRegex(output
, 'iif test1')
1889 self
.assertRegex(output
, 'lookup 9')
1891 output
= check_output('ip -6 rule list iif test1 priority 100')
1893 self
.assertRegex(output
, '100:')
1894 self
.assertRegex(output
, 'from all')
1895 self
.assertRegex(output
, 'iif test1')
1896 self
.assertRegex(output
, 'lookup 8')
1898 output
= check_output('ip -6 rule list iif test1 priority 101')
1900 self
.assertRegex(output
, '101:')
1901 self
.assertRegex(output
, 'from all')
1902 self
.assertRegex(output
, 'iif test1')
1903 self
.assertRegex(output
, 'lookup 9')
1905 def test_routing_policy_rule_issue_11280(self
):
1906 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1907 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1909 for trial
in range(3):
1910 # Remove state files only first time
1912 self
.wait_online(['test1:degraded', 'dummy98:degraded'])
1915 output
= check_output('ip rule list table 7')
1917 self
.assertRegex(output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
1919 output
= check_output('ip rule list table 8')
1921 self
.assertRegex(output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1923 stop_networkd(remove_state_files
=False)
1925 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1926 def test_routing_policy_rule_port_range(self
):
1927 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1929 self
.wait_online(['test1:degraded'])
1931 output
= check_output('ip rule')
1933 self
.assertRegex(output
, '111')
1934 self
.assertRegex(output
, 'from 192.168.100.18')
1935 self
.assertRegex(output
, '1123-1150')
1936 self
.assertRegex(output
, '3224-3290')
1937 self
.assertRegex(output
, 'tcp')
1938 self
.assertRegex(output
, 'lookup 7')
1940 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1941 def test_routing_policy_rule_invert(self
):
1942 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1944 self
.wait_online(['test1:degraded'])
1946 output
= check_output('ip rule')
1948 self
.assertRegex(output
, '111')
1949 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
1950 self
.assertRegex(output
, 'tcp')
1951 self
.assertRegex(output
, 'lookup 7')
1953 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable()
1954 def test_routing_policy_rule_uidrange(self
):
1955 copy_unit_to_networkd_unit_path('25-fibrule-uidrange.network', '11-dummy.netdev')
1957 self
.wait_online(['test1:degraded'])
1959 output
= check_output('ip rule')
1961 self
.assertRegex(output
, '111')
1962 self
.assertRegex(output
, 'from 192.168.100.18')
1963 self
.assertRegex(output
, 'lookup 7')
1964 self
.assertRegex(output
, 'uidrange 100-200')
1966 def test_route_static(self
):
1967 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1969 self
.wait_online(['dummy98:routable'])
1971 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
1974 print('### ip -6 route show dev dummy98')
1975 output
= check_output('ip -6 route show dev dummy98')
1977 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1978 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
1980 print('### ip -6 route show dev dummy98 default')
1981 output
= check_output('ip -6 route show dev dummy98 default')
1983 self
.assertRegex(output
, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1985 print('### ip -4 route show dev dummy98')
1986 output
= check_output('ip -4 route show dev dummy98')
1988 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1989 self
.assertRegex(output
, '149.10.124.64 proto static scope link')
1990 self
.assertRegex(output
, '169.254.0.0/16 proto static scope link metric 2048')
1991 self
.assertRegex(output
, '192.168.1.1 proto static initcwnd 20')
1992 self
.assertRegex(output
, '192.168.1.2 proto static initrwnd 30')
1993 self
.assertRegex(output
, 'multicast 149.10.123.4 proto static')
1995 print('### ip -4 route show dev dummy98 default')
1996 output
= check_output('ip -4 route show dev dummy98 default')
1998 self
.assertRegex(output
, 'default via 149.10.125.65 proto static onlink')
1999 self
.assertRegex(output
, 'default via 149.10.124.64 proto static')
2000 self
.assertRegex(output
, 'default proto static')
2002 print('### ip -4 route show table local dev dummy98')
2003 output
= check_output('ip -4 route show table local dev dummy98')
2005 self
.assertRegex(output
, 'local 149.10.123.1 proto static scope host')
2006 self
.assertRegex(output
, 'anycast 149.10.123.2 proto static scope link')
2007 self
.assertRegex(output
, 'broadcast 149.10.123.3 proto static scope link')
2009 print('### ip route show type blackhole')
2010 output
= check_output('ip route show type blackhole')
2012 self
.assertRegex(output
, 'blackhole 202.54.1.2 proto static')
2014 print('### ip route show type unreachable')
2015 output
= check_output('ip route show type unreachable')
2017 self
.assertRegex(output
, 'unreachable 202.54.1.3 proto static')
2019 print('### ip route show type prohibit')
2020 output
= check_output('ip route show type prohibit')
2022 self
.assertRegex(output
, 'prohibit 202.54.1.4 proto static')
2024 print('### ip route show 192.168.10.1')
2025 output
= check_output('ip route show 192.168.10.1')
2027 self
.assertRegex(output
, '192.168.10.1 proto static')
2028 self
.assertRegex(output
, 'nexthop via 149.10.124.59 dev dummy98 weight 10')
2029 self
.assertRegex(output
, 'nexthop via 149.10.124.60 dev dummy98 weight 5')
2031 print('### ip route show 192.168.10.2')
2032 output
= check_output('ip route show 192.168.10.2')
2034 # old ip command does not show IPv6 gateways...
2035 self
.assertRegex(output
, '192.168.10.2 proto static')
2036 self
.assertRegex(output
, 'nexthop')
2037 self
.assertRegex(output
, 'dev dummy98 weight 10')
2038 self
.assertRegex(output
, 'dev dummy98 weight 5')
2040 print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2041 output
= check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2043 # old ip command does not show 'nexthop' keyword and weight...
2044 self
.assertRegex(output
, '2001:1234:5:7fff:ff:ff:ff:ff')
2045 self
.assertRegex(output
, 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98')
2046 self
.assertRegex(output
, 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98')
2048 @expectedFailureIfModuleIsNotAvailable('vrf')
2049 def test_route_vrf(self
):
2050 copy_unit_to_networkd_unit_path('25-route-vrf.network', '12-dummy.netdev',
2051 '25-vrf.netdev', '25-vrf.network')
2053 self
.wait_online(['dummy98:routable', 'vrf99:carrier'])
2055 output
= check_output('ip route show vrf vrf99')
2057 self
.assertRegex(output
, 'default via 192.168.100.1')
2059 output
= check_output('ip route show')
2061 self
.assertNotRegex(output
, 'default via 192.168.100.1')
2063 def test_gateway_reconfigure(self
):
2064 copy_unit_to_networkd_unit_path('25-gateway-static.network', '12-dummy.netdev')
2066 self
.wait_online(['dummy98:routable'])
2067 print('### ip -4 route show dev dummy98 default')
2068 output
= check_output('ip -4 route show dev dummy98 default')
2070 self
.assertRegex(output
, 'default via 149.10.124.59 proto static')
2071 self
.assertNotRegex(output
, '149.10.124.60')
2073 remove_unit_from_networkd_path(['25-gateway-static.network'])
2074 copy_unit_to_networkd_unit_path('25-gateway-next-static.network')
2076 self
.wait_online(['dummy98:routable'])
2077 print('### ip -4 route show dev dummy98 default')
2078 output
= check_output('ip -4 route show dev dummy98 default')
2080 self
.assertNotRegex(output
, '149.10.124.59')
2081 self
.assertRegex(output
, 'default via 149.10.124.60 proto static')
2083 def test_ip_route_ipv6_src_route(self
):
2084 # a dummy device does not make the addresses go through tentative state, so we
2085 # reuse a bond from an earlier test, which does make the addresses go through
2086 # tentative state, and do our test on that
2087 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2089 self
.wait_online(['dummy98:enslaved', 'bond199:routable'])
2091 output
= check_output('ip -6 route list dev bond199')
2093 self
.assertRegex(output
, 'abcd::/16')
2094 self
.assertRegex(output
, 'src')
2095 self
.assertRegex(output
, '2001:1234:56:8f63::2')
2097 def test_ip_link_mac_address(self
):
2098 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
2100 self
.wait_online(['dummy98:degraded'])
2102 output
= check_output('ip link show dummy98')
2104 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
2106 def test_ip_link_unmanaged(self
):
2107 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
2110 self
.check_link_exists('dummy98')
2112 self
.wait_operstate('dummy98', 'off', setup_state
='unmanaged')
2114 def test_ipv6_address_label(self
):
2115 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
2117 self
.wait_online(['dummy98:degraded'])
2119 output
= check_output('ip addrlabel list')
2121 self
.assertRegex(output
, '2004:da8:1::/64')
2123 def test_neighbor_section(self
):
2124 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2126 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2128 print('### ip neigh list dev dummy98')
2129 output
= check_output('ip neigh list dev dummy98')
2131 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2132 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2134 def test_neighbor_reconfigure(self
):
2135 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2137 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2139 print('### ip neigh list dev dummy98')
2140 output
= check_output('ip neigh list dev dummy98')
2142 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2143 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2145 remove_unit_from_networkd_path(['25-neighbor-section.network'])
2146 copy_unit_to_networkd_unit_path('25-neighbor-next.network')
2148 self
.wait_online(['dummy98:degraded'], timeout
='40s')
2149 print('### ip neigh list dev dummy98')
2150 output
= check_output('ip neigh list dev dummy98')
2152 self
.assertNotRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2153 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT')
2154 self
.assertNotRegex(output
, '2004:da8:1::1.*PERMANENT')
2156 def test_neighbor_gre(self
):
2157 copy_unit_to_networkd_unit_path('25-neighbor-ip.network', '25-neighbor-ipv6.network', '25-neighbor-ip-dummy.network',
2158 '12-dummy.netdev', '25-gre-tunnel-remote-any.netdev', '25-ip6gre-tunnel-remote-any.netdev')
2160 self
.wait_online(['dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable'], timeout
='40s')
2162 output
= check_output('ip neigh list dev gretun97')
2164 self
.assertRegex(output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT')
2166 output
= check_output('ip neigh list dev ip6gretun97')
2168 self
.assertRegex(output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
2170 def test_link_local_addressing(self
):
2171 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
2172 '25-link-local-addressing-no.network', '12-dummy.netdev')
2174 self
.wait_online(['test1:degraded', 'dummy98:carrier'])
2176 output
= check_output('ip address show dev test1')
2178 self
.assertRegex(output
, 'inet .* scope link')
2179 self
.assertRegex(output
, 'inet6 .* scope link')
2181 output
= check_output('ip address show dev dummy98')
2183 self
.assertNotRegex(output
, 'inet6* .* scope link')
2186 Documentation/networking/ip-sysctl.txt
2188 addr_gen_mode - INTEGER
2189 Defines how link-local and autoconf addresses are generated.
2191 0: generate address based on EUI64 (default)
2192 1: do no generate a link-local address, use EUI64 for addresses generated
2194 2: generate stable privacy addresses, using the secret from
2195 stable_secret (RFC7217)
2196 3: generate stable privacy addresses, using a random secret if unset
2199 test1_addr_gen_mode
= ''
2200 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
2201 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
2205 # if stable_secret is unset, then EIO is returned
2206 test1_addr_gen_mode
= '0'
2208 test1_addr_gen_mode
= '2'
2210 test1_addr_gen_mode
= '0'
2212 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
2213 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
2215 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
2216 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
2218 def test_link_local_addressing_remove_ipv6ll(self
):
2219 copy_unit_to_networkd_unit_path('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
2221 self
.wait_online(['dummy98:degraded'])
2223 output
= check_output('ip address show dev dummy98')
2225 self
.assertRegex(output
, 'inet6 .* scope link')
2227 copy_unit_to_networkd_unit_path('25-link-local-addressing-no.network')
2229 self
.wait_online(['dummy98:carrier'])
2231 output
= check_output('ip address show dev dummy98')
2233 self
.assertNotRegex(output
, 'inet6* .* scope link')
2235 def test_sysctl(self
):
2236 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
2238 self
.wait_online(['dummy98:degraded'])
2240 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
2241 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
2242 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
2243 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
2244 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
2245 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
2246 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
2247 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'accept_local'), '1')
2249 def test_sysctl_disable_ipv6(self
):
2250 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
2252 print('## Disable ipv6')
2253 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
2254 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
2257 self
.wait_online(['dummy98:routable'])
2259 output
= check_output('ip -4 address show dummy98')
2261 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2262 output
= check_output('ip -6 address show dummy98')
2264 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2265 self
.assertRegex(output
, 'inet6 .* scope link')
2266 output
= check_output('ip -4 route show dev dummy98')
2268 self
.assertRegex(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2269 output
= check_output('ip -6 route show dev dummy98')
2271 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2273 check_output('ip link del dummy98')
2275 print('## Enable ipv6')
2276 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
2277 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
2280 self
.wait_online(['dummy98:routable'])
2282 output
= check_output('ip -4 address show dummy98')
2284 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2285 output
= check_output('ip -6 address show dummy98')
2287 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2288 self
.assertRegex(output
, 'inet6 .* scope link')
2289 output
= check_output('ip -4 route show dev dummy98')
2291 self
.assertRegex(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2292 output
= check_output('ip -6 route show dev dummy98')
2294 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2296 def test_bind_carrier(self
):
2297 check_output('ip link add dummy98 type dummy')
2298 check_output('ip link set dummy98 up')
2301 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
2303 self
.wait_online(['test1:routable'])
2305 output
= check_output('ip address show test1')
2307 self
.assertRegex(output
, 'UP,LOWER_UP')
2308 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2309 self
.wait_operstate('test1', 'routable')
2311 check_output('ip link add dummy99 type dummy')
2312 check_output('ip link set dummy99 up')
2314 output
= check_output('ip address show test1')
2316 self
.assertRegex(output
, 'UP,LOWER_UP')
2317 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2318 self
.wait_operstate('test1', 'routable')
2320 check_output('ip link del dummy98')
2322 output
= check_output('ip address show test1')
2324 self
.assertRegex(output
, 'UP,LOWER_UP')
2325 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2326 self
.wait_operstate('test1', 'routable')
2328 check_output('ip link set dummy99 down')
2330 output
= check_output('ip address show test1')
2332 self
.assertNotRegex(output
, 'UP,LOWER_UP')
2333 self
.assertRegex(output
, 'DOWN')
2334 self
.assertNotRegex(output
, '192.168.10')
2335 self
.wait_operstate('test1', 'off')
2337 check_output('ip link set dummy99 up')
2339 output
= check_output('ip address show test1')
2341 self
.assertRegex(output
, 'UP,LOWER_UP')
2342 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2343 self
.wait_operstate('test1', 'routable')
2345 def test_domain(self
):
2346 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
2348 self
.wait_online(['dummy98:routable'])
2350 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'dummy98', env
=env
)
2352 self
.assertRegex(output
, 'Address: 192.168.42.100')
2353 self
.assertRegex(output
, 'DNS: 192.168.42.1')
2354 self
.assertRegex(output
, 'Search Domains: one')
2356 def test_keep_configuration_static(self
):
2357 check_output('systemctl stop systemd-networkd')
2359 check_output('ip link add name dummy98 type dummy')
2360 check_output('ip address add 10.1.2.3/16 dev dummy98')
2361 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
2362 output
= check_output('ip address show dummy98')
2364 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2365 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2366 output
= check_output('ip route show dev dummy98')
2369 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
2371 self
.wait_online(['dummy98:routable'])
2373 output
= check_output('ip address show dummy98')
2375 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2376 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2378 @expectedFailureIfNexthopIsNotAvailable()
2379 def test_nexthop(self
):
2380 copy_unit_to_networkd_unit_path('25-nexthop.network', '25-veth.netdev', '25-veth-peer.network')
2382 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2384 output
= check_output('ip nexthop list dev veth99')
2386 self
.assertRegex(output
, '192.168.5.1')
2388 def test_qdisc(self
):
2389 copy_unit_to_networkd_unit_path('25-qdisc-clsact-and-htb.network', '12-dummy.netdev',
2390 '25-qdisc-ingress-netem-compat.network', '11-dummy.netdev')
2391 check_output('modprobe sch_teql max_equalizers=2')
2394 self
.wait_online(['dummy98:routable', 'test1:routable'])
2396 output
= check_output('tc qdisc show dev test1')
2398 self
.assertRegex(output
, 'qdisc netem')
2399 self
.assertRegex(output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
2400 self
.assertRegex(output
, 'qdisc ingress')
2402 output
= check_output('tc qdisc show dev dummy98')
2404 self
.assertRegex(output
, 'qdisc clsact')
2406 self
.assertRegex(output
, 'qdisc htb 2: root')
2407 self
.assertRegex(output
, r
'default (0x30|30)')
2409 self
.assertRegex(output
, 'qdisc netem 30: parent 2:30')
2410 self
.assertRegex(output
, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
2411 self
.assertRegex(output
, 'qdisc fq_codel')
2412 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')
2414 self
.assertRegex(output
, 'qdisc teql1 31: parent 2:31')
2416 self
.assertRegex(output
, 'qdisc fq 32: parent 2:32')
2417 self
.assertRegex(output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
2418 self
.assertRegex(output
, 'quantum 1500')
2419 self
.assertRegex(output
, 'initial_quantum 13000')
2420 self
.assertRegex(output
, 'maxrate 1Mbit')
2422 self
.assertRegex(output
, 'qdisc codel 33: parent 2:33')
2423 self
.assertRegex(output
, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn')
2425 self
.assertRegex(output
, 'qdisc fq_codel 34: parent 2:34')
2426 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')
2428 self
.assertRegex(output
, 'qdisc tbf 35: parent 2:35')
2429 self
.assertRegex(output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms')
2431 self
.assertRegex(output
, 'qdisc sfq 36: parent 2:36')
2432 self
.assertRegex(output
, 'perturb 5sec')
2434 self
.assertRegex(output
, 'qdisc pfifo 37: parent 2:37')
2435 self
.assertRegex(output
, 'limit 100000p')
2437 self
.assertRegex(output
, 'qdisc gred 38: parent 2:38')
2438 self
.assertRegex(output
, 'vqs 12 default 10 grio')
2440 self
.assertRegex(output
, 'qdisc sfb 39: parent 2:39')
2441 self
.assertRegex(output
, 'limit 200000')
2443 self
.assertRegex(output
, 'qdisc bfifo 3a: parent 2:3a')
2444 self
.assertRegex(output
, 'limit 1000000')
2446 self
.assertRegex(output
, 'qdisc pfifo_head_drop 3b: parent 2:3b')
2447 self
.assertRegex(output
, 'limit 1023p')
2449 self
.assertRegex(output
, 'qdisc pfifo_fast 3c: parent 2:3c')
2451 output
= check_output('tc -d class show dev dummy98')
2453 self
.assertRegex(output
, 'class htb 2:30 root leaf 30:')
2454 self
.assertRegex(output
, 'class htb 2:31 root leaf 31:')
2455 self
.assertRegex(output
, 'class htb 2:32 root leaf 32:')
2456 self
.assertRegex(output
, 'class htb 2:33 root leaf 33:')
2457 self
.assertRegex(output
, 'class htb 2:34 root leaf 34:')
2458 self
.assertRegex(output
, 'class htb 2:35 root leaf 35:')
2459 self
.assertRegex(output
, 'class htb 2:36 root leaf 36:')
2460 self
.assertRegex(output
, 'class htb 2:37 root leaf 37:')
2461 self
.assertRegex(output
, 'class htb 2:38 root leaf 38:')
2462 self
.assertRegex(output
, 'class htb 2:39 root leaf 39:')
2463 self
.assertRegex(output
, 'class htb 2:3a root leaf 3a:')
2464 self
.assertRegex(output
, 'class htb 2:3b root leaf 3b:')
2465 self
.assertRegex(output
, 'class htb 2:3c root leaf 3c:')
2466 self
.assertRegex(output
, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit')
2467 self
.assertRegex(output
, 'burst 123456')
2468 self
.assertRegex(output
, 'cburst 123457')
2470 def test_qdisc2(self
):
2471 copy_unit_to_networkd_unit_path('25-qdisc-drr.network', '12-dummy.netdev',
2472 '25-qdisc-qfq.network', '11-dummy.netdev')
2475 self
.wait_online(['dummy98:routable', 'test1:routable'])
2477 output
= check_output('tc qdisc show dev dummy98')
2479 self
.assertRegex(output
, 'qdisc drr 2: root')
2480 output
= check_output('tc class show dev dummy98')
2482 self
.assertRegex(output
, 'class drr 2:30 root quantum 2000b')
2484 output
= check_output('tc qdisc show dev test1')
2486 self
.assertRegex(output
, 'qdisc qfq 2: root')
2487 output
= check_output('tc class show dev test1')
2489 self
.assertRegex(output
, 'class qfq 2:30 root weight 2 maxpkt 16000')
2490 self
.assertRegex(output
, 'class qfq 2:31 root weight 10 maxpkt 8000')
2492 @expectedFailureIfCAKEIsNotAvailable()
2493 def test_qdisc_cake(self
):
2494 copy_unit_to_networkd_unit_path('25-qdisc-cake.network', '12-dummy.netdev')
2496 self
.wait_online(['dummy98:routable'])
2498 output
= check_output('tc qdisc show dev dummy98')
2500 self
.assertRegex(output
, 'qdisc cake 3a: root')
2501 self
.assertRegex(output
, 'bandwidth 500Mbit')
2502 self
.assertRegex(output
, 'overhead 128')
2504 @expectedFailureIfPIEIsNotAvailable()
2505 def test_qdisc_pie(self
):
2506 copy_unit_to_networkd_unit_path('25-qdisc-pie.network', '12-dummy.netdev')
2508 self
.wait_online(['dummy98:routable'])
2510 output
= check_output('tc qdisc show dev dummy98')
2512 self
.assertRegex(output
, 'qdisc pie 3a: root')
2513 self
.assertRegex(output
, 'limit 200000')
2515 @expectedFailureIfHHFIsNotAvailable()
2516 def test_qdisc_hhf(self
):
2517 copy_unit_to_networkd_unit_path('25-qdisc-hhf.network', '12-dummy.netdev')
2519 self
.wait_online(['dummy98:routable'])
2521 output
= check_output('tc qdisc show dev dummy98')
2523 self
.assertRegex(output
, 'qdisc hhf 3a: root')
2524 self
.assertRegex(output
, 'limit 1022p')
2526 @expectedFailureIfETSIsNotAvailable()
2527 def test_qdisc_ets(self
):
2528 copy_unit_to_networkd_unit_path('25-qdisc-ets.network', '12-dummy.netdev')
2530 self
.wait_online(['dummy98:routable'])
2532 output
= check_output('tc qdisc show dev dummy98')
2534 self
.assertRegex(output
, 'qdisc ets 3a: root')
2535 self
.assertRegex(output
, 'bands 10 strict 3')
2536 self
.assertRegex(output
, 'quanta 1 2 3 4 5')
2537 self
.assertRegex(output
, 'priomap 3 4 5 6 7')
2539 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable()
2540 def test_sriov(self
):
2541 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
2542 call('modprobe netdevsim', stderr
=subprocess
.DEVNULL
)
2543 with
open('/sys/bus/netdevsim/new_device', mode
='w') as f
:
2546 call('udevadm settle')
2547 call('udevadm info -w10s /sys/devices/netdevsim99/net/eni99np1', stderr
=subprocess
.DEVNULL
)
2548 with
open('/sys/class/net/eni99np1/device/sriov_numvfs', mode
='w') as f
:
2551 copy_unit_to_networkd_unit_path('25-sriov.network')
2553 self
.wait_online(['eni99np1:routable'])
2555 output
= check_output('ip link show dev eni99np1')
2557 self
.assertRegex(output
,
2558 '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 *'
2559 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
2560 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
2563 call('rmmod netdevsim', stderr
=subprocess
.DEVNULL
)
2565 class NetworkdStateFileTests(unittest
.TestCase
, Utilities
):
2572 'state-file-tests.network',
2576 remove_links(self
.links
)
2577 stop_networkd(show_logs
=False)
2580 remove_links(self
.links
)
2581 remove_unit_from_networkd_path(self
.units
)
2582 stop_networkd(show_logs
=True)
2584 def test_state_file(self
):
2585 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'state-file-tests.network')
2587 self
.wait_online(['dummy98:routable'])
2589 output
= check_output(*networkctl_cmd
, '--no-legend', 'list', 'dummy98', env
=env
)
2591 ifindex
= output
.split()[0]
2593 path
= os
.path
.join('/run/systemd/netif/links/', ifindex
)
2594 self
.assertTrue(os
.path
.exists(path
))
2597 with
open(path
) as f
:
2599 self
.assertRegex(data
, r
'ADMIN_STATE=configured')
2600 self
.assertRegex(data
, r
'OPER_STATE=routable')
2601 self
.assertRegex(data
, r
'REQUIRED_FOR_ONLINE=yes')
2602 self
.assertRegex(data
, r
'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
2603 self
.assertRegex(data
, r
'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
2604 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
2605 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2606 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2607 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2608 self
.assertRegex(data
, r
'LLMNR=no')
2609 self
.assertRegex(data
, r
'MDNS=yes')
2610 self
.assertRegex(data
, r
'DNSSEC=no')
2611 self
.assertRegex(data
, r
'ADDRESSES=192.168.(10.10|12.12)/24 192.168.(12.12|10.10)/24')
2613 check_output(*resolvectl_cmd
, 'dns', 'dummy98', '10.10.10.12', '10.10.10.13', env
=env
)
2614 check_output(*resolvectl_cmd
, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env
=env
)
2615 check_output(*resolvectl_cmd
, 'llmnr', 'dummy98', 'yes', env
=env
)
2616 check_output(*resolvectl_cmd
, 'mdns', 'dummy98', 'no', env
=env
)
2617 check_output(*resolvectl_cmd
, 'dnssec', 'dummy98', 'yes', env
=env
)
2618 check_output(*timedatectl_cmd
, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env
=env
)
2621 with
open(path
) as f
:
2623 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
2624 self
.assertRegex(data
, r
'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org')
2625 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2626 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2627 self
.assertRegex(data
, r
'LLMNR=yes')
2628 self
.assertRegex(data
, r
'MDNS=no')
2629 self
.assertRegex(data
, r
'DNSSEC=yes')
2631 check_output(*timedatectl_cmd
, 'revert', 'dummy98', env
=env
)
2634 with
open(path
) as f
:
2636 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
2637 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2638 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2639 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2640 self
.assertRegex(data
, r
'LLMNR=yes')
2641 self
.assertRegex(data
, r
'MDNS=no')
2642 self
.assertRegex(data
, r
'DNSSEC=yes')
2644 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
2647 with
open(path
) as f
:
2649 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
2650 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2651 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2652 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2653 self
.assertRegex(data
, r
'LLMNR=no')
2654 self
.assertRegex(data
, r
'MDNS=yes')
2655 self
.assertRegex(data
, r
'DNSSEC=no')
2657 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
2667 '23-active-slave.network',
2668 '23-bond199.network',
2669 '23-primary-slave.network',
2670 '25-bond-active-backup-slave.netdev',
2673 'bond-slave.network']
2676 remove_links(self
.links
)
2677 stop_networkd(show_logs
=False)
2680 remove_links(self
.links
)
2681 remove_unit_from_networkd_path(self
.units
)
2682 stop_networkd(show_logs
=True)
2684 def test_bond_active_slave(self
):
2685 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2687 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2689 output
= check_output('ip -d link show bond199')
2691 self
.assertRegex(output
, 'active_slave dummy98')
2693 def test_bond_primary_slave(self
):
2694 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2696 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2698 output
= check_output('ip -d link show bond199')
2700 self
.assertRegex(output
, 'primary dummy98')
2702 def test_bond_operstate(self
):
2703 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
2704 'bond99.network','bond-slave.network')
2706 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
2708 output
= check_output('ip -d link show dummy98')
2710 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2712 output
= check_output('ip -d link show test1')
2714 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2716 output
= check_output('ip -d link show bond99')
2718 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
2720 self
.wait_operstate('dummy98', 'enslaved')
2721 self
.wait_operstate('test1', 'enslaved')
2722 self
.wait_operstate('bond99', 'routable')
2724 check_output('ip link set dummy98 down')
2726 self
.wait_operstate('dummy98', 'off')
2727 self
.wait_operstate('test1', 'enslaved')
2728 self
.wait_operstate('bond99', 'degraded-carrier')
2730 check_output('ip link set dummy98 up')
2732 self
.wait_operstate('dummy98', 'enslaved')
2733 self
.wait_operstate('test1', 'enslaved')
2734 self
.wait_operstate('bond99', 'routable')
2736 check_output('ip link set dummy98 down')
2737 check_output('ip link set test1 down')
2739 self
.wait_operstate('dummy98', 'off')
2740 self
.wait_operstate('test1', 'off')
2742 if not self
.wait_operstate('bond99', 'no-carrier', setup_timeout
=30, fail_assert
=False):
2743 # Huh? Kernel does not recognize that all slave interfaces are down?
2744 # Let's confirm that networkd's operstate is consistent with ip's result.
2745 self
.assertNotRegex(output
, 'NO-CARRIER')
2747 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
2757 '26-bridge-configure-without-carrier.network',
2758 '26-bridge-slave-interface-1.network',
2759 '26-bridge-slave-interface-2.network',
2760 '26-bridge-vlan-master.network',
2761 '26-bridge-vlan-slave.network',
2762 'bridge99-ignore-carrier-loss.network',
2765 routing_policy_rule_tables
= ['100']
2768 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2769 remove_links(self
.links
)
2770 stop_networkd(show_logs
=False)
2773 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2774 remove_links(self
.links
)
2775 remove_unit_from_networkd_path(self
.units
)
2776 stop_networkd(show_logs
=True)
2778 def test_bridge_vlan(self
):
2779 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
2780 '26-bridge.netdev', '26-bridge-vlan-master.network')
2782 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
2784 output
= check_output('bridge vlan show dev test1')
2786 self
.assertNotRegex(output
, '4063')
2787 for i
in range(4064, 4095):
2788 self
.assertRegex(output
, f
'{i}')
2789 self
.assertNotRegex(output
, '4095')
2791 output
= check_output('bridge vlan show dev bridge99')
2793 self
.assertNotRegex(output
, '4059')
2794 for i
in range(4060, 4095):
2795 self
.assertRegex(output
, f
'{i}')
2796 self
.assertNotRegex(output
, '4095')
2798 def test_bridge_property(self
):
2799 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2800 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2803 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2805 output
= check_output('ip -d link show test1')
2807 self
.assertRegex(output
, 'master')
2808 self
.assertRegex(output
, 'bridge')
2810 output
= check_output('ip -d link show dummy98')
2812 self
.assertRegex(output
, 'master')
2813 self
.assertRegex(output
, 'bridge')
2815 output
= check_output('ip addr show bridge99')
2817 self
.assertRegex(output
, '192.168.0.15/24')
2819 output
= check_output('bridge -d link show dummy98')
2821 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
2822 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
2823 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
2824 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
2825 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
2826 # CONFIG_BRIDGE_IGMP_SNOOPING=y
2827 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
2828 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
2829 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
2830 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
2831 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
2832 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'priority'), '23')
2833 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard'), '1')
2834 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'root_block'), '1')
2836 output
= check_output('bridge -d link show test1')
2838 self
.assertEqual(read_bridge_port_attr('bridge99', 'test1', 'priority'), '0')
2840 check_output('ip address add 192.168.0.16/24 dev bridge99')
2843 output
= check_output('ip addr show bridge99')
2845 self
.assertRegex(output
, '192.168.0.16/24')
2848 print('### ip -6 route list table all dev bridge99')
2849 output
= check_output('ip -6 route list table all dev bridge99')
2851 self
.assertRegex(output
, 'ff00::/8 table local metric 256 pref medium')
2853 self
.assertEqual(call('ip link del test1'), 0)
2855 self
.wait_operstate('bridge99', 'degraded-carrier')
2857 check_output('ip link del dummy98')
2859 self
.wait_operstate('bridge99', 'no-carrier')
2861 output
= check_output('ip address show bridge99')
2863 self
.assertRegex(output
, 'NO-CARRIER')
2864 self
.assertNotRegex(output
, '192.168.0.15/24')
2865 self
.assertNotRegex(output
, '192.168.0.16/24')
2867 print('### ip -6 route list table all dev bridge99')
2868 output
= check_output('ip -6 route list table all dev bridge99')
2870 self
.assertRegex(output
, 'ff00::/8 table local metric 256 (linkdown )?pref medium')
2872 def test_bridge_configure_without_carrier(self
):
2873 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-configure-without-carrier.network',
2877 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
2878 for test
in ['no-slave', 'add-slave', 'slave-up', 'slave-no-carrier', 'slave-carrier', 'slave-down']:
2879 with self
.subTest(test
=test
):
2880 if test
== 'no-slave':
2881 # bridge has no slaves; it's up but *might* not have carrier
2882 # It may take very long time that the interface become configured state.
2883 self
.wait_online(['bridge99:no-carrier'], timeout
='2m', setup_state
=None)
2884 # due to a bug in the kernel, newly-created bridges are brought up
2885 # *with* carrier, unless they have had any setting changed; e.g.
2886 # their mac set, priority set, etc. Then, they will lose carrier
2887 # as soon as a (down) slave interface is added, and regain carrier
2888 # again once the slave interface is brought up.
2889 #self.check_link_attr('bridge99', 'carrier', '0')
2890 elif test
== 'add-slave':
2891 # add slave to bridge, but leave it down; bridge is definitely no-carrier
2892 self
.check_link_attr('test1', 'operstate', 'down')
2893 check_output('ip link set dev test1 master bridge99')
2894 self
.wait_online(['bridge99:no-carrier:no-carrier'], setup_state
=None)
2895 self
.check_link_attr('bridge99', 'carrier', '0')
2896 elif test
== 'slave-up':
2897 # bring up slave, which will have carrier; bridge gains carrier
2898 check_output('ip link set dev test1 up')
2899 self
.wait_online(['bridge99:routable'])
2900 self
.check_link_attr('bridge99', 'carrier', '1')
2901 elif test
== 'slave-no-carrier':
2902 # drop slave carrier; bridge loses carrier
2903 check_output('ip link set dev test1 carrier off')
2904 self
.wait_online(['bridge99:no-carrier:no-carrier'])
2905 self
.check_link_attr('bridge99', 'carrier', '0')
2906 elif test
== 'slave-carrier':
2907 # restore slave carrier; bridge gains carrier
2908 check_output('ip link set dev test1 carrier on')
2909 self
.wait_online(['bridge99:routable'])
2910 self
.check_link_attr('bridge99', 'carrier', '1')
2911 elif test
== 'slave-down':
2912 # bring down slave; bridge loses carrier
2913 check_output('ip link set dev test1 down')
2914 self
.wait_online(['bridge99:no-carrier:no-carrier'])
2915 self
.check_link_attr('bridge99', 'carrier', '0')
2917 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
2919 self
.assertRegex(output
, '10.1.2.3')
2920 self
.assertRegex(output
, '10.1.2.1')
2922 def test_bridge_ignore_carrier_loss(self
):
2923 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2924 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2925 'bridge99-ignore-carrier-loss.network')
2927 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2929 check_output('ip address add 192.168.0.16/24 dev bridge99')
2932 check_output('ip link del test1')
2933 check_output('ip link del dummy98')
2936 output
= check_output('ip address show bridge99')
2938 self
.assertRegex(output
, 'NO-CARRIER')
2939 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2940 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
2942 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
2943 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
2944 'bridge99-ignore-carrier-loss.network')
2946 self
.wait_online(['bridge99:no-carrier'])
2948 for trial
in range(4):
2949 check_output('ip link add dummy98 type dummy')
2950 check_output('ip link set dummy98 up')
2952 check_output('ip link del dummy98')
2954 self
.wait_online(['bridge99:routable', 'dummy98:enslaved'])
2956 output
= check_output('ip address show bridge99')
2958 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2960 output
= check_output('ip rule list table 100')
2962 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
2964 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
2968 '23-emit-lldp.network',
2973 remove_links(self
.links
)
2974 stop_networkd(show_logs
=False)
2977 remove_links(self
.links
)
2978 remove_unit_from_networkd_path(self
.units
)
2979 stop_networkd(show_logs
=True)
2981 def test_lldp(self
):
2982 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
2984 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
2986 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
2988 self
.assertRegex(output
, 'veth-peer')
2989 self
.assertRegex(output
, 'veth99')
2991 class NetworkdRATests(unittest
.TestCase
, Utilities
):
2996 'ipv6-prefix.network',
2997 'ipv6-prefix-veth.network',
2998 'ipv6-prefix-veth-token-static.network',
2999 'ipv6-prefix-veth-token-static-explicit.network',
3000 'ipv6-prefix-veth-token-static-multiple.network',
3001 'ipv6-prefix-veth-token-prefixstable.network']
3004 remove_links(self
.links
)
3005 stop_networkd(show_logs
=False)
3008 remove_links(self
.links
)
3009 remove_unit_from_networkd_path(self
.units
)
3010 stop_networkd(show_logs
=True)
3012 def test_ipv6_prefix_delegation(self
):
3013 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
3015 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3017 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3019 self
.assertRegex(output
, 'fe80::')
3020 self
.assertRegex(output
, '2002:da8:1::1')
3022 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3024 self
.assertRegex(output
, '2002:da8:1:0')
3026 def test_ipv6_token_static(self
):
3027 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static.network')
3029 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3031 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3033 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
3035 def test_ipv6_token_static_explicit(self
):
3036 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static-explicit.network')
3038 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3040 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3042 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
3044 def test_ipv6_token_static_multiple(self
):
3045 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static-multiple.network')
3047 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3049 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3051 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
3052 self
.assertRegex(output
, '2002:da8:1:0:fa:de:ca:fe')
3054 def test_ipv6_token_prefixstable(self
):
3055 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable.network')
3057 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3059 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3061 self
.assertRegex(output
, '2002:da8:1:0')
3063 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
3068 'dhcp-client.network',
3069 'dhcp-client-timezone-router.network',
3070 'dhcp-server.network',
3071 'dhcp-server-timezone-router.network']
3074 remove_links(self
.links
)
3075 stop_networkd(show_logs
=False)
3078 remove_links(self
.links
)
3079 remove_unit_from_networkd_path(self
.units
)
3080 stop_networkd(show_logs
=True)
3082 def test_dhcp_server(self
):
3083 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
3085 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3087 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3089 self
.assertRegex(output
, '192.168.5.*')
3090 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
3091 self
.assertRegex(output
, 'DNS: 192.168.5.1')
3092 self
.assertRegex(output
, 'NTP: 192.168.5.1')
3094 def test_emit_router_timezone(self
):
3095 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
3097 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3099 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3101 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
3102 self
.assertRegex(output
, '192.168.5.*')
3103 self
.assertRegex(output
, 'Europe/Berlin')
3105 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
3114 'dhcp-client-anonymize.network',
3115 'dhcp-client-decline.network',
3116 'dhcp-client-gateway-ipv4.network',
3117 'dhcp-client-gateway-ipv6.network',
3118 'dhcp-client-gateway-onlink-implicit.network',
3119 'dhcp-client-ipv4-dhcp-settings.network',
3120 'dhcp-client-ipv4-only-ipv6-disabled.network',
3121 'dhcp-client-ipv4-only.network',
3122 'dhcp-client-ipv4-use-routes-use-gateway.network',
3123 'dhcp-client-ipv6-only.network',
3124 'dhcp-client-ipv6-rapid-commit.network',
3125 'dhcp-client-keep-configuration-dhcp-on-stop.network',
3126 'dhcp-client-keep-configuration-dhcp.network',
3127 'dhcp-client-listen-port.network',
3128 'dhcp-client-reassign-static-routes-ipv4.network',
3129 'dhcp-client-reassign-static-routes-ipv6.network',
3130 'dhcp-client-route-metric.network',
3131 'dhcp-client-route-table.network',
3132 'dhcp-client-use-dns-ipv4-and-ra.network',
3133 'dhcp-client-use-dns-ipv4.network',
3134 'dhcp-client-use-dns-no.network',
3135 'dhcp-client-use-dns-yes.network',
3136 'dhcp-client-use-domains.network',
3137 'dhcp-client-vrf.network',
3138 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
3139 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
3140 'dhcp-client-with-static-address.network',
3141 'dhcp-client.network',
3142 'dhcp-server-decline.network',
3143 'dhcp-server-veth-peer.network',
3144 'dhcp-v4-server-veth-peer.network',
3148 stop_dnsmasq(dnsmasq_pid_file
)
3149 remove_links(self
.links
)
3150 stop_networkd(show_logs
=False)
3153 stop_dnsmasq(dnsmasq_pid_file
)
3156 remove_links(self
.links
)
3157 remove_unit_from_networkd_path(self
.units
)
3158 stop_networkd(show_logs
=True)
3160 def test_dhcp_client_ipv6_only(self
):
3161 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3164 self
.wait_online(['veth-peer:carrier'])
3166 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3168 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3170 self
.assertRegex(output
, '2600::')
3171 self
.assertNotRegex(output
, '192.168.5')
3173 # Confirm that ipv6 token is not set in the kernel
3174 output
= check_output('ip token show dev veth99')
3176 self
.assertRegex(output
, 'token :: dev veth99')
3178 def test_dhcp_client_ipv4_only(self
):
3179 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
3182 self
.wait_online(['veth-peer:carrier'])
3183 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
3184 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3186 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3188 self
.assertNotRegex(output
, '2600::')
3189 self
.assertRegex(output
, '192.168.5')
3190 self
.assertRegex(output
, '192.168.5.6')
3191 self
.assertRegex(output
, '192.168.5.7')
3193 # checking routes to DNS servers
3194 output
= check_output('ip route show dev veth99')
3196 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3197 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3198 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3200 stop_dnsmasq(dnsmasq_pid_file
)
3201 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8', lease_time
='2m')
3203 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3204 print('Wait for the dynamic address to be renewed')
3207 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3209 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3211 self
.assertNotRegex(output
, '2600::')
3212 self
.assertRegex(output
, '192.168.5')
3213 self
.assertNotRegex(output
, '192.168.5.6')
3214 self
.assertRegex(output
, '192.168.5.7')
3215 self
.assertRegex(output
, '192.168.5.8')
3217 # checking routes to DNS servers
3218 output
= check_output('ip route show dev veth99')
3220 self
.assertNotRegex(output
, r
'192.168.5.6')
3221 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3222 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3223 self
.assertRegex(output
, r
'192.168.5.8 proto dhcp scope link src 192.168.5.181 metric 1024')
3225 def test_dhcp_client_ipv4_use_routes_gateway(self
):
3226 for (routes
, gateway
, dnsroutes
) in itertools
.product([True, False, None], repeat
=3):
3228 with self
.subTest(routes
=routes
, gateway
=gateway
, dnsroutes
=dnsroutes
):
3229 self
._test
_dhcp
_client
_ipv
4_use
_routes
_gateway
(routes
, gateway
, dnsroutes
)
3232 def _test_dhcp_client_ipv4_use_routes_gateway(self
, routes
, gateway
, dnsroutes
):
3233 testunit
= 'dhcp-client-ipv4-use-routes-use-gateway.network'
3234 testunits
= ['25-veth.netdev', 'dhcp-server-veth-peer.network', testunit
]
3236 testunits
.append(f
'{testunit}.d/use-routes-{routes}.conf');
3238 testunits
.append(f
'{testunit}.d/use-gateway-{gateway}.conf');
3239 if dnsroutes
!= None:
3240 testunits
.append(f
'{testunit}.d/use-dns-routes-{dnsroutes}.conf');
3241 copy_unit_to_networkd_unit_path(*testunits
, dropins
=False)
3244 self
.wait_online(['veth-peer:carrier'])
3245 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
3246 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3248 output
= check_output('ip route show dev veth99')
3251 # UseRoutes= defaults to true
3252 useroutes
= routes
in [True, None]
3253 # UseGateway= defaults to useroutes
3254 usegateway
= useroutes
if gateway
== None else gateway
3258 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.181 metric 1024')
3260 self
.assertNotRegex(output
, r
'192.168.5.5')
3264 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.181 metric 1024')
3266 self
.assertNotRegex(output
, r
'default via 192.168.5.1')
3268 # Check RoutesToDNS=, which defaults to false
3270 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3271 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3273 self
.assertNotRegex(output
, r
'192.168.5.6')
3274 self
.assertNotRegex(output
, r
'192.168.5.7')
3276 def test_dhcp_client_ipv4_ipv6(self
):
3277 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
3278 'dhcp-client-ipv4-only.network')
3280 self
.wait_online(['veth-peer:carrier'])
3282 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3284 # link become 'routable' when at least one protocol provide an valid address.
3285 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3286 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3288 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3290 self
.assertRegex(output
, '2600::')
3291 self
.assertRegex(output
, '192.168.5')
3293 def test_dhcp_client_settings(self
):
3294 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
3297 self
.wait_online(['veth-peer:carrier'])
3299 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3301 print('## ip address show dev veth99')
3302 output
= check_output('ip address show dev veth99')
3304 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3305 self
.assertRegex(output
, '192.168.5')
3306 self
.assertRegex(output
, '1492')
3308 print('## ip route show table main dev veth99')
3309 output
= check_output('ip route show table main dev veth99')
3312 main_table_is_empty
= output
== ''
3313 if not main_table_is_empty
:
3314 self
.assertNotRegex(output
, 'proto dhcp')
3316 print('## ip route show table 211 dev veth99')
3317 output
= check_output('ip route show table 211 dev veth99')
3319 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
3320 if main_table_is_empty
:
3321 self
.assertRegex(output
, '192.168.5.0/24 proto dhcp')
3322 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
3323 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
3325 print('## dnsmasq log')
3326 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
3327 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
3328 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
3329 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
3331 def test_dhcp6_client_settings_rapidcommit_true(self
):
3332 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3334 self
.wait_online(['veth-peer:carrier'])
3336 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3338 output
= check_output('ip address show dev veth99')
3340 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3341 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
3343 def test_dhcp6_client_settings_rapidcommit_false(self
):
3344 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
3346 self
.wait_online(['veth-peer:carrier'])
3348 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3350 output
= check_output('ip address show dev veth99')
3352 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3353 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
3355 def test_dhcp_client_settings_anonymize(self
):
3356 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
3358 self
.wait_online(['veth-peer:carrier'])
3360 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3362 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
3363 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
3364 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
3366 def test_dhcp_client_listen_port(self
):
3367 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
3369 self
.wait_online(['veth-peer:carrier'])
3370 start_dnsmasq('--dhcp-alternate-port=67,5555')
3371 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3373 output
= check_output('ip -4 address show dev veth99')
3375 self
.assertRegex(output
, '192.168.5.* dynamic')
3377 def test_dhcp_client_with_static_address(self
):
3378 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
3379 'dhcp-client-with-static-address.network')
3381 self
.wait_online(['veth-peer:carrier'])
3383 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3385 output
= check_output('ip address show dev veth99 scope global')
3387 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
3388 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
3390 output
= check_output('ip route show dev veth99')
3392 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
3393 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
3394 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
3395 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
3397 def test_dhcp_route_table_id(self
):
3398 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
3400 self
.wait_online(['veth-peer:carrier'])
3402 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3404 output
= check_output('ip route show table 12')
3406 self
.assertRegex(output
, 'veth99 proto dhcp')
3407 self
.assertRegex(output
, '192.168.5.1')
3409 def test_dhcp_route_metric(self
):
3410 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
3412 self
.wait_online(['veth-peer:carrier'])
3414 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3416 output
= check_output('ip route show dev veth99')
3418 self
.assertRegex(output
, 'metric 24')
3420 def test_dhcp_client_reassign_static_routes_ipv4(self
):
3421 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3422 'dhcp-client-reassign-static-routes-ipv4.network')
3424 self
.wait_online(['veth-peer:carrier'])
3425 start_dnsmasq(lease_time
='2m')
3426 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3428 output
= check_output('ip address show dev veth99 scope global')
3430 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3432 output
= check_output('ip route show dev veth99')
3434 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3435 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3436 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3437 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3439 stop_dnsmasq(dnsmasq_pid_file
)
3440 start_dnsmasq(ipv4_range
='192.168.5.210,192.168.5.220', lease_time
='2m')
3442 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3443 print('Wait for the dynamic address to be renewed')
3446 self
.wait_online(['veth99:routable'])
3448 output
= check_output('ip route show dev veth99')
3450 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3451 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3452 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3453 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3455 def test_dhcp_client_reassign_static_routes_ipv6(self
):
3456 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3457 'dhcp-client-reassign-static-routes-ipv6.network')
3459 self
.wait_online(['veth-peer:carrier'])
3460 start_dnsmasq(lease_time
='2m')
3461 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3463 output
= check_output('ip address show dev veth99 scope global')
3465 self
.assertRegex(output
, r
'inet6 2600::[0-9a-f]*/128 scope global (noprefixroute dynamic|dynamic noprefixroute)')
3467 output
= check_output('ip -6 route show dev veth99')
3469 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3470 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3472 stop_dnsmasq(dnsmasq_pid_file
)
3473 start_dnsmasq(ipv6_range
='2600::30,2600::40', lease_time
='2m')
3475 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3476 print('Wait for the dynamic address to be renewed')
3479 self
.wait_online(['veth99:routable'])
3481 output
= check_output('ip -6 route show dev veth99')
3483 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3484 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3486 def test_dhcp_keep_configuration_dhcp(self
):
3487 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
3489 self
.wait_online(['veth-peer:carrier'])
3490 start_dnsmasq(lease_time
='2m')
3491 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3493 output
= check_output('ip address show dev veth99 scope global')
3495 self
.assertRegex(output
, r
'192.168.5.*')
3497 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3499 self
.assertRegex(output
, r
'192.168.5.*')
3501 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
3502 stop_dnsmasq(dnsmasq_pid_file
)
3504 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3505 print('Wait for the dynamic address to be expired')
3508 print('The lease address should be kept after lease expired')
3509 output
= check_output('ip address show dev veth99 scope global')
3511 self
.assertRegex(output
, r
'192.168.5.*')
3513 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3515 self
.assertRegex(output
, r
'192.168.5.*')
3517 check_output('systemctl stop systemd-networkd')
3519 print('The lease address should be kept after networkd stopped')
3520 output
= check_output('ip address show dev veth99 scope global')
3522 self
.assertRegex(output
, r
'192.168.5.*')
3524 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3526 self
.assertRegex(output
, r
'192.168.5.*')
3529 self
.wait_online(['veth-peer:routable'])
3531 print('Still the lease address should be kept after networkd restarted')
3532 output
= check_output('ip address show dev veth99 scope global')
3534 self
.assertRegex(output
, r
'192.168.5.*')
3536 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3538 self
.assertRegex(output
, r
'192.168.5.*')
3540 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
3541 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
3543 self
.wait_online(['veth-peer:carrier'])
3544 start_dnsmasq(lease_time
='2m')
3545 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3547 output
= check_output('ip address show dev veth99 scope global')
3549 self
.assertRegex(output
, r
'192.168.5.*')
3551 stop_dnsmasq(dnsmasq_pid_file
)
3552 check_output('systemctl stop systemd-networkd')
3554 output
= check_output('ip address show dev veth99 scope global')
3556 self
.assertRegex(output
, r
'192.168.5.*')
3559 self
.wait_online(['veth-peer:routable'])
3561 output
= check_output('ip address show dev veth99 scope global')
3563 self
.assertNotRegex(output
, r
'192.168.5.*')
3565 def test_dhcp_client_reuse_address_as_static(self
):
3566 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
3568 self
.wait_online(['veth-peer:carrier'])
3570 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3572 # link become 'routable' when at least one protocol provide an valid address.
3573 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3574 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3576 output
= check_output('ip address show dev veth99 scope global')
3578 self
.assertRegex(output
, '192.168.5')
3579 self
.assertRegex(output
, '2600::')
3581 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
3582 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
3583 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
3584 print(static_network
)
3586 remove_unit_from_networkd_path(['dhcp-client.network'])
3588 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
3589 f
.write(static_network
)
3591 # When networkd started, the links are already configured, so let's wait for 5 seconds
3592 # the links to be re-configured.
3594 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3596 output
= check_output('ip -4 address show dev veth99 scope global')
3598 self
.assertRegex(output
, '192.168.5')
3599 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3601 output
= check_output('ip -6 address show dev veth99 scope global')
3603 self
.assertRegex(output
, '2600::')
3604 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3606 @expectedFailureIfModuleIsNotAvailable('vrf')
3607 def test_dhcp_client_vrf(self
):
3608 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
3609 '25-vrf.netdev', '25-vrf.network')
3611 self
.wait_online(['veth-peer:carrier'])
3613 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
3615 # link become 'routable' when at least one protocol provide an valid address.
3616 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3617 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3619 print('## ip -d link show dev vrf99')
3620 output
= check_output('ip -d link show dev vrf99')
3622 self
.assertRegex(output
, 'vrf table 42')
3624 print('## ip address show vrf vrf99')
3625 output
= check_output('ip address show vrf vrf99')
3627 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3628 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3629 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3630 self
.assertRegex(output
, 'inet6 .* scope link')
3632 print('## ip address show dev veth99')
3633 output
= check_output('ip address show dev veth99')
3635 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3636 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3637 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3638 self
.assertRegex(output
, 'inet6 .* scope link')
3640 print('## ip route show vrf vrf99')
3641 output
= check_output('ip route show vrf vrf99')
3643 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
3644 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
3645 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
3646 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
3647 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
3649 print('## ip route show table main dev veth99')
3650 output
= check_output('ip route show table main dev veth99')
3652 self
.assertEqual(output
, '')
3654 def test_dhcp_client_gateway_ipv4(self
):
3655 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3656 'dhcp-client-gateway-ipv4.network')
3658 self
.wait_online(['veth-peer:carrier'])
3660 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3662 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3664 self
.assertRegex(output
, '10.0.0.0/8 via 192.168.5.1 proto static')
3666 def test_dhcp_client_gateway_ipv6(self
):
3667 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3668 'dhcp-client-gateway-ipv6.network')
3670 self
.wait_online(['veth-peer:carrier'])
3672 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3674 output
= check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
3676 self
.assertRegex(output
, 'via fe80::1034:56ff:fe78:9abd')
3678 def test_dhcp_client_gateway_onlink_implicit(self
):
3679 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3680 'dhcp-client-gateway-onlink-implicit.network')
3682 self
.wait_online(['veth-peer:carrier'])
3684 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3686 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3688 self
.assertRegex(output
, '192.168.5')
3690 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3692 self
.assertRegex(output
, 'onlink')
3693 output
= check_output('ip route list dev veth99 192.168.100.0/24')
3695 self
.assertRegex(output
, 'onlink')
3697 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
3698 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3699 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
3701 self
.wait_online(['veth-peer:carrier'])
3702 start_dnsmasq(lease_time
='2m')
3703 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3705 output
= check_output('ip address show dev veth99')
3708 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3709 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3710 output
= check_output('ip -6 address show dev veth99 scope link')
3711 self
.assertRegex(output
, 'inet6 .* scope link')
3712 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3713 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3714 output
= check_output('ip -4 address show dev veth99 scope link')
3715 self
.assertNotRegex(output
, 'inet .* scope link')
3717 print('Wait for the dynamic address to be expired')
3720 output
= check_output('ip address show dev veth99')
3723 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3724 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3725 output
= check_output('ip -6 address show dev veth99 scope link')
3726 self
.assertRegex(output
, 'inet6 .* scope link')
3727 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3728 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3729 output
= check_output('ip -4 address show dev veth99 scope link')
3730 self
.assertNotRegex(output
, 'inet .* scope link')
3732 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
3734 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
3735 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3736 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
3738 self
.wait_online(['veth99:degraded', 'veth-peer:routable'])
3740 output
= check_output('ip address show dev veth99')
3743 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3744 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3745 output
= check_output('ip -6 address show dev veth99 scope link')
3746 self
.assertRegex(output
, 'inet6 .* scope link')
3747 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3748 self
.assertNotRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3749 output
= check_output('ip -4 address show dev veth99 scope link')
3750 self
.assertRegex(output
, 'inet .* scope link')
3752 def test_dhcp_client_route_remove_on_renew(self
):
3753 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3754 'dhcp-client-ipv4-only-ipv6-disabled.network')
3756 self
.wait_online(['veth-peer:carrier'])
3757 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
3758 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3760 # test for issue #12490
3762 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3764 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3766 for line
in output
.splitlines():
3767 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3768 address1
= line
.split()[1].split('/')[0]
3771 output
= check_output('ip -4 route show dev veth99')
3773 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3774 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3776 stop_dnsmasq(dnsmasq_pid_file
)
3777 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
3779 print('Wait for the dynamic address to be expired')
3782 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3784 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3786 for line
in output
.splitlines():
3787 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3788 address2
= line
.split()[1].split('/')[0]
3791 self
.assertNotEqual(address1
, address2
)
3793 output
= check_output('ip -4 route show dev veth99')
3795 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3796 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3797 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
3798 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
3800 def test_dhcp_client_use_dns_yes(self
):
3801 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-yes.network')
3804 self
.wait_online(['veth-peer:carrier'])
3805 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3806 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3808 # link become 'routable' when at least one protocol provide an valid address.
3809 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3810 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3813 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3815 self
.assertRegex(output
, '192.168.5.1')
3816 self
.assertRegex(output
, '2600::1')
3818 def test_dhcp_client_use_dns_no(self
):
3819 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-no.network')
3822 self
.wait_online(['veth-peer:carrier'])
3823 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3824 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3826 # link become 'routable' when at least one protocol provide an valid address.
3827 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3828 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3831 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3833 self
.assertNotRegex(output
, '192.168.5.1')
3834 self
.assertNotRegex(output
, '2600::1')
3836 def test_dhcp_client_use_dns_ipv4(self
):
3837 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4.network')
3840 self
.wait_online(['veth-peer:carrier'])
3841 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3842 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3844 # link become 'routable' when at least one protocol provide an valid address.
3845 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3846 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3849 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3851 self
.assertRegex(output
, '192.168.5.1')
3852 self
.assertNotRegex(output
, '2600::1')
3854 def test_dhcp_client_use_dns_ipv4_and_ra(self
):
3855 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4-and-ra.network')
3858 self
.wait_online(['veth-peer:carrier'])
3859 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3860 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3862 # link become 'routable' when at least one protocol provide an valid address.
3863 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3864 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3867 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3869 self
.assertRegex(output
, '192.168.5.1')
3870 self
.assertRegex(output
, '2600::1')
3872 def test_dhcp_client_use_domains(self
):
3873 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-domains.network')
3876 self
.wait_online(['veth-peer:carrier'])
3877 start_dnsmasq('--dhcp-option=option:domain-search,example.com')
3878 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3880 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3882 self
.assertRegex(output
, 'Search Domains: example.com')
3885 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
3887 self
.assertRegex(output
, 'example.com')
3889 def test_dhcp_client_decline(self
):
3890 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-decline.network', 'dhcp-client-decline.network')
3893 self
.wait_online(['veth-peer:carrier'])
3894 rc
= call(*wait_online_cmd
, '--timeout=10s', '--interface=veth99:routable', env
=env
)
3895 self
.assertTrue(rc
== 1)
3897 class NetworkdIPv6PrefixTests(unittest
.TestCase
, Utilities
):
3902 'ipv6ra-prefix-client.network',
3903 'ipv6ra-prefix.network'
3907 remove_links(self
.links
)
3908 stop_networkd(show_logs
=False)
3912 remove_links(self
.links
)
3913 remove_unit_from_networkd_path(self
.units
)
3914 stop_networkd(show_logs
=True)
3916 def test_ipv6_route_prefix(self
):
3917 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client.network', 'ipv6ra-prefix.network')
3920 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3922 output
= check_output('ip -6 route show dev veth-peer')
3924 self
.assertRegex(output
, '2001:db8:0:1::/64 proto ra')
3926 output
= check_output('ip addr show dev veth99')
3928 self
.assertNotRegex(output
, '2001:db8:0:1')
3929 self
.assertRegex(output
, '2001:db8:0:2')
3931 class NetworkdMTUTests(unittest
.TestCase
, Utilities
):
3936 '12-dummy-mtu.netdev',
3937 '12-dummy-mtu.link',
3942 remove_links(self
.links
)
3943 stop_networkd(show_logs
=False)
3947 remove_links(self
.links
)
3948 remove_unit_from_networkd_path(self
.units
)
3949 stop_networkd(show_logs
=True)
3951 def check_mtu(self
, mtu
, ipv6_mtu
=None, reset
=True):
3957 self
.wait_online(['dummy98:routable'])
3958 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
3959 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
3961 # test normal restart
3963 self
.wait_online(['dummy98:routable'])
3964 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
3965 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
3968 self
.reset_check_mtu(mtu
, ipv6_mtu
)
3970 def reset_check_mtu(self
, mtu
, ipv6_mtu
=None):
3971 ''' test setting mtu/ipv6_mtu with interface already up '''
3974 # note - changing the device mtu resets the ipv6 mtu
3975 run('ip link set up mtu 1501 dev dummy98')
3976 run('ip link set up mtu 1500 dev dummy98')
3977 self
.assertEqual(read_link_attr('dummy98', 'mtu'), '1500')
3978 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), '1500')
3980 self
.check_mtu(mtu
, ipv6_mtu
, reset
=False)
3982 def test_mtu_network(self
):
3983 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
3984 self
.check_mtu('1600')
3986 def test_mtu_netdev(self
):
3987 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network', dropins
=False)
3988 # note - MTU set by .netdev happens ONLY at device creation!
3989 self
.check_mtu('1600', reset
=False)
3991 def test_mtu_link(self
):
3992 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', dropins
=False)
3993 # must reload udev because it only picks up new files after 3 second delay
3994 call('udevadm control --reload')
3995 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
3996 self
.check_mtu('1600', reset
=False)
3998 def test_ipv6_mtu(self
):
3999 ''' set ipv6 mtu without setting device mtu '''
4000 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
4001 self
.check_mtu('1500', '1400')
4003 def test_ipv6_mtu_toolarge(self
):
4004 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
4005 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
4006 self
.check_mtu('1500', '1500')
4008 def test_mtu_network_ipv6_mtu(self
):
4009 ''' set ipv6 mtu and set device mtu via network file '''
4010 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
4011 self
.check_mtu('1600', '1550')
4013 def test_mtu_netdev_ipv6_mtu(self
):
4014 ''' set ipv6 mtu and set device mtu via netdev file '''
4015 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
4016 self
.check_mtu('1600', '1550', reset
=False)
4018 def test_mtu_link_ipv6_mtu(self
):
4019 ''' set ipv6 mtu and set device mtu via link file '''
4020 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
4021 # must reload udev because it only picks up new files after 3 second delay
4022 call('udevadm control --reload')
4023 self
.check_mtu('1600', '1550', reset
=False)
4026 if __name__
== '__main__':
4027 parser
= argparse
.ArgumentParser()
4028 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
4029 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
4030 parser
.add_argument('--resolved', help='Path to systemd-resolved', dest
='resolved_bin')
4031 parser
.add_argument('--udevd', help='Path to systemd-udevd', dest
='udevd_bin')
4032 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
4033 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
4034 parser
.add_argument('--resolvectl', help='Path to resolvectl', dest
='resolvectl_bin')
4035 parser
.add_argument('--timedatectl', help='Path to timedatectl', dest
='timedatectl_bin')
4036 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
4037 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
4038 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
4039 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
4040 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
4041 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
4044 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
:
4045 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
4046 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
4047 resolved_bin
= os
.path
.join(ns
.build_dir
, 'systemd-resolved')
4048 udevd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-udevd')
4049 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
4050 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
4051 resolvectl_bin
= os
.path
.join(ns
.build_dir
, 'resolvectl')
4052 timedatectl_bin
= os
.path
.join(ns
.build_dir
, 'timedatectl')
4055 networkd_bin
= ns
.networkd_bin
4057 resolved_bin
= ns
.resolved_bin
4059 udevd_bin
= ns
.udevd_bin
4060 if ns
.wait_online_bin
:
4061 wait_online_bin
= ns
.wait_online_bin
4062 if ns
.networkctl_bin
:
4063 networkctl_bin
= ns
.networkctl_bin
4064 if ns
.resolvectl_bin
:
4065 resolvectl_bin
= ns
.resolvectl_bin
4066 if ns
.timedatectl_bin
:
4067 timedatectl_bin
= ns
.timedatectl_bin
4069 use_valgrind
= ns
.use_valgrind
4070 enable_debug
= ns
.enable_debug
4071 asan_options
= ns
.asan_options
4072 lsan_options
= ns
.lsan_options
4073 ubsan_options
= ns
.ubsan_options
4076 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
4077 resolvectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin
]
4078 timedatectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin
]
4079 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
4081 networkctl_cmd
= [networkctl_bin
]
4082 resolvectl_cmd
= [resolvectl_bin
]
4083 timedatectl_cmd
= [timedatectl_bin
]
4084 wait_online_cmd
= [wait_online_bin
]
4087 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
4089 env
.update({ 'ASAN_OPTIONS' : asan_options
})
4091 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
4093 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
4096 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,