]> git.ipfire.org Git - thirdparty/systemd.git/blame - test/test-network/systemd-networkd-tests.py
network: make address_get() work for null address
[thirdparty/systemd.git] / test / test-network / systemd-networkd-tests.py
CommitLineData
1f0e3109 1#!/usr/bin/env python3
db9ecf05 2# SPDX-License-Identifier: LGPL-2.1-or-later
87bf983c
FS
3# pylint: disable=line-too-long,too-many-lines,too-many-branches,too-many-statements,too-many-arguments
4# pylint: disable=too-many-public-methods,too-many-boolean-expressions,invalid-name
5# pylint: disable=missing-function-docstring,missing-class-docstring,missing-module-docstring
1f0e3109
SS
6# systemd-networkd tests
7
0f1853e2 8# These tests can be executed in the systemd mkosi image when booted in QEMU. After booting the QEMU VM,
3ceb96e0 9# simply run this file which can be found in the VM at /usr/lib/systemd/tests/testdata/test-network/systemd-networkd-tests.py.
0f1853e2 10
9c1ae484 11import argparse
dded88ac 12import errno
7c0d36ff 13import itertools
1f0e3109 14import os
a962d857 15import pathlib
201bf07f 16import re
1f0e3109
SS
17import shutil
18import signal
a9bc5e37
YW
19import subprocess
20import sys
a9bc5e37
YW
21import time
22import unittest
a962d857 23
ef11b841
FS
24import psutil
25
a962d857
YW
26network_unit_dir = '/run/systemd/network'
27networkd_conf_dropin_dir = '/run/systemd/networkd.conf.d'
28networkd_ci_temp_dir = '/run/networkd-ci'
29udev_rules_dir = '/run/udev/rules.d'
30
31dnsmasq_pid_file = '/run/networkd-ci/test-dnsmasq.pid'
32dnsmasq_log_file = '/run/networkd-ci/test-dnsmasq.log'
33dnsmasq_lease_file = '/run/networkd-ci/test-dnsmasq.lease'
34
35isc_dhcpd_pid_file = '/run/networkd-ci/test-isc-dhcpd.pid'
36isc_dhcpd_lease_file = '/run/networkd-ci/test-isc-dhcpd.lease'
37
38systemd_lib_paths = ['/usr/lib/systemd', '/lib/systemd']
39which_paths = ':'.join(systemd_lib_paths + os.getenv('PATH', os.defpath).lstrip(':').split(':'))
40
41networkd_bin = shutil.which('systemd-networkd', path=which_paths)
42resolved_bin = shutil.which('systemd-resolved', path=which_paths)
b05c4d6b 43timesyncd_bin = shutil.which('systemd-timesyncd', path=which_paths)
a962d857
YW
44udevd_bin = shutil.which('systemd-udevd', path=which_paths)
45wait_online_bin = shutil.which('systemd-networkd-wait-online', path=which_paths)
46networkctl_bin = shutil.which('networkctl', path=which_paths)
47resolvectl_bin = shutil.which('resolvectl', path=which_paths)
48timedatectl_bin = shutil.which('timedatectl', path=which_paths)
b05c4d6b 49udevadm_bin = shutil.which('udevadm', path=which_paths)
a962d857
YW
50
51use_valgrind = False
b05c4d6b 52valgrind_cmd = ''
a962d857 53enable_debug = True
9c1ae484 54env = {}
163d095f 55wait_online_env = {}
a962d857
YW
56asan_options = None
57lsan_options = None
58ubsan_options = None
59with_coverage = False
60
61active_units = []
62protected_links = {
63 'erspan0',
64 'gre0',
65 'gretap0',
66 'ifb0',
67 'ifb1',
68 'ip6_vti0',
69 'ip6gre0',
70 'ip6tnl0',
71 'ip_vti0',
72 'lo',
73 'sit0',
74 'tunl0',
75}
76saved_routes = None
77saved_ipv4_rules = None
78saved_ipv6_rules = None
f54dce2d 79saved_timezone = None
a962d857
YW
80
81def rm_f(path):
82 if os.path.exists(path):
83 os.remove(path)
84
85def rm_rf(path):
86 shutil.rmtree(path, ignore_errors=True)
87
88def cp(src, dst):
89 shutil.copy(src, dst)
90
91def cp_r(src, dst):
92 shutil.copytree(src, dst, copy_function=shutil.copy)
93
94def mkdir_p(path):
95 os.makedirs(path, exist_ok=True)
96
97def touch(path):
98 pathlib.Path(path).touch()
99
f9073c24 100# pylint: disable=R1710
66504b22 101def check_output(*command, **kwargs):
a962d857
YW
102 # This checks the result and returns stdout (and stderr) on success.
103 command = command[0].split() + list(command[1:])
17479d51
YW
104 ret = subprocess.run(command, check=False, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kwargs)
105 if ret.returncode == 0:
106 return ret.stdout.rstrip()
107 # When returncode != 0, print stdout and stderr, then trigger CalledProcessError.
108 print(ret.stdout)
109 ret.check_returncode()
2225e7fd 110
66504b22 111def call(*command, **kwargs):
b5dac5b0 112 # This returns returncode. stdout and stderr are merged and shown in console
371810d1 113 command = command[0].split() + list(command[1:])
66504b22 114 return subprocess.run(command, check=False, universal_newlines=True, stderr=subprocess.STDOUT, **kwargs).returncode
371810d1 115
66504b22 116def call_quiet(*command, **kwargs):
371810d1 117 command = command[0].split() + list(command[1:])
66504b22 118 return subprocess.run(command, check=False, universal_newlines=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, **kwargs).returncode
371810d1 119
66504b22 120def run(*command, **kwargs):
a962d857 121 # This returns CompletedProcess instance.
371810d1 122 command = command[0].split() + list(command[1:])
66504b22 123 return subprocess.run(command, check=False, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
371810d1 124
59edcf2b
YW
125def is_module_available(*module_names):
126 for module_name in module_names:
127 lsmod_output = check_output('lsmod')
128 module_re = re.compile(rf'^{re.escape(module_name)}\b', re.MULTILINE)
129 if not module_re.search(lsmod_output) and call_quiet('modprobe', module_name) != 0:
130 return False
131 return True
132
133def expectedFailureIfModuleIsNotAvailable(*module_names):
7a0a37b2 134 def f(func):
59edcf2b 135 return func if is_module_available(*module_names) else unittest.expectedFailure(func)
7a0a37b2
EV
136
137 return f
138
2f0260c1
YW
139def expectedFailureIfERSPANv0IsNotSupported():
140 # erspan version 0 is supported since f989d546a2d5a9f001f6f8be49d98c10ab9b1897 (v5.8)
7bea7f9b 141 def f(func):
a962d857
YW
142 rc = call_quiet('ip link add dev erspan99 type erspan seq key 30 local 192.168.1.4 remote 192.168.1.1 erspan_ver 0')
143 remove_link('erspan99')
144 return func if rc == 0 else unittest.expectedFailure(func)
2f0260c1
YW
145
146 return f
147
148def expectedFailureIfERSPANv2IsNotSupported():
149 # erspan version 2 is supported since f551c91de262ba36b20c3ac19538afb4f4507441 (v4.16)
150 def f(func):
a962d857
YW
151 rc = call_quiet('ip link add dev erspan99 type erspan seq key 30 local 192.168.1.4 remote 192.168.1.1 erspan_ver 2')
152 remove_link('erspan99')
153 return func if rc == 0 else unittest.expectedFailure(func)
7bea7f9b
SS
154
155 return f
156
d586a2c3
YW
157def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable():
158 def f(func):
a962d857
YW
159 rc = call_quiet('ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
160 call_quiet('ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
161 return func if rc == 0 else unittest.expectedFailure(func)
d586a2c3
YW
162
163 return f
164
165def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
166 def f(func):
a962d857
YW
167 rc = call_quiet('ip rule add not from 192.168.100.19 ipproto tcp table 7')
168 call_quiet('ip rule del not from 192.168.100.19 ipproto tcp table 7')
169 return func if rc == 0 else unittest.expectedFailure(func)
d586a2c3
YW
170
171 return f
172
6be8e78e
YW
173def expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable():
174 def f(func):
a962d857
YW
175 supported = False
176 if call_quiet('ip rule add from 192.168.100.19 table 7 uidrange 200-300') == 0:
177 ret = run('ip rule list from 192.168.100.19 table 7')
178 supported = ret.returncode == 0 and 'uidrange 200-300' in ret.stdout
179 call_quiet('ip rule del from 192.168.100.19 table 7 uidrange 200-300')
180 return func if supported else unittest.expectedFailure(func)
6be8e78e
YW
181
182 return f
183
086bcf5d
YW
184def expectedFailureIfNexthopIsNotAvailable():
185 def f(func):
a962d857
YW
186 rc = call_quiet('ip nexthop list')
187 return func if rc == 0 else unittest.expectedFailure(func)
086bcf5d
YW
188
189 return f
190
297f9d86
YW
191def expectedFailureIfRTA_VIAIsNotSupported():
192 def f(func):
a962d857
YW
193 call_quiet('ip link add dummy98 type dummy')
194 call_quiet('ip link set up dev dummy98')
195 call_quiet('ip route add 2001:1234:5:8fff:ff:ff:ff:fe/128 dev dummy98')
196 rc = call_quiet('ip route add 10.10.10.10 via inet6 2001:1234:5:8fff:ff:ff:ff:fe dev dummy98')
197 remove_link('dummy98')
198 return func if rc == 0 else unittest.expectedFailure(func)
297f9d86
YW
199
200 return f
201
6934ace0
YW
202def expectedFailureIfAlternativeNameIsNotAvailable():
203 def f(func):
a962d857
YW
204 call_quiet('ip link add dummy98 type dummy')
205 supported = \
206 call_quiet('ip link prop add dev dummy98 altname hogehogehogehogehoge') == 0 and \
207 call_quiet('ip link show dev hogehogehogehogehoge') == 0
208 remove_link('dummy98')
209 return func if supported else unittest.expectedFailure(func)
6934ace0
YW
210
211 return f
212
3d2c2692
YW
213def expectedFailureIfNetdevsimWithSRIOVIsNotAvailable():
214 def f(func):
a962d857
YW
215 def finalize(func, supported):
216 call_quiet('rmmod netdevsim')
217 return func if supported else unittest.expectedFailure(func)
218
219 call_quiet('rmmod netdevsim')
220 if call_quiet('modprobe netdevsim') != 0:
221 return finalize(func, False)
3d2c2692
YW
222
223 try:
d45476ef 224 with open('/sys/bus/netdevsim/new_device', mode='w', encoding='utf-8') as f:
3d2c2692 225 f.write('99 1')
54e2f32f 226 except OSError:
a962d857 227 return finalize(func, False)
3d2c2692 228
d8746f16 229 return finalize(func, os.path.exists('/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs'))
3d2c2692
YW
230
231 return f
232
b3de9d7b
FS
233# pylint: disable=C0415
234def compare_kernel_version(min_kernel_version):
235 try:
236 import platform
237 from packaging import version
238 except ImportError:
239 print('Failed to import either platform or packaging module, assuming the comparison failed')
240 return False
241
242 # Get only the actual kernel version without any build/distro/arch stuff
243 # e.g. '5.18.5-200.fc36.x86_64' -> '5.18.5'
244 kver = platform.release().split('-')[0]
245
246 return version.parse(kver) >= version.parse(min_kernel_version)
247
32ab27af 248def udev_reload():
b05c4d6b 249 check_output(*udevadm_cmd, 'control', '--reload')
32ab27af 250
a962d857
YW
251def copy_network_unit(*units, copy_dropins=True):
252 """
253 Copy networkd unit files into the testbed.
1f0e3109 254
a962d857 255 Any networkd unit file type can be specified, as well as drop-in files.
1f0e3109 256
a962d857
YW
257 By default, all drop-ins for a specified unit file are copied in;
258 to avoid that specify dropins=False.
3e3b0d2a 259
a962d857
YW
260 When a drop-in file is specified, its unit file is also copied in automatically.
261 """
32ab27af 262 has_link = False
a962d857
YW
263 mkdir_p(network_unit_dir)
264 for unit in units:
265 if copy_dropins and os.path.exists(os.path.join(networkd_ci_temp_dir, unit + '.d')):
266 cp_r(os.path.join(networkd_ci_temp_dir, unit + '.d'), os.path.join(network_unit_dir, unit + '.d'))
32ab27af 267
a962d857
YW
268 if unit.endswith('.conf'):
269 dropin = unit
270 unit = os.path.dirname(dropin).rstrip('.d')
271 dropindir = os.path.join(network_unit_dir, unit + '.d')
272 mkdir_p(dropindir)
273 cp(os.path.join(networkd_ci_temp_dir, dropin), dropindir)
32ab27af 274
a962d857
YW
275 cp(os.path.join(networkd_ci_temp_dir, unit), network_unit_dir)
276
32ab27af
YW
277 if unit.endswith('.link'):
278 has_link = True
279
280 if has_link:
281 udev_reload()
282
a962d857
YW
283def remove_network_unit(*units):
284 """
285 Remove previously copied unit files from the testbed.
286
287 Drop-ins will be removed automatically.
288 """
32ab27af 289 has_link = False
a962d857
YW
290 for unit in units:
291 rm_f(os.path.join(network_unit_dir, unit))
292 rm_rf(os.path.join(network_unit_dir, unit + '.d'))
293
32ab27af
YW
294 if unit.endswith('.link') or unit.endswith('.link.d'):
295 has_link = True
296
297 if has_link:
298 udev_reload()
299
a962d857 300def clear_network_units():
32ab27af
YW
301 has_link = False
302 if os.path.exists(network_unit_dir):
303 units = os.listdir(network_unit_dir)
304 for unit in units:
305 if unit.endswith('.link') or unit.endswith('.link.d'):
306 has_link = True
307
a962d857
YW
308 rm_rf(network_unit_dir)
309
32ab27af
YW
310 if has_link:
311 udev_reload()
312
a962d857
YW
313def copy_networkd_conf_dropin(*dropins):
314 """Copy networkd.conf dropin files into the testbed."""
315 mkdir_p(networkd_conf_dropin_dir)
316 for dropin in dropins:
317 cp(os.path.join(networkd_ci_temp_dir, dropin), networkd_conf_dropin_dir)
318
319def remove_networkd_conf_dropin(*dropins):
320 """Remove previously copied networkd.conf dropin files from the testbed."""
321 for dropin in dropins:
322 rm_f(os.path.join(networkd_conf_dropin_dir, dropin))
323
324def clear_networkd_conf_dropins():
325 rm_rf(networkd_conf_dropin_dir)
326
327def copy_udev_rule(*rules):
328 """Copy udev rules"""
329 mkdir_p(udev_rules_dir)
330 for rule in rules:
331 cp(os.path.join(networkd_ci_temp_dir, rule), udev_rules_dir)
332
333def remove_udev_rule(*rules):
334 """Remove previously copied udev rules"""
335 for rule in rules:
336 rm_f(os.path.join(udev_rules_dir, rule))
337
338def clear_udev_rules():
339 rm_rf(udev_rules_dir)
340
341def save_active_units():
87b308c8 342 for u in ['systemd-networkd.socket', 'systemd-networkd.service',
b05c4d6b 343 'systemd-resolved.service', 'systemd-timesyncd.service',
f7ada4b8 344 'firewalld.service']:
2225e7fd 345 if call(f'systemctl is-active --quiet {u}') == 0:
a962d857
YW
346 call(f'systemctl stop {u}')
347 active_units.append(u)
348
349def restore_active_units():
350 if 'systemd-networkd.socket' in active_units:
351 call('systemctl stop systemd-networkd.socket systemd-networkd.service')
a962d857
YW
352 for u in active_units:
353 call(f'systemctl restart {u}')
354
93f5ae6b
YW
355def create_unit_dropin(unit, contents):
356 mkdir_p(f'/run/systemd/system/{unit}.d')
357 with open(f'/run/systemd/system/{unit}.d/00-override.conf', mode='w', encoding='utf-8') as f:
358 f.write('\n'.join(contents))
359
62eaf8d0 360def create_service_dropin(service, command, additional_settings=None):
b05c4d6b
YW
361 drop_in = [
362 '[Service]',
363 'ExecStart=',
364 f'ExecStart=!!{valgrind_cmd}{command}',
365 ]
b05c4d6b
YW
366 if enable_debug:
367 drop_in += ['Environment=SYSTEMD_LOG_LEVEL=debug']
368 if asan_options:
369 drop_in += [f'Environment=ASAN_OPTIONS="{asan_options}"']
370 if lsan_options:
371 drop_in += [f'Environment=LSAN_OPTIONS="{lsan_options}"']
372 if ubsan_options:
373 drop_in += [f'Environment=UBSAN_OPTIONS="{ubsan_options}"']
374 if asan_options or lsan_options or ubsan_options:
375 drop_in += ['SystemCallFilter=']
376 if use_valgrind or asan_options or lsan_options or ubsan_options:
377 drop_in += ['MemoryDenyWriteExecute=no']
378 if use_valgrind:
379 drop_in += [
380 'Environment=SYSTEMD_MEMPOOL=0',
381 'PrivateTmp=yes',
382 ]
383 if with_coverage:
384 drop_in += [
385 'ProtectSystem=no',
386 'ProtectHome=no',
387 ]
388 if additional_settings:
389 drop_in += additional_settings
390
93f5ae6b 391 create_unit_dropin(f'{service}.service', drop_in)
b05c4d6b 392
a962d857 393def link_exists(link):
dee6c26f 394 return call_quiet(f'ip link show {link}') == 0
a962d857 395
b95d35b5
YW
396def link_resolve(link):
397 return check_output(f'ip link show {link}').split(':')[1].strip()
a962d857
YW
398
399def remove_link(*links, protect=False):
400 for link in links:
401 if protect and link in protected_links:
402 continue
403 if link_exists(link):
404 call(f'ip link del dev {link}')
405
406def save_existing_links():
407 links = os.listdir('/sys/class/net')
408 for link in links:
409 if link_exists(link):
410 protected_links.add(link)
411
412 print('### The following links will be protected:')
413 print(', '.join(sorted(list(protected_links))))
414
415def flush_links():
416 links = os.listdir('/sys/class/net')
417 remove_link(*links, protect=True)
418
419def flush_nexthops():
420 # Currently, the 'ip nexthop' command does not have 'save' and 'restore'.
421 # Hence, we cannot restore nexthops in a simple way.
422 # Let's assume there is no nexthop used in the system
423 call_quiet('ip nexthop flush')
424
425def save_routes():
426 # pylint: disable=global-statement
427 global saved_routes
428 saved_routes = check_output('ip route show table all')
429 print('### The following routes will be protected:')
430 print(saved_routes)
431
432def flush_routes():
433 have = False
434 output = check_output('ip route show table all')
435 for line in output.splitlines():
436 if line in saved_routes:
437 continue
438 if 'proto kernel' in line:
439 continue
440 if ' dev ' in line and not ' dev lo ' in line:
441 continue
442 if not have:
443 have = True
444 print('### Removing routes that did not exist when the test started.')
445 print(f'# {line}')
446 call(f'ip route del {line}')
447
448def save_routing_policy_rules():
449 # pylint: disable=global-statement
450 global saved_ipv4_rules, saved_ipv6_rules
451 def save(ipv):
452 output = check_output(f'ip -{ipv} rule show')
453 print(f'### The following IPv{ipv} routing policy rules will be protected:')
454 print(output)
455 return output
456
457 saved_ipv4_rules = save(4)
458 saved_ipv6_rules = save(6)
459
460def flush_routing_policy_rules():
461 def flush(ipv, saved_rules):
462 have = False
463 output = check_output(f'ip -{ipv} rule show')
464 for line in output.splitlines():
465 if line in saved_rules:
466 continue
467 if not have:
468 have = True
469 print(f'### Removing IPv{ipv} routing policy rules that did not exist when the test started.')
470 print(f'# {line}')
e755ad61 471 words = line.replace('lookup [l3mdev-table]', 'l3mdev').split()
a962d857
YW
472 priority = words[0].rstrip(':')
473 call(f'ip -{ipv} rule del priority {priority} ' + ' '.join(words[1:]))
474
475 flush(4, saved_ipv4_rules)
476 flush(6, saved_ipv6_rules)
477
478def flush_fou_ports():
479 ret = run('ip fou show')
480 if ret.returncode != 0:
481 return # fou may not be supported
482 for line in ret.stdout.splitlines():
483 port = line.split()[1]
484 call(f'ip fou del port {port}')
485
486def flush_l2tp_tunnels():
e11d0e39 487 tids = []
49ad2872
YW
488 ret = run('ip l2tp show tunnel')
489 if ret.returncode != 0:
490 return # l2tp may not be supported
491 for line in ret.stdout.splitlines():
a962d857
YW
492 words = line.split()
493 if words[0] == 'Tunnel':
494 tid = words[1].rstrip(',')
495 call(f'ip l2tp del tunnel tunnel_id {tid}')
e11d0e39
YW
496 tids.append(tid)
497
498 # Removing L2TP tunnel is asynchronous and slightly takes a time.
499 for tid in tids:
500 for _ in range(50):
501 r = run(f'ip l2tp show tunnel tunnel_id {tid}')
502 if r.returncode != 0 or len(r.stdout.rstrip()) == 0:
503 break
504 time.sleep(.2)
505 else:
506 print(f'Cannot remove L2TP tunnel {tid}, ignoring.')
a962d857 507
f54dce2d 508def save_timezone():
f9073c24 509 # pylint: disable=global-statement
f54dce2d 510 global saved_timezone
67a9b3ec 511 r = run(*timedatectl_cmd, 'show', '--value', '--property', 'Timezone', env=env)
f54dce2d
YW
512 if r.returncode == 0:
513 saved_timezone = r.stdout.rstrip()
514 print(f'### Saved timezone: {saved_timezone}')
515
516def restore_timezone():
517 if saved_timezone:
67a9b3ec 518 call(*timedatectl_cmd, 'set-timezone', f'{saved_timezone}', env=env)
f54dce2d 519
a962d857
YW
520def read_link_attr(*args):
521 with open(os.path.join('/sys/class/net', *args), encoding='utf-8') as f:
522 return f.readline().strip()
523
524def read_link_state_file(link):
525 ifindex = read_link_attr(link, 'ifindex')
526 path = os.path.join('/run/systemd/netif/links', ifindex)
527 with open(path, encoding='utf-8') as f:
528 return f.read()
529
530def read_ip_sysctl_attr(link, attribute, ipv):
531 with open(os.path.join('/proc/sys/net', ipv, 'conf', link, attribute), encoding='utf-8') as f:
532 return f.readline().strip()
533
534def read_ipv6_sysctl_attr(link, attribute):
535 return read_ip_sysctl_attr(link, attribute, 'ipv6')
536
537def read_ipv4_sysctl_attr(link, attribute):
538 return read_ip_sysctl_attr(link, attribute, 'ipv4')
539
540def start_dnsmasq(*additional_options, interface='veth-peer', lease_time='2m', ipv4_range='192.168.5.10,192.168.5.200', ipv4_router='192.168.5.1', ipv6_range='2600::10,2600::20'):
541 command = (
542 'dnsmasq',
543 f'--log-facility={dnsmasq_log_file}',
544 '--log-queries=extra',
545 '--log-dhcp',
546 f'--pid-file={dnsmasq_pid_file}',
547 '--conf-file=/dev/null',
548 '--bind-interfaces',
549 f'--interface={interface}',
550 f'--dhcp-leasefile={dnsmasq_lease_file}',
551 '--enable-ra',
552 f'--dhcp-range={ipv6_range},{lease_time}',
553 f'--dhcp-range={ipv4_range},{lease_time}',
554 '--dhcp-option=option:mtu,1492',
555 f'--dhcp-option=option:router,{ipv4_router}',
556 '--port=0',
557 '--no-resolv',
558 ) + additional_options
559 check_output(*command)
560
561def stop_by_pid_file(pid_file):
562 if not os.path.exists(pid_file):
563 return
564 with open(pid_file, 'r', encoding='utf-8') as f:
565 pid = f.read().rstrip(' \t\r\n\0')
566 os.kill(int(pid), signal.SIGTERM)
567 for _ in range(25):
568 try:
569 os.kill(int(pid), 0)
570 print(f"PID {pid} is still alive, waiting...")
571 time.sleep(.2)
572 except OSError as e:
573 if e.errno == errno.ESRCH:
574 break
575 print(f"Unexpected exception when waiting for {pid} to die: {e.errno}")
576 os.remove(pid_file)
577
578def stop_dnsmasq():
579 stop_by_pid_file(dnsmasq_pid_file)
580 rm_f(dnsmasq_lease_file)
581 rm_f(dnsmasq_log_file)
582
583def read_dnsmasq_log_file():
584 with open(dnsmasq_log_file, encoding='utf-8') as f:
585 return f.read()
586
587def start_isc_dhcpd(conf_file, ipv, interface='veth-peer'):
588 conf_file_path = os.path.join(networkd_ci_temp_dir, conf_file)
589 isc_dhcpd_command = f'dhcpd {ipv} -cf {conf_file_path} -lf {isc_dhcpd_lease_file} -pf {isc_dhcpd_pid_file} {interface}'
590 touch(isc_dhcpd_lease_file)
591 check_output(isc_dhcpd_command)
592
593def stop_isc_dhcpd():
594 stop_by_pid_file(isc_dhcpd_pid_file)
595 rm_f(isc_dhcpd_lease_file)
596
5bd2a7c5
YW
597def networkd_invocation_id():
598 return check_output('systemctl show --value -p InvocationID systemd-networkd.service')
599
600def read_networkd_log(invocation_id=None):
601 if not invocation_id:
602 invocation_id = networkd_invocation_id()
603 return check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id)
604
a962d857
YW
605def stop_networkd(show_logs=True):
606 if show_logs:
5bd2a7c5 607 invocation_id = networkd_invocation_id()
a962d857
YW
608 check_output('systemctl stop systemd-networkd.socket')
609 check_output('systemctl stop systemd-networkd.service')
610 if show_logs:
5bd2a7c5 611 print(read_networkd_log(invocation_id))
a962d857
YW
612
613def start_networkd():
614 check_output('systemctl start systemd-networkd')
615
616def restart_networkd(show_logs=True):
85b1a14d 617 if show_logs:
5bd2a7c5 618 invocation_id = networkd_invocation_id()
85b1a14d
YW
619 check_output('systemctl restart systemd-networkd.service')
620 if show_logs:
5bd2a7c5 621 print(read_networkd_log(invocation_id))
a962d857 622
ae014ecb
YW
623def networkd_pid():
624 return int(check_output('systemctl show --value -p MainPID systemd-networkd.service'))
625
a962d857
YW
626def networkctl_reconfigure(*links):
627 check_output(*networkctl_cmd, 'reconfigure', *links, env=env)
628
629def networkctl_reload(sleep_time=1):
630 check_output(*networkctl_cmd, 'reload', env=env)
631 # 'networkctl reload' asynchronously reconfigure links.
632 # Hence, we need to wait for a short time for link to be in configuring state.
633 if sleep_time > 0:
634 time.sleep(sleep_time)
635
636def setup_common():
637 print()
638
639def tear_down_common():
640 # 1. stop DHCP servers
641 stop_dnsmasq()
642 stop_isc_dhcpd()
643
644 # 2. remove modules
645 call_quiet('rmmod netdevsim')
646 call_quiet('rmmod sch_teql')
647
648 # 3. remove network namespace
649 call_quiet('ip netns del ns99')
650
651 # 4. remove links
e11d0e39 652 flush_l2tp_tunnels()
a962d857
YW
653 flush_links()
654
655 # 5. stop networkd
249b7ecc 656 stop_networkd()
a962d857
YW
657
658 # 6. remove configs
659 clear_network_units()
660 clear_networkd_conf_dropins()
661
662 # 7. flush settings
663 flush_fou_ports()
a962d857
YW
664 flush_nexthops()
665 flush_routing_policy_rules()
666 flush_routes()
667
668def setUpModule():
669 rm_rf(networkd_ci_temp_dir)
670 cp_r(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'conf'), networkd_ci_temp_dir)
671
672 clear_network_units()
673 clear_networkd_conf_dropins()
674 clear_udev_rules()
675
676 copy_udev_rule('00-debug-net.rules')
677
678 # Save current state
679 save_active_units()
680 save_existing_links()
681 save_routes()
682 save_routing_policy_rules()
f54dce2d 683 save_timezone()
c0bf6733 684
b05c4d6b 685 create_service_dropin('systemd-networkd', networkd_bin,
b05c4d6b
YW
686 ['[Service]', 'Restart=no', '[Unit]', 'StartLimitIntervalSec=0'])
687 create_service_dropin('systemd-resolved', resolved_bin)
688 create_service_dropin('systemd-timesyncd', timesyncd_bin)
b6d587d1 689
b05c4d6b
YW
690 # TODO: also run udevd with sanitizers, valgrind, or coverage
691 #create_service_dropin('systemd-udevd', udevd_bin,
692 # f'{udevadm_bin} control --reload --timeout 0')
93f5ae6b
YW
693 create_unit_dropin(
694 'systemd-udevd.service',
695 [
696 '[Service]',
697 'ExecStart=',
698 f'ExecStart=!!{udevd_bin}',
93f5ae6b
YW
699 ]
700 )
701 create_unit_dropin(
702 'systemd-networkd.socket',
703 [
704 '[Unit]',
705 'StartLimitIntervalSec=0',
706 ]
707 )
641aa412 708
371810d1
ZJS
709 check_output('systemctl daemon-reload')
710 print(check_output('systemctl cat systemd-networkd.service'))
b6d587d1 711 print(check_output('systemctl cat systemd-resolved.service'))
b05c4d6b 712 print(check_output('systemctl cat systemd-timesyncd.service'))
641aa412 713 print(check_output('systemctl cat systemd-udevd.service'))
a962d857 714 check_output('systemctl restart systemd-resolved.service')
b05c4d6b 715 check_output('systemctl restart systemd-timesyncd.service')
a962d857 716 check_output('systemctl restart systemd-udevd.service')
9c1ae484 717
1f0e3109 718def tearDownModule():
a962d857
YW
719 rm_rf(networkd_ci_temp_dir)
720 clear_udev_rules()
721 clear_network_units()
722 clear_networkd_conf_dropins()
723
f54dce2d
YW
724 restore_timezone()
725
a962d857 726 rm_rf('/run/systemd/system/systemd-networkd.service.d')
93f5ae6b 727 rm_rf('/run/systemd/system/systemd-networkd.socket.d')
a962d857 728 rm_rf('/run/systemd/system/systemd-resolved.service.d')
b05c4d6b 729 rm_rf('/run/systemd/system/systemd-timesyncd.service.d')
a962d857 730 rm_rf('/run/systemd/system/systemd-udevd.service.d')
371810d1 731 check_output('systemctl daemon-reload')
87b308c8 732 check_output('systemctl restart systemd-udevd.service')
a962d857 733 restore_active_units()
ec38833c 734
a962d857
YW
735class Utilities():
736 # pylint: disable=no-member
caad88a2 737
a962d857
YW
738 def check_link_exists(self, link, expected=True):
739 if expected:
740 self.assertTrue(link_exists(link))
741 else:
742 self.assertFalse(link_exists(link))
caad88a2 743
a962d857
YW
744 def check_link_attr(self, *args):
745 self.assertEqual(read_link_attr(*args[:-1]), args[-1])
aaae5713 746
a962d857
YW
747 def check_bridge_port_attr(self, master, port, attribute, expected, allow_enoent=False):
748 path = os.path.join('/sys/devices/virtual/net', master, 'lower_' + port, 'brport', attribute)
749 if allow_enoent and not os.path.exists(path):
750 return
751 with open(path, encoding='utf-8') as f:
752 self.assertEqual(f.readline().strip(), expected)
aaae5713 753
a962d857
YW
754 def check_ipv4_sysctl_attr(self, link, attribute, expected):
755 self.assertEqual(read_ipv4_sysctl_attr(link, attribute), expected)
ec38833c 756
a962d857
YW
757 def check_ipv6_sysctl_attr(self, link, attribute, expected):
758 self.assertEqual(read_ipv6_sysctl_attr(link, attribute), expected)
aaae5713 759
a962d857
YW
760 def wait_links(self, *links, timeout=20, fail_assert=True):
761 def links_exist(*links):
762 for link in links:
763 if not link_exists(link):
764 return False
765 return True
524cc9d1 766
a962d857
YW
767 for iteration in range(timeout + 1):
768 if iteration > 0:
769 time.sleep(1)
2be0b6fc 770
a962d857
YW
771 if links_exist(*links):
772 return True
773 if fail_assert:
774 self.fail('Timed out waiting for all links to be created: ' + ', '.join(list(links)))
775 return False
0fc0d85f 776
cfbdc438
YW
777 def wait_activated(self, link, state='down', timeout=20, fail_assert=True):
778 # wait for the interface is activated.
779 invocation_id = check_output('systemctl show systemd-networkd -p InvocationID --value')
780 needle = f'{link}: Bringing link {state}'
781 flag = state.upper()
a962d857 782 for iteration in range(timeout + 1):
459c35d4
YW
783 if iteration != 0:
784 time.sleep(1)
785 if not link_exists(link):
786 continue
cfbdc438
YW
787 output = check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id)
788 if needle in output and flag in check_output(f'ip link show {link}'):
789 return True
cfbdc438
YW
790 if fail_assert:
791 self.fail(f'Timed out waiting for {link} activated.')
792 return False
793
a4632dc7
DS
794 def wait_operstate(self, link, operstate='degraded', setup_state='configured', setup_timeout=5, fail_assert=True):
795 """Wait for the link to reach the specified operstate and/or setup state.
796
797 Specify None or '' for either operstate or setup_state to ignore that state.
798 This will recheck until the state conditions are met or the timeout expires.
799
800 If the link successfully matches the requested state, this returns True.
801 If this times out waiting for the link to match, the behavior depends on the
802 'fail_assert' parameter; if True, this causes a test assertion failure,
803 otherwise this returns False. The default is to cause assertion failure.
804
805 Note that this function matches on *exactly* the given operstate and setup_state.
806 To wait for a link to reach *or exceed* a given operstate, use wait_online().
807 """
808 if not operstate:
809 operstate = r'\S+'
810 if not setup_state:
811 setup_state = r'\S+'
812
813 for secs in range(setup_timeout + 1):
459c35d4
YW
814 if secs != 0:
815 time.sleep(1)
816 if not link_exists(link):
817 continue
a4632dc7 818 output = check_output(*networkctl_cmd, '-n', '0', 'status', link, env=env)
a4632dc7
DS
819 if re.search(rf'(?m)^\s*State:\s+{operstate}\s+\({setup_state}\)\s*$', output):
820 return True
894ff7d1 821
a4632dc7
DS
822 if fail_assert:
823 self.fail(f'Timed out waiting for {link} to reach state {operstate}/{setup_state}')
824 return False
2be0b6fc 825
70448bb1 826 def wait_online(self, links_with_operstate, timeout='20s', bool_any=False, ipv4=False, ipv6=False, setup_state='configured', setup_timeout=5):
0923b425 827 """Wait for the links to reach the specified operstate and/or setup state.
0c020321
DS
828
829 This is similar to wait_operstate() but can be used for multiple links,
830 and it also calls systemd-networkd-wait-online to wait for the given operstate.
831 The operstate should be specified in the link name, like 'eth0:degraded'.
832 If just a link name is provided, wait-online's default operstate to wait for is degraded.
833
834 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
835 'setup_timeout' controls the per-link timeout waiting for the setup_state.
836
837 Set 'bool_any' to True to wait for any (instead of all) of the given links.
838 If this is set, no setup_state checks are done.
839
70448bb1
L
840 Set 'ipv4' or 'ipv6' to True to wait for IPv4 address or IPv6 address, respectively, of each of the given links.
841 This is applied only for the operational state 'degraded' or above.
842
0923b425 843 Note that this function waits for the links to reach *or exceed* the given operstate.
0c020321
DS
844 However, the setup_state, if specified, must be matched *exactly*.
845
0923b425 846 This returns if the links reached the requested operstate/setup_state; otherwise it
0c020321
DS
847 raises CalledProcessError or fails test assertion.
848 """
56dfde0d 849 args = wait_online_cmd + [f'--timeout={timeout}'] + [f'--interface={link}' for link in links_with_operstate] + [f'--ignore={link}' for link in protected_links]
e2aea43f
YW
850 if bool_any:
851 args += ['--any']
70448bb1
L
852 if ipv4:
853 args += ['--ipv4']
854 if ipv6:
855 args += ['--ipv6']
e2aea43f 856 try:
163d095f 857 check_output(*args, env=wait_online_env)
f9073c24 858 except subprocess.CalledProcessError:
17479d51 859 # show detailed status on failure
e2aea43f 860 for link in links_with_operstate:
66dc5d82
YW
861 name = link.split(':')[0]
862 if link_exists(name):
a962d857 863 call(*networkctl_cmd, '-n', '0', 'status', name, env=env)
e2aea43f 864 raise
fd372b1a 865 if not bool_any and setup_state:
0c020321
DS
866 for link in links_with_operstate:
867 self.wait_operstate(link.split(':')[0], None, setup_state, setup_timeout)
e2aea43f 868
53c32c2b 869 def wait_address(self, link, address_regex, scope='global', ipv='', timeout_sec=100):
2629df47
YW
870 for i in range(timeout_sec):
871 if i > 0:
872 time.sleep(1)
371810d1 873 output = check_output(f'ip {ipv} address show dev {link} scope {scope}')
571f9539 874 if re.search(address_regex, output) and 'tentative' not in output:
2629df47 875 break
240e4137
YW
876
877 self.assertRegex(output, address_regex)
878
879 def wait_address_dropped(self, link, address_regex, scope='global', ipv='', timeout_sec=100):
880 for i in range(timeout_sec):
881 if i > 0:
882 time.sleep(1)
883 output = check_output(f'ip {ipv} address show dev {link} scope {scope}')
884 if not re.search(address_regex, output):
885 break
886
887 self.assertNotRegex(output, address_regex)
2629df47 888
bb80f633
YW
889 def wait_route(self, link, route_regex, table='main', ipv='', timeout_sec=100):
890 for i in range(timeout_sec):
891 if i > 0:
892 time.sleep(1)
893 output = check_output(f'ip {ipv} route show dev {link} table {table}')
894 if re.search(route_regex, output):
895 break
896
897 self.assertRegex(output, route_regex)
898
a4640bed
TM
899 def check_netlabel(self, interface, address, label='system_u:object_r:root_t:s0'):
900 if not shutil.which('selinuxenabled'):
e4377659 901 print('## Checking NetLabel skipped: selinuxenabled command not found.')
a4640bed 902 elif call_quiet('selinuxenabled') != 0:
e4377659 903 print('## Checking NetLabel skipped: SELinux disabled.')
a4640bed 904 elif not shutil.which('netlabelctl'): # not packaged by all distros
e4377659 905 print('## Checking NetLabel skipped: netlabelctl command not found.')
a4640bed
TM
906 else:
907 output = check_output('netlabelctl unlbl list')
908 print(output)
909 self.assertRegex(output, f'interface:{interface},address:{address},label:"{label}"')
910
1ca44d7d
YW
911class NetworkctlTests(unittest.TestCase, Utilities):
912
1ca44d7d 913 def setUp(self):
a962d857 914 setup_common()
1ca44d7d
YW
915
916 def tearDown(self):
a962d857 917 tear_down_common()
1ca44d7d 918
6934ace0
YW
919 @expectedFailureIfAlternativeNameIsNotAvailable()
920 def test_altname(self):
a962d857 921 copy_network_unit('26-netdev-link-local-addressing-yes.network', '12-dummy.netdev', '12-dummy.link')
6934ace0
YW
922 start_networkd()
923 self.wait_online(['dummy98:degraded'])
924
fc79e6ff 925 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98', env=env)
6934ace0
YW
926 self.assertRegex(output, 'hogehogehogehogehogehoge')
927
f68f644a
NR
928 @expectedFailureIfAlternativeNameIsNotAvailable()
929 def test_rename_to_altname(self):
930 copy_network_unit('26-netdev-link-local-addressing-yes.network',
931 '12-dummy.netdev', '12-dummy-rename-to-altname.link')
932 start_networkd()
933 self.wait_online(['dummyalt:degraded'])
934
935 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummyalt', env=env)
936 self.assertIn('hogehogehogehogehogehoge', output)
937 self.assertNotIn('dummy98', output)
938
dcd9f07c 939 def test_reconfigure(self):
a962d857 940 copy_network_unit('25-address-static.network', '12-dummy.netdev')
dcd9f07c
YW
941 start_networkd()
942 self.wait_online(['dummy98:routable'])
943
944 output = check_output('ip -4 address show dev dummy98')
945 print(output)
3bad5487
YW
946 self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output)
947 self.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output)
948 self.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output)
dcd9f07c
YW
949
950 check_output('ip address del 10.1.2.3/16 dev dummy98')
951 check_output('ip address del 10.1.2.4/16 dev dummy98')
952 check_output('ip address del 10.2.2.4/16 dev dummy98')
953
a962d857 954 networkctl_reconfigure('dummy98')
dcd9f07c
YW
955 self.wait_online(['dummy98:routable'])
956
957 output = check_output('ip -4 address show dev dummy98')
958 print(output)
3bad5487
YW
959 self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output)
960 self.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output)
961 self.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output)
962
a962d857 963 remove_network_unit('25-address-static.network')
3bad5487 964
a962d857 965 networkctl_reload()
3bad5487
YW
966 self.wait_operstate('dummy98', 'degraded', setup_state='unmanaged')
967
968 output = check_output('ip -4 address show dev dummy98')
969 print(output)
970 self.assertNotIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output)
971 self.assertNotIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output)
972 self.assertNotIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output)
973
a962d857
YW
974 copy_network_unit('25-address-static.network')
975 networkctl_reload()
3bad5487
YW
976 self.wait_online(['dummy98:routable'])
977
978 output = check_output('ip -4 address show dev dummy98')
979 print(output)
980 self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output)
981 self.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output)
982 self.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output)
dcd9f07c 983
66de8671 984 def test_reload(self):
a962d857 985 start_networkd()
66de8671 986
a962d857
YW
987 copy_network_unit('11-dummy.netdev')
988 networkctl_reload()
19cf3143 989 self.wait_operstate('test1', 'off', setup_state='unmanaged')
66de8671 990
a962d857
YW
991 copy_network_unit('11-dummy.network')
992 networkctl_reload()
66de8671
YW
993 self.wait_online(['test1:degraded'])
994
a962d857
YW
995 remove_network_unit('11-dummy.network')
996 networkctl_reload()
19cf3143 997 self.wait_operstate('test1', 'degraded', setup_state='unmanaged')
66de8671 998
a962d857
YW
999 remove_network_unit('11-dummy.netdev')
1000 networkctl_reload()
19cf3143 1001 self.wait_operstate('test1', 'degraded', setup_state='unmanaged')
66de8671 1002
a962d857
YW
1003 copy_network_unit('11-dummy.netdev', '11-dummy.network')
1004 networkctl_reload()
19cf3143 1005 self.wait_operstate('test1', 'degraded')
66de8671 1006
1ca44d7d 1007 def test_glob(self):
a962d857 1008 copy_network_unit('11-dummy.netdev', '11-dummy.network')
2cf6fdff 1009 start_networkd()
1ca44d7d 1010
e2aea43f 1011 self.wait_online(['test1:degraded'])
1ca44d7d 1012
371810d1 1013 output = check_output(*networkctl_cmd, 'list', env=env)
1ca44d7d
YW
1014 self.assertRegex(output, '1 lo ')
1015 self.assertRegex(output, 'test1')
1016
371810d1 1017 output = check_output(*networkctl_cmd, 'list', 'test1', env=env)
1ca44d7d
YW
1018 self.assertNotRegex(output, '1 lo ')
1019 self.assertRegex(output, 'test1')
1020
371810d1 1021 output = check_output(*networkctl_cmd, 'list', 'te*', env=env)
1ca44d7d
YW
1022 self.assertNotRegex(output, '1 lo ')
1023 self.assertRegex(output, 'test1')
1024
fc79e6ff 1025 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'te*', env=env)
1ca44d7d
YW
1026 self.assertNotRegex(output, '1: lo ')
1027 self.assertRegex(output, 'test1')
1028
fc79e6ff 1029 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'tes[a-z][0-9]', env=env)
1ca44d7d
YW
1030 self.assertNotRegex(output, '1: lo ')
1031 self.assertRegex(output, 'test1')
1032
6d5b4efe 1033 def test_mtu(self):
a962d857 1034 copy_network_unit('11-dummy-mtu.netdev', '11-dummy.network')
2cf6fdff 1035 start_networkd()
6d5b4efe 1036
e2aea43f 1037 self.wait_online(['test1:degraded'])
6d5b4efe 1038
fc79e6ff 1039 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'test1', env=env)
6d5b4efe
YW
1040 self.assertRegex(output, 'MTU: 1600')
1041
e28fd95f 1042 def test_type(self):
a962d857 1043 copy_network_unit('11-dummy.netdev', '11-dummy.network')
e28fd95f 1044 start_networkd()
e2aea43f 1045 self.wait_online(['test1:degraded'])
e28fd95f 1046
fc79e6ff 1047 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'test1', env=env)
e28fd95f
YW
1048 print(output)
1049 self.assertRegex(output, 'Type: ether')
1050
fc79e6ff 1051 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'lo', env=env)
e28fd95f
YW
1052 print(output)
1053 self.assertRegex(output, 'Type: loopback')
1054
e28fd95f 1055 def test_udev_link_file(self):
d8746f16 1056 copy_network_unit('11-dummy.netdev', '11-dummy.network', '25-default.link')
e28fd95f 1057 start_networkd()
e2aea43f 1058 self.wait_online(['test1:degraded'])
e28fd95f 1059
fc79e6ff 1060 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'test1', env=env)
e28fd95f 1061 print(output)
d8746f16 1062 self.assertRegex(output, r'Link File: /run/systemd/network/25-default.link')
e28fd95f
YW
1063 self.assertRegex(output, r'Network File: /run/systemd/network/11-dummy.network')
1064
df0a741c
YW
1065 # This test may be run on the system that has older udevd than 70f32a260b5ebb68c19ecadf5d69b3844896ba55 (v249).
1066 # In that case, the udev DB for the loopback network interface may already have ID_NET_LINK_FILE property.
1067 # Let's reprocess the interface and drop the property.
1068 check_output(*udevadm_cmd, 'trigger', '--settle', '--action=add', '/sys/class/net/lo')
fc79e6ff 1069 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'lo', env=env)
e28fd95f 1070 print(output)
767bc538
YW
1071 self.assertRegex(output, r'Link File: n/a')
1072 self.assertRegex(output, r'Network File: n/a')
e28fd95f 1073
bee692fd 1074 def test_delete_links(self):
a962d857
YW
1075 copy_network_unit('11-dummy.netdev', '11-dummy.network',
1076 '25-veth.netdev', '26-netdev-link-local-addressing-yes.network')
2cf6fdff 1077 start_networkd()
bee692fd 1078
e2aea43f 1079 self.wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
bee692fd 1080
7a2f6fb6 1081 check_output(*networkctl_cmd, 'delete', 'test1', 'veth99', env=env)
a962d857
YW
1082 self.check_link_exists('test1', expected=False)
1083 self.check_link_exists('veth99', expected=False)
1084 self.check_link_exists('veth-peer', expected=False)
bee692fd 1085
fa4d3fed
YW
1086class NetworkdMatchTests(unittest.TestCase, Utilities):
1087
1088 def setUp(self):
1089 setup_common()
1090
1091 def tearDown(self):
1092 tear_down_common()
1093
7618ab1b 1094 @expectedFailureIfAlternativeNameIsNotAvailable()
fa4d3fed
YW
1095 def test_match(self):
1096 copy_network_unit('12-dummy-mac.netdev',
1097 '12-dummy-match-mac-01.network',
1098 '12-dummy-match-mac-02.network',
1099 '12-dummy-match-renamed.network',
1100 '12-dummy-match-altname.network',
1101 '12-dummy-altname.link')
1102 start_networkd()
1103
1104 self.wait_online(['dummy98:routable'])
1105 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98', env=env)
1106 self.assertIn('Network File: /run/systemd/network/12-dummy-match-mac-01.network', output)
1107 output = check_output('ip -4 address show dev dummy98')
1108 self.assertIn('10.0.0.1/16', output)
1109
1110 check_output('ip link set dev dummy98 down')
1111 check_output('ip link set dev dummy98 address 12:34:56:78:9a:02')
1112
1113 self.wait_address('dummy98', '10.0.0.2/16', ipv='-4', timeout_sec=10)
1114 self.wait_online(['dummy98:routable'])
1115 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98', env=env)
1116 self.assertIn('Network File: /run/systemd/network/12-dummy-match-mac-02.network', output)
1117
1118 check_output('ip link set dev dummy98 down')
1119 check_output('ip link set dev dummy98 name dummy98-1')
1120
1121 self.wait_address('dummy98-1', '10.0.1.2/16', ipv='-4', timeout_sec=10)
1122 self.wait_online(['dummy98-1:routable'])
1123 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98-1', env=env)
1124 self.assertIn('Network File: /run/systemd/network/12-dummy-match-renamed.network', output)
1125
1126 check_output('ip link set dev dummy98-1 down')
1127 check_output('ip link set dev dummy98-1 name dummy98-2')
1128 check_output(*udevadm_cmd, 'trigger', '--action=add', '/sys/class/net/dummy98-2')
1129
1130 self.wait_address('dummy98-2', '10.0.2.2/16', ipv='-4', timeout_sec=10)
1131 self.wait_online(['dummy98-2:routable'])
1132 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98-2', env=env)
1133 self.assertIn('Network File: /run/systemd/network/12-dummy-match-altname.network', output)
1134
5432adae
YW
1135 def test_match_udev_property(self):
1136 copy_network_unit('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
1137 start_networkd()
1138 self.wait_online(['dummy98:routable'])
1139
1140 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98', env=env)
1141 print(output)
1142 self.assertRegex(output, 'Network File: /run/systemd/network/14-match-udev-property')
1143
b09ec847
YW
1144class WaitOnlineTests(unittest.TestCase, Utilities):
1145
1146 def setUp(self):
1147 setup_common()
1148
1149 def tearDown(self):
1150 tear_down_common()
1151
1152 def test_wait_online_any(self):
1153 copy_network_unit('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
1154 start_networkd()
1155
1156 self.wait_online(['bridge99', 'test1:degraded'], bool_any=True)
1157
1158 self.wait_operstate('bridge99', '(off|no-carrier)', setup_state='configuring')
1159 self.wait_operstate('test1', 'degraded')
1160
1f0e3109
SS
1161class NetworkdNetDevTests(unittest.TestCase, Utilities):
1162
1f0e3109 1163 def setUp(self):
a962d857 1164 setup_common()
1f0e3109
SS
1165
1166 def tearDown(self):
a962d857 1167 tear_down_common()
1f0e3109 1168
1ca44d7d 1169 def test_dropin_and_name_conflict(self):
a962d857 1170 copy_network_unit('10-dropin-test.netdev', '15-name-conflict-test.netdev')
2cf6fdff 1171 start_networkd()
d80734f7 1172
e2aea43f 1173 self.wait_online(['dropin-test:off'], setup_state='unmanaged')
d80734f7 1174
371810d1 1175 output = check_output('ip link show dropin-test')
d80734f7 1176 print(output)
45aa0e84 1177 self.assertRegex(output, '00:50:56:c0:00:28')
d80734f7 1178
13060471
YW
1179 @expectedFailureIfModuleIsNotAvailable('bareudp')
1180 def test_bareudp(self):
a962d857 1181 copy_network_unit('25-bareudp.netdev', '26-netdev-link-local-addressing-yes.network')
13060471
YW
1182 start_networkd()
1183
1184 self.wait_online(['bareudp99:degraded'])
1185
1186 output = check_output('ip -d link show bareudp99')
1187 print(output)
1188 self.assertRegex(output, 'dstport 1000 ')
1189 self.assertRegex(output, 'ethertype ip ')
1190
c0267a59
AW
1191 @expectedFailureIfModuleIsNotAvailable('batman-adv')
1192 def test_batadv(self):
a962d857 1193 copy_network_unit('25-batadv.netdev', '26-netdev-link-local-addressing-yes.network')
c0267a59
AW
1194 start_networkd()
1195
1196 self.wait_online(['batadv99:degraded'])
1197
1198 output = check_output('ip -d link show batadv99')
1199 print(output)
1200 self.assertRegex(output, 'batadv')
1201
1f0e3109 1202 def test_bridge(self):
a962d857 1203 copy_network_unit('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
2cf6fdff 1204 start_networkd()
1f0e3109 1205
e2aea43f 1206 self.wait_online(['bridge99:no-carrier'])
1f0e3109 1207
3d165124 1208 tick = os.sysconf('SC_CLK_TCK')
ec38833c
ZJS
1209 self.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick))
1210 self.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick))
c9047092
YW
1211 self.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'forward_delay')) / tick))
1212 self.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'ageing_time')) / tick))
1213 self.assertEqual(9, int(read_link_attr('bridge99', 'bridge', 'priority')))
1214 self.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_querier')))
1215 self.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_snooping')))
1216 self.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'stp_state')))
1217 self.assertEqual(3, int(read_link_attr('bridge99', 'bridge', 'multicast_igmp_version')))
1f0e3109 1218
fc79e6ff 1219 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'bridge99', env=env)
36bc2ffb
YW
1220 print(output)
1221 self.assertRegex(output, 'Priority: 9')
1222 self.assertRegex(output, 'STP: yes')
1223 self.assertRegex(output, 'Multicast IGMP Version: 3')
1224
b6d5dab7
YW
1225 output = check_output('ip -d link show bridge99')
1226 print(output)
1227 self.assertIn('vlan_filtering 1 ', output)
1228 self.assertIn('vlan_protocol 802.1ad ', output)
1229 self.assertIn('vlan_default_pvid 9 ', output)
1230
1f0e3109 1231 def test_bond(self):
a962d857 1232 copy_network_unit('25-bond.netdev', '25-bond-balanced-tlb.netdev')
2cf6fdff 1233 start_networkd()
ec38833c 1234
e2aea43f 1235 self.wait_online(['bond99:off', 'bond98:off'], setup_state='unmanaged')
ec38833c 1236
a962d857
YW
1237 self.check_link_attr('bond99', 'bonding', 'mode', '802.3ad 4')
1238 self.check_link_attr('bond99', 'bonding', 'xmit_hash_policy', 'layer3+4 1')
1239 self.check_link_attr('bond99', 'bonding', 'miimon', '1000')
1240 self.check_link_attr('bond99', 'bonding', 'lacp_rate', 'fast 1')
1241 self.check_link_attr('bond99', 'bonding', 'updelay', '2000')
1242 self.check_link_attr('bond99', 'bonding', 'downdelay', '2000')
1243 self.check_link_attr('bond99', 'bonding', 'resend_igmp', '4')
1244 self.check_link_attr('bond99', 'bonding', 'min_links', '1')
1245 self.check_link_attr('bond99', 'bonding', 'ad_actor_sys_prio', '1218')
1246 self.check_link_attr('bond99', 'bonding', 'ad_user_port_key', '811')
1247 self.check_link_attr('bond99', 'bonding', 'ad_actor_system', '00:11:22:33:44:55')
1248
1249 self.check_link_attr('bond98', 'bonding', 'mode', 'balance-tlb 5')
1250 self.check_link_attr('bond98', 'bonding', 'tlb_dynamic_lb', '1')
fde60a42 1251
acfe3b65
YW
1252 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'bond99', env=env)
1253 print(output)
1254 self.assertIn('Mode: 802.3ad', output)
1255 self.assertIn('Miimon: 1s', output)
1256 self.assertIn('Updelay: 2s', output)
1257 self.assertIn('Downdelay: 2s', output)
1258
1259 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'bond98', env=env)
1260 print(output)
1261 self.assertIn('Mode: balance-tlb', output)
1262
1f0e3109 1263 def test_vlan(self):
a962d857
YW
1264 copy_network_unit('21-vlan.netdev', '11-dummy.netdev',
1265 '21-vlan.network', '21-vlan-test1.network')
2cf6fdff 1266 start_networkd()
1f0e3109 1267
e2aea43f 1268 self.wait_online(['test1:degraded', 'vlan99:routable'])
1f0e3109 1269
371810d1 1270 output = check_output('ip -d link show test1')
72b7f1b9 1271 print(output)
7d7be1b9 1272 self.assertRegex(output, ' mtu 2000 ')
72b7f1b9 1273
371810d1 1274 output = check_output('ip -d link show vlan99')
14ecd604 1275 print(output)
73d24e45
YW
1276 self.assertIn(' mtu 2000 ', output)
1277 self.assertIn('REORDER_HDR', output)
1278 self.assertIn('LOOSE_BINDING', output)
1279 self.assertIn('GVRP', output)
1280 self.assertIn('MVRP', output)
1281 self.assertIn(' id 99 ', output)
1282 self.assertIn('ingress-qos-map { 4:100 7:13 }', output)
1283 self.assertIn('egress-qos-map { 0:1 1:3 6:6 7:7 10:3 }', output)
1f0e3109 1284
371810d1 1285 output = check_output('ip -4 address show dev test1')
7f45d738
YW
1286 print(output)
1287 self.assertRegex(output, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
1288 self.assertRegex(output, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
1289
371810d1 1290 output = check_output('ip -4 address show dev vlan99')
7f45d738
YW
1291 print(output)
1292 self.assertRegex(output, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
1293
b249834b
YW
1294 def test_vlan_on_bond(self):
1295 # For issue #24377 (https://github.com/systemd/systemd/issues/24377),
1296 # which is fixed by b05e52000b4eee764b383cc3031da0a3739e996e (PR#24020).
1297
1298 copy_network_unit('21-bond-802.3ad.netdev', '21-bond-802.3ad.network',
1299 '21-vlan-on-bond.netdev', '21-vlan-on-bond.network')
1300 start_networkd()
1301 self.wait_online(['bond99:off'])
1302 self.wait_operstate('vlan99', operstate='off', setup_state='configuring', setup_timeout=10)
1303
1304 # The commit b05e52000b4eee764b383cc3031da0a3739e996e adds ", ignoring". To make it easily confirmed
1305 # that the issue is fixed by the commit, let's allow to match both string.
1306 log_re = re.compile('vlan99: Could not bring up interface(, ignoring|): Network is down$', re.MULTILINE)
1307 for i in range(20):
1308 if i > 0:
1309 time.sleep(0.5)
1310 if log_re.search(read_networkd_log()):
1311 break
1312 else:
1313 self.fail()
1314
1315 copy_network_unit('11-dummy.netdev', '12-dummy.netdev', '21-dummy-bond-slave.network')
1316 networkctl_reload()
1317 self.wait_online(['test1:enslaved', 'dummy98:enslaved', 'bond99:carrier', 'vlan99:routable'])
1318
1f0e3109 1319 def test_macvtap(self):
a962d857 1320 first = True
460feb61 1321 for mode in ['private', 'vepa', 'bridge', 'passthru']:
a962d857
YW
1322 if first:
1323 first = False
1324 else:
1325 self.tearDown()
1326
1327 print(f'### test_macvtap(mode={mode})')
460feb61 1328 with self.subTest(mode=mode):
a962d857
YW
1329 copy_network_unit('21-macvtap.netdev', '26-netdev-link-local-addressing-yes.network',
1330 '11-dummy.netdev', '25-macvtap.network')
1331 with open(os.path.join(network_unit_dir, '21-macvtap.netdev'), mode='a', encoding='utf-8') as f:
460feb61 1332 f.write('[MACVTAP]\nMode=' + mode)
2cf6fdff 1333 start_networkd()
1f0e3109 1334
c918b70a
TY
1335 self.wait_online(['macvtap99:degraded',
1336 'test1:carrier' if mode == 'passthru' else 'test1:degraded'])
460feb61 1337
371810d1 1338 output = check_output('ip -d link show macvtap99')
460feb61
YW
1339 print(output)
1340 self.assertRegex(output, 'macvtap mode ' + mode + ' ')
1f0e3109
SS
1341
1342 def test_macvlan(self):
a962d857 1343 first = True
dff9792b 1344 for mode in ['private', 'vepa', 'bridge', 'passthru']:
a962d857
YW
1345 if first:
1346 first = False
1347 else:
1348 self.tearDown()
1349
1350 print(f'### test_macvlan(mode={mode})')
dff9792b 1351 with self.subTest(mode=mode):
a962d857
YW
1352 copy_network_unit('21-macvlan.netdev', '26-netdev-link-local-addressing-yes.network',
1353 '11-dummy.netdev', '25-macvlan.network')
1354 with open(os.path.join(network_unit_dir, '21-macvlan.netdev'), mode='a', encoding='utf-8') as f:
dff9792b 1355 f.write('[MACVLAN]\nMode=' + mode)
2cf6fdff 1356 start_networkd()
dff9792b 1357
c918b70a
TY
1358 self.wait_online(['macvlan99:degraded',
1359 'test1:carrier' if mode == 'passthru' else 'test1:degraded'])
dff9792b 1360
371810d1 1361 output = check_output('ip -d link show test1')
dff9792b
YW
1362 print(output)
1363 self.assertRegex(output, ' mtu 2000 ')
72b7f1b9 1364
371810d1 1365 output = check_output('ip -d link show macvlan99')
dff9792b
YW
1366 print(output)
1367 self.assertRegex(output, ' mtu 2000 ')
1368 self.assertRegex(output, 'macvlan mode ' + mode + ' ')
72b7f1b9 1369
a962d857 1370 remove_link('test1')
1d0c9bd7
YW
1371 time.sleep(1)
1372
a962d857 1373 check_output("ip link add test1 type dummy")
c918b70a
TY
1374 self.wait_online(['macvlan99:degraded',
1375 'test1:carrier' if mode == 'passthru' else 'test1:degraded'])
1d0c9bd7
YW
1376
1377 output = check_output('ip -d link show test1')
1378 print(output)
1379 self.assertRegex(output, ' mtu 2000 ')
1380
1381 output = check_output('ip -d link show macvlan99')
1382 print(output)
1383 self.assertRegex(output, ' mtu 2000 ')
1384 self.assertRegex(output, 'macvlan mode ' + mode + ' ')
1385
7a0a37b2 1386 @expectedFailureIfModuleIsNotAvailable('ipvlan')
1f0e3109 1387 def test_ipvlan(self):
a962d857 1388 first = True
bc6dff6e 1389 for mode, flag in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
a962d857
YW
1390 if first:
1391 first = False
1392 else:
1393 self.tearDown()
1394
1395 print(f'### test_ipvlan(mode={mode}, flag={flag})')
bc6dff6e 1396 with self.subTest(mode=mode, flag=flag):
a962d857
YW
1397 copy_network_unit('25-ipvlan.netdev', '26-netdev-link-local-addressing-yes.network',
1398 '11-dummy.netdev', '25-ipvlan.network')
1399 with open(os.path.join(network_unit_dir, '25-ipvlan.netdev'), mode='a', encoding='utf-8') as f:
bc6dff6e 1400 f.write('[IPVLAN]\nMode=' + mode + '\nFlags=' + flag)
1f0e3109 1401
2cf6fdff 1402 start_networkd()
e2aea43f 1403 self.wait_online(['ipvlan99:degraded', 'test1:degraded'])
bc6dff6e 1404
371810d1 1405 output = check_output('ip -d link show ipvlan99')
bc6dff6e
YW
1406 print(output)
1407 self.assertRegex(output, 'ipvlan *mode ' + mode.lower() + ' ' + flag)
1f0e3109 1408
956c8fec
YW
1409 @expectedFailureIfModuleIsNotAvailable('ipvtap')
1410 def test_ipvtap(self):
a962d857 1411 first = True
40921f08 1412 for mode, flag in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
a962d857
YW
1413 if first:
1414 first = False
1415 else:
1416 self.tearDown()
1417
1418 print(f'### test_ipvtap(mode={mode}, flag={flag})')
40921f08 1419 with self.subTest(mode=mode, flag=flag):
a962d857
YW
1420 copy_network_unit('25-ipvtap.netdev', '26-netdev-link-local-addressing-yes.network',
1421 '11-dummy.netdev', '25-ipvtap.network')
1422 with open(os.path.join(network_unit_dir, '25-ipvtap.netdev'), mode='a', encoding='utf-8') as f:
40921f08
YW
1423 f.write('[IPVTAP]\nMode=' + mode + '\nFlags=' + flag)
1424
2cf6fdff 1425 start_networkd()
e2aea43f 1426 self.wait_online(['ipvtap99:degraded', 'test1:degraded'])
956c8fec 1427
371810d1 1428 output = check_output('ip -d link show ipvtap99')
40921f08
YW
1429 print(output)
1430 self.assertRegex(output, 'ipvtap *mode ' + mode.lower() + ' ' + flag)
956c8fec 1431
1f0e3109 1432 def test_veth(self):
a962d857
YW
1433 copy_network_unit('25-veth.netdev', '26-netdev-link-local-addressing-yes.network',
1434 '25-veth-mtu.netdev')
2cf6fdff 1435 start_networkd()
1f0e3109 1436
0874be35 1437 self.wait_online(['veth99:degraded', 'veth-peer:degraded', 'veth-mtu:degraded', 'veth-mtu-peer:degraded'])
671dacdf 1438
371810d1 1439 output = check_output('ip -d link show veth99')
671dacdf
YW
1440 print(output)
1441 self.assertRegex(output, 'link/ether 12:34:56:78:9a:bc')
371810d1 1442 output = check_output('ip -d link show veth-peer')
671dacdf
YW
1443 print(output)
1444 self.assertRegex(output, 'link/ether 12:34:56:78:9a:bd')
1f0e3109 1445
0874be35
YW
1446 output = check_output('ip -d link show veth-mtu')
1447 print(output)
1448 self.assertRegex(output, 'link/ether 12:34:56:78:9a:be')
1449 self.assertRegex(output, 'mtu 1800')
1450 output = check_output('ip -d link show veth-mtu-peer')
1451 print(output)
1452 self.assertRegex(output, 'link/ether 12:34:56:78:9a:bf')
1453 self.assertRegex(output, 'mtu 1800')
1454
5cdc7c89 1455 def test_tuntap(self):
ae014ecb 1456 copy_network_unit('25-tun.netdev', '25-tap.netdev', '26-netdev-link-local-addressing-yes.network')
2cf6fdff 1457 start_networkd()
1f0e3109 1458
ae014ecb
YW
1459 self.wait_online(['testtun99:degraded', 'testtap99:degraded'])
1460
1461 pid = networkd_pid()
1462 name = psutil.Process(pid).name()[:15]
1463
1464 output = check_output('ip -d tuntap show')
1465 print(output)
0677130e
FS
1466 self.assertRegex(output, fr'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:{name}\({pid}\)systemd\(1\)$')
1467 self.assertRegex(output, fr'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:{name}\({pid}\)systemd\(1\)$')
1f0e3109 1468
5cdc7c89 1469 output = check_output('ip -d link show testtun99')
2746d307
YW
1470 print(output)
1471 # Old ip command does not support IFF_ flags
426654d7 1472 self.assertRegex(output, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
ae014ecb 1473 self.assertIn('UP,LOWER_UP', output)
2746d307 1474
5cdc7c89 1475 output = check_output('ip -d link show testtap99')
2746d307 1476 print(output)
426654d7 1477 self.assertRegex(output, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
ae014ecb
YW
1478 self.assertIn('UP,LOWER_UP', output)
1479
1480 remove_network_unit('26-netdev-link-local-addressing-yes.network')
1481
1482 restart_networkd()
1483 self.wait_online(['testtun99:degraded', 'testtap99:degraded'], setup_state='unmanaged')
1484
1485 pid = networkd_pid()
1486 name = psutil.Process(pid).name()[:15]
1487
1488 output = check_output('ip -d tuntap show')
1489 print(output)
0677130e
FS
1490 self.assertRegex(output, fr'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:{name}\({pid}\)systemd\(1\)$')
1491 self.assertRegex(output, fr'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:{name}\({pid}\)systemd\(1\)$')
ae014ecb
YW
1492
1493 output = check_output('ip -d link show testtun99')
1494 print(output)
1495 self.assertRegex(output, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
1496 self.assertIn('UP,LOWER_UP', output)
1497
1498 output = check_output('ip -d link show testtap99')
1499 print(output)
1500 self.assertRegex(output, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
1501 self.assertIn('UP,LOWER_UP', output)
1502
1503 clear_network_units()
1504 restart_networkd()
1505 self.wait_online(['testtun99:off', 'testtap99:off'], setup_state='unmanaged')
1506
1507 output = check_output('ip -d tuntap show')
1508 print(output)
0677130e
FS
1509 self.assertRegex(output, r'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$')
1510 self.assertRegex(output, r'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$')
ae014ecb
YW
1511
1512 for i in range(10):
1513 if i != 0:
1514 time.sleep(1)
1515 output = check_output('ip -d link show testtun99')
1516 print(output)
1517 self.assertRegex(output, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
1518 if 'NO-CARRIER' in output:
1519 break
1520 else:
1521 self.fail()
1522
1523 for i in range(10):
1524 if i != 0:
1525 time.sleep(1)
1526 output = check_output('ip -d link show testtap99')
1527 print(output)
1528 self.assertRegex(output, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
1529 if 'NO-CARRIER' in output:
1530 break
1531 else:
1532 self.fail()
2746d307 1533
7a0a37b2 1534 @expectedFailureIfModuleIsNotAvailable('vrf')
1f0e3109 1535 def test_vrf(self):
a962d857 1536 copy_network_unit('25-vrf.netdev', '26-netdev-link-local-addressing-yes.network')
2cf6fdff 1537 start_networkd()
1f0e3109 1538
e2aea43f 1539 self.wait_online(['vrf99:carrier'])
1f0e3109 1540
7a0a37b2 1541 @expectedFailureIfModuleIsNotAvailable('vcan')
1f0e3109 1542 def test_vcan(self):
a962d857 1543 copy_network_unit('25-vcan.netdev', '26-netdev-link-local-addressing-yes.network')
2cf6fdff 1544 start_networkd()
1f0e3109 1545
e2aea43f 1546 self.wait_online(['vcan99:carrier'])
1f0e3109 1547
f63b14d3
YW
1548 @expectedFailureIfModuleIsNotAvailable('vxcan')
1549 def test_vxcan(self):
a962d857 1550 copy_network_unit('25-vxcan.netdev', '26-netdev-link-local-addressing-yes.network')
2cf6fdff 1551 start_networkd()
f63b14d3 1552
e2aea43f 1553 self.wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
f63b14d3 1554
7a3bc5a8
EV
1555 @expectedFailureIfModuleIsNotAvailable('wireguard')
1556 def test_wireguard(self):
a962d857
YW
1557 copy_network_unit('25-wireguard.netdev', '25-wireguard.network',
1558 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
1559 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt',
1560 '25-wireguard-no-peer.netdev', '25-wireguard-no-peer.network')
2cf6fdff 1561 start_networkd()
84d32bf5
YW
1562 self.wait_online(['wg99:routable', 'wg98:routable', 'wg97:carrier'])
1563
1564 output = check_output('ip -4 address show dev wg99')
1565 print(output)
1566 self.assertIn('inet 192.168.124.1/24 scope global wg99', output)
5a0bd90b 1567
e4e0b239
YW
1568 output = check_output('ip -4 address show dev wg99')
1569 print(output)
1570 self.assertIn('inet 169.254.11.1/24 scope link wg99', output)
1571
1572 output = check_output('ip -6 address show dev wg99')
1573 print(output)
1574 self.assertIn('inet6 fe80::1/64 scope link', output)
1575
045db4fa
YW
1576 output = check_output('ip -4 address show dev wg98')
1577 print(output)
1578 self.assertIn('inet 192.168.123.123/24 scope global wg98', output)
1579
1580 output = check_output('ip -6 address show dev wg98')
1581 print(output)
1582 self.assertIn('inet6 fd8d:4d6d:3ccb:500::1/64 scope global', output)
1583
6387cac3
YW
1584 output = check_output('ip -4 route show dev wg99 table 1234')
1585 print(output)
1586 self.assertIn('192.168.26.0/24 proto static metric 123', output)
1587
1588 output = check_output('ip -6 route show dev wg99 table 1234')
1589 print(output)
1590 self.assertIn('fd31:bf08:57cb::/48 proto static metric 123 pref medium', output)
1591
1592 output = check_output('ip -6 route show dev wg98 table 1234')
1593 print(output)
1594 self.assertIn('fd8d:4d6d:3ccb:500:c79:2339:edce:ece1 proto static metric 123 pref medium', output)
1595 self.assertIn('fd8d:4d6d:3ccb:500:1dbf:ca8a:32d3:dd81 proto static metric 123 pref medium', output)
1596 self.assertIn('fd8d:4d6d:3ccb:500:1e54:1415:35d0:a47c proto static metric 123 pref medium', output)
1597 self.assertIn('fd8d:4d6d:3ccb:500:270d:b5dd:4a3f:8909 proto static metric 123 pref medium', output)
1598 self.assertIn('fd8d:4d6d:3ccb:500:5660:679d:3532:94d8 proto static metric 123 pref medium', output)
1599 self.assertIn('fd8d:4d6d:3ccb:500:6825:573f:30f3:9472 proto static metric 123 pref medium', output)
1600 self.assertIn('fd8d:4d6d:3ccb:500:6f2e:6888:c6fd:dfb9 proto static metric 123 pref medium', output)
1601 self.assertIn('fd8d:4d6d:3ccb:500:8d4d:bab:7280:a09a proto static metric 123 pref medium', output)
1602 self.assertIn('fd8d:4d6d:3ccb:500:900c:d437:ec27:8822 proto static metric 123 pref medium', output)
1603 self.assertIn('fd8d:4d6d:3ccb:500:9742:9931:5217:18d5 proto static metric 123 pref medium', output)
1604 self.assertIn('fd8d:4d6d:3ccb:500:9c11:d820:2e96:9be0 proto static metric 123 pref medium', output)
1605 self.assertIn('fd8d:4d6d:3ccb:500:a072:80da:de4f:add1 proto static metric 123 pref medium', output)
1606 self.assertIn('fd8d:4d6d:3ccb:500:a3f3:df38:19b0:721 proto static metric 123 pref medium', output)
1607 self.assertIn('fd8d:4d6d:3ccb:500:a94b:cd6a:a32d:90e6 proto static metric 123 pref medium', output)
1608 self.assertIn('fd8d:4d6d:3ccb:500:b39c:9cdc:755a:ead3 proto static metric 123 pref medium', output)
1609 self.assertIn('fd8d:4d6d:3ccb:500:b684:4f81:2e3e:132e proto static metric 123 pref medium', output)
1610 self.assertIn('fd8d:4d6d:3ccb:500:bad5:495d:8e9c:3427 proto static metric 123 pref medium', output)
1611 self.assertIn('fd8d:4d6d:3ccb:500:bfe5:c3c3:5d77:fcb proto static metric 123 pref medium', output)
1612 self.assertIn('fd8d:4d6d:3ccb:500:c624:6bf7:4c09:3b59 proto static metric 123 pref medium', output)
1613 self.assertIn('fd8d:4d6d:3ccb:500:d4f9:5dc:9296:a1a proto static metric 123 pref medium', output)
1614 self.assertIn('fd8d:4d6d:3ccb:500:dcdd:d33b:90c9:6088 proto static metric 123 pref medium', output)
1615 self.assertIn('fd8d:4d6d:3ccb:500:e2e1:ae15:103f:f376 proto static metric 123 pref medium', output)
1616 self.assertIn('fd8d:4d6d:3ccb:500:f349:c4f0:10c1:6b4 proto static metric 123 pref medium', output)
1617 self.assertIn('fd8d:4d6d:3ccb:c79:2339:edce::/96 proto static metric 123 pref medium', output)
1618 self.assertIn('fd8d:4d6d:3ccb:1dbf:ca8a:32d3::/96 proto static metric 123 pref medium', output)
1619 self.assertIn('fd8d:4d6d:3ccb:1e54:1415:35d0::/96 proto static metric 123 pref medium', output)
1620 self.assertIn('fd8d:4d6d:3ccb:270d:b5dd:4a3f::/96 proto static metric 123 pref medium', output)
1621 self.assertIn('fd8d:4d6d:3ccb:5660:679d:3532::/96 proto static metric 123 pref medium', output)
1622 self.assertIn('fd8d:4d6d:3ccb:6825:573f:30f3::/96 proto static metric 123 pref medium', output)
1623 self.assertIn('fd8d:4d6d:3ccb:6f2e:6888:c6fd::/96 proto static metric 123 pref medium', output)
1624 self.assertIn('fd8d:4d6d:3ccb:8d4d:bab:7280::/96 proto static metric 123 pref medium', output)
1625 self.assertIn('fd8d:4d6d:3ccb:900c:d437:ec27::/96 proto static metric 123 pref medium', output)
1626 self.assertIn('fd8d:4d6d:3ccb:9742:9931:5217::/96 proto static metric 123 pref medium', output)
1627 self.assertIn('fd8d:4d6d:3ccb:9c11:d820:2e96::/96 proto static metric 123 pref medium', output)
1628 self.assertIn('fd8d:4d6d:3ccb:a072:80da:de4f::/96 proto static metric 123 pref medium', output)
1629 self.assertIn('fd8d:4d6d:3ccb:a3f3:df38:19b0::/96 proto static metric 123 pref medium', output)
1630 self.assertIn('fd8d:4d6d:3ccb:a94b:cd6a:a32d::/96 proto static metric 123 pref medium', output)
1631 self.assertIn('fd8d:4d6d:3ccb:b39c:9cdc:755a::/96 proto static metric 123 pref medium', output)
1632 self.assertIn('fd8d:4d6d:3ccb:b684:4f81:2e3e::/96 proto static metric 123 pref medium', output)
1633 self.assertIn('fd8d:4d6d:3ccb:bad5:495d:8e9c::/96 proto static metric 123 pref medium', output)
1634 self.assertIn('fd8d:4d6d:3ccb:bfe5:c3c3:5d77::/96 proto static metric 123 pref medium', output)
1635 self.assertIn('fd8d:4d6d:3ccb:c624:6bf7:4c09::/96 proto static metric 123 pref medium', output)
1636 self.assertIn('fd8d:4d6d:3ccb:d4f9:5dc:9296::/96 proto static metric 123 pref medium', output)
1637 self.assertIn('fd8d:4d6d:3ccb:dcdd:d33b:90c9::/96 proto static metric 123 pref medium', output)
1638 self.assertIn('fd8d:4d6d:3ccb:e2e1:ae15:103f::/96 proto static metric 123 pref medium', output)
1639 self.assertIn('fd8d:4d6d:3ccb:f349:c4f0:10c1::/96 proto static metric 123 pref medium', output)
1640
7a3bc5a8 1641 if shutil.which('wg'):
371810d1 1642 call('wg')
5a0bd90b 1643
371810d1 1644 output = check_output('wg show wg99 listen-port')
84d32bf5 1645 self.assertEqual(output, '51820')
371810d1 1646 output = check_output('wg show wg99 fwmark')
84d32bf5
YW
1647 self.assertEqual(output, '0x4d2')
1648 output = check_output('wg show wg99 private-key')
1649 self.assertEqual(output, 'EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=')
371810d1 1650 output = check_output('wg show wg99 allowed-ips')
84d32bf5
YW
1651 self.assertIn('9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c=\t192.168.124.3/32', output)
1652 self.assertIn('TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10=\t192.168.124.2/32', output)
1653 self.assertIn('lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128', output)
1654 self.assertIn('RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48', output)
371810d1 1655 output = check_output('wg show wg99 persistent-keepalive')
84d32bf5
YW
1656 self.assertIn('9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c=\toff', output)
1657 self.assertIn('TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10=\toff', output)
1658 self.assertIn('lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\toff', output)
1659 self.assertIn('RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t20', output)
371810d1 1660 output = check_output('wg show wg99 endpoints')
84d32bf5
YW
1661 self.assertIn('9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c=\t(none)', output)
1662 self.assertIn('TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10=\t(none)', output)
1663 self.assertIn('lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\t(none)', output)
1664 self.assertIn('RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t192.168.27.3:51820', output)
371810d1 1665 output = check_output('wg show wg99 preshared-keys')
84d32bf5
YW
1666 self.assertIn('9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c=\t6Fsg8XN0DE6aPQgAX4r2oazEYJOGqyHUz3QRH/jCB+I=', output)
1667 self.assertIn('TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10=\tit7nd33chCT/tKT2ZZWfYyp43Zs+6oif72hexnSNMqA=', output)
1668 self.assertIn('lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tcPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=', output)
1669 self.assertIn('RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\tIIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=', output)
7a3bc5a8 1670
371810d1 1671 output = check_output('wg show wg98 private-key')
84d32bf5 1672 self.assertEqual(output, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr+WHtZLZ90FU=')
da44fb8a 1673
da3509f0 1674 output = check_output('wg show wg97 listen-port')
84d32bf5 1675 self.assertEqual(output, '51821')
da3509f0 1676 output = check_output('wg show wg97 fwmark')
84d32bf5 1677 self.assertEqual(output, '0x4d3')
da3509f0 1678
1f0e3109 1679 def test_geneve(self):
a962d857 1680 copy_network_unit('25-geneve.netdev', '26-netdev-link-local-addressing-yes.network')
2cf6fdff 1681 start_networkd()
1f0e3109 1682
e2aea43f 1683 self.wait_online(['geneve99:degraded'])
1f0e3109 1684
371810d1 1685 output = check_output('ip -d link show geneve99')
14ecd604 1686 print(output)
06895a1d
YW
1687 self.assertRegex(output, '192.168.22.1')
1688 self.assertRegex(output, '6082')
1689 self.assertRegex(output, 'udpcsum')
1690 self.assertRegex(output, 'udp6zerocsumrx')
1f0e3109
SS
1691
1692 def test_ipip_tunnel(self):
a962d857
YW
1693 copy_network_unit('12-dummy.netdev', '25-ipip.network',
1694 '25-ipip-tunnel.netdev', '25-tunnel.network',
1695 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1696 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1697 '25-ipip-tunnel-any-any.netdev', '25-tunnel-any-any.network')
2cf6fdff 1698 start_networkd()
e2aea43f 1699 self.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'ipiptun96:routable', 'dummy98:degraded'])
6a97a864 1700
371810d1 1701 output = check_output('ip -d link show ipiptun99')
6a97a864 1702 print(output)
426654d7 1703 self.assertRegex(output, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98')
371810d1 1704 output = check_output('ip -d link show ipiptun98')
6a97a864 1705 print(output)
426654d7 1706 self.assertRegex(output, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98')
371810d1 1707 output = check_output('ip -d link show ipiptun97')
6a97a864 1708 print(output)
426654d7 1709 self.assertRegex(output, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98')
42a29fcb
YW
1710 output = check_output('ip -d link show ipiptun96')
1711 print(output)
426654d7 1712 self.assertRegex(output, 'ipip (ipip )?remote any local any dev dummy98')
1f0e3109
SS
1713
1714 def test_gre_tunnel(self):
a962d857
YW
1715 copy_network_unit('12-dummy.netdev', '25-gretun.network',
1716 '25-gre-tunnel.netdev', '25-tunnel.network',
1717 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1718 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1719 '25-gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
2cf6fdff 1720 start_networkd()
e2aea43f 1721 self.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'gretun96:routable', 'dummy98:degraded'])
6a97a864 1722
371810d1 1723 output = check_output('ip -d link show gretun99')
6a97a864
YW
1724 print(output)
1725 self.assertRegex(output, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
38f4bb44
YW
1726 self.assertRegex(output, 'ikey 1.2.3.103')
1727 self.assertRegex(output, 'okey 1.2.4.103')
1728 self.assertRegex(output, 'iseq')
1729 self.assertRegex(output, 'oseq')
371810d1 1730 output = check_output('ip -d link show gretun98')
6a97a864
YW
1731 print(output)
1732 self.assertRegex(output, 'gre remote 10.65.223.239 local any dev dummy98')
38f4bb44
YW
1733 self.assertRegex(output, 'ikey 0.0.0.104')
1734 self.assertRegex(output, 'okey 0.0.0.104')
1735 self.assertNotRegex(output, 'iseq')
1736 self.assertNotRegex(output, 'oseq')
371810d1 1737 output = check_output('ip -d link show gretun97')
6a97a864
YW
1738 print(output)
1739 self.assertRegex(output, 'gre remote any local 10.65.223.238 dev dummy98')
38f4bb44
YW
1740 self.assertRegex(output, 'ikey 0.0.0.105')
1741 self.assertRegex(output, 'okey 0.0.0.105')
1742 self.assertNotRegex(output, 'iseq')
1743 self.assertNotRegex(output, 'oseq')
42a29fcb
YW
1744 output = check_output('ip -d link show gretun96')
1745 print(output)
1746 self.assertRegex(output, 'gre remote any local any dev dummy98')
1747 self.assertRegex(output, 'ikey 0.0.0.106')
1748 self.assertRegex(output, 'okey 0.0.0.106')
1749 self.assertNotRegex(output, 'iseq')
1750 self.assertNotRegex(output, 'oseq')
6a97a864
YW
1751
1752 def test_ip6gre_tunnel(self):
a962d857
YW
1753 copy_network_unit('12-dummy.netdev', '25-ip6gretun.network',
1754 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
1755 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1756 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1757 '25-ip6gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1758 start_networkd()
6a97a864 1759
17bcf0a0
YW
1760 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1761
a962d857 1762 self.wait_links('dummy98', 'ip6gretun99', 'ip6gretun98', 'ip6gretun97', 'ip6gretun96')
6a97a864 1763
371810d1 1764 output = check_output('ip -d link show ip6gretun99')
6a97a864
YW
1765 print(output)
1766 self.assertRegex(output, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
371810d1 1767 output = check_output('ip -d link show ip6gretun98')
6a97a864
YW
1768 print(output)
1769 self.assertRegex(output, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
371810d1 1770 output = check_output('ip -d link show ip6gretun97')
6a97a864
YW
1771 print(output)
1772 self.assertRegex(output, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
42a29fcb
YW
1773 output = check_output('ip -d link show ip6gretun96')
1774 print(output)
1775 self.assertRegex(output, 'ip6gre remote any local any dev dummy98')
1f0e3109 1776
11309591 1777 def test_gretap_tunnel(self):
a962d857
YW
1778 copy_network_unit('12-dummy.netdev', '25-gretap.network',
1779 '25-gretap-tunnel.netdev', '25-tunnel.network',
1780 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
2cf6fdff 1781 start_networkd()
e2aea43f 1782 self.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
6a97a864 1783
371810d1 1784 output = check_output('ip -d link show gretap99')
6a97a864
YW
1785 print(output)
1786 self.assertRegex(output, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
38f4bb44
YW
1787 self.assertRegex(output, 'ikey 0.0.0.106')
1788 self.assertRegex(output, 'okey 0.0.0.106')
1789 self.assertRegex(output, 'iseq')
1790 self.assertRegex(output, 'oseq')
b67e8a4e
YZ
1791 self.assertIn('nopmtudisc', output)
1792 self.assertIn('ignore-df', output)
371810d1 1793 output = check_output('ip -d link show gretap98')
6a97a864
YW
1794 print(output)
1795 self.assertRegex(output, 'gretap remote 10.65.223.239 local any dev dummy98')
38f4bb44
YW
1796 self.assertRegex(output, 'ikey 0.0.0.107')
1797 self.assertRegex(output, 'okey 0.0.0.107')
1798 self.assertRegex(output, 'iseq')
1799 self.assertRegex(output, 'oseq')
1f0e3109
SS
1800
1801 def test_ip6gretap_tunnel(self):
a962d857
YW
1802 copy_network_unit('12-dummy.netdev', '25-ip6gretap.network',
1803 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1804 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
2cf6fdff 1805 start_networkd()
e2aea43f 1806 self.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
6a97a864 1807
371810d1 1808 output = check_output('ip -d link show ip6gretap99')
6a97a864
YW
1809 print(output)
1810 self.assertRegex(output, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
371810d1 1811 output = check_output('ip -d link show ip6gretap98')
6a97a864
YW
1812 print(output)
1813 self.assertRegex(output, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1f0e3109
SS
1814
1815 def test_vti_tunnel(self):
a962d857
YW
1816 copy_network_unit('12-dummy.netdev', '25-vti.network',
1817 '25-vti-tunnel.netdev', '25-tunnel.network',
1818 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1819 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1820 '25-vti-tunnel-any-any.netdev', '25-tunnel-any-any.network')
2cf6fdff 1821 start_networkd()
e2aea43f 1822 self.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'vtitun96:routable', 'dummy98:degraded'])
6a97a864 1823
371810d1 1824 output = check_output('ip -d link show vtitun99')
6a97a864
YW
1825 print(output)
1826 self.assertRegex(output, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
371810d1 1827 output = check_output('ip -d link show vtitun98')
6a97a864
YW
1828 print(output)
1829 self.assertRegex(output, 'vti remote 10.65.223.239 local any dev dummy98')
371810d1 1830 output = check_output('ip -d link show vtitun97')
6a97a864
YW
1831 print(output)
1832 self.assertRegex(output, 'vti remote any local 10.65.223.238 dev dummy98')
42a29fcb
YW
1833 output = check_output('ip -d link show vtitun96')
1834 print(output)
1835 self.assertRegex(output, 'vti remote any local any dev dummy98')
1f0e3109
SS
1836
1837 def test_vti6_tunnel(self):
a962d857
YW
1838 copy_network_unit('12-dummy.netdev', '25-vti6.network',
1839 '25-vti6-tunnel.netdev', '25-tunnel.network',
1840 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1841 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
2cf6fdff 1842 start_networkd()
e2aea43f 1843 self.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
6a97a864 1844
371810d1 1845 output = check_output('ip -d link show vti6tun99')
6a97a864
YW
1846 print(output)
1847 self.assertRegex(output, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
371810d1 1848 output = check_output('ip -d link show vti6tun98')
6a97a864 1849 print(output)
426654d7 1850 self.assertRegex(output, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
371810d1 1851 output = check_output('ip -d link show vti6tun97')
6a97a864 1852 print(output)
426654d7 1853 self.assertRegex(output, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1f0e3109
SS
1854
1855 def test_ip6tnl_tunnel(self):
a962d857
YW
1856 copy_network_unit('12-dummy.netdev', '25-ip6tnl.network',
1857 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1858 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1859 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1860 '25-veth.netdev', '25-ip6tnl-slaac.network', '25-ipv6-prefix.network',
1861 '25-ip6tnl-tunnel-local-slaac.netdev', '25-ip6tnl-tunnel-local-slaac.network',
1862 '25-ip6tnl-tunnel-external.netdev', '26-netdev-link-local-addressing-yes.network')
2cf6fdff 1863 start_networkd()
7809cab7
YW
1864 self.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable',
1865 'ip6tnl-slaac:degraded', 'ip6tnl-external:degraded',
da7d6848 1866 'dummy98:degraded', 'veth99:routable', 'veth-peer:degraded'])
6a97a864 1867
371810d1 1868 output = check_output('ip -d link show ip6tnl99')
6a97a864 1869 print(output)
da7d6848 1870 self.assertIn('ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98', output)
371810d1 1871 output = check_output('ip -d link show ip6tnl98')
6a97a864 1872 print(output)
426654d7 1873 self.assertRegex(output, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
371810d1 1874 output = check_output('ip -d link show ip6tnl97')
6a97a864 1875 print(output)
426654d7 1876 self.assertRegex(output, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
7809cab7
YW
1877 output = check_output('ip -d link show ip6tnl-external')
1878 print(output)
1879 self.assertIn('ip6tnl-external@NONE:', output)
1880 self.assertIn('ip6tnl external ', output)
da7d6848
YW
1881 output = check_output('ip -d link show ip6tnl-slaac')
1882 print(output)
1883 self.assertIn('ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99', output)
1884
1885 output = check_output('ip -6 address show veth99')
1886 print(output)
1887 self.assertIn('inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic', output)
1888
1889 output = check_output('ip -4 route show default')
1890 print(output)
1891 self.assertIn('default dev ip6tnl-slaac proto static', output)
1f0e3109
SS
1892
1893 def test_sit_tunnel(self):
a962d857
YW
1894 copy_network_unit('12-dummy.netdev', '25-sit.network',
1895 '25-sit-tunnel.netdev', '25-tunnel.network',
1896 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1897 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1898 '25-sit-tunnel-any-any.netdev', '25-tunnel-any-any.network')
2cf6fdff 1899 start_networkd()
e2aea43f 1900 self.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'sittun96:routable', 'dummy98:degraded'])
6a97a864 1901
371810d1 1902 output = check_output('ip -d link show sittun99')
6a97a864 1903 print(output)
426654d7 1904 self.assertRegex(output, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98")
371810d1 1905 output = check_output('ip -d link show sittun98')
6a97a864 1906 print(output)
426654d7 1907 self.assertRegex(output, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98")
371810d1 1908 output = check_output('ip -d link show sittun97')
6a97a864 1909 print(output)
426654d7 1910 self.assertRegex(output, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98")
42a29fcb
YW
1911 output = check_output('ip -d link show sittun96')
1912 print(output)
426654d7 1913 self.assertRegex(output, "sit (ip6ip )?remote any local any dev dummy98")
1f0e3109 1914
d0e728b6 1915 def test_isatap_tunnel(self):
a962d857
YW
1916 copy_network_unit('12-dummy.netdev', '25-isatap.network',
1917 '25-isatap-tunnel.netdev', '25-tunnel.network')
2cf6fdff 1918 start_networkd()
e2aea43f 1919 self.wait_online(['isataptun99:routable', 'dummy98:degraded'])
d0e728b6 1920
371810d1 1921 output = check_output('ip -d link show isataptun99')
14ecd604 1922 print(output)
d0e728b6
SS
1923 self.assertRegex(output, "isatap ")
1924
d29dc4f1 1925 def test_6rd_tunnel(self):
a962d857
YW
1926 copy_network_unit('12-dummy.netdev', '25-6rd.network',
1927 '25-6rd-tunnel.netdev', '25-tunnel.network')
2cf6fdff 1928 start_networkd()
e2aea43f 1929 self.wait_online(['sittun99:routable', 'dummy98:degraded'])
d29dc4f1 1930
371810d1 1931 output = check_output('ip -d link show sittun99')
6a97a864
YW
1932 print(output)
1933 self.assertRegex(output, '6rd-prefix 2602::/24')
1934
2f0260c1
YW
1935 @expectedFailureIfERSPANv0IsNotSupported()
1936 def test_erspan_tunnel_v0(self):
a962d857
YW
1937 copy_network_unit('12-dummy.netdev', '25-erspan.network',
1938 '25-erspan0-tunnel.netdev', '25-tunnel.network',
1939 '25-erspan0-tunnel-local-any.netdev', '25-tunnel-local-any.network')
2cf6fdff 1940 start_networkd()
e2aea43f 1941 self.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
2266864b 1942
371810d1 1943 output = check_output('ip -d link show erspan99')
6a97a864 1944 print(output)
2f0260c1
YW
1945 self.assertIn('erspan remote 172.16.1.100 local 172.16.1.200', output)
1946 self.assertIn('erspan_ver 0', output)
1947 self.assertNotIn('erspan_index 123', output)
1948 self.assertNotIn('erspan_dir ingress', output)
1949 self.assertNotIn('erspan_hwid 1f', output)
1950 self.assertIn('ikey 0.0.0.101', output)
1951 self.assertIn('iseq', output)
b67e8a4e
YZ
1952 self.assertIn('nopmtudisc', output)
1953 self.assertIn('ignore-df', output)
371810d1 1954 output = check_output('ip -d link show erspan98')
2266864b 1955 print(output)
2f0260c1
YW
1956 self.assertIn('erspan remote 172.16.1.100 local any', output)
1957 self.assertIn('erspan_ver 0', output)
1958 self.assertNotIn('erspan_index 124', output)
1959 self.assertNotIn('erspan_dir egress', output)
1960 self.assertNotIn('erspan_hwid 2f', output)
1961 self.assertIn('ikey 0.0.0.102', output)
1962 self.assertIn('iseq', output)
1963
1964 def test_erspan_tunnel_v1(self):
a962d857
YW
1965 copy_network_unit('12-dummy.netdev', '25-erspan.network',
1966 '25-erspan1-tunnel.netdev', '25-tunnel.network',
1967 '25-erspan1-tunnel-local-any.netdev', '25-tunnel-local-any.network')
2f0260c1
YW
1968 start_networkd()
1969 self.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1970
1971 output = check_output('ip -d link show erspan99')
1972 print(output)
1973 self.assertIn('erspan remote 172.16.1.100 local 172.16.1.200', output)
1974 self.assertIn('erspan_ver 1', output)
1975 self.assertIn('erspan_index 123', output)
1976 self.assertNotIn('erspan_dir ingress', output)
1977 self.assertNotIn('erspan_hwid 1f', output)
1978 self.assertIn('ikey 0.0.0.101', output)
1979 self.assertIn('okey 0.0.0.101', output)
1980 self.assertIn('iseq', output)
1981 self.assertIn('oseq', output)
1982 output = check_output('ip -d link show erspan98')
1983 print(output)
1984 self.assertIn('erspan remote 172.16.1.100 local any', output)
1985 self.assertIn('erspan_ver 1', output)
1986 self.assertIn('erspan_index 124', output)
1987 self.assertNotIn('erspan_dir egress', output)
1988 self.assertNotIn('erspan_hwid 2f', output)
1989 self.assertIn('ikey 0.0.0.102', output)
1990 self.assertIn('okey 0.0.0.102', output)
1991 self.assertIn('iseq', output)
1992 self.assertIn('oseq', output)
1993
1994 @expectedFailureIfERSPANv2IsNotSupported()
1995 def test_erspan_tunnel_v2(self):
a962d857
YW
1996 copy_network_unit('12-dummy.netdev', '25-erspan.network',
1997 '25-erspan2-tunnel.netdev', '25-tunnel.network',
1998 '25-erspan2-tunnel-local-any.netdev', '25-tunnel-local-any.network')
2f0260c1
YW
1999 start_networkd()
2000 self.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
2001
2002 output = check_output('ip -d link show erspan99')
2003 print(output)
2004 self.assertIn('erspan remote 172.16.1.100 local 172.16.1.200', output)
2005 self.assertIn('erspan_ver 2', output)
2006 self.assertNotIn('erspan_index 123', output)
2007 self.assertIn('erspan_dir ingress', output)
2008 self.assertIn('erspan_hwid 0x1f', output)
2009 self.assertIn('ikey 0.0.0.101', output)
2010 self.assertIn('okey 0.0.0.101', output)
2011 self.assertIn('iseq', output)
2012 self.assertIn('oseq', output)
2013 output = check_output('ip -d link show erspan98')
2014 print(output)
2015 self.assertIn('erspan remote 172.16.1.100 local any', output)
2016 self.assertIn('erspan_ver 2', output)
2017 self.assertNotIn('erspan_index 124', output)
2018 self.assertIn('erspan_dir egress', output)
2019 self.assertIn('erspan_hwid 0x2f', output)
2020 self.assertIn('ikey 0.0.0.102', output)
2021 self.assertIn('okey 0.0.0.102', output)
2022 self.assertIn('iseq', output)
2023 self.assertIn('oseq', output)
2266864b 2024
1f0e3109 2025 def test_tunnel_independent(self):
a962d857 2026 copy_network_unit('25-ipip-tunnel-independent.netdev', '26-netdev-link-local-addressing-yes.network')
2cf6fdff 2027 start_networkd()
e40a58b5 2028
e2aea43f 2029 self.wait_online(['ipiptun99:carrier'])
1f0e3109 2030
95082dbe 2031 def test_tunnel_independent_loopback(self):
a962d857 2032 copy_network_unit('25-ipip-tunnel-independent-loopback.netdev', '26-netdev-link-local-addressing-yes.network')
95082dbe
YW
2033 start_networkd()
2034
e2aea43f 2035 self.wait_online(['ipiptun99:carrier'])
95082dbe 2036
e64dc406
YW
2037 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
2038 def test_xfrm(self):
a962d857
YW
2039 copy_network_unit('12-dummy.netdev', '25-xfrm.network',
2040 '25-xfrm.netdev', '25-xfrm-independent.netdev',
2041 '26-netdev-link-local-addressing-yes.network')
e64dc406
YW
2042 start_networkd()
2043
020483b2 2044 self.wait_online(['dummy98:degraded', 'xfrm98:degraded', 'xfrm99:degraded'])
e64dc406 2045
020483b2 2046 output = check_output('ip -d link show dev xfrm98')
e64dc406 2047 print(output)
020483b2
YW
2048 self.assertIn('xfrm98@dummy98:', output)
2049 self.assertIn('xfrm if_id 0x98 ', output)
e64dc406 2050
020483b2
YW
2051 output = check_output('ip -d link show dev xfrm99')
2052 print(output)
2053 self.assertIn('xfrm99@lo:', output)
2054 self.assertIn('xfrm if_id 0x99 ', output)
e64dc406 2055
4b6a6d1e
YW
2056 @expectedFailureIfModuleIsNotAvailable('fou')
2057 def test_fou(self):
2058 # The following redundant check is necessary for CentOS CI.
2059 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
2060 self.assertTrue(is_module_available('fou'))
2061
a962d857
YW
2062 copy_network_unit('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
2063 '25-fou-ipip.netdev', '25-fou-sit.netdev',
2064 '25-fou-gre.netdev', '25-fou-gretap.netdev')
2cf6fdff 2065 start_networkd()
4b6a6d1e 2066
e2aea43f 2067 self.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'], setup_state='unmanaged')
4b6a6d1e 2068
371810d1 2069 output = check_output('ip fou show')
4b6a6d1e
YW
2070 print(output)
2071 self.assertRegex(output, 'port 55555 ipproto 4')
2072 self.assertRegex(output, 'port 55556 ipproto 47')
2073
371810d1 2074 output = check_output('ip -d link show ipiptun96')
4b6a6d1e
YW
2075 print(output)
2076 self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55555')
371810d1 2077 output = check_output('ip -d link show sittun96')
4b6a6d1e
YW
2078 print(output)
2079 self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55555')
371810d1 2080 output = check_output('ip -d link show gretun96')
4b6a6d1e
YW
2081 print(output)
2082 self.assertRegex(output, 'encap fou encap-sport 1001 encap-dport 55556')
371810d1 2083 output = check_output('ip -d link show gretap96')
4b6a6d1e
YW
2084 print(output)
2085 self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55556')
2086
1f0e3109 2087 def test_vxlan(self):
a962d857
YW
2088 copy_network_unit('11-dummy.netdev', '25-vxlan-test1.network',
2089 '25-vxlan.netdev', '25-vxlan.network',
2090 '25-vxlan-ipv6.netdev', '25-vxlan-ipv6.network',
2091 '25-vxlan-independent.netdev', '26-netdev-link-local-addressing-yes.network',
2092 '25-veth.netdev', '25-vxlan-veth99.network', '25-ipv6-prefix.network',
2093 '25-vxlan-local-slaac.netdev', '25-vxlan-local-slaac.network')
2cf6fdff 2094 start_networkd()
1f0e3109 2095
49ad8da7
YW
2096 self.wait_online(['test1:degraded', 'veth99:routable', 'veth-peer:degraded',
2097 'vxlan99:degraded', 'vxlan98:degraded', 'vxlan97:degraded', 'vxlan-slaac:degraded'])
1f0e3109 2098
a5e478b2 2099 output = check_output('ip -d -d link show vxlan99')
14ecd604 2100 print(output)
cca07d91
YW
2101 self.assertIn('999', output)
2102 self.assertIn('5555', output)
2103 self.assertIn('l2miss', output)
2104 self.assertIn('l3miss', output)
cca07d91 2105 self.assertIn('gbp', output)
a5e478b2
FS
2106 # Since [0] some of the options use slightly different names and some
2107 # options with default values are shown only if the -d(etails) setting
2108 # is repeated
2109 # [0] https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit/?id=1215e9d3862387353d8672296cb4c6c16e8cbb72
2110 self.assertRegex(output, '(udpcsum|udp_csum)')
2111 self.assertRegex(output, '(udp6zerocsumtx|udp_zero_csum6_tx)')
2112 self.assertRegex(output, '(udp6zerocsumrx|udp_zero_csum6_rx)')
2113 self.assertRegex(output, '(remcsumtx|remcsum_tx)')
2114 self.assertRegex(output, '(remcsumrx|remcsum_rx)')
1f0e3109 2115
371810d1 2116 output = check_output('bridge fdb show dev vxlan99')
1c862fe0 2117 print(output)
cca07d91
YW
2118 self.assertIn('00:11:22:33:44:55 dst 10.0.0.5 self permanent', output)
2119 self.assertIn('00:11:22:33:44:66 dst 10.0.0.6 self permanent', output)
2120 self.assertIn('00:11:22:33:44:77 dst 10.0.0.7 via test1 self permanent', output)
1c862fe0 2121
fc79e6ff 2122 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'vxlan99', env=env)
36bc2ffb 2123 print(output)
cca07d91
YW
2124 self.assertIn('VNI: 999', output)
2125 self.assertIn('Destination Port: 5555', output)
2126 self.assertIn('Underlying Device: test1', output)
2127
2128 output = check_output('bridge fdb show dev vxlan97')
2129 print(output)
2130 self.assertIn('00:00:00:00:00:00 dst fe80::23b:d2ff:fe95:967f via test1 self permanent', output)
2131 self.assertIn('00:00:00:00:00:00 dst fe80::27c:16ff:fec0:6c74 via test1 self permanent', output)
2132 self.assertIn('00:00:00:00:00:00 dst fe80::2a2:e4ff:fef9:2269 via test1 self permanent', output)
36bc2ffb 2133
49ad8da7
YW
2134 output = check_output('ip -d link show vxlan-slaac')
2135 print(output)
2136 self.assertIn('vxlan id 4831584 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99', output)
2137
2138 output = check_output('ip -6 address show veth99')
2139 print(output)
2140 self.assertIn('inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic', output)
2141
b3de9d7b 2142 @unittest.skipUnless(compare_kernel_version("6"), reason="Causes kernel panic on unpatched kernels: https://bugzilla.kernel.org/show_bug.cgi?id=208315")
02849d8b 2143 def test_macsec(self):
a962d857
YW
2144 copy_network_unit('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
2145 '26-macsec.network', '12-dummy.netdev')
2cf6fdff 2146 start_networkd()
02849d8b 2147
e2aea43f 2148 self.wait_online(['dummy98:degraded', 'macsec99:routable'])
02849d8b 2149
371810d1 2150 output = check_output('ip -d link show macsec99')
02849d8b
YW
2151 print(output)
2152 self.assertRegex(output, 'macsec99@dummy98')
2153 self.assertRegex(output, 'macsec sci [0-9a-f]*000b')
2154 self.assertRegex(output, 'encrypt on')
2155
371810d1 2156 output = check_output('ip macsec show macsec99')
02849d8b
YW
2157 print(output)
2158 self.assertRegex(output, 'encrypt on')
2159 self.assertRegex(output, 'TXSC: [0-9a-f]*000b on SA 1')
2160 self.assertRegex(output, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
2161 self.assertRegex(output, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
2162 self.assertRegex(output, 'RXSC: c619528fe6a00100, state on')
2163 self.assertRegex(output, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
2164 self.assertRegex(output, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
2165 self.assertRegex(output, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
2166 self.assertRegex(output, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
2167 self.assertNotRegex(output, 'key 02030405067080900000000000000000')
2168 self.assertRegex(output, 'RXSC: 8c16456c83a90002, state on')
2169 self.assertRegex(output, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
2170
811f33d0 2171 def test_nlmon(self):
a962d857 2172 copy_network_unit('25-nlmon.netdev', '26-netdev-link-local-addressing-yes.network')
2cf6fdff 2173 start_networkd()
811f33d0 2174
e2aea43f 2175 self.wait_online(['nlmon99:carrier'])
02849d8b 2176
b076d5d7
YW
2177 @expectedFailureIfModuleIsNotAvailable('ifb')
2178 def test_ifb(self):
a962d857 2179 copy_network_unit('25-ifb.netdev', '26-netdev-link-local-addressing-yes.network')
b076d5d7
YW
2180 start_networkd()
2181
2182 self.wait_online(['ifb99:degraded'])
2183
cff83db9
YW
2184class NetworkdL2TPTests(unittest.TestCase, Utilities):
2185
cff83db9 2186 def setUp(self):
a962d857 2187 setup_common()
cff83db9
YW
2188
2189 def tearDown(self):
a962d857 2190 tear_down_common()
cff83db9 2191
59edcf2b 2192 @expectedFailureIfModuleIsNotAvailable('l2tp_eth', 'l2tp_netlink')
cff83db9 2193 def test_l2tp_udp(self):
a962d857
YW
2194 copy_network_unit('11-dummy.netdev', '25-l2tp-dummy.network',
2195 '25-l2tp-udp.netdev', '25-l2tp.network')
2cf6fdff 2196 start_networkd()
cff83db9 2197
e2aea43f 2198 self.wait_online(['test1:routable', 'l2tp-ses1:degraded', 'l2tp-ses2:degraded'])
cff83db9 2199
371810d1 2200 output = check_output('ip l2tp show tunnel tunnel_id 10')
cff83db9
YW
2201 print(output)
2202 self.assertRegex(output, "Tunnel 10, encap UDP")
2203 self.assertRegex(output, "From 192.168.30.100 to 192.168.30.101")
2204 self.assertRegex(output, "Peer tunnel 11")
2205 self.assertRegex(output, "UDP source / dest ports: 3000/4000")
2206 self.assertRegex(output, "UDP checksum: enabled")
2207
371810d1 2208 output = check_output('ip l2tp show session tid 10 session_id 15')
cff83db9
YW
2209 print(output)
2210 self.assertRegex(output, "Session 15 in tunnel 10")
2211 self.assertRegex(output, "Peer session 16, tunnel 11")
2212 self.assertRegex(output, "interface name: l2tp-ses1")
2213
371810d1 2214 output = check_output('ip l2tp show session tid 10 session_id 17')
cff83db9
YW
2215 print(output)
2216 self.assertRegex(output, "Session 17 in tunnel 10")
2217 self.assertRegex(output, "Peer session 18, tunnel 11")
2218 self.assertRegex(output, "interface name: l2tp-ses2")
2219
59edcf2b 2220 @expectedFailureIfModuleIsNotAvailable('l2tp_eth', 'l2tp_ip', 'l2tp_netlink')
cff83db9 2221 def test_l2tp_ip(self):
a962d857
YW
2222 copy_network_unit('11-dummy.netdev', '25-l2tp-dummy.network',
2223 '25-l2tp-ip.netdev', '25-l2tp.network')
2cf6fdff 2224 start_networkd()
cff83db9 2225
e2aea43f 2226 self.wait_online(['test1:routable', 'l2tp-ses3:degraded', 'l2tp-ses4:degraded'])
cff83db9 2227
371810d1 2228 output = check_output('ip l2tp show tunnel tunnel_id 10')
cff83db9
YW
2229 print(output)
2230 self.assertRegex(output, "Tunnel 10, encap IP")
2231 self.assertRegex(output, "From 192.168.30.100 to 192.168.30.101")
2232 self.assertRegex(output, "Peer tunnel 12")
2233
371810d1 2234 output = check_output('ip l2tp show session tid 10 session_id 25')
cff83db9
YW
2235 print(output)
2236 self.assertRegex(output, "Session 25 in tunnel 10")
2237 self.assertRegex(output, "Peer session 26, tunnel 12")
2238 self.assertRegex(output, "interface name: l2tp-ses3")
2239
371810d1 2240 output = check_output('ip l2tp show session tid 10 session_id 27')
cff83db9
YW
2241 print(output)
2242 self.assertRegex(output, "Session 27 in tunnel 10")
2243 self.assertRegex(output, "Peer session 28, tunnel 12")
2244 self.assertRegex(output, "interface name: l2tp-ses4")
2245
be68c2c9 2246class NetworkdNetworkTests(unittest.TestCase, Utilities):
95c74b0a 2247
1f0e3109 2248 def setUp(self):
a962d857 2249 setup_common()
1f0e3109
SS
2250
2251 def tearDown(self):
a962d857 2252 tear_down_common()
1f0e3109 2253
b8102725 2254 def test_address_static(self):
6dcc087c 2255 # test for #22515. The address will be removed and replaced with /64 prefix.
a962d857
YW
2256 check_output('ip link add dummy98 type dummy')
2257 check_output('ip link set dev dummy98 up')
2258 check_output('ip -6 address add 2001:db8:0:f101::15/128 dev dummy98')
6dcc087c 2259 self.wait_address('dummy98', '2001:db8:0:f101::15/128', ipv='-6')
a962d857 2260 check_output('ip -4 address add 10.3.2.3/16 brd 10.3.255.250 scope global label dummy98:hoge dev dummy98')
6dcc087c
YW
2261 self.wait_address('dummy98', '10.3.2.3/16 brd 10.3.255.250', ipv='-4')
2262
a962d857 2263 copy_network_unit('25-address-static.network', '12-dummy.netdev')
2cf6fdff 2264 start_networkd()
b8102725 2265
e2aea43f 2266 self.wait_online(['dummy98:routable'])
b8102725 2267
371810d1 2268 output = check_output('ip -4 address show dev dummy98')
b8102725 2269 print(output)
4a704501
YW
2270 self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output)
2271 self.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output)
2272 self.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output)
2273 self.assertIn('inet 10.7.8.9/16 brd 10.7.255.255 scope link deprecated dummy98', output)
045db4fa 2274 self.assertIn('inet 10.8.8.1/16 scope global dummy98', output)
1ac845ff
YW
2275 self.assertIn('inet 10.8.8.2/16 brd 10.8.8.128 scope global secondary dummy98', output)
2276 self.assertRegex(output, 'inet 10.9.0.1/16 (metric 128 |)brd 10.9.255.255 scope global dummy98')
b8102725 2277
766f8f38 2278 # test for ENOBUFS issue #17012
a962d857 2279 for i in range(1, 254):
4a704501 2280 self.assertIn(f'inet 10.3.3.{i}/16 brd 10.3.255.255', output)
766f8f38 2281
b8102725 2282 # invalid sections
4a704501
YW
2283 self.assertNotIn('10.10.0.1/16', output)
2284 self.assertNotIn('10.10.0.2/16', output)
b8102725 2285
371810d1 2286 output = check_output('ip -4 address show dev dummy98 label 32')
4a704501 2287 self.assertIn('inet 10.3.2.3/16 brd 10.3.255.255 scope global 32', output)
b8102725 2288
371810d1 2289 output = check_output('ip -4 address show dev dummy98 label 33')
4a704501 2290 self.assertIn('inet 10.4.2.3 peer 10.4.2.4/16 scope global 33', output)
b8102725 2291
371810d1 2292 output = check_output('ip -4 address show dev dummy98 label 34')
4a704501 2293 self.assertRegex(output, r'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
b8102725 2294
371810d1 2295 output = check_output('ip -4 address show dev dummy98 label 35')
4a704501 2296 self.assertRegex(output, r'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
b8102725 2297
1ac845ff
YW
2298 output = check_output('ip -4 route show dev dummy98')
2299 print(output)
2300 self.assertIn('10.9.0.0/16 proto kernel scope link src 10.9.0.1 metric 128', output)
2301
371810d1 2302 output = check_output('ip -6 address show dev dummy98')
b8102725 2303 print(output)
4a704501
YW
2304 self.assertIn('inet6 2001:db8:0:f101::15/64 scope global', output)
2305 self.assertIn('inet6 2001:db8:0:f101::16/64 scope global', output)
2306 self.assertIn('inet6 2001:db8:0:f102::15/64 scope global', output)
2307 self.assertIn('inet6 2001:db8:0:f102::16/64 scope global', output)
2308 self.assertIn('inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global', output)
2309 self.assertIn('inet6 2001:db8:1:f101::1/64 scope global deprecated', output)
2310 self.assertRegex(output, r'inet6 fd[0-9a-f:]*1/64 scope global')
b8102725 2311
0677130e 2312 self.check_netlabel('dummy98', r'10\.4\.3\.0/24')
a4640bed 2313
40971657
YW
2314 # Tests for #20891.
2315 # 1. set preferred lifetime forever to drop the deprecated flag for testing #20891.
a962d857
YW
2316 check_output('ip address change 10.7.8.9/16 dev dummy98 preferred_lft forever')
2317 check_output('ip address change 2001:db8:1:f101::1/64 dev dummy98 preferred_lft forever')
40971657
YW
2318 output = check_output('ip -4 address show dev dummy98')
2319 print(output)
2320 self.assertNotIn('deprecated', output)
2321 output = check_output('ip -6 address show dev dummy98')
2322 print(output)
2323 self.assertNotIn('deprecated', output)
2324
5b47f35d 2325 # 2. reconfigure the interface.
a962d857 2326 networkctl_reconfigure('dummy98')
766f8f38
YW
2327 self.wait_online(['dummy98:routable'])
2328
40971657
YW
2329 # 3. check the deprecated flag is set for the address configured with PreferredLifetime=0
2330 output = check_output('ip -4 address show dev dummy98')
2331 print(output)
2332 self.assertIn('inet 10.7.8.9/16 brd 10.7.255.255 scope link deprecated dummy98', output)
2333 output = check_output('ip -6 address show dev dummy98')
2334 print(output)
2335 self.assertIn('inet6 2001:db8:1:f101::1/64 scope global deprecated', output)
2336
766f8f38
YW
2337 # test for ENOBUFS issue #17012
2338 output = check_output('ip -4 address show dev dummy98')
a962d857 2339 for i in range(1, 254):
4a704501 2340 self.assertIn(f'inet 10.3.3.{i}/16 brd 10.3.255.255', output)
e4783b54 2341
146726b2
YW
2342 # TODO: check json string
2343 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
2344
44924431
YW
2345 def test_address_ipv4acd(self):
2346 check_output('ip netns add ns99')
2347 check_output('ip link add veth99 type veth peer veth-peer')
2348 check_output('ip link set veth-peer netns ns99')
2349 check_output('ip link set veth99 up')
2350 check_output('ip netns exec ns99 ip link set veth-peer up')
2351 check_output('ip netns exec ns99 ip address add 192.168.100.10/24 dev veth-peer')
2352
a962d857 2353 copy_network_unit('25-address-ipv4acd-veth99.network', copy_dropins=False)
dc7d3c5f 2354 start_networkd()
44924431 2355 self.wait_online(['veth99:routable'])
dc7d3c5f
YW
2356
2357 output = check_output('ip -4 address show dev veth99')
2358 print(output)
44924431
YW
2359 self.assertNotIn('192.168.100.10/24', output)
2360 self.assertIn('192.168.100.11/24', output)
dc7d3c5f 2361
a962d857
YW
2362 copy_network_unit('25-address-ipv4acd-veth99.network.d/conflict-address.conf')
2363 networkctl_reload()
37611ccb 2364 self.wait_operstate('veth99', operstate='routable', setup_state='configuring', setup_timeout=10)
44924431
YW
2365
2366 output = check_output('ip -4 address show dev veth99')
dc7d3c5f 2367 print(output)
44924431
YW
2368 self.assertNotIn('192.168.100.10/24', output)
2369 self.assertIn('192.168.100.11/24', output)
dc7d3c5f 2370
21266e60
YW
2371 def test_address_peer_ipv4(self):
2372 # test for issue #17304
a962d857 2373 copy_network_unit('25-address-peer-ipv4.network', '12-dummy.netdev')
21266e60
YW
2374
2375 for trial in range(2):
2376 if trial == 0:
2377 start_networkd()
2378 else:
2379 restart_networkd()
2380
2381 self.wait_online(['dummy98:routable'])
2382
2383 output = check_output('ip -4 address show dev dummy98')
2384 self.assertIn('inet 100.64.0.1 peer 100.64.0.2/32 scope global', output)
2385
c9d223e8
YW
2386 @expectedFailureIfModuleIsNotAvailable('vrf')
2387 def test_prefix_route(self):
a962d857
YW
2388 copy_network_unit('25-prefix-route-with-vrf.network', '12-dummy.netdev',
2389 '25-prefix-route-without-vrf.network', '11-dummy.netdev',
2390 '25-vrf.netdev', '25-vrf.network')
c9d223e8
YW
2391 for trial in range(2):
2392 if trial == 0:
2393 start_networkd()
2394 else:
a962d857 2395 restart_networkd()
c9d223e8
YW
2396
2397 self.wait_online(['dummy98:routable', 'test1:routable', 'vrf99:carrier'])
2398
2399 output = check_output('ip route show table 42 dev dummy98')
2400 print('### ip route show table 42 dev dummy98')
2401 print(output)
2402 self.assertRegex(output, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1')
c9d223e8
YW
2403 self.assertRegex(output, '10.20.33.0/24 proto kernel scope link src 10.20.33.1')
2404 self.assertRegex(output, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1')
2405 self.assertRegex(output, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1')
2406 self.assertRegex(output, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1')
c9d223e8
YW
2407 self.assertRegex(output, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1')
2408 self.assertRegex(output, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1')
2409 output = check_output('ip -6 route show table 42 dev dummy98')
2410 print('### ip -6 route show table 42 dev dummy98')
2411 print(output)
2412 if trial == 0:
2413 # Kernel's bug?
2414 self.assertRegex(output, 'local fdde:11:22::1 proto kernel metric 0 pref medium')
2415 #self.assertRegex(output, 'fdde:11:22::1 proto kernel metric 256 pref medium')
2416 self.assertRegex(output, 'local fdde:11:33::1 proto kernel metric 0 pref medium')
2417 self.assertRegex(output, 'fdde:11:33::/64 proto kernel metric 256 pref medium')
2418 self.assertRegex(output, 'local fdde:11:44::1 proto kernel metric 0 pref medium')
2419 self.assertRegex(output, 'local fdde:11:55::1 proto kernel metric 0 pref medium')
2420 self.assertRegex(output, 'fe80::/64 proto kernel metric 256 pref medium')
beb75dd3 2421 self.assertRegex(output, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium')
c9d223e8
YW
2422
2423 print()
2424
2425 output = check_output('ip route show dev test1')
2426 print('### ip route show dev test1')
2427 print(output)
2428 self.assertRegex(output, '10.21.33.0/24 proto kernel scope link src 10.21.33.1')
2429 output = check_output('ip route show table local dev test1')
2430 print('### ip route show table local dev test1')
2431 print(output)
2432 self.assertRegex(output, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1')
c9d223e8
YW
2433 self.assertRegex(output, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1')
2434 self.assertRegex(output, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1')
2435 self.assertRegex(output, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1')
c9d223e8
YW
2436 self.assertRegex(output, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1')
2437 self.assertRegex(output, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1')
2438 output = check_output('ip -6 route show dev test1')
2439 print('### ip -6 route show dev test1')
2440 print(output)
2441 self.assertRegex(output, 'fdde:12:22::1 proto kernel metric 256 pref medium')
2442 self.assertRegex(output, 'fdde:12:33::/64 proto kernel metric 256 pref medium')
2443 self.assertRegex(output, 'fe80::/64 proto kernel metric 256 pref medium')
2444 output = check_output('ip -6 route show table local dev test1')
2445 print('### ip -6 route show table local dev test1')
2446 print(output)
2447 self.assertRegex(output, 'local fdde:12:22::1 proto kernel metric 0 pref medium')
2448 self.assertRegex(output, 'local fdde:12:33::1 proto kernel metric 0 pref medium')
2449 self.assertRegex(output, 'local fdde:12:44::1 proto kernel metric 0 pref medium')
2450 self.assertRegex(output, 'local fdde:12:55::1 proto kernel metric 0 pref medium')
beb75dd3 2451 self.assertRegex(output, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium')
c9d223e8 2452
1f0e3109 2453 def test_configure_without_carrier(self):
a962d857 2454 copy_network_unit('11-dummy.netdev')
2cf6fdff 2455 start_networkd()
9bacf431
DS
2456 self.wait_operstate('test1', 'off', '')
2457 check_output('ip link set dev test1 up carrier off')
2458
a962d857 2459 copy_network_unit('25-test1.network.d/configure-without-carrier.conf', copy_dropins=False)
9bacf431
DS
2460 restart_networkd()
2461 self.wait_online(['test1:no-carrier'])
2462
2463 carrier_map = {'on': '1', 'off': '0'}
2464 routable_map = {'on': 'routable', 'off': 'no-carrier'}
2465 for carrier in ['off', 'on', 'off']:
2466 with self.subTest(carrier=carrier):
2467 if carrier_map[carrier] != read_link_attr('test1', 'carrier'):
2468 check_output(f'ip link set dev test1 carrier {carrier}')
705c7b18 2469 self.wait_online([f'test1:{routable_map[carrier]}:{routable_map[carrier]}'])
9bacf431
DS
2470
2471 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'test1', env=env)
2472 print(output)
2473 self.assertRegex(output, '192.168.0.15')
2474 self.assertRegex(output, '192.168.0.1')
2475 self.assertRegex(output, routable_map[carrier])
e40a58b5 2476
9bacf431 2477 def test_configure_without_carrier_yes_ignore_carrier_loss_no(self):
a962d857 2478 copy_network_unit('11-dummy.netdev')
9bacf431
DS
2479 start_networkd()
2480 self.wait_operstate('test1', 'off', '')
2481 check_output('ip link set dev test1 up carrier off')
2482
a962d857 2483 copy_network_unit('25-test1.network')
9bacf431
DS
2484 restart_networkd()
2485 self.wait_online(['test1:no-carrier'])
2486
2487 carrier_map = {'on': '1', 'off': '0'}
2488 routable_map = {'on': 'routable', 'off': 'no-carrier'}
2489 for (carrier, have_config) in [('off', True), ('on', True), ('off', False)]:
2490 with self.subTest(carrier=carrier, have_config=have_config):
2491 if carrier_map[carrier] != read_link_attr('test1', 'carrier'):
2492 check_output(f'ip link set dev test1 carrier {carrier}')
705c7b18 2493 self.wait_online([f'test1:{routable_map[carrier]}:{routable_map[carrier]}'])
9bacf431
DS
2494
2495 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'test1', env=env)
2496 print(output)
2497 if have_config:
2498 self.assertRegex(output, '192.168.0.15')
2499 self.assertRegex(output, '192.168.0.1')
2500 else:
2501 self.assertNotRegex(output, '192.168.0.15')
2502 self.assertNotRegex(output, '192.168.0.1')
2503 self.assertRegex(output, routable_map[carrier])
1f0e3109 2504
1f0e3109 2505 def test_routing_policy_rule(self):
a962d857 2506 copy_network_unit('25-routing-policy-rule-test1.network', '11-dummy.netdev')
2cf6fdff 2507 start_networkd()
e2aea43f 2508 self.wait_online(['test1:degraded'])
e40a58b5 2509
65c24cd0 2510 output = check_output('ip rule list iif test1 priority 111')
1f0e3109 2511 print(output)
65c24cd0 2512 self.assertRegex(output, '111:')
1f0e3109 2513 self.assertRegex(output, 'from 192.168.100.18')
426654d7 2514 self.assertRegex(output, r'tos (0x08|throughput)\s')
1f0e3109
SS
2515 self.assertRegex(output, 'iif test1')
2516 self.assertRegex(output, 'oif test1')
2517 self.assertRegex(output, 'lookup 7')
2518
65c24cd0
YW
2519 output = check_output('ip rule list iif test1 priority 101')
2520 print(output)
2521 self.assertRegex(output, '101:')
2522 self.assertRegex(output, 'from all')
2523 self.assertRegex(output, 'iif test1')
2524 self.assertRegex(output, 'lookup 9')
2525
2526 output = check_output('ip -6 rule list iif test1 priority 100')
2527 print(output)
2528 self.assertRegex(output, '100:')
2529 self.assertRegex(output, 'from all')
2530 self.assertRegex(output, 'iif test1')
2531 self.assertRegex(output, 'lookup 8')
2532
2e8a32af
HV
2533 output = check_output('ip rule list iif test1 priority 102')
2534 print(output)
2535 self.assertRegex(output, '102:')
2536 self.assertRegex(output, 'from 0.0.0.0/8')
2537 self.assertRegex(output, 'iif test1')
2538 self.assertRegex(output, 'lookup 10')
2539
146726b2
YW
2540 # TODO: check json string
2541 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
2542
b677774d 2543 def test_routing_policy_rule_issue_11280(self):
a962d857
YW
2544 copy_network_unit('25-routing-policy-rule-test1.network', '11-dummy.netdev',
2545 '25-routing-policy-rule-dummy98.network', '12-dummy.netdev')
b677774d 2546
a962d857
YW
2547 for trial in range(3):
2548 restart_networkd(show_logs=(trial > 0))
e2aea43f 2549 self.wait_online(['test1:degraded', 'dummy98:degraded'])
b677774d 2550
371810d1 2551 output = check_output('ip rule list table 7')
b677774d 2552 print(output)
426654d7 2553 self.assertRegex(output, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
b677774d 2554
371810d1 2555 output = check_output('ip rule list table 8')
b677774d 2556 print(output)
426654d7 2557 self.assertRegex(output, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
b677774d 2558
87adeabf 2559 def test_routing_policy_rule_reconfigure(self):
a962d857 2560 copy_network_unit('25-routing-policy-rule-reconfigure2.network', '11-dummy.netdev')
87adeabf
YW
2561 start_networkd()
2562 self.wait_online(['test1:degraded'])
2563
2564 output = check_output('ip rule list table 1011')
2565 print(output)
49ff3f34
YW
2566 self.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output)
2567 self.assertIn('10112: from all oif test1 lookup 1011', output)
2568 self.assertIn('10113: from all iif test1 lookup 1011', output)
2569 self.assertIn('10114: from 192.168.8.254 lookup 1011', output)
2570
2571 output = check_output('ip -6 rule list table 1011')
2572 print(output)
2573 self.assertIn('10112: from all oif test1 lookup 1011', output)
2574
a962d857
YW
2575 copy_network_unit('25-routing-policy-rule-reconfigure1.network', '11-dummy.netdev')
2576 networkctl_reload()
49ff3f34
YW
2577 self.wait_online(['test1:degraded'])
2578
2579 output = check_output('ip rule list table 1011')
2580 print(output)
2581 self.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output)
2582 self.assertIn('10112: from all oif test1 lookup 1011', output)
2583 self.assertIn('10113: from all iif test1 lookup 1011', output)
2584 self.assertIn('10114: from 192.168.8.254 lookup 1011', output)
2585
2586 output = check_output('ip -6 rule list table 1011')
2587 print(output)
2588 self.assertNotIn('10112: from all oif test1 lookup 1011', output)
2589 self.assertIn('10113: from all iif test1 lookup 1011', output)
87adeabf 2590
a962d857
YW
2591 call('ip rule delete priority 10111')
2592 call('ip rule delete priority 10112')
2593 call('ip rule delete priority 10113')
2594 call('ip rule delete priority 10114')
2595 call('ip -6 rule delete priority 10113')
87adeabf
YW
2596
2597 output = check_output('ip rule list table 1011')
2598 print(output)
2599 self.assertEqual(output, '')
2600
49ff3f34
YW
2601 output = check_output('ip -6 rule list table 1011')
2602 print(output)
2603 self.assertEqual(output, '')
87adeabf 2604
a962d857 2605 networkctl_reconfigure('test1')
87adeabf
YW
2606 self.wait_online(['test1:degraded'])
2607
2608 output = check_output('ip rule list table 1011')
2609 print(output)
49ff3f34
YW
2610 self.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output)
2611 self.assertIn('10112: from all oif test1 lookup 1011', output)
2612 self.assertIn('10113: from all iif test1 lookup 1011', output)
2613 self.assertIn('10114: from 192.168.8.254 lookup 1011', output)
2614
2615 output = check_output('ip -6 rule list table 1011')
2616 print(output)
2617 self.assertIn('10113: from all iif test1 lookup 1011', output)
87adeabf 2618
d586a2c3 2619 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
926062f0 2620 def test_routing_policy_rule_port_range(self):
a962d857 2621 copy_network_unit('25-fibrule-port-range.network', '11-dummy.netdev')
2cf6fdff 2622 start_networkd()
e2aea43f 2623 self.wait_online(['test1:degraded'])
e40a58b5 2624
371810d1 2625 output = check_output('ip rule')
926062f0
SS
2626 print(output)
2627 self.assertRegex(output, '111')
2628 self.assertRegex(output, 'from 192.168.100.18')
2629 self.assertRegex(output, '1123-1150')
2630 self.assertRegex(output, '3224-3290')
2631 self.assertRegex(output, 'tcp')
2632 self.assertRegex(output, 'lookup 7')
1f0e3109 2633
d586a2c3 2634 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
efecf9cd 2635 def test_routing_policy_rule_invert(self):
a962d857 2636 copy_network_unit('25-fibrule-invert.network', '11-dummy.netdev')
2cf6fdff 2637 start_networkd()
e2aea43f 2638 self.wait_online(['test1:degraded'])
e40a58b5 2639
371810d1 2640 output = check_output('ip rule')
efecf9cd 2641 print(output)
efecf9cd
SS
2642 self.assertRegex(output, '111')
2643 self.assertRegex(output, 'not.*?from.*?192.168.100.18')
2644 self.assertRegex(output, 'tcp')
2645 self.assertRegex(output, 'lookup 7')
2646
6be8e78e
YW
2647 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable()
2648 def test_routing_policy_rule_uidrange(self):
a962d857 2649 copy_network_unit('25-fibrule-uidrange.network', '11-dummy.netdev')
6be8e78e
YW
2650 start_networkd()
2651 self.wait_online(['test1:degraded'])
2652
2653 output = check_output('ip rule')
2654 print(output)
2655 self.assertRegex(output, '111')
2656 self.assertRegex(output, 'from 192.168.100.18')
2657 self.assertRegex(output, 'lookup 7')
2658 self.assertRegex(output, 'uidrange 100-200')
2659
1d26d4cd
YW
2660 def _test_route_static(self, manage_foreign_routes):
2661 if not manage_foreign_routes:
2662 copy_networkd_conf_dropin('networkd-manage-foreign-routes-no.conf')
2663
a962d857 2664 copy_network_unit('25-route-static.network', '12-dummy.netdev')
2cf6fdff 2665 start_networkd()
e2aea43f
YW
2666 self.wait_online(['dummy98:routable'])
2667
fc79e6ff 2668 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98', env=env)
e2aea43f 2669 print(output)
0d34228f 2670
6d60f9db 2671 print('### ip -6 route show dev dummy98')
371810d1 2672 output = check_output('ip -6 route show dev dummy98')
0d34228f 2673 print(output)
0b5dc249
YW
2674 self.assertIn('2001:1234:5:8fff:ff:ff:ff:ff proto static', output)
2675 self.assertIn('2001:1234:5:8f63::1 proto kernel', output)
180c5116 2676 self.assertIn('2001:1234:5:afff:ff:ff:ff:ff via fe80:0:222:4dff:ff:ff:ff:ff proto static', output)
1f0e3109 2677
d9005dec
YW
2678 print('### ip -6 route show default')
2679 output = check_output('ip -6 route show default')
6d60f9db 2680 print(output)
0b5dc249
YW
2681 self.assertIn('default', output)
2682 self.assertIn('via 2001:1234:5:8fff:ff:ff:ff:ff', output)
1f0e3109 2683
6d60f9db 2684 print('### ip -4 route show dev dummy98')
371810d1 2685 output = check_output('ip -4 route show dev dummy98')
1f0e3109 2686 print(output)
0b5dc249
YW
2687 self.assertIn('149.10.124.48/28 proto kernel scope link src 149.10.124.58', output)
2688 self.assertIn('149.10.124.64 proto static scope link', output)
2689 self.assertIn('169.254.0.0/16 proto static scope link metric 2048', output)
902bbdc4
YW
2690 self.assertIn('192.168.1.1 proto static scope link initcwnd 20', output)
2691 self.assertIn('192.168.1.2 proto static scope link initrwnd 30', output)
2692 self.assertIn('192.168.1.3 proto static scope link advmss 30', output)
0b5dc249 2693 self.assertIn('multicast 149.10.123.4 proto static', output)
1f0e3109 2694
6d60f9db 2695 print('### ip -4 route show dev dummy98 default')
371810d1 2696 output = check_output('ip -4 route show dev dummy98 default')
6d60f9db 2697 print(output)
0b5dc249
YW
2698 self.assertIn('default via 149.10.125.65 proto static onlink', output)
2699 self.assertIn('default via 149.10.124.64 proto static', output)
2700 self.assertIn('default proto static', output)
1f0e3109 2701
6d60f9db
YW
2702 print('### ip -4 route show table local dev dummy98')
2703 output = check_output('ip -4 route show table local dev dummy98')
2704 print(output)
0b5dc249
YW
2705 self.assertIn('local 149.10.123.1 proto static scope host', output)
2706 self.assertIn('anycast 149.10.123.2 proto static scope link', output)
2707 self.assertIn('broadcast 149.10.123.3 proto static scope link', output)
6d60f9db 2708
b4f4f119
YW
2709 print('### ip -4 route show type blackhole')
2710 output = check_output('ip -4 route show type blackhole')
1f0e3109 2711 print(output)
0b5dc249 2712 self.assertIn('blackhole 202.54.1.2 proto static', output)
f5050e48 2713
b4f4f119
YW
2714 print('### ip -4 route show type unreachable')
2715 output = check_output('ip -4 route show type unreachable')
f5050e48 2716 print(output)
0b5dc249 2717 self.assertIn('unreachable 202.54.1.3 proto static', output)
f5050e48 2718
b4f4f119
YW
2719 print('### ip -4 route show type prohibit')
2720 output = check_output('ip -4 route show type prohibit')
f5050e48 2721 print(output)
0b5dc249 2722 self.assertIn('prohibit 202.54.1.4 proto static', output)
f5050e48 2723
452d86a5
YW
2724 print('### ip -6 route show type blackhole')
2725 output = check_output('ip -6 route show type blackhole')
2726 print(output)
2727 self.assertIn('blackhole 2001:1234:5678::2 dev lo proto static', output)
2728
2729 print('### ip -6 route show type unreachable')
2730 output = check_output('ip -6 route show type unreachable')
2731 print(output)
2732 self.assertIn('unreachable 2001:1234:5678::3 dev lo proto static', output)
2733
2734 print('### ip -6 route show type prohibit')
2735 output = check_output('ip -6 route show type prohibit')
2736 print(output)
2737 self.assertIn('prohibit 2001:1234:5678::4 dev lo proto static', output)
2738
a0ce990e
YW
2739 print('### ip route show 192.168.10.1')
2740 output = check_output('ip route show 192.168.10.1')
2741 print(output)
0b5dc249
YW
2742 self.assertIn('192.168.10.1 proto static', output)
2743 self.assertIn('nexthop via 149.10.124.59 dev dummy98 weight 10', output)
2744 self.assertIn('nexthop via 149.10.124.60 dev dummy98 weight 5', output)
a0ce990e
YW
2745
2746 print('### ip route show 192.168.10.2')
2747 output = check_output('ip route show 192.168.10.2')
2748 print(output)
2749 # old ip command does not show IPv6 gateways...
0b5dc249
YW
2750 self.assertIn('192.168.10.2 proto static', output)
2751 self.assertIn('nexthop', output)
2752 self.assertIn('dev dummy98 weight 10', output)
2753 self.assertIn('dev dummy98 weight 5', output)
a0ce990e
YW
2754
2755 print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2756 output = check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2757 print(output)
2758 # old ip command does not show 'nexthop' keyword and weight...
0b5dc249
YW
2759 self.assertIn('2001:1234:5:7fff:ff:ff:ff:ff', output)
2760 self.assertIn('via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98', output)
2761 self.assertIn('via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98', output)
a0ce990e 2762
146726b2
YW
2763 # TODO: check json string
2764 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
2765
a962d857
YW
2766 copy_network_unit('25-address-static.network')
2767 networkctl_reload()
43d4bc9f
YW
2768 self.wait_online(['dummy98:routable'])
2769
2770 # check all routes managed by Manager are removed
b4f4f119
YW
2771 print('### ip -4 route show type blackhole')
2772 output = check_output('ip -4 route show type blackhole')
43d4bc9f
YW
2773 print(output)
2774 self.assertEqual(output, '')
2775
b4f4f119
YW
2776 print('### ip -4 route show type unreachable')
2777 output = check_output('ip -4 route show type unreachable')
43d4bc9f
YW
2778 print(output)
2779 self.assertEqual(output, '')
2780
b4f4f119
YW
2781 print('### ip -4 route show type prohibit')
2782 output = check_output('ip -4 route show type prohibit')
43d4bc9f
YW
2783 print(output)
2784 self.assertEqual(output, '')
2785
452d86a5
YW
2786 print('### ip -6 route show type blackhole')
2787 output = check_output('ip -6 route show type blackhole')
2788 print(output)
2789 self.assertEqual(output, '')
2790
2791 print('### ip -6 route show type unreachable')
2792 output = check_output('ip -6 route show type unreachable')
2793 print(output)
2794 self.assertEqual(output, '')
2795
2796 print('### ip -6 route show type prohibit')
2797 output = check_output('ip -6 route show type prohibit')
2798 print(output)
2799 self.assertEqual(output, '')
2800
a962d857
YW
2801 remove_network_unit('25-address-static.network')
2802 networkctl_reload()
43d4bc9f
YW
2803 self.wait_online(['dummy98:routable'])
2804
2805 # check all routes managed by Manager are reconfigured
b4f4f119
YW
2806 print('### ip -4 route show type blackhole')
2807 output = check_output('ip -4 route show type blackhole')
43d4bc9f 2808 print(output)
0b5dc249 2809 self.assertIn('blackhole 202.54.1.2 proto static', output)
43d4bc9f 2810
b4f4f119
YW
2811 print('### ip -4 route show type unreachable')
2812 output = check_output('ip -4 route show type unreachable')
43d4bc9f 2813 print(output)
0b5dc249 2814 self.assertIn('unreachable 202.54.1.3 proto static', output)
43d4bc9f 2815
b4f4f119
YW
2816 print('### ip -4 route show type prohibit')
2817 output = check_output('ip -4 route show type prohibit')
43d4bc9f 2818 print(output)
0b5dc249 2819 self.assertIn('prohibit 202.54.1.4 proto static', output)
43d4bc9f 2820
452d86a5
YW
2821 print('### ip -6 route show type blackhole')
2822 output = check_output('ip -6 route show type blackhole')
2823 print(output)
2824 self.assertIn('blackhole 2001:1234:5678::2 dev lo proto static', output)
2825
2826 print('### ip -6 route show type unreachable')
2827 output = check_output('ip -6 route show type unreachable')
2828 print(output)
2829 self.assertIn('unreachable 2001:1234:5678::3 dev lo proto static', output)
2830
2831 print('### ip -6 route show type prohibit')
2832 output = check_output('ip -6 route show type prohibit')
2833 print(output)
2834 self.assertIn('prohibit 2001:1234:5678::4 dev lo proto static', output)
2835
a962d857 2836 remove_link('dummy98')
43d4bc9f
YW
2837 time.sleep(2)
2838
2839 # check all routes managed by Manager are removed
b4f4f119
YW
2840 print('### ip -4 route show type blackhole')
2841 output = check_output('ip -4 route show type blackhole')
43d4bc9f
YW
2842 print(output)
2843 self.assertEqual(output, '')
2844
b4f4f119
YW
2845 print('### ip -4 route show type unreachable')
2846 output = check_output('ip -4 route show type unreachable')
43d4bc9f
YW
2847 print(output)
2848 self.assertEqual(output, '')
2849
b4f4f119
YW
2850 print('### ip -4 route show type prohibit')
2851 output = check_output('ip -4 route show type prohibit')
43d4bc9f
YW
2852 print(output)
2853 self.assertEqual(output, '')
2854
452d86a5
YW
2855 print('### ip -6 route show type blackhole')
2856 output = check_output('ip -6 route show type blackhole')
2857 print(output)
2858 self.assertEqual(output, '')
2859
2860 print('### ip -6 route show type unreachable')
2861 output = check_output('ip -6 route show type unreachable')
2862 print(output)
2863 self.assertEqual(output, '')
2864
2865 print('### ip -6 route show type prohibit')
2866 output = check_output('ip -6 route show type prohibit')
2867 print(output)
2868 self.assertEqual(output, '')
2869
1d26d4cd
YW
2870 self.tearDown()
2871
2872 def test_route_static(self):
a962d857 2873 first = True
1d26d4cd 2874 for manage_foreign_routes in [True, False]:
a962d857
YW
2875 if first:
2876 first = False
2877 else:
2878 self.tearDown()
2879
2880 print(f'### test_route_static(manage_foreign_routes={manage_foreign_routes})')
1d26d4cd
YW
2881 with self.subTest(manage_foreign_routes=manage_foreign_routes):
2882 self._test_route_static(manage_foreign_routes)
2883
297f9d86
YW
2884 @expectedFailureIfRTA_VIAIsNotSupported()
2885 def test_route_via_ipv6(self):
a962d857 2886 copy_network_unit('25-route-via-ipv6.network', '12-dummy.netdev')
297f9d86
YW
2887 start_networkd()
2888 self.wait_online(['dummy98:routable'])
2889
2890 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98', env=env)
2891 print(output)
2892
2893 print('### ip -6 route show dev dummy98')
2894 output = check_output('ip -6 route show dev dummy98')
2895 print(output)
2896 self.assertRegex(output, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
2897 self.assertRegex(output, '2001:1234:5:8f63::1 proto kernel')
2898
2899 print('### ip -4 route show dev dummy98')
2900 output = check_output('ip -4 route show dev dummy98')
2901 print(output)
2902 self.assertRegex(output, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
2903 self.assertRegex(output, '149.10.124.66 via inet6 2001:1234:5:8fff:ff:ff:ff:ff proto static')
2904
93e898d6
YW
2905 @expectedFailureIfModuleIsNotAvailable('tcp_dctcp')
2906 def test_route_congctl(self):
2907 copy_network_unit('25-route-congctl.network', '12-dummy.netdev')
2908 start_networkd()
2909 self.wait_online(['dummy98:routable'])
2910
2911 print('### ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff')
2912 output = check_output('ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff')
2913 print(output)
2914 self.assertIn('2001:1234:5:8fff:ff:ff:ff:ff proto static', output)
2915 self.assertIn('congctl dctcp', output)
2916
2917 print('### ip -4 route show dev dummy98 149.10.124.66')
2918 output = check_output('ip -4 route show dev dummy98 149.10.124.66')
2919 print(output)
2920 self.assertIn('149.10.124.66 proto static', output)
2921 self.assertIn('congctl dctcp', output)
2922
40afe491
YW
2923 @expectedFailureIfModuleIsNotAvailable('vrf')
2924 def test_route_vrf(self):
a962d857
YW
2925 copy_network_unit('25-route-vrf.network', '12-dummy.netdev',
2926 '25-vrf.netdev', '25-vrf.network')
40afe491
YW
2927 start_networkd()
2928 self.wait_online(['dummy98:routable', 'vrf99:carrier'])
2929
2930 output = check_output('ip route show vrf vrf99')
2931 print(output)
2932 self.assertRegex(output, 'default via 192.168.100.1')
2933
2934 output = check_output('ip route show')
2935 print(output)
2936 self.assertNotRegex(output, 'default via 192.168.100.1')
2937
0b1cd3e2 2938 def test_gateway_reconfigure(self):
a962d857 2939 copy_network_unit('25-gateway-static.network', '12-dummy.netdev')
0b1cd3e2
WKI
2940 start_networkd()
2941 self.wait_online(['dummy98:routable'])
2942 print('### ip -4 route show dev dummy98 default')
2943 output = check_output('ip -4 route show dev dummy98 default')
2944 print(output)
a962d857
YW
2945 self.assertIn('default via 149.10.124.59 proto static', output)
2946 self.assertNotIn('149.10.124.60', output)
0b1cd3e2 2947
a962d857
YW
2948 remove_network_unit('25-gateway-static.network')
2949 copy_network_unit('25-gateway-next-static.network')
2950 networkctl_reload()
0b1cd3e2
WKI
2951 self.wait_online(['dummy98:routable'])
2952 print('### ip -4 route show dev dummy98 default')
2953 output = check_output('ip -4 route show dev dummy98 default')
2954 print(output)
a962d857
YW
2955 self.assertNotIn('149.10.124.59', output)
2956 self.assertIn('default via 149.10.124.60 proto static', output)
0b1cd3e2 2957
20ca06a6
DA
2958 def test_ip_route_ipv6_src_route(self):
2959 # a dummy device does not make the addresses go through tentative state, so we
2960 # reuse a bond from an earlier test, which does make the addresses go through
2961 # tentative state, and do our test on that
a962d857 2962 copy_network_unit('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2cf6fdff 2963 start_networkd()
e2aea43f 2964 self.wait_online(['dummy98:enslaved', 'bond199:routable'])
20ca06a6 2965
371810d1 2966 output = check_output('ip -6 route list dev bond199')
20ca06a6 2967 print(output)
7e305278 2968 self.assertIn('abcd::/16 via 2001:1234:56:8f63::1:1 proto static src 2001:1234:56:8f63::2', output)
20ca06a6 2969
e4948bb2
YW
2970 def test_route_preferred_source_with_existing_address(self):
2971 # See issue #28009.
2972 copy_network_unit('25-route-preferred-source.network', '12-dummy.netdev')
2973 start_networkd()
2974
2975 for i in range(3):
2976 if i != 0:
2977 networkctl_reconfigure('dummy98')
2978
2979 self.wait_online(['dummy98:routable'])
2980
2981 output = check_output('ip -6 route list dev dummy98')
2982 print(output)
2983 self.assertIn('abcd::/16 via 2001:1234:56:8f63::1:1 proto static src 2001:1234:56:8f63::1', output)
2984
1f0e3109 2985 def test_ip_link_mac_address(self):
a962d857 2986 copy_network_unit('25-address-link-section.network', '12-dummy.netdev')
2cf6fdff 2987 start_networkd()
e2aea43f 2988 self.wait_online(['dummy98:degraded'])
1f0e3109 2989
371810d1 2990 output = check_output('ip link show dummy98')
1f0e3109 2991 print(output)
45aa0e84 2992 self.assertRegex(output, '00:01:02:aa:bb:cc')
1f0e3109
SS
2993
2994 def test_ip_link_unmanaged(self):
a962d857
YW
2995 copy_network_unit('25-link-section-unmanaged.network', '12-dummy.netdev')
2996 start_networkd()
1f0e3109 2997
19cf3143 2998 self.wait_operstate('dummy98', 'off', setup_state='unmanaged')
1f0e3109
SS
2999
3000 def test_ipv6_address_label(self):
a962d857 3001 copy_network_unit('25-ipv6-address-label-section.network', '12-dummy.netdev')
2cf6fdff 3002 start_networkd()
e2aea43f 3003 self.wait_online(['dummy98:degraded'])
1f0e3109 3004
371810d1 3005 output = check_output('ip addrlabel list')
1f0e3109
SS
3006 print(output)
3007 self.assertRegex(output, '2004:da8:1::/64')
3008
cff0cadc 3009 def test_ipv6_proxy_ndp(self):
a962d857 3010 copy_network_unit('25-ipv6-proxy-ndp.network', '12-dummy.netdev')
cff0cadc
YW
3011 start_networkd()
3012
3013 self.wait_online(['dummy98:routable'])
3014
3015 output = check_output('ip neighbor show proxy dev dummy98')
3016 print(output)
a962d857 3017 for i in range(1, 5):
cff0cadc
YW
3018 self.assertRegex(output, f'2607:5300:203:5215:{i}::1 *proxy')
3019
d86f5c19 3020 def test_neighbor_section(self):
a962d857 3021 copy_network_unit('25-neighbor-section.network', '12-dummy.netdev')
2cf6fdff 3022 start_networkd()
e2aea43f 3023 self.wait_online(['dummy98:degraded'], timeout='40s')
e4a71bf3 3024
d1bdafd2 3025 print('### ip neigh list dev dummy98')
df7f9afa 3026 output = check_output('ip neigh list dev dummy98')
e4a71bf3
WKI
3027 print(output)
3028 self.assertRegex(output, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
094b5479 3029 self.assertRegex(output, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
e4a71bf3 3030
146726b2
YW
3031 # TODO: check json string
3032 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
3033
d1bdafd2 3034 def test_neighbor_reconfigure(self):
a962d857 3035 copy_network_unit('25-neighbor-section.network', '12-dummy.netdev')
d1bdafd2
WKI
3036 start_networkd()
3037 self.wait_online(['dummy98:degraded'], timeout='40s')
3038
3039 print('### ip neigh list dev dummy98')
3040 output = check_output('ip neigh list dev dummy98')
3041 print(output)
3042 self.assertRegex(output, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
3043 self.assertRegex(output, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
3044
a962d857
YW
3045 remove_network_unit('25-neighbor-section.network')
3046 copy_network_unit('25-neighbor-next.network')
3047 networkctl_reload()
d1bdafd2
WKI
3048 self.wait_online(['dummy98:degraded'], timeout='40s')
3049 print('### ip neigh list dev dummy98')
3050 output = check_output('ip neigh list dev dummy98')
3051 print(output)
3052 self.assertNotRegex(output, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
3053 self.assertRegex(output, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT')
3054 self.assertNotRegex(output, '2004:da8:1::1.*PERMANENT')
3055
74761cf3 3056 def test_neighbor_gre(self):
a962d857
YW
3057 copy_network_unit('25-neighbor-ip.network', '25-neighbor-ipv6.network', '25-neighbor-ip-dummy.network',
3058 '12-dummy.netdev', '25-gre-tunnel-remote-any.netdev', '25-ip6gre-tunnel-remote-any.netdev')
74761cf3 3059 start_networkd()
fb2ba330 3060 self.wait_online(['dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable'], timeout='40s')
74761cf3
YW
3061
3062 output = check_output('ip neigh list dev gretun97')
3063 print(output)
3064 self.assertRegex(output, '10.0.0.22 lladdr 10.65.223.239 PERMANENT')
fb2ba330
YW
3065
3066 output = check_output('ip neigh list dev ip6gretun97')
3067 print(output)
3068 self.assertRegex(output, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
74761cf3 3069
146726b2
YW
3070 # TODO: check json string
3071 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
3072
05514ae1 3073 def test_link_local_addressing(self):
a962d857
YW
3074 copy_network_unit('25-link-local-addressing-yes.network', '11-dummy.netdev',
3075 '25-link-local-addressing-no.network', '12-dummy.netdev')
2cf6fdff 3076 start_networkd()
e2aea43f 3077 self.wait_online(['test1:degraded', 'dummy98:carrier'])
05514ae1 3078
371810d1 3079 output = check_output('ip address show dev test1')
05514ae1
YW
3080 print(output)
3081 self.assertRegex(output, 'inet .* scope link')
3082 self.assertRegex(output, 'inet6 .* scope link')
3083
371810d1 3084 output = check_output('ip address show dev dummy98')
05514ae1
YW
3085 print(output)
3086 self.assertNotRegex(output, 'inet6* .* scope link')
3087
f7805a6c
FS
3088 # Documentation/networking/ip-sysctl.txt
3089 #
3090 # addr_gen_mode - INTEGER
3091 # Defines how link-local and autoconf addresses are generated.
3092 #
3093 # 0: generate address based on EUI64 (default)
3094 # 1: do no generate a link-local address, use EUI64 for addresses generated
3095 # from autoconf
3096 # 2: generate stable privacy addresses, using the secret from
3097 # stable_secret (RFC7217)
3098 # 3: generate stable privacy addresses, using a random secret if unset
05514ae1 3099
a962d857
YW
3100 self.check_ipv6_sysctl_attr('test1', 'stable_secret', '0123:4567:89ab:cdef:0123:4567:89ab:cdef')
3101 self.check_ipv6_sysctl_attr('test1', 'addr_gen_mode', '2')
3102 self.check_ipv6_sysctl_attr('dummy98', 'addr_gen_mode', '1')
05514ae1 3103
2becdbcc 3104 def test_link_local_addressing_ipv6ll(self):
a962d857 3105 copy_network_unit('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
7b3770a7
YW
3106 start_networkd()
3107 self.wait_online(['dummy98:degraded'])
3108
2becdbcc 3109 # An IPv6LL address exists by default.
7b3770a7
YW
3110 output = check_output('ip address show dev dummy98')
3111 print(output)
3112 self.assertRegex(output, 'inet6 .* scope link')
3113
a962d857
YW
3114 copy_network_unit('25-link-local-addressing-no.network')
3115 networkctl_reload()
7b3770a7
YW
3116 self.wait_online(['dummy98:carrier'])
3117
2becdbcc 3118 # Check if the IPv6LL address is removed.
7b3770a7
YW
3119 output = check_output('ip address show dev dummy98')
3120 print(output)
2becdbcc
YW
3121 self.assertNotRegex(output, 'inet6 .* scope link')
3122
a962d857
YW
3123 remove_network_unit('25-link-local-addressing-no.network')
3124 networkctl_reload()
2becdbcc
YW
3125 self.wait_online(['dummy98:degraded'])
3126
3127 # Check if a new IPv6LL address is assigned.
3128 output = check_output('ip address show dev dummy98')
3129 print(output)
3130 self.assertRegex(output, 'inet6 .* scope link')
7b3770a7 3131
1f0e3109 3132 def test_sysctl(self):
856a247e
YW
3133 copy_networkd_conf_dropin('25-global-ipv6-privacy-extensions.conf')
3134 copy_network_unit('25-sysctl.network', '12-dummy.netdev', copy_dropins=False)
2cf6fdff 3135 start_networkd()
e2aea43f 3136 self.wait_online(['dummy98:degraded'])
ec38833c 3137
a962d857 3138 self.check_ipv6_sysctl_attr('dummy98', 'forwarding', '1')
856a247e 3139 self.check_ipv6_sysctl_attr('dummy98', 'use_tempaddr', '1')
a962d857
YW
3140 self.check_ipv6_sysctl_attr('dummy98', 'dad_transmits', '3')
3141 self.check_ipv6_sysctl_attr('dummy98', 'hop_limit', '5')
3142 self.check_ipv6_sysctl_attr('dummy98', 'proxy_ndp', '1')
3143 self.check_ipv4_sysctl_attr('dummy98', 'forwarding', '1')
3144 self.check_ipv4_sysctl_attr('dummy98', 'proxy_arp', '1')
3145 self.check_ipv4_sysctl_attr('dummy98', 'accept_local', '1')
1f0e3109 3146
856a247e
YW
3147 copy_network_unit('25-sysctl.network.d/25-ipv6-privacy-extensions.conf')
3148 networkctl_reload()
3149 self.wait_online(['dummy98:degraded'])
3150
3151 self.check_ipv6_sysctl_attr('dummy98', 'use_tempaddr', '2')
3152
4da33154 3153 def test_sysctl_disable_ipv6(self):
a962d857 3154 copy_network_unit('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
4da33154
YW
3155
3156 print('## Disable ipv6')
cefd6b3d
ZJS
3157 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
3158 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
4da33154 3159
2cf6fdff 3160 start_networkd()
e2aea43f 3161 self.wait_online(['dummy98:routable'])
4da33154 3162
371810d1 3163 output = check_output('ip -4 address show dummy98')
4da33154
YW
3164 print(output)
3165 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
371810d1 3166 output = check_output('ip -6 address show dummy98')
4da33154 3167 print(output)
57ad7607
ZJS
3168 self.assertRegex(output, 'inet6 2607:5300:203:3906::/64 scope global')
3169 self.assertRegex(output, 'inet6 .* scope link')
4933b97d
YW
3170 output = check_output('ip -4 route show dev dummy98')
3171 print(output)
3d2c2692 3172 self.assertRegex(output, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
d9005dec 3173 output = check_output('ip -6 route show default')
4933b97d 3174 print(output)
d9005dec
YW
3175 self.assertRegex(output, 'default')
3176 self.assertRegex(output, 'via 2607:5300:203:39ff:ff:ff:ff:ff')
4da33154 3177
a962d857 3178 remove_link('dummy98')
4da33154
YW
3179
3180 print('## Enable ipv6')
cefd6b3d
ZJS
3181 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
3182 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
4da33154 3183
a962d857 3184 restart_networkd()
e2aea43f 3185 self.wait_online(['dummy98:routable'])
4da33154 3186
371810d1 3187 output = check_output('ip -4 address show dummy98')
4da33154
YW
3188 print(output)
3189 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
371810d1 3190 output = check_output('ip -6 address show dummy98')
4da33154 3191 print(output)
4933b97d 3192 self.assertRegex(output, 'inet6 2607:5300:203:3906::/64 scope global')
4da33154 3193 self.assertRegex(output, 'inet6 .* scope link')
4933b97d
YW
3194 output = check_output('ip -4 route show dev dummy98')
3195 print(output)
3d2c2692 3196 self.assertRegex(output, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
d9005dec 3197 output = check_output('ip -6 route show default')
4933b97d 3198 print(output)
d9005dec 3199 self.assertRegex(output, 'via 2607:5300:203:39ff:ff:ff:ff:ff')
4da33154 3200
cd65d067 3201 def test_bind_carrier(self):
a962d857 3202 copy_network_unit('25-bind-carrier.network', '11-dummy.netdev')
2cf6fdff 3203 start_networkd()
cd65d067 3204
3e2f7c46
YW
3205 # no bound interface.
3206 self.wait_operstate('test1', 'off', setup_state='configuring')
371810d1 3207 output = check_output('ip address show test1')
cd65d067 3208 print(output)
3e2f7c46
YW
3209 self.assertNotIn('UP,LOWER_UP', output)
3210 self.assertIn('DOWN', output)
3211 self.assertNotIn('192.168.10', output)
cd65d067 3212
3e2f7c46
YW
3213 # add one bound interface. The interface will be up.
3214 check_output('ip link add dummy98 type dummy')
3215 check_output('ip link set dummy98 up')
3216 self.wait_online(['test1:routable'])
3217 output = check_output('ip address show test1')
3218 print(output)
3219 self.assertIn('UP,LOWER_UP', output)
3220 self.assertIn('inet 192.168.10.30/24 brd 192.168.10.255 scope global test1', output)
3221
3222 # add another bound interface. The interface is still up.
cefd6b3d
ZJS
3223 check_output('ip link add dummy99 type dummy')
3224 check_output('ip link set dummy99 up')
fcd79988 3225 self.wait_operstate('dummy99', 'degraded', setup_state='unmanaged')
371810d1 3226 output = check_output('ip address show test1')
cd65d067 3227 print(output)
3e2f7c46
YW
3228 self.assertIn('UP,LOWER_UP', output)
3229 self.assertIn('inet 192.168.10.30/24 brd 192.168.10.255 scope global test1', output)
cd65d067 3230
3e2f7c46 3231 # remove one of the bound interfaces. The interface is still up
a962d857 3232 remove_link('dummy98')
371810d1 3233 output = check_output('ip address show test1')
cd65d067 3234 print(output)
3e2f7c46
YW
3235 self.assertIn('UP,LOWER_UP', output)
3236 self.assertIn('inet 192.168.10.30/24 brd 192.168.10.255 scope global test1', output)
cd65d067 3237
3e2f7c46 3238 # bring down the remaining bound interface. The interface will be down.
bc942f69 3239 check_output('ip link set dummy99 down')
3e2f7c46
YW
3240 self.wait_operstate('test1', 'off')
3241 self.wait_address_dropped('test1', r'192.168.10', ipv='-4', timeout_sec=10)
371810d1 3242 output = check_output('ip address show test1')
cd65d067 3243 print(output)
3e2f7c46
YW
3244 self.assertNotIn('UP,LOWER_UP', output)
3245 self.assertIn('DOWN', output)
3246 self.assertNotIn('192.168.10', output)
cd65d067 3247
3e2f7c46 3248 # bring up the bound interface. The interface will be up.
bc942f69 3249 check_output('ip link set dummy99 up')
3e2f7c46 3250 self.wait_online(['test1:routable'])
371810d1 3251 output = check_output('ip address show test1')
cd65d067 3252 print(output)
3e2f7c46
YW
3253 self.assertIn('UP,LOWER_UP', output)
3254 self.assertIn('inet 192.168.10.30/24 brd 192.168.10.255 scope global test1', output)
3255
3256 # remove the remaining bound interface. The interface will be down.
3257 remove_link('dummy99')
3258 self.wait_operstate('test1', 'off')
3259 self.wait_address_dropped('test1', r'192.168.10', ipv='-4', timeout_sec=10)
3260 output = check_output('ip address show test1')
3261 print(output)
3262 self.assertNotIn('UP,LOWER_UP', output)
3263 self.assertIn('DOWN', output)
3264 self.assertNotIn('192.168.10', output)
3265
3266 # re-add one bound interface. The interface will be up.
3267 check_output('ip link add dummy98 type dummy')
3268 check_output('ip link set dummy98 up')
3269 self.wait_online(['test1:routable'])
3270 output = check_output('ip address show test1')
3271 print(output)
3272 self.assertIn('UP,LOWER_UP', output)
3273 self.assertIn('inet 192.168.10.30/24 brd 192.168.10.255 scope global test1', output)
cd65d067 3274
a962d857 3275 def _test_activation_policy(self, interface, test):
2236d75d
DS
3276 conffile = '25-activation-policy.network'
3277 if test:
3278 conffile = f'{conffile}.d/{test}.conf'
ee9918ae 3279 if interface == 'vlan99':
a962d857
YW
3280 copy_network_unit('21-vlan.netdev', '21-vlan-test1.network')
3281 copy_network_unit('11-dummy.netdev', conffile, copy_dropins=False)
2236d75d
DS
3282 start_networkd()
3283
3284 always = test.startswith('always')
ebb5036f 3285 initial_up = test != 'manual' and not test.endswith('down') # note: default is up
2236d75d
DS
3286 expect_up = initial_up
3287 next_up = not expect_up
3288
cfbdc438 3289 if test.endswith('down'):
ee9918ae 3290 self.wait_activated(interface)
cfbdc438 3291
2236d75d
DS
3292 for iteration in range(4):
3293 with self.subTest(iteration=iteration, expect_up=expect_up):
3294 operstate = 'routable' if expect_up else 'off'
618da3e7 3295 setup_state = 'configured' if expect_up else ('configuring' if iteration == 0 else None)
ee9918ae 3296 self.wait_operstate(interface, operstate, setup_state=setup_state, setup_timeout=20)
2236d75d
DS
3297
3298 if expect_up:
ee9918ae
YW
3299 self.assertIn('UP', check_output(f'ip link show {interface}'))
3300 self.assertIn('192.168.10.30/24', check_output(f'ip address show {interface}'))
3301 self.assertIn('default via 192.168.10.1', check_output(f'ip route show dev {interface}'))
2236d75d 3302 else:
ee9918ae 3303 self.assertIn('DOWN', check_output(f'ip link show {interface}'))
2236d75d
DS
3304
3305 if next_up:
ee9918ae 3306 check_output(f'ip link set dev {interface} up')
2236d75d 3307 else:
ee9918ae 3308 check_output(f'ip link set dev {interface} down')
2236d75d
DS
3309 expect_up = initial_up if always else next_up
3310 next_up = not next_up
073ad7ed
YW
3311 if always:
3312 time.sleep(1)
2236d75d 3313
2236d75d 3314 def test_activation_policy(self):
a962d857 3315 first = True
ee9918ae 3316 for interface in ['test1', 'vlan99']:
a962d857
YW
3317 for test in ['up', 'always-up', 'manual', 'always-down', 'down', '']:
3318 if first:
3319 first = False
3320 else:
3321 self.tearDown()
3322
3323 print(f'### test_activation_policy(interface={interface}, test={test})')
3324 with self.subTest(interface=interface, test=test):
3325 self._test_activation_policy(interface, test)
2236d75d 3326
61764fe4 3327 def _test_activation_policy_required_for_online(self, policy, required):
61764fe4
DS
3328 conffile = '25-activation-policy.network'
3329 units = ['11-dummy.netdev', '12-dummy.netdev', '12-dummy.network', conffile]
3330 if policy:
3331 units += [f'{conffile}.d/{policy}.conf']
3332 if required:
3333 units += [f'{conffile}.d/required-{required}.conf']
a962d857 3334 copy_network_unit(*units, copy_dropins=False)
61764fe4
DS
3335 start_networkd()
3336
cfbdc438
YW
3337 if policy.endswith('down'):
3338 self.wait_activated('test1')
3339
61764fe4
DS
3340 if policy.endswith('down') or policy == 'manual':
3341 self.wait_operstate('test1', 'off', setup_state='configuring')
3342 else:
3343 self.wait_online(['test1'])
3344
3345 if policy == 'always-down':
3346 # if always-down, required for online is forced to no
3347 expected = False
3348 elif required:
3349 # otherwise if required for online is specified, it should match that
3350 expected = required == 'yes'
3351 elif policy:
3352 # otherwise if only policy specified, required for online defaults to
3353 # true if policy is up, always-up, or bound
3354 expected = policy.endswith('up') or policy == 'bound'
3355 else:
3356 # default is true, if neither are specified
3357 expected = True
3358
3359 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'test1', env=env)
3360 print(output)
3361
3362 yesno = 'yes' if expected else 'no'
3363 self.assertRegex(output, f'Required For Online: {yesno}')
3364
61764fe4 3365 def test_activation_policy_required_for_online(self):
a962d857 3366 first = True
61764fe4
DS
3367 for policy in ['up', 'always-up', 'manual', 'always-down', 'down', 'bound', '']:
3368 for required in ['yes', 'no', '']:
a962d857
YW
3369 if first:
3370 first = False
3371 else:
3372 self.tearDown()
3373
3374 print(f'### test_activation_policy_required_for_online(policy={policy}, required={required})')
61764fe4
DS
3375 with self.subTest(policy=policy, required=required):
3376 self._test_activation_policy_required_for_online(policy, required)
3377
fdcd1ec5 3378 def test_domain(self):
a962d857 3379 copy_network_unit('12-dummy.netdev', '24-search-domain.network')
2cf6fdff 3380 start_networkd()
e2aea43f 3381 self.wait_online(['dummy98:routable'])
fdcd1ec5 3382
fc79e6ff 3383 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98', env=env)
fdcd1ec5
YW
3384 print(output)
3385 self.assertRegex(output, 'Address: 192.168.42.100')
3386 self.assertRegex(output, 'DNS: 192.168.42.1')
3387 self.assertRegex(output, 'Search Domains: one')
3388
1e498853 3389 def test_keep_configuration_static(self):
1e498853
YW
3390 check_output('ip link add name dummy98 type dummy')
3391 check_output('ip address add 10.1.2.3/16 dev dummy98')
3392 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
3393 output = check_output('ip address show dummy98')
3394 print(output)
3395 self.assertRegex(output, 'inet 10.1.2.3/16 scope global dummy98')
3396 self.assertRegex(output, 'inet 10.2.3.4/16 scope global dynamic dummy98')
3397 output = check_output('ip route show dev dummy98')
3398 print(output)
3399
a962d857 3400 copy_network_unit('24-keep-configuration-static.network')
2cf6fdff 3401 start_networkd()
e2aea43f 3402 self.wait_online(['dummy98:routable'])
1e498853
YW
3403
3404 output = check_output('ip address show dummy98')
3405 print(output)
3406 self.assertRegex(output, 'inet 10.1.2.3/16 scope global dummy98')
3407 self.assertNotRegex(output, 'inet 10.2.3.4/16 scope global dynamic dummy98')
3408
086bcf5d
YW
3409 @expectedFailureIfNexthopIsNotAvailable()
3410 def test_nexthop(self):
9c8f90d0
YW
3411 def check_nexthop(self):
3412 self.wait_online(['veth99:routable', 'veth-peer:routable', 'dummy98:routable'])
086bcf5d 3413
9c8f90d0
YW
3414 output = check_output('ip nexthop list dev veth99')
3415 print(output)
3416 self.assertIn('id 1 via 192.168.5.1 dev veth99', output)
3417 self.assertIn('id 2 via 2001:1234:5:8f63::2 dev veth99', output)
3418 self.assertIn('id 3 dev veth99', output)
3419 self.assertIn('id 4 dev veth99', output)
3420 self.assertRegex(output, 'id 5 via 192.168.10.1 dev veth99 .*onlink')
180c5116 3421 self.assertIn('id 8 via fe80:0:222:4dff:ff:ff:ff:ff dev veth99', output)
9c8f90d0
YW
3422 self.assertRegex(output, r'id [0-9]* via 192.168.5.2 dev veth99')
3423
3424 output = check_output('ip nexthop list dev dummy98')
3425 print(output)
3426 self.assertIn('id 20 via 192.168.20.1 dev dummy98', output)
086bcf5d 3427
9c8f90d0
YW
3428 # kernel manages blackhole nexthops on lo
3429 output = check_output('ip nexthop list dev lo')
3430 print(output)
3431 self.assertIn('id 6 blackhole', output)
3432 self.assertIn('id 7 blackhole', output)
69a91c70 3433
9c8f90d0
YW
3434 # group nexthops are shown with -0 option
3435 output = check_output('ip -0 nexthop list id 21')
3436 print(output)
3437 self.assertRegex(output, r'id 21 group (1,3/20|20/1,3)')
cee0f719 3438
9c8f90d0
YW
3439 output = check_output('ip route show dev veth99 10.10.10.10')
3440 print(output)
3441 self.assertEqual('10.10.10.10 nhid 1 via 192.168.5.1 proto static', output)
cee0f719 3442
9c8f90d0
YW
3443 output = check_output('ip route show dev veth99 10.10.10.11')
3444 print(output)
3445 self.assertEqual('10.10.10.11 nhid 2 via inet6 2001:1234:5:8f63::2 proto static', output)
e2d9bc5c 3446
9c8f90d0
YW
3447 output = check_output('ip route show dev veth99 10.10.10.12')
3448 print(output)
3449 self.assertEqual('10.10.10.12 nhid 5 via 192.168.10.1 proto static onlink', output)
cee0f719 3450
9c8f90d0
YW
3451 output = check_output('ip -6 route show dev veth99 2001:1234:5:8f62::1')
3452 print(output)
3453 self.assertEqual('2001:1234:5:8f62::1 nhid 2 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium', output)
69a91c70 3454
9c8f90d0
YW
3455 output = check_output('ip route show 10.10.10.13')
3456 print(output)
3457 self.assertEqual('blackhole 10.10.10.13 nhid 6 dev lo proto static', output)
3458
3459 output = check_output('ip -6 route show 2001:1234:5:8f62::2')
3460 print(output)
3461 self.assertEqual('blackhole 2001:1234:5:8f62::2 nhid 7 dev lo proto static metric 1024 pref medium', output)
3462
3463 output = check_output('ip route show 10.10.10.14')
3464 print(output)
3465 self.assertIn('10.10.10.14 nhid 21 proto static', output)
3466 self.assertIn('nexthop via 192.168.20.1 dev dummy98 weight 1', output)
3467 self.assertIn('nexthop via 192.168.5.1 dev veth99 weight 3', output)
3468
146726b2
YW
3469 # TODO: check json string
3470 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
3471
a962d857
YW
3472 copy_network_unit('25-nexthop.network', '25-veth.netdev', '25-veth-peer.network',
3473 '12-dummy.netdev', '25-nexthop-dummy.network')
9c8f90d0
YW
3474 start_networkd()
3475
3476 check_nexthop(self)
69a91c70 3477
a962d857
YW
3478 remove_network_unit('25-nexthop.network')
3479 copy_network_unit('25-nexthop-nothing.network')
3480 networkctl_reload()
932e157b
YW
3481 self.wait_online(['veth99:routable', 'veth-peer:routable'])
3482
9947c7ba
YW
3483 output = check_output('ip nexthop list dev veth99')
3484 print(output)
3485 self.assertEqual(output, '')
3486 output = check_output('ip nexthop list dev lo')
3487 print(output)
3488 self.assertEqual(output, '')
3489
a962d857
YW
3490 remove_network_unit('25-nexthop-nothing.network')
3491 copy_network_unit('25-nexthop.network')
3492 networkctl_reconfigure('dummy98')
3493 networkctl_reload()
9947c7ba 3494
9c8f90d0 3495 check_nexthop(self)
932e157b 3496
a962d857 3497 remove_link('veth99')
9947c7ba
YW
3498 time.sleep(2)
3499
3500 output = check_output('ip nexthop list dev lo')
3501 print(output)
3502 self.assertEqual(output, '')
3503
23b38192
YW
3504class NetworkdTCTests(unittest.TestCase, Utilities):
3505
3506 def setUp(self):
3507 setup_common()
3508
3509 def tearDown(self):
3510 tear_down_common()
3511
4c7d13f4
YW
3512 @expectedFailureIfModuleIsNotAvailable('sch_cake')
3513 def test_qdisc_cake(self):
3514 copy_network_unit('25-qdisc-cake.network', '12-dummy.netdev')
ef3c8a92 3515 start_networkd()
4c7d13f4 3516 self.wait_online(['dummy98:routable'])
ef3c8a92 3517
4c7d13f4 3518 output = check_output('tc qdisc show dev dummy98')
f1de1eb3 3519 print(output)
4c7d13f4
YW
3520 self.assertIn('qdisc cake 3a: root', output)
3521 self.assertIn('bandwidth 500Mbit', output)
3522 self.assertIn('autorate-ingress', output)
3523 self.assertIn('diffserv8', output)
3524 self.assertIn('dual-dsthost', output)
3525 self.assertIn(' nat', output)
3526 self.assertIn(' wash', output)
3527 self.assertIn(' split-gso', output)
3528 self.assertIn(' raw', output)
3529 self.assertIn(' atm', output)
3530 self.assertIn('overhead 128', output)
3531 self.assertIn('mpu 20', output)
3532 self.assertIn('fwmark 0xff00', output)
77d5f36d
YW
3533 self.assertIn('rtt 1s', output)
3534 self.assertIn('ack-filter-aggressive', output)
4c7d13f4
YW
3535
3536 @expectedFailureIfModuleIsNotAvailable('sch_codel')
3537 def test_qdisc_codel(self):
3538 copy_network_unit('25-qdisc-codel.network', '12-dummy.netdev')
3539 start_networkd()
3540 self.wait_online(['dummy98:routable'])
f1de1eb3 3541
ef3c8a92
YW
3542 output = check_output('tc qdisc show dev dummy98')
3543 print(output)
4c7d13f4
YW
3544 self.assertRegex(output, 'qdisc codel 33: root')
3545 self.assertRegex(output, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn')
f1de1eb3 3546
4c7d13f4
YW
3547 @expectedFailureIfModuleIsNotAvailable('sch_drr')
3548 def test_qdisc_drr(self):
3549 copy_network_unit('25-qdisc-drr.network', '12-dummy.netdev')
3550 start_networkd()
3551 self.wait_online(['dummy98:routable'])
f1de1eb3 3552
4c7d13f4
YW
3553 output = check_output('tc qdisc show dev dummy98')
3554 print(output)
3555 self.assertRegex(output, 'qdisc drr 2: root')
3556 output = check_output('tc class show dev dummy98')
3557 print(output)
3558 self.assertRegex(output, 'class drr 2:30 root quantum 2000b')
ef3c8a92 3559
4c7d13f4
YW
3560 @expectedFailureIfModuleIsNotAvailable('sch_ets')
3561 def test_qdisc_ets(self):
3562 copy_network_unit('25-qdisc-ets.network', '12-dummy.netdev')
3563 start_networkd()
3564 self.wait_online(['dummy98:routable'])
3565
3566 output = check_output('tc qdisc show dev dummy98')
3567 print(output)
3568
3569 self.assertRegex(output, 'qdisc ets 3a: root')
3570 self.assertRegex(output, 'bands 10 strict 3')
3571 self.assertRegex(output, 'quanta 1 2 3 4 5')
3572 self.assertRegex(output, 'priomap 3 4 5 6 7')
3573
3574 @expectedFailureIfModuleIsNotAvailable('sch_fq')
3575 def test_qdisc_fq(self):
3576 copy_network_unit('25-qdisc-fq.network', '12-dummy.netdev')
3577 start_networkd()
3578 self.wait_online(['dummy98:routable'])
0baddbd5 3579
4c7d13f4
YW
3580 output = check_output('tc qdisc show dev dummy98')
3581 print(output)
3582 self.assertRegex(output, 'qdisc fq 32: root')
a05a6e8b
YW
3583 self.assertRegex(output, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
3584 self.assertRegex(output, 'quantum 1500')
3585 self.assertRegex(output, 'initial_quantum 13000')
3586 self.assertRegex(output, 'maxrate 1Mbit')
ab9dc1db 3587
4c7d13f4
YW
3588 @expectedFailureIfModuleIsNotAvailable('sch_fq_codel')
3589 def test_qdisc_fq_codel(self):
3590 copy_network_unit('25-qdisc-fq_codel.network', '12-dummy.netdev')
3591 start_networkd()
3592 self.wait_online(['dummy98:routable'])
ab9dc1db 3593
4c7d13f4
YW
3594 output = check_output('tc qdisc show dev dummy98')
3595 print(output)
3596 self.assertRegex(output, 'qdisc fq_codel 34: root')
7887e580 3597 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')
ab9dc1db 3598
4c7d13f4
YW
3599 @expectedFailureIfModuleIsNotAvailable('sch_fq_pie')
3600 def test_qdisc_fq_pie(self):
3601 copy_network_unit('25-qdisc-fq_pie.network', '12-dummy.netdev')
3602 start_networkd()
3603 self.wait_online(['dummy98:routable'])
ab9dc1db 3604
4c7d13f4
YW
3605 output = check_output('tc qdisc show dev dummy98')
3606 print(output)
3d55b5a9 3607
4c7d13f4
YW
3608 self.assertRegex(output, 'qdisc fq_pie 3a: root')
3609 self.assertRegex(output, 'limit 200000p')
bc0769c9 3610
4c7d13f4
YW
3611 @expectedFailureIfModuleIsNotAvailable('sch_gred')
3612 def test_qdisc_gred(self):
3613 copy_network_unit('25-qdisc-gred.network', '12-dummy.netdev')
3614 start_networkd()
3615 self.wait_online(['dummy98:routable'])
3616
3617 output = check_output('tc qdisc show dev dummy98')
3618 print(output)
3619 self.assertRegex(output, 'qdisc gred 38: root')
95edcf3f
YW
3620 self.assertRegex(output, 'vqs 12 default 10 grio')
3621
4c7d13f4
YW
3622 @expectedFailureIfModuleIsNotAvailable('sch_hhf')
3623 def test_qdisc_hhf(self):
3624 copy_network_unit('25-qdisc-hhf.network', '12-dummy.netdev')
3625 start_networkd()
3626 self.wait_online(['dummy98:routable'])
3627
3628 output = check_output('tc qdisc show dev dummy98')
3629 print(output)
3630 self.assertRegex(output, 'qdisc hhf 3a: root')
3631 self.assertRegex(output, 'limit 1022p')
3632
3633 @expectedFailureIfModuleIsNotAvailable('sch_htb')
3634 def test_qdisc_htb_fifo(self):
3635 copy_network_unit('25-qdisc-htb-fifo.network', '12-dummy.netdev')
3636 start_networkd()
3637 self.wait_online(['dummy98:routable'])
3638
3639 output = check_output('tc qdisc show dev dummy98')
3640 print(output)
3641 self.assertRegex(output, 'qdisc htb 2: root')
3642 self.assertRegex(output, r'default (0x30|30)')
3643
3644 self.assertRegex(output, 'qdisc pfifo 37: parent 2:37')
3645 self.assertRegex(output, 'limit 100000p')
f2c5c129 3646
7b1a31a3
YW
3647 self.assertRegex(output, 'qdisc bfifo 3a: parent 2:3a')
3648 self.assertRegex(output, 'limit 1000000')
3649
73136507
YW
3650 self.assertRegex(output, 'qdisc pfifo_head_drop 3b: parent 2:3b')
3651 self.assertRegex(output, 'limit 1023p')
3652
41bb371b
YW
3653 self.assertRegex(output, 'qdisc pfifo_fast 3c: parent 2:3c')
3654
2ee7e54b 3655 output = check_output('tc -d class show dev dummy98')
ab9dc1db 3656 print(output)
8e2449a5
YW
3657 # Here (:|prio) is a workaround for a bug in iproute2 v6.2.0 caused by
3658 # https://github.com/shemminger/iproute2/commit/010a8388aea11e767ba3a2506728b9ad9760df0e
3659 # which is fixed in v6.3.0 by
3660 # https://github.com/shemminger/iproute2/commit/4e0e56e0ef05387f7f5d8ab41fe6ec6a1897b26d
3661 self.assertRegex(output, 'class htb 2:37 root leaf 37(:|prio) ')
3662 self.assertRegex(output, 'class htb 2:3a root leaf 3a(:|prio) ')
3663 self.assertRegex(output, 'class htb 2:3b root leaf 3b(:|prio) ')
3664 self.assertRegex(output, 'class htb 2:3c root leaf 3c(:|prio) ')
2ee7e54b
YW
3665 self.assertRegex(output, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit')
3666 self.assertRegex(output, 'burst 123456')
3667 self.assertRegex(output, 'cburst 123457')
0baddbd5 3668
4c7d13f4
YW
3669 @expectedFailureIfModuleIsNotAvailable('sch_ingress')
3670 def test_qdisc_ingress(self):
3671 copy_network_unit('25-qdisc-clsact.network', '12-dummy.netdev',
3672 '25-qdisc-ingress.network', '11-dummy.netdev')
557fa421 3673 start_networkd()
891ff963 3674 self.wait_online(['dummy98:routable', 'test1:routable'])
557fa421
YW
3675
3676 output = check_output('tc qdisc show dev dummy98')
3677 print(output)
4c7d13f4 3678 self.assertRegex(output, 'qdisc clsact')
557fa421 3679
891ff963
YW
3680 output = check_output('tc qdisc show dev test1')
3681 print(output)
4c7d13f4 3682 self.assertRegex(output, 'qdisc ingress')
891ff963 3683
4c7d13f4
YW
3684 @expectedFailureIfModuleIsNotAvailable('sch_netem')
3685 def test_qdisc_netem(self):
3686 copy_network_unit('25-qdisc-netem.network', '12-dummy.netdev',
3687 '25-qdisc-netem-compat.network', '11-dummy.netdev')
3d55b5a9 3688 start_networkd()
4c7d13f4 3689 self.wait_online(['dummy98:routable', 'test1:routable'])
3d55b5a9
YW
3690
3691 output = check_output('tc qdisc show dev dummy98')
3692 print(output)
4c7d13f4
YW
3693 self.assertRegex(output, 'qdisc netem 30: root')
3694 self.assertRegex(output, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
3695
3696 output = check_output('tc qdisc show dev test1')
3697 print(output)
3698 self.assertRegex(output, 'qdisc netem [0-9a-f]*: root')
3699 self.assertRegex(output, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
3d55b5a9 3700
854f9899 3701 @expectedFailureIfModuleIsNotAvailable('sch_pie')
be94e591 3702 def test_qdisc_pie(self):
a962d857 3703 copy_network_unit('25-qdisc-pie.network', '12-dummy.netdev')
be94e591
YW
3704 start_networkd()
3705 self.wait_online(['dummy98:routable'])
3706
3707 output = check_output('tc qdisc show dev dummy98')
3708 print(output)
3709 self.assertRegex(output, 'qdisc pie 3a: root')
3710 self.assertRegex(output, 'limit 200000')
3711
4c7d13f4
YW
3712 @expectedFailureIfModuleIsNotAvailable('sch_qfq')
3713 def test_qdisc_qfq(self):
3714 copy_network_unit('25-qdisc-qfq.network', '12-dummy.netdev')
970ab1fc
YW
3715 start_networkd()
3716 self.wait_online(['dummy98:routable'])
3717
3718 output = check_output('tc qdisc show dev dummy98')
3719 print(output)
4c7d13f4
YW
3720 self.assertRegex(output, 'qdisc qfq 2: root')
3721 output = check_output('tc class show dev dummy98')
3722 print(output)
3723 self.assertRegex(output, 'class qfq 2:30 root weight 2 maxpkt 16000')
3724 self.assertRegex(output, 'class qfq 2:31 root weight 10 maxpkt 8000')
970ab1fc 3725
4c7d13f4
YW
3726 @expectedFailureIfModuleIsNotAvailable('sch_sfb')
3727 def test_qdisc_sfb(self):
3728 copy_network_unit('25-qdisc-sfb.network', '12-dummy.netdev')
b753e835
YW
3729 start_networkd()
3730 self.wait_online(['dummy98:routable'])
3731
3732 output = check_output('tc qdisc show dev dummy98')
3733 print(output)
4c7d13f4
YW
3734 self.assertRegex(output, 'qdisc sfb 39: root')
3735 self.assertRegex(output, 'limit 200000')
1578266b 3736
4c7d13f4
YW
3737 @expectedFailureIfModuleIsNotAvailable('sch_sfq')
3738 def test_qdisc_sfq(self):
3739 copy_network_unit('25-qdisc-sfq.network', '12-dummy.netdev')
3740 start_networkd()
3741 self.wait_online(['dummy98:routable'])
b753e835 3742
4c7d13f4
YW
3743 output = check_output('tc qdisc show dev dummy98')
3744 print(output)
3745 self.assertRegex(output, 'qdisc sfq 36: root')
3746 self.assertRegex(output, 'perturb 5sec')
3747
3748 @expectedFailureIfModuleIsNotAvailable('sch_tbf')
3749 def test_qdisc_tbf(self):
3750 copy_network_unit('25-qdisc-tbf.network', '12-dummy.netdev')
1578266b
YW
3751 start_networkd()
3752 self.wait_online(['dummy98:routable'])
3753
3754 output = check_output('tc qdisc show dev dummy98')
3755 print(output)
4c7d13f4
YW
3756 self.assertRegex(output, 'qdisc tbf 35: root')
3757 self.assertRegex(output, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms')
1578266b 3758
4c7d13f4
YW
3759 @expectedFailureIfModuleIsNotAvailable('sch_teql')
3760 def test_qdisc_teql(self):
3761 call_quiet('rmmod sch_teql')
3762
3763 copy_network_unit('25-qdisc-teql.network', '12-dummy.netdev')
3764 start_networkd()
3765 self.wait_links('dummy98')
3766 check_output('modprobe sch_teql max_equalizers=2')
3767 self.wait_online(['dummy98:routable'])
3768
3769 output = check_output('tc qdisc show dev dummy98')
3770 print(output)
3771 self.assertRegex(output, 'qdisc teql1 31: root')
1578266b 3772
336d18f0 3773class NetworkdStateFileTests(unittest.TestCase, Utilities):
336d18f0
YW
3774
3775 def setUp(self):
a962d857 3776 setup_common()
336d18f0
YW
3777
3778 def tearDown(self):
a962d857 3779 tear_down_common()
336d18f0
YW
3780
3781 def test_state_file(self):
a962d857 3782 copy_network_unit('12-dummy.netdev', '25-state-file-tests.network')
336d18f0
YW
3783 start_networkd()
3784 self.wait_online(['dummy98:routable'])
3785
f91b2340
YW
3786 # make link state file updated
3787 check_output(*resolvectl_cmd, 'revert', 'dummy98', env=env)
336d18f0 3788
94f0bd62
YW
3789 # TODO: check json string
3790 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
3791
1a8e1d78
YW
3792 output = read_link_state_file('dummy98')
3793 print(output)
3794 self.assertIn('IPV4_ADDRESS_STATE=routable', output)
3795 self.assertIn('IPV6_ADDRESS_STATE=routable', output)
3796 self.assertIn('ADMIN_STATE=configured', output)
3797 self.assertIn('OPER_STATE=routable', output)
3798 self.assertIn('REQUIRED_FOR_ONLINE=yes', output)
3799 self.assertIn('REQUIRED_OPER_STATE_FOR_ONLINE=routable', output)
3800 self.assertIn('REQUIRED_FAMILY_FOR_ONLINE=both', output)
3801 self.assertIn('ACTIVATION_POLICY=up', output)
3802 self.assertIn('NETWORK_FILE=/run/systemd/network/25-state-file-tests.network', output)
3803 self.assertIn('DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com', output)
3804 self.assertIn('NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org', output)
3805 self.assertIn('DOMAINS=hogehoge', output)
3806 self.assertIn('ROUTE_DOMAINS=foofoo', output)
3807 self.assertIn('LLMNR=no', output)
3808 self.assertIn('MDNS=yes', output)
3809 self.assertIn('DNSSEC=no', output)
336d18f0 3810
66479677 3811 check_output(*resolvectl_cmd, 'dns', 'dummy98', '10.10.10.12#ccc.com', '10.10.10.13', '1111:2222::3333', env=env)
336d18f0
YW
3812 check_output(*resolvectl_cmd, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env=env)
3813 check_output(*resolvectl_cmd, 'llmnr', 'dummy98', 'yes', env=env)
3814 check_output(*resolvectl_cmd, 'mdns', 'dummy98', 'no', env=env)
3815 check_output(*resolvectl_cmd, 'dnssec', 'dummy98', 'yes', env=env)
3816 check_output(*timedatectl_cmd, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env=env)
336d18f0 3817
94f0bd62
YW
3818 # TODO: check json string
3819 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
3820
1a8e1d78
YW
3821 output = read_link_state_file('dummy98')
3822 print(output)
3823 self.assertIn('DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333', output)
3824 self.assertIn('NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org', output)
3825 self.assertIn('DOMAINS=hogehogehoge', output)
3826 self.assertIn('ROUTE_DOMAINS=foofoofoo', output)
3827 self.assertIn('LLMNR=yes', output)
3828 self.assertIn('MDNS=no', output)
3829 self.assertIn('DNSSEC=yes', output)
336d18f0
YW
3830
3831 check_output(*timedatectl_cmd, 'revert', 'dummy98', env=env)
336d18f0 3832
94f0bd62
YW
3833 # TODO: check json string
3834 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
3835
1a8e1d78
YW
3836 output = read_link_state_file('dummy98')
3837 print(output)
3838 self.assertIn('DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333', output)
3839 self.assertIn('NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org', output)
3840 self.assertIn('DOMAINS=hogehogehoge', output)
3841 self.assertIn('ROUTE_DOMAINS=foofoofoo', output)
3842 self.assertIn('LLMNR=yes', output)
3843 self.assertIn('MDNS=no', output)
3844 self.assertIn('DNSSEC=yes', output)
336d18f0
YW
3845
3846 check_output(*resolvectl_cmd, 'revert', 'dummy98', env=env)
336d18f0 3847
94f0bd62
YW
3848 # TODO: check json string
3849 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
3850
1a8e1d78
YW
3851 output = read_link_state_file('dummy98')
3852 print(output)
3853 self.assertIn('DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com', output)
3854 self.assertIn('NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org', output)
3855 self.assertIn('DOMAINS=hogehoge', output)
3856 self.assertIn('ROUTE_DOMAINS=foofoo', output)
3857 self.assertIn('LLMNR=no', output)
3858 self.assertIn('MDNS=yes', output)
3859 self.assertIn('DNSSEC=no', output)
336d18f0 3860
ee3cbfdb
YW
3861 def test_address_state(self):
3862 copy_network_unit('12-dummy.netdev', '12-dummy-no-address.network')
3863 start_networkd()
3864
3865 self.wait_online(['dummy98:degraded'])
3866
3867 output = read_link_state_file('dummy98')
3868 self.assertIn('IPV4_ADDRESS_STATE=off', output)
3869 self.assertIn('IPV6_ADDRESS_STATE=degraded', output)
3870
3871 # with a routable IPv4 address
3872 check_output('ip address add 10.1.2.3/16 dev dummy98')
3873 self.wait_online(['dummy98:routable'], ipv4=True)
3874 self.wait_online(['dummy98:routable'])
3875
3876 output = read_link_state_file('dummy98')
3877 self.assertIn('IPV4_ADDRESS_STATE=routable', output)
3878 self.assertIn('IPV6_ADDRESS_STATE=degraded', output)
3879
3880 check_output('ip address del 10.1.2.3/16 dev dummy98')
3881
3882 # with a routable IPv6 address
3883 check_output('ip address add 2002:da8:1:0:1034:56ff:fe78:9abc/64 dev dummy98')
3884 self.wait_online(['dummy98:routable'], ipv6=True)
3885 self.wait_online(['dummy98:routable'])
3886
3887 output = read_link_state_file('dummy98')
3888 self.assertIn('IPV4_ADDRESS_STATE=off', output)
3889 self.assertIn('IPV6_ADDRESS_STATE=routable', output)
3890
be68c2c9 3891class NetworkdBondTests(unittest.TestCase, Utilities):
c3a8853f
YW
3892
3893 def setUp(self):
a962d857 3894 setup_common()
c3a8853f
YW
3895
3896 def tearDown(self):
a962d857 3897 tear_down_common()
c3a8853f 3898
b06469a6
YW
3899 def test_bond_keep_master(self):
3900 check_output('ip link add bond199 type bond mode active-backup')
3901 check_output('ip link add dummy98 type dummy')
3902 check_output('ip link set dummy98 master bond199')
3903
a962d857 3904 copy_network_unit('23-keep-master.network')
b06469a6
YW
3905 start_networkd()
3906 self.wait_online(['dummy98:enslaved'])
3907
3908 output = check_output('ip -d link show bond199')
3909 print(output)
3910 self.assertRegex(output, 'active_slave dummy98')
3911
3912 output = check_output('ip -d link show dummy98')
3913 print(output)
3914 self.assertRegex(output, 'master bond199')
3915
c2990ec3 3916 def test_bond_active_slave(self):
a962d857 3917 copy_network_unit('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2cf6fdff 3918 start_networkd()
e2aea43f 3919 self.wait_online(['dummy98:enslaved', 'bond199:degraded'])
c2990ec3 3920
371810d1 3921 output = check_output('ip -d link show bond199')
c2990ec3 3922 print(output)
b448fc0a 3923 self.assertIn('active_slave dummy98', output)
c2990ec3
YW
3924
3925 def test_bond_primary_slave(self):
a962d857 3926 copy_network_unit('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2cf6fdff 3927 start_networkd()
e2aea43f 3928 self.wait_online(['dummy98:enslaved', 'bond199:degraded'])
c2990ec3 3929
371810d1 3930 output = check_output('ip -d link show bond199')
c2990ec3 3931 print(output)
b448fc0a
YW
3932 self.assertIn('primary dummy98', output)
3933
3934 # for issue #25627
3935 mkdir_p(os.path.join(network_unit_dir, '23-bond199.network.d'))
3936 for mac in ['00:11:22:33:44:55', '00:11:22:33:44:56']:
3937 with open(os.path.join(network_unit_dir, '23-bond199.network.d/mac.conf'), mode='w', encoding='utf-8') as f:
3938 f.write(f'[Link]\nMACAddress={mac}\n')
3939
3940 networkctl_reload()
3941 self.wait_online(['dummy98:enslaved', 'bond199:degraded'])
3942
3943 output = check_output('ip -d link show bond199')
3944 print(output)
3945 self.assertIn(f'link/ether {mac}', output)
c2990ec3 3946
cc3e488c 3947 def test_bond_operstate(self):
a962d857
YW
3948 copy_network_unit('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
3949 '25-bond99.network', '25-bond-slave.network')
2cf6fdff 3950 start_networkd()
e2aea43f 3951 self.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
c3a8853f 3952
371810d1 3953 output = check_output('ip -d link show dummy98')
c3a8853f 3954 print(output)
cc3e488c 3955 self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
c3a8853f 3956
371810d1 3957 output = check_output('ip -d link show test1')
c3a8853f
YW
3958 print(output)
3959 self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
3960
371810d1 3961 output = check_output('ip -d link show bond99')
c3a8853f
YW
3962 print(output)
3963 self.assertRegex(output, 'MASTER,UP,LOWER_UP')
3964
19cf3143
DS
3965 self.wait_operstate('dummy98', 'enslaved')
3966 self.wait_operstate('test1', 'enslaved')
3967 self.wait_operstate('bond99', 'routable')
c3a8853f 3968
cefd6b3d 3969 check_output('ip link set dummy98 down')
c3a8853f 3970
19cf3143
DS
3971 self.wait_operstate('dummy98', 'off')
3972 self.wait_operstate('test1', 'enslaved')
cf4dbd84 3973 self.wait_operstate('bond99', 'routable')
c3a8853f 3974
cefd6b3d 3975 check_output('ip link set dummy98 up')
c3a8853f 3976
19cf3143
DS
3977 self.wait_operstate('dummy98', 'enslaved')
3978 self.wait_operstate('test1', 'enslaved')
3979 self.wait_operstate('bond99', 'routable')
c3a8853f 3980
cefd6b3d
ZJS
3981 check_output('ip link set dummy98 down')
3982 check_output('ip link set test1 down')
cc3e488c 3983
19cf3143
DS
3984 self.wait_operstate('dummy98', 'off')
3985 self.wait_operstate('test1', 'off')
2700d2c7 3986
a4632dc7 3987 if not self.wait_operstate('bond99', 'no-carrier', setup_timeout=30, fail_assert=False):
2700d2c7
YW
3988 # Huh? Kernel does not recognize that all slave interfaces are down?
3989 # Let's confirm that networkd's operstate is consistent with ip's result.
3990 self.assertNotRegex(output, 'NO-CARRIER')
cc3e488c 3991
be68c2c9 3992class NetworkdBridgeTests(unittest.TestCase, Utilities):
8d17c386 3993
1f0e3109 3994 def setUp(self):
a962d857 3995 setup_common()
1f0e3109
SS
3996
3997 def tearDown(self):
a962d857 3998 tear_down_common()
1f0e3109 3999
6f943798 4000 def test_bridge_vlan(self):
a962d857
YW
4001 copy_network_unit('11-dummy.netdev', '26-bridge-vlan-slave.network',
4002 '26-bridge.netdev', '26-bridge-vlan-master.network')
6f943798 4003 start_networkd()
e2aea43f 4004 self.wait_online(['test1:enslaved', 'bridge99:degraded'])
6f943798
YW
4005
4006 output = check_output('bridge vlan show dev test1')
4007 print(output)
4008 self.assertNotRegex(output, '4063')
4009 for i in range(4064, 4095):
4010 self.assertRegex(output, f'{i}')
4011 self.assertNotRegex(output, '4095')
4012
4013 output = check_output('bridge vlan show dev bridge99')
4014 print(output)
4015 self.assertNotRegex(output, '4059')
4016 for i in range(4060, 4095):
4017 self.assertRegex(output, f'{i}')
4018 self.assertNotRegex(output, '4095')
4019
988b0660 4020 def test_bridge_vlan_issue_20373(self):
a962d857
YW
4021 copy_network_unit('11-dummy.netdev', '26-bridge-vlan-slave-issue-20373.network',
4022 '26-bridge-issue-20373.netdev', '26-bridge-vlan-master-issue-20373.network',
4023 '21-vlan.netdev', '21-vlan.network')
988b0660
YW
4024 start_networkd()
4025 self.wait_online(['test1:enslaved', 'bridge99:degraded', 'vlan99:routable'])
4026
4027 output = check_output('bridge vlan show dev test1')
4028 print(output)
4029 self.assertIn('100 PVID Egress Untagged', output)
4030 self.assertIn('560', output)
4031 self.assertIn('600', output)
4032
4033 output = check_output('bridge vlan show dev bridge99')
4034 print(output)
4035 self.assertIn('1 PVID Egress Untagged', output)
4036 self.assertIn('100', output)
4037 self.assertIn('600', output)
4038
cc0276cc 4039 def test_bridge_mdb(self):
a962d857
YW
4040 copy_network_unit('11-dummy.netdev', '26-bridge-mdb-slave.network',
4041 '26-bridge.netdev', '26-bridge-mdb-master.network')
cc0276cc
YW
4042 start_networkd()
4043 self.wait_online(['test1:enslaved', 'bridge99:degraded'])
4044
4045 output = check_output('bridge mdb show dev bridge99')
4046 print(output)
4047 self.assertRegex(output, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064')
4048 self.assertRegex(output, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065')
4049
9f773037 4050 # Old kernel may not support bridge MDB entries on bridge master
a962d857 4051 if call_quiet('bridge mdb add dev bridge99 port bridge99 grp 224.0.1.3 temp vid 4068') == 0:
9f773037
YW
4052 self.assertRegex(output, 'dev bridge99 port bridge99 grp ff02:aaaa:fee5::1:4 temp *vid 4066')
4053 self.assertRegex(output, 'dev bridge99 port bridge99 grp 224.0.1.2 temp *vid 4067')
4054
b06469a6
YW
4055 def test_bridge_keep_master(self):
4056 check_output('ip link add bridge99 type bridge')
4057 check_output('ip link set bridge99 up')
4058 check_output('ip link add dummy98 type dummy')
4059 check_output('ip link set dummy98 master bridge99')
4060
a962d857 4061 copy_network_unit('23-keep-master.network')
b06469a6
YW
4062 start_networkd()
4063 self.wait_online(['dummy98:enslaved'])
4064
4065 output = check_output('ip -d link show dummy98')
4066 print(output)
4067 self.assertRegex(output, 'master bridge99')
4068 self.assertRegex(output, 'bridge')
4069
4070 output = check_output('bridge -d link show dummy98')
4071 print(output)
a962d857
YW
4072 self.check_bridge_port_attr('bridge99', 'dummy98', 'path_cost', '400')
4073 self.check_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode', '1')
4074 self.check_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave', '1')
4075 self.check_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood', '1')
4076 self.check_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood', '0')
b06469a6 4077 # CONFIG_BRIDGE_IGMP_SNOOPING=y
a962d857
YW
4078 self.check_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast', '1', allow_enoent=True)
4079 self.check_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress', '1', allow_enoent=True)
4080 self.check_bridge_port_attr('bridge99', 'dummy98', 'learning', '0')
4081 self.check_bridge_port_attr('bridge99', 'dummy98', 'priority', '23')
3f504b89
YW
4082 self.check_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard', '0')
4083 self.check_bridge_port_attr('bridge99', 'dummy98', 'root_block', '0')
b06469a6 4084
1f0e3109 4085 def test_bridge_property(self):
a962d857
YW
4086 copy_network_unit('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
4087 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
4088 '25-bridge99.network')
2cf6fdff 4089 start_networkd()
e2aea43f 4090 self.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
1f0e3109 4091
21d0ed68
YW
4092 output = check_output('ip -d link show bridge99')
4093 print(output)
4094 self.assertIn('mtu 9000 ', output)
4095
371810d1 4096 output = check_output('ip -d link show test1')
1f0e3109 4097 print(output)
21d0ed68
YW
4098 self.assertIn('master bridge99 ', output)
4099 self.assertIn('bridge_slave', output)
4100 self.assertIn('mtu 9000 ', output)
1f0e3109 4101
371810d1 4102 output = check_output('ip -d link show dummy98')
1f0e3109 4103 print(output)
21d0ed68
YW
4104 self.assertIn('master bridge99 ', output)
4105 self.assertIn('bridge_slave', output)
4106 self.assertIn('mtu 9000 ', output)
1f0e3109 4107
371810d1 4108 output = check_output('ip addr show bridge99')
1f0e3109 4109 print(output)
21d0ed68 4110 self.assertIn('192.168.0.15/24', output)
1f0e3109 4111
371810d1 4112 output = check_output('bridge -d link show dummy98')
1f0e3109 4113 print(output)
a962d857
YW
4114 self.check_bridge_port_attr('bridge99', 'dummy98', 'path_cost', '400')
4115 self.check_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode', '1')
4116 self.check_bridge_port_attr('bridge99', 'dummy98', 'isolated', '1')
4117 self.check_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave', '1')
4118 self.check_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood', '1')
4119 self.check_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood', '0')
5424fd95 4120 # CONFIG_BRIDGE_IGMP_SNOOPING=y
a962d857
YW
4121 self.check_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast', '1', allow_enoent=True)
4122 self.check_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress', '1', allow_enoent=True)
4123 self.check_bridge_port_attr('bridge99', 'dummy98', 'learning', '0')
4124 self.check_bridge_port_attr('bridge99', 'dummy98', 'priority', '23')
3f504b89
YW
4125 self.check_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard', '0')
4126 self.check_bridge_port_attr('bridge99', 'dummy98', 'root_block', '0')
4d7ed14f 4127
5424fd95
YW
4128 output = check_output('bridge -d link show test1')
4129 print(output)
a962d857 4130 self.check_bridge_port_attr('bridge99', 'test1', 'priority', '0')
1f0e3109 4131
371810d1 4132 check_output('ip address add 192.168.0.16/24 dev bridge99')
371810d1 4133 output = check_output('ip addr show bridge99')
2be6c5d2 4134 print(output)
21d0ed68 4135 self.assertIn('192.168.0.16/24', output)
2be6c5d2 4136
e3cbaeab
YW
4137 # for issue #6088
4138 print('### ip -6 route list table all dev bridge99')
4139 output = check_output('ip -6 route list table all dev bridge99')
4140 print(output)
beb75dd3 4141 self.assertRegex(output, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
e3cbaeab 4142
a962d857 4143 remove_link('test1')
cf4dbd84 4144 self.wait_operstate('bridge99', 'routable')
2be6c5d2 4145
21d0ed68
YW
4146 output = check_output('ip -d link show bridge99')
4147 print(output)
4148 self.assertIn('mtu 9000 ', output)
4149
4150 output = check_output('ip -d link show dummy98')
4151 print(output)
4152 self.assertIn('master bridge99 ', output)
4153 self.assertIn('bridge_slave', output)
4154 self.assertIn('mtu 9000 ', output)
804b6cd2 4155
21d0ed68 4156 remove_link('dummy98')
19cf3143 4157 self.wait_operstate('bridge99', 'no-carrier')
2be6c5d2 4158
21d0ed68
YW
4159 output = check_output('ip -d link show bridge99')
4160 print(output)
4161 # When no carrier, the kernel may reset the MTU
4162 self.assertIn('NO-CARRIER', output)
4163
371810d1 4164 output = check_output('ip address show bridge99')
804b6cd2 4165 print(output)
21d0ed68
YW
4166 self.assertNotIn('192.168.0.15/24', output)
4167 self.assertIn('192.168.0.16/24', output) # foreign address is kept
804b6cd2 4168
e3cbaeab
YW
4169 print('### ip -6 route list table all dev bridge99')
4170 output = check_output('ip -6 route list table all dev bridge99')
4171 print(output)
beb75dd3 4172 self.assertRegex(output, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
e3cbaeab 4173
21d0ed68
YW
4174 check_output('ip link add dummy98 type dummy')
4175 self.wait_online(['dummy98:enslaved', 'bridge99:routable'])
4176
4177 output = check_output('ip -d link show bridge99')
4178 print(output)
4179 self.assertIn('mtu 9000 ', output)
4180
4181 output = check_output('ip -d link show dummy98')
4182 print(output)
4183 self.assertIn('master bridge99 ', output)
4184 self.assertIn('bridge_slave', output)
4185 self.assertIn('mtu 9000 ', output)
4186
0fc0d85f 4187 def test_bridge_configure_without_carrier(self):
a962d857
YW
4188 copy_network_unit('26-bridge.netdev', '26-bridge-configure-without-carrier.network',
4189 '11-dummy.netdev')
0fc0d85f
DS
4190 start_networkd()
4191
4192 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
4193 for test in ['no-slave', 'add-slave', 'slave-up', 'slave-no-carrier', 'slave-carrier', 'slave-down']:
4194 with self.subTest(test=test):
4195 if test == 'no-slave':
4196 # bridge has no slaves; it's up but *might* not have carrier
001c07cf 4197 self.wait_operstate('bridge99', operstate=r'(no-carrier|routable)', setup_state=None, setup_timeout=30)
0fc0d85f
DS
4198 # due to a bug in the kernel, newly-created bridges are brought up
4199 # *with* carrier, unless they have had any setting changed; e.g.
4200 # their mac set, priority set, etc. Then, they will lose carrier
4201 # as soon as a (down) slave interface is added, and regain carrier
4202 # again once the slave interface is brought up.
4203 #self.check_link_attr('bridge99', 'carrier', '0')
4204 elif test == 'add-slave':
4205 # add slave to bridge, but leave it down; bridge is definitely no-carrier
4206 self.check_link_attr('test1', 'operstate', 'down')
4207 check_output('ip link set dev test1 master bridge99')
001c07cf 4208 self.wait_operstate('bridge99', operstate='no-carrier', setup_state=None)
0fc0d85f
DS
4209 self.check_link_attr('bridge99', 'carrier', '0')
4210 elif test == 'slave-up':
4211 # bring up slave, which will have carrier; bridge gains carrier
4212 check_output('ip link set dev test1 up')
4213 self.wait_online(['bridge99:routable'])
4214 self.check_link_attr('bridge99', 'carrier', '1')
4215 elif test == 'slave-no-carrier':
4216 # drop slave carrier; bridge loses carrier
4217 check_output('ip link set dev test1 carrier off')
4218 self.wait_online(['bridge99:no-carrier:no-carrier'])
4219 self.check_link_attr('bridge99', 'carrier', '0')
4220 elif test == 'slave-carrier':
4221 # restore slave carrier; bridge gains carrier
4222 check_output('ip link set dev test1 carrier on')
4223 self.wait_online(['bridge99:routable'])
4224 self.check_link_attr('bridge99', 'carrier', '1')
4225 elif test == 'slave-down':
4226 # bring down slave; bridge loses carrier
4227 check_output('ip link set dev test1 down')
4228 self.wait_online(['bridge99:no-carrier:no-carrier'])
4229 self.check_link_attr('bridge99', 'carrier', '0')
4230
4231 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'bridge99', env=env)
0fc0d85f
DS
4232 self.assertRegex(output, '10.1.2.3')
4233 self.assertRegex(output, '10.1.2.1')
4234
804b6cd2 4235 def test_bridge_ignore_carrier_loss(self):
a962d857
YW
4236 copy_network_unit('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
4237 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
4238 '25-bridge99-ignore-carrier-loss.network')
2cf6fdff 4239 start_networkd()
e2aea43f 4240 self.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
804b6cd2 4241
371810d1 4242 check_output('ip address add 192.168.0.16/24 dev bridge99')
a962d857 4243 remove_link('test1', 'dummy98')
804b6cd2
YW
4244 time.sleep(3)
4245
371810d1 4246 output = check_output('ip address show bridge99')
804b6cd2
YW
4247 print(output)
4248 self.assertRegex(output, 'NO-CARRIER')
4249 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
4250 self.assertRegex(output, 'inet 192.168.0.16/24 scope global secondary bridge99')
4251
6609924c 4252 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self):
a962d857
YW
4253 copy_network_unit('26-bridge.netdev', '26-bridge-slave-interface-1.network',
4254 '25-bridge99-ignore-carrier-loss.network')
2cf6fdff 4255 start_networkd()
e2aea43f 4256 self.wait_online(['bridge99:no-carrier'])
6609924c 4257
90e3bcbd
YW
4258 for trial in range(4):
4259 check_output('ip link add dummy98 type dummy')
4260 check_output('ip link set dummy98 up')
4261 if trial < 3:
a962d857 4262 remove_link('dummy98')
6609924c 4263
e2aea43f 4264 self.wait_online(['bridge99:routable', 'dummy98:enslaved'])
6609924c 4265
371810d1 4266 output = check_output('ip address show bridge99')
6609924c
YW
4267 print(output)
4268 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
4269
371810d1 4270 output = check_output('ip rule list table 100')
6609924c 4271 print(output)
c4f7a347 4272 self.assertIn('from all to 8.8.8.8 lookup 100', output)
6609924c 4273
a03ff4c0 4274class NetworkdSRIOVTests(unittest.TestCase, Utilities):
a03ff4c0
YW
4275
4276 def setUp(self):
a962d857 4277 setup_common()
a03ff4c0
YW
4278
4279 def tearDown(self):
a962d857 4280 tear_down_common()
a03ff4c0
YW
4281
4282 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable()
4283 def test_sriov(self):
d8746f16
YW
4284 copy_network_unit('25-default.link', '25-sriov.network')
4285
a962d857 4286 call('modprobe netdevsim')
a03ff4c0 4287
d45476ef 4288 with open('/sys/bus/netdevsim/new_device', mode='w', encoding='utf-8') as f:
a03ff4c0
YW
4289 f.write('99 1')
4290
a962d857 4291 with open('/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs', mode='w', encoding='utf-8') as f:
a03ff4c0
YW
4292 f.write('3')
4293
a03ff4c0
YW
4294 start_networkd()
4295 self.wait_online(['eni99np1:routable'])
4296
4297 output = check_output('ip link show dev eni99np1')
4298 print(output)
4299 self.assertRegex(output,
4300 '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 *'
4301 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
4302 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
a962d857 4303 )
a03ff4c0 4304
1e8e9730
YW
4305 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable()
4306 def test_sriov_udev(self):
a962d857 4307 copy_network_unit('25-sriov.link', '25-sriov-udev.network')
1e8e9730 4308
a962d857
YW
4309 call('modprobe netdevsim')
4310
d45476ef 4311 with open('/sys/bus/netdevsim/new_device', mode='w', encoding='utf-8') as f:
1e8e9730
YW
4312 f.write('99 1')
4313
4314 start_networkd()
4315 self.wait_online(['eni99np1:routable'])
4316
b95d35b5
YW
4317 # the name eni99np1 may be an alternative name.
4318 ifname = link_resolve('eni99np1')
4319
1e8e9730
YW
4320 output = check_output('ip link show dev eni99np1')
4321 print(output)
4322 self.assertRegex(output,
4323 '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 *'
4324 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
4325 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
a962d857 4326 )
1e8e9730
YW
4327 self.assertNotIn('vf 3', output)
4328 self.assertNotIn('vf 4', output)
4329
a962d857 4330 with open(os.path.join(network_unit_dir, '25-sriov.link'), mode='a', encoding='utf-8') as f:
1e8e9730
YW
4331 f.write('[Link]\nSR-IOVVirtualFunctions=4\n')
4332
32ab27af 4333 udev_reload()
b95d35b5 4334 check_output(*udevadm_cmd, 'trigger', '--action=add', '--settle', f'/sys/devices/netdevsim99/net/{ifname}')
1e8e9730
YW
4335
4336 output = check_output('ip link show dev eni99np1')
4337 print(output)
4338 self.assertRegex(output,
4339 '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 *'
4340 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
4341 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off\n *'
4342 'vf 3'
a962d857 4343 )
1e8e9730
YW
4344 self.assertNotIn('vf 4', output)
4345
a962d857 4346 with open(os.path.join(network_unit_dir, '25-sriov.link'), mode='a', encoding='utf-8') as f:
1e8e9730
YW
4347 f.write('[Link]\nSR-IOVVirtualFunctions=\n')
4348
32ab27af 4349 udev_reload()
b95d35b5 4350 check_output(*udevadm_cmd, 'trigger', '--action=add', '--settle', f'/sys/devices/netdevsim99/net/{ifname}')
1e8e9730
YW
4351
4352 output = check_output('ip link show dev eni99np1')
4353 print(output)
4354 self.assertRegex(output,
4355 '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 *'
4356 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
4357 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off\n *'
4358 'vf 3'
a962d857 4359 )
1e8e9730
YW
4360 self.assertNotIn('vf 4', output)
4361
a962d857 4362 with open(os.path.join(network_unit_dir, '25-sriov.link'), mode='a', encoding='utf-8') as f:
1e8e9730
YW
4363 f.write('[Link]\nSR-IOVVirtualFunctions=2\n')
4364
32ab27af 4365 udev_reload()
b95d35b5 4366 check_output(*udevadm_cmd, 'trigger', '--action=add', '--settle', f'/sys/devices/netdevsim99/net/{ifname}')
1e8e9730
YW
4367
4368 output = check_output('ip link show dev eni99np1')
4369 print(output)
4370 self.assertRegex(output,
4371 '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 *'
4372 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off'
a962d857 4373 )
1e8e9730
YW
4374 self.assertNotIn('vf 2', output)
4375 self.assertNotIn('vf 3', output)
4376 self.assertNotIn('vf 4', output)
4377
a962d857 4378 with open(os.path.join(network_unit_dir, '25-sriov.link'), mode='a', encoding='utf-8') as f:
1e8e9730
YW
4379 f.write('[Link]\nSR-IOVVirtualFunctions=\n')
4380
32ab27af 4381 udev_reload()
b95d35b5 4382 check_output(*udevadm_cmd, 'trigger', '--action=add', '--settle', f'/sys/devices/netdevsim99/net/{ifname}')
1e8e9730
YW
4383
4384 output = check_output('ip link show dev eni99np1')
4385 print(output)
4386 self.assertRegex(output,
4387 '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 *'
4388 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
4389 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
a962d857 4390 )
1e8e9730
YW
4391 self.assertNotIn('vf 3', output)
4392 self.assertNotIn('vf 4', output)
4393
be68c2c9 4394class NetworkdLLDPTests(unittest.TestCase, Utilities):
1f0e3109
SS
4395
4396 def setUp(self):
a962d857 4397 setup_common()
1f0e3109
SS
4398
4399 def tearDown(self):
a962d857 4400 tear_down_common()
1f0e3109
SS
4401
4402 def test_lldp(self):
a962d857 4403 copy_network_unit('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
2cf6fdff 4404 start_networkd()
e2aea43f 4405 self.wait_online(['veth99:degraded', 'veth-peer:degraded'])
1f0e3109 4406
f0d87798
YW
4407 for trial in range(10):
4408 if trial > 0:
4409 time.sleep(1)
4410
4411 output = check_output(*networkctl_cmd, 'lldp', env=env)
4412 print(output)
4413 if re.search(r'veth99 .* veth-peer', output):
4414 break
4415 else:
4416 self.fail()
1f0e3109 4417
be68c2c9 4418class NetworkdRATests(unittest.TestCase, Utilities):
1f0e3109
SS
4419
4420 def setUp(self):
a962d857 4421 setup_common()
1f0e3109
SS
4422
4423 def tearDown(self):
a962d857 4424 tear_down_common()
1f0e3109
SS
4425
4426 def test_ipv6_prefix_delegation(self):
a962d857 4427 copy_network_unit('25-veth.netdev', '25-ipv6-prefix.network', '25-ipv6-prefix-veth.network')
2cf6fdff 4428 start_networkd()
e2aea43f 4429 self.wait_online(['veth99:routable', 'veth-peer:degraded'])
1f0e3109 4430
41fd8fe7
YW
4431 output = check_output(*resolvectl_cmd, 'dns', 'veth99', env=env)
4432 print(output)
4433 self.assertRegex(output, 'fe80::')
4434 self.assertRegex(output, '2002:da8:1::1')
4435
80762ccc
YW
4436 output = check_output(*resolvectl_cmd, 'domain', 'veth99', env=env)
4437 print(output)
4438 self.assertIn('hogehoge.test', output)
4439
fc79e6ff 4440 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
1f0e3109
SS
4441 print(output)
4442 self.assertRegex(output, '2002:da8:1:0')
4443
a4640bed
TM
4444 self.check_netlabel('veth99', '2002:da8:1::/64')
4445 self.check_netlabel('veth99', '2002:da8:2::/64')
4446
e2c4070e 4447 def test_ipv6_token_static(self):
a962d857 4448 copy_network_unit('25-veth.netdev', '25-ipv6-prefix.network', '25-ipv6-prefix-veth-token-static.network')
87bbebea 4449 start_networkd()
b241fa00
KF
4450 self.wait_online(['veth99:routable', 'veth-peer:degraded'])
4451
4452 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
4453 print(output)
4454 self.assertRegex(output, '2002:da8:1:0:1a:2b:3c:4d')
68248f43
YW
4455 self.assertRegex(output, '2002:da8:1:0:fa:de:ca:fe')
4456 self.assertRegex(output, '2002:da8:2:0:1a:2b:3c:4d')
4457 self.assertRegex(output, '2002:da8:2:0:fa:de:ca:fe')
b241fa00 4458
68248f43 4459 def test_ipv6_token_prefixstable(self):
a962d857 4460 copy_network_unit('25-veth.netdev', '25-ipv6-prefix.network', '25-ipv6-prefix-veth-token-prefixstable.network')
c24c83dc
KF
4461 start_networkd()
4462 self.wait_online(['veth99:routable', 'veth-peer:degraded'])
4463
4464 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
4465 print(output)
7a2e124b
YW
4466 self.assertIn('2002:da8:1:0:b47e:7975:fc7a:7d6e', output)
4467 self.assertIn('2002:da8:2:0:1034:56ff:fe78:9abc', output) # EUI64
c24c83dc 4468
68248f43 4469 def test_ipv6_token_prefixstable_without_address(self):
a962d857 4470 copy_network_unit('25-veth.netdev', '25-ipv6-prefix.network', '25-ipv6-prefix-veth-token-prefixstable-without-address.network')
87bbebea
YW
4471 start_networkd()
4472 self.wait_online(['veth99:routable', 'veth-peer:degraded'])
4473
4474 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
4475 print(output)
7a2e124b
YW
4476 self.assertIn('2002:da8:1:0:b47e:7975:fc7a:7d6e', output)
4477 self.assertIn('2002:da8:2:0:f689:561a:8eda:7443', output)
87bbebea 4478
bb80f633
YW
4479 def test_router_preference(self):
4480 copy_network_unit('25-veth-client.netdev',
4481 '25-veth-router-high.netdev',
4482 '25-veth-router-low.netdev',
4483 '26-bridge.netdev',
4484 '25-veth-bridge.network',
4485 '25-veth-client.network',
4486 '25-veth-router-high.network',
4487 '25-veth-router-low.network',
4488 '25-bridge99.network')
4489 start_networkd()
4490 self.wait_online(['client-p:enslaved',
4491 'router-high:degraded', 'router-high-p:enslaved',
4492 'router-low:degraded', 'router-low-p:enslaved',
4493 'bridge99:routable'])
4494
4495 networkctl_reconfigure('client')
4496 self.wait_online(['client:routable'])
4497
4498 self.wait_address('client', '2002:da8:1:99:1034:56ff:fe78:9a00/64', ipv='-6', timeout_sec=10)
4499 self.wait_address('client', '2002:da8:1:98:1034:56ff:fe78:9a00/64', ipv='-6', timeout_sec=10)
4500 self.wait_route('client', 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 512', ipv='-6', timeout_sec=10)
4501 self.wait_route('client', 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 2048', ipv='-6', timeout_sec=10)
4502
4503 output = check_output('ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99')
4504 print(output)
4505 self.assertIn('pref high', output)
4506 output = check_output('ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98')
4507 print(output)
4508 self.assertIn('pref low', output)
4509
4510 with open(os.path.join(network_unit_dir, '25-veth-client.network'), mode='a', encoding='utf-8') as f:
4511 f.write('\n[Link]\nMACAddress=12:34:56:78:9a:01\n[IPv6AcceptRA]\nRouteMetric=100:200:300\n')
4512
4513 networkctl_reload()
4514 self.wait_online(['client:routable'])
4515
4516 self.wait_address('client', '2002:da8:1:99:1034:56ff:fe78:9a01/64', ipv='-6', timeout_sec=10)
4517 self.wait_address('client', '2002:da8:1:98:1034:56ff:fe78:9a01/64', ipv='-6', timeout_sec=10)
4518 self.wait_route('client', 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 100', ipv='-6', timeout_sec=10)
4519 self.wait_route('client', 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 300', ipv='-6', timeout_sec=10)
4520
4521 output = check_output('ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99')
4522 print(output)
4523 self.assertIn('pref high', output)
4524 output = check_output('ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98')
4525 print(output)
4526 self.assertIn('pref low', output)
4527
be68c2c9 4528class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
1f0e3109
SS
4529
4530 def setUp(self):
a962d857 4531 setup_common()
1f0e3109
SS
4532
4533 def tearDown(self):
a962d857 4534 tear_down_common()
1f0e3109
SS
4535
4536 def test_dhcp_server(self):
a962d857 4537 copy_network_unit('25-veth.netdev', '25-dhcp-client.network', '25-dhcp-server.network')
c5f7a087
YW
4538 start_networkd()
4539 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4540
4541 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
4542 print(output)
283863a1 4543 self.assertRegex(output, r'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)')
c5f7a087
YW
4544 self.assertIn('Gateway: 192.168.5.3', output)
4545 self.assertRegex(output, 'DNS: 192.168.5.1\n *192.168.5.10')
4546 self.assertRegex(output, 'NTP: 192.168.5.1\n *192.168.5.11')
4547
4548 def test_dhcp_server_with_uplink(self):
a962d857
YW
4549 copy_network_unit('25-veth.netdev', '25-dhcp-client.network', '25-dhcp-server-downstream.network',
4550 '12-dummy.netdev', '25-dhcp-server-uplink.network')
2cf6fdff 4551 start_networkd()
e2aea43f 4552 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1f0e3109 4553
fc79e6ff 4554 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
1f0e3109 4555 print(output)
283863a1 4556 self.assertRegex(output, r'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)')
32d97330
YW
4557 self.assertIn('Gateway: 192.168.5.3', output)
4558 self.assertIn('DNS: 192.168.5.1', output)
4559 self.assertIn('NTP: 192.168.5.1', output)
1f0e3109 4560
1f0e3109 4561 def test_emit_router_timezone(self):
a962d857 4562 copy_network_unit('25-veth.netdev', '25-dhcp-client-timezone-router.network', '25-dhcp-server-timezone-router.network')
2cf6fdff 4563 start_networkd()
e2aea43f 4564 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1f0e3109 4565
fc79e6ff 4566 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
1f0e3109 4567 print(output)
283863a1 4568 self.assertRegex(output, r'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)')
32d97330
YW
4569 self.assertIn('Gateway: 192.168.5.1', output)
4570 self.assertIn('Time Zone: Europe/Berlin', output)
1f0e3109 4571
ffaece68 4572 def test_dhcp_server_static_lease(self):
a962d857 4573 copy_network_unit('25-veth.netdev', '25-dhcp-client-static-lease.network', '25-dhcp-server-static-lease.network')
ffaece68 4574 start_networkd()
4575 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4576
4577 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
4578 print(output)
32d97330 4579 self.assertIn('Address: 10.1.1.200 (DHCP4 via 10.1.1.1)', output)
82c60c93
YW
4580 self.assertIn('DHCP4 Client ID: 12:34:56:78:9a:bc', output)
4581
4582 def test_dhcp_server_static_lease_default_client_id(self):
4583 copy_network_unit('25-veth.netdev', '25-dhcp-client.network', '25-dhcp-server-static-lease.network')
4584 start_networkd()
4585 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4586
4587 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
4588 print(output)
4589 self.assertIn('Address: 10.1.1.200 (DHCP4 via 10.1.1.1)', output)
4590 self.assertRegex(output, 'DHCP4 Client ID: IAID:[0-9a-z]*/DUID')
ffaece68 4591
c95df587 4592class NetworkdDHCPServerRelayAgentTests(unittest.TestCase, Utilities):
c95df587
YA
4593
4594 def setUp(self):
a962d857 4595 setup_common()
c95df587
YA
4596
4597 def tearDown(self):
a962d857 4598 tear_down_common()
c95df587
YA
4599
4600 def test_relay_agent(self):
a962d857
YW
4601 copy_network_unit('25-agent-veth-client.netdev',
4602 '25-agent-veth-server.netdev',
4603 '25-agent-client.network',
4604 '25-agent-server.network',
4605 '25-agent-client-peer.network',
4606 '25-agent-server-peer.network')
c95df587
YA
4607 start_networkd()
4608
c95df587
YA
4609 self.wait_online(['client:routable'])
4610
4611 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'client', env=env)
4612 print(output)
283863a1 4613 self.assertRegex(output, r'Address: 192.168.5.150 \(DHCP4 via 192.168.5.1\)')
c95df587 4614
be68c2c9 4615class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
1f0e3109
SS
4616
4617 def setUp(self):
a962d857 4618 setup_common()
1f0e3109
SS
4619
4620 def tearDown(self):
a962d857 4621 tear_down_common()
1f0e3109
SS
4622
4623 def test_dhcp_client_ipv6_only(self):
a962d857 4624 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-ipv6-only.network')
1f0e3109 4625
2cf6fdff 4626 start_networkd()
e2aea43f 4627 self.wait_online(['veth-peer:carrier'])
ec38833c 4628 start_dnsmasq()
e2aea43f 4629 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1f0e3109 4630
18f2638f
YW
4631 # checking address
4632 output = check_output('ip address show dev veth99 scope global')
c5fcd8a7 4633 print(output)
18f2638f
YW
4634 self.assertRegex(output, r'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute')
4635 self.assertNotIn('192.168.5', output)
c5fcd8a7 4636
589af70b
YW
4637 # checking semi-static route
4638 output = check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
4639 print(output)
4640 self.assertRegex(output, 'via fe80::1034:56ff:fe78:9abd')
4641
3a956d38 4642 # Confirm that ipv6 token is not set in the kernel
371810d1 4643 output = check_output('ip token show dev veth99')
3a956d38
YW
4644 print(output)
4645 self.assertRegex(output, 'token :: dev veth99')
4646
91a7afde
YW
4647 print('## dnsmasq log')
4648 output = read_dnsmasq_log_file()
4649 print(output)
4650 self.assertIn('DHCPSOLICIT(veth-peer)', output)
4651 self.assertNotIn('DHCPADVERTISE(veth-peer)', output)
4652 self.assertNotIn('DHCPREQUEST(veth-peer)', output)
4653 self.assertIn('DHCPREPLY(veth-peer)', output)
4654 self.assertIn('sent size: 0 option: 14 rapid-commit', output)
4655
4656 with open(os.path.join(network_unit_dir, '25-dhcp-client-ipv6-only.network'), mode='a', encoding='utf-8') as f:
4657 f.write('\n[DHCPv6]\nRapidCommit=no\n')
4658
4659 stop_dnsmasq()
4660 start_dnsmasq()
4661
4662 networkctl_reload()
4663 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4664
4665 # checking address
4666 output = check_output('ip address show dev veth99 scope global')
4667 print(output)
4668 self.assertRegex(output, r'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute')
4669 self.assertNotIn('192.168.5', output)
4670
4671 # checking semi-static route
4672 output = check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
4673 print(output)
4674 self.assertRegex(output, 'via fe80::1034:56ff:fe78:9abd')
4675
4676 print('## dnsmasq log')
4677 output = read_dnsmasq_log_file()
4678 print(output)
4679 self.assertIn('DHCPSOLICIT(veth-peer)', output)
4680 self.assertIn('DHCPADVERTISE(veth-peer)', output)
4681 self.assertIn('DHCPREQUEST(veth-peer)', output)
4682 self.assertIn('DHCPREPLY(veth-peer)', output)
4683 self.assertNotIn('rapid-commit', output)
4684
1f0e3109 4685 def test_dhcp_client_ipv4_only(self):
a962d857 4686 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-ipv4-only.network')
1f0e3109 4687
2cf6fdff 4688 start_networkd()
e2aea43f 4689 self.wait_online(['veth-peer:carrier'])
a962d857
YW
4690 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7',
4691 '--dhcp-option=option:domain-search,example.com',
4692 '--dhcp-alternate-port=67,5555',
4693 ipv4_range='192.168.5.110,192.168.5.119')
e2aea43f 4694 self.wait_online(['veth99:routable', 'veth-peer:routable'])
9e7d91ed 4695 self.wait_address('veth99', r'inet 192.168.5.11[0-9]*/24', ipv='-4')
1f0e3109 4696
18f2638f
YW
4697 print('## ip address show dev veth99 scope global')
4698 output = check_output('ip address show dev veth99 scope global')
1f0e3109 4699 print(output)
18f2638f
YW
4700 self.assertIn('mtu 1492', output)
4701 self.assertIn('inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99', output)
4702 self.assertRegex(output, r'inet 192.168.5.11[0-9]/24 metric 24 brd 192.168.5.255 scope global secondary dynamic noprefixroute test-label')
4703 self.assertNotIn('2600::', output)
195a18c1 4704
18f2638f
YW
4705 print('## ip route show table main dev veth99')
4706 output = check_output('ip route show table main dev veth99')
195a18c1 4707 print(output)
18f2638f
YW
4708 # no DHCP routes assigned to the main table
4709 self.assertNotIn('proto dhcp', output)
4710 # static routes
4711 self.assertIn('192.168.5.0/24 proto kernel scope link src 192.168.5.250', output)
4712 self.assertIn('192.168.5.0/24 proto static scope link', output)
4713 self.assertIn('192.168.6.0/24 proto static scope link', output)
4714 self.assertIn('192.168.7.0/24 proto static scope link', output)
4715
4716 print('## ip route show table 211 dev veth99')
4717 output = check_output('ip route show table 211 dev veth99')
4718 print(output)
4719 self.assertRegex(output, 'default via 192.168.5.1 proto dhcp src 192.168.5.11[0-9] metric 24')
4720 self.assertRegex(output, '192.168.5.0/24 proto dhcp scope link src 192.168.5.11[0-9] metric 24')
4721 self.assertRegex(output, '192.168.5.1 proto dhcp scope link src 192.168.5.11[0-9] metric 24')
4722 self.assertRegex(output, '192.168.5.6 proto dhcp scope link src 192.168.5.11[0-9] metric 24')
4723 self.assertRegex(output, '192.168.5.7 proto dhcp scope link src 192.168.5.11[0-9] metric 24')
4724 self.assertIn('10.0.0.0/8 via 192.168.5.1 proto dhcp', output)
4725
1a8e1d78
YW
4726 print('## link state file')
4727 output = read_link_state_file('veth99')
4728 print(output)
18f2638f 4729 # checking DNS server and Domains
1a8e1d78
YW
4730 self.assertIn('DNS=192.168.5.6 192.168.5.7', output)
4731 self.assertIn('DOMAINS=example.com', output)
195a18c1 4732
18f2638f 4733 print('## dnsmasq log')
063c7e9b
YW
4734 output = read_dnsmasq_log_file()
4735 print(output)
4736 self.assertIn('vendor class: FooBarVendorTest', output)
4737 self.assertIn('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc', output)
4738 self.assertIn('client provides name: test-hostname', output)
4739 self.assertIn('26:mtu', output)
18f2638f
YW
4740
4741 # change address range, DNS servers, and Domains
888f57c1 4742 stop_dnsmasq()
a962d857
YW
4743 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8',
4744 '--dhcp-option=option:domain-search,foo.example.com',
4745 '--dhcp-alternate-port=67,5555',
4746 ipv4_range='192.168.5.120,192.168.5.129',)
195a18c1
YW
4747
4748 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
a102a52c 4749 print('Wait for the DHCP lease to be expired')
4b31fc88
YW
4750 self.wait_address_dropped('veth99', r'inet 192.168.5.11[0-9]*/24', ipv='-4', timeout_sec=120)
4751 self.wait_address('veth99', r'inet 192.168.5.12[0-9]*/24', ipv='-4')
195a18c1
YW
4752
4753 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4754
18f2638f
YW
4755 print('## ip address show dev veth99 scope global')
4756 output = check_output('ip address show dev veth99 scope global')
195a18c1 4757 print(output)
18f2638f
YW
4758 self.assertIn('mtu 1492', output)
4759 self.assertIn('inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99', output)
4760 self.assertNotIn('192.168.5.11', output)
4761 self.assertRegex(output, r'inet 192.168.5.12[0-9]/24 metric 24 brd 192.168.5.255 scope global secondary dynamic noprefixroute test-label')
4762 self.assertNotIn('2600::', output)
195a18c1 4763
18f2638f
YW
4764 print('## ip route show table main dev veth99')
4765 output = check_output('ip route show table main dev veth99')
195a18c1 4766 print(output)
18f2638f
YW
4767 # no DHCP routes assigned to the main table
4768 self.assertNotIn('proto dhcp', output)
4769 # static routes
4770 self.assertIn('192.168.5.0/24 proto kernel scope link src 192.168.5.250', output)
4771 self.assertIn('192.168.5.0/24 proto static scope link', output)
4772 self.assertIn('192.168.6.0/24 proto static scope link', output)
4773 self.assertIn('192.168.7.0/24 proto static scope link', output)
4774
4775 print('## ip route show table 211 dev veth99')
4776 output = check_output('ip route show table 211 dev veth99')
4777 print(output)
4778 self.assertRegex(output, 'default via 192.168.5.1 proto dhcp src 192.168.5.12[0-9] metric 24')
4779 self.assertRegex(output, '192.168.5.0/24 proto dhcp scope link src 192.168.5.12[0-9] metric 24')
4780 self.assertRegex(output, '192.168.5.1 proto dhcp scope link src 192.168.5.12[0-9] metric 24')
4781 self.assertNotIn('192.168.5.6', output)
4782 self.assertRegex(output, '192.168.5.7 proto dhcp scope link src 192.168.5.12[0-9] metric 24')
4783 self.assertRegex(output, '192.168.5.8 proto dhcp scope link src 192.168.5.12[0-9] metric 24')
4784 self.assertIn('10.0.0.0/8 via 192.168.5.1 proto dhcp', output)
4785
1a8e1d78
YW
4786 print('## link state file')
4787 output = read_link_state_file('veth99')
4788 print(output)
18f2638f 4789 # checking DNS server and Domains
1a8e1d78
YW
4790 self.assertIn('DNS=192.168.5.1 192.168.5.7 192.168.5.8', output)
4791 self.assertIn('DOMAINS=foo.example.com', output)
18f2638f
YW
4792
4793 print('## dnsmasq log')
063c7e9b
YW
4794 output = read_dnsmasq_log_file()
4795 print(output)
4796 self.assertIn('vendor class: FooBarVendorTest', output)
4797 self.assertIn('DHCPDISCOVER(veth-peer) 192.168.5.11', output)
4798 self.assertIn('client provides name: test-hostname', output)
4799 self.assertIn('26:mtu', output)
1f0e3109 4800
0677130e 4801 self.check_netlabel('veth99', r'192\.168\.5\.0/24')
a4640bed 4802
7c0d36ff 4803 def test_dhcp_client_ipv4_use_routes_gateway(self):
a962d857 4804 first = True
e1220a70 4805 for (routes, gateway, dns_and_ntp_routes, classless) in itertools.product([True, False], repeat=4):
a962d857
YW
4806 if first:
4807 first = False
4808 else:
4809 self.tearDown()
4810
4811 print(f'### test_dhcp_client_ipv4_use_routes_gateway(routes={routes}, gateway={gateway}, dns_and_ntp_routes={dns_and_ntp_routes}, classless={classless})')
e1220a70
YW
4812 with self.subTest(routes=routes, gateway=gateway, dns_and_ntp_routes=dns_and_ntp_routes, classless=classless):
4813 self._test_dhcp_client_ipv4_use_routes_gateway(routes, gateway, dns_and_ntp_routes, classless)
7c0d36ff 4814
e1220a70 4815 def _test_dhcp_client_ipv4_use_routes_gateway(self, use_routes, use_gateway, dns_and_ntp_routes, classless):
1e86c833
DDM
4816 testunit = '25-dhcp-client-ipv4-use-routes-use-gateway.network'
4817 testunits = ['25-veth.netdev', '25-dhcp-server-veth-peer.network', testunit]
6983bb0e
FS
4818 testunits.append(f'{testunit}.d/use-routes-{use_routes}.conf')
4819 testunits.append(f'{testunit}.d/use-gateway-{use_gateway}.conf')
4820 testunits.append(f'{testunit}.d/use-dns-and-ntp-routes-{dns_and_ntp_routes}.conf')
a962d857 4821 copy_network_unit(*testunits, copy_dropins=False)
4c2e1833
YW
4822
4823 start_networkd()
4824 self.wait_online(['veth-peer:carrier'])
a962d857
YW
4825 additional_options = [
4826 '--dhcp-option=option:dns-server,192.168.5.10,8.8.8.8',
4827 '--dhcp-option=option:ntp-server,192.168.5.11,9.9.9.9',
4828 '--dhcp-option=option:static-route,192.168.5.100,192.168.5.2,8.8.8.8,192.168.5.3'
4829 ]
625772c9 4830 if classless:
a962d857 4831 additional_options += [
86f67600 4832 '--dhcp-option=option:classless-static-route,0.0.0.0/0,192.168.5.4,8.0.0.0/8,192.168.5.5,192.168.5.64/26,192.168.5.5'
a962d857
YW
4833 ]
4834 start_dnsmasq(*additional_options)
4c2e1833
YW
4835 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4836
625772c9 4837 output = check_output('ip -4 route show dev veth99')
4c2e1833 4838 print(output)
4c2e1833 4839
7c0d36ff 4840 # Check UseRoutes=
625772c9
YW
4841 if use_routes:
4842 if classless:
4843 self.assertRegex(output, r'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
4844 self.assertRegex(output, r'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
86f67600 4845 self.assertRegex(output, r'192.168.5.64/26 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
625772c9
YW
4846 self.assertRegex(output, r'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4847 self.assertRegex(output, r'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4848 else:
4849 self.assertRegex(output, r'192.168.5.0/24 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4850 self.assertRegex(output, r'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024')
4851 self.assertRegex(output, r'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
7c0d36ff 4852 else:
625772c9
YW
4853 self.assertNotRegex(output, r'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
4854 self.assertNotRegex(output, r'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
4855 self.assertNotRegex(output, r'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4856 self.assertNotRegex(output, r'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4857 self.assertNotRegex(output, r'192.168.5.0/24 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4858 self.assertNotRegex(output, r'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024')
4859 self.assertNotRegex(output, r'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
0d7bd445 4860
7c0d36ff 4861 # Check UseGateway=
625772c9
YW
4862 if use_gateway and (not classless or not use_routes):
4863 self.assertRegex(output, r'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
7c0d36ff 4864 else:
625772c9 4865 self.assertNotRegex(output, r'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
87e62d32
YW
4866
4867 # Check route to gateway
4868 if (use_gateway or dns_and_ntp_routes) and (not classless or not use_routes):
4869 self.assertRegex(output, r'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4870 else:
625772c9 4871 self.assertNotRegex(output, r'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
7c0d36ff 4872
e1220a70
YW
4873 # Check RoutesToDNS= and RoutesToNTP=
4874 if dns_and_ntp_routes:
625772c9 4875 self.assertRegex(output, r'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
e1220a70 4876 self.assertRegex(output, r'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
625772c9
YW
4877 if classless and use_routes:
4878 self.assertRegex(output, r'8.8.8.8 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
e1220a70 4879 self.assertRegex(output, r'9.9.9.9 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
87e62d32 4880 else:
625772c9 4881 self.assertRegex(output, r'8.8.8.8 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
e1220a70 4882 self.assertRegex(output, r'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
7c0d36ff 4883 else:
625772c9 4884 self.assertNotRegex(output, r'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
e1220a70 4885 self.assertNotRegex(output, r'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
625772c9 4886 self.assertNotRegex(output, r'8.8.8.8 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024')
e1220a70 4887 self.assertNotRegex(output, r'9.9.9.9 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024')
0d7bd445 4888
94f0bd62
YW
4889 # TODO: check json string
4890 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
4891
1f0e3109 4892 def test_dhcp_client_settings_anonymize(self):
a962d857 4893 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-anonymize.network')
2cf6fdff 4894 start_networkd()
e2aea43f 4895 self.wait_online(['veth-peer:carrier'])
ec38833c 4896 start_dnsmasq()
e2aea43f 4897 self.wait_online(['veth99:routable', 'veth-peer:routable'])
e40a58b5 4898
063c7e9b
YW
4899 print('## dnsmasq log')
4900 output = read_dnsmasq_log_file()
4901 print(output)
4902 self.assertNotIn('VendorClassIdentifier=SusantVendorTest', output)
4903 self.assertNotIn('test-hostname', output)
4904 self.assertNotIn('26:mtu', output)
1f0e3109 4905
1e498853 4906 def test_dhcp_keep_configuration_dhcp(self):
a962d857
YW
4907 copy_network_unit('25-veth.netdev',
4908 '25-dhcp-server-veth-peer.network',
4909 '25-dhcp-client-keep-configuration-dhcp.network')
2cf6fdff 4910 start_networkd()
e2aea43f 4911 self.wait_online(['veth-peer:carrier'])
a962d857 4912 start_dnsmasq()
e2aea43f 4913 self.wait_online(['veth99:routable', 'veth-peer:routable'])
e40a58b5 4914
1e498853
YW
4915 output = check_output('ip address show dev veth99 scope global')
4916 print(output)
2b6a24a6
YW
4917 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4918 'valid_lft forever preferred_lft forever')
e40a58b5 4919
5238e957 4920 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
888f57c1 4921 stop_dnsmasq()
1f0e3109
SS
4922
4923 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
a102a52c
YW
4924 print('Wait for the DHCP lease to be expired')
4925 time.sleep(120)
1f0e3109 4926
2b6a24a6 4927 # The lease address should be kept after the lease expired
1e498853
YW
4928 output = check_output('ip address show dev veth99 scope global')
4929 print(output)
2b6a24a6
YW
4930 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4931 'valid_lft forever preferred_lft forever')
1e498853 4932
2b6a24a6 4933 stop_networkd()
1e498853 4934
2b6a24a6 4935 # The lease address should be kept after networkd stopped
1e498853
YW
4936 output = check_output('ip address show dev veth99 scope global')
4937 print(output)
2b6a24a6
YW
4938 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4939 'valid_lft forever preferred_lft forever')
1e498853 4940
a962d857 4941 with open(os.path.join(network_unit_dir, '25-dhcp-client-keep-configuration-dhcp.network'), mode='a', encoding='utf-8') as f:
2347b6b9 4942 f.write('[Network]\nDHCP=no\n')
1e498853 4943
2347b6b9
YW
4944 start_networkd()
4945 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1e498853 4946
2b6a24a6 4947 # Still the lease address should be kept after networkd restarted
1e498853
YW
4948 output = check_output('ip address show dev veth99 scope global')
4949 print(output)
2b6a24a6
YW
4950 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4951 'valid_lft forever preferred_lft forever')
1e498853
YW
4952
4953 def test_dhcp_keep_configuration_dhcp_on_stop(self):
a962d857
YW
4954 copy_network_unit('25-veth.netdev',
4955 '25-dhcp-server-veth-peer.network',
4956 '25-dhcp-client-keep-configuration-dhcp-on-stop.network')
2cf6fdff 4957 start_networkd()
e2aea43f 4958 self.wait_online(['veth-peer:carrier'])
a962d857 4959 start_dnsmasq()
e2aea43f 4960 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1e498853
YW
4961
4962 output = check_output('ip address show dev veth99 scope global')
4963 print(output)
2b6a24a6 4964 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
1e498853 4965
888f57c1 4966 stop_dnsmasq()
2b6a24a6 4967 stop_networkd()
1e498853
YW
4968
4969 output = check_output('ip address show dev veth99 scope global')
4970 print(output)
2b6a24a6 4971 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
1e498853 4972
a962d857 4973 start_networkd()
e2aea43f 4974 self.wait_online(['veth-peer:routable'])
1e498853
YW
4975
4976 output = check_output('ip address show dev veth99 scope global')
4977 print(output)
2b6a24a6 4978 self.assertNotIn('192.168.5.', output)
1f0e3109 4979
30d3b54e 4980 def test_dhcp_client_reuse_address_as_static(self):
a962d857 4981 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client.network')
2cf6fdff 4982 start_networkd()
e2aea43f 4983 self.wait_online(['veth-peer:carrier'])
ec38833c 4984 start_dnsmasq()
e2aea43f 4985 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2629df47
YW
4986
4987 # link become 'routable' when at least one protocol provide an valid address.
3e726c15 4988 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
426654d7 4989 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
30d3b54e 4990
371810d1 4991 output = check_output('ip address show dev veth99 scope global')
15519a81
YW
4992 ipv4_address = re.search(r'192.168.5.[0-9]*/24', output).group()
4993 ipv6_address = re.search(r'2600::[0-9a-f:]*/128', output).group()
4994 static_network = '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address, 'Address=' + ipv6_address])
30d3b54e
YW
4995 print(static_network)
4996
a962d857 4997 remove_network_unit('25-dhcp-client.network')
30d3b54e 4998
a962d857 4999 with open(os.path.join(network_unit_dir, '25-static.network'), mode='w', encoding='utf-8') as f:
30d3b54e
YW
5000 f.write(static_network)
5001
15519a81
YW
5002 restart_networkd()
5003 self.wait_online(['veth99:routable'])
30d3b54e 5004
371810d1 5005 output = check_output('ip -4 address show dev veth99 scope global')
30d3b54e 5006 print(output)
15519a81
YW
5007 self.assertRegex(output, f'inet {ipv4_address} brd 192.168.5.255 scope global veth99\n *'
5008 'valid_lft forever preferred_lft forever')
30d3b54e 5009
371810d1 5010 output = check_output('ip -6 address show dev veth99 scope global')
30d3b54e 5011 print(output)
15519a81
YW
5012 self.assertRegex(output, f'inet6 {ipv6_address} scope global *\n *'
5013 'valid_lft forever preferred_lft forever')
30d3b54e 5014
18c613dc
YW
5015 @expectedFailureIfModuleIsNotAvailable('vrf')
5016 def test_dhcp_client_vrf(self):
a962d857
YW
5017 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-vrf.network',
5018 '25-vrf.netdev', '25-vrf.network')
2cf6fdff 5019 start_networkd()
e2aea43f 5020 self.wait_online(['veth-peer:carrier'])
ec38833c 5021 start_dnsmasq()
e2aea43f 5022 self.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
2629df47
YW
5023
5024 # link become 'routable' when at least one protocol provide an valid address.
3e726c15 5025 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
426654d7 5026 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
18c613dc
YW
5027
5028 print('## ip -d link show dev vrf99')
371810d1 5029 output = check_output('ip -d link show dev vrf99')
18c613dc
YW
5030 print(output)
5031 self.assertRegex(output, 'vrf table 42')
5032
5033 print('## ip address show vrf vrf99')
371810d1 5034 output = check_output('ip address show vrf vrf99')
d90f4f7d 5035 print(output)
3e726c15 5036 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
426654d7 5037 self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
d90f4f7d 5038 self.assertRegex(output, 'inet6 .* scope link')
18c613dc
YW
5039
5040 print('## ip address show dev veth99')
371810d1 5041 output = check_output('ip address show dev veth99')
18c613dc 5042 print(output)
3e726c15 5043 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
426654d7 5044 self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
18c613dc
YW
5045 self.assertRegex(output, 'inet6 .* scope link')
5046
5047 print('## ip route show vrf vrf99')
371810d1 5048 output = check_output('ip route show vrf vrf99')
18c613dc
YW
5049 print(output)
5050 self.assertRegex(output, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
18c613dc 5051 self.assertRegex(output, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
18c613dc
YW
5052 self.assertRegex(output, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
5053
5054 print('## ip route show table main dev veth99')
371810d1 5055 output = check_output('ip route show table main dev veth99')
18c613dc
YW
5056 print(output)
5057 self.assertEqual(output, '')
5058
af3b1498 5059 def test_dhcp_client_gateway_onlink_implicit(self):
a962d857
YW
5060 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network',
5061 '25-dhcp-client-gateway-onlink-implicit.network')
2cf6fdff 5062 start_networkd()
e2aea43f 5063 self.wait_online(['veth-peer:carrier'])
ec38833c 5064 start_dnsmasq()
e2aea43f 5065 self.wait_online(['veth99:routable', 'veth-peer:routable'])
af3b1498 5066
fc79e6ff 5067 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
af3b1498
YW
5068 print(output)
5069 self.assertRegex(output, '192.168.5')
5070
371810d1 5071 output = check_output('ip route list dev veth99 10.0.0.0/8')
af3b1498
YW
5072 print(output)
5073 self.assertRegex(output, 'onlink')
371810d1 5074 output = check_output('ip route list dev veth99 192.168.100.0/24')
af3b1498
YW
5075 print(output)
5076 self.assertRegex(output, 'onlink')
5077
2d7a594f 5078 def test_dhcp_client_with_ipv4ll(self):
a962d857
YW
5079 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network',
5080 '25-dhcp-client-with-ipv4ll.network')
2cf6fdff 5081 start_networkd()
2d7a594f
YW
5082 # we need to increase timeout above default, as this will need to wait for
5083 # systemd-networkd to get the dhcpv4 transient failure event
5084 self.wait_online(['veth99:degraded', 'veth-peer:routable'], timeout='60s')
63c598ed 5085
2d7a594f 5086 output = check_output('ip -4 address show dev veth99')
63c598ed 5087 print(output)
2d7a594f 5088 self.assertNotIn('192.168.5.', output)
72c747e6 5089 self.assertIn('inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link', output)
63c598ed 5090
a962d857 5091 start_dnsmasq()
2d7a594f
YW
5092 print('Wait for a DHCP lease to be acquired and the IPv4LL address to be dropped')
5093 self.wait_address('veth99', r'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic', ipv='-4')
5094 self.wait_address_dropped('veth99', r'inet 169\.254\.\d+\.\d+/16 metric 2048 brd 169\.254\.255\.255 scope link', scope='link', ipv='-4')
5095 self.wait_online(['veth99:routable'])
63c598ed 5096
2d7a594f 5097 output = check_output('ip -4 address show dev veth99')
63c598ed 5098 print(output)
3e726c15 5099 self.assertRegex(output, r'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99')
2d7a594f
YW
5100 self.assertNotIn('169.254.', output)
5101 self.assertNotIn('scope link', output)
63c598ed 5102
2d7a594f
YW
5103 stop_dnsmasq()
5104 print('Wait for the DHCP lease to be expired and an IPv4LL address to be acquired')
286bf3a9 5105 self.wait_address_dropped('veth99', r'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic', ipv='-4', timeout_sec=130)
72c747e6 5106 self.wait_address('veth99', r'inet 169\.254\.133\.11/16 metric 2048 brd 169\.254\.255\.255 scope link', scope='link', ipv='-4')
117a55c7 5107
2d7a594f 5108 output = check_output('ip -4 address show dev veth99')
117a55c7 5109 print(output)
2d7a594f 5110 self.assertNotIn('192.168.5.', output)
72c747e6 5111 self.assertIn('inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link', output)
240e4137 5112
3d8e0aa2
YW
5113 def test_dhcp_client_use_dns(self):
5114 def check(self, ipv4, ipv6):
a962d857
YW
5115 os.makedirs(os.path.join(network_unit_dir, '25-dhcp-client.network.d'), exist_ok=True)
5116 with open(os.path.join(network_unit_dir, '25-dhcp-client.network.d/override.conf'), mode='w', encoding='utf-8') as f:
3d8e0aa2
YW
5117 f.write('[DHCPv4]\nUseDNS=')
5118 f.write('yes' if ipv4 else 'no')
5119 f.write('\n[DHCPv6]\nUseDNS=')
5120 f.write('yes' if ipv6 else 'no')
5121 f.write('\n[IPv6AcceptRA]\nUseDNS=no')
5122
a962d857 5123 networkctl_reload()
3d8e0aa2 5124 self.wait_online(['veth99:routable'])
e2d5aab3 5125
3d8e0aa2
YW
5126 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5127 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
5128 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
e2d5aab3 5129
3d8e0aa2
YW
5130 # make resolved re-read the link state file
5131 check_output(*resolvectl_cmd, 'revert', 'veth99', env=env)
e2d5aab3 5132
3d8e0aa2
YW
5133 output = check_output(*resolvectl_cmd, 'dns', 'veth99', env=env)
5134 print(output)
5135 if ipv4:
5136 self.assertIn('192.168.5.1', output)
5137 else:
5138 self.assertNotIn('192.168.5.1', output)
5139 if ipv6:
5140 self.assertIn('2600::1', output)
5141 else:
5142 self.assertNotIn('2600::1', output)
e2d5aab3 5143
3d8e0aa2
YW
5144 # TODO: check json string
5145 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
e2d5aab3 5146
a962d857 5147 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client.network', copy_dropins=False)
e2d5aab3
YW
5148
5149 start_networkd()
e2aea43f 5150 self.wait_online(['veth-peer:carrier'])
a962d857
YW
5151 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1',
5152 '--dhcp-option=option6:dns-server,[2600::1]')
e2d5aab3 5153
3d8e0aa2
YW
5154 check(self, True, True)
5155 check(self, True, False)
5156 check(self, False, True)
5157 check(self, False, False)
e2d5aab3 5158
dbe960f0
RP
5159 def test_dhcp_client_use_captive_portal(self):
5160 def check(self, ipv4, ipv6):
5161 os.makedirs(os.path.join(network_unit_dir, '25-dhcp-client.network.d'), exist_ok=True)
5162 with open(os.path.join(network_unit_dir, '25-dhcp-client.network.d/override.conf'), mode='w', encoding='utf-8') as f:
5163 f.write('[DHCPv4]\nUseCaptivePortal=')
5164 f.write('yes' if ipv4 else 'no')
5165 f.write('\n[DHCPv6]\nUseCaptivePortal=')
5166 f.write('yes' if ipv6 else 'no')
5167 f.write('\n[IPv6AcceptRA]\nUseCaptivePortal=no')
5168
5169 networkctl_reload()
5170 self.wait_online(['veth99:routable'])
5171
5172 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5173 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
5174 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
5175
5176 output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
5177 print(output)
5178 if ipv4 or ipv6:
5179 self.assertIn('Captive Portal: http://systemd.io', output)
5180 else:
5181 self.assertNotIn('Captive Portal: http://systemd.io', output)
5182
5183 # TODO: check json string
5184 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
5185
5186 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client.network', copy_dropins=False)
5187
5188 start_networkd()
5189 self.wait_online(['veth-peer:carrier'])
5190 start_dnsmasq('--dhcp-option=114,http://systemd.io',
5191 '--dhcp-option=option6:103,http://systemd.io')
5192
5193 check(self, True, True)
5194 check(self, True, False)
5195 check(self, False, True)
5196 check(self, False, False)
5197
1219391c
RP
5198 def test_dhcp_client_reject_captive_portal(self):
5199 def check(self, ipv4, ipv6):
5200 os.makedirs(os.path.join(network_unit_dir, '25-dhcp-client.network.d'), exist_ok=True)
5201 with open(os.path.join(network_unit_dir, '25-dhcp-client.network.d/override.conf'), mode='w', encoding='utf-8') as f:
5202 f.write('[DHCPv4]\nUseCaptivePortal=')
5203 f.write('yes' if ipv4 else 'no')
5204 f.write('\n[DHCPv6]\nUseCaptivePortal=')
5205 f.write('yes' if ipv6 else 'no')
5206 f.write('\n[IPv6AcceptRA]\nUseCaptivePortal=no')
5207
5208 networkctl_reload()
5209 self.wait_online(['veth99:routable'])
5210
5211 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5212 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
5213 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
5214
5215 output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
5216 print(output)
5217 self.assertNotIn('Captive Portal: ', output)
5218 self.assertNotIn('invalid/url', output)
5219
5220 # TODO: check json string
5221 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
5222
5223 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client.network', copy_dropins=False)
5224
5225 start_networkd()
5226 self.wait_online(['veth-peer:carrier'])
5227 masq = lambda bs: ':'.join(f'{b:02x}' for b in bs)
5228 start_dnsmasq('--dhcp-option=114,' + masq(b'http://\x00invalid/url'),
5229 '--dhcp-option=option6:103,' + masq(b'http://\x00/invalid/url'))
5230
5231 check(self, True, True)
5232 check(self, True, False)
5233 check(self, False, True)
5234 check(self, False, False)
5235
a27588d4 5236class NetworkdDHCPPDTests(unittest.TestCase, Utilities):
caad88a2
YW
5237
5238 def setUp(self):
a962d857 5239 setup_common()
caad88a2
YW
5240
5241 def tearDown(self):
a962d857 5242 tear_down_common()
caad88a2
YW
5243
5244 def test_dhcp6pd(self):
a962d857
YW
5245 copy_network_unit('25-veth.netdev', '25-dhcp6pd-server.network', '25-dhcp6pd-upstream.network',
5246 '25-veth-downstream-veth97.netdev', '25-dhcp-pd-downstream-veth97.network', '25-dhcp-pd-downstream-veth97-peer.network',
5247 '25-veth-downstream-veth98.netdev', '25-dhcp-pd-downstream-veth98.network', '25-dhcp-pd-downstream-veth98-peer.network',
5248 '11-dummy.netdev', '25-dhcp-pd-downstream-test1.network',
5249 '25-dhcp-pd-downstream-dummy97.network',
5250 '12-dummy.netdev', '25-dhcp-pd-downstream-dummy98.network',
5251 '13-dummy.netdev', '25-dhcp-pd-downstream-dummy99.network')
caad88a2
YW
5252
5253 start_networkd()
133f65ef 5254 self.wait_online(['veth-peer:routable'])
a962d857 5255 start_isc_dhcpd(conf_file='isc-dhcpd-dhcp6pd.conf', ipv='-6')
133f65ef 5256 self.wait_online(['veth99:routable', 'test1:routable', 'dummy98:routable', 'dummy99:degraded',
6c8d6bdd 5257 'veth97:routable', 'veth97-peer:routable', 'veth98:routable', 'veth98-peer:routable'])
caad88a2
YW
5258
5259 print('### ip -6 address show dev veth-peer scope global')
5260 output = check_output('ip -6 address show dev veth-peer scope global')
5261 print(output)
5262 self.assertIn('inet6 3ffe:501:ffff:100::1/64 scope global', output)
5263
f7805a6c
FS
5264 # Link Subnet IDs
5265 # test1: 0x00
5266 # dummy97: 0x01 (The link will appear later)
07b7337a
YW
5267 # dummy98: 0x00
5268 # dummy99: auto -> 0x02 (No address assignment)
f7805a6c
FS
5269 # veth97: 0x08
5270 # veth98: 0x09
38488bab 5271 # veth99: 0x10
6016f1cf 5272
caad88a2
YW
5273 print('### ip -6 address show dev veth99 scope global')
5274 output = check_output('ip -6 address show dev veth99 scope global')
5275 print(output)
5276 # IA_NA
5277 self.assertRegex(output, 'inet6 3ffe:501:ffff:100::[0-9]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
5278 # address in IA_PD (Token=static)
38488bab 5279 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic')
caad88a2 5280 # address in IA_PD (Token=eui64)
38488bab
YW
5281 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic')
5282 # address in IA_PD (temporary)
5283 # Note that the temporary addresses may appear after the link enters configured state
5284 self.wait_address('veth99', 'inet6 3ffe:501:ffff:[2-9a-f]10:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6')
caad88a2
YW
5285
5286 print('### ip -6 address show dev test1 scope global')
5287 output = check_output('ip -6 address show dev test1 scope global')
5288 print(output)
5289 # address in IA_PD (Token=static)
5290 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5291 # address in IA_PD (temporary)
5292 self.wait_address('test1', 'inet6 3ffe:501:ffff:[2-9a-f]00:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6')
5293
5294 print('### ip -6 address show dev dummy98 scope global')
5295 output = check_output('ip -6 address show dev dummy98 scope global')
5296 print(output)
5297 # address in IA_PD (Token=static)
07b7337a 5298 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
caad88a2 5299 # address in IA_PD (temporary)
07b7337a 5300 self.wait_address('dummy98', 'inet6 3ffe:501:ffff:[2-9a-f]00:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6')
6016f1cf
YW
5301
5302 print('### ip -6 address show dev dummy99 scope global')
5303 output = check_output('ip -6 address show dev dummy99 scope global')
5304 print(output)
5305 # Assign=no
07b7337a 5306 self.assertNotRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]02')
caad88a2 5307
6c8d6bdd
YW
5308 print('### ip -6 address show dev veth97 scope global')
5309 output = check_output('ip -6 address show dev veth97 scope global')
5310 print(output)
5311 # address in IA_PD (Token=static)
5312 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5313 # address in IA_PD (Token=eui64)
5314 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr')
5315 # address in IA_PD (temporary)
5316 self.wait_address('veth97', 'inet6 3ffe:501:ffff:[2-9a-f]08:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6')
5317
5318 print('### ip -6 address show dev veth97-peer scope global')
5319 output = check_output('ip -6 address show dev veth97-peer scope global')
5320 print(output)
5321 # NDisc address (Token=static)
5322 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
5323 # NDisc address (Token=eui64)
5324 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr')
5325 # NDisc address (temporary)
5326 self.wait_address('veth97-peer', 'inet6 3ffe:501:ffff:[2-9a-f]08:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6')
5327
caad88a2
YW
5328 print('### ip -6 address show dev veth98 scope global')
5329 output = check_output('ip -6 address show dev veth98 scope global')
5330 print(output)
5331 # address in IA_PD (Token=static)
5332 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5333 # address in IA_PD (Token=eui64)
5334 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr')
5335 # address in IA_PD (temporary)
5336 self.wait_address('veth98', 'inet6 3ffe:501:ffff:[2-9a-f]09:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6')
5337
5338 print('### ip -6 address show dev veth98-peer scope global')
5339 output = check_output('ip -6 address show dev veth98-peer scope global')
5340 print(output)
5341 # NDisc address (Token=static)
5342 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
5343 # NDisc address (Token=eui64)
5344 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr')
5345 # NDisc address (temporary)
5346 self.wait_address('veth98-peer', 'inet6 3ffe:501:ffff:[2-9a-f]09:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6')
5347
caad88a2
YW
5348 print('### ip -6 route show type unreachable')
5349 output = check_output('ip -6 route show type unreachable')
5350 print(output)
5351 self.assertRegex(output, 'unreachable 3ffe:501:ffff:[2-9a-f]00::/56 dev lo proto dhcp')
5352
5353 print('### ip -6 route show dev veth99')
5354 output = check_output('ip -6 route show dev veth99')
5355 print(output)
38488bab 5356 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]10::/64 proto kernel metric [0-9]* expires')
caad88a2
YW
5357
5358 print('### ip -6 route show dev test1')
5359 output = check_output('ip -6 route show dev test1')
5360 print(output)
5361 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires')
5362
5363 print('### ip -6 route show dev dummy98')
5364 output = check_output('ip -6 route show dev dummy98')
5365 print(output)
07b7337a 5366 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires')
caad88a2
YW
5367
5368 print('### ip -6 route show dev dummy99')
5369 output = check_output('ip -6 route show dev dummy99')
5370 print(output)
07b7337a 5371 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires')
6016f1cf
YW
5372
5373 print('### ip -6 route show dev veth97')
5374 output = check_output('ip -6 route show dev veth97')
5375 print(output)
5376 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]08::/64 proto kernel metric [0-9]* expires')
5377
5378 print('### ip -6 route show dev veth97-peer')
5379 output = check_output('ip -6 route show dev veth97-peer')
5380 print(output)
5381 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]08::/64 proto ra metric [0-9]* expires')
caad88a2
YW
5382
5383 print('### ip -6 route show dev veth98')
5384 output = check_output('ip -6 route show dev veth98')
5385 print(output)
5386 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]09::/64 proto kernel metric [0-9]* expires')
5387
5388 print('### ip -6 route show dev veth98-peer')
5389 output = check_output('ip -6 route show dev veth98-peer')
5390 print(output)
5391 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]09::/64 proto ra metric [0-9]* expires')
5392
5393 # Test case for a downstream which appears later
5394 check_output('ip link add dummy97 type dummy')
5395 self.wait_online(['dummy97:routable'])
5396
5397 print('### ip -6 address show dev dummy97 scope global')
5398 output = check_output('ip -6 address show dev dummy97 scope global')
5399 print(output)
5400 # address in IA_PD (Token=static)
6016f1cf 5401 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
caad88a2 5402 # address in IA_PD (temporary)
6016f1cf 5403 self.wait_address('dummy97', 'inet6 3ffe:501:ffff:[2-9a-f]01:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6')
caad88a2
YW
5404
5405 print('### ip -6 route show dev dummy97')
5406 output = check_output('ip -6 route show dev dummy97')
5407 print(output)
6016f1cf 5408 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]01::/64 proto kernel metric [0-9]* expires')
caad88a2
YW
5409
5410 # Test case for reconfigure
a962d857 5411 networkctl_reconfigure('dummy98', 'dummy99')
8d2a5502 5412 self.wait_online(['dummy98:routable', 'dummy99:degraded'])
caad88a2
YW
5413
5414 print('### ip -6 address show dev dummy98 scope global')
5415 output = check_output('ip -6 address show dev dummy98 scope global')
5416 print(output)
5417 # address in IA_PD (Token=static)
07b7337a 5418 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
caad88a2 5419 # address in IA_PD (temporary)
07b7337a 5420 self.wait_address('dummy98', 'inet6 3ffe:501:ffff:[2-9a-f]00:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6')
6016f1cf
YW
5421
5422 print('### ip -6 address show dev dummy99 scope global')
5423 output = check_output('ip -6 address show dev dummy99 scope global')
5424 print(output)
5425 # Assign=no
07b7337a 5426 self.assertNotRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]02')
caad88a2
YW
5427
5428 print('### ip -6 route show dev dummy98')
5429 output = check_output('ip -6 route show dev dummy98')
5430 print(output)
07b7337a 5431 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires')
6016f1cf
YW
5432
5433 print('### ip -6 route show dev dummy99')
5434 output = check_output('ip -6 route show dev dummy99')
5435 print(output)
07b7337a 5436 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires')
caad88a2 5437
a4640bed
TM
5438 self.check_netlabel('dummy98', '3ffe:501:ffff:[2-9a-f]00::/64')
5439
6a936c9c 5440 def verify_dhcp4_6rd(self, tunnel_name):
84cc85f9
YW
5441 print('### ip -4 address show dev veth-peer scope global')
5442 output = check_output('ip -4 address show dev veth-peer scope global')
5443 print(output)
5444 self.assertIn('inet 10.0.0.1/8 brd 10.255.255.255 scope global veth-peer', output)
5445
f7805a6c
FS
5446 # Link Subnet IDs
5447 # test1: 0x00
5448 # dummy97: 0x01 (The link will appear later)
07b7337a
YW
5449 # dummy98: 0x00
5450 # dummy99: auto -> 0x0[23] (No address assignment)
5451 # 6rd-XXX: auto -> 0x0[23]
f7805a6c
FS
5452 # veth97: 0x08
5453 # veth98: 0x09
5454 # veth99: 0x10
84cc85f9
YW
5455
5456 print('### ip -4 address show dev veth99 scope global')
5457 output = check_output('ip -4 address show dev veth99 scope global')
5458 print(output)
5459 self.assertRegex(output, 'inet 10.100.100.[0-9]*/8 (metric 1024 |)brd 10.255.255.255 scope global dynamic veth99')
5460
5461 print('### ip -6 address show dev veth99 scope global')
5462 output = check_output('ip -6 address show dev veth99 scope global')
5463 print(output)
5464 # address in IA_PD (Token=static)
5465 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5466 # address in IA_PD (Token=eui64)
5467 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic mngtmpaddr')
5468 # address in IA_PD (temporary)
5469 # Note that the temporary addresses may appear after the link enters configured state
5470 self.wait_address('veth99', 'inet6 2001:db8:6464:[0-9a-f]+10:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6')
5471
5472 print('### ip -6 address show dev test1 scope global')
5473 output = check_output('ip -6 address show dev test1 scope global')
5474 print(output)
5475 # address in IA_PD (Token=static)
5476 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5477 # address in IA_PD (temporary)
5478 self.wait_address('test1', 'inet6 2001:db8:6464:[0-9a-f]+00:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6')
5479
5480 print('### ip -6 address show dev dummy98 scope global')
5481 output = check_output('ip -6 address show dev dummy98 scope global')
5482 print(output)
5483 # address in IA_PD (Token=static)
07b7337a 5484 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
84cc85f9 5485 # address in IA_PD (temporary)
07b7337a 5486 self.wait_address('dummy98', 'inet6 2001:db8:6464:[0-9a-f]+00:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6')
84cc85f9
YW
5487
5488 print('### ip -6 address show dev dummy99 scope global')
5489 output = check_output('ip -6 address show dev dummy99 scope global')
5490 print(output)
5491 # Assign=no
07b7337a 5492 self.assertNotRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+0[23]')
84cc85f9
YW
5493
5494 print('### ip -6 address show dev veth97 scope global')
5495 output = check_output('ip -6 address show dev veth97 scope global')
5496 print(output)
5497 # address in IA_PD (Token=static)
5498 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5499 # address in IA_PD (Token=eui64)
5500 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr')
5501 # address in IA_PD (temporary)
5502 self.wait_address('veth97', 'inet6 2001:db8:6464:[0-9a-f]+08:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6')
5503
5504 print('### ip -6 address show dev veth97-peer scope global')
5505 output = check_output('ip -6 address show dev veth97-peer scope global')
5506 print(output)
5507 # NDisc address (Token=static)
5508 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
5509 # NDisc address (Token=eui64)
5510 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr')
5511 # NDisc address (temporary)
5512 self.wait_address('veth97-peer', 'inet6 2001:db8:6464:[0-9a-f]+08:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6')
5513
5514 print('### ip -6 address show dev veth98 scope global')
5515 output = check_output('ip -6 address show dev veth98 scope global')
5516 print(output)
5517 # address in IA_PD (Token=static)
5518 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5519 # address in IA_PD (Token=eui64)
5520 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr')
5521 # address in IA_PD (temporary)
5522 self.wait_address('veth98', 'inet6 2001:db8:6464:[0-9a-f]+09:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6')
5523
5524 print('### ip -6 address show dev veth98-peer scope global')
5525 output = check_output('ip -6 address show dev veth98-peer scope global')
5526 print(output)
5527 # NDisc address (Token=static)
5528 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
5529 # NDisc address (Token=eui64)
5530 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr')
5531 # NDisc address (temporary)
5532 self.wait_address('veth98-peer', 'inet6 2001:db8:6464:[0-9a-f]+09:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6')
5533
5534 print('### ip -6 route show type unreachable')
5535 output = check_output('ip -6 route show type unreachable')
5536 print(output)
5537 self.assertRegex(output, 'unreachable 2001:db8:6464:[0-9a-f]+00::/56 dev lo proto dhcp')
5538
5539 print('### ip -6 route show dev veth99')
5540 output = check_output('ip -6 route show dev veth99')
5541 print(output)
5542 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+10::/64 proto kernel metric [0-9]* expires')
5543
5544 print('### ip -6 route show dev test1')
5545 output = check_output('ip -6 route show dev test1')
5546 print(output)
5547 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires')
5548
5549 print('### ip -6 route show dev dummy98')
5550 output = check_output('ip -6 route show dev dummy98')
5551 print(output)
07b7337a 5552 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires')
84cc85f9
YW
5553
5554 print('### ip -6 route show dev dummy99')
5555 output = check_output('ip -6 route show dev dummy99')
5556 print(output)
07b7337a 5557 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto dhcp metric [0-9]* expires')
84cc85f9
YW
5558
5559 print('### ip -6 route show dev veth97')
5560 output = check_output('ip -6 route show dev veth97')
5561 print(output)
5562 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+08::/64 proto kernel metric [0-9]* expires')
5563
5564 print('### ip -6 route show dev veth97-peer')
5565 output = check_output('ip -6 route show dev veth97-peer')
5566 print(output)
5567 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+08::/64 proto ra metric [0-9]* expires')
5568
5569 print('### ip -6 route show dev veth98')
5570 output = check_output('ip -6 route show dev veth98')
5571 print(output)
5572 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+09::/64 proto kernel metric [0-9]* expires')
5573
5574 print('### ip -6 route show dev veth98-peer')
5575 output = check_output('ip -6 route show dev veth98-peer')
5576 print(output)
5577 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+09::/64 proto ra metric [0-9]* expires')
5578
84cc85f9
YW
5579 print('### ip -6 address show dev dummy97 scope global')
5580 output = check_output('ip -6 address show dev dummy97 scope global')
5581 print(output)
5582 # address in IA_PD (Token=static)
5583 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5584 # address in IA_PD (temporary)
5585 self.wait_address('dummy97', 'inet6 2001:db8:6464:[0-9a-f]+01:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global temporary dynamic', ipv='-6')
5586
5587 print('### ip -6 route show dev dummy97')
5588 output = check_output('ip -6 route show dev dummy97')
5589 print(output)
5590 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+01::/64 proto kernel metric [0-9]* expires')
5591
e4295d4d
FS
5592 print(f'### ip -d link show dev {tunnel_name}')
5593 output = check_output(f'ip -d link show dev {tunnel_name}')
84cc85f9
YW
5594 print(output)
5595 self.assertIn('link/sit 10.100.100.', output)
5596 self.assertIn('local 10.100.100.', output)
84cc85f9
YW
5597 self.assertIn('ttl 64', output)
5598 self.assertIn('6rd-prefix 2001:db8::/32', output)
5599 self.assertIn('6rd-relay_prefix 10.0.0.0/8', output)
5600
e4295d4d
FS
5601 print(f'### ip -6 address show dev {tunnel_name}')
5602 output = check_output(f'ip -6 address show dev {tunnel_name}')
84cc85f9 5603 print(output)
07b7337a 5604 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+0[23]:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*/64 (metric 256 |)scope global dynamic')
84cc85f9
YW
5605 self.assertRegex(output, 'inet6 ::10.100.100.[0-9]+/96 scope global')
5606
e4295d4d
FS
5607 print(f'### ip -6 route show dev {tunnel_name}')
5608 output = check_output(f'ip -6 route show dev {tunnel_name}')
84cc85f9 5609 print(output)
07b7337a 5610 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto kernel metric [0-9]* expires')
84cc85f9
YW
5611 self.assertRegex(output, '::/96 proto kernel metric [0-9]*')
5612
5613 print('### ip -6 route show default')
5614 output = check_output('ip -6 route show default')
5615 print(output)
5616 self.assertIn('default', output)
e4295d4d 5617 self.assertIn(f'via ::10.0.0.1 dev {tunnel_name}', output)
84cc85f9 5618
6a936c9c 5619 def test_dhcp4_6rd(self):
a962d857
YW
5620 copy_network_unit('25-veth.netdev', '25-dhcp4-6rd-server.network', '25-dhcp4-6rd-upstream.network',
5621 '25-veth-downstream-veth97.netdev', '25-dhcp-pd-downstream-veth97.network', '25-dhcp-pd-downstream-veth97-peer.network',
5622 '25-veth-downstream-veth98.netdev', '25-dhcp-pd-downstream-veth98.network', '25-dhcp-pd-downstream-veth98-peer.network',
5623 '11-dummy.netdev', '25-dhcp-pd-downstream-test1.network',
5624 '25-dhcp-pd-downstream-dummy97.network',
5625 '12-dummy.netdev', '25-dhcp-pd-downstream-dummy98.network',
5626 '13-dummy.netdev', '25-dhcp-pd-downstream-dummy99.network',
5627 '80-6rd-tunnel.network')
6a936c9c
YW
5628
5629 start_networkd()
5630 self.wait_online(['veth-peer:routable'])
f7805a6c
FS
5631
5632 # ipv4masklen: 8
5633 # 6rd-prefix: 2001:db8::/32
5634 # br-addresss: 10.0.0.1
5635
a962d857
YW
5636 start_dnsmasq('--dhcp-option=212,08:20:20:01:0d:b8:00:00:00:00:00:00:00:00:00:00:00:00:0a:00:00:01',
5637 ipv4_range='10.100.100.100,10.100.100.200',
5638 ipv4_router='10.0.0.1')
6a936c9c
YW
5639 self.wait_online(['veth99:routable', 'test1:routable', 'dummy98:routable', 'dummy99:degraded',
5640 'veth97:routable', 'veth97-peer:routable', 'veth98:routable', 'veth98-peer:routable'])
5641
5642 # Test case for a downstream which appears later
5643 check_output('ip link add dummy97 type dummy')
5644 self.wait_online(['dummy97:routable'])
5645
5646 # Find tunnel name
5647 tunnel_name = None
5648 for name in os.listdir('/sys/class/net/'):
5649 if name.startswith('6rd-'):
5650 tunnel_name = name
5651 break
5652
e4295d4d 5653 self.wait_online([f'{tunnel_name}:routable'])
6a936c9c
YW
5654
5655 self.verify_dhcp4_6rd(tunnel_name)
5656
5657 # Test case for reconfigure
a962d857 5658 networkctl_reconfigure('dummy98', 'dummy99')
6a936c9c
YW
5659 self.wait_online(['dummy98:routable', 'dummy99:degraded'])
5660
5661 self.verify_dhcp4_6rd(tunnel_name)
5662
3af934bc 5663 print('Wait for the DHCP lease to be renewed/rebind')
a102a52c 5664 time.sleep(120)
6a936c9c 5665
6a936c9c
YW
5666 self.wait_online(['veth99:routable', 'test1:routable', 'dummy97:routable', 'dummy98:routable', 'dummy99:degraded',
5667 'veth97:routable', 'veth97-peer:routable', 'veth98:routable', 'veth98-peer:routable'])
5668
5669 self.verify_dhcp4_6rd(tunnel_name)
5670
9633f977 5671class NetworkdIPv6PrefixTests(unittest.TestCase, Utilities):
9633f977
SS
5672
5673 def setUp(self):
a962d857 5674 setup_common()
9633f977
SS
5675
5676 def tearDown(self):
a962d857 5677 tear_down_common()
9633f977
SS
5678
5679 def test_ipv6_route_prefix(self):
a962d857
YW
5680 copy_network_unit('25-veth.netdev', '25-ipv6ra-prefix-client.network', '25-ipv6ra-prefix.network',
5681 '12-dummy.netdev', '25-ipv6ra-uplink.network')
9633f977
SS
5682
5683 start_networkd()
4a906586 5684 self.wait_online(['veth99:routable', 'veth-peer:routable', 'dummy98:routable'])
9633f977 5685
635f2a66
YW
5686 output = check_output('ip address show dev veth-peer')
5687 print(output)
5688 self.assertIn('inet6 2001:db8:0:1:', output)
5689 self.assertNotIn('inet6 2001:db8:0:2:', output)
ab47f960 5690 self.assertNotIn('inet6 2001:db8:0:3:', output)
635f2a66 5691
3c874fd7 5692 output = check_output('ip -6 route show dev veth-peer')
9633f977 5693 print(output)
635f2a66
YW
5694 self.assertIn('2001:db8:0:1::/64 proto ra', output)
5695 self.assertNotIn('2001:db8:0:2::/64 proto ra', output)
ab47f960 5696 self.assertNotIn('2001:db8:0:3::/64 proto ra', output)
635f2a66
YW
5697 self.assertIn('2001:db0:fff::/64 via ', output)
5698 self.assertNotIn('2001:db1:fff::/64 via ', output)
ab47f960 5699 self.assertNotIn('2001:db2:fff::/64 via ', output)
9633f977 5700
635f2a66
YW
5701 output = check_output('ip address show dev veth99')
5702 print(output)
5703 self.assertNotIn('inet6 2001:db8:0:1:', output)
fe2a8b3d
YW
5704 self.assertIn('inet6 2001:db8:0:2:1a:2b:3c:4d', output)
5705 self.assertIn('inet6 2001:db8:0:2:fa:de:ca:fe', output)
ab47f960 5706 self.assertNotIn('inet6 2001:db8:0:3:', output)
635f2a66 5707
4a906586
YW
5708 output = check_output(*resolvectl_cmd, 'dns', 'veth-peer', env=env)
5709 print(output)
5710 self.assertRegex(output, '2001:db8:1:1::2')
5711
5712 output = check_output(*resolvectl_cmd, 'domain', 'veth-peer', env=env)
5713 print(output)
5714 self.assertIn('example.com', output)
5715
94f0bd62
YW
5716 # TODO: check json string
5717 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
5718
635f2a66 5719 def test_ipv6_route_prefix_deny_list(self):
a962d857
YW
5720 copy_network_unit('25-veth.netdev', '25-ipv6ra-prefix-client-deny-list.network', '25-ipv6ra-prefix.network',
5721 '12-dummy.netdev', '25-ipv6ra-uplink.network')
635f2a66
YW
5722
5723 start_networkd()
4a906586 5724 self.wait_online(['veth99:routable', 'veth-peer:routable', 'dummy98:routable'])
635f2a66
YW
5725
5726 output = check_output('ip address show dev veth-peer')
5727 print(output)
5728 self.assertIn('inet6 2001:db8:0:1:', output)
5729 self.assertNotIn('inet6 2001:db8:0:2:', output)
5730
5731 output = check_output('ip -6 route show dev veth-peer')
5732 print(output)
5733 self.assertIn('2001:db8:0:1::/64 proto ra', output)
5734 self.assertNotIn('2001:db8:0:2::/64 proto ra', output)
5735 self.assertIn('2001:db0:fff::/64 via ', output)
5736 self.assertNotIn('2001:db1:fff::/64 via ', output)
5737
5738 output = check_output('ip address show dev veth99')
3c874fd7 5739 print(output)
635f2a66
YW
5740 self.assertNotIn('inet6 2001:db8:0:1:', output)
5741 self.assertIn('inet6 2001:db8:0:2:', output)
3c874fd7 5742
4a906586
YW
5743 output = check_output(*resolvectl_cmd, 'dns', 'veth-peer', env=env)
5744 print(output)
5745 self.assertRegex(output, '2001:db8:1:1::2')
5746
5747 output = check_output(*resolvectl_cmd, 'domain', 'veth-peer', env=env)
5748 print(output)
5749 self.assertIn('example.com', output)
5750
7db05447 5751class NetworkdMTUTests(unittest.TestCase, Utilities):
7db05447
DS
5752
5753 def setUp(self):
a962d857 5754 setup_common()
7db05447
DS
5755
5756 def tearDown(self):
a962d857 5757 tear_down_common()
7db05447
DS
5758
5759 def check_mtu(self, mtu, ipv6_mtu=None, reset=True):
5760 if not ipv6_mtu:
5761 ipv6_mtu = mtu
5762
5763 # test normal start
5764 start_networkd()
5765 self.wait_online(['dummy98:routable'])
a962d857
YW
5766 self.check_link_attr('dummy98', 'mtu', mtu)
5767 self.check_ipv6_sysctl_attr('dummy98', 'mtu', ipv6_mtu)
7db05447
DS
5768
5769 # test normal restart
5770 restart_networkd()
5771 self.wait_online(['dummy98:routable'])
a962d857
YW
5772 self.check_link_attr('dummy98', 'mtu', mtu)
5773 self.check_ipv6_sysctl_attr('dummy98', 'mtu', ipv6_mtu)
7db05447
DS
5774
5775 if reset:
5776 self.reset_check_mtu(mtu, ipv6_mtu)
5777
5778 def reset_check_mtu(self, mtu, ipv6_mtu=None):
5779 ''' test setting mtu/ipv6_mtu with interface already up '''
5780 stop_networkd()
5781
5782 # note - changing the device mtu resets the ipv6 mtu
a962d857
YW
5783 check_output('ip link set up mtu 1501 dev dummy98')
5784 check_output('ip link set up mtu 1500 dev dummy98')
5785 self.check_link_attr('dummy98', 'mtu', '1500')
5786 self.check_ipv6_sysctl_attr('dummy98', 'mtu', '1500')
7db05447
DS
5787
5788 self.check_mtu(mtu, ipv6_mtu, reset=False)
5789
5790 def test_mtu_network(self):
a962d857 5791 copy_network_unit('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
7db05447
DS
5792 self.check_mtu('1600')
5793
5794 def test_mtu_netdev(self):
a962d857 5795 copy_network_unit('12-dummy-mtu.netdev', '12-dummy.network', copy_dropins=False)
7db05447
DS
5796 # note - MTU set by .netdev happens ONLY at device creation!
5797 self.check_mtu('1600', reset=False)
5798
5799 def test_mtu_link(self):
a962d857 5800 copy_network_unit('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', copy_dropins=False)
7db05447
DS
5801 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
5802 self.check_mtu('1600', reset=False)
5803
5804 def test_ipv6_mtu(self):
5805 ''' set ipv6 mtu without setting device mtu '''
a962d857 5806 copy_network_unit('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
7db05447
DS
5807 self.check_mtu('1500', '1400')
5808
5809 def test_ipv6_mtu_toolarge(self):
5810 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
a962d857 5811 copy_network_unit('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
7db05447
DS
5812 self.check_mtu('1500', '1500')
5813
5814 def test_mtu_network_ipv6_mtu(self):
5815 ''' set ipv6 mtu and set device mtu via network file '''
a962d857 5816 copy_network_unit('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
7db05447
DS
5817 self.check_mtu('1600', '1550')
5818
5819 def test_mtu_netdev_ipv6_mtu(self):
5820 ''' set ipv6 mtu and set device mtu via netdev file '''
a962d857 5821 copy_network_unit('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
7db05447
DS
5822 self.check_mtu('1600', '1550', reset=False)
5823
5824 def test_mtu_link_ipv6_mtu(self):
5825 ''' set ipv6 mtu and set device mtu via link file '''
a962d857 5826 copy_network_unit('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
7db05447
DS
5827 self.check_mtu('1600', '1550', reset=False)
5828
5829
1f0e3109 5830if __name__ == '__main__':
9c1ae484
YW
5831 parser = argparse.ArgumentParser()
5832 parser.add_argument('--build-dir', help='Path to build dir', dest='build_dir')
5833 parser.add_argument('--networkd', help='Path to systemd-networkd', dest='networkd_bin')
b6d587d1 5834 parser.add_argument('--resolved', help='Path to systemd-resolved', dest='resolved_bin')
b05c4d6b 5835 parser.add_argument('--timesyncd', help='Path to systemd-timesyncd', dest='timesyncd_bin')
641aa412 5836 parser.add_argument('--udevd', help='Path to systemd-udevd', dest='udevd_bin')
9c1ae484
YW
5837 parser.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest='wait_online_bin')
5838 parser.add_argument('--networkctl', help='Path to networkctl', dest='networkctl_bin')
b6d587d1
YW
5839 parser.add_argument('--resolvectl', help='Path to resolvectl', dest='resolvectl_bin')
5840 parser.add_argument('--timedatectl', help='Path to timedatectl', dest='timedatectl_bin')
b05c4d6b 5841 parser.add_argument('--udevadm', help='Path to udevadm', dest='udevadm_bin')
9c1ae484
YW
5842 parser.add_argument('--valgrind', help='Enable valgrind', dest='use_valgrind', type=bool, nargs='?', const=True, default=use_valgrind)
5843 parser.add_argument('--debug', help='Generate debugging logs', dest='enable_debug', type=bool, nargs='?', const=True, default=enable_debug)
94c03122 5844 parser.add_argument('--asan-options', help='ASAN options', dest='asan_options')
fa4c6095 5845 parser.add_argument('--lsan-options', help='LSAN options', dest='lsan_options')
94c03122 5846 parser.add_argument('--ubsan-options', help='UBSAN options', dest='ubsan_options')
6c9efba6 5847 parser.add_argument('--with-coverage', help='Loosen certain sandbox restrictions to make gcov happy', dest='with_coverage', type=bool, nargs='?', const=True, default=with_coverage)
a561bcee 5848 ns, unknown_args = parser.parse_known_args(namespace=unittest)
9c1ae484
YW
5849
5850 if ns.build_dir:
b05c4d6b
YW
5851 if ns.networkd_bin or ns.resolved_bin or ns.timesyncd_bin or ns.udevd_bin or \
5852 ns.wait_online_bin or ns.networkctl_bin or ns.resolvectl_bin or ns.timedatectl_bin or ns.udevadm_bin:
5853 print('WARNING: --networkd, --resolved, --timesyncd, --udevd, --wait-online, --networkctl, --resolvectl, --timedatectl, or --udevadm options are ignored when --build-dir is specified.')
9c1ae484 5854 networkd_bin = os.path.join(ns.build_dir, 'systemd-networkd')
b6d587d1 5855 resolved_bin = os.path.join(ns.build_dir, 'systemd-resolved')
b05c4d6b 5856 timesyncd_bin = os.path.join(ns.build_dir, 'systemd-timesyncd')
641aa412 5857 udevd_bin = os.path.join(ns.build_dir, 'systemd-udevd')
9c1ae484
YW
5858 wait_online_bin = os.path.join(ns.build_dir, 'systemd-networkd-wait-online')
5859 networkctl_bin = os.path.join(ns.build_dir, 'networkctl')
b6d587d1
YW
5860 resolvectl_bin = os.path.join(ns.build_dir, 'resolvectl')
5861 timedatectl_bin = os.path.join(ns.build_dir, 'timedatectl')
b05c4d6b 5862 udevadm_bin = os.path.join(ns.build_dir, 'udevadm')
9c1ae484
YW
5863 else:
5864 if ns.networkd_bin:
5865 networkd_bin = ns.networkd_bin
b6d587d1
YW
5866 if ns.resolved_bin:
5867 resolved_bin = ns.resolved_bin
b05c4d6b
YW
5868 if ns.timesyncd_bin:
5869 timesyncd_bin = ns.timesyncd_bin
641aa412
YW
5870 if ns.udevd_bin:
5871 udevd_bin = ns.udevd_bin
9c1ae484
YW
5872 if ns.wait_online_bin:
5873 wait_online_bin = ns.wait_online_bin
5874 if ns.networkctl_bin:
5875 networkctl_bin = ns.networkctl_bin
b6d587d1
YW
5876 if ns.resolvectl_bin:
5877 resolvectl_bin = ns.resolvectl_bin
5878 if ns.timedatectl_bin:
5879 timedatectl_bin = ns.timedatectl_bin
b05c4d6b
YW
5880 if ns.udevadm_bin:
5881 udevadm_bin = ns.udevadm_bin
9c1ae484
YW
5882
5883 use_valgrind = ns.use_valgrind
5884 enable_debug = ns.enable_debug
94c03122 5885 asan_options = ns.asan_options
fa4c6095 5886 lsan_options = ns.lsan_options
94c03122 5887 ubsan_options = ns.ubsan_options
6c9efba6 5888 with_coverage = ns.with_coverage
9c1ae484
YW
5889
5890 if use_valgrind:
b05c4d6b
YW
5891 # Do not forget the trailing space.
5892 valgrind_cmd = 'valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all '
5893
5894 networkctl_cmd = valgrind_cmd.split() + [networkctl_bin]
5895 resolvectl_cmd = valgrind_cmd.split() + [resolvectl_bin]
5896 timedatectl_cmd = valgrind_cmd.split() + [timedatectl_bin]
5897 udevadm_cmd = valgrind_cmd.split() + [udevadm_bin]
5898 wait_online_cmd = valgrind_cmd.split() + [wait_online_bin]
9c1ae484 5899
94c03122 5900 if asan_options:
a962d857 5901 env.update({'ASAN_OPTIONS': asan_options})
fa4c6095 5902 if lsan_options:
a962d857 5903 env.update({'LSAN_OPTIONS': lsan_options})
94c03122 5904 if ubsan_options:
a962d857 5905 env.update({'UBSAN_OPTIONS': ubsan_options})
b05c4d6b
YW
5906 if use_valgrind:
5907 env.update({'SYSTEMD_MEMPOOL': '0'})
9c1ae484 5908
163d095f
YW
5909 wait_online_env = env.copy()
5910 if enable_debug:
a962d857 5911 wait_online_env.update({'SYSTEMD_LOG_LEVEL': 'debug'})
163d095f 5912
a561bcee 5913 sys.argv[1:] = unknown_args
0765763e 5914 unittest.main(verbosity=3)