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
) and 'tentative' not in 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#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
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#ccc.com', '10.10.10.13', '1111:2222::3333', 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#ccc.com 10.10.10.13 1111:2222::3333')
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#ccc.com 10.10.10.13 1111:2222::3333')
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#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
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 self
.wait_operstate('bridge99', operstate
=r
'(no-carrier|routable)', setup_state
=None, setup_timeout
=30)
2883 # due to a bug in the kernel, newly-created bridges are brought up
2884 # *with* carrier, unless they have had any setting changed; e.g.
2885 # their mac set, priority set, etc. Then, they will lose carrier
2886 # as soon as a (down) slave interface is added, and regain carrier
2887 # again once the slave interface is brought up.
2888 #self.check_link_attr('bridge99', 'carrier', '0')
2889 elif test
== 'add-slave':
2890 # add slave to bridge, but leave it down; bridge is definitely no-carrier
2891 self
.check_link_attr('test1', 'operstate', 'down')
2892 check_output('ip link set dev test1 master bridge99')
2893 self
.wait_operstate('bridge99', operstate
='no-carrier', setup_state
=None)
2894 self
.check_link_attr('bridge99', 'carrier', '0')
2895 elif test
== 'slave-up':
2896 # bring up slave, which will have carrier; bridge gains carrier
2897 check_output('ip link set dev test1 up')
2898 self
.wait_online(['bridge99:routable'])
2899 self
.check_link_attr('bridge99', 'carrier', '1')
2900 elif test
== 'slave-no-carrier':
2901 # drop slave carrier; bridge loses carrier
2902 check_output('ip link set dev test1 carrier off')
2903 self
.wait_online(['bridge99:no-carrier:no-carrier'])
2904 self
.check_link_attr('bridge99', 'carrier', '0')
2905 elif test
== 'slave-carrier':
2906 # restore slave carrier; bridge gains carrier
2907 check_output('ip link set dev test1 carrier on')
2908 self
.wait_online(['bridge99:routable'])
2909 self
.check_link_attr('bridge99', 'carrier', '1')
2910 elif test
== 'slave-down':
2911 # bring down slave; bridge loses carrier
2912 check_output('ip link set dev test1 down')
2913 self
.wait_online(['bridge99:no-carrier:no-carrier'])
2914 self
.check_link_attr('bridge99', 'carrier', '0')
2916 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'bridge99', env
=env
)
2917 self
.assertRegex(output
, '10.1.2.3')
2918 self
.assertRegex(output
, '10.1.2.1')
2920 def test_bridge_ignore_carrier_loss(self
):
2921 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2922 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2923 'bridge99-ignore-carrier-loss.network')
2925 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2927 check_output('ip address add 192.168.0.16/24 dev bridge99')
2930 check_output('ip link del test1')
2931 check_output('ip link del dummy98')
2934 output
= check_output('ip address show bridge99')
2936 self
.assertRegex(output
, 'NO-CARRIER')
2937 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2938 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
2940 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
2941 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
2942 'bridge99-ignore-carrier-loss.network')
2944 self
.wait_online(['bridge99:no-carrier'])
2946 for trial
in range(4):
2947 check_output('ip link add dummy98 type dummy')
2948 check_output('ip link set dummy98 up')
2950 check_output('ip link del dummy98')
2952 self
.wait_online(['bridge99:routable', 'dummy98:enslaved'])
2954 output
= check_output('ip address show bridge99')
2956 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2958 output
= check_output('ip rule list table 100')
2960 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
2962 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
2966 '23-emit-lldp.network',
2971 remove_links(self
.links
)
2972 stop_networkd(show_logs
=False)
2975 remove_links(self
.links
)
2976 remove_unit_from_networkd_path(self
.units
)
2977 stop_networkd(show_logs
=True)
2979 def test_lldp(self
):
2980 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
2982 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
2984 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
2986 self
.assertRegex(output
, 'veth-peer')
2987 self
.assertRegex(output
, 'veth99')
2989 class NetworkdRATests(unittest
.TestCase
, Utilities
):
2994 'ipv6-prefix.network',
2995 'ipv6-prefix-veth.network',
2996 'ipv6-prefix-veth-token-static.network',
2997 'ipv6-prefix-veth-token-static-explicit.network',
2998 'ipv6-prefix-veth-token-static-multiple.network',
2999 'ipv6-prefix-veth-token-prefixstable.network']
3002 remove_links(self
.links
)
3003 stop_networkd(show_logs
=False)
3006 remove_links(self
.links
)
3007 remove_unit_from_networkd_path(self
.units
)
3008 stop_networkd(show_logs
=True)
3010 def test_ipv6_prefix_delegation(self
):
3011 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
3013 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3015 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3017 self
.assertRegex(output
, 'fe80::')
3018 self
.assertRegex(output
, '2002:da8:1::1')
3020 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3022 self
.assertRegex(output
, '2002:da8:1:0')
3024 def test_ipv6_token_static(self
):
3025 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static.network')
3027 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3029 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3031 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
3033 def test_ipv6_token_static_explicit(self
):
3034 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static-explicit.network')
3036 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3038 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3040 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
3042 def test_ipv6_token_static_multiple(self
):
3043 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static-multiple.network')
3045 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3047 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3049 self
.assertRegex(output
, '2002:da8:1:0:1a:2b:3c:4d')
3050 self
.assertRegex(output
, '2002:da8:1:0:fa:de:ca:fe')
3052 def test_ipv6_token_prefixstable(self
):
3053 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable.network')
3055 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
3057 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3059 self
.assertRegex(output
, '2002:da8:1:0')
3061 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
3066 'dhcp-client.network',
3067 'dhcp-client-timezone-router.network',
3068 'dhcp-server.network',
3069 'dhcp-server-timezone-router.network']
3072 remove_links(self
.links
)
3073 stop_networkd(show_logs
=False)
3076 remove_links(self
.links
)
3077 remove_unit_from_networkd_path(self
.units
)
3078 stop_networkd(show_logs
=True)
3080 def test_dhcp_server(self
):
3081 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
3083 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3085 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3087 self
.assertRegex(output
, '192.168.5.*')
3088 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
3089 self
.assertRegex(output
, 'DNS: 192.168.5.1')
3090 self
.assertRegex(output
, 'NTP: 192.168.5.1')
3092 def test_emit_router_timezone(self
):
3093 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
3095 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3097 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3099 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
3100 self
.assertRegex(output
, '192.168.5.*')
3101 self
.assertRegex(output
, 'Europe/Berlin')
3103 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
3112 'dhcp-client-anonymize.network',
3113 'dhcp-client-decline.network',
3114 'dhcp-client-gateway-ipv4.network',
3115 'dhcp-client-gateway-ipv6.network',
3116 'dhcp-client-gateway-onlink-implicit.network',
3117 'dhcp-client-ipv4-dhcp-settings.network',
3118 'dhcp-client-ipv4-only-ipv6-disabled.network',
3119 'dhcp-client-ipv4-only.network',
3120 'dhcp-client-ipv4-use-routes-use-gateway.network',
3121 'dhcp-client-ipv6-only.network',
3122 'dhcp-client-ipv6-rapid-commit.network',
3123 'dhcp-client-keep-configuration-dhcp-on-stop.network',
3124 'dhcp-client-keep-configuration-dhcp.network',
3125 'dhcp-client-listen-port.network',
3126 'dhcp-client-reassign-static-routes-ipv4.network',
3127 'dhcp-client-reassign-static-routes-ipv6.network',
3128 'dhcp-client-route-metric.network',
3129 'dhcp-client-route-table.network',
3130 'dhcp-client-use-dns-ipv4-and-ra.network',
3131 'dhcp-client-use-dns-ipv4.network',
3132 'dhcp-client-use-dns-no.network',
3133 'dhcp-client-use-dns-yes.network',
3134 'dhcp-client-use-domains.network',
3135 'dhcp-client-vrf.network',
3136 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
3137 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
3138 'dhcp-client-with-static-address.network',
3139 'dhcp-client.network',
3140 'dhcp-server-decline.network',
3141 'dhcp-server-veth-peer.network',
3142 'dhcp-v4-server-veth-peer.network',
3146 stop_dnsmasq(dnsmasq_pid_file
)
3147 remove_links(self
.links
)
3148 stop_networkd(show_logs
=False)
3151 stop_dnsmasq(dnsmasq_pid_file
)
3154 remove_links(self
.links
)
3155 remove_unit_from_networkd_path(self
.units
)
3156 stop_networkd(show_logs
=True)
3158 def test_dhcp_client_ipv6_only(self
):
3159 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3162 self
.wait_online(['veth-peer:carrier'])
3164 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3166 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3168 self
.assertRegex(output
, '2600::')
3169 self
.assertNotRegex(output
, '192.168.5')
3171 output
= check_output('ip addr show dev veth99')
3173 self
.assertRegex(output
, '2600::')
3174 self
.assertNotRegex(output
, '192.168.5')
3175 self
.assertNotRegex(output
, 'tentative')
3177 # Confirm that ipv6 token is not set in the kernel
3178 output
= check_output('ip token show dev veth99')
3180 self
.assertRegex(output
, 'token :: dev veth99')
3182 def test_dhcp_client_ipv4_only(self
):
3183 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
3186 self
.wait_online(['veth-peer:carrier'])
3187 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
3188 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3190 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3192 self
.assertNotRegex(output
, '2600::')
3193 self
.assertRegex(output
, '192.168.5')
3194 self
.assertRegex(output
, '192.168.5.6')
3195 self
.assertRegex(output
, '192.168.5.7')
3197 # checking routes to DNS servers
3198 output
= check_output('ip route show dev veth99')
3200 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3201 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3202 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3204 stop_dnsmasq(dnsmasq_pid_file
)
3205 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8', lease_time
='2m')
3207 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3208 print('Wait for the dynamic address to be renewed')
3211 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3213 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3215 self
.assertNotRegex(output
, '2600::')
3216 self
.assertRegex(output
, '192.168.5')
3217 self
.assertNotRegex(output
, '192.168.5.6')
3218 self
.assertRegex(output
, '192.168.5.7')
3219 self
.assertRegex(output
, '192.168.5.8')
3221 # checking routes to DNS servers
3222 output
= check_output('ip route show dev veth99')
3224 self
.assertNotRegex(output
, r
'192.168.5.6')
3225 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3226 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3227 self
.assertRegex(output
, r
'192.168.5.8 proto dhcp scope link src 192.168.5.181 metric 1024')
3229 def test_dhcp_client_ipv4_use_routes_gateway(self
):
3230 for (routes
, gateway
, dnsroutes
) in itertools
.product([True, False, None], repeat
=3):
3232 with self
.subTest(routes
=routes
, gateway
=gateway
, dnsroutes
=dnsroutes
):
3233 self
._test
_dhcp
_client
_ipv
4_use
_routes
_gateway
(routes
, gateway
, dnsroutes
)
3236 def _test_dhcp_client_ipv4_use_routes_gateway(self
, routes
, gateway
, dnsroutes
):
3237 testunit
= 'dhcp-client-ipv4-use-routes-use-gateway.network'
3238 testunits
= ['25-veth.netdev', 'dhcp-server-veth-peer.network', testunit
]
3240 testunits
.append(f
'{testunit}.d/use-routes-{routes}.conf');
3242 testunits
.append(f
'{testunit}.d/use-gateway-{gateway}.conf');
3243 if dnsroutes
!= None:
3244 testunits
.append(f
'{testunit}.d/use-dns-routes-{dnsroutes}.conf');
3245 copy_unit_to_networkd_unit_path(*testunits
, dropins
=False)
3248 self
.wait_online(['veth-peer:carrier'])
3249 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
3250 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3252 output
= check_output('ip route show dev veth99')
3255 # UseRoutes= defaults to true
3256 useroutes
= routes
in [True, None]
3257 # UseGateway= defaults to useroutes
3258 usegateway
= useroutes
if gateway
== None else gateway
3262 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.181 metric 1024')
3264 self
.assertNotRegex(output
, r
'192.168.5.5')
3268 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.181 metric 1024')
3270 self
.assertNotRegex(output
, r
'default via 192.168.5.1')
3272 # Check RoutesToDNS=, which defaults to false
3274 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3275 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3277 self
.assertNotRegex(output
, r
'192.168.5.6')
3278 self
.assertNotRegex(output
, r
'192.168.5.7')
3280 def test_dhcp_client_ipv4_ipv6(self
):
3281 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
3282 'dhcp-client-ipv4-only.network')
3284 self
.wait_online(['veth-peer:carrier'])
3286 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3288 # link become 'routable' when at least one protocol provide an valid address.
3289 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3290 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3292 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3294 self
.assertRegex(output
, '2600::')
3295 self
.assertRegex(output
, '192.168.5')
3297 def test_dhcp_client_settings(self
):
3298 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
3301 self
.wait_online(['veth-peer:carrier'])
3303 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3305 print('## ip address show dev veth99')
3306 output
= check_output('ip address show dev veth99')
3308 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3309 self
.assertRegex(output
, '192.168.5')
3310 self
.assertRegex(output
, '1492')
3312 print('## ip route show table main dev veth99')
3313 output
= check_output('ip route show table main dev veth99')
3316 main_table_is_empty
= output
== ''
3317 if not main_table_is_empty
:
3318 self
.assertNotRegex(output
, 'proto dhcp')
3320 print('## ip route show table 211 dev veth99')
3321 output
= check_output('ip route show table 211 dev veth99')
3323 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
3324 if main_table_is_empty
:
3325 self
.assertRegex(output
, '192.168.5.0/24 proto dhcp')
3326 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
3327 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
3329 print('## dnsmasq log')
3330 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
3331 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
3332 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
3333 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
3335 def test_dhcp6_client_settings_rapidcommit_true(self
):
3336 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
3338 self
.wait_online(['veth-peer:carrier'])
3340 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3342 output
= check_output('ip address show dev veth99')
3344 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3345 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
3347 def test_dhcp6_client_settings_rapidcommit_false(self
):
3348 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
3350 self
.wait_online(['veth-peer:carrier'])
3352 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3354 output
= check_output('ip address show dev veth99')
3356 self
.assertRegex(output
, '12:34:56:78:9a:bc')
3357 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
3359 def test_dhcp_client_settings_anonymize(self
):
3360 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
3362 self
.wait_online(['veth-peer:carrier'])
3364 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3366 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
3367 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
3368 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
3370 def test_dhcp_client_listen_port(self
):
3371 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
3373 self
.wait_online(['veth-peer:carrier'])
3374 start_dnsmasq('--dhcp-alternate-port=67,5555')
3375 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3377 output
= check_output('ip -4 address show dev veth99')
3379 self
.assertRegex(output
, '192.168.5.* dynamic')
3381 def test_dhcp_client_with_static_address(self
):
3382 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
3383 'dhcp-client-with-static-address.network')
3385 self
.wait_online(['veth-peer:carrier'])
3387 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3389 output
= check_output('ip address show dev veth99 scope global')
3391 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
3392 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
3394 output
= check_output('ip route show dev veth99')
3396 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
3397 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
3398 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
3399 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
3401 def test_dhcp_route_table_id(self
):
3402 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
3404 self
.wait_online(['veth-peer:carrier'])
3406 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3408 output
= check_output('ip route show table 12')
3410 self
.assertRegex(output
, 'veth99 proto dhcp')
3411 self
.assertRegex(output
, '192.168.5.1')
3413 def test_dhcp_route_metric(self
):
3414 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
3416 self
.wait_online(['veth-peer:carrier'])
3418 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3420 output
= check_output('ip route show dev veth99')
3422 self
.assertRegex(output
, 'metric 24')
3424 def test_dhcp_client_reassign_static_routes_ipv4(self
):
3425 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3426 'dhcp-client-reassign-static-routes-ipv4.network')
3428 self
.wait_online(['veth-peer:carrier'])
3429 start_dnsmasq(lease_time
='2m')
3430 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3432 output
= check_output('ip address show dev veth99 scope global')
3434 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3436 output
= check_output('ip route show dev veth99')
3438 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3439 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3440 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3441 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3443 stop_dnsmasq(dnsmasq_pid_file
)
3444 start_dnsmasq(ipv4_range
='192.168.5.210,192.168.5.220', lease_time
='2m')
3446 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3447 print('Wait for the dynamic address to be renewed')
3450 self
.wait_online(['veth99:routable'])
3452 output
= check_output('ip route show dev veth99')
3454 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3455 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
3456 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
3457 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
3459 def test_dhcp_client_reassign_static_routes_ipv6(self
):
3460 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3461 'dhcp-client-reassign-static-routes-ipv6.network')
3463 self
.wait_online(['veth-peer:carrier'])
3464 start_dnsmasq(lease_time
='2m')
3465 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3467 output
= check_output('ip address show dev veth99 scope global')
3469 self
.assertRegex(output
, r
'inet6 2600::[0-9a-f]*/128 scope global (noprefixroute dynamic|dynamic noprefixroute)')
3471 output
= check_output('ip -6 route show dev veth99')
3473 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3474 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3476 stop_dnsmasq(dnsmasq_pid_file
)
3477 start_dnsmasq(ipv6_range
='2600::30,2600::40', lease_time
='2m')
3479 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3480 print('Wait for the dynamic address to be renewed')
3483 self
.wait_online(['veth99:routable'])
3485 output
= check_output('ip -6 route show dev veth99')
3487 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
3488 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
3490 def test_dhcp_keep_configuration_dhcp(self
):
3491 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
3493 self
.wait_online(['veth-peer:carrier'])
3494 start_dnsmasq(lease_time
='2m')
3495 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3497 output
= check_output('ip address show dev veth99 scope global')
3499 self
.assertRegex(output
, r
'192.168.5.*')
3501 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3503 self
.assertRegex(output
, r
'192.168.5.*')
3505 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
3506 stop_dnsmasq(dnsmasq_pid_file
)
3508 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3509 print('Wait for the dynamic address to be expired')
3512 print('The lease address should be kept after lease expired')
3513 output
= check_output('ip address show dev veth99 scope global')
3515 self
.assertRegex(output
, r
'192.168.5.*')
3517 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3519 self
.assertRegex(output
, r
'192.168.5.*')
3521 check_output('systemctl stop systemd-networkd')
3523 print('The lease address should be kept after networkd stopped')
3524 output
= check_output('ip address show dev veth99 scope global')
3526 self
.assertRegex(output
, r
'192.168.5.*')
3528 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3530 self
.assertRegex(output
, r
'192.168.5.*')
3533 self
.wait_online(['veth-peer:routable'])
3535 print('Still the lease address should be kept after networkd restarted')
3536 output
= check_output('ip address show dev veth99 scope global')
3538 self
.assertRegex(output
, r
'192.168.5.*')
3540 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3542 self
.assertRegex(output
, r
'192.168.5.*')
3544 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
3545 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
3547 self
.wait_online(['veth-peer:carrier'])
3548 start_dnsmasq(lease_time
='2m')
3549 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3551 output
= check_output('ip address show dev veth99 scope global')
3553 self
.assertRegex(output
, r
'192.168.5.*')
3555 stop_dnsmasq(dnsmasq_pid_file
)
3556 check_output('systemctl stop systemd-networkd')
3558 output
= check_output('ip address show dev veth99 scope global')
3560 self
.assertRegex(output
, r
'192.168.5.*')
3563 self
.wait_online(['veth-peer:routable'])
3565 output
= check_output('ip address show dev veth99 scope global')
3567 self
.assertNotRegex(output
, r
'192.168.5.*')
3569 def test_dhcp_client_reuse_address_as_static(self
):
3570 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
3572 self
.wait_online(['veth-peer:carrier'])
3574 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3576 # link become 'routable' when at least one protocol provide an valid address.
3577 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3578 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3580 output
= check_output('ip address show dev veth99 scope global')
3582 self
.assertRegex(output
, '192.168.5')
3583 self
.assertRegex(output
, '2600::')
3585 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
3586 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
3587 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
3588 print(static_network
)
3590 remove_unit_from_networkd_path(['dhcp-client.network'])
3592 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
3593 f
.write(static_network
)
3595 # When networkd started, the links are already configured, so let's wait for 5 seconds
3596 # the links to be re-configured.
3598 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3600 output
= check_output('ip -4 address show dev veth99 scope global')
3602 self
.assertRegex(output
, '192.168.5')
3603 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3605 output
= check_output('ip -6 address show dev veth99 scope global')
3607 self
.assertRegex(output
, '2600::')
3608 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3610 @expectedFailureIfModuleIsNotAvailable('vrf')
3611 def test_dhcp_client_vrf(self
):
3612 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
3613 '25-vrf.netdev', '25-vrf.network')
3615 self
.wait_online(['veth-peer:carrier'])
3617 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
3619 # link become 'routable' when at least one protocol provide an valid address.
3620 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3621 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3623 print('## ip -d link show dev vrf99')
3624 output
= check_output('ip -d link show dev vrf99')
3626 self
.assertRegex(output
, 'vrf table 42')
3628 print('## ip address show vrf vrf99')
3629 output
= check_output('ip address show vrf vrf99')
3631 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3632 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3633 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3634 self
.assertRegex(output
, 'inet6 .* scope link')
3636 print('## ip address show dev veth99')
3637 output
= check_output('ip address show dev veth99')
3639 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3640 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3641 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3642 self
.assertRegex(output
, 'inet6 .* scope link')
3644 print('## ip route show vrf vrf99')
3645 output
= check_output('ip route show vrf vrf99')
3647 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
3648 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
3649 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
3650 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
3651 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
3653 print('## ip route show table main dev veth99')
3654 output
= check_output('ip route show table main dev veth99')
3656 self
.assertEqual(output
, '')
3658 def test_dhcp_client_gateway_ipv4(self
):
3659 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3660 'dhcp-client-gateway-ipv4.network')
3662 self
.wait_online(['veth-peer:carrier'])
3664 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3666 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3668 self
.assertRegex(output
, '10.0.0.0/8 via 192.168.5.1 proto static')
3670 def test_dhcp_client_gateway_ipv6(self
):
3671 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3672 'dhcp-client-gateway-ipv6.network')
3674 self
.wait_online(['veth-peer:carrier'])
3676 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3678 output
= check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
3680 self
.assertRegex(output
, 'via fe80::1034:56ff:fe78:9abd')
3682 def test_dhcp_client_gateway_onlink_implicit(self
):
3683 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3684 'dhcp-client-gateway-onlink-implicit.network')
3686 self
.wait_online(['veth-peer:carrier'])
3688 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3690 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3692 self
.assertRegex(output
, '192.168.5')
3694 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3696 self
.assertRegex(output
, 'onlink')
3697 output
= check_output('ip route list dev veth99 192.168.100.0/24')
3699 self
.assertRegex(output
, 'onlink')
3701 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
3702 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3703 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
3705 self
.wait_online(['veth-peer:carrier'])
3706 start_dnsmasq(lease_time
='2m')
3707 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3709 output
= check_output('ip address show dev veth99')
3712 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3713 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3714 output
= check_output('ip -6 address show dev veth99 scope link')
3715 self
.assertRegex(output
, 'inet6 .* scope link')
3716 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3717 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3718 output
= check_output('ip -4 address show dev veth99 scope link')
3719 self
.assertNotRegex(output
, 'inet .* scope link')
3721 print('Wait for the dynamic address to be expired')
3724 output
= check_output('ip address show dev veth99')
3727 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3728 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3729 output
= check_output('ip -6 address show dev veth99 scope link')
3730 self
.assertRegex(output
, 'inet6 .* scope link')
3731 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3732 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3733 output
= check_output('ip -4 address show dev veth99 scope link')
3734 self
.assertNotRegex(output
, 'inet .* scope link')
3736 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
3738 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
3739 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3740 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
3742 self
.wait_online(['veth99:degraded', 'veth-peer:routable'])
3744 output
= check_output('ip address show dev veth99')
3747 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3748 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3749 output
= check_output('ip -6 address show dev veth99 scope link')
3750 self
.assertRegex(output
, 'inet6 .* scope link')
3751 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3752 self
.assertNotRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3753 output
= check_output('ip -4 address show dev veth99 scope link')
3754 self
.assertRegex(output
, 'inet .* scope link')
3756 def test_dhcp_client_route_remove_on_renew(self
):
3757 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3758 'dhcp-client-ipv4-only-ipv6-disabled.network')
3760 self
.wait_online(['veth-peer:carrier'])
3761 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
3762 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3764 # test for issue #12490
3766 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3768 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3770 for line
in output
.splitlines():
3771 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3772 address1
= line
.split()[1].split('/')[0]
3775 output
= check_output('ip -4 route show dev veth99')
3777 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3778 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3780 stop_dnsmasq(dnsmasq_pid_file
)
3781 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
3783 print('Wait for the dynamic address to be expired')
3786 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3788 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3790 for line
in output
.splitlines():
3791 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3792 address2
= line
.split()[1].split('/')[0]
3795 self
.assertNotEqual(address1
, address2
)
3797 output
= check_output('ip -4 route show dev veth99')
3799 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3800 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3801 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
3802 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
3804 def test_dhcp_client_use_dns_yes(self
):
3805 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-yes.network')
3808 self
.wait_online(['veth-peer:carrier'])
3809 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3810 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3812 # link become 'routable' when at least one protocol provide an valid address.
3813 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3814 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3817 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3819 self
.assertRegex(output
, '192.168.5.1')
3820 self
.assertRegex(output
, '2600::1')
3822 def test_dhcp_client_use_dns_no(self
):
3823 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-no.network')
3826 self
.wait_online(['veth-peer:carrier'])
3827 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3828 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3830 # link become 'routable' when at least one protocol provide an valid address.
3831 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3832 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3835 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3837 self
.assertNotRegex(output
, '192.168.5.1')
3838 self
.assertNotRegex(output
, '2600::1')
3840 def test_dhcp_client_use_dns_ipv4(self
):
3841 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4.network')
3844 self
.wait_online(['veth-peer:carrier'])
3845 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3846 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3848 # link become 'routable' when at least one protocol provide an valid address.
3849 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3850 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3853 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3855 self
.assertRegex(output
, '192.168.5.1')
3856 self
.assertNotRegex(output
, '2600::1')
3858 def test_dhcp_client_use_dns_ipv4_and_ra(self
):
3859 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4-and-ra.network')
3862 self
.wait_online(['veth-peer:carrier'])
3863 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3864 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3866 # link become 'routable' when at least one protocol provide an valid address.
3867 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3868 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3871 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3873 self
.assertRegex(output
, '192.168.5.1')
3874 self
.assertRegex(output
, '2600::1')
3876 def test_dhcp_client_use_domains(self
):
3877 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-domains.network')
3880 self
.wait_online(['veth-peer:carrier'])
3881 start_dnsmasq('--dhcp-option=option:domain-search,example.com')
3882 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3884 output
= check_output(*networkctl_cmd
, '-n', '0', 'status', 'veth99', env
=env
)
3886 self
.assertRegex(output
, 'Search Domains: example.com')
3889 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
3891 self
.assertRegex(output
, 'example.com')
3893 def test_dhcp_client_decline(self
):
3894 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-decline.network', 'dhcp-client-decline.network')
3897 self
.wait_online(['veth-peer:carrier'])
3898 rc
= call(*wait_online_cmd
, '--timeout=10s', '--interface=veth99:routable', env
=env
)
3899 self
.assertTrue(rc
== 1)
3901 class NetworkdIPv6PrefixTests(unittest
.TestCase
, Utilities
):
3906 'ipv6ra-prefix-client.network',
3907 'ipv6ra-prefix.network'
3911 remove_links(self
.links
)
3912 stop_networkd(show_logs
=False)
3916 remove_links(self
.links
)
3917 remove_unit_from_networkd_path(self
.units
)
3918 stop_networkd(show_logs
=True)
3920 def test_ipv6_route_prefix(self
):
3921 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client.network', 'ipv6ra-prefix.network')
3924 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3926 output
= check_output('ip -6 route show dev veth-peer')
3928 self
.assertRegex(output
, '2001:db8:0:1::/64 proto ra')
3930 output
= check_output('ip addr show dev veth99')
3932 self
.assertNotRegex(output
, '2001:db8:0:1')
3933 self
.assertRegex(output
, '2001:db8:0:2')
3935 class NetworkdMTUTests(unittest
.TestCase
, Utilities
):
3940 '12-dummy-mtu.netdev',
3941 '12-dummy-mtu.link',
3946 remove_links(self
.links
)
3947 stop_networkd(show_logs
=False)
3951 remove_links(self
.links
)
3952 remove_unit_from_networkd_path(self
.units
)
3953 stop_networkd(show_logs
=True)
3955 def check_mtu(self
, mtu
, ipv6_mtu
=None, reset
=True):
3961 self
.wait_online(['dummy98:routable'])
3962 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
3963 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
3965 # test normal restart
3967 self
.wait_online(['dummy98:routable'])
3968 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
3969 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
3972 self
.reset_check_mtu(mtu
, ipv6_mtu
)
3974 def reset_check_mtu(self
, mtu
, ipv6_mtu
=None):
3975 ''' test setting mtu/ipv6_mtu with interface already up '''
3978 # note - changing the device mtu resets the ipv6 mtu
3979 run('ip link set up mtu 1501 dev dummy98')
3980 run('ip link set up mtu 1500 dev dummy98')
3981 self
.assertEqual(read_link_attr('dummy98', 'mtu'), '1500')
3982 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), '1500')
3984 self
.check_mtu(mtu
, ipv6_mtu
, reset
=False)
3986 def test_mtu_network(self
):
3987 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
3988 self
.check_mtu('1600')
3990 def test_mtu_netdev(self
):
3991 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network', dropins
=False)
3992 # note - MTU set by .netdev happens ONLY at device creation!
3993 self
.check_mtu('1600', reset
=False)
3995 def test_mtu_link(self
):
3996 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', dropins
=False)
3997 # must reload udev because it only picks up new files after 3 second delay
3998 call('udevadm control --reload')
3999 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
4000 self
.check_mtu('1600', reset
=False)
4002 def test_ipv6_mtu(self
):
4003 ''' set ipv6 mtu without setting device mtu '''
4004 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
4005 self
.check_mtu('1500', '1400')
4007 def test_ipv6_mtu_toolarge(self
):
4008 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
4009 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
4010 self
.check_mtu('1500', '1500')
4012 def test_mtu_network_ipv6_mtu(self
):
4013 ''' set ipv6 mtu and set device mtu via network file '''
4014 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
4015 self
.check_mtu('1600', '1550')
4017 def test_mtu_netdev_ipv6_mtu(self
):
4018 ''' set ipv6 mtu and set device mtu via netdev file '''
4019 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
4020 self
.check_mtu('1600', '1550', reset
=False)
4022 def test_mtu_link_ipv6_mtu(self
):
4023 ''' set ipv6 mtu and set device mtu via link file '''
4024 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
4025 # must reload udev because it only picks up new files after 3 second delay
4026 call('udevadm control --reload')
4027 self
.check_mtu('1600', '1550', reset
=False)
4030 if __name__
== '__main__':
4031 parser
= argparse
.ArgumentParser()
4032 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
4033 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
4034 parser
.add_argument('--resolved', help='Path to systemd-resolved', dest
='resolved_bin')
4035 parser
.add_argument('--udevd', help='Path to systemd-udevd', dest
='udevd_bin')
4036 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
4037 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
4038 parser
.add_argument('--resolvectl', help='Path to resolvectl', dest
='resolvectl_bin')
4039 parser
.add_argument('--timedatectl', help='Path to timedatectl', dest
='timedatectl_bin')
4040 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
4041 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
4042 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
4043 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
4044 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
4045 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
4048 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
:
4049 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
4050 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
4051 resolved_bin
= os
.path
.join(ns
.build_dir
, 'systemd-resolved')
4052 udevd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-udevd')
4053 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
4054 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
4055 resolvectl_bin
= os
.path
.join(ns
.build_dir
, 'resolvectl')
4056 timedatectl_bin
= os
.path
.join(ns
.build_dir
, 'timedatectl')
4059 networkd_bin
= ns
.networkd_bin
4061 resolved_bin
= ns
.resolved_bin
4063 udevd_bin
= ns
.udevd_bin
4064 if ns
.wait_online_bin
:
4065 wait_online_bin
= ns
.wait_online_bin
4066 if ns
.networkctl_bin
:
4067 networkctl_bin
= ns
.networkctl_bin
4068 if ns
.resolvectl_bin
:
4069 resolvectl_bin
= ns
.resolvectl_bin
4070 if ns
.timedatectl_bin
:
4071 timedatectl_bin
= ns
.timedatectl_bin
4073 use_valgrind
= ns
.use_valgrind
4074 enable_debug
= ns
.enable_debug
4075 asan_options
= ns
.asan_options
4076 lsan_options
= ns
.lsan_options
4077 ubsan_options
= ns
.ubsan_options
4080 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
4081 resolvectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin
]
4082 timedatectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin
]
4083 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
4085 networkctl_cmd
= [networkctl_bin
]
4086 resolvectl_cmd
= [resolvectl_bin
]
4087 timedatectl_cmd
= [timedatectl_bin
]
4088 wait_online_cmd
= [wait_online_bin
]
4091 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
4093 env
.update({ 'ASAN_OPTIONS' : asan_options
})
4095 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
4097 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
4100 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,