]> git.ipfire.org Git - thirdparty/systemd.git/blame - test/test-network/systemd-networkd-tests.py
test-network: Make source directory optional
[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
1f0e3109
SS
3# systemd-networkd tests
4
0f1853e2 5# These tests can be executed in the systemd mkosi image when booted in QEMU. After booting the QEMU VM,
3ceb96e0 6# simply run this file which can be found in the VM at /usr/lib/systemd/tests/testdata/test-network/systemd-networkd-tests.py.
d4c8de21
MM
7#
8# To run an individual test, specify it as a command line argument in the form
9# of <class>.<test_function>. E.g. the NetworkdMTUTests class has a test
10# function called test_ipv6_mtu(). To run just that test use:
11#
12# sudo ./systemd-networkd-tests.py NetworkdMTUTests.test_ipv6_mtu
13#
68676af6 14# Similarly, other individual tests can be run, eg.:
d4c8de21
MM
15#
16# sudo ./systemd-networkd-tests.py NetworkdNetworkTests.test_ipv6_neigh_retrans_time
0f1853e2 17
9c1ae484 18import argparse
b65c5390 19import datetime
dded88ac 20import errno
7c0d36ff 21import itertools
aca99a3a 22import json
1f0e3109 23import os
a962d857 24import pathlib
6d1cea7b 25import random
201bf07f 26import re
1f0e3109
SS
27import shutil
28import signal
681007ac 29import socket
a9bc5e37
YW
30import subprocess
31import sys
a9bc5e37
YW
32import time
33import unittest
a962d857 34
ef11b841
FS
35import psutil
36
a962d857
YW
37network_unit_dir = '/run/systemd/network'
38networkd_conf_dropin_dir = '/run/systemd/networkd.conf.d'
39networkd_ci_temp_dir = '/run/networkd-ci'
40udev_rules_dir = '/run/udev/rules.d'
fa724cd5 41credstore_dir = '/run/credstore'
a962d857
YW
42
43dnsmasq_pid_file = '/run/networkd-ci/test-dnsmasq.pid'
44dnsmasq_log_file = '/run/networkd-ci/test-dnsmasq.log'
45dnsmasq_lease_file = '/run/networkd-ci/test-dnsmasq.lease'
46
47isc_dhcpd_pid_file = '/run/networkd-ci/test-isc-dhcpd.pid'
48isc_dhcpd_lease_file = '/run/networkd-ci/test-isc-dhcpd.lease'
49
c1dd58b3
FS
50radvd_pid_file = '/run/networkd-ci/test-radvd.pid'
51
a962d857
YW
52systemd_lib_paths = ['/usr/lib/systemd', '/lib/systemd']
53which_paths = ':'.join(systemd_lib_paths + os.getenv('PATH', os.defpath).lstrip(':').split(':'))
54
55networkd_bin = shutil.which('systemd-networkd', path=which_paths)
56resolved_bin = shutil.which('systemd-resolved', path=which_paths)
b05c4d6b 57timesyncd_bin = shutil.which('systemd-timesyncd', path=which_paths)
a962d857
YW
58wait_online_bin = shutil.which('systemd-networkd-wait-online', path=which_paths)
59networkctl_bin = shutil.which('networkctl', path=which_paths)
60resolvectl_bin = shutil.which('resolvectl', path=which_paths)
61timedatectl_bin = shutil.which('timedatectl', path=which_paths)
b05c4d6b 62udevadm_bin = shutil.which('udevadm', path=which_paths)
9dcdf16b 63test_ndisc_send = None
f66045c7
YW
64build_dir = None
65source_dir = None
a962d857
YW
66
67use_valgrind = False
b05c4d6b 68valgrind_cmd = ''
a962d857 69enable_debug = True
9c1ae484 70env = {}
163d095f 71wait_online_env = {}
a962d857
YW
72asan_options = None
73lsan_options = None
74ubsan_options = None
75with_coverage = False
76
77active_units = []
78protected_links = {
79 'erspan0',
80 'gre0',
81 'gretap0',
82 'ifb0',
83 'ifb1',
84 'ip6_vti0',
85 'ip6gre0',
86 'ip6tnl0',
87 'ip_vti0',
88 'lo',
89 'sit0',
90 'tunl0',
91}
92saved_routes = None
93saved_ipv4_rules = None
94saved_ipv6_rules = None
f54dce2d 95saved_timezone = None
a962d857
YW
96
97def rm_f(path):
98 if os.path.exists(path):
99 os.remove(path)
100
101def rm_rf(path):
102 shutil.rmtree(path, ignore_errors=True)
103
104def cp(src, dst):
105 shutil.copy(src, dst)
106
107def cp_r(src, dst):
108 shutil.copytree(src, dst, copy_function=shutil.copy)
109
110def mkdir_p(path):
111 os.makedirs(path, exist_ok=True)
112
113def touch(path):
114 pathlib.Path(path).touch()
115
f9073c24 116# pylint: disable=R1710
66504b22 117def check_output(*command, **kwargs):
a962d857
YW
118 # This checks the result and returns stdout (and stderr) on success.
119 command = command[0].split() + list(command[1:])
17479d51
YW
120 ret = subprocess.run(command, check=False, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kwargs)
121 if ret.returncode == 0:
122 return ret.stdout.rstrip()
123 # When returncode != 0, print stdout and stderr, then trigger CalledProcessError.
124 print(ret.stdout)
125 ret.check_returncode()
2225e7fd 126
66504b22 127def call(*command, **kwargs):
b5dac5b0 128 # This returns returncode. stdout and stderr are merged and shown in console
371810d1 129 command = command[0].split() + list(command[1:])
66504b22 130 return subprocess.run(command, check=False, universal_newlines=True, stderr=subprocess.STDOUT, **kwargs).returncode
371810d1 131
7e107bc3
FS
132def call_check(*command, **kwargs):
133 # Same as call() above, but it triggers CalledProcessError if rc != 0
134 command = command[0].split() + list(command[1:])
135 return subprocess.run(command, check=False, universal_newlines=True, stderr=subprocess.STDOUT, **kwargs).check_returncode()
136
66504b22 137def call_quiet(*command, **kwargs):
371810d1 138 command = command[0].split() + list(command[1:])
66504b22 139 return subprocess.run(command, check=False, universal_newlines=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, **kwargs).returncode
371810d1 140
66504b22 141def run(*command, **kwargs):
a962d857 142 # This returns CompletedProcess instance.
371810d1 143 command = command[0].split() + list(command[1:])
66504b22 144 return subprocess.run(command, check=False, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
371810d1 145
aca99a3a
FS
146def check_json(string):
147 try:
148 json.loads(string)
149 except json.JSONDecodeError:
150 print(f"String is not a valid JSON: '{string}'")
151 raise
152
59edcf2b
YW
153def is_module_available(*module_names):
154 for module_name in module_names:
155 lsmod_output = check_output('lsmod')
156 module_re = re.compile(rf'^{re.escape(module_name)}\b', re.MULTILINE)
157 if not module_re.search(lsmod_output) and call_quiet('modprobe', module_name) != 0:
158 return False
159 return True
160
161def expectedFailureIfModuleIsNotAvailable(*module_names):
7a0a37b2 162 def f(func):
59edcf2b 163 return func if is_module_available(*module_names) else unittest.expectedFailure(func)
7a0a37b2
EV
164
165 return f
166
2f0260c1
YW
167def expectedFailureIfERSPANv0IsNotSupported():
168 # erspan version 0 is supported since f989d546a2d5a9f001f6f8be49d98c10ab9b1897 (v5.8)
7bea7f9b 169 def f(func):
a962d857
YW
170 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')
171 remove_link('erspan99')
172 return func if rc == 0 else unittest.expectedFailure(func)
2f0260c1
YW
173
174 return f
175
176def expectedFailureIfERSPANv2IsNotSupported():
177 # erspan version 2 is supported since f551c91de262ba36b20c3ac19538afb4f4507441 (v4.16)
178 def f(func):
a962d857
YW
179 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')
180 remove_link('erspan99')
181 return func if rc == 0 else unittest.expectedFailure(func)
7bea7f9b
SS
182
183 return f
184
d586a2c3
YW
185def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable():
186 def f(func):
a962d857
YW
187 rc = call_quiet('ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
188 call_quiet('ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
189 return func if rc == 0 else unittest.expectedFailure(func)
d586a2c3
YW
190
191 return f
192
193def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
194 def f(func):
a962d857
YW
195 rc = call_quiet('ip rule add not from 192.168.100.19 ipproto tcp table 7')
196 call_quiet('ip rule del not from 192.168.100.19 ipproto tcp table 7')
197 return func if rc == 0 else unittest.expectedFailure(func)
d586a2c3
YW
198
199 return f
200
6be8e78e
YW
201def expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable():
202 def f(func):
a962d857
YW
203 supported = False
204 if call_quiet('ip rule add from 192.168.100.19 table 7 uidrange 200-300') == 0:
205 ret = run('ip rule list from 192.168.100.19 table 7')
206 supported = ret.returncode == 0 and 'uidrange 200-300' in ret.stdout
207 call_quiet('ip rule del from 192.168.100.19 table 7 uidrange 200-300')
208 return func if supported else unittest.expectedFailure(func)
6be8e78e
YW
209
210 return f
211
4be1fc84
NC
212def expectedFailureIfRoutingPolicyL3MasterDeviceIsNotAvailable():
213 def f(func):
214 rc = call_quiet('ip rule add not from 192.168.100.19 l3mdev')
215 call_quiet('ip rule del not from 192.168.100.19 l3mdev')
216 return func if rc == 0 else unittest.expectedFailure(func)
217
218 return f
219
086bcf5d
YW
220def expectedFailureIfNexthopIsNotAvailable():
221 def f(func):
a962d857
YW
222 rc = call_quiet('ip nexthop list')
223 return func if rc == 0 else unittest.expectedFailure(func)
086bcf5d
YW
224
225 return f
226
297f9d86
YW
227def expectedFailureIfRTA_VIAIsNotSupported():
228 def f(func):
a962d857
YW
229 call_quiet('ip link add dummy98 type dummy')
230 call_quiet('ip link set up dev dummy98')
231 call_quiet('ip route add 2001:1234:5:8fff:ff:ff:ff:fe/128 dev dummy98')
232 rc = call_quiet('ip route add 10.10.10.10 via inet6 2001:1234:5:8fff:ff:ff:ff:fe dev dummy98')
233 remove_link('dummy98')
234 return func if rc == 0 else unittest.expectedFailure(func)
297f9d86
YW
235
236 return f
237
6934ace0
YW
238def expectedFailureIfAlternativeNameIsNotAvailable():
239 def f(func):
a962d857
YW
240 call_quiet('ip link add dummy98 type dummy')
241 supported = \
242 call_quiet('ip link prop add dev dummy98 altname hogehogehogehogehoge') == 0 and \
243 call_quiet('ip link show dev hogehogehogehogehoge') == 0
244 remove_link('dummy98')
245 return func if supported else unittest.expectedFailure(func)
6934ace0
YW
246
247 return f
248
3d2c2692
YW
249def expectedFailureIfNetdevsimWithSRIOVIsNotAvailable():
250 def f(func):
a962d857
YW
251 def finalize(func, supported):
252 call_quiet('rmmod netdevsim')
253 return func if supported else unittest.expectedFailure(func)
254
255 call_quiet('rmmod netdevsim')
256 if call_quiet('modprobe netdevsim') != 0:
257 return finalize(func, False)
3d2c2692
YW
258
259 try:
d45476ef 260 with open('/sys/bus/netdevsim/new_device', mode='w', encoding='utf-8') as f:
3d2c2692 261 f.write('99 1')
54e2f32f 262 except OSError:
a962d857 263 return finalize(func, False)
3d2c2692 264
d8746f16 265 return finalize(func, os.path.exists('/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs'))
3d2c2692
YW
266
267 return f
268
b3de9d7b
FS
269# pylint: disable=C0415
270def compare_kernel_version(min_kernel_version):
271 try:
272 import platform
273 from packaging import version
274 except ImportError:
275 print('Failed to import either platform or packaging module, assuming the comparison failed')
276 return False
277
278 # Get only the actual kernel version without any build/distro/arch stuff
279 # e.g. '5.18.5-200.fc36.x86_64' -> '5.18.5'
280 kver = platform.release().split('-')[0]
0e808f62
TM
281 # Get also rid of '+'
282 kver = kver.split('+')[0]
b3de9d7b
FS
283
284 return version.parse(kver) >= version.parse(min_kernel_version)
285
a962d857
YW
286def copy_network_unit(*units, copy_dropins=True):
287 """
288 Copy networkd unit files into the testbed.
1f0e3109 289
a962d857 290 Any networkd unit file type can be specified, as well as drop-in files.
1f0e3109 291
a962d857
YW
292 By default, all drop-ins for a specified unit file are copied in;
293 to avoid that specify dropins=False.
3e3b0d2a 294
a962d857
YW
295 When a drop-in file is specified, its unit file is also copied in automatically.
296 """
32ab27af 297 has_link = False
a962d857
YW
298 mkdir_p(network_unit_dir)
299 for unit in units:
300 if copy_dropins and os.path.exists(os.path.join(networkd_ci_temp_dir, unit + '.d')):
301 cp_r(os.path.join(networkd_ci_temp_dir, unit + '.d'), os.path.join(network_unit_dir, unit + '.d'))
32ab27af 302
a962d857
YW
303 if unit.endswith('.conf'):
304 dropin = unit
305 unit = os.path.dirname(dropin).rstrip('.d')
306 dropindir = os.path.join(network_unit_dir, unit + '.d')
307 mkdir_p(dropindir)
308 cp(os.path.join(networkd_ci_temp_dir, dropin), dropindir)
32ab27af 309
a962d857
YW
310 cp(os.path.join(networkd_ci_temp_dir, unit), network_unit_dir)
311
32ab27af
YW
312 if unit.endswith('.link'):
313 has_link = True
314
315 if has_link:
a39a2a81 316 udevadm_reload()
32ab27af 317
fa724cd5
MY
318def copy_credential(src, target):
319 mkdir_p(credstore_dir)
320 cp(os.path.join(networkd_ci_temp_dir, src),
321 os.path.join(credstore_dir, target))
322
a962d857
YW
323def remove_network_unit(*units):
324 """
325 Remove previously copied unit files from the testbed.
326
327 Drop-ins will be removed automatically.
328 """
32ab27af 329 has_link = False
a962d857
YW
330 for unit in units:
331 rm_f(os.path.join(network_unit_dir, unit))
332 rm_rf(os.path.join(network_unit_dir, unit + '.d'))
333
32ab27af
YW
334 if unit.endswith('.link') or unit.endswith('.link.d'):
335 has_link = True
336
337 if has_link:
a39a2a81 338 udevadm_reload()
32ab27af 339
a962d857 340def clear_network_units():
32ab27af
YW
341 has_link = False
342 if os.path.exists(network_unit_dir):
343 units = os.listdir(network_unit_dir)
344 for unit in units:
345 if unit.endswith('.link') or unit.endswith('.link.d'):
346 has_link = True
347
a962d857
YW
348 rm_rf(network_unit_dir)
349
32ab27af 350 if has_link:
a39a2a81 351 udevadm_reload()
32ab27af 352
a962d857
YW
353def copy_networkd_conf_dropin(*dropins):
354 """Copy networkd.conf dropin files into the testbed."""
355 mkdir_p(networkd_conf_dropin_dir)
356 for dropin in dropins:
357 cp(os.path.join(networkd_ci_temp_dir, dropin), networkd_conf_dropin_dir)
358
359def remove_networkd_conf_dropin(*dropins):
360 """Remove previously copied networkd.conf dropin files from the testbed."""
361 for dropin in dropins:
362 rm_f(os.path.join(networkd_conf_dropin_dir, dropin))
363
364def clear_networkd_conf_dropins():
365 rm_rf(networkd_conf_dropin_dir)
366
33b0e0c0 367def setup_systemd_udev_rules():
f2adc1de 368 if not build_dir and not source_dir:
33b0e0c0
FS
369 return
370
371 mkdir_p(udev_rules_dir)
372
f66045c7 373 for path in [build_dir, source_dir]:
f2adc1de
DDM
374 if not path:
375 continue
376
f66045c7 377 path = os.path.join(path, "rules.d")
33b0e0c0
FS
378 print(f"Copying udev rules from {path} to {udev_rules_dir}")
379
380 for rule in os.listdir(path):
381 if not rule.endswith(".rules"):
382 continue
383 cp(os.path.join(path, rule), udev_rules_dir)
384
c84a5f5e
YW
385def clear_networkd_state_files():
386 rm_rf('/var/lib/systemd/network/')
387
a962d857
YW
388def copy_udev_rule(*rules):
389 """Copy udev rules"""
390 mkdir_p(udev_rules_dir)
391 for rule in rules:
392 cp(os.path.join(networkd_ci_temp_dir, rule), udev_rules_dir)
393
394def remove_udev_rule(*rules):
395 """Remove previously copied udev rules"""
396 for rule in rules:
397 rm_f(os.path.join(udev_rules_dir, rule))
398
399def clear_udev_rules():
400 rm_rf(udev_rules_dir)
401
402def save_active_units():
87b308c8 403 for u in ['systemd-networkd.socket', 'systemd-networkd.service',
b05c4d6b 404 'systemd-resolved.service', 'systemd-timesyncd.service',
f7ada4b8 405 'firewalld.service']:
2225e7fd 406 if call(f'systemctl is-active --quiet {u}') == 0:
a962d857
YW
407 call(f'systemctl stop {u}')
408 active_units.append(u)
409
410def restore_active_units():
411 if 'systemd-networkd.socket' in active_units:
412 call('systemctl stop systemd-networkd.socket systemd-networkd.service')
a962d857
YW
413 for u in active_units:
414 call(f'systemctl restart {u}')
415
93f5ae6b
YW
416def create_unit_dropin(unit, contents):
417 mkdir_p(f'/run/systemd/system/{unit}.d')
418 with open(f'/run/systemd/system/{unit}.d/00-override.conf', mode='w', encoding='utf-8') as f:
419 f.write('\n'.join(contents))
420
62eaf8d0 421def create_service_dropin(service, command, additional_settings=None):
c84a5f5e
YW
422 drop_in = ['[Service]']
423 if command:
424 drop_in += [
425 'ExecStart=',
426 f'ExecStart=!!{valgrind_cmd}{command}',
427 ]
b05c4d6b
YW
428 if enable_debug:
429 drop_in += ['Environment=SYSTEMD_LOG_LEVEL=debug']
430 if asan_options:
431 drop_in += [f'Environment=ASAN_OPTIONS="{asan_options}"']
432 if lsan_options:
433 drop_in += [f'Environment=LSAN_OPTIONS="{lsan_options}"']
434 if ubsan_options:
435 drop_in += [f'Environment=UBSAN_OPTIONS="{ubsan_options}"']
436 if asan_options or lsan_options or ubsan_options:
437 drop_in += ['SystemCallFilter=']
438 if use_valgrind or asan_options or lsan_options or ubsan_options:
439 drop_in += ['MemoryDenyWriteExecute=no']
440 if use_valgrind:
441 drop_in += [
442 'Environment=SYSTEMD_MEMPOOL=0',
443 'PrivateTmp=yes',
444 ]
445 if with_coverage:
446 drop_in += [
447 'ProtectSystem=no',
448 'ProtectHome=no',
449 ]
450 if additional_settings:
451 drop_in += additional_settings
452
93f5ae6b 453 create_unit_dropin(f'{service}.service', drop_in)
b05c4d6b 454
83cc1825 455def setup_system_units():
f2adc1de 456 if build_dir or source_dir:
83cc1825
YW
457 mkdir_p('/run/systemd/system/')
458
459 for unit in [
460 'systemd-networkd.service',
461 'systemd-networkd.socket',
c84a5f5e 462 'systemd-networkd-persistent-storage.service',
83cc1825
YW
463 'systemd-resolved.service',
464 'systemd-timesyncd.service',
465 'systemd-udevd.service',
466 ]:
467 for path in [build_dir, source_dir]:
f2adc1de
DDM
468 if not path:
469 continue
470
83cc1825
YW
471 fullpath = os.path.join(os.path.join(path, "units"), unit)
472 if os.path.exists(fullpath):
473 print(f"Copying unit file from {fullpath} to /run/systemd/system/")
474 cp(fullpath, '/run/systemd/system/')
475 break
476
477 create_service_dropin('systemd-networkd', networkd_bin,
478 ['[Service]',
479 'Restart=no',
480 'Environment=SYSTEMD_NETWORK_TEST_MODE=yes',
481 '[Unit]',
482 'StartLimitIntervalSec=0'])
483 create_service_dropin('systemd-resolved', resolved_bin)
484 create_service_dropin('systemd-timesyncd', timesyncd_bin)
485
486 # TODO: also run udevd with sanitizers, valgrind, or coverage
487 create_unit_dropin(
488 'systemd-udevd.service',
489 [
490 '[Service]',
491 'ExecStart=',
492 f'ExecStart=!!@{udevadm_bin} systemd-udevd',
493 ]
494 )
495 create_unit_dropin(
496 'systemd-networkd.socket',
497 [
498 '[Unit]',
499 'StartLimitIntervalSec=0',
500 ]
501 )
c84a5f5e
YW
502 create_unit_dropin(
503 'systemd-networkd-persistent-storage.service',
504 [
505 '[Unit]',
506 'StartLimitIntervalSec=0',
507 '[Service]',
508 'ExecStart=',
509 f'ExecStart={networkctl_bin} persistent-storage yes',
510 'ExecStop=',
511 f'ExecStop={networkctl_bin} persistent-storage no'
512 ]
513 )
83cc1825
YW
514
515 check_output('systemctl daemon-reload')
516 print(check_output('systemctl cat systemd-networkd.service'))
c84a5f5e 517 print(check_output('systemctl cat systemd-networkd-persistent-storage.service'))
83cc1825
YW
518 print(check_output('systemctl cat systemd-resolved.service'))
519 print(check_output('systemctl cat systemd-timesyncd.service'))
520 print(check_output('systemctl cat systemd-udevd.service'))
521 check_output('systemctl restart systemd-resolved.service')
522 check_output('systemctl restart systemd-timesyncd.service')
523 check_output('systemctl restart systemd-udevd.service')
524
525def clear_system_units():
526 def rm_unit(name):
527 rm_f(f'/run/systemd/system/{name}')
528 rm_rf(f'/run/systemd/system/{name}.d')
529
530 rm_unit('systemd-networkd.service')
531 rm_unit('systemd-networkd.socket')
c84a5f5e 532 rm_unit('systemd-networkd-persistent-storage.service')
83cc1825
YW
533 rm_unit('systemd-resolved.service')
534 rm_unit('systemd-timesyncd.service')
535 rm_unit('systemd-udevd.service')
536 check_output('systemctl daemon-reload')
537 check_output('systemctl restart systemd-udevd.service')
538
a962d857 539def link_exists(link):
dee6c26f 540 return call_quiet(f'ip link show {link}') == 0
a962d857 541
b95d35b5
YW
542def link_resolve(link):
543 return check_output(f'ip link show {link}').split(':')[1].strip()
a962d857
YW
544
545def remove_link(*links, protect=False):
546 for link in links:
547 if protect and link in protected_links:
548 continue
549 if link_exists(link):
550 call(f'ip link del dev {link}')
551
552def save_existing_links():
553 links = os.listdir('/sys/class/net')
554 for link in links:
555 if link_exists(link):
556 protected_links.add(link)
557
558 print('### The following links will be protected:')
559 print(', '.join(sorted(list(protected_links))))
560
561def flush_links():
562 links = os.listdir('/sys/class/net')
563 remove_link(*links, protect=True)
564
565def flush_nexthops():
566 # Currently, the 'ip nexthop' command does not have 'save' and 'restore'.
567 # Hence, we cannot restore nexthops in a simple way.
568 # Let's assume there is no nexthop used in the system
569 call_quiet('ip nexthop flush')
570
571def save_routes():
572 # pylint: disable=global-statement
573 global saved_routes
574 saved_routes = check_output('ip route show table all')
575 print('### The following routes will be protected:')
576 print(saved_routes)
577
578def flush_routes():
579 have = False
580 output = check_output('ip route show table all')
581 for line in output.splitlines():
582 if line in saved_routes:
583 continue
584 if 'proto kernel' in line:
585 continue
586 if ' dev ' in line and not ' dev lo ' in line:
587 continue
588 if not have:
589 have = True
590 print('### Removing routes that did not exist when the test started.')
591 print(f'# {line}')
592 call(f'ip route del {line}')
593
594def save_routing_policy_rules():
595 # pylint: disable=global-statement
596 global saved_ipv4_rules, saved_ipv6_rules
597 def save(ipv):
598 output = check_output(f'ip -{ipv} rule show')
599 print(f'### The following IPv{ipv} routing policy rules will be protected:')
600 print(output)
601 return output
602
603 saved_ipv4_rules = save(4)
604 saved_ipv6_rules = save(6)
605
606def flush_routing_policy_rules():
607 def flush(ipv, saved_rules):
608 have = False
609 output = check_output(f'ip -{ipv} rule show')
610 for line in output.splitlines():
611 if line in saved_rules:
612 continue
613 if not have:
614 have = True
615 print(f'### Removing IPv{ipv} routing policy rules that did not exist when the test started.')
616 print(f'# {line}')
e755ad61 617 words = line.replace('lookup [l3mdev-table]', 'l3mdev').split()
a962d857
YW
618 priority = words[0].rstrip(':')
619 call(f'ip -{ipv} rule del priority {priority} ' + ' '.join(words[1:]))
620
621 flush(4, saved_ipv4_rules)
622 flush(6, saved_ipv6_rules)
623
624def flush_fou_ports():
625 ret = run('ip fou show')
626 if ret.returncode != 0:
627 return # fou may not be supported
628 for line in ret.stdout.splitlines():
629 port = line.split()[1]
630 call(f'ip fou del port {port}')
631
632def flush_l2tp_tunnels():
e11d0e39 633 tids = []
49ad2872
YW
634 ret = run('ip l2tp show tunnel')
635 if ret.returncode != 0:
636 return # l2tp may not be supported
637 for line in ret.stdout.splitlines():
a962d857
YW
638 words = line.split()
639 if words[0] == 'Tunnel':
640 tid = words[1].rstrip(',')
641 call(f'ip l2tp del tunnel tunnel_id {tid}')
e11d0e39
YW
642 tids.append(tid)
643
644 # Removing L2TP tunnel is asynchronous and slightly takes a time.
645 for tid in tids:
646 for _ in range(50):
647 r = run(f'ip l2tp show tunnel tunnel_id {tid}')
648 if r.returncode != 0 or len(r.stdout.rstrip()) == 0:
649 break
650 time.sleep(.2)
651 else:
652 print(f'Cannot remove L2TP tunnel {tid}, ignoring.')
a962d857 653
f54dce2d 654def save_timezone():
f9073c24 655 # pylint: disable=global-statement
f54dce2d 656 global saved_timezone
67a9b3ec 657 r = run(*timedatectl_cmd, 'show', '--value', '--property', 'Timezone', env=env)
f54dce2d
YW
658 if r.returncode == 0:
659 saved_timezone = r.stdout.rstrip()
660 print(f'### Saved timezone: {saved_timezone}')
661
662def restore_timezone():
663 if saved_timezone:
67a9b3ec 664 call(*timedatectl_cmd, 'set-timezone', f'{saved_timezone}', env=env)
f54dce2d 665
a962d857
YW
666def read_link_attr(*args):
667 with open(os.path.join('/sys/class/net', *args), encoding='utf-8') as f:
668 return f.readline().strip()
669
34290c6a
YW
670def read_manager_state_file():
671 with open('/run/systemd/netif/state', encoding='utf-8') as f:
672 return f.read()
673
a962d857
YW
674def read_link_state_file(link):
675 ifindex = read_link_attr(link, 'ifindex')
676 path = os.path.join('/run/systemd/netif/links', ifindex)
677 with open(path, encoding='utf-8') as f:
678 return f.read()
679
680def read_ip_sysctl_attr(link, attribute, ipv):
681 with open(os.path.join('/proc/sys/net', ipv, 'conf', link, attribute), encoding='utf-8') as f:
682 return f.readline().strip()
683
d4c8de21
MM
684def read_ip_neigh_sysctl_attr(link, attribute, ipv):
685 with open(os.path.join('/proc/sys/net', ipv, 'neigh', link, attribute), encoding='utf-8') as f:
686 return f.readline().strip()
687
a962d857
YW
688def read_ipv6_sysctl_attr(link, attribute):
689 return read_ip_sysctl_attr(link, attribute, 'ipv6')
690
d4c8de21
MM
691def read_ipv6_neigh_sysctl_attr(link, attribute):
692 return read_ip_neigh_sysctl_attr(link, attribute, 'ipv6')
693
a962d857
YW
694def read_ipv4_sysctl_attr(link, attribute):
695 return read_ip_sysctl_attr(link, attribute, 'ipv4')
696
c1dd58b3
FS
697def stop_by_pid_file(pid_file):
698 if not os.path.exists(pid_file):
699 return
700 with open(pid_file, 'r', encoding='utf-8') as f:
701 pid = f.read().rstrip(' \t\r\n\0')
702 os.kill(int(pid), signal.SIGTERM)
703 for _ in range(25):
704 try:
705 os.kill(int(pid), 0)
706 print(f"PID {pid} is still alive, waiting...")
707 time.sleep(.2)
708 except OSError as e:
709 if e.errno == errno.ESRCH:
710 break
711 print(f"Unexpected exception when waiting for {pid} to die: {e.errno}")
712 rm_f(pid_file)
713
2d7ca6b4
YW
714def start_dnsmasq(*additional_options, interface='veth-peer', ra_mode=None, ipv4_range='192.168.5.10,192.168.5.200', ipv4_router='192.168.5.1', ipv6_range='2600::10,2600::20'):
715 if ra_mode:
716 ra_mode = f',{ra_mode}'
717 else:
718 ra_mode = ''
719
a962d857
YW
720 command = (
721 'dnsmasq',
722 f'--log-facility={dnsmasq_log_file}',
723 '--log-queries=extra',
724 '--log-dhcp',
725 f'--pid-file={dnsmasq_pid_file}',
726 '--conf-file=/dev/null',
727 '--bind-interfaces',
728 f'--interface={interface}',
729 f'--dhcp-leasefile={dnsmasq_lease_file}',
730 '--enable-ra',
2d7ca6b4
YW
731 f'--dhcp-range={ipv6_range}{ra_mode},2m',
732 f'--dhcp-range={ipv4_range},2m',
a962d857
YW
733 '--dhcp-option=option:mtu,1492',
734 f'--dhcp-option=option:router,{ipv4_router}',
735 '--port=0',
736 '--no-resolv',
737 ) + additional_options
738 check_output(*command)
739
a962d857
YW
740def stop_dnsmasq():
741 stop_by_pid_file(dnsmasq_pid_file)
742 rm_f(dnsmasq_lease_file)
743 rm_f(dnsmasq_log_file)
744
745def read_dnsmasq_log_file():
746 with open(dnsmasq_log_file, encoding='utf-8') as f:
747 return f.read()
748
749def start_isc_dhcpd(conf_file, ipv, interface='veth-peer'):
750 conf_file_path = os.path.join(networkd_ci_temp_dir, conf_file)
751 isc_dhcpd_command = f'dhcpd {ipv} -cf {conf_file_path} -lf {isc_dhcpd_lease_file} -pf {isc_dhcpd_pid_file} {interface}'
752 touch(isc_dhcpd_lease_file)
753 check_output(isc_dhcpd_command)
754
755def stop_isc_dhcpd():
756 stop_by_pid_file(isc_dhcpd_pid_file)
757 rm_f(isc_dhcpd_lease_file)
758
e081ffc1
YW
759def get_dbus_link_path(link):
760 out = subprocess.check_output(['busctl', 'call', 'org.freedesktop.network1',
761 '/org/freedesktop/network1', 'org.freedesktop.network1.Manager',
762 'GetLinkByName', 's', link])
763
764 assert out.startswith(b'io ')
765 out = out.strip()
766 assert out.endswith(b'"')
767 out = out.decode()
768 return out[:-1].split('"')[1]
769
770def get_dhcp_client_state(link, family):
771 link_path = get_dbus_link_path(link)
772
773 out = subprocess.check_output(['busctl', 'get-property', 'org.freedesktop.network1',
774 link_path, f'org.freedesktop.network1.DHCPv{family}Client', 'State'])
775 assert out.startswith(b's "')
776 out = out.strip()
777 assert out.endswith(b'"')
778 return out[3:-1].decode()
779
780def get_dhcp4_client_state(link):
781 return get_dhcp_client_state(link, '4')
782
783def get_dhcp6_client_state(link):
784 return get_dhcp_client_state(link, '6')
785
786def get_link_description(link):
787 link_path = get_dbus_link_path(link)
788
789 out = subprocess.check_output(['busctl', 'call', 'org.freedesktop.network1',
790 link_path, 'org.freedesktop.network1.Link', 'Describe'])
791 assert out.startswith(b's "')
792 out = out.strip()
793 assert out.endswith(b'"')
794 json_raw = out[2:].decode()
795 check_json(json_raw)
796 description = json.loads(json_raw) # Convert from escaped sequences to json
797 check_json(description)
798 return json.loads(description) # Now parse the json
799
c1dd58b3
FS
800def start_radvd(*additional_options, config_file):
801 config_file_path = os.path.join(networkd_ci_temp_dir, 'radvd', config_file)
802 command = (
803 'radvd',
804 f'--pidfile={radvd_pid_file}',
805 f'--config={config_file_path}',
806 '--logmethod=stderr',
807 ) + additional_options
808 check_output(*command)
809
810def stop_radvd():
811 stop_by_pid_file(radvd_pid_file)
812
813def radvd_check_config(config_file):
814 if not shutil.which('radvd'):
815 print('radvd is not installed, assuming the config check failed')
816 return False
817
818 # Note: can't use networkd_ci_temp_dir here, as this command may run before that dir is
819 # set up (one instance is @unittest.skipX())
820 config_file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'conf/radvd', config_file)
821 return call(f'radvd --config={config_file_path} --configtest') == 0
822
5bd2a7c5
YW
823def networkd_invocation_id():
824 return check_output('systemctl show --value -p InvocationID systemd-networkd.service')
825
b65c5390 826def read_networkd_log(invocation_id=None, since=None):
5bd2a7c5
YW
827 if not invocation_id:
828 invocation_id = networkd_invocation_id()
b65c5390
YW
829 command = [
830 'journalctl',
dc60ac29
YW
831 '--no-hostname',
832 '--output=short-monotonic',
b65c5390
YW
833 f'_SYSTEMD_INVOCATION_ID={invocation_id}',
834 ]
835 if since:
836 command.append(f'--since={since}')
bd581438 837 check_output('journalctl --sync')
b65c5390 838 return check_output(*command)
5bd2a7c5 839
6b07675d
YW
840def networkd_is_failed():
841 return call_quiet('systemctl is-failed -q systemd-networkd.service') != 1
842
a962d857
YW
843def stop_networkd(show_logs=True):
844 if show_logs:
5bd2a7c5 845 invocation_id = networkd_invocation_id()
a962d857
YW
846 check_output('systemctl stop systemd-networkd.socket')
847 check_output('systemctl stop systemd-networkd.service')
848 if show_logs:
5bd2a7c5 849 print(read_networkd_log(invocation_id))
7618fd06 850 # Check if networkd exits cleanly.
6b07675d 851 assert not networkd_is_failed()
a962d857
YW
852
853def start_networkd():
854 check_output('systemctl start systemd-networkd')
855
856def restart_networkd(show_logs=True):
85b1a14d 857 if show_logs:
5bd2a7c5 858 invocation_id = networkd_invocation_id()
85b1a14d
YW
859 check_output('systemctl restart systemd-networkd.service')
860 if show_logs:
5bd2a7c5 861 print(read_networkd_log(invocation_id))
a962d857 862
ae014ecb
YW
863def networkd_pid():
864 return int(check_output('systemctl show --value -p MainPID systemd-networkd.service'))
865
10d670a3 866def networkctl(*args):
6b07675d
YW
867 # Do not call networkctl if networkd is in failed state.
868 # Otherwise, networkd may be restarted and we may get wrong results.
869 assert not networkd_is_failed()
10d670a3
YW
870 return check_output(*(networkctl_cmd + list(args)), env=env)
871
872def networkctl_status(*args):
873 return networkctl('-n', '0', 'status', *args)
874
875def networkctl_json(*args):
876 return networkctl('--json=short', 'status', *args)
877
a962d857 878def networkctl_reconfigure(*links):
10d670a3 879 networkctl('reconfigure', *links)
a962d857 880
4bc771d0 881def networkctl_reload():
10d670a3 882 networkctl('reload')
a962d857 883
10d670a3
YW
884def resolvectl(*args):
885 return check_output(*(resolvectl_cmd + list(args)), env=env)
886
887def timedatectl(*args):
888 return check_output(*(timedatectl_cmd + list(args)), env=env)
889
a39a2a81
YW
890def udevadm(*args):
891 return check_output(*(udevadm_cmd + list(args)))
892
893def udevadm_reload():
894 udevadm('control', '--reload')
895
896def udevadm_trigger(*args, action='add'):
897 udevadm('trigger', '--settle', f'--action={action}', *args)
898
a962d857
YW
899def setup_common():
900 print()
901
902def tear_down_common():
c1dd58b3 903 # 1. stop DHCP/RA servers
a962d857
YW
904 stop_dnsmasq()
905 stop_isc_dhcpd()
c1dd58b3 906 stop_radvd()
a962d857
YW
907
908 # 2. remove modules
909 call_quiet('rmmod netdevsim')
910 call_quiet('rmmod sch_teql')
911
912 # 3. remove network namespace
913 call_quiet('ip netns del ns99')
914
915 # 4. remove links
e11d0e39 916 flush_l2tp_tunnels()
a962d857
YW
917 flush_links()
918
919 # 5. stop networkd
249b7ecc 920 stop_networkd()
a962d857
YW
921
922 # 6. remove configs
923 clear_network_units()
924 clear_networkd_conf_dropins()
c84a5f5e 925 clear_networkd_state_files()
a962d857
YW
926
927 # 7. flush settings
928 flush_fou_ports()
a962d857
YW
929 flush_nexthops()
930 flush_routing_policy_rules()
931 flush_routes()
932
933def setUpModule():
934 rm_rf(networkd_ci_temp_dir)
935 cp_r(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'conf'), networkd_ci_temp_dir)
936
937 clear_network_units()
938 clear_networkd_conf_dropins()
c84a5f5e 939 clear_networkd_state_files()
a962d857
YW
940 clear_udev_rules()
941
33b0e0c0 942 setup_systemd_udev_rules()
a962d857
YW
943 copy_udev_rule('00-debug-net.rules')
944
945 # Save current state
946 save_active_units()
947 save_existing_links()
948 save_routes()
949 save_routing_policy_rules()
f54dce2d 950 save_timezone()
c0bf6733 951
83cc1825 952 setup_system_units()
9c1ae484 953
1f0e3109 954def tearDownModule():
a962d857
YW
955 rm_rf(networkd_ci_temp_dir)
956 clear_udev_rules()
957 clear_network_units()
958 clear_networkd_conf_dropins()
c84a5f5e 959 clear_networkd_state_files()
a962d857 960
f54dce2d
YW
961 restore_timezone()
962
83cc1825 963 clear_system_units()
a962d857 964 restore_active_units()
ec38833c 965
a962d857
YW
966class Utilities():
967 # pylint: disable=no-member
caad88a2 968
a962d857
YW
969 def check_link_exists(self, link, expected=True):
970 if expected:
971 self.assertTrue(link_exists(link))
972 else:
973 self.assertFalse(link_exists(link))
caad88a2 974
a962d857
YW
975 def check_link_attr(self, *args):
976 self.assertEqual(read_link_attr(*args[:-1]), args[-1])
aaae5713 977
a962d857
YW
978 def check_bridge_port_attr(self, master, port, attribute, expected, allow_enoent=False):
979 path = os.path.join('/sys/devices/virtual/net', master, 'lower_' + port, 'brport', attribute)
980 if allow_enoent and not os.path.exists(path):
981 return
982 with open(path, encoding='utf-8') as f:
983 self.assertEqual(f.readline().strip(), expected)
aaae5713 984
a962d857
YW
985 def check_ipv4_sysctl_attr(self, link, attribute, expected):
986 self.assertEqual(read_ipv4_sysctl_attr(link, attribute), expected)
ec38833c 987
a962d857
YW
988 def check_ipv6_sysctl_attr(self, link, attribute, expected):
989 self.assertEqual(read_ipv6_sysctl_attr(link, attribute), expected)
aaae5713 990
d4c8de21
MM
991 def check_ipv6_neigh_sysctl_attr(self, link, attribute, expected):
992 self.assertEqual(read_ipv6_neigh_sysctl_attr(link, attribute), expected)
993
a962d857
YW
994 def wait_links(self, *links, timeout=20, fail_assert=True):
995 def links_exist(*links):
996 for link in links:
997 if not link_exists(link):
998 return False
999 return True
524cc9d1 1000
a962d857
YW
1001 for iteration in range(timeout + 1):
1002 if iteration > 0:
1003 time.sleep(1)
2be0b6fc 1004
a962d857
YW
1005 if links_exist(*links):
1006 return True
1007 if fail_assert:
1008 self.fail('Timed out waiting for all links to be created: ' + ', '.join(list(links)))
1009 return False
0fc0d85f 1010
cfbdc438
YW
1011 def wait_activated(self, link, state='down', timeout=20, fail_assert=True):
1012 # wait for the interface is activated.
cfbdc438
YW
1013 needle = f'{link}: Bringing link {state}'
1014 flag = state.upper()
a962d857 1015 for iteration in range(timeout + 1):
459c35d4
YW
1016 if iteration != 0:
1017 time.sleep(1)
1018 if not link_exists(link):
1019 continue
032fd10d 1020 output = read_networkd_log()
cfbdc438
YW
1021 if needle in output and flag in check_output(f'ip link show {link}'):
1022 return True
cfbdc438
YW
1023 if fail_assert:
1024 self.fail(f'Timed out waiting for {link} activated.')
1025 return False
1026
a4632dc7
DS
1027 def wait_operstate(self, link, operstate='degraded', setup_state='configured', setup_timeout=5, fail_assert=True):
1028 """Wait for the link to reach the specified operstate and/or setup state.
1029
1030 Specify None or '' for either operstate or setup_state to ignore that state.
1031 This will recheck until the state conditions are met or the timeout expires.
1032
1033 If the link successfully matches the requested state, this returns True.
1034 If this times out waiting for the link to match, the behavior depends on the
1035 'fail_assert' parameter; if True, this causes a test assertion failure,
1036 otherwise this returns False. The default is to cause assertion failure.
1037
1038 Note that this function matches on *exactly* the given operstate and setup_state.
1039 To wait for a link to reach *or exceed* a given operstate, use wait_online().
1040 """
1041 if not operstate:
1042 operstate = r'\S+'
1043 if not setup_state:
1044 setup_state = r'\S+'
1045
1046 for secs in range(setup_timeout + 1):
459c35d4
YW
1047 if secs != 0:
1048 time.sleep(1)
1049 if not link_exists(link):
1050 continue
10d670a3 1051 output = networkctl_status(link)
a4632dc7
DS
1052 if re.search(rf'(?m)^\s*State:\s+{operstate}\s+\({setup_state}\)\s*$', output):
1053 return True
894ff7d1 1054
a4632dc7
DS
1055 if fail_assert:
1056 self.fail(f'Timed out waiting for {link} to reach state {operstate}/{setup_state}')
1057 return False
2be0b6fc 1058
95e1fbba 1059 def wait_online(self, *links_with_operstate, timeout='20s', bool_any=False, ipv4=False, ipv6=False, setup_state='configured', setup_timeout=5):
0923b425 1060 """Wait for the links to reach the specified operstate and/or setup state.
0c020321
DS
1061
1062 This is similar to wait_operstate() but can be used for multiple links,
1063 and it also calls systemd-networkd-wait-online to wait for the given operstate.
1064 The operstate should be specified in the link name, like 'eth0:degraded'.
1065 If just a link name is provided, wait-online's default operstate to wait for is degraded.
1066
1067 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
1068 'setup_timeout' controls the per-link timeout waiting for the setup_state.
1069
1070 Set 'bool_any' to True to wait for any (instead of all) of the given links.
1071 If this is set, no setup_state checks are done.
1072
70448bb1
L
1073 Set 'ipv4' or 'ipv6' to True to wait for IPv4 address or IPv6 address, respectively, of each of the given links.
1074 This is applied only for the operational state 'degraded' or above.
1075
0923b425 1076 Note that this function waits for the links to reach *or exceed* the given operstate.
0c020321
DS
1077 However, the setup_state, if specified, must be matched *exactly*.
1078
0923b425 1079 This returns if the links reached the requested operstate/setup_state; otherwise it
0c020321
DS
1080 raises CalledProcessError or fails test assertion.
1081 """
56dfde0d 1082 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
1083 if bool_any:
1084 args += ['--any']
70448bb1
L
1085 if ipv4:
1086 args += ['--ipv4']
1087 if ipv6:
1088 args += ['--ipv6']
e2aea43f 1089 try:
163d095f 1090 check_output(*args, env=wait_online_env)
f9073c24 1091 except subprocess.CalledProcessError:
6b07675d
YW
1092 if networkd_is_failed():
1093 print('!!!!! systemd-networkd.service is failed !!!!!')
1094 call('systemctl status systemd-networkd.service')
1095 else:
1096 # show detailed status on failure
1097 for link in links_with_operstate:
1098 name = link.split(':')[0]
1099 if link_exists(name):
68543224
YW
1100 print(networkctl_status(name))
1101 else:
1102 print(f'Interface {name} not found.')
e2aea43f 1103 raise
fd372b1a 1104 if not bool_any and setup_state:
0c020321
DS
1105 for link in links_with_operstate:
1106 self.wait_operstate(link.split(':')[0], None, setup_state, setup_timeout)
e2aea43f 1107
53c32c2b 1108 def wait_address(self, link, address_regex, scope='global', ipv='', timeout_sec=100):
2629df47
YW
1109 for i in range(timeout_sec):
1110 if i > 0:
1111 time.sleep(1)
371810d1 1112 output = check_output(f'ip {ipv} address show dev {link} scope {scope}')
571f9539 1113 if re.search(address_regex, output) and 'tentative' not in output:
2629df47 1114 break
240e4137
YW
1115
1116 self.assertRegex(output, address_regex)
1117
1118 def wait_address_dropped(self, link, address_regex, scope='global', ipv='', timeout_sec=100):
1119 for i in range(timeout_sec):
1120 if i > 0:
1121 time.sleep(1)
1122 output = check_output(f'ip {ipv} address show dev {link} scope {scope}')
1123 if not re.search(address_regex, output):
1124 break
1125
1126 self.assertNotRegex(output, address_regex)
2629df47 1127
bb80f633
YW
1128 def wait_route(self, link, route_regex, table='main', ipv='', timeout_sec=100):
1129 for i in range(timeout_sec):
1130 if i > 0:
1131 time.sleep(1)
1132 output = check_output(f'ip {ipv} route show dev {link} table {table}')
1133 if re.search(route_regex, output):
1134 break
1135
1136 self.assertRegex(output, route_regex)
1137
9dcdf16b
YW
1138 def wait_route_dropped(self, link, route_regex, table='main', ipv='', timeout_sec=100):
1139 for i in range(timeout_sec):
1140 if i > 0:
1141 time.sleep(1)
1142 output = check_output(f'ip {ipv} route show dev {link} table {table}')
1143 if not re.search(route_regex, output):
1144 break
1145
1146 self.assertNotRegex(output, route_regex)
1147
a4640bed
TM
1148 def check_netlabel(self, interface, address, label='system_u:object_r:root_t:s0'):
1149 if not shutil.which('selinuxenabled'):
e4377659 1150 print('## Checking NetLabel skipped: selinuxenabled command not found.')
a4640bed 1151 elif call_quiet('selinuxenabled') != 0:
e4377659 1152 print('## Checking NetLabel skipped: SELinux disabled.')
a4640bed 1153 elif not shutil.which('netlabelctl'): # not packaged by all distros
e4377659 1154 print('## Checking NetLabel skipped: netlabelctl command not found.')
a4640bed
TM
1155 else:
1156 output = check_output('netlabelctl unlbl list')
1157 print(output)
1158 self.assertRegex(output, f'interface:{interface},address:{address},label:"{label}"')
1159
c742d7e8
TM
1160 def setup_nftset(self, filter_name, filter_type, flags=''):
1161 if not shutil.which('nft'):
1162 print('## Setting up NFT sets skipped: nft command not found.')
1163 else:
1164 if call(f'nft add table inet sd_test') != 0:
1165 print('## Setting up NFT table failed.')
1166 self.fail()
1167 if call(f'nft add set inet sd_test {filter_name} {{ type {filter_type}; {flags} }}') != 0:
1168 print('## Setting up NFT sets failed.')
1169 self.fail()
1170
1171 def teardown_nftset(self, *filters):
1172 if not shutil.which('nft'):
1173 print('## Tearing down NFT sets skipped: nft command not found.')
1174 else:
1175 for filter_name in filters:
1176 if call(f'nft delete set inet sd_test {filter_name}') != 0:
1177 print('## Tearing down NFT sets failed.')
1178 self.fail()
1179 if call(f'nft delete table inet sd_test') != 0:
1180 print('## Tearing down NFT table failed.')
1181 self.fail()
1182
1183 def check_nftset(self, filter_name, contents):
1184 if not shutil.which('nft'):
1185 print('## Checking NFT sets skipped: nft command not found.')
1186 else:
1187 output = check_output(f'nft list set inet sd_test {filter_name}')
1188 print(output)
1189 self.assertRegex(output, r'.*elements = { [^}]*' + contents + r'[^}]* }.*')
1190
45c2bbba
YW
1191 def check_networkd_log(self, contents, since=None, trial=20):
1192 for _ in range(trial):
1193 if contents in read_networkd_log(since=since):
1194 break
1195 time.sleep(0.5)
1196 else:
1197 self.fail(f'"{contents}" not found in journal.')
1198
1ca44d7d
YW
1199class NetworkctlTests(unittest.TestCase, Utilities):
1200
1ca44d7d 1201 def setUp(self):
a962d857 1202 setup_common()
1ca44d7d
YW
1203
1204 def tearDown(self):
a962d857 1205 tear_down_common()
1ca44d7d 1206
6934ace0
YW
1207 @expectedFailureIfAlternativeNameIsNotAvailable()
1208 def test_altname(self):
a962d857 1209 copy_network_unit('26-netdev-link-local-addressing-yes.network', '12-dummy.netdev', '12-dummy.link')
6934ace0 1210 start_networkd()
95e1fbba 1211 self.wait_online('dummy98:degraded')
6934ace0 1212
10d670a3 1213 output = networkctl_status('dummy98')
6934ace0
YW
1214 self.assertRegex(output, 'hogehogehogehogehogehoge')
1215
f68f644a
NR
1216 @expectedFailureIfAlternativeNameIsNotAvailable()
1217 def test_rename_to_altname(self):
1218 copy_network_unit('26-netdev-link-local-addressing-yes.network',
1219 '12-dummy.netdev', '12-dummy-rename-to-altname.link')
1220 start_networkd()
95e1fbba 1221 self.wait_online('dummyalt:degraded')
f68f644a 1222
10d670a3 1223 output = networkctl_status('dummyalt')
f68f644a
NR
1224 self.assertIn('hogehogehogehogehogehoge', output)
1225 self.assertNotIn('dummy98', output)
1226
dcd9f07c 1227 def test_reconfigure(self):
67150a7b 1228 copy_network_unit('25-address-static.network', '12-dummy.netdev', copy_dropins=False)
dcd9f07c 1229 start_networkd()
95e1fbba 1230 self.wait_online('dummy98:routable')
dcd9f07c
YW
1231
1232 output = check_output('ip -4 address show dev dummy98')
1233 print(output)
3bad5487
YW
1234 self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output)
1235 self.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output)
1236 self.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output)
dcd9f07c
YW
1237
1238 check_output('ip address del 10.1.2.3/16 dev dummy98')
1239 check_output('ip address del 10.1.2.4/16 dev dummy98')
1240 check_output('ip address del 10.2.2.4/16 dev dummy98')
1241
a962d857 1242 networkctl_reconfigure('dummy98')
95e1fbba 1243 self.wait_online('dummy98:routable')
dcd9f07c
YW
1244
1245 output = check_output('ip -4 address show dev dummy98')
1246 print(output)
3bad5487
YW
1247 self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output)
1248 self.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output)
1249 self.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output)
1250
a962d857 1251 remove_network_unit('25-address-static.network')
3bad5487 1252
a962d857 1253 networkctl_reload()
3bad5487
YW
1254 self.wait_operstate('dummy98', 'degraded', setup_state='unmanaged')
1255
1256 output = check_output('ip -4 address show dev dummy98')
1257 print(output)
1258 self.assertNotIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output)
1259 self.assertNotIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output)
1260 self.assertNotIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output)
1261
67150a7b 1262 copy_network_unit('25-address-static.network', copy_dropins=False)
a962d857 1263 networkctl_reload()
95e1fbba 1264 self.wait_online('dummy98:routable')
3bad5487
YW
1265
1266 output = check_output('ip -4 address show dev dummy98')
1267 print(output)
1268 self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output)
1269 self.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output)
1270 self.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output)
dcd9f07c 1271
7e107bc3
FS
1272 def test_renew(self):
1273 def check():
95e1fbba 1274 self.wait_online('veth99:routable', 'veth-peer:routable')
10d670a3 1275 output = networkctl_status('veth99')
7e107bc3 1276 print(output)
e6c4b5dc 1277 self.assertRegex(output, r'Address: 192.168.5.[0-9]* \(DHCPv4 via 192.168.5.1\)')
7e107bc3
FS
1278 self.assertIn('Gateway: 192.168.5.3', output)
1279 self.assertRegex(output, 'DNS: 192.168.5.1\n *192.168.5.10')
1280 self.assertRegex(output, 'NTP: 192.168.5.1\n *192.168.5.11')
1281
1282 copy_network_unit('25-veth.netdev', '25-dhcp-client.network', '25-dhcp-server.network')
1283 start_networkd()
1284 check()
10d670a3 1285 check_json(networkctl_json('--lines=0', '--stats', '--all', '--full'))
7e107bc3
FS
1286
1287 for verb in ['renew', 'forcerenew']:
10d670a3 1288 networkctl(verb, 'veth99')
7e107bc3 1289 check()
10d670a3 1290 networkctl(verb, 'veth99', 'veth99', 'veth99')
7e107bc3
FS
1291 check()
1292
1293 def test_up_down(self):
67150a7b 1294 copy_network_unit('25-address-static.network', '12-dummy.netdev', copy_dropins=False)
7e107bc3 1295 start_networkd()
95e1fbba 1296 self.wait_online('dummy98:routable')
7e107bc3 1297
10d670a3 1298 networkctl('down', 'dummy98')
95e1fbba 1299 self.wait_online('dummy98:off')
10d670a3 1300 networkctl('up', 'dummy98')
95e1fbba 1301 self.wait_online('dummy98:routable')
10d670a3 1302 networkctl('down', 'dummy98', 'dummy98', 'dummy98')
95e1fbba 1303 self.wait_online('dummy98:off')
10d670a3 1304 networkctl('up', 'dummy98', 'dummy98', 'dummy98')
95e1fbba 1305 self.wait_online('dummy98:routable')
7e107bc3 1306
66de8671 1307 def test_reload(self):
a962d857 1308 start_networkd()
66de8671 1309
a962d857
YW
1310 copy_network_unit('11-dummy.netdev')
1311 networkctl_reload()
19cf3143 1312 self.wait_operstate('test1', 'off', setup_state='unmanaged')
66de8671 1313
a962d857
YW
1314 copy_network_unit('11-dummy.network')
1315 networkctl_reload()
95e1fbba 1316 self.wait_online('test1:degraded')
66de8671 1317
a962d857
YW
1318 remove_network_unit('11-dummy.network')
1319 networkctl_reload()
19cf3143 1320 self.wait_operstate('test1', 'degraded', setup_state='unmanaged')
66de8671 1321
a962d857
YW
1322 remove_network_unit('11-dummy.netdev')
1323 networkctl_reload()
19cf3143 1324 self.wait_operstate('test1', 'degraded', setup_state='unmanaged')
66de8671 1325
a962d857
YW
1326 copy_network_unit('11-dummy.netdev', '11-dummy.network')
1327 networkctl_reload()
19cf3143 1328 self.wait_operstate('test1', 'degraded')
66de8671 1329
1ca44d7d 1330 def test_glob(self):
a962d857 1331 copy_network_unit('11-dummy.netdev', '11-dummy.network')
2cf6fdff 1332 start_networkd()
1ca44d7d 1333
95e1fbba 1334 self.wait_online('test1:degraded')
1ca44d7d 1335
10d670a3 1336 output = networkctl('list')
1ca44d7d
YW
1337 self.assertRegex(output, '1 lo ')
1338 self.assertRegex(output, 'test1')
1339
10d670a3 1340 output = networkctl('list', 'test1')
1ca44d7d
YW
1341 self.assertNotRegex(output, '1 lo ')
1342 self.assertRegex(output, 'test1')
1343
10d670a3 1344 output = networkctl('list', 'te*')
1ca44d7d
YW
1345 self.assertNotRegex(output, '1 lo ')
1346 self.assertRegex(output, 'test1')
1347
10d670a3 1348 output = networkctl_status('te*')
1ca44d7d
YW
1349 self.assertNotRegex(output, '1: lo ')
1350 self.assertRegex(output, 'test1')
1351
10d670a3 1352 output = networkctl_status('tes[a-z][0-9]')
1ca44d7d
YW
1353 self.assertNotRegex(output, '1: lo ')
1354 self.assertRegex(output, 'test1')
1355
6d5b4efe 1356 def test_mtu(self):
a962d857 1357 copy_network_unit('11-dummy-mtu.netdev', '11-dummy.network')
2cf6fdff 1358 start_networkd()
6d5b4efe 1359
95e1fbba 1360 self.wait_online('test1:degraded')
6d5b4efe 1361
10d670a3 1362 output = networkctl_status('test1')
6d5b4efe
YW
1363 self.assertRegex(output, 'MTU: 1600')
1364
e28fd95f 1365 def test_type(self):
a962d857 1366 copy_network_unit('11-dummy.netdev', '11-dummy.network')
e28fd95f 1367 start_networkd()
95e1fbba 1368 self.wait_online('test1:degraded')
e28fd95f 1369
10d670a3 1370 output = networkctl_status('test1')
e28fd95f
YW
1371 print(output)
1372 self.assertRegex(output, 'Type: ether')
1373
10d670a3 1374 output = networkctl_status('lo')
e28fd95f
YW
1375 print(output)
1376 self.assertRegex(output, 'Type: loopback')
1377
b993e7e7
YW
1378 def test_unit_file(self):
1379 copy_network_unit('11-test-unit-file.netdev', '11-test-unit-file.network', '11-test-unit-file.link')
e28fd95f 1380 start_networkd()
95e1fbba 1381 self.wait_online('test1:degraded')
e28fd95f 1382
10d670a3 1383 output = networkctl_status('test1')
e28fd95f 1384 print(output)
b993e7e7
YW
1385 self.assertIn('Link File: /run/systemd/network/11-test-unit-file.link', output)
1386 self.assertIn('/run/systemd/network/11-test-unit-file.link.d/dropin.conf', output)
1387 self.assertIn('Network File: /run/systemd/network/11-test-unit-file.network', output)
1388 self.assertIn('/run/systemd/network/11-test-unit-file.network.d/dropin.conf', output)
1389
45c2bbba 1390 self.check_networkd_log('test1: Configuring with /run/systemd/network/11-test-unit-file.network (dropins: /run/systemd/network/11-test-unit-file.network.d/dropin.conf).')
e28fd95f 1391
df0a741c
YW
1392 # This test may be run on the system that has older udevd than 70f32a260b5ebb68c19ecadf5d69b3844896ba55 (v249).
1393 # In that case, the udev DB for the loopback network interface may already have ID_NET_LINK_FILE property.
1394 # Let's reprocess the interface and drop the property.
a39a2a81 1395 udevadm_trigger('/sys/class/net/lo')
10d670a3 1396 output = networkctl_status('lo')
e28fd95f 1397 print(output)
b993e7e7
YW
1398 self.assertIn('Link File: n/a', output)
1399 self.assertIn('Network File: n/a', output)
e28fd95f 1400
bee692fd 1401 def test_delete_links(self):
a962d857
YW
1402 copy_network_unit('11-dummy.netdev', '11-dummy.network',
1403 '25-veth.netdev', '26-netdev-link-local-addressing-yes.network')
2cf6fdff 1404 start_networkd()
bee692fd 1405
95e1fbba 1406 self.wait_online('test1:degraded', 'veth99:degraded', 'veth-peer:degraded')
bee692fd 1407
10d670a3 1408 networkctl('delete', 'test1', 'veth99')
a962d857
YW
1409 self.check_link_exists('test1', expected=False)
1410 self.check_link_exists('veth99', expected=False)
1411 self.check_link_exists('veth-peer', expected=False)
bee692fd 1412
7e107bc3 1413 def test_label(self):
10d670a3 1414 networkctl('label')
7e107bc3 1415
fa4d3fed
YW
1416class NetworkdMatchTests(unittest.TestCase, Utilities):
1417
1418 def setUp(self):
1419 setup_common()
1420
1421 def tearDown(self):
1422 tear_down_common()
1423
7618ab1b 1424 @expectedFailureIfAlternativeNameIsNotAvailable()
fa4d3fed
YW
1425 def test_match(self):
1426 copy_network_unit('12-dummy-mac.netdev',
1427 '12-dummy-match-mac-01.network',
1428 '12-dummy-match-mac-02.network',
1429 '12-dummy-match-renamed.network',
1430 '12-dummy-match-altname.network',
1431 '12-dummy-altname.link')
1432 start_networkd()
1433
95e1fbba 1434 self.wait_online('dummy98:routable')
10d670a3 1435 output = networkctl_status('dummy98')
fa4d3fed
YW
1436 self.assertIn('Network File: /run/systemd/network/12-dummy-match-mac-01.network', output)
1437 output = check_output('ip -4 address show dev dummy98')
1438 self.assertIn('10.0.0.1/16', output)
1439
1440 check_output('ip link set dev dummy98 down')
1441 check_output('ip link set dev dummy98 address 12:34:56:78:9a:02')
1442
1443 self.wait_address('dummy98', '10.0.0.2/16', ipv='-4', timeout_sec=10)
95e1fbba 1444 self.wait_online('dummy98:routable')
10d670a3 1445 output = networkctl_status('dummy98')
fa4d3fed
YW
1446 self.assertIn('Network File: /run/systemd/network/12-dummy-match-mac-02.network', output)
1447
1448 check_output('ip link set dev dummy98 down')
1449 check_output('ip link set dev dummy98 name dummy98-1')
1450
1451 self.wait_address('dummy98-1', '10.0.1.2/16', ipv='-4', timeout_sec=10)
95e1fbba 1452 self.wait_online('dummy98-1:routable')
10d670a3 1453 output = networkctl_status('dummy98-1')
fa4d3fed
YW
1454 self.assertIn('Network File: /run/systemd/network/12-dummy-match-renamed.network', output)
1455
1456 check_output('ip link set dev dummy98-1 down')
1457 check_output('ip link set dev dummy98-1 name dummy98-2')
a39a2a81 1458 udevadm_trigger('/sys/class/net/dummy98-2')
fa4d3fed
YW
1459
1460 self.wait_address('dummy98-2', '10.0.2.2/16', ipv='-4', timeout_sec=10)
95e1fbba 1461 self.wait_online('dummy98-2:routable')
10d670a3 1462 output = networkctl_status('dummy98-2')
fa4d3fed
YW
1463 self.assertIn('Network File: /run/systemd/network/12-dummy-match-altname.network', output)
1464
5432adae
YW
1465 def test_match_udev_property(self):
1466 copy_network_unit('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
1467 start_networkd()
95e1fbba 1468 self.wait_online('dummy98:routable')
5432adae 1469
10d670a3 1470 output = networkctl_status('dummy98')
5432adae
YW
1471 print(output)
1472 self.assertRegex(output, 'Network File: /run/systemd/network/14-match-udev-property')
1473
b09ec847
YW
1474class WaitOnlineTests(unittest.TestCase, Utilities):
1475
1476 def setUp(self):
1477 setup_common()
1478
1479 def tearDown(self):
1480 tear_down_common()
1481
1482 def test_wait_online_any(self):
1483 copy_network_unit('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
1484 start_networkd()
1485
95e1fbba 1486 self.wait_online('bridge99', 'test1:degraded', bool_any=True)
b09ec847
YW
1487
1488 self.wait_operstate('bridge99', '(off|no-carrier)', setup_state='configuring')
1489 self.wait_operstate('test1', 'degraded')
1490
1f0e3109
SS
1491class NetworkdNetDevTests(unittest.TestCase, Utilities):
1492
1f0e3109 1493 def setUp(self):
a962d857 1494 setup_common()
1f0e3109
SS
1495
1496 def tearDown(self):
a962d857 1497 tear_down_common()
1f0e3109 1498
1ca44d7d 1499 def test_dropin_and_name_conflict(self):
a962d857 1500 copy_network_unit('10-dropin-test.netdev', '15-name-conflict-test.netdev')
2cf6fdff 1501 start_networkd()
d80734f7 1502
95e1fbba 1503 self.wait_online('dropin-test:off', setup_state='unmanaged')
d80734f7 1504
371810d1 1505 output = check_output('ip link show dropin-test')
d80734f7 1506 print(output)
45aa0e84 1507 self.assertRegex(output, '00:50:56:c0:00:28')
d80734f7 1508
13060471
YW
1509 @expectedFailureIfModuleIsNotAvailable('bareudp')
1510 def test_bareudp(self):
a962d857 1511 copy_network_unit('25-bareudp.netdev', '26-netdev-link-local-addressing-yes.network')
13060471
YW
1512 start_networkd()
1513
95e1fbba 1514 self.wait_online('bareudp99:degraded')
13060471
YW
1515
1516 output = check_output('ip -d link show bareudp99')
1517 print(output)
1518 self.assertRegex(output, 'dstport 1000 ')
1519 self.assertRegex(output, 'ethertype ip ')
1520
c0267a59
AW
1521 @expectedFailureIfModuleIsNotAvailable('batman-adv')
1522 def test_batadv(self):
a962d857 1523 copy_network_unit('25-batadv.netdev', '26-netdev-link-local-addressing-yes.network')
c0267a59
AW
1524 start_networkd()
1525
95e1fbba 1526 self.wait_online('batadv99:degraded')
c0267a59
AW
1527
1528 output = check_output('ip -d link show batadv99')
1529 print(output)
1530 self.assertRegex(output, 'batadv')
1531
1f0e3109 1532 def test_bridge(self):
a962d857 1533 copy_network_unit('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
2cf6fdff 1534 start_networkd()
1f0e3109 1535
95e1fbba 1536 self.wait_online('bridge99:no-carrier')
1f0e3109 1537
3d165124 1538 tick = os.sysconf('SC_CLK_TCK')
ec38833c
ZJS
1539 self.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick))
1540 self.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick))
c9047092
YW
1541 self.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'forward_delay')) / tick))
1542 self.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'ageing_time')) / tick))
1543 self.assertEqual(9, int(read_link_attr('bridge99', 'bridge', 'priority')))
1544 self.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_querier')))
1545 self.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_snooping')))
1546 self.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'stp_state')))
1547 self.assertEqual(3, int(read_link_attr('bridge99', 'bridge', 'multicast_igmp_version')))
1f0e3109 1548
10d670a3 1549 output = networkctl_status('bridge99')
36bc2ffb
YW
1550 print(output)
1551 self.assertRegex(output, 'Priority: 9')
1552 self.assertRegex(output, 'STP: yes')
1553 self.assertRegex(output, 'Multicast IGMP Version: 3')
1554
b6d5dab7
YW
1555 output = check_output('ip -d link show bridge99')
1556 print(output)
1557 self.assertIn('vlan_filtering 1 ', output)
1558 self.assertIn('vlan_protocol 802.1ad ', output)
1559 self.assertIn('vlan_default_pvid 9 ', output)
1560
1f0e3109 1561 def test_bond(self):
d2d0a8d4 1562 copy_network_unit('25-bond.netdev', '25-bond-balanced-tlb.netdev', '25-bond-property.netdev')
2cf6fdff 1563 start_networkd()
ec38833c 1564
d2d0a8d4 1565 self.wait_online('bond99:off', 'bond98:off', 'bond97:off', setup_state='unmanaged')
ec38833c 1566
a962d857
YW
1567 self.check_link_attr('bond99', 'bonding', 'mode', '802.3ad 4')
1568 self.check_link_attr('bond99', 'bonding', 'xmit_hash_policy', 'layer3+4 1')
1569 self.check_link_attr('bond99', 'bonding', 'miimon', '1000')
1570 self.check_link_attr('bond99', 'bonding', 'lacp_rate', 'fast 1')
1571 self.check_link_attr('bond99', 'bonding', 'updelay', '2000')
1572 self.check_link_attr('bond99', 'bonding', 'downdelay', '2000')
1573 self.check_link_attr('bond99', 'bonding', 'resend_igmp', '4')
1574 self.check_link_attr('bond99', 'bonding', 'min_links', '1')
1575 self.check_link_attr('bond99', 'bonding', 'ad_actor_sys_prio', '1218')
1576 self.check_link_attr('bond99', 'bonding', 'ad_user_port_key', '811')
1577 self.check_link_attr('bond99', 'bonding', 'ad_actor_system', '00:11:22:33:44:55')
1578
1579 self.check_link_attr('bond98', 'bonding', 'mode', 'balance-tlb 5')
1580 self.check_link_attr('bond98', 'bonding', 'tlb_dynamic_lb', '1')
fde60a42 1581
10d670a3 1582 output = networkctl_status('bond99')
acfe3b65
YW
1583 print(output)
1584 self.assertIn('Mode: 802.3ad', output)
1585 self.assertIn('Miimon: 1s', output)
1586 self.assertIn('Updelay: 2s', output)
1587 self.assertIn('Downdelay: 2s', output)
1588
10d670a3 1589 output = networkctl_status('bond98')
acfe3b65
YW
1590 print(output)
1591 self.assertIn('Mode: balance-tlb', output)
1592
d2d0a8d4
SS
1593 output = networkctl_status('bond97')
1594 print(output)
1595
1596 self.check_link_attr('bond97', 'bonding', 'arp_missed_max', '10')
de736b96 1597 self.check_link_attr('bond97', 'bonding', 'peer_notif_delay', '300000')
d2d0a8d4 1598
1f0e3109 1599 def test_vlan(self):
a962d857
YW
1600 copy_network_unit('21-vlan.netdev', '11-dummy.netdev',
1601 '21-vlan.network', '21-vlan-test1.network')
2cf6fdff 1602 start_networkd()
1f0e3109 1603
95e1fbba 1604 self.wait_online('test1:degraded', 'vlan99:routable')
1f0e3109 1605
371810d1 1606 output = check_output('ip -d link show test1')
72b7f1b9 1607 print(output)
7d7be1b9 1608 self.assertRegex(output, ' mtu 2000 ')
72b7f1b9 1609
371810d1 1610 output = check_output('ip -d link show vlan99')
14ecd604 1611 print(output)
73d24e45
YW
1612 self.assertIn(' mtu 2000 ', output)
1613 self.assertIn('REORDER_HDR', output)
1614 self.assertIn('LOOSE_BINDING', output)
1615 self.assertIn('GVRP', output)
1616 self.assertIn('MVRP', output)
1617 self.assertIn(' id 99 ', output)
1618 self.assertIn('ingress-qos-map { 4:100 7:13 }', output)
1619 self.assertIn('egress-qos-map { 0:1 1:3 6:6 7:7 10:3 }', output)
1f0e3109 1620
371810d1 1621 output = check_output('ip -4 address show dev test1')
7f45d738
YW
1622 print(output)
1623 self.assertRegex(output, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
1624 self.assertRegex(output, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
1625
371810d1 1626 output = check_output('ip -4 address show dev vlan99')
7f45d738
YW
1627 print(output)
1628 self.assertRegex(output, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
1629
b249834b
YW
1630 def test_vlan_on_bond(self):
1631 # For issue #24377 (https://github.com/systemd/systemd/issues/24377),
1632 # which is fixed by b05e52000b4eee764b383cc3031da0a3739e996e (PR#24020).
1633
1634 copy_network_unit('21-bond-802.3ad.netdev', '21-bond-802.3ad.network',
1635 '21-vlan-on-bond.netdev', '21-vlan-on-bond.network')
1636 start_networkd()
95e1fbba 1637 self.wait_online('bond99:off')
b249834b
YW
1638 self.wait_operstate('vlan99', operstate='off', setup_state='configuring', setup_timeout=10)
1639
45c2bbba 1640 self.check_networkd_log('vlan99: Could not bring up interface, ignoring: Network is down')
b249834b
YW
1641
1642 copy_network_unit('11-dummy.netdev', '12-dummy.netdev', '21-dummy-bond-slave.network')
1643 networkctl_reload()
95e1fbba 1644 self.wait_online('test1:enslaved', 'dummy98:enslaved', 'bond99:carrier', 'vlan99:routable')
b249834b 1645
1f0e3109 1646 def test_macvtap(self):
a962d857 1647 first = True
460feb61 1648 for mode in ['private', 'vepa', 'bridge', 'passthru']:
a962d857
YW
1649 if first:
1650 first = False
1651 else:
1652 self.tearDown()
1653
1654 print(f'### test_macvtap(mode={mode})')
460feb61 1655 with self.subTest(mode=mode):
a962d857
YW
1656 copy_network_unit('21-macvtap.netdev', '26-netdev-link-local-addressing-yes.network',
1657 '11-dummy.netdev', '25-macvtap.network')
1658 with open(os.path.join(network_unit_dir, '21-macvtap.netdev'), mode='a', encoding='utf-8') as f:
460feb61 1659 f.write('[MACVTAP]\nMode=' + mode)
2cf6fdff 1660 start_networkd()
1f0e3109 1661
95e1fbba
YW
1662 self.wait_online('macvtap99:degraded',
1663 'test1:carrier' if mode == 'passthru' else 'test1:degraded')
460feb61 1664
371810d1 1665 output = check_output('ip -d link show macvtap99')
460feb61
YW
1666 print(output)
1667 self.assertRegex(output, 'macvtap mode ' + mode + ' ')
1f0e3109
SS
1668
1669 def test_macvlan(self):
a962d857 1670 first = True
dff9792b 1671 for mode in ['private', 'vepa', 'bridge', 'passthru']:
a962d857
YW
1672 if first:
1673 first = False
1674 else:
1675 self.tearDown()
1676
1677 print(f'### test_macvlan(mode={mode})')
dff9792b 1678 with self.subTest(mode=mode):
a962d857
YW
1679 copy_network_unit('21-macvlan.netdev', '26-netdev-link-local-addressing-yes.network',
1680 '11-dummy.netdev', '25-macvlan.network')
1681 with open(os.path.join(network_unit_dir, '21-macvlan.netdev'), mode='a', encoding='utf-8') as f:
dff9792b 1682 f.write('[MACVLAN]\nMode=' + mode)
2cf6fdff 1683 start_networkd()
dff9792b 1684
95e1fbba
YW
1685 self.wait_online('macvlan99:degraded',
1686 'test1:carrier' if mode == 'passthru' else 'test1:degraded')
dff9792b 1687
371810d1 1688 output = check_output('ip -d link show test1')
dff9792b 1689 print(output)
0183d48d 1690 self.assertIn(' mtu 2000 ', output)
72b7f1b9 1691
371810d1 1692 output = check_output('ip -d link show macvlan99')
dff9792b 1693 print(output)
0183d48d
YW
1694 self.assertIn(' mtu 2000 ', output)
1695 self.assertIn(f' macvlan mode {mode} ', output)
72b7f1b9 1696
a962d857 1697 remove_link('test1')
1d0c9bd7
YW
1698 time.sleep(1)
1699
a962d857 1700 check_output("ip link add test1 type dummy")
95e1fbba
YW
1701 self.wait_online('macvlan99:degraded',
1702 'test1:carrier' if mode == 'passthru' else 'test1:degraded')
1d0c9bd7
YW
1703
1704 output = check_output('ip -d link show test1')
1705 print(output)
0183d48d 1706 self.assertIn(' mtu 2000 ', output)
1d0c9bd7
YW
1707
1708 output = check_output('ip -d link show macvlan99')
1709 print(output)
0183d48d
YW
1710 self.assertIn(' mtu 2000 ', output)
1711 self.assertIn(f' macvlan mode {mode} ', output)
2b98febe
SS
1712 self.assertIn(' bcqueuelen 1234 ', output)
1713 self.assertIn(' bclim 2147483647 ', output)
1d0c9bd7 1714
7a0a37b2 1715 @expectedFailureIfModuleIsNotAvailable('ipvlan')
1f0e3109 1716 def test_ipvlan(self):
a962d857 1717 first = True
bc6dff6e 1718 for mode, flag in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
a962d857
YW
1719 if first:
1720 first = False
1721 else:
1722 self.tearDown()
1723
1724 print(f'### test_ipvlan(mode={mode}, flag={flag})')
bc6dff6e 1725 with self.subTest(mode=mode, flag=flag):
a962d857
YW
1726 copy_network_unit('25-ipvlan.netdev', '26-netdev-link-local-addressing-yes.network',
1727 '11-dummy.netdev', '25-ipvlan.network')
1728 with open(os.path.join(network_unit_dir, '25-ipvlan.netdev'), mode='a', encoding='utf-8') as f:
bc6dff6e 1729 f.write('[IPVLAN]\nMode=' + mode + '\nFlags=' + flag)
1f0e3109 1730
2cf6fdff 1731 start_networkd()
95e1fbba 1732 self.wait_online('ipvlan99:degraded', 'test1:degraded')
bc6dff6e 1733
371810d1 1734 output = check_output('ip -d link show ipvlan99')
bc6dff6e
YW
1735 print(output)
1736 self.assertRegex(output, 'ipvlan *mode ' + mode.lower() + ' ' + flag)
1f0e3109 1737
956c8fec
YW
1738 @expectedFailureIfModuleIsNotAvailable('ipvtap')
1739 def test_ipvtap(self):
a962d857 1740 first = True
40921f08 1741 for mode, flag in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
a962d857
YW
1742 if first:
1743 first = False
1744 else:
1745 self.tearDown()
1746
1747 print(f'### test_ipvtap(mode={mode}, flag={flag})')
40921f08 1748 with self.subTest(mode=mode, flag=flag):
a962d857
YW
1749 copy_network_unit('25-ipvtap.netdev', '26-netdev-link-local-addressing-yes.network',
1750 '11-dummy.netdev', '25-ipvtap.network')
1751 with open(os.path.join(network_unit_dir, '25-ipvtap.netdev'), mode='a', encoding='utf-8') as f:
40921f08
YW
1752 f.write('[IPVTAP]\nMode=' + mode + '\nFlags=' + flag)
1753
2cf6fdff 1754 start_networkd()
95e1fbba 1755 self.wait_online('ipvtap99:degraded', 'test1:degraded')
956c8fec 1756
371810d1 1757 output = check_output('ip -d link show ipvtap99')
40921f08
YW
1758 print(output)
1759 self.assertRegex(output, 'ipvtap *mode ' + mode.lower() + ' ' + flag)
956c8fec 1760
1f0e3109 1761 def test_veth(self):
a962d857
YW
1762 copy_network_unit('25-veth.netdev', '26-netdev-link-local-addressing-yes.network',
1763 '25-veth-mtu.netdev')
2cf6fdff 1764 start_networkd()
1f0e3109 1765
95e1fbba 1766 self.wait_online('veth99:degraded', 'veth-peer:degraded', 'veth-mtu:degraded', 'veth-mtu-peer:degraded')
671dacdf 1767
371810d1 1768 output = check_output('ip -d link show veth99')
671dacdf
YW
1769 print(output)
1770 self.assertRegex(output, 'link/ether 12:34:56:78:9a:bc')
371810d1 1771 output = check_output('ip -d link show veth-peer')
671dacdf
YW
1772 print(output)
1773 self.assertRegex(output, 'link/ether 12:34:56:78:9a:bd')
1f0e3109 1774
0874be35
YW
1775 output = check_output('ip -d link show veth-mtu')
1776 print(output)
1777 self.assertRegex(output, 'link/ether 12:34:56:78:9a:be')
1778 self.assertRegex(output, 'mtu 1800')
1779 output = check_output('ip -d link show veth-mtu-peer')
1780 print(output)
1781 self.assertRegex(output, 'link/ether 12:34:56:78:9a:bf')
1782 self.assertRegex(output, 'mtu 1800')
1783
5cdc7c89 1784 def test_tuntap(self):
ae014ecb 1785 copy_network_unit('25-tun.netdev', '25-tap.netdev', '26-netdev-link-local-addressing-yes.network')
2cf6fdff 1786 start_networkd()
1f0e3109 1787
95e1fbba 1788 self.wait_online('testtun99:degraded', 'testtap99:degraded')
ae014ecb
YW
1789
1790 pid = networkd_pid()
1791 name = psutil.Process(pid).name()[:15]
1792
1793 output = check_output('ip -d tuntap show')
1794 print(output)
0677130e
FS
1795 self.assertRegex(output, fr'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:{name}\({pid}\)systemd\(1\)$')
1796 self.assertRegex(output, fr'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:{name}\({pid}\)systemd\(1\)$')
1f0e3109 1797
5cdc7c89 1798 output = check_output('ip -d link show testtun99')
2746d307
YW
1799 print(output)
1800 # Old ip command does not support IFF_ flags
426654d7 1801 self.assertRegex(output, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
ae014ecb 1802 self.assertIn('UP,LOWER_UP', output)
2746d307 1803
5cdc7c89 1804 output = check_output('ip -d link show testtap99')
2746d307 1805 print(output)
426654d7 1806 self.assertRegex(output, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
ae014ecb
YW
1807 self.assertIn('UP,LOWER_UP', output)
1808
1809 remove_network_unit('26-netdev-link-local-addressing-yes.network')
1810
1811 restart_networkd()
95e1fbba 1812 self.wait_online('testtun99:degraded', 'testtap99:degraded', setup_state='unmanaged')
ae014ecb
YW
1813
1814 pid = networkd_pid()
1815 name = psutil.Process(pid).name()[:15]
1816
1817 output = check_output('ip -d tuntap show')
1818 print(output)
0677130e
FS
1819 self.assertRegex(output, fr'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:{name}\({pid}\)systemd\(1\)$')
1820 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
1821
1822 output = check_output('ip -d link show testtun99')
1823 print(output)
1824 self.assertRegex(output, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
1825 self.assertIn('UP,LOWER_UP', output)
1826
1827 output = check_output('ip -d link show testtap99')
1828 print(output)
1829 self.assertRegex(output, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
1830 self.assertIn('UP,LOWER_UP', output)
1831
1832 clear_network_units()
1833 restart_networkd()
95e1fbba 1834 self.wait_online('testtun99:off', 'testtap99:off', setup_state='unmanaged')
ae014ecb
YW
1835
1836 output = check_output('ip -d tuntap show')
1837 print(output)
0677130e
FS
1838 self.assertRegex(output, r'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$')
1839 self.assertRegex(output, r'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$')
ae014ecb
YW
1840
1841 for i in range(10):
1842 if i != 0:
1843 time.sleep(1)
1844 output = check_output('ip -d link show testtun99')
1845 print(output)
1846 self.assertRegex(output, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
1847 if 'NO-CARRIER' in output:
1848 break
1849 else:
1850 self.fail()
1851
1852 for i in range(10):
1853 if i != 0:
1854 time.sleep(1)
1855 output = check_output('ip -d link show testtap99')
1856 print(output)
1857 self.assertRegex(output, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
1858 if 'NO-CARRIER' in output:
1859 break
1860 else:
1861 self.fail()
2746d307 1862
7a0a37b2 1863 @expectedFailureIfModuleIsNotAvailable('vrf')
1f0e3109 1864 def test_vrf(self):
a962d857 1865 copy_network_unit('25-vrf.netdev', '26-netdev-link-local-addressing-yes.network')
2cf6fdff 1866 start_networkd()
1f0e3109 1867
95e1fbba 1868 self.wait_online('vrf99:carrier')
1f0e3109 1869
7a0a37b2 1870 @expectedFailureIfModuleIsNotAvailable('vcan')
1f0e3109 1871 def test_vcan(self):
470a329d
YW
1872 copy_network_unit('25-vcan.netdev', '26-netdev-link-local-addressing-yes.network',
1873 '25-vcan98.netdev', '25-vcan98.network')
2cf6fdff 1874 start_networkd()
1f0e3109 1875
95e1fbba 1876 self.wait_online('vcan99:carrier', 'vcan98:carrier')
7155ad95 1877 # For can devices, 'carrier' is the default required operational state.
95e1fbba 1878 self.wait_online('vcan99', 'vcan98')
470a329d
YW
1879
1880 # https://github.com/systemd/systemd/issues/30140
1881 output = check_output('ip -d link show vcan99')
1882 print(output)
1883 self.assertIn('mtu 16 ', output)
1884
1885 output = check_output('ip -d link show vcan98')
1886 print(output)
1887 self.assertIn('mtu 16 ', output)
1f0e3109 1888
f63b14d3
YW
1889 @expectedFailureIfModuleIsNotAvailable('vxcan')
1890 def test_vxcan(self):
a962d857 1891 copy_network_unit('25-vxcan.netdev', '26-netdev-link-local-addressing-yes.network')
2cf6fdff 1892 start_networkd()
f63b14d3 1893
95e1fbba 1894 self.wait_online('vxcan99:carrier', 'vxcan-peer:carrier')
7155ad95 1895 # For can devices, 'carrier' is the default required operational state.
95e1fbba 1896 self.wait_online('vxcan99', 'vxcan-peer')
f63b14d3 1897
7a3bc5a8
EV
1898 @expectedFailureIfModuleIsNotAvailable('wireguard')
1899 def test_wireguard(self):
fa724cd5
MY
1900 copy_credential('25-wireguard-endpoint-peer0-cred.txt', 'network.wireguard.peer0.endpoint')
1901 copy_credential('25-wireguard-preshared-key-peer2-cred.txt', 'network.wireguard.peer2.psk')
1902 copy_credential('25-wireguard-no-peer-private-key-cred.txt', 'network.wireguard.private.25-wireguard-no-peer')
1903
a962d857
YW
1904 copy_network_unit('25-wireguard.netdev', '25-wireguard.network',
1905 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
1906 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt',
1907 '25-wireguard-no-peer.netdev', '25-wireguard-no-peer.network')
2cf6fdff 1908 start_networkd()
95e1fbba 1909 self.wait_online('wg99:routable', 'wg98:routable', 'wg97:carrier')
84d32bf5
YW
1910
1911 output = check_output('ip -4 address show dev wg99')
1912 print(output)
1913 self.assertIn('inet 192.168.124.1/24 scope global wg99', output)
5a0bd90b 1914
e4e0b239
YW
1915 output = check_output('ip -4 address show dev wg99')
1916 print(output)
1917 self.assertIn('inet 169.254.11.1/24 scope link wg99', output)
1918
1919 output = check_output('ip -6 address show dev wg99')
1920 print(output)
1921 self.assertIn('inet6 fe80::1/64 scope link', output)
1922
045db4fa
YW
1923 output = check_output('ip -4 address show dev wg98')
1924 print(output)
1925 self.assertIn('inet 192.168.123.123/24 scope global wg98', output)
1926
1927 output = check_output('ip -6 address show dev wg98')
1928 print(output)
1929 self.assertIn('inet6 fd8d:4d6d:3ccb:500::1/64 scope global', output)
1930
6387cac3
YW
1931 output = check_output('ip -4 route show dev wg99 table 1234')
1932 print(output)
4db8ccbb 1933 self.assertIn('192.168.26.0/24 proto static scope link metric 123', output)
6387cac3
YW
1934
1935 output = check_output('ip -6 route show dev wg99 table 1234')
1936 print(output)
1937 self.assertIn('fd31:bf08:57cb::/48 proto static metric 123 pref medium', output)
1938
1939 output = check_output('ip -6 route show dev wg98 table 1234')
1940 print(output)
1941 self.assertIn('fd8d:4d6d:3ccb:500:c79:2339:edce:ece1 proto static metric 123 pref medium', output)
1942 self.assertIn('fd8d:4d6d:3ccb:500:1dbf:ca8a:32d3:dd81 proto static metric 123 pref medium', output)
1943 self.assertIn('fd8d:4d6d:3ccb:500:1e54:1415:35d0:a47c proto static metric 123 pref medium', output)
1944 self.assertIn('fd8d:4d6d:3ccb:500:270d:b5dd:4a3f:8909 proto static metric 123 pref medium', output)
1945 self.assertIn('fd8d:4d6d:3ccb:500:5660:679d:3532:94d8 proto static metric 123 pref medium', output)
1946 self.assertIn('fd8d:4d6d:3ccb:500:6825:573f:30f3:9472 proto static metric 123 pref medium', output)
1947 self.assertIn('fd8d:4d6d:3ccb:500:6f2e:6888:c6fd:dfb9 proto static metric 123 pref medium', output)
1948 self.assertIn('fd8d:4d6d:3ccb:500:8d4d:bab:7280:a09a proto static metric 123 pref medium', output)
1949 self.assertIn('fd8d:4d6d:3ccb:500:900c:d437:ec27:8822 proto static metric 123 pref medium', output)
1950 self.assertIn('fd8d:4d6d:3ccb:500:9742:9931:5217:18d5 proto static metric 123 pref medium', output)
1951 self.assertIn('fd8d:4d6d:3ccb:500:9c11:d820:2e96:9be0 proto static metric 123 pref medium', output)
1952 self.assertIn('fd8d:4d6d:3ccb:500:a072:80da:de4f:add1 proto static metric 123 pref medium', output)
1953 self.assertIn('fd8d:4d6d:3ccb:500:a3f3:df38:19b0:721 proto static metric 123 pref medium', output)
1954 self.assertIn('fd8d:4d6d:3ccb:500:a94b:cd6a:a32d:90e6 proto static metric 123 pref medium', output)
1955 self.assertIn('fd8d:4d6d:3ccb:500:b39c:9cdc:755a:ead3 proto static metric 123 pref medium', output)
1956 self.assertIn('fd8d:4d6d:3ccb:500:b684:4f81:2e3e:132e proto static metric 123 pref medium', output)
1957 self.assertIn('fd8d:4d6d:3ccb:500:bad5:495d:8e9c:3427 proto static metric 123 pref medium', output)
1958 self.assertIn('fd8d:4d6d:3ccb:500:bfe5:c3c3:5d77:fcb proto static metric 123 pref medium', output)
1959 self.assertIn('fd8d:4d6d:3ccb:500:c624:6bf7:4c09:3b59 proto static metric 123 pref medium', output)
1960 self.assertIn('fd8d:4d6d:3ccb:500:d4f9:5dc:9296:a1a proto static metric 123 pref medium', output)
1961 self.assertIn('fd8d:4d6d:3ccb:500:dcdd:d33b:90c9:6088 proto static metric 123 pref medium', output)
1962 self.assertIn('fd8d:4d6d:3ccb:500:e2e1:ae15:103f:f376 proto static metric 123 pref medium', output)
1963 self.assertIn('fd8d:4d6d:3ccb:500:f349:c4f0:10c1:6b4 proto static metric 123 pref medium', output)
1964 self.assertIn('fd8d:4d6d:3ccb:c79:2339:edce::/96 proto static metric 123 pref medium', output)
1965 self.assertIn('fd8d:4d6d:3ccb:1dbf:ca8a:32d3::/96 proto static metric 123 pref medium', output)
1966 self.assertIn('fd8d:4d6d:3ccb:1e54:1415:35d0::/96 proto static metric 123 pref medium', output)
1967 self.assertIn('fd8d:4d6d:3ccb:270d:b5dd:4a3f::/96 proto static metric 123 pref medium', output)
1968 self.assertIn('fd8d:4d6d:3ccb:5660:679d:3532::/96 proto static metric 123 pref medium', output)
1969 self.assertIn('fd8d:4d6d:3ccb:6825:573f:30f3::/96 proto static metric 123 pref medium', output)
1970 self.assertIn('fd8d:4d6d:3ccb:6f2e:6888:c6fd::/96 proto static metric 123 pref medium', output)
1971 self.assertIn('fd8d:4d6d:3ccb:8d4d:bab:7280::/96 proto static metric 123 pref medium', output)
1972 self.assertIn('fd8d:4d6d:3ccb:900c:d437:ec27::/96 proto static metric 123 pref medium', output)
1973 self.assertIn('fd8d:4d6d:3ccb:9742:9931:5217::/96 proto static metric 123 pref medium', output)
1974 self.assertIn('fd8d:4d6d:3ccb:9c11:d820:2e96::/96 proto static metric 123 pref medium', output)
1975 self.assertIn('fd8d:4d6d:3ccb:a072:80da:de4f::/96 proto static metric 123 pref medium', output)
1976 self.assertIn('fd8d:4d6d:3ccb:a3f3:df38:19b0::/96 proto static metric 123 pref medium', output)
1977 self.assertIn('fd8d:4d6d:3ccb:a94b:cd6a:a32d::/96 proto static metric 123 pref medium', output)
1978 self.assertIn('fd8d:4d6d:3ccb:b39c:9cdc:755a::/96 proto static metric 123 pref medium', output)
1979 self.assertIn('fd8d:4d6d:3ccb:b684:4f81:2e3e::/96 proto static metric 123 pref medium', output)
1980 self.assertIn('fd8d:4d6d:3ccb:bad5:495d:8e9c::/96 proto static metric 123 pref medium', output)
1981 self.assertIn('fd8d:4d6d:3ccb:bfe5:c3c3:5d77::/96 proto static metric 123 pref medium', output)
1982 self.assertIn('fd8d:4d6d:3ccb:c624:6bf7:4c09::/96 proto static metric 123 pref medium', output)
1983 self.assertIn('fd8d:4d6d:3ccb:d4f9:5dc:9296::/96 proto static metric 123 pref medium', output)
1984 self.assertIn('fd8d:4d6d:3ccb:dcdd:d33b:90c9::/96 proto static metric 123 pref medium', output)
1985 self.assertIn('fd8d:4d6d:3ccb:e2e1:ae15:103f::/96 proto static metric 123 pref medium', output)
1986 self.assertIn('fd8d:4d6d:3ccb:f349:c4f0:10c1::/96 proto static metric 123 pref medium', output)
1987
7a3bc5a8 1988 if shutil.which('wg'):
371810d1 1989 call('wg')
5a0bd90b 1990
371810d1 1991 output = check_output('wg show wg99 listen-port')
84d32bf5 1992 self.assertEqual(output, '51820')
371810d1 1993 output = check_output('wg show wg99 fwmark')
84d32bf5
YW
1994 self.assertEqual(output, '0x4d2')
1995 output = check_output('wg show wg99 private-key')
1996 self.assertEqual(output, 'EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=')
371810d1 1997 output = check_output('wg show wg99 allowed-ips')
84d32bf5
YW
1998 self.assertIn('9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c=\t192.168.124.3/32', output)
1999 self.assertIn('TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10=\t192.168.124.2/32', output)
2000 self.assertIn('lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128', output)
2001 self.assertIn('RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48', output)
371810d1 2002 output = check_output('wg show wg99 persistent-keepalive')
84d32bf5
YW
2003 self.assertIn('9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c=\toff', output)
2004 self.assertIn('TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10=\toff', output)
2005 self.assertIn('lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\toff', output)
2006 self.assertIn('RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t20', output)
371810d1 2007 output = check_output('wg show wg99 endpoints')
84d32bf5
YW
2008 self.assertIn('9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c=\t(none)', output)
2009 self.assertIn('TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10=\t(none)', output)
2010 self.assertIn('lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\t(none)', output)
2011 self.assertIn('RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t192.168.27.3:51820', output)
371810d1 2012 output = check_output('wg show wg99 preshared-keys')
84d32bf5
YW
2013 self.assertIn('9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c=\t6Fsg8XN0DE6aPQgAX4r2oazEYJOGqyHUz3QRH/jCB+I=', output)
2014 self.assertIn('TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10=\tit7nd33chCT/tKT2ZZWfYyp43Zs+6oif72hexnSNMqA=', output)
2015 self.assertIn('lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tcPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=', output)
2016 self.assertIn('RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\tIIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=', output)
7a3bc5a8 2017
371810d1 2018 output = check_output('wg show wg98 private-key')
84d32bf5 2019 self.assertEqual(output, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr+WHtZLZ90FU=')
da44fb8a 2020
da3509f0 2021 output = check_output('wg show wg97 listen-port')
84d32bf5 2022 self.assertEqual(output, '51821')
da3509f0 2023 output = check_output('wg show wg97 fwmark')
84d32bf5 2024 self.assertEqual(output, '0x4d3')
da3509f0 2025
1f0e3109 2026 def test_geneve(self):
a962d857 2027 copy_network_unit('25-geneve.netdev', '26-netdev-link-local-addressing-yes.network')
2cf6fdff 2028 start_networkd()
1f0e3109 2029
95e1fbba 2030 self.wait_online('geneve99:degraded')
1f0e3109 2031
371810d1 2032 output = check_output('ip -d link show geneve99')
14ecd604 2033 print(output)
06895a1d
YW
2034 self.assertRegex(output, '192.168.22.1')
2035 self.assertRegex(output, '6082')
2036 self.assertRegex(output, 'udpcsum')
2037 self.assertRegex(output, 'udp6zerocsumrx')
1f0e3109
SS
2038
2039 def test_ipip_tunnel(self):
a962d857
YW
2040 copy_network_unit('12-dummy.netdev', '25-ipip.network',
2041 '25-ipip-tunnel.netdev', '25-tunnel.network',
2042 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
2043 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
2044 '25-ipip-tunnel-any-any.netdev', '25-tunnel-any-any.network')
2cf6fdff 2045 start_networkd()
95e1fbba 2046 self.wait_online('ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'ipiptun96:routable', 'dummy98:degraded')
6a97a864 2047
371810d1 2048 output = check_output('ip -d link show ipiptun99')
6a97a864 2049 print(output)
426654d7 2050 self.assertRegex(output, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98')
371810d1 2051 output = check_output('ip -d link show ipiptun98')
6a97a864 2052 print(output)
426654d7 2053 self.assertRegex(output, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98')
371810d1 2054 output = check_output('ip -d link show ipiptun97')
6a97a864 2055 print(output)
426654d7 2056 self.assertRegex(output, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98')
42a29fcb
YW
2057 output = check_output('ip -d link show ipiptun96')
2058 print(output)
426654d7 2059 self.assertRegex(output, 'ipip (ipip )?remote any local any dev dummy98')
1f0e3109
SS
2060
2061 def test_gre_tunnel(self):
a962d857
YW
2062 copy_network_unit('12-dummy.netdev', '25-gretun.network',
2063 '25-gre-tunnel.netdev', '25-tunnel.network',
2064 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
2065 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
2066 '25-gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
2cf6fdff 2067 start_networkd()
95e1fbba 2068 self.wait_online('gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'gretun96:routable', 'dummy98:degraded')
6a97a864 2069
371810d1 2070 output = check_output('ip -d link show gretun99')
6a97a864
YW
2071 print(output)
2072 self.assertRegex(output, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
38f4bb44
YW
2073 self.assertRegex(output, 'ikey 1.2.3.103')
2074 self.assertRegex(output, 'okey 1.2.4.103')
2075 self.assertRegex(output, 'iseq')
2076 self.assertRegex(output, 'oseq')
371810d1 2077 output = check_output('ip -d link show gretun98')
6a97a864
YW
2078 print(output)
2079 self.assertRegex(output, 'gre remote 10.65.223.239 local any dev dummy98')
38f4bb44
YW
2080 self.assertRegex(output, 'ikey 0.0.0.104')
2081 self.assertRegex(output, 'okey 0.0.0.104')
2082 self.assertNotRegex(output, 'iseq')
2083 self.assertNotRegex(output, 'oseq')
371810d1 2084 output = check_output('ip -d link show gretun97')
6a97a864
YW
2085 print(output)
2086 self.assertRegex(output, 'gre remote any local 10.65.223.238 dev dummy98')
38f4bb44
YW
2087 self.assertRegex(output, 'ikey 0.0.0.105')
2088 self.assertRegex(output, 'okey 0.0.0.105')
2089 self.assertNotRegex(output, 'iseq')
2090 self.assertNotRegex(output, 'oseq')
42a29fcb
YW
2091 output = check_output('ip -d link show gretun96')
2092 print(output)
2093 self.assertRegex(output, 'gre remote any local any dev dummy98')
2094 self.assertRegex(output, 'ikey 0.0.0.106')
2095 self.assertRegex(output, 'okey 0.0.0.106')
2096 self.assertNotRegex(output, 'iseq')
2097 self.assertNotRegex(output, 'oseq')
6a97a864
YW
2098
2099 def test_ip6gre_tunnel(self):
a962d857
YW
2100 copy_network_unit('12-dummy.netdev', '25-ip6gretun.network',
2101 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
2102 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
2103 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
2104 '25-ip6gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
2105 start_networkd()
6a97a864 2106
17bcf0a0
YW
2107 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
2108
a962d857 2109 self.wait_links('dummy98', 'ip6gretun99', 'ip6gretun98', 'ip6gretun97', 'ip6gretun96')
6a97a864 2110
371810d1 2111 output = check_output('ip -d link show ip6gretun99')
6a97a864
YW
2112 print(output)
2113 self.assertRegex(output, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
371810d1 2114 output = check_output('ip -d link show ip6gretun98')
6a97a864
YW
2115 print(output)
2116 self.assertRegex(output, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
371810d1 2117 output = check_output('ip -d link show ip6gretun97')
6a97a864
YW
2118 print(output)
2119 self.assertRegex(output, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
42a29fcb
YW
2120 output = check_output('ip -d link show ip6gretun96')
2121 print(output)
2122 self.assertRegex(output, 'ip6gre remote any local any dev dummy98')
1f0e3109 2123
11309591 2124 def test_gretap_tunnel(self):
a962d857
YW
2125 copy_network_unit('12-dummy.netdev', '25-gretap.network',
2126 '25-gretap-tunnel.netdev', '25-tunnel.network',
2127 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
2cf6fdff 2128 start_networkd()
95e1fbba 2129 self.wait_online('gretap99:routable', 'gretap98:routable', 'dummy98:degraded')
6a97a864 2130
371810d1 2131 output = check_output('ip -d link show gretap99')
6a97a864
YW
2132 print(output)
2133 self.assertRegex(output, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
38f4bb44
YW
2134 self.assertRegex(output, 'ikey 0.0.0.106')
2135 self.assertRegex(output, 'okey 0.0.0.106')
2136 self.assertRegex(output, 'iseq')
2137 self.assertRegex(output, 'oseq')
b67e8a4e
YZ
2138 self.assertIn('nopmtudisc', output)
2139 self.assertIn('ignore-df', output)
371810d1 2140 output = check_output('ip -d link show gretap98')
6a97a864
YW
2141 print(output)
2142 self.assertRegex(output, 'gretap remote 10.65.223.239 local any dev dummy98')
38f4bb44
YW
2143 self.assertRegex(output, 'ikey 0.0.0.107')
2144 self.assertRegex(output, 'okey 0.0.0.107')
2145 self.assertRegex(output, 'iseq')
2146 self.assertRegex(output, 'oseq')
1f0e3109
SS
2147
2148 def test_ip6gretap_tunnel(self):
a962d857
YW
2149 copy_network_unit('12-dummy.netdev', '25-ip6gretap.network',
2150 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
2151 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
2cf6fdff 2152 start_networkd()
95e1fbba 2153 self.wait_online('ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded')
6a97a864 2154
371810d1 2155 output = check_output('ip -d link show ip6gretap99')
6a97a864
YW
2156 print(output)
2157 self.assertRegex(output, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
371810d1 2158 output = check_output('ip -d link show ip6gretap98')
6a97a864
YW
2159 print(output)
2160 self.assertRegex(output, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1f0e3109
SS
2161
2162 def test_vti_tunnel(self):
a962d857
YW
2163 copy_network_unit('12-dummy.netdev', '25-vti.network',
2164 '25-vti-tunnel.netdev', '25-tunnel.network',
2165 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
2166 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
2167 '25-vti-tunnel-any-any.netdev', '25-tunnel-any-any.network')
2cf6fdff 2168 start_networkd()
95e1fbba 2169 self.wait_online('vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'vtitun96:routable', 'dummy98:degraded')
6a97a864 2170
371810d1 2171 output = check_output('ip -d link show vtitun99')
6a97a864
YW
2172 print(output)
2173 self.assertRegex(output, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
371810d1 2174 output = check_output('ip -d link show vtitun98')
6a97a864
YW
2175 print(output)
2176 self.assertRegex(output, 'vti remote 10.65.223.239 local any dev dummy98')
371810d1 2177 output = check_output('ip -d link show vtitun97')
6a97a864
YW
2178 print(output)
2179 self.assertRegex(output, 'vti remote any local 10.65.223.238 dev dummy98')
42a29fcb
YW
2180 output = check_output('ip -d link show vtitun96')
2181 print(output)
2182 self.assertRegex(output, 'vti remote any local any dev dummy98')
1f0e3109
SS
2183
2184 def test_vti6_tunnel(self):
a962d857
YW
2185 copy_network_unit('12-dummy.netdev', '25-vti6.network',
2186 '25-vti6-tunnel.netdev', '25-tunnel.network',
2187 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
2188 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
2cf6fdff 2189 start_networkd()
95e1fbba 2190 self.wait_online('vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded')
6a97a864 2191
371810d1 2192 output = check_output('ip -d link show vti6tun99')
6a97a864
YW
2193 print(output)
2194 self.assertRegex(output, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
371810d1 2195 output = check_output('ip -d link show vti6tun98')
6a97a864 2196 print(output)
426654d7 2197 self.assertRegex(output, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
371810d1 2198 output = check_output('ip -d link show vti6tun97')
6a97a864 2199 print(output)
426654d7 2200 self.assertRegex(output, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1f0e3109
SS
2201
2202 def test_ip6tnl_tunnel(self):
a962d857
YW
2203 copy_network_unit('12-dummy.netdev', '25-ip6tnl.network',
2204 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
2205 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
2206 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
2207 '25-veth.netdev', '25-ip6tnl-slaac.network', '25-ipv6-prefix.network',
2208 '25-ip6tnl-tunnel-local-slaac.netdev', '25-ip6tnl-tunnel-local-slaac.network',
2209 '25-ip6tnl-tunnel-external.netdev', '26-netdev-link-local-addressing-yes.network')
2cf6fdff 2210 start_networkd()
95e1fbba
YW
2211 self.wait_online('ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable',
2212 'ip6tnl-slaac:degraded', 'ip6tnl-external:degraded',
2213 'dummy98:degraded', 'veth99:routable', 'veth-peer:degraded')
6a97a864 2214
371810d1 2215 output = check_output('ip -d link show ip6tnl99')
6a97a864 2216 print(output)
da7d6848 2217 self.assertIn('ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98', output)
371810d1 2218 output = check_output('ip -d link show ip6tnl98')
6a97a864 2219 print(output)
426654d7 2220 self.assertRegex(output, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
371810d1 2221 output = check_output('ip -d link show ip6tnl97')
6a97a864 2222 print(output)
426654d7 2223 self.assertRegex(output, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
7809cab7
YW
2224 output = check_output('ip -d link show ip6tnl-external')
2225 print(output)
2226 self.assertIn('ip6tnl-external@NONE:', output)
2227 self.assertIn('ip6tnl external ', output)
da7d6848
YW
2228 output = check_output('ip -d link show ip6tnl-slaac')
2229 print(output)
2230 self.assertIn('ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99', output)
2231
2232 output = check_output('ip -6 address show veth99')
2233 print(output)
2234 self.assertIn('inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic', output)
2235
2236 output = check_output('ip -4 route show default')
2237 print(output)
2238 self.assertIn('default dev ip6tnl-slaac proto static', output)
1f0e3109
SS
2239
2240 def test_sit_tunnel(self):
a962d857
YW
2241 copy_network_unit('12-dummy.netdev', '25-sit.network',
2242 '25-sit-tunnel.netdev', '25-tunnel.network',
2243 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
2244 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
2245 '25-sit-tunnel-any-any.netdev', '25-tunnel-any-any.network')
2cf6fdff 2246 start_networkd()
95e1fbba 2247 self.wait_online('sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'sittun96:routable', 'dummy98:degraded')
6a97a864 2248
371810d1 2249 output = check_output('ip -d link show sittun99')
6a97a864 2250 print(output)
426654d7 2251 self.assertRegex(output, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98")
371810d1 2252 output = check_output('ip -d link show sittun98')
6a97a864 2253 print(output)
426654d7 2254 self.assertRegex(output, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98")
371810d1 2255 output = check_output('ip -d link show sittun97')
6a97a864 2256 print(output)
426654d7 2257 self.assertRegex(output, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98")
42a29fcb
YW
2258 output = check_output('ip -d link show sittun96')
2259 print(output)
426654d7 2260 self.assertRegex(output, "sit (ip6ip )?remote any local any dev dummy98")
1f0e3109 2261
d0e728b6 2262 def test_isatap_tunnel(self):
a962d857
YW
2263 copy_network_unit('12-dummy.netdev', '25-isatap.network',
2264 '25-isatap-tunnel.netdev', '25-tunnel.network')
2cf6fdff 2265 start_networkd()
95e1fbba 2266 self.wait_online('isataptun99:routable', 'dummy98:degraded')
d0e728b6 2267
371810d1 2268 output = check_output('ip -d link show isataptun99')
14ecd604 2269 print(output)
d0e728b6
SS
2270 self.assertRegex(output, "isatap ")
2271
d29dc4f1 2272 def test_6rd_tunnel(self):
a962d857
YW
2273 copy_network_unit('12-dummy.netdev', '25-6rd.network',
2274 '25-6rd-tunnel.netdev', '25-tunnel.network')
2cf6fdff 2275 start_networkd()
95e1fbba 2276 self.wait_online('sittun99:routable', 'dummy98:degraded')
d29dc4f1 2277
371810d1 2278 output = check_output('ip -d link show sittun99')
6a97a864
YW
2279 print(output)
2280 self.assertRegex(output, '6rd-prefix 2602::/24')
2281
2f0260c1
YW
2282 @expectedFailureIfERSPANv0IsNotSupported()
2283 def test_erspan_tunnel_v0(self):
a962d857
YW
2284 copy_network_unit('12-dummy.netdev', '25-erspan.network',
2285 '25-erspan0-tunnel.netdev', '25-tunnel.network',
2286 '25-erspan0-tunnel-local-any.netdev', '25-tunnel-local-any.network')
2cf6fdff 2287 start_networkd()
95e1fbba 2288 self.wait_online('erspan99:routable', 'erspan98:routable', 'dummy98:degraded')
2266864b 2289
371810d1 2290 output = check_output('ip -d link show erspan99')
6a97a864 2291 print(output)
2f0260c1
YW
2292 self.assertIn('erspan remote 172.16.1.100 local 172.16.1.200', output)
2293 self.assertIn('erspan_ver 0', output)
2294 self.assertNotIn('erspan_index 123', output)
2295 self.assertNotIn('erspan_dir ingress', output)
2296 self.assertNotIn('erspan_hwid 1f', output)
2297 self.assertIn('ikey 0.0.0.101', output)
2298 self.assertIn('iseq', output)
b67e8a4e
YZ
2299 self.assertIn('nopmtudisc', output)
2300 self.assertIn('ignore-df', output)
371810d1 2301 output = check_output('ip -d link show erspan98')
2266864b 2302 print(output)
2f0260c1
YW
2303 self.assertIn('erspan remote 172.16.1.100 local any', output)
2304 self.assertIn('erspan_ver 0', output)
2305 self.assertNotIn('erspan_index 124', output)
2306 self.assertNotIn('erspan_dir egress', output)
2307 self.assertNotIn('erspan_hwid 2f', output)
2308 self.assertIn('ikey 0.0.0.102', output)
2309 self.assertIn('iseq', output)
2310
2311 def test_erspan_tunnel_v1(self):
a962d857
YW
2312 copy_network_unit('12-dummy.netdev', '25-erspan.network',
2313 '25-erspan1-tunnel.netdev', '25-tunnel.network',
2314 '25-erspan1-tunnel-local-any.netdev', '25-tunnel-local-any.network')
2f0260c1 2315 start_networkd()
95e1fbba 2316 self.wait_online('erspan99:routable', 'erspan98:routable', 'dummy98:degraded')
2f0260c1
YW
2317
2318 output = check_output('ip -d link show erspan99')
2319 print(output)
2320 self.assertIn('erspan remote 172.16.1.100 local 172.16.1.200', output)
2321 self.assertIn('erspan_ver 1', output)
2322 self.assertIn('erspan_index 123', output)
2323 self.assertNotIn('erspan_dir ingress', output)
2324 self.assertNotIn('erspan_hwid 1f', output)
2325 self.assertIn('ikey 0.0.0.101', output)
2326 self.assertIn('okey 0.0.0.101', output)
2327 self.assertIn('iseq', output)
2328 self.assertIn('oseq', output)
2329 output = check_output('ip -d link show erspan98')
2330 print(output)
2331 self.assertIn('erspan remote 172.16.1.100 local any', output)
2332 self.assertIn('erspan_ver 1', output)
2333 self.assertIn('erspan_index 124', output)
2334 self.assertNotIn('erspan_dir egress', output)
2335 self.assertNotIn('erspan_hwid 2f', output)
2336 self.assertIn('ikey 0.0.0.102', output)
2337 self.assertIn('okey 0.0.0.102', output)
2338 self.assertIn('iseq', output)
2339 self.assertIn('oseq', output)
2340
2341 @expectedFailureIfERSPANv2IsNotSupported()
2342 def test_erspan_tunnel_v2(self):
a962d857
YW
2343 copy_network_unit('12-dummy.netdev', '25-erspan.network',
2344 '25-erspan2-tunnel.netdev', '25-tunnel.network',
2345 '25-erspan2-tunnel-local-any.netdev', '25-tunnel-local-any.network')
2f0260c1 2346 start_networkd()
95e1fbba 2347 self.wait_online('erspan99:routable', 'erspan98:routable', 'dummy98:degraded')
2f0260c1
YW
2348
2349 output = check_output('ip -d link show erspan99')
2350 print(output)
2351 self.assertIn('erspan remote 172.16.1.100 local 172.16.1.200', output)
2352 self.assertIn('erspan_ver 2', output)
2353 self.assertNotIn('erspan_index 123', output)
2354 self.assertIn('erspan_dir ingress', output)
2355 self.assertIn('erspan_hwid 0x1f', output)
2356 self.assertIn('ikey 0.0.0.101', output)
2357 self.assertIn('okey 0.0.0.101', output)
2358 self.assertIn('iseq', output)
2359 self.assertIn('oseq', output)
2360 output = check_output('ip -d link show erspan98')
2361 print(output)
2362 self.assertIn('erspan remote 172.16.1.100 local any', output)
2363 self.assertIn('erspan_ver 2', output)
2364 self.assertNotIn('erspan_index 124', output)
2365 self.assertIn('erspan_dir egress', output)
2366 self.assertIn('erspan_hwid 0x2f', output)
2367 self.assertIn('ikey 0.0.0.102', output)
2368 self.assertIn('okey 0.0.0.102', output)
2369 self.assertIn('iseq', output)
2370 self.assertIn('oseq', output)
2266864b 2371
1f0e3109 2372 def test_tunnel_independent(self):
a962d857 2373 copy_network_unit('25-ipip-tunnel-independent.netdev', '26-netdev-link-local-addressing-yes.network')
2cf6fdff 2374 start_networkd()
e40a58b5 2375
95e1fbba 2376 self.wait_online('ipiptun99:carrier')
1f0e3109 2377
95082dbe 2378 def test_tunnel_independent_loopback(self):
a962d857 2379 copy_network_unit('25-ipip-tunnel-independent-loopback.netdev', '26-netdev-link-local-addressing-yes.network')
95082dbe
YW
2380 start_networkd()
2381
95e1fbba 2382 self.wait_online('ipiptun99:carrier')
95082dbe 2383
e64dc406
YW
2384 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
2385 def test_xfrm(self):
a962d857
YW
2386 copy_network_unit('12-dummy.netdev', '25-xfrm.network',
2387 '25-xfrm.netdev', '25-xfrm-independent.netdev',
2388 '26-netdev-link-local-addressing-yes.network')
e64dc406
YW
2389 start_networkd()
2390
95e1fbba 2391 self.wait_online('dummy98:degraded', 'xfrm98:degraded', 'xfrm99:degraded')
e64dc406 2392
020483b2 2393 output = check_output('ip -d link show dev xfrm98')
e64dc406 2394 print(output)
020483b2
YW
2395 self.assertIn('xfrm98@dummy98:', output)
2396 self.assertIn('xfrm if_id 0x98 ', output)
e64dc406 2397
020483b2
YW
2398 output = check_output('ip -d link show dev xfrm99')
2399 print(output)
2400 self.assertIn('xfrm99@lo:', output)
2401 self.assertIn('xfrm if_id 0x99 ', output)
e64dc406 2402
4b6a6d1e
YW
2403 @expectedFailureIfModuleIsNotAvailable('fou')
2404 def test_fou(self):
2405 # The following redundant check is necessary for CentOS CI.
2406 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
2407 self.assertTrue(is_module_available('fou'))
2408
a962d857
YW
2409 copy_network_unit('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
2410 '25-fou-ipip.netdev', '25-fou-sit.netdev',
2411 '25-fou-gre.netdev', '25-fou-gretap.netdev')
2cf6fdff 2412 start_networkd()
4b6a6d1e 2413
95e1fbba 2414 self.wait_online('ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off', setup_state='unmanaged')
4b6a6d1e 2415
371810d1 2416 output = check_output('ip fou show')
4b6a6d1e
YW
2417 print(output)
2418 self.assertRegex(output, 'port 55555 ipproto 4')
2419 self.assertRegex(output, 'port 55556 ipproto 47')
2420
371810d1 2421 output = check_output('ip -d link show ipiptun96')
4b6a6d1e
YW
2422 print(output)
2423 self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55555')
371810d1 2424 output = check_output('ip -d link show sittun96')
4b6a6d1e
YW
2425 print(output)
2426 self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55555')
371810d1 2427 output = check_output('ip -d link show gretun96')
4b6a6d1e
YW
2428 print(output)
2429 self.assertRegex(output, 'encap fou encap-sport 1001 encap-dport 55556')
371810d1 2430 output = check_output('ip -d link show gretap96')
4b6a6d1e
YW
2431 print(output)
2432 self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55556')
2433
1f0e3109 2434 def test_vxlan(self):
a962d857
YW
2435 copy_network_unit('11-dummy.netdev', '25-vxlan-test1.network',
2436 '25-vxlan.netdev', '25-vxlan.network',
2437 '25-vxlan-ipv6.netdev', '25-vxlan-ipv6.network',
2438 '25-vxlan-independent.netdev', '26-netdev-link-local-addressing-yes.network',
2439 '25-veth.netdev', '25-vxlan-veth99.network', '25-ipv6-prefix.network',
2440 '25-vxlan-local-slaac.netdev', '25-vxlan-local-slaac.network')
2cf6fdff 2441 start_networkd()
1f0e3109 2442
95e1fbba
YW
2443 self.wait_online('test1:degraded', 'veth99:routable', 'veth-peer:degraded',
2444 'vxlan99:degraded', 'vxlan98:degraded', 'vxlan97:degraded', 'vxlan-slaac:degraded')
1f0e3109 2445
a5e478b2 2446 output = check_output('ip -d -d link show vxlan99')
14ecd604 2447 print(output)
cca07d91
YW
2448 self.assertIn('999', output)
2449 self.assertIn('5555', output)
2450 self.assertIn('l2miss', output)
2451 self.assertIn('l3miss', output)
cca07d91 2452 self.assertIn('gbp', output)
a5e478b2
FS
2453 # Since [0] some of the options use slightly different names and some
2454 # options with default values are shown only if the -d(etails) setting
2455 # is repeated
2456 # [0] https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit/?id=1215e9d3862387353d8672296cb4c6c16e8cbb72
2457 self.assertRegex(output, '(udpcsum|udp_csum)')
2458 self.assertRegex(output, '(udp6zerocsumtx|udp_zero_csum6_tx)')
2459 self.assertRegex(output, '(udp6zerocsumrx|udp_zero_csum6_rx)')
2460 self.assertRegex(output, '(remcsumtx|remcsum_tx)')
2461 self.assertRegex(output, '(remcsumrx|remcsum_rx)')
1f0e3109 2462
371810d1 2463 output = check_output('bridge fdb show dev vxlan99')
1c862fe0 2464 print(output)
cca07d91
YW
2465 self.assertIn('00:11:22:33:44:55 dst 10.0.0.5 self permanent', output)
2466 self.assertIn('00:11:22:33:44:66 dst 10.0.0.6 self permanent', output)
2467 self.assertIn('00:11:22:33:44:77 dst 10.0.0.7 via test1 self permanent', output)
1c862fe0 2468
10d670a3 2469 output = networkctl_status('vxlan99')
36bc2ffb 2470 print(output)
cca07d91
YW
2471 self.assertIn('VNI: 999', output)
2472 self.assertIn('Destination Port: 5555', output)
2473 self.assertIn('Underlying Device: test1', output)
2474
2475 output = check_output('bridge fdb show dev vxlan97')
2476 print(output)
2477 self.assertIn('00:00:00:00:00:00 dst fe80::23b:d2ff:fe95:967f via test1 self permanent', output)
2478 self.assertIn('00:00:00:00:00:00 dst fe80::27c:16ff:fec0:6c74 via test1 self permanent', output)
2479 self.assertIn('00:00:00:00:00:00 dst fe80::2a2:e4ff:fef9:2269 via test1 self permanent', output)
36bc2ffb 2480
49ad8da7
YW
2481 output = check_output('ip -d link show vxlan-slaac')
2482 print(output)
2483 self.assertIn('vxlan id 4831584 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99', output)
2484
2485 output = check_output('ip -6 address show veth99')
2486 print(output)
2487 self.assertIn('inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic', output)
2488
b3de9d7b 2489 @unittest.skipUnless(compare_kernel_version("6"), reason="Causes kernel panic on unpatched kernels: https://bugzilla.kernel.org/show_bug.cgi?id=208315")
02849d8b 2490 def test_macsec(self):
a962d857
YW
2491 copy_network_unit('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
2492 '26-macsec.network', '12-dummy.netdev')
2cf6fdff 2493 start_networkd()
02849d8b 2494
95e1fbba 2495 self.wait_online('dummy98:degraded', 'macsec99:routable')
02849d8b 2496
371810d1 2497 output = check_output('ip -d link show macsec99')
02849d8b
YW
2498 print(output)
2499 self.assertRegex(output, 'macsec99@dummy98')
2500 self.assertRegex(output, 'macsec sci [0-9a-f]*000b')
2501 self.assertRegex(output, 'encrypt on')
2502
371810d1 2503 output = check_output('ip macsec show macsec99')
02849d8b
YW
2504 print(output)
2505 self.assertRegex(output, 'encrypt on')
2506 self.assertRegex(output, 'TXSC: [0-9a-f]*000b on SA 1')
2507 self.assertRegex(output, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
2508 self.assertRegex(output, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
2509 self.assertRegex(output, 'RXSC: c619528fe6a00100, state on')
2510 self.assertRegex(output, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
2511 self.assertRegex(output, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
2512 self.assertRegex(output, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
2513 self.assertRegex(output, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
2514 self.assertNotRegex(output, 'key 02030405067080900000000000000000')
2515 self.assertRegex(output, 'RXSC: 8c16456c83a90002, state on')
2516 self.assertRegex(output, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
2517
811f33d0 2518 def test_nlmon(self):
a962d857 2519 copy_network_unit('25-nlmon.netdev', '26-netdev-link-local-addressing-yes.network')
2cf6fdff 2520 start_networkd()
811f33d0 2521
95e1fbba 2522 self.wait_online('nlmon99:carrier')
02849d8b 2523
b076d5d7
YW
2524 @expectedFailureIfModuleIsNotAvailable('ifb')
2525 def test_ifb(self):
a962d857 2526 copy_network_unit('25-ifb.netdev', '26-netdev-link-local-addressing-yes.network')
b076d5d7
YW
2527 start_networkd()
2528
95e1fbba 2529 self.wait_online('ifb99:degraded')
b076d5d7 2530
a6f5673c
RRZ
2531 @unittest.skipUnless(os.cpu_count() >= 2, reason="CPU count should be >= 2 to pass this test")
2532 def test_rps_cpu_1(self):
4b35dab8 2533 copy_network_unit('12-dummy.netdev', '12-dummy.network', '25-rps-cpu-1.link')
a6f5673c
RRZ
2534 start_networkd()
2535
4b35dab8 2536 self.wait_online('dummy98:carrier')
a6f5673c
RRZ
2537
2538 output = check_output('cat /sys/class/net/dummy98/queues/rx-0/rps_cpus')
2539 print(output)
2540 self.assertEqual(int(output.replace(',', ''), base=16), 2)
2541
2542 @unittest.skipUnless(os.cpu_count() >= 2, reason="CPU count should be >= 2 to pass this test")
2543 def test_rps_cpu_0_1(self):
4b35dab8 2544 copy_network_unit('12-dummy.netdev', '12-dummy.network', '25-rps-cpu-0-1.link')
a6f5673c
RRZ
2545 start_networkd()
2546
4b35dab8 2547 self.wait_online('dummy98:carrier')
a6f5673c
RRZ
2548
2549 output = check_output('cat /sys/class/net/dummy98/queues/rx-0/rps_cpus')
2550 print(output)
2551 self.assertEqual(int(output.replace(',', ''), base=16), 3)
2552
2553 @unittest.skipUnless(os.cpu_count() >= 4, reason="CPU count should be >= 4 to pass this test")
2554 def test_rps_cpu_multi(self):
4b35dab8 2555 copy_network_unit('12-dummy.netdev', '12-dummy.network', '25-rps-cpu-multi.link')
a6f5673c
RRZ
2556 start_networkd()
2557
4b35dab8 2558 self.wait_online('dummy98:carrier')
a6f5673c
RRZ
2559
2560 output = check_output('cat /sys/class/net/dummy98/queues/rx-0/rps_cpus')
2561 print(output)
2562 self.assertEqual(int(output.replace(',', ''), base=16), 15)
2563
4b35dab8 2564 def test_rps_cpu(self):
a6f5673c
RRZ
2565 cpu_count = os.cpu_count()
2566
4b35dab8 2567 copy_network_unit('12-dummy.netdev', '12-dummy.network')
a6f5673c
RRZ
2568 start_networkd()
2569
4b35dab8 2570 self.wait_online('dummy98:carrier')
a6f5673c 2571
4b35dab8
YW
2572 # 0
2573 copy_network_unit('25-rps-cpu-0.link')
2574 udevadm_trigger('/sys/class/net/dummy98')
a6f5673c
RRZ
2575 output = check_output('cat /sys/class/net/dummy98/queues/rx-0/rps_cpus')
2576 print(output)
4b35dab8
YW
2577 self.assertEqual(int(output.replace(',', ''), base=16), 1)
2578 remove_network_unit('25-rps-cpu-0.link')
a6f5673c 2579
4b35dab8
YW
2580 # all
2581 copy_network_unit('25-rps-cpu-all.link')
2582 udevadm_trigger('/sys/class/net/dummy98')
a6f5673c
RRZ
2583 output = check_output('cat /sys/class/net/dummy98/queues/rx-0/rps_cpus')
2584 print(output)
4b35dab8
YW
2585 self.assertEqual(f"{int(output.replace(',', ''), base=16):x}", f'{(1 << cpu_count) - 1:x}')
2586 remove_network_unit('25-rps-cpu-all.link')
a6f5673c 2587
4b35dab8
YW
2588 # disable
2589 copy_network_unit('24-rps-cpu-disable.link')
2590 udevadm_trigger('/sys/class/net/dummy98')
a6f5673c
RRZ
2591 output = check_output('cat /sys/class/net/dummy98/queues/rx-0/rps_cpus')
2592 print(output)
2593 self.assertEqual(int(output.replace(',', ''), base=16), 0)
4b35dab8 2594 remove_network_unit('24-rps-cpu-disable.link')
a6f5673c 2595
4b35dab8
YW
2596 # set all again
2597 copy_network_unit('25-rps-cpu-all.link')
2598 udevadm_trigger('/sys/class/net/dummy98')
a6f5673c
RRZ
2599 output = check_output('cat /sys/class/net/dummy98/queues/rx-0/rps_cpus')
2600 print(output)
4b35dab8
YW
2601 self.assertEqual(f"{int(output.replace(',', ''), base=16):x}", f'{(1 << cpu_count) - 1:x}')
2602 remove_network_unit('25-rps-cpu-all.link')
a6f5673c 2603
4b35dab8
YW
2604 # empty -> unchanged
2605 copy_network_unit('24-rps-cpu-empty.link')
2606 udevadm_trigger('/sys/class/net/dummy98')
a6f5673c
RRZ
2607 output = check_output('cat /sys/class/net/dummy98/queues/rx-0/rps_cpus')
2608 print(output)
4b35dab8
YW
2609 self.assertEqual(f"{int(output.replace(',', ''), base=16):x}", f'{(1 << cpu_count) - 1:x}')
2610 remove_network_unit('24-rps-cpu-empty.link')
a6f5673c 2611
4b35dab8
YW
2612 # 0, then empty -> unchanged
2613 copy_network_unit('25-rps-cpu-0-empty.link')
2614 udevadm_trigger('/sys/class/net/dummy98')
a6f5673c
RRZ
2615 output = check_output('cat /sys/class/net/dummy98/queues/rx-0/rps_cpus')
2616 print(output)
4b35dab8
YW
2617 self.assertEqual(f"{int(output.replace(',', ''), base=16):x}", f'{(1 << cpu_count) - 1:x}')
2618 remove_network_unit('25-rps-cpu-0-empty.link')
a6f5673c 2619
4b35dab8
YW
2620 # 0, then invalid -> 0
2621 copy_network_unit('25-rps-cpu-0-invalid.link')
2622 udevadm_trigger('/sys/class/net/dummy98')
a6f5673c
RRZ
2623 output = check_output('cat /sys/class/net/dummy98/queues/rx-0/rps_cpus')
2624 print(output)
2625 self.assertEqual(int(output.replace(',', ''), base=16), 1)
4b35dab8 2626 remove_network_unit('25-rps-cpu-0-invalid.link')
a6f5673c 2627
4b35dab8
YW
2628 # invalid -> unchanged
2629 copy_network_unit('24-rps-cpu-invalid.link')
2630 udevadm_trigger('/sys/class/net/dummy98')
a6f5673c
RRZ
2631 output = check_output('cat /sys/class/net/dummy98/queues/rx-0/rps_cpus')
2632 print(output)
4b35dab8
YW
2633 self.assertEqual(int(output.replace(',', ''), base=16), 1)
2634 remove_network_unit('24-rps-cpu-invalid.link')
a6f5673c 2635
cff83db9
YW
2636class NetworkdL2TPTests(unittest.TestCase, Utilities):
2637
cff83db9 2638 def setUp(self):
a962d857 2639 setup_common()
cff83db9
YW
2640
2641 def tearDown(self):
a962d857 2642 tear_down_common()
cff83db9 2643
59edcf2b 2644 @expectedFailureIfModuleIsNotAvailable('l2tp_eth', 'l2tp_netlink')
cff83db9 2645 def test_l2tp_udp(self):
a962d857
YW
2646 copy_network_unit('11-dummy.netdev', '25-l2tp-dummy.network',
2647 '25-l2tp-udp.netdev', '25-l2tp.network')
2cf6fdff 2648 start_networkd()
cff83db9 2649
95e1fbba 2650 self.wait_online('test1:routable', 'l2tp-ses1:degraded', 'l2tp-ses2:degraded')
cff83db9 2651
371810d1 2652 output = check_output('ip l2tp show tunnel tunnel_id 10')
cff83db9
YW
2653 print(output)
2654 self.assertRegex(output, "Tunnel 10, encap UDP")
2655 self.assertRegex(output, "From 192.168.30.100 to 192.168.30.101")
2656 self.assertRegex(output, "Peer tunnel 11")
2657 self.assertRegex(output, "UDP source / dest ports: 3000/4000")
2658 self.assertRegex(output, "UDP checksum: enabled")
2659
371810d1 2660 output = check_output('ip l2tp show session tid 10 session_id 15')
cff83db9
YW
2661 print(output)
2662 self.assertRegex(output, "Session 15 in tunnel 10")
2663 self.assertRegex(output, "Peer session 16, tunnel 11")
2664 self.assertRegex(output, "interface name: l2tp-ses1")
2665
371810d1 2666 output = check_output('ip l2tp show session tid 10 session_id 17')
cff83db9
YW
2667 print(output)
2668 self.assertRegex(output, "Session 17 in tunnel 10")
2669 self.assertRegex(output, "Peer session 18, tunnel 11")
2670 self.assertRegex(output, "interface name: l2tp-ses2")
2671
59edcf2b 2672 @expectedFailureIfModuleIsNotAvailable('l2tp_eth', 'l2tp_ip', 'l2tp_netlink')
cff83db9 2673 def test_l2tp_ip(self):
a962d857
YW
2674 copy_network_unit('11-dummy.netdev', '25-l2tp-dummy.network',
2675 '25-l2tp-ip.netdev', '25-l2tp.network')
2cf6fdff 2676 start_networkd()
cff83db9 2677
95e1fbba 2678 self.wait_online('test1:routable', 'l2tp-ses3:degraded', 'l2tp-ses4:degraded')
cff83db9 2679
371810d1 2680 output = check_output('ip l2tp show tunnel tunnel_id 10')
cff83db9
YW
2681 print(output)
2682 self.assertRegex(output, "Tunnel 10, encap IP")
2683 self.assertRegex(output, "From 192.168.30.100 to 192.168.30.101")
2684 self.assertRegex(output, "Peer tunnel 12")
2685
371810d1 2686 output = check_output('ip l2tp show session tid 10 session_id 25')
cff83db9
YW
2687 print(output)
2688 self.assertRegex(output, "Session 25 in tunnel 10")
2689 self.assertRegex(output, "Peer session 26, tunnel 12")
2690 self.assertRegex(output, "interface name: l2tp-ses3")
2691
371810d1 2692 output = check_output('ip l2tp show session tid 10 session_id 27')
cff83db9
YW
2693 print(output)
2694 self.assertRegex(output, "Session 27 in tunnel 10")
2695 self.assertRegex(output, "Peer session 28, tunnel 12")
2696 self.assertRegex(output, "interface name: l2tp-ses4")
2697
be68c2c9 2698class NetworkdNetworkTests(unittest.TestCase, Utilities):
95c74b0a 2699
1f0e3109 2700 def setUp(self):
a962d857 2701 setup_common()
1f0e3109
SS
2702
2703 def tearDown(self):
a962d857 2704 tear_down_common()
1f0e3109 2705
f2bcd324
YW
2706 def verify_address_static(
2707 self,
2708 label1: str,
2709 label2: str,
2710 label3: str,
2711 broadcast1: str,
2712 broadcast2: str,
2713 broadcast3: str,
2714 peer1: str,
2715 peer2: str,
2716 peer3: str,
2717 peer4: str,
2718 peer5: str,
2719 peer6: str,
2720 scope1: str,
2721 scope2: str,
2722 deprecated1: str,
2723 deprecated2: str,
2724 deprecated3: str,
2725 deprecated4: str,
2726 route_metric: int,
2727 flag1: str,
2728 flag2: str,
2729 flag3: str,
2730 flag4: str,
d5adff70
YW
2731 ip4_null_16: str,
2732 ip4_null_24: str,
2733 ip6_null_73: str,
2734 ip6_null_74: str,
f2bcd324
YW
2735 ):
2736 output = check_output('ip address show dev dummy98')
2737 print(output)
2738
2739 # simple settings
4a704501
YW
2740 self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output)
2741 self.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output)
2742 self.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output)
4a704501
YW
2743 self.assertIn('inet6 2001:db8:0:f101::15/64 scope global', output)
2744 self.assertIn('inet6 2001:db8:0:f101::16/64 scope global', output)
2745 self.assertIn('inet6 2001:db8:0:f102::15/64 scope global', output)
f2bcd324
YW
2746
2747 # label
2748 self.assertIn(f'inet 10.3.1.1/24 brd 10.3.1.255 scope global {label1}', output)
2749 self.assertIn(f'inet 10.3.2.1/24 brd 10.3.2.255 scope global {label2}', output)
2750 self.assertIn(f'inet 10.3.3.1/24 brd 10.3.3.255 scope global {label3}', output)
2751
2752 # broadcast
2753 self.assertIn(f'inet 10.4.1.1/24{broadcast1} scope global dummy98', output)
2754 self.assertIn(f'inet 10.4.2.1/24{broadcast2} scope global dummy98', output)
2755 self.assertIn(f'inet 10.4.3.1/24{broadcast3} scope global dummy98', output)
2756
2757 # peer
2758 self.assertIn(f'inet 10.5.1.1{peer1} scope global dummy98', output)
2759 self.assertIn(f'inet 10.5.2.1{peer2} scope global dummy98', output)
2760 self.assertIn(f'inet 10.5.3.1{peer3} scope global dummy98', output)
2761 self.assertIn(f'inet6 2001:db8:0:f103::1{peer4} scope global', output)
2762 self.assertIn(f'inet6 2001:db8:0:f103::2{peer5} scope global', output)
2763 self.assertIn(f'inet6 2001:db8:0:f103::3{peer6} scope global', output)
2764
2765 # scope
2766 self.assertIn(f'inet 10.6.1.1/24 brd 10.6.1.255 scope {scope1} dummy98', output)
2767 self.assertIn(f'inet 10.6.2.1/24 brd 10.6.2.255 scope {scope2} dummy98', output)
2768
2769 # lifetime
2770 self.assertIn(f'inet 10.7.1.1/24 brd 10.7.1.255 scope global{deprecated1} dummy98', output)
2771 self.assertIn(f'inet 10.7.2.1/24 brd 10.7.2.255 scope global{deprecated2} dummy98', output)
2772 self.assertIn(f'inet6 2001:db8:0:f104::1/64 scope global{deprecated3}', output)
2773 self.assertIn(f'inet6 2001:db8:0:f104::2/64 scope global{deprecated4}', output)
2774
2775 # route metric
2776 self.assertRegex(output, rf'inet 10.8.1.1/24 (metric {route_metric} |)brd 10.8.1.255 scope global dummy98')
2777 self.assertRegex(output, rf'inet6 2001:db8:0:f105::1/64 (metric {route_metric} |)scope global')
2778
2779 output_route = check_output('ip -4 route show dev dummy98 10.8.1.0/24')
2780 print(output_route)
2781 self.assertIn(f'10.8.1.0/24 proto kernel scope link src 10.8.1.1 metric {route_metric}', output_route)
2782
2783 output_route = check_output('ip -6 route show dev dummy98 2001:db8:0:f105::/64')
2784 print(output_route)
2785 self.assertIn(f'2001:db8:0:f105::/64 proto kernel metric {route_metric}', output_route)
2786
2787 # flags
2788 self.assertIn(f'inet 10.9.1.1/24 brd 10.9.1.255 scope global{flag1} dummy98', output)
2789 self.assertIn(f'inet 10.9.2.1/24 brd 10.9.2.255 scope global{flag2} dummy98', output)
2790 self.assertIn(f'inet6 2001:db8:0:f106::1/64 scope global{flag3}', output)
2791 self.assertIn(f'inet6 2001:db8:0:f106::2/64 scope global{flag4}', output)
2792
2793 # null address
d5adff70
YW
2794 self.assertTrue(ip4_null_16.endswith('.0.1'))
2795 prefix16 = ip4_null_16[:-len('.0.1')]
2796 self.assertTrue(ip4_null_24.endswith('.1'))
2797 prefix24 = ip4_null_24[:-len('.1')]
2798 self.assertIn(f'inet {ip4_null_16}/16 brd {prefix16}.255.255 scope global subnet16', output)
2799 self.assertIn(f'inet {ip4_null_24}/24 brd {prefix24}.255 scope global subnet24', output)
2800 self.assertIn(f'inet6 {ip6_null_73}/73 scope global', output)
2801 self.assertIn(f'inet6 {ip6_null_74}/74 scope global', output)
f2bcd324
YW
2802
2803 # invalid sections
2804 self.assertNotIn('10.4.4.1', output)
2805 self.assertNotIn('10.5.4.1', output)
2806 self.assertNotIn('10.5.5.1', output)
2807 self.assertNotIn('10.8.2.1', output)
2808 self.assertNotIn('10.9.3.1', output)
2809 self.assertNotIn('2001:db8:0:f101::2', output)
2810 self.assertNotIn('2001:db8:0:f103::4', output)
b8102725 2811
d19704cd 2812 # netlabel
f2bcd324 2813 self.check_netlabel('dummy98', r'10\.10\.1\.0/24')
a4640bed 2814
10d670a3 2815 check_json(networkctl_json())
d19704cd
YW
2816
2817 def test_address_static(self):
d19704cd 2818 copy_network_unit('25-address-static.network', '12-dummy.netdev', copy_dropins=False)
c742d7e8
TM
2819 self.setup_nftset('addr4', 'ipv4_addr')
2820 self.setup_nftset('network4', 'ipv4_addr', 'flags interval;')
2821 self.setup_nftset('ifindex', 'iface_index')
1ce2ffac 2822 start_networkd()
d19704cd 2823
95e1fbba 2824 self.wait_online('dummy98:routable')
d5adff70
YW
2825
2826 ip4_null_16 = None
2827 ip4_null_24 = None
2828 output = check_output('ip -4 --json address show dev dummy98')
2829 for i in json.loads(output)[0]['addr_info']:
2830 if i['label'] == 'subnet16':
2831 ip4_null_16 = i['local']
2832 elif i['label'] == 'subnet24':
2833 ip4_null_24 = i['local']
2834 self.assertTrue(ip4_null_16.endswith('.0.1'))
2835 self.assertTrue(ip4_null_24.endswith('.1'))
2836
2837 ip6_null_73 = None
2838 ip6_null_74 = None
2839 output = check_output('ip -6 --json address show dev dummy98')
2840 for i in json.loads(output)[0]['addr_info']:
2841 if i['prefixlen'] == 73:
2842 ip6_null_73 = i['local']
2843 elif i['prefixlen'] == 74:
2844 ip6_null_74 = i['local']
2845 self.assertTrue(ip6_null_73.endswith(':1'))
2846 self.assertTrue(ip6_null_74.endswith(':1'))
2847
f2bcd324
YW
2848 self.verify_address_static(
2849 label1='label1',
2850 label2='label2',
2851 label3='dummy98',
2852 broadcast1='',
2853 broadcast2=' brd 10.4.2.255',
2854 broadcast3=' brd 10.4.3.63',
2855 peer1=' peer 10.5.1.101/24',
2856 peer2=' peer 10.5.2.101/24',
2857 peer3='/24 brd 10.5.3.255',
2858 peer4=' peer 2001:db8:0:f103::101/128',
2859 peer5=' peer 2001:db8:0:f103::102/128',
2860 peer6='/128',
2861 scope1='global',
2862 scope2='link',
2863 deprecated1='',
2864 deprecated2=' deprecated',
2865 deprecated3='',
2866 deprecated4=' deprecated',
2867 route_metric=128,
2868 flag1=' noprefixroute',
2869 flag2='',
2870 flag3=' noprefixroute',
2871 flag4=' home mngtmpaddr',
d5adff70
YW
2872 ip4_null_16=ip4_null_16,
2873 ip4_null_24=ip4_null_24,
2874 ip6_null_73=ip6_null_73,
2875 ip6_null_74=ip6_null_74,
f2bcd324 2876 )
c742d7e8 2877 # nft set
f432aa90
TM
2878 self.check_nftset('addr4', r'10\.10\.1\.1')
2879 self.check_nftset('network4', r'10\.10\.1\.0/24')
2880 self.check_nftset('ifindex', 'dummy98')
c742d7e8
TM
2881
2882 self.teardown_nftset('addr4', 'network4', 'ifindex')
f2bcd324
YW
2883
2884 copy_network_unit('25-address-static.network.d/10-override.conf')
d19704cd 2885 networkctl_reload()
95e1fbba 2886 self.wait_online('dummy98:routable')
f2bcd324
YW
2887 self.verify_address_static(
2888 label1='new-label1',
2889 label2='dummy98',
2890 label3='new-label3',
2891 broadcast1=' brd 10.4.1.255',
2892 broadcast2='',
2893 broadcast3=' brd 10.4.3.31',
2894 peer1=' peer 10.5.1.102/24',
2895 peer2='/24 brd 10.5.2.255',
2896 peer3=' peer 10.5.3.102/24',
2897 peer4=' peer 2001:db8:0:f103::201/128',
2898 peer5='/128',
2899 peer6=' peer 2001:db8:0:f103::203/128',
2900 scope1='link',
2901 scope2='global',
2902 deprecated1=' deprecated',
2903 deprecated2='',
2904 deprecated3=' deprecated',
2905 deprecated4='',
2906 route_metric=256,
2907 flag1='',
2908 flag2=' noprefixroute',
2909 flag3=' home mngtmpaddr',
2910 flag4=' noprefixroute',
d5adff70
YW
2911 ip4_null_16=ip4_null_16,
2912 ip4_null_24=ip4_null_24,
2913 ip6_null_73=ip6_null_73,
2914 ip6_null_74=ip6_null_74,
f2bcd324 2915 )
d19704cd
YW
2916
2917 networkctl_reconfigure('dummy98')
95e1fbba 2918 self.wait_online('dummy98:routable')
f2bcd324
YW
2919 self.verify_address_static(
2920 label1='new-label1',
2921 label2='dummy98',
2922 label3='new-label3',
2923 broadcast1=' brd 10.4.1.255',
2924 broadcast2='',
2925 broadcast3=' brd 10.4.3.31',
2926 peer1=' peer 10.5.1.102/24',
2927 peer2='/24 brd 10.5.2.255',
2928 peer3=' peer 10.5.3.102/24',
2929 peer4=' peer 2001:db8:0:f103::201/128',
2930 peer5='/128',
2931 peer6=' peer 2001:db8:0:f103::203/128',
2932 scope1='link',
2933 scope2='global',
2934 deprecated1=' deprecated',
2935 deprecated2='',
2936 deprecated3=' deprecated',
2937 deprecated4='',
2938 route_metric=256,
2939 flag1='',
2940 flag2=' noprefixroute',
2941 flag3=' home mngtmpaddr',
2942 flag4=' noprefixroute',
d5adff70
YW
2943 ip4_null_16=ip4_null_16,
2944 ip4_null_24=ip4_null_24,
2945 ip6_null_73=ip6_null_73,
2946 ip6_null_74=ip6_null_74,
f2bcd324 2947 )
d19704cd 2948
40971657
YW
2949 # Tests for #20891.
2950 # 1. set preferred lifetime forever to drop the deprecated flag for testing #20891.
f2bcd324
YW
2951 check_output('ip address change 10.7.1.1/24 dev dummy98 preferred_lft forever')
2952 check_output('ip address change 2001:db8:0:f104::1/64 dev dummy98 preferred_lft forever')
2953 output = check_output('ip address show dev dummy98')
40971657 2954 print(output)
f2bcd324
YW
2955 self.assertNotRegex(output, '10.7.1.1/24 .* deprecated')
2956 self.assertNotRegex(output, '2001:db8:0:f104::1/64 .* deprecated')
40971657 2957
f2bcd324 2958 # 2. reconfigure the interface, and check the deprecated flag is set again
a962d857 2959 networkctl_reconfigure('dummy98')
95e1fbba 2960 self.wait_online('dummy98:routable')
f2bcd324
YW
2961 self.verify_address_static(
2962 label1='new-label1',
2963 label2='dummy98',
2964 label3='new-label3',
2965 broadcast1=' brd 10.4.1.255',
2966 broadcast2='',
2967 broadcast3=' brd 10.4.3.31',
2968 peer1=' peer 10.5.1.102/24',
2969 peer2='/24 brd 10.5.2.255',
2970 peer3=' peer 10.5.3.102/24',
2971 peer4=' peer 2001:db8:0:f103::201/128',
2972 peer5='/128',
2973 peer6=' peer 2001:db8:0:f103::203/128',
2974 scope1='link',
2975 scope2='global',
2976 deprecated1=' deprecated',
2977 deprecated2='',
2978 deprecated3=' deprecated',
2979 deprecated4='',
2980 route_metric=256,
2981 flag1='',
2982 flag2=' noprefixroute',
2983 flag3=' home mngtmpaddr',
2984 flag4=' noprefixroute',
d5adff70
YW
2985 ip4_null_16=ip4_null_16,
2986 ip4_null_24=ip4_null_24,
2987 ip6_null_73=ip6_null_73,
2988 ip6_null_74=ip6_null_74,
f2bcd324 2989 )
40971657 2990
d19704cd
YW
2991 # test for ENOBUFS issue #17012 (with reload)
2992 copy_network_unit('25-address-static.network.d/10-many-address.conf')
2993 networkctl_reload()
95e1fbba 2994 self.wait_online('dummy98:routable')
766f8f38 2995 output = check_output('ip -4 address show dev dummy98')
a962d857 2996 for i in range(1, 254):
4a704501 2997 self.assertIn(f'inet 10.3.3.{i}/16 brd 10.3.255.255', output)
e4783b54 2998
d19704cd
YW
2999 # (with reconfigure)
3000 networkctl_reconfigure('dummy98')
95e1fbba 3001 self.wait_online('dummy98:routable')
d19704cd
YW
3002 output = check_output('ip -4 address show dev dummy98')
3003 for i in range(1, 254):
3004 self.assertIn(f'inet 10.3.3.{i}/16 brd 10.3.255.255', output)
3a2ef59d
YW
3005
3006 # test for an empty string assignment for Address= in [Network]
3007 copy_network_unit('25-address-static.network.d/20-clear-addresses.conf')
3008 networkctl_reload()
95e1fbba 3009 self.wait_online('dummy98:routable')
3a2ef59d
YW
3010 output = check_output('ip -4 address show dev dummy98')
3011 for i in range(1, 254):
3012 self.assertNotIn(f'inet 10.3.3.{i}/16 brd 10.3.255.255', output)
3013 self.assertIn('inet 10.4.0.1/16 brd 10.4.255.255', output)
146726b2 3014
44924431
YW
3015 def test_address_ipv4acd(self):
3016 check_output('ip netns add ns99')
3017 check_output('ip link add veth99 type veth peer veth-peer')
3018 check_output('ip link set veth-peer netns ns99')
3019 check_output('ip link set veth99 up')
3020 check_output('ip netns exec ns99 ip link set veth-peer up')
3021 check_output('ip netns exec ns99 ip address add 192.168.100.10/24 dev veth-peer')
3022
a962d857 3023 copy_network_unit('25-address-ipv4acd-veth99.network', copy_dropins=False)
dc7d3c5f 3024 start_networkd()
95e1fbba 3025 self.wait_online('veth99:routable')
dc7d3c5f
YW
3026
3027 output = check_output('ip -4 address show dev veth99')
3028 print(output)
44924431
YW
3029 self.assertNotIn('192.168.100.10/24', output)
3030 self.assertIn('192.168.100.11/24', output)
dc7d3c5f 3031
a962d857
YW
3032 copy_network_unit('25-address-ipv4acd-veth99.network.d/conflict-address.conf')
3033 networkctl_reload()
37611ccb 3034 self.wait_operstate('veth99', operstate='routable', setup_state='configuring', setup_timeout=10)
44924431
YW
3035
3036 output = check_output('ip -4 address show dev veth99')
dc7d3c5f 3037 print(output)
44924431
YW
3038 self.assertNotIn('192.168.100.10/24', output)
3039 self.assertIn('192.168.100.11/24', output)
dc7d3c5f 3040
21266e60
YW
3041 def test_address_peer_ipv4(self):
3042 # test for issue #17304
a962d857 3043 copy_network_unit('25-address-peer-ipv4.network', '12-dummy.netdev')
21266e60
YW
3044
3045 for trial in range(2):
3046 if trial == 0:
3047 start_networkd()
3048 else:
3049 restart_networkd()
3050
95e1fbba 3051 self.wait_online('dummy98:routable')
21266e60
YW
3052
3053 output = check_output('ip -4 address show dev dummy98')
3054 self.assertIn('inet 100.64.0.1 peer 100.64.0.2/32 scope global', output)
3055
c9d223e8
YW
3056 @expectedFailureIfModuleIsNotAvailable('vrf')
3057 def test_prefix_route(self):
a962d857
YW
3058 copy_network_unit('25-prefix-route-with-vrf.network', '12-dummy.netdev',
3059 '25-prefix-route-without-vrf.network', '11-dummy.netdev',
3060 '25-vrf.netdev', '25-vrf.network')
c9d223e8
YW
3061 for trial in range(2):
3062 if trial == 0:
3063 start_networkd()
3064 else:
a962d857 3065 restart_networkd()
c9d223e8 3066
95e1fbba 3067 self.wait_online('dummy98:routable', 'test1:routable', 'vrf99:carrier')
c9d223e8
YW
3068
3069 output = check_output('ip route show table 42 dev dummy98')
3070 print('### ip route show table 42 dev dummy98')
3071 print(output)
3072 self.assertRegex(output, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1')
c9d223e8
YW
3073 self.assertRegex(output, '10.20.33.0/24 proto kernel scope link src 10.20.33.1')
3074 self.assertRegex(output, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1')
3075 self.assertRegex(output, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1')
3076 self.assertRegex(output, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1')
c9d223e8
YW
3077 self.assertRegex(output, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1')
3078 self.assertRegex(output, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1')
3079 output = check_output('ip -6 route show table 42 dev dummy98')
3080 print('### ip -6 route show table 42 dev dummy98')
3081 print(output)
3082 if trial == 0:
3083 # Kernel's bug?
3084 self.assertRegex(output, 'local fdde:11:22::1 proto kernel metric 0 pref medium')
3085 #self.assertRegex(output, 'fdde:11:22::1 proto kernel metric 256 pref medium')
3086 self.assertRegex(output, 'local fdde:11:33::1 proto kernel metric 0 pref medium')
3087 self.assertRegex(output, 'fdde:11:33::/64 proto kernel metric 256 pref medium')
3088 self.assertRegex(output, 'local fdde:11:44::1 proto kernel metric 0 pref medium')
3089 self.assertRegex(output, 'local fdde:11:55::1 proto kernel metric 0 pref medium')
3090 self.assertRegex(output, 'fe80::/64 proto kernel metric 256 pref medium')
beb75dd3 3091 self.assertRegex(output, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium')
c9d223e8
YW
3092
3093 print()
3094
3095 output = check_output('ip route show dev test1')
3096 print('### ip route show dev test1')
3097 print(output)
3098 self.assertRegex(output, '10.21.33.0/24 proto kernel scope link src 10.21.33.1')
3099 output = check_output('ip route show table local dev test1')
3100 print('### ip route show table local dev test1')
3101 print(output)
3102 self.assertRegex(output, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1')
c9d223e8
YW
3103 self.assertRegex(output, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1')
3104 self.assertRegex(output, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1')
3105 self.assertRegex(output, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1')
c9d223e8
YW
3106 self.assertRegex(output, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1')
3107 self.assertRegex(output, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1')
3108 output = check_output('ip -6 route show dev test1')
3109 print('### ip -6 route show dev test1')
3110 print(output)
3111 self.assertRegex(output, 'fdde:12:22::1 proto kernel metric 256 pref medium')
3112 self.assertRegex(output, 'fdde:12:33::/64 proto kernel metric 256 pref medium')
3113 self.assertRegex(output, 'fe80::/64 proto kernel metric 256 pref medium')
3114 output = check_output('ip -6 route show table local dev test1')
3115 print('### ip -6 route show table local dev test1')
3116 print(output)
3117 self.assertRegex(output, 'local fdde:12:22::1 proto kernel metric 0 pref medium')
3118 self.assertRegex(output, 'local fdde:12:33::1 proto kernel metric 0 pref medium')
3119 self.assertRegex(output, 'local fdde:12:44::1 proto kernel metric 0 pref medium')
3120 self.assertRegex(output, 'local fdde:12:55::1 proto kernel metric 0 pref medium')
beb75dd3 3121 self.assertRegex(output, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium')
c9d223e8 3122
1f0e3109 3123 def test_configure_without_carrier(self):
a962d857 3124 copy_network_unit('11-dummy.netdev')
2cf6fdff 3125 start_networkd()
9bacf431
DS
3126 self.wait_operstate('test1', 'off', '')
3127 check_output('ip link set dev test1 up carrier off')
3128
a962d857 3129 copy_network_unit('25-test1.network.d/configure-without-carrier.conf', copy_dropins=False)
9bacf431 3130 restart_networkd()
95e1fbba 3131 self.wait_online('test1:no-carrier')
9bacf431
DS
3132
3133 carrier_map = {'on': '1', 'off': '0'}
3134 routable_map = {'on': 'routable', 'off': 'no-carrier'}
3135 for carrier in ['off', 'on', 'off']:
3136 with self.subTest(carrier=carrier):
3137 if carrier_map[carrier] != read_link_attr('test1', 'carrier'):
3138 check_output(f'ip link set dev test1 carrier {carrier}')
95e1fbba 3139 self.wait_online(f'test1:{routable_map[carrier]}:{routable_map[carrier]}')
9bacf431 3140
10d670a3 3141 output = networkctl_status('test1')
9bacf431
DS
3142 print(output)
3143 self.assertRegex(output, '192.168.0.15')
3144 self.assertRegex(output, '192.168.0.1')
3145 self.assertRegex(output, routable_map[carrier])
e40a58b5 3146
9bacf431 3147 def test_configure_without_carrier_yes_ignore_carrier_loss_no(self):
a962d857 3148 copy_network_unit('11-dummy.netdev')
9bacf431
DS
3149 start_networkd()
3150 self.wait_operstate('test1', 'off', '')
3151 check_output('ip link set dev test1 up carrier off')
3152
a962d857 3153 copy_network_unit('25-test1.network')
9bacf431 3154 restart_networkd()
95e1fbba 3155 self.wait_online('test1:no-carrier')
9bacf431
DS
3156
3157 carrier_map = {'on': '1', 'off': '0'}
3158 routable_map = {'on': 'routable', 'off': 'no-carrier'}
3159 for (carrier, have_config) in [('off', True), ('on', True), ('off', False)]:
3160 with self.subTest(carrier=carrier, have_config=have_config):
3161 if carrier_map[carrier] != read_link_attr('test1', 'carrier'):
3162 check_output(f'ip link set dev test1 carrier {carrier}')
95e1fbba 3163 self.wait_online(f'test1:{routable_map[carrier]}:{routable_map[carrier]}')
9bacf431 3164
10d670a3 3165 output = networkctl_status('test1')
9bacf431
DS
3166 print(output)
3167 if have_config:
3168 self.assertRegex(output, '192.168.0.15')
3169 self.assertRegex(output, '192.168.0.1')
3170 else:
3171 self.assertNotRegex(output, '192.168.0.15')
3172 self.assertNotRegex(output, '192.168.0.1')
3173 self.assertRegex(output, routable_map[carrier])
1f0e3109 3174
1f0e3109 3175 def test_routing_policy_rule(self):
a962d857 3176 copy_network_unit('25-routing-policy-rule-test1.network', '11-dummy.netdev')
2cf6fdff 3177 start_networkd()
95e1fbba 3178 self.wait_online('test1:degraded')
e40a58b5 3179
65c24cd0 3180 output = check_output('ip rule list iif test1 priority 111')
1f0e3109 3181 print(output)
65c24cd0 3182 self.assertRegex(output, '111:')
1f0e3109 3183 self.assertRegex(output, 'from 192.168.100.18')
426654d7 3184 self.assertRegex(output, r'tos (0x08|throughput)\s')
1f0e3109
SS
3185 self.assertRegex(output, 'iif test1')
3186 self.assertRegex(output, 'oif test1')
3187 self.assertRegex(output, 'lookup 7')
3188
65c24cd0
YW
3189 output = check_output('ip rule list iif test1 priority 101')
3190 print(output)
3191 self.assertRegex(output, '101:')
3192 self.assertRegex(output, 'from all')
3193 self.assertRegex(output, 'iif test1')
3194 self.assertRegex(output, 'lookup 9')
3195
3196 output = check_output('ip -6 rule list iif test1 priority 100')
3197 print(output)
3198 self.assertRegex(output, '100:')
3199 self.assertRegex(output, 'from all')
3200 self.assertRegex(output, 'iif test1')
3201 self.assertRegex(output, 'lookup 8')
3202
2e8a32af
HV
3203 output = check_output('ip rule list iif test1 priority 102')
3204 print(output)
3205 self.assertRegex(output, '102:')
3206 self.assertRegex(output, 'from 0.0.0.0/8')
3207 self.assertRegex(output, 'iif test1')
3208 self.assertRegex(output, 'lookup 10')
3209
10d670a3 3210 check_json(networkctl_json())
146726b2 3211
b677774d 3212 def test_routing_policy_rule_issue_11280(self):
a962d857
YW
3213 copy_network_unit('25-routing-policy-rule-test1.network', '11-dummy.netdev',
3214 '25-routing-policy-rule-dummy98.network', '12-dummy.netdev')
b677774d 3215
a962d857
YW
3216 for trial in range(3):
3217 restart_networkd(show_logs=(trial > 0))
95e1fbba 3218 self.wait_online('test1:degraded', 'dummy98:degraded')
b677774d 3219
371810d1 3220 output = check_output('ip rule list table 7')
b677774d 3221 print(output)
426654d7 3222 self.assertRegex(output, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
b677774d 3223
371810d1 3224 output = check_output('ip rule list table 8')
b677774d 3225 print(output)
426654d7 3226 self.assertRegex(output, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
b677774d 3227
87adeabf 3228 def test_routing_policy_rule_reconfigure(self):
a962d857 3229 copy_network_unit('25-routing-policy-rule-reconfigure2.network', '11-dummy.netdev')
87adeabf 3230 start_networkd()
95e1fbba 3231 self.wait_online('test1:degraded')
87adeabf
YW
3232
3233 output = check_output('ip rule list table 1011')
3234 print(output)
49ff3f34
YW
3235 self.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output)
3236 self.assertIn('10112: from all oif test1 lookup 1011', output)
3237 self.assertIn('10113: from all iif test1 lookup 1011', output)
3238 self.assertIn('10114: from 192.168.8.254 lookup 1011', output)
3239
3240 output = check_output('ip -6 rule list table 1011')
3241 print(output)
3242 self.assertIn('10112: from all oif test1 lookup 1011', output)
3243
a962d857
YW
3244 copy_network_unit('25-routing-policy-rule-reconfigure1.network', '11-dummy.netdev')
3245 networkctl_reload()
95e1fbba 3246 self.wait_online('test1:degraded')
49ff3f34
YW
3247
3248 output = check_output('ip rule list table 1011')
3249 print(output)
3250 self.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output)
3251 self.assertIn('10112: from all oif test1 lookup 1011', output)
3252 self.assertIn('10113: from all iif test1 lookup 1011', output)
3253 self.assertIn('10114: from 192.168.8.254 lookup 1011', output)
3254
3255 output = check_output('ip -6 rule list table 1011')
3256 print(output)
3257 self.assertNotIn('10112: from all oif test1 lookup 1011', output)
3258 self.assertIn('10113: from all iif test1 lookup 1011', output)
87adeabf 3259
a962d857
YW
3260 call('ip rule delete priority 10111')
3261 call('ip rule delete priority 10112')
3262 call('ip rule delete priority 10113')
3263 call('ip rule delete priority 10114')
3264 call('ip -6 rule delete priority 10113')
87adeabf
YW
3265
3266 output = check_output('ip rule list table 1011')
3267 print(output)
3268 self.assertEqual(output, '')
3269
49ff3f34
YW
3270 output = check_output('ip -6 rule list table 1011')
3271 print(output)
3272 self.assertEqual(output, '')
87adeabf 3273
a962d857 3274 networkctl_reconfigure('test1')
95e1fbba 3275 self.wait_online('test1:degraded')
87adeabf
YW
3276
3277 output = check_output('ip rule list table 1011')
3278 print(output)
49ff3f34
YW
3279 self.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output)
3280 self.assertIn('10112: from all oif test1 lookup 1011', output)
3281 self.assertIn('10113: from all iif test1 lookup 1011', output)
3282 self.assertIn('10114: from 192.168.8.254 lookup 1011', output)
3283
3284 output = check_output('ip -6 rule list table 1011')
3285 print(output)
3286 self.assertIn('10113: from all iif test1 lookup 1011', output)
87adeabf 3287
d586a2c3 3288 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
926062f0 3289 def test_routing_policy_rule_port_range(self):
a962d857 3290 copy_network_unit('25-fibrule-port-range.network', '11-dummy.netdev')
2cf6fdff 3291 start_networkd()
95e1fbba 3292 self.wait_online('test1:degraded')
e40a58b5 3293
371810d1 3294 output = check_output('ip rule')
926062f0
SS
3295 print(output)
3296 self.assertRegex(output, '111')
3297 self.assertRegex(output, 'from 192.168.100.18')
3298 self.assertRegex(output, '1123-1150')
3299 self.assertRegex(output, '3224-3290')
3300 self.assertRegex(output, 'tcp')
3301 self.assertRegex(output, 'lookup 7')
1f0e3109 3302
d586a2c3 3303 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
efecf9cd 3304 def test_routing_policy_rule_invert(self):
a962d857 3305 copy_network_unit('25-fibrule-invert.network', '11-dummy.netdev')
2cf6fdff 3306 start_networkd()
95e1fbba 3307 self.wait_online('test1:degraded')
e40a58b5 3308
371810d1 3309 output = check_output('ip rule')
efecf9cd 3310 print(output)
efecf9cd
SS
3311 self.assertRegex(output, '111')
3312 self.assertRegex(output, 'not.*?from.*?192.168.100.18')
3313 self.assertRegex(output, 'tcp')
3314 self.assertRegex(output, 'lookup 7')
3315
4be1fc84
NC
3316 @expectedFailureIfRoutingPolicyL3MasterDeviceIsNotAvailable()
3317 def test_routing_policy_rule_l3mdev(self):
3318 copy_network_unit('25-fibrule-l3mdev.network', '11-dummy.netdev')
3319 start_networkd()
95e1fbba 3320 self.wait_online('test1:degraded')
4be1fc84
NC
3321
3322 output = check_output('ip rule')
3323 print(output)
3324 self.assertIn('1500: from all lookup [l3mdev-table]', output)
3325 self.assertIn('2000: from all lookup [l3mdev-table] unreachable', output)
3326
6be8e78e
YW
3327 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable()
3328 def test_routing_policy_rule_uidrange(self):
a962d857 3329 copy_network_unit('25-fibrule-uidrange.network', '11-dummy.netdev')
6be8e78e 3330 start_networkd()
95e1fbba 3331 self.wait_online('test1:degraded')
6be8e78e
YW
3332
3333 output = check_output('ip rule')
3334 print(output)
3335 self.assertRegex(output, '111')
3336 self.assertRegex(output, 'from 192.168.100.18')
3337 self.assertRegex(output, 'lookup 7')
3338 self.assertRegex(output, 'uidrange 100-200')
3339
1d26d4cd
YW
3340 def _test_route_static(self, manage_foreign_routes):
3341 if not manage_foreign_routes:
3342 copy_networkd_conf_dropin('networkd-manage-foreign-routes-no.conf')
3343
d3779490
YW
3344 copy_network_unit('25-route-static.network', '12-dummy.netdev',
3345 '25-route-static-test1.network', '11-dummy.netdev')
2cf6fdff 3346 start_networkd()
95e1fbba 3347 self.wait_online('dummy98:routable')
e2aea43f 3348
10d670a3 3349 output = networkctl_status('dummy98')
e2aea43f 3350 print(output)
0d34228f 3351
6d60f9db 3352 print('### ip -6 route show dev dummy98')
371810d1 3353 output = check_output('ip -6 route show dev dummy98')
0d34228f 3354 print(output)
0b5dc249
YW
3355 self.assertIn('2001:1234:5:8fff:ff:ff:ff:ff proto static', output)
3356 self.assertIn('2001:1234:5:8f63::1 proto kernel', output)
180c5116 3357 self.assertIn('2001:1234:5:afff:ff:ff:ff:ff via fe80:0:222:4dff:ff:ff:ff:ff proto static', output)
1f0e3109 3358
d9005dec
YW
3359 print('### ip -6 route show default')
3360 output = check_output('ip -6 route show default')
6d60f9db 3361 print(output)
0b5dc249
YW
3362 self.assertIn('default', output)
3363 self.assertIn('via 2001:1234:5:8fff:ff:ff:ff:ff', output)
1f0e3109 3364
6d60f9db 3365 print('### ip -4 route show dev dummy98')
371810d1 3366 output = check_output('ip -4 route show dev dummy98')
1f0e3109 3367 print(output)
0b5dc249
YW
3368 self.assertIn('149.10.124.48/28 proto kernel scope link src 149.10.124.58', output)
3369 self.assertIn('149.10.124.64 proto static scope link', output)
3370 self.assertIn('169.254.0.0/16 proto static scope link metric 2048', output)
902bbdc4
YW
3371 self.assertIn('192.168.1.1 proto static scope link initcwnd 20', output)
3372 self.assertIn('192.168.1.2 proto static scope link initrwnd 30', output)
3373 self.assertIn('192.168.1.3 proto static scope link advmss 30', output)
288f58c0 3374 self.assertIn('192.168.1.4 proto static scope link hoplimit 122', output)
0b5dc249 3375 self.assertIn('multicast 149.10.123.4 proto static', output)
1f0e3109 3376
6d60f9db 3377 print('### ip -4 route show dev dummy98 default')
371810d1 3378 output = check_output('ip -4 route show dev dummy98 default')
6d60f9db 3379 print(output)
0b5dc249
YW
3380 self.assertIn('default via 149.10.125.65 proto static onlink', output)
3381 self.assertIn('default via 149.10.124.64 proto static', output)
3382 self.assertIn('default proto static', output)
5e46ca98 3383 self.assertIn('default via 1.1.8.104 proto static', output)
1f0e3109 3384
6d60f9db
YW
3385 print('### ip -4 route show table local dev dummy98')
3386 output = check_output('ip -4 route show table local dev dummy98')
3387 print(output)
0b5dc249
YW
3388 self.assertIn('local 149.10.123.1 proto static scope host', output)
3389 self.assertIn('anycast 149.10.123.2 proto static scope link', output)
3390 self.assertIn('broadcast 149.10.123.3 proto static scope link', output)
6d60f9db 3391
b4f4f119
YW
3392 print('### ip -4 route show type blackhole')
3393 output = check_output('ip -4 route show type blackhole')
1f0e3109 3394 print(output)
0b5dc249 3395 self.assertIn('blackhole 202.54.1.2 proto static', output)
f5050e48 3396
b4f4f119
YW
3397 print('### ip -4 route show type unreachable')
3398 output = check_output('ip -4 route show type unreachable')
f5050e48 3399 print(output)
0b5dc249 3400 self.assertIn('unreachable 202.54.1.3 proto static', output)
f5050e48 3401
b4f4f119
YW
3402 print('### ip -4 route show type prohibit')
3403 output = check_output('ip -4 route show type prohibit')
f5050e48 3404 print(output)
0b5dc249 3405 self.assertIn('prohibit 202.54.1.4 proto static', output)
f5050e48 3406
452d86a5
YW
3407 print('### ip -6 route show type blackhole')
3408 output = check_output('ip -6 route show type blackhole')
3409 print(output)
3410 self.assertIn('blackhole 2001:1234:5678::2 dev lo proto static', output)
3411
3412 print('### ip -6 route show type unreachable')
3413 output = check_output('ip -6 route show type unreachable')
3414 print(output)
3415 self.assertIn('unreachable 2001:1234:5678::3 dev lo proto static', output)
3416
3417 print('### ip -6 route show type prohibit')
3418 output = check_output('ip -6 route show type prohibit')
3419 print(output)
3420 self.assertIn('prohibit 2001:1234:5678::4 dev lo proto static', output)
3421
a0ce990e
YW
3422 print('### ip route show 192.168.10.1')
3423 output = check_output('ip route show 192.168.10.1')
3424 print(output)
0b5dc249 3425 self.assertIn('192.168.10.1 proto static', output)
d3779490
YW
3426 self.assertIn('nexthop via 149.10.123.59 dev test1 weight 20', output)
3427 self.assertIn('nexthop via 149.10.123.60 dev test1 weight 30', output)
0b5dc249
YW
3428 self.assertIn('nexthop via 149.10.124.59 dev dummy98 weight 10', output)
3429 self.assertIn('nexthop via 149.10.124.60 dev dummy98 weight 5', output)
a0ce990e
YW
3430
3431 print('### ip route show 192.168.10.2')
3432 output = check_output('ip route show 192.168.10.2')
3433 print(output)
3434 # old ip command does not show IPv6 gateways...
0b5dc249
YW
3435 self.assertIn('192.168.10.2 proto static', output)
3436 self.assertIn('nexthop', output)
d3779490
YW
3437 self.assertIn('dev test1 weight 20', output)
3438 self.assertIn('dev test1 weight 30', output)
0b5dc249
YW
3439 self.assertIn('dev dummy98 weight 10', output)
3440 self.assertIn('dev dummy98 weight 5', output)
a0ce990e
YW
3441
3442 print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
3443 output = check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
3444 print(output)
3445 # old ip command does not show 'nexthop' keyword and weight...
0b5dc249 3446 self.assertIn('2001:1234:5:7fff:ff:ff:ff:ff', output)
d3779490
YW
3447 self.assertIn('via 2001:1234:5:6fff:ff:ff:ff:ff dev test1', output)
3448 self.assertIn('via 2001:1234:5:7fff:ff:ff:ff:ff dev test1', output)
0b5dc249
YW
3449 self.assertIn('via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98', output)
3450 self.assertIn('via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98', output)
a0ce990e 3451
10d670a3 3452 check_json(networkctl_json())
146726b2 3453
67150a7b 3454 copy_network_unit('25-address-static.network', copy_dropins=False)
a962d857 3455 networkctl_reload()
95e1fbba 3456 self.wait_online('dummy98:routable')
43d4bc9f
YW
3457
3458 # check all routes managed by Manager are removed
b4f4f119
YW
3459 print('### ip -4 route show type blackhole')
3460 output = check_output('ip -4 route show type blackhole')
43d4bc9f
YW
3461 print(output)
3462 self.assertEqual(output, '')
3463
b4f4f119
YW
3464 print('### ip -4 route show type unreachable')
3465 output = check_output('ip -4 route show type unreachable')
43d4bc9f
YW
3466 print(output)
3467 self.assertEqual(output, '')
3468
b4f4f119
YW
3469 print('### ip -4 route show type prohibit')
3470 output = check_output('ip -4 route show type prohibit')
43d4bc9f
YW
3471 print(output)
3472 self.assertEqual(output, '')
3473
452d86a5
YW
3474 print('### ip -6 route show type blackhole')
3475 output = check_output('ip -6 route show type blackhole')
3476 print(output)
3477 self.assertEqual(output, '')
3478
3479 print('### ip -6 route show type unreachable')
3480 output = check_output('ip -6 route show type unreachable')
3481 print(output)
3482 self.assertEqual(output, '')
3483
3484 print('### ip -6 route show type prohibit')
3485 output = check_output('ip -6 route show type prohibit')
3486 print(output)
3487 self.assertEqual(output, '')
3488
a962d857
YW
3489 remove_network_unit('25-address-static.network')
3490 networkctl_reload()
95e1fbba 3491 self.wait_online('dummy98:routable')
43d4bc9f
YW
3492
3493 # check all routes managed by Manager are reconfigured
b4f4f119
YW
3494 print('### ip -4 route show type blackhole')
3495 output = check_output('ip -4 route show type blackhole')
43d4bc9f 3496 print(output)
0b5dc249 3497 self.assertIn('blackhole 202.54.1.2 proto static', output)
43d4bc9f 3498
b4f4f119
YW
3499 print('### ip -4 route show type unreachable')
3500 output = check_output('ip -4 route show type unreachable')
43d4bc9f 3501 print(output)
0b5dc249 3502 self.assertIn('unreachable 202.54.1.3 proto static', output)
43d4bc9f 3503
b4f4f119
YW
3504 print('### ip -4 route show type prohibit')
3505 output = check_output('ip -4 route show type prohibit')
43d4bc9f 3506 print(output)
0b5dc249 3507 self.assertIn('prohibit 202.54.1.4 proto static', output)
43d4bc9f 3508
452d86a5
YW
3509 print('### ip -6 route show type blackhole')
3510 output = check_output('ip -6 route show type blackhole')
3511 print(output)
3512 self.assertIn('blackhole 2001:1234:5678::2 dev lo proto static', output)
3513
3514 print('### ip -6 route show type unreachable')
3515 output = check_output('ip -6 route show type unreachable')
3516 print(output)
3517 self.assertIn('unreachable 2001:1234:5678::3 dev lo proto static', output)
3518
3519 print('### ip -6 route show type prohibit')
3520 output = check_output('ip -6 route show type prohibit')
3521 print(output)
3522 self.assertIn('prohibit 2001:1234:5678::4 dev lo proto static', output)
3523
a962d857 3524 remove_link('dummy98')
43d4bc9f
YW
3525 time.sleep(2)
3526
3527 # check all routes managed by Manager are removed
b4f4f119
YW
3528 print('### ip -4 route show type blackhole')
3529 output = check_output('ip -4 route show type blackhole')
43d4bc9f
YW
3530 print(output)
3531 self.assertEqual(output, '')
3532
b4f4f119
YW
3533 print('### ip -4 route show type unreachable')
3534 output = check_output('ip -4 route show type unreachable')
43d4bc9f
YW
3535 print(output)
3536 self.assertEqual(output, '')
3537
b4f4f119
YW
3538 print('### ip -4 route show type prohibit')
3539 output = check_output('ip -4 route show type prohibit')
43d4bc9f
YW
3540 print(output)
3541 self.assertEqual(output, '')
3542
452d86a5
YW
3543 print('### ip -6 route show type blackhole')
3544 output = check_output('ip -6 route show type blackhole')
3545 print(output)
3546 self.assertEqual(output, '')
3547
3548 print('### ip -6 route show type unreachable')
3549 output = check_output('ip -6 route show type unreachable')
3550 print(output)
3551 self.assertEqual(output, '')
3552
3553 print('### ip -6 route show type prohibit')
3554 output = check_output('ip -6 route show type prohibit')
3555 print(output)
3556 self.assertEqual(output, '')
3557
1d26d4cd 3558 def test_route_static(self):
a962d857 3559 first = True
1d26d4cd 3560 for manage_foreign_routes in [True, False]:
a962d857
YW
3561 if first:
3562 first = False
3563 else:
3564 self.tearDown()
3565
3566 print(f'### test_route_static(manage_foreign_routes={manage_foreign_routes})')
1d26d4cd
YW
3567 with self.subTest(manage_foreign_routes=manage_foreign_routes):
3568 self._test_route_static(manage_foreign_routes)
3569
297f9d86
YW
3570 @expectedFailureIfRTA_VIAIsNotSupported()
3571 def test_route_via_ipv6(self):
a962d857 3572 copy_network_unit('25-route-via-ipv6.network', '12-dummy.netdev')
297f9d86 3573 start_networkd()
95e1fbba 3574 self.wait_online('dummy98:routable')
297f9d86 3575
10d670a3 3576 output = networkctl_status('dummy98')
297f9d86
YW
3577 print(output)
3578
3579 print('### ip -6 route show dev dummy98')
3580 output = check_output('ip -6 route show dev dummy98')
3581 print(output)
3582 self.assertRegex(output, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
3583 self.assertRegex(output, '2001:1234:5:8f63::1 proto kernel')
3584
3585 print('### ip -4 route show dev dummy98')
3586 output = check_output('ip -4 route show dev dummy98')
3587 print(output)
3588 self.assertRegex(output, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
3589 self.assertRegex(output, '149.10.124.66 via inet6 2001:1234:5:8fff:ff:ff:ff:ff proto static')
3590
93e898d6
YW
3591 @expectedFailureIfModuleIsNotAvailable('tcp_dctcp')
3592 def test_route_congctl(self):
3593 copy_network_unit('25-route-congctl.network', '12-dummy.netdev')
3594 start_networkd()
95e1fbba 3595 self.wait_online('dummy98:routable')
93e898d6
YW
3596
3597 print('### ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff')
3598 output = check_output('ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff')
3599 print(output)
3600 self.assertIn('2001:1234:5:8fff:ff:ff:ff:ff proto static', output)
3601 self.assertIn('congctl dctcp', output)
3602
3603 print('### ip -4 route show dev dummy98 149.10.124.66')
3604 output = check_output('ip -4 route show dev dummy98 149.10.124.66')
3605 print(output)
3606 self.assertIn('149.10.124.66 proto static', output)
3607 self.assertIn('congctl dctcp', output)
1791956e 3608 self.assertIn('rto_min 300s', output)
93e898d6 3609
40afe491
YW
3610 @expectedFailureIfModuleIsNotAvailable('vrf')
3611 def test_route_vrf(self):
a962d857
YW
3612 copy_network_unit('25-route-vrf.network', '12-dummy.netdev',
3613 '25-vrf.netdev', '25-vrf.network')
40afe491 3614 start_networkd()
95e1fbba 3615 self.wait_online('dummy98:routable', 'vrf99:carrier')
40afe491
YW
3616
3617 output = check_output('ip route show vrf vrf99')
3618 print(output)
3619 self.assertRegex(output, 'default via 192.168.100.1')
3620
3621 output = check_output('ip route show')
3622 print(output)
3623 self.assertNotRegex(output, 'default via 192.168.100.1')
3624
0b1cd3e2 3625 def test_gateway_reconfigure(self):
a962d857 3626 copy_network_unit('25-gateway-static.network', '12-dummy.netdev')
0b1cd3e2 3627 start_networkd()
95e1fbba 3628 self.wait_online('dummy98:routable')
0b1cd3e2
WKI
3629 print('### ip -4 route show dev dummy98 default')
3630 output = check_output('ip -4 route show dev dummy98 default')
3631 print(output)
a962d857
YW
3632 self.assertIn('default via 149.10.124.59 proto static', output)
3633 self.assertNotIn('149.10.124.60', output)
0b1cd3e2 3634
a962d857
YW
3635 remove_network_unit('25-gateway-static.network')
3636 copy_network_unit('25-gateway-next-static.network')
3637 networkctl_reload()
95e1fbba 3638 self.wait_online('dummy98:routable')
0b1cd3e2
WKI
3639 print('### ip -4 route show dev dummy98 default')
3640 output = check_output('ip -4 route show dev dummy98 default')
3641 print(output)
a962d857
YW
3642 self.assertNotIn('149.10.124.59', output)
3643 self.assertIn('default via 149.10.124.60 proto static', output)
0b1cd3e2 3644
20ca06a6
DA
3645 def test_ip_route_ipv6_src_route(self):
3646 # a dummy device does not make the addresses go through tentative state, so we
3647 # reuse a bond from an earlier test, which does make the addresses go through
3648 # tentative state, and do our test on that
a962d857 3649 copy_network_unit('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2cf6fdff 3650 start_networkd()
95e1fbba 3651 self.wait_online('dummy98:enslaved', 'bond199:routable')
20ca06a6 3652
371810d1 3653 output = check_output('ip -6 route list dev bond199')
20ca06a6 3654 print(output)
7e305278 3655 self.assertIn('abcd::/16 via 2001:1234:56:8f63::1:1 proto static src 2001:1234:56:8f63::2', output)
20ca06a6 3656
e4948bb2
YW
3657 def test_route_preferred_source_with_existing_address(self):
3658 # See issue #28009.
3659 copy_network_unit('25-route-preferred-source.network', '12-dummy.netdev')
3660 start_networkd()
3661
3662 for i in range(3):
3663 if i != 0:
3664 networkctl_reconfigure('dummy98')
3665
95e1fbba 3666 self.wait_online('dummy98:routable')
e4948bb2
YW
3667
3668 output = check_output('ip -6 route list dev dummy98')
3669 print(output)
3670 self.assertIn('abcd::/16 via 2001:1234:56:8f63::1:1 proto static src 2001:1234:56:8f63::1', output)
3671
1f0e3109 3672 def test_ip_link_mac_address(self):
a962d857 3673 copy_network_unit('25-address-link-section.network', '12-dummy.netdev')
2cf6fdff 3674 start_networkd()
95e1fbba 3675 self.wait_online('dummy98:degraded')
1f0e3109 3676
371810d1 3677 output = check_output('ip link show dummy98')
1f0e3109 3678 print(output)
45aa0e84 3679 self.assertRegex(output, '00:01:02:aa:bb:cc')
1f0e3109
SS
3680
3681 def test_ip_link_unmanaged(self):
a962d857
YW
3682 copy_network_unit('25-link-section-unmanaged.network', '12-dummy.netdev')
3683 start_networkd()
1f0e3109 3684
19cf3143 3685 self.wait_operstate('dummy98', 'off', setup_state='unmanaged')
1f0e3109
SS
3686
3687 def test_ipv6_address_label(self):
a962d857 3688 copy_network_unit('25-ipv6-address-label-section.network', '12-dummy.netdev')
2cf6fdff 3689 start_networkd()
95e1fbba 3690 self.wait_online('dummy98:degraded')
1f0e3109 3691
371810d1 3692 output = check_output('ip addrlabel list')
1f0e3109
SS
3693 print(output)
3694 self.assertRegex(output, '2004:da8:1::/64')
3695
cff0cadc 3696 def test_ipv6_proxy_ndp(self):
a962d857 3697 copy_network_unit('25-ipv6-proxy-ndp.network', '12-dummy.netdev')
cff0cadc
YW
3698 start_networkd()
3699
95e1fbba 3700 self.wait_online('dummy98:routable')
cff0cadc
YW
3701
3702 output = check_output('ip neighbor show proxy dev dummy98')
3703 print(output)
a962d857 3704 for i in range(1, 5):
cff0cadc
YW
3705 self.assertRegex(output, f'2607:5300:203:5215:{i}::1 *proxy')
3706
d4c8de21
MM
3707 def test_ipv6_neigh_retrans_time(self):
3708 link='test25'
3709 copy_network_unit('25-dummy.netdev', '25-dummy.network')
3710 start_networkd()
3711
95e1fbba 3712 self.wait_online(f'{link}:degraded')
d4c8de21
MM
3713 remove_network_unit('25-dummy.network')
3714
3715 # expect retrans_time_ms updated
3716 copy_network_unit('25-ipv6-neigh-retrans-time-3s.network')
3717 networkctl_reload()
95e1fbba 3718 self.wait_online(f'{link}:degraded')
d4c8de21
MM
3719 self.check_ipv6_neigh_sysctl_attr(link, 'retrans_time_ms', '3000')
3720 remove_network_unit('25-ipv6-neigh-retrans-time-3s.network')
3721
3722 # expect retrans_time_ms unchanged
3723 copy_network_unit('25-ipv6-neigh-retrans-time-0s.network')
3724 networkctl_reload()
95e1fbba 3725 self.wait_online(f'{link}:degraded')
d4c8de21
MM
3726 self.check_ipv6_neigh_sysctl_attr(link, 'retrans_time_ms', '3000')
3727 remove_network_unit('25-ipv6-neigh-retrans-time-0s.network')
3728
3729 # expect retrans_time_ms unchanged
3730 copy_network_unit('25-ipv6-neigh-retrans-time-toobig.network')
3731 networkctl_reload()
95e1fbba 3732 self.wait_online(f'{link}:degraded')
d4c8de21
MM
3733 self.check_ipv6_neigh_sysctl_attr(link, 'retrans_time_ms', '3000')
3734 remove_network_unit('25-ipv6-neigh-retrans-time-toobig.network')
3735
3736 # expect retrans_time_ms unchanged
3737 copy_network_unit('25-ipv6-neigh-retrans-time-infinity.network')
3738 networkctl_reload()
95e1fbba 3739 self.wait_online(f'{link}:degraded')
d4c8de21
MM
3740 self.check_ipv6_neigh_sysctl_attr(link, 'retrans_time_ms', '3000')
3741 remove_network_unit('25-ipv6-neigh-retrans-time-infinity.network')
3742
3743 # expect retrans_time_ms unchanged
3744 copy_network_unit('25-ipv6-neigh-retrans-time-invalid.network')
3745 networkctl_reload()
95e1fbba 3746 self.wait_online(f'{link}:degraded')
d4c8de21
MM
3747 self.check_ipv6_neigh_sysctl_attr(link, 'retrans_time_ms', '3000')
3748 remove_network_unit('25-ipv6-neigh-retrans-time-invalid.network')
3749
3750 # expect retrans_time_ms updated
3751 copy_network_unit('25-ipv6-neigh-retrans-time-4s.network')
3752 networkctl_reload()
95e1fbba 3753 self.wait_online(f'{link}:degraded')
d4c8de21
MM
3754 self.check_ipv6_neigh_sysctl_attr(link, 'retrans_time_ms', '4000')
3755 remove_network_unit('25-ipv6-neigh-retrans-time-4s.network')
3756
9362f7d5
YW
3757 def test_neighbor(self):
3758 copy_network_unit('12-dummy.netdev', '25-neighbor-dummy.network', '25-neighbor-dummy.network.d/10-step1.conf',
3759 '25-gre-tunnel-remote-any.netdev', '25-neighbor-ip.network',
3760 '25-ip6gre-tunnel-remote-any.netdev', '25-neighbor-ipv6.network',
3761 copy_dropins=False)
2cf6fdff 3762 start_networkd()
95e1fbba 3763 self.wait_online('dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable')
9362f7d5
YW
3764
3765 print('### ip neigh list dev gretun97')
3766 output = check_output('ip neigh list dev gretun97')
3767 print(output)
3768 self.assertIn('10.0.0.22 lladdr 10.65.223.239 PERMANENT', output)
3769 self.assertNotIn('10.0.0.23', output)
3770
3771 print('### ip neigh list dev ip6gretun97')
3772 output = check_output('ip neigh list dev ip6gretun97')
3773 print(output)
3774 self.assertRegex(output, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
3775 self.assertNotIn('2001:db8:0:f102::18', output)
e4a71bf3 3776
d1bdafd2 3777 print('### ip neigh list dev dummy98')
df7f9afa 3778 output = check_output('ip neigh list dev dummy98')
e4a71bf3 3779 print(output)
2ede3559
YW
3780 self.assertIn('192.168.10.1 lladdr 00:00:5e:00:02:65 PERMANENT', output)
3781 self.assertIn('2004:da8:1::1 lladdr 00:00:5e:00:02:66 PERMANENT', output)
3782 self.assertNotIn('2004:da8:1:0::2', output)
3783 self.assertNotIn('192.168.10.2', output)
3784 self.assertNotIn('00:00:5e:00:02:67', output)
e4a71bf3 3785
10d670a3 3786 check_json(networkctl_json())
146726b2 3787
9362f7d5
YW
3788 # Here, 10-step1.conf is intendedly kept, to verify that 10-step2.conf overrides
3789 # the valid configurations in 10-step1.conf.
3790 copy_network_unit('25-neighbor-dummy.network.d/10-step2.conf')
2ede3559 3791 networkctl_reload()
95e1fbba 3792 self.wait_online('dummy98:degraded')
2ede3559 3793
9362f7d5 3794 print('### ip neigh list dev dummy98')
2ede3559
YW
3795 output = check_output('ip neigh list dev dummy98')
3796 print(output)
3797 self.assertIn('192.168.10.1 lladdr 00:00:5e:00:03:65 PERMANENT', output)
3798 self.assertIn('2004:da8:1::1 lladdr 00:00:5e:00:03:66 PERMANENT', output)
3799 self.assertNotIn('2004:da8:1:0::2', output)
3800 self.assertNotIn('192.168.10.2', output)
9362f7d5 3801 self.assertNotIn('00:00:5e:00:02:67', output)
d1bdafd2 3802
10d670a3 3803 check_json(networkctl_json())
d1bdafd2 3804
9362f7d5
YW
3805 remove_network_unit('25-neighbor-dummy.network.d/10-step1.conf',
3806 '25-neighbor-dummy.network.d/10-step2.conf')
3807 copy_network_unit('25-neighbor-dummy.network.d/10-step3.conf')
a962d857 3808 networkctl_reload()
95e1fbba 3809 self.wait_online('dummy98:degraded')
9362f7d5 3810
d1bdafd2
WKI
3811 print('### ip neigh list dev dummy98')
3812 output = check_output('ip neigh list dev dummy98')
3813 print(output)
9362f7d5 3814 self.assertIn('192.168.10.1 lladdr 00:00:5e:00:03:66 PERMANENT', output)
2ede3559 3815 self.assertNotIn('00:00:5e:00:02:65', output)
9362f7d5
YW
3816 self.assertNotIn('00:00:5e:00:02:66', output)
3817 self.assertNotIn('00:00:5e:00:03:65', output)
2ede3559 3818 self.assertNotIn('2004:da8:1::1', output)
d1bdafd2 3819
05514ae1 3820 def test_link_local_addressing(self):
a962d857
YW
3821 copy_network_unit('25-link-local-addressing-yes.network', '11-dummy.netdev',
3822 '25-link-local-addressing-no.network', '12-dummy.netdev')
2cf6fdff 3823 start_networkd()
95e1fbba 3824 self.wait_online('test1:degraded', 'dummy98:carrier')
05514ae1 3825
371810d1 3826 output = check_output('ip address show dev test1')
05514ae1
YW
3827 print(output)
3828 self.assertRegex(output, 'inet .* scope link')
3829 self.assertRegex(output, 'inet6 .* scope link')
3830
371810d1 3831 output = check_output('ip address show dev dummy98')
05514ae1
YW
3832 print(output)
3833 self.assertNotRegex(output, 'inet6* .* scope link')
3834
f7805a6c
FS
3835 # Documentation/networking/ip-sysctl.txt
3836 #
3837 # addr_gen_mode - INTEGER
3838 # Defines how link-local and autoconf addresses are generated.
3839 #
3840 # 0: generate address based on EUI64 (default)
3841 # 1: do no generate a link-local address, use EUI64 for addresses generated
3842 # from autoconf
3843 # 2: generate stable privacy addresses, using the secret from
3844 # stable_secret (RFC7217)
3845 # 3: generate stable privacy addresses, using a random secret if unset
05514ae1 3846
a962d857
YW
3847 self.check_ipv6_sysctl_attr('test1', 'stable_secret', '0123:4567:89ab:cdef:0123:4567:89ab:cdef')
3848 self.check_ipv6_sysctl_attr('test1', 'addr_gen_mode', '2')
3849 self.check_ipv6_sysctl_attr('dummy98', 'addr_gen_mode', '1')
05514ae1 3850
2becdbcc 3851 def test_link_local_addressing_ipv6ll(self):
a962d857 3852 copy_network_unit('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
7b3770a7 3853 start_networkd()
95e1fbba 3854 self.wait_online('dummy98:degraded')
7b3770a7 3855
2becdbcc 3856 # An IPv6LL address exists by default.
7b3770a7
YW
3857 output = check_output('ip address show dev dummy98')
3858 print(output)
3859 self.assertRegex(output, 'inet6 .* scope link')
3860
a962d857
YW
3861 copy_network_unit('25-link-local-addressing-no.network')
3862 networkctl_reload()
95e1fbba 3863 self.wait_online('dummy98:carrier')
7b3770a7 3864
2becdbcc 3865 # Check if the IPv6LL address is removed.
7b3770a7
YW
3866 output = check_output('ip address show dev dummy98')
3867 print(output)
2becdbcc
YW
3868 self.assertNotRegex(output, 'inet6 .* scope link')
3869
a962d857
YW
3870 remove_network_unit('25-link-local-addressing-no.network')
3871 networkctl_reload()
95e1fbba 3872 self.wait_online('dummy98:degraded')
2becdbcc
YW
3873
3874 # Check if a new IPv6LL address is assigned.
3875 output = check_output('ip address show dev dummy98')
3876 print(output)
3877 self.assertRegex(output, 'inet6 .* scope link')
7b3770a7 3878
1f0e3109 3879 def test_sysctl(self):
856a247e
YW
3880 copy_networkd_conf_dropin('25-global-ipv6-privacy-extensions.conf')
3881 copy_network_unit('25-sysctl.network', '12-dummy.netdev', copy_dropins=False)
2cf6fdff 3882 start_networkd()
95e1fbba 3883 self.wait_online('dummy98:degraded')
ec38833c 3884
a962d857 3885 self.check_ipv6_sysctl_attr('dummy98', 'forwarding', '1')
856a247e 3886 self.check_ipv6_sysctl_attr('dummy98', 'use_tempaddr', '1')
a962d857
YW
3887 self.check_ipv6_sysctl_attr('dummy98', 'dad_transmits', '3')
3888 self.check_ipv6_sysctl_attr('dummy98', 'hop_limit', '5')
3889 self.check_ipv6_sysctl_attr('dummy98', 'proxy_ndp', '1')
3890 self.check_ipv4_sysctl_attr('dummy98', 'forwarding', '1')
3891 self.check_ipv4_sysctl_attr('dummy98', 'proxy_arp', '1')
b4959550 3892 self.check_ipv4_sysctl_attr('dummy98', 'proxy_arp_pvlan', '1')
a962d857 3893 self.check_ipv4_sysctl_attr('dummy98', 'accept_local', '1')
ab2d9e29 3894 self.check_ipv4_sysctl_attr('dummy98', 'rp_filter', '0')
1f0e3109 3895
856a247e
YW
3896 copy_network_unit('25-sysctl.network.d/25-ipv6-privacy-extensions.conf')
3897 networkctl_reload()
95e1fbba 3898 self.wait_online('dummy98:degraded')
856a247e
YW
3899
3900 self.check_ipv6_sysctl_attr('dummy98', 'use_tempaddr', '2')
3901
4da33154 3902 def test_sysctl_disable_ipv6(self):
a962d857 3903 copy_network_unit('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
4da33154
YW
3904
3905 print('## Disable ipv6')
cefd6b3d
ZJS
3906 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
3907 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
4da33154 3908
2cf6fdff 3909 start_networkd()
95e1fbba 3910 self.wait_online('dummy98:routable')
4da33154 3911
371810d1 3912 output = check_output('ip -4 address show dummy98')
4da33154
YW
3913 print(output)
3914 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
371810d1 3915 output = check_output('ip -6 address show dummy98')
4da33154 3916 print(output)
57ad7607
ZJS
3917 self.assertRegex(output, 'inet6 2607:5300:203:3906::/64 scope global')
3918 self.assertRegex(output, 'inet6 .* scope link')
4933b97d
YW
3919 output = check_output('ip -4 route show dev dummy98')
3920 print(output)
3d2c2692 3921 self.assertRegex(output, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
d9005dec 3922 output = check_output('ip -6 route show default')
4933b97d 3923 print(output)
d9005dec
YW
3924 self.assertRegex(output, 'default')
3925 self.assertRegex(output, 'via 2607:5300:203:39ff:ff:ff:ff:ff')
4da33154 3926
a962d857 3927 remove_link('dummy98')
4da33154
YW
3928
3929 print('## Enable ipv6')
cefd6b3d
ZJS
3930 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
3931 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
4da33154 3932
a962d857 3933 restart_networkd()
95e1fbba 3934 self.wait_online('dummy98:routable')
4da33154 3935
371810d1 3936 output = check_output('ip -4 address show dummy98')
4da33154
YW
3937 print(output)
3938 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
371810d1 3939 output = check_output('ip -6 address show dummy98')
4da33154 3940 print(output)
4933b97d 3941 self.assertRegex(output, 'inet6 2607:5300:203:3906::/64 scope global')
4da33154 3942 self.assertRegex(output, 'inet6 .* scope link')
4933b97d
YW
3943 output = check_output('ip -4 route show dev dummy98')
3944 print(output)
3d2c2692 3945 self.assertRegex(output, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
d9005dec 3946 output = check_output('ip -6 route show default')
4933b97d 3947 print(output)
d9005dec 3948 self.assertRegex(output, 'via 2607:5300:203:39ff:ff:ff:ff:ff')
4da33154 3949
cd65d067 3950 def test_bind_carrier(self):
a962d857 3951 copy_network_unit('25-bind-carrier.network', '11-dummy.netdev')
2cf6fdff 3952 start_networkd()
cd65d067 3953
3e2f7c46
YW
3954 # no bound interface.
3955 self.wait_operstate('test1', 'off', setup_state='configuring')
371810d1 3956 output = check_output('ip address show test1')
cd65d067 3957 print(output)
3e2f7c46
YW
3958 self.assertNotIn('UP,LOWER_UP', output)
3959 self.assertIn('DOWN', output)
3960 self.assertNotIn('192.168.10', output)
cd65d067 3961
3e2f7c46
YW
3962 # add one bound interface. The interface will be up.
3963 check_output('ip link add dummy98 type dummy')
3964 check_output('ip link set dummy98 up')
95e1fbba 3965 self.wait_online('test1:routable')
3e2f7c46
YW
3966 output = check_output('ip address show test1')
3967 print(output)
3968 self.assertIn('UP,LOWER_UP', output)
3969 self.assertIn('inet 192.168.10.30/24 brd 192.168.10.255 scope global test1', output)
3970
3971 # add another bound interface. The interface is still up.
cefd6b3d
ZJS
3972 check_output('ip link add dummy99 type dummy')
3973 check_output('ip link set dummy99 up')
fcd79988 3974 self.wait_operstate('dummy99', 'degraded', setup_state='unmanaged')
371810d1 3975 output = check_output('ip address show test1')
cd65d067 3976 print(output)
3e2f7c46
YW
3977 self.assertIn('UP,LOWER_UP', output)
3978 self.assertIn('inet 192.168.10.30/24 brd 192.168.10.255 scope global test1', output)
cd65d067 3979
3e2f7c46 3980 # remove one of the bound interfaces. The interface is still up
a962d857 3981 remove_link('dummy98')
371810d1 3982 output = check_output('ip address show test1')
cd65d067 3983 print(output)
3e2f7c46
YW
3984 self.assertIn('UP,LOWER_UP', output)
3985 self.assertIn('inet 192.168.10.30/24 brd 192.168.10.255 scope global test1', output)
cd65d067 3986
3e2f7c46 3987 # bring down the remaining bound interface. The interface will be down.
bc942f69 3988 check_output('ip link set dummy99 down')
3e2f7c46
YW
3989 self.wait_operstate('test1', 'off')
3990 self.wait_address_dropped('test1', r'192.168.10', ipv='-4', timeout_sec=10)
371810d1 3991 output = check_output('ip address show test1')
cd65d067 3992 print(output)
3e2f7c46
YW
3993 self.assertNotIn('UP,LOWER_UP', output)
3994 self.assertIn('DOWN', output)
3995 self.assertNotIn('192.168.10', output)
cd65d067 3996
3e2f7c46 3997 # bring up the bound interface. The interface will be up.
bc942f69 3998 check_output('ip link set dummy99 up')
95e1fbba 3999 self.wait_online('test1:routable')
371810d1 4000 output = check_output('ip address show test1')
cd65d067 4001 print(output)
3e2f7c46
YW
4002 self.assertIn('UP,LOWER_UP', output)
4003 self.assertIn('inet 192.168.10.30/24 brd 192.168.10.255 scope global test1', output)
4004
4005 # remove the remaining bound interface. The interface will be down.
4006 remove_link('dummy99')
4007 self.wait_operstate('test1', 'off')
4008 self.wait_address_dropped('test1', r'192.168.10', ipv='-4', timeout_sec=10)
4009 output = check_output('ip address show test1')
4010 print(output)
4011 self.assertNotIn('UP,LOWER_UP', output)
4012 self.assertIn('DOWN', output)
4013 self.assertNotIn('192.168.10', output)
4014
4015 # re-add one bound interface. The interface will be up.
4016 check_output('ip link add dummy98 type dummy')
4017 check_output('ip link set dummy98 up')
95e1fbba 4018 self.wait_online('test1:routable')
3e2f7c46
YW
4019 output = check_output('ip address show test1')
4020 print(output)
4021 self.assertIn('UP,LOWER_UP', output)
4022 self.assertIn('inet 192.168.10.30/24 brd 192.168.10.255 scope global test1', output)
cd65d067 4023
a962d857 4024 def _test_activation_policy(self, interface, test):
2236d75d
DS
4025 conffile = '25-activation-policy.network'
4026 if test:
4027 conffile = f'{conffile}.d/{test}.conf'
ee9918ae 4028 if interface == 'vlan99':
a962d857
YW
4029 copy_network_unit('21-vlan.netdev', '21-vlan-test1.network')
4030 copy_network_unit('11-dummy.netdev', conffile, copy_dropins=False)
2236d75d
DS
4031 start_networkd()
4032
4033 always = test.startswith('always')
ebb5036f 4034 initial_up = test != 'manual' and not test.endswith('down') # note: default is up
2236d75d
DS
4035 expect_up = initial_up
4036 next_up = not expect_up
4037
cfbdc438 4038 if test.endswith('down'):
ee9918ae 4039 self.wait_activated(interface)
cfbdc438 4040
2236d75d
DS
4041 for iteration in range(4):
4042 with self.subTest(iteration=iteration, expect_up=expect_up):
4043 operstate = 'routable' if expect_up else 'off'
618da3e7 4044 setup_state = 'configured' if expect_up else ('configuring' if iteration == 0 else None)
ee9918ae 4045 self.wait_operstate(interface, operstate, setup_state=setup_state, setup_timeout=20)
2236d75d
DS
4046
4047 if expect_up:
ee9918ae
YW
4048 self.assertIn('UP', check_output(f'ip link show {interface}'))
4049 self.assertIn('192.168.10.30/24', check_output(f'ip address show {interface}'))
4050 self.assertIn('default via 192.168.10.1', check_output(f'ip route show dev {interface}'))
2236d75d 4051 else:
ee9918ae 4052 self.assertIn('DOWN', check_output(f'ip link show {interface}'))
2236d75d
DS
4053
4054 if next_up:
ee9918ae 4055 check_output(f'ip link set dev {interface} up')
2236d75d 4056 else:
ee9918ae 4057 check_output(f'ip link set dev {interface} down')
2236d75d
DS
4058 expect_up = initial_up if always else next_up
4059 next_up = not next_up
073ad7ed
YW
4060 if always:
4061 time.sleep(1)
2236d75d 4062
2236d75d 4063 def test_activation_policy(self):
a962d857 4064 first = True
ee9918ae 4065 for interface in ['test1', 'vlan99']:
a962d857
YW
4066 for test in ['up', 'always-up', 'manual', 'always-down', 'down', '']:
4067 if first:
4068 first = False
4069 else:
4070 self.tearDown()
4071
4072 print(f'### test_activation_policy(interface={interface}, test={test})')
4073 with self.subTest(interface=interface, test=test):
4074 self._test_activation_policy(interface, test)
2236d75d 4075
61764fe4 4076 def _test_activation_policy_required_for_online(self, policy, required):
61764fe4
DS
4077 conffile = '25-activation-policy.network'
4078 units = ['11-dummy.netdev', '12-dummy.netdev', '12-dummy.network', conffile]
4079 if policy:
4080 units += [f'{conffile}.d/{policy}.conf']
4081 if required:
4082 units += [f'{conffile}.d/required-{required}.conf']
a962d857 4083 copy_network_unit(*units, copy_dropins=False)
61764fe4
DS
4084 start_networkd()
4085
cfbdc438
YW
4086 if policy.endswith('down'):
4087 self.wait_activated('test1')
4088
61764fe4
DS
4089 if policy.endswith('down') or policy == 'manual':
4090 self.wait_operstate('test1', 'off', setup_state='configuring')
4091 else:
95e1fbba 4092 self.wait_online('test1')
61764fe4
DS
4093
4094 if policy == 'always-down':
4095 # if always-down, required for online is forced to no
4096 expected = False
4097 elif required:
4098 # otherwise if required for online is specified, it should match that
4099 expected = required == 'yes'
4100 elif policy:
4101 # otherwise if only policy specified, required for online defaults to
4102 # true if policy is up, always-up, or bound
4103 expected = policy.endswith('up') or policy == 'bound'
4104 else:
4105 # default is true, if neither are specified
4106 expected = True
4107
10d670a3 4108 output = networkctl_status('test1')
61764fe4
DS
4109 print(output)
4110
4111 yesno = 'yes' if expected else 'no'
4112 self.assertRegex(output, f'Required For Online: {yesno}')
4113
61764fe4 4114 def test_activation_policy_required_for_online(self):
a962d857 4115 first = True
61764fe4
DS
4116 for policy in ['up', 'always-up', 'manual', 'always-down', 'down', 'bound', '']:
4117 for required in ['yes', 'no', '']:
a962d857
YW
4118 if first:
4119 first = False
4120 else:
4121 self.tearDown()
4122
4123 print(f'### test_activation_policy_required_for_online(policy={policy}, required={required})')
61764fe4
DS
4124 with self.subTest(policy=policy, required=required):
4125 self._test_activation_policy_required_for_online(policy, required)
4126
fdcd1ec5 4127 def test_domain(self):
a962d857 4128 copy_network_unit('12-dummy.netdev', '24-search-domain.network')
2cf6fdff 4129 start_networkd()
95e1fbba 4130 self.wait_online('dummy98:routable')
fdcd1ec5 4131
10d670a3 4132 output = networkctl_status('dummy98')
fdcd1ec5
YW
4133 print(output)
4134 self.assertRegex(output, 'Address: 192.168.42.100')
4135 self.assertRegex(output, 'DNS: 192.168.42.1')
4136 self.assertRegex(output, 'Search Domains: one')
4137
1e498853 4138 def test_keep_configuration_static(self):
1e498853
YW
4139 check_output('ip link add name dummy98 type dummy')
4140 check_output('ip address add 10.1.2.3/16 dev dummy98')
4141 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
4142 output = check_output('ip address show dummy98')
4143 print(output)
4144 self.assertRegex(output, 'inet 10.1.2.3/16 scope global dummy98')
4145 self.assertRegex(output, 'inet 10.2.3.4/16 scope global dynamic dummy98')
4146 output = check_output('ip route show dev dummy98')
4147 print(output)
4148
a962d857 4149 copy_network_unit('24-keep-configuration-static.network')
2cf6fdff 4150 start_networkd()
95e1fbba 4151 self.wait_online('dummy98:routable')
1e498853
YW
4152
4153 output = check_output('ip address show dummy98')
4154 print(output)
4155 self.assertRegex(output, 'inet 10.1.2.3/16 scope global dummy98')
4156 self.assertNotRegex(output, 'inet 10.2.3.4/16 scope global dynamic dummy98')
4157
78265b5b 4158 def check_nexthop(self, manage_foreign_nexthops, first):
95e1fbba 4159 self.wait_online('veth99:routable', 'veth-peer:routable', 'dummy98:routable')
086bcf5d 4160
e7660b9a
YW
4161 output = check_output('ip nexthop list dev veth99')
4162 print(output)
78265b5b
YW
4163 if first:
4164 self.assertIn('id 1 via 192.168.5.1 dev veth99', output)
4165 self.assertIn('id 2 via 2001:1234:5:8f63::2 dev veth99', output)
4166 else:
4167 self.assertIn('id 6 via 192.168.5.1 dev veth99', output)
4168 self.assertIn('id 7 via 2001:1234:5:8f63::2 dev veth99', output)
e7660b9a
YW
4169 self.assertIn('id 3 dev veth99', output)
4170 self.assertIn('id 4 dev veth99', output)
78265b5b
YW
4171 if first:
4172 self.assertRegex(output, 'id 5 via 192.168.10.1 dev veth99 .*onlink')
4173 else:
4174 self.assertIn('id 5 via 192.168.5.3 dev veth99', output)
4175 self.assertNotRegex(output, 'id 5 via 192.168.5.3 dev veth99 .*onlink')
e7660b9a 4176 self.assertIn('id 8 via fe80:0:222:4dff:ff:ff:ff:ff dev veth99', output)
41231f26
YW
4177 if manage_foreign_nexthops:
4178 self.assertRegex(output, r'id [0-9]* via 192.168.5.2 dev veth99')
086bcf5d 4179
e7660b9a
YW
4180 output = check_output('ip nexthop list dev dummy98')
4181 print(output)
78265b5b
YW
4182 if first:
4183 self.assertIn('id 20 via 192.168.20.1 dev dummy98', output)
4184 else:
4185 self.assertIn('id 21 via 192.168.20.1 dev dummy98', output)
41231f26
YW
4186 if manage_foreign_nexthops:
4187 self.assertNotIn('id 42 via 192.168.20.2 dev dummy98', output)
4188 else:
4189 self.assertIn('id 42 via 192.168.20.2 dev dummy98', output)
69a91c70 4190
e7660b9a
YW
4191 # kernel manages blackhole nexthops on lo
4192 output = check_output('ip nexthop list dev lo')
4193 print(output)
78265b5b
YW
4194 if first:
4195 self.assertIn('id 6 blackhole', output)
4196 self.assertIn('id 7 blackhole', output)
4197 else:
4198 self.assertIn('id 1 blackhole', output)
4199 self.assertIn('id 2 blackhole', output)
cee0f719 4200
e7660b9a 4201 # group nexthops are shown with -0 option
78265b5b
YW
4202 if first:
4203 output = check_output('ip -0 nexthop list id 21')
4204 print(output)
4205 self.assertRegex(output, r'id 21 group (1,3/20|20/1,3)')
4206 else:
4207 output = check_output('ip -0 nexthop list id 20')
4208 print(output)
4209 self.assertRegex(output, r'id 20 group (5,3/21|21/5,3)')
cee0f719 4210
e7660b9a
YW
4211 output = check_output('ip route show dev veth99 10.10.10.10')
4212 print(output)
78265b5b
YW
4213 if first:
4214 self.assertEqual('10.10.10.10 nhid 1 via 192.168.5.1 proto static', output)
4215 else:
4216 self.assertEqual('10.10.10.10 nhid 6 via 192.168.5.1 proto static', output)
e2d9bc5c 4217
e7660b9a
YW
4218 output = check_output('ip route show dev veth99 10.10.10.11')
4219 print(output)
78265b5b
YW
4220 if first:
4221 self.assertEqual('10.10.10.11 nhid 2 via inet6 2001:1234:5:8f63::2 proto static', output)
4222 else:
4223 self.assertEqual('10.10.10.11 nhid 7 via inet6 2001:1234:5:8f63::2 proto static', output)
cee0f719 4224
e7660b9a
YW
4225 output = check_output('ip route show dev veth99 10.10.10.12')
4226 print(output)
78265b5b
YW
4227 if first:
4228 self.assertEqual('10.10.10.12 nhid 5 via 192.168.10.1 proto static onlink', output)
4229 else:
4230 self.assertEqual('10.10.10.12 nhid 5 via 192.168.5.3 proto static', output)
69a91c70 4231
e7660b9a
YW
4232 output = check_output('ip -6 route show dev veth99 2001:1234:5:8f62::1')
4233 print(output)
78265b5b
YW
4234 if first:
4235 self.assertEqual('2001:1234:5:8f62::1 nhid 2 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium', output)
4236 else:
4237 self.assertEqual('2001:1234:5:8f62::1 nhid 7 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium', output)
9c8f90d0 4238
e7660b9a
YW
4239 output = check_output('ip route show 10.10.10.13')
4240 print(output)
78265b5b
YW
4241 if first:
4242 self.assertEqual('blackhole 10.10.10.13 nhid 6 dev lo proto static', output)
4243 else:
4244 self.assertEqual('blackhole 10.10.10.13 nhid 1 dev lo proto static', output)
9c8f90d0 4245
e7660b9a
YW
4246 output = check_output('ip -6 route show 2001:1234:5:8f62::2')
4247 print(output)
78265b5b
YW
4248 if first:
4249 self.assertEqual('blackhole 2001:1234:5:8f62::2 nhid 7 dev lo proto static metric 1024 pref medium', output)
4250 else:
4251 self.assertEqual('blackhole 2001:1234:5:8f62::2 nhid 2 dev lo proto static metric 1024 pref medium', output)
9c8f90d0 4252
e7660b9a
YW
4253 output = check_output('ip route show 10.10.10.14')
4254 print(output)
78265b5b
YW
4255 if first:
4256 self.assertIn('10.10.10.14 nhid 21 proto static', output)
4257 self.assertIn('nexthop via 192.168.5.1 dev veth99 weight 3', output)
4258 else:
4259 self.assertIn('10.10.10.14 nhid 20 proto static', output)
4260 self.assertIn('nexthop via 192.168.5.3 dev veth99 weight 3', output)
e7660b9a 4261 self.assertIn('nexthop via 192.168.20.1 dev dummy98 weight 1', output)
146726b2 4262
b5edf3a9
YW
4263 output = networkctl_json()
4264 check_json(output)
4265 self.assertNotIn('"Destination":[10.10.10.14]', output)
e7660b9a 4266
41231f26
YW
4267 def _test_nexthop(self, manage_foreign_nexthops):
4268 if not manage_foreign_nexthops:
4269 copy_networkd_conf_dropin('networkd-manage-foreign-nexthops-no.conf')
4270
4271 check_output('ip link add dummy98 type dummy')
4272 check_output('ip link set dummy98 up')
4273 check_output('ip address add 192.168.20.20/24 dev dummy98')
4274 check_output('ip nexthop add id 42 via 192.168.20.2 dev dummy98')
4275
78265b5b
YW
4276 copy_network_unit('25-nexthop-1.network', '25-veth.netdev', '25-veth-peer.network',
4277 '12-dummy.netdev', '25-nexthop-dummy-1.network')
9c8f90d0
YW
4278 start_networkd()
4279
78265b5b
YW
4280 self.check_nexthop(manage_foreign_nexthops, first=True)
4281
4282 remove_network_unit('25-nexthop-1.network', '25-nexthop-dummy-1.network')
4283 copy_network_unit('25-nexthop-2.network', '25-nexthop-dummy-2.network')
4284 networkctl_reload()
4285 self.check_nexthop(manage_foreign_nexthops, first=False)
69a91c70 4286
78265b5b 4287 remove_network_unit('25-nexthop-2.network')
a962d857
YW
4288 copy_network_unit('25-nexthop-nothing.network')
4289 networkctl_reload()
95e1fbba 4290 self.wait_online('veth99:routable', 'veth-peer:routable')
932e157b 4291
9947c7ba
YW
4292 output = check_output('ip nexthop list dev veth99')
4293 print(output)
4294 self.assertEqual(output, '')
4295 output = check_output('ip nexthop list dev lo')
4296 print(output)
4297 self.assertEqual(output, '')
4298
78265b5b
YW
4299 remove_network_unit('25-nexthop-nothing.network', '25-nexthop-dummy-2.network')
4300 copy_network_unit('25-nexthop-1.network', '25-nexthop-dummy-1.network')
2ec0e95e
YW
4301 # Of course, networkctl_reconfigure() below is unnecessary in normal operation, but it is intentional
4302 # here to test reconfiguring with different .network files does not trigger race.
4303 # See also comments in link_drop_requests().
4304 networkctl_reconfigure('dummy98') # reconfigured with 25-nexthop-dummy-2.network
4305 networkctl_reload() # reconfigured with 25-nexthop-dummy-1.network
9947c7ba 4306
78265b5b 4307 self.check_nexthop(manage_foreign_nexthops, first=True)
932e157b 4308
f9b5c276
YW
4309 # Remove nexthop with ID 20
4310 check_output('ip nexthop del id 20')
4311 copy_network_unit('11-dummy.netdev', '25-nexthop-test1.network')
4312 networkctl_reload()
4313
4314 # 25-nexthop-test1.network requests a route with nexthop ID 21,
4315 # which is silently removed by the kernel when nexthop with ID 20 is removed in the above,
4316 # hence test1 should be stuck in the configuring state.
4317 self.wait_operstate('test1', operstate='routable', setup_state='configuring')
4318
4319 # Wait for a while, and check if the interface is still in the configuring state.
4320 time.sleep(1)
4321 output = networkctl_status('test1')
4322 self.assertIn('State: routable (configuring)', output)
4323
b5edf3a9
YW
4324 # Check if the route which needs nexthop 20 and 21 are forgotten.
4325 output = networkctl_json()
4326 check_json(output)
4327 self.assertNotIn('"Destination":[10.10.10.14]', output)
4328
f9b5c276
YW
4329 # Reconfigure the interface that has nexthop with ID 20 and 21,
4330 # then the route requested by test1 can be configured.
4331 networkctl_reconfigure('dummy98')
95e1fbba 4332 self.wait_online('test1:routable')
f9b5c276
YW
4333
4334 # Check if the requested route actually configured.
4335 output = check_output('ip route show 10.10.11.10')
4336 print(output)
4337 self.assertIn('10.10.11.10 nhid 21 proto static', output)
4338 self.assertIn('nexthop via 192.168.5.1 dev veth99 weight 3', output)
4339 self.assertIn('nexthop via 192.168.20.1 dev dummy98 weight 1', output)
4340
a962d857 4341 remove_link('veth99')
9947c7ba
YW
4342 time.sleep(2)
4343
4344 output = check_output('ip nexthop list dev lo')
4345 print(output)
4346 self.assertEqual(output, '')
4347
41231f26
YW
4348 @expectedFailureIfNexthopIsNotAvailable()
4349 def test_nexthop(self):
4350 first = True
4351 for manage_foreign_nexthops in [True, False]:
4352 if first:
4353 first = False
4354 else:
4355 self.tearDown()
4356
4357 print(f'### test_nexthop(manage_foreign_nexthops={manage_foreign_nexthops})')
4358 with self.subTest(manage_foreign_nexthops=manage_foreign_nexthops):
4359 self._test_nexthop(manage_foreign_nexthops)
4360
23b38192
YW
4361class NetworkdTCTests(unittest.TestCase, Utilities):
4362
4363 def setUp(self):
4364 setup_common()
4365
4366 def tearDown(self):
4367 tear_down_common()
4368
4c7d13f4
YW
4369 @expectedFailureIfModuleIsNotAvailable('sch_cake')
4370 def test_qdisc_cake(self):
4371 copy_network_unit('25-qdisc-cake.network', '12-dummy.netdev')
ef3c8a92 4372 start_networkd()
95e1fbba 4373 self.wait_online('dummy98:routable')
ef3c8a92 4374
4c7d13f4 4375 output = check_output('tc qdisc show dev dummy98')
f1de1eb3 4376 print(output)
4c7d13f4
YW
4377 self.assertIn('qdisc cake 3a: root', output)
4378 self.assertIn('bandwidth 500Mbit', output)
4379 self.assertIn('autorate-ingress', output)
4380 self.assertIn('diffserv8', output)
4381 self.assertIn('dual-dsthost', output)
4382 self.assertIn(' nat', output)
4383 self.assertIn(' wash', output)
4384 self.assertIn(' split-gso', output)
4385 self.assertIn(' raw', output)
4386 self.assertIn(' atm', output)
4387 self.assertIn('overhead 128', output)
4388 self.assertIn('mpu 20', output)
4389 self.assertIn('fwmark 0xff00', output)
77d5f36d
YW
4390 self.assertIn('rtt 1s', output)
4391 self.assertIn('ack-filter-aggressive', output)
4c7d13f4
YW
4392
4393 @expectedFailureIfModuleIsNotAvailable('sch_codel')
4394 def test_qdisc_codel(self):
4395 copy_network_unit('25-qdisc-codel.network', '12-dummy.netdev')
4396 start_networkd()
95e1fbba 4397 self.wait_online('dummy98:routable')
f1de1eb3 4398
ef3c8a92
YW
4399 output = check_output('tc qdisc show dev dummy98')
4400 print(output)
4c7d13f4
YW
4401 self.assertRegex(output, 'qdisc codel 33: root')
4402 self.assertRegex(output, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn')
f1de1eb3 4403
4c7d13f4
YW
4404 @expectedFailureIfModuleIsNotAvailable('sch_drr')
4405 def test_qdisc_drr(self):
4406 copy_network_unit('25-qdisc-drr.network', '12-dummy.netdev')
4407 start_networkd()
95e1fbba 4408 self.wait_online('dummy98:routable')
f1de1eb3 4409
4c7d13f4
YW
4410 output = check_output('tc qdisc show dev dummy98')
4411 print(output)
4412 self.assertRegex(output, 'qdisc drr 2: root')
4413 output = check_output('tc class show dev dummy98')
4414 print(output)
4415 self.assertRegex(output, 'class drr 2:30 root quantum 2000b')
ef3c8a92 4416
4c7d13f4
YW
4417 @expectedFailureIfModuleIsNotAvailable('sch_ets')
4418 def test_qdisc_ets(self):
4419 copy_network_unit('25-qdisc-ets.network', '12-dummy.netdev')
4420 start_networkd()
95e1fbba 4421 self.wait_online('dummy98:routable')
4c7d13f4
YW
4422
4423 output = check_output('tc qdisc show dev dummy98')
4424 print(output)
4425
4426 self.assertRegex(output, 'qdisc ets 3a: root')
4427 self.assertRegex(output, 'bands 10 strict 3')
4428 self.assertRegex(output, 'quanta 1 2 3 4 5')
4429 self.assertRegex(output, 'priomap 3 4 5 6 7')
4430
4431 @expectedFailureIfModuleIsNotAvailable('sch_fq')
4432 def test_qdisc_fq(self):
4433 copy_network_unit('25-qdisc-fq.network', '12-dummy.netdev')
4434 start_networkd()
95e1fbba 4435 self.wait_online('dummy98:routable')
0baddbd5 4436
4c7d13f4
YW
4437 output = check_output('tc qdisc show dev dummy98')
4438 print(output)
4439 self.assertRegex(output, 'qdisc fq 32: root')
a05a6e8b
YW
4440 self.assertRegex(output, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
4441 self.assertRegex(output, 'quantum 1500')
4442 self.assertRegex(output, 'initial_quantum 13000')
4443 self.assertRegex(output, 'maxrate 1Mbit')
ab9dc1db 4444
4c7d13f4
YW
4445 @expectedFailureIfModuleIsNotAvailable('sch_fq_codel')
4446 def test_qdisc_fq_codel(self):
4447 copy_network_unit('25-qdisc-fq_codel.network', '12-dummy.netdev')
4448 start_networkd()
95e1fbba 4449 self.wait_online('dummy98:routable')
ab9dc1db 4450
4c7d13f4
YW
4451 output = check_output('tc qdisc show dev dummy98')
4452 print(output)
4453 self.assertRegex(output, 'qdisc fq_codel 34: root')
7887e580 4454 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 4455
4c7d13f4
YW
4456 @expectedFailureIfModuleIsNotAvailable('sch_fq_pie')
4457 def test_qdisc_fq_pie(self):
4458 copy_network_unit('25-qdisc-fq_pie.network', '12-dummy.netdev')
4459 start_networkd()
95e1fbba 4460 self.wait_online('dummy98:routable')
ab9dc1db 4461
4c7d13f4
YW
4462 output = check_output('tc qdisc show dev dummy98')
4463 print(output)
3d55b5a9 4464
4c7d13f4
YW
4465 self.assertRegex(output, 'qdisc fq_pie 3a: root')
4466 self.assertRegex(output, 'limit 200000p')
bc0769c9 4467
4c7d13f4
YW
4468 @expectedFailureIfModuleIsNotAvailable('sch_gred')
4469 def test_qdisc_gred(self):
4470 copy_network_unit('25-qdisc-gred.network', '12-dummy.netdev')
4471 start_networkd()
95e1fbba 4472 self.wait_online('dummy98:routable')
4c7d13f4
YW
4473
4474 output = check_output('tc qdisc show dev dummy98')
4475 print(output)
4476 self.assertRegex(output, 'qdisc gred 38: root')
95edcf3f
YW
4477 self.assertRegex(output, 'vqs 12 default 10 grio')
4478
4c7d13f4
YW
4479 @expectedFailureIfModuleIsNotAvailable('sch_hhf')
4480 def test_qdisc_hhf(self):
4481 copy_network_unit('25-qdisc-hhf.network', '12-dummy.netdev')
4482 start_networkd()
95e1fbba 4483 self.wait_online('dummy98:routable')
4c7d13f4
YW
4484
4485 output = check_output('tc qdisc show dev dummy98')
4486 print(output)
4487 self.assertRegex(output, 'qdisc hhf 3a: root')
4488 self.assertRegex(output, 'limit 1022p')
4489
4490 @expectedFailureIfModuleIsNotAvailable('sch_htb')
4491 def test_qdisc_htb_fifo(self):
4492 copy_network_unit('25-qdisc-htb-fifo.network', '12-dummy.netdev')
4493 start_networkd()
95e1fbba 4494 self.wait_online('dummy98:routable')
4c7d13f4
YW
4495
4496 output = check_output('tc qdisc show dev dummy98')
4497 print(output)
4498 self.assertRegex(output, 'qdisc htb 2: root')
4499 self.assertRegex(output, r'default (0x30|30)')
4500
4501 self.assertRegex(output, 'qdisc pfifo 37: parent 2:37')
4502 self.assertRegex(output, 'limit 100000p')
f2c5c129 4503
7b1a31a3
YW
4504 self.assertRegex(output, 'qdisc bfifo 3a: parent 2:3a')
4505 self.assertRegex(output, 'limit 1000000')
4506
73136507
YW
4507 self.assertRegex(output, 'qdisc pfifo_head_drop 3b: parent 2:3b')
4508 self.assertRegex(output, 'limit 1023p')
4509
41bb371b
YW
4510 self.assertRegex(output, 'qdisc pfifo_fast 3c: parent 2:3c')
4511
2ee7e54b 4512 output = check_output('tc -d class show dev dummy98')
ab9dc1db 4513 print(output)
8e2449a5
YW
4514 # Here (:|prio) is a workaround for a bug in iproute2 v6.2.0 caused by
4515 # https://github.com/shemminger/iproute2/commit/010a8388aea11e767ba3a2506728b9ad9760df0e
4516 # which is fixed in v6.3.0 by
4517 # https://github.com/shemminger/iproute2/commit/4e0e56e0ef05387f7f5d8ab41fe6ec6a1897b26d
4518 self.assertRegex(output, 'class htb 2:37 root leaf 37(:|prio) ')
4519 self.assertRegex(output, 'class htb 2:3a root leaf 3a(:|prio) ')
4520 self.assertRegex(output, 'class htb 2:3b root leaf 3b(:|prio) ')
4521 self.assertRegex(output, 'class htb 2:3c root leaf 3c(:|prio) ')
2ee7e54b
YW
4522 self.assertRegex(output, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit')
4523 self.assertRegex(output, 'burst 123456')
4524 self.assertRegex(output, 'cburst 123457')
0baddbd5 4525
4c7d13f4
YW
4526 @expectedFailureIfModuleIsNotAvailable('sch_ingress')
4527 def test_qdisc_ingress(self):
4528 copy_network_unit('25-qdisc-clsact.network', '12-dummy.netdev',
4529 '25-qdisc-ingress.network', '11-dummy.netdev')
557fa421 4530 start_networkd()
95e1fbba 4531 self.wait_online('dummy98:routable', 'test1:routable')
557fa421
YW
4532
4533 output = check_output('tc qdisc show dev dummy98')
4534 print(output)
4c7d13f4 4535 self.assertRegex(output, 'qdisc clsact')
557fa421 4536
891ff963
YW
4537 output = check_output('tc qdisc show dev test1')
4538 print(output)
4c7d13f4 4539 self.assertRegex(output, 'qdisc ingress')
891ff963 4540
4c7d13f4
YW
4541 @expectedFailureIfModuleIsNotAvailable('sch_netem')
4542 def test_qdisc_netem(self):
4543 copy_network_unit('25-qdisc-netem.network', '12-dummy.netdev',
4544 '25-qdisc-netem-compat.network', '11-dummy.netdev')
3d55b5a9 4545 start_networkd()
95e1fbba 4546 self.wait_online('dummy98:routable', 'test1:routable')
3d55b5a9
YW
4547
4548 output = check_output('tc qdisc show dev dummy98')
4549 print(output)
4c7d13f4
YW
4550 self.assertRegex(output, 'qdisc netem 30: root')
4551 self.assertRegex(output, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
4552
4553 output = check_output('tc qdisc show dev test1')
4554 print(output)
4555 self.assertRegex(output, 'qdisc netem [0-9a-f]*: root')
4556 self.assertRegex(output, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
3d55b5a9 4557
854f9899 4558 @expectedFailureIfModuleIsNotAvailable('sch_pie')
be94e591 4559 def test_qdisc_pie(self):
a962d857 4560 copy_network_unit('25-qdisc-pie.network', '12-dummy.netdev')
be94e591 4561 start_networkd()
95e1fbba 4562 self.wait_online('dummy98:routable')
be94e591
YW
4563
4564 output = check_output('tc qdisc show dev dummy98')
4565 print(output)
4566 self.assertRegex(output, 'qdisc pie 3a: root')
4567 self.assertRegex(output, 'limit 200000')
4568
4c7d13f4
YW
4569 @expectedFailureIfModuleIsNotAvailable('sch_qfq')
4570 def test_qdisc_qfq(self):
4571 copy_network_unit('25-qdisc-qfq.network', '12-dummy.netdev')
970ab1fc 4572 start_networkd()
95e1fbba 4573 self.wait_online('dummy98:routable')
970ab1fc
YW
4574
4575 output = check_output('tc qdisc show dev dummy98')
4576 print(output)
4c7d13f4
YW
4577 self.assertRegex(output, 'qdisc qfq 2: root')
4578 output = check_output('tc class show dev dummy98')
4579 print(output)
4580 self.assertRegex(output, 'class qfq 2:30 root weight 2 maxpkt 16000')
4581 self.assertRegex(output, 'class qfq 2:31 root weight 10 maxpkt 8000')
970ab1fc 4582
4c7d13f4
YW
4583 @expectedFailureIfModuleIsNotAvailable('sch_sfb')
4584 def test_qdisc_sfb(self):
4585 copy_network_unit('25-qdisc-sfb.network', '12-dummy.netdev')
b753e835 4586 start_networkd()
95e1fbba 4587 self.wait_online('dummy98:routable')
b753e835
YW
4588
4589 output = check_output('tc qdisc show dev dummy98')
4590 print(output)
4c7d13f4
YW
4591 self.assertRegex(output, 'qdisc sfb 39: root')
4592 self.assertRegex(output, 'limit 200000')
1578266b 4593
4c7d13f4
YW
4594 @expectedFailureIfModuleIsNotAvailable('sch_sfq')
4595 def test_qdisc_sfq(self):
4596 copy_network_unit('25-qdisc-sfq.network', '12-dummy.netdev')
4597 start_networkd()
95e1fbba 4598 self.wait_online('dummy98:routable')
b753e835 4599
4c7d13f4
YW
4600 output = check_output('tc qdisc show dev dummy98')
4601 print(output)
4602 self.assertRegex(output, 'qdisc sfq 36: root')
4603 self.assertRegex(output, 'perturb 5sec')
4604
4605 @expectedFailureIfModuleIsNotAvailable('sch_tbf')
4606 def test_qdisc_tbf(self):
4607 copy_network_unit('25-qdisc-tbf.network', '12-dummy.netdev')
1578266b 4608 start_networkd()
95e1fbba 4609 self.wait_online('dummy98:routable')
1578266b
YW
4610
4611 output = check_output('tc qdisc show dev dummy98')
4612 print(output)
4c7d13f4
YW
4613 self.assertRegex(output, 'qdisc tbf 35: root')
4614 self.assertRegex(output, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms')
1578266b 4615
4c7d13f4
YW
4616 @expectedFailureIfModuleIsNotAvailable('sch_teql')
4617 def test_qdisc_teql(self):
4618 call_quiet('rmmod sch_teql')
4619
4620 copy_network_unit('25-qdisc-teql.network', '12-dummy.netdev')
4621 start_networkd()
4622 self.wait_links('dummy98')
4623 check_output('modprobe sch_teql max_equalizers=2')
95e1fbba 4624 self.wait_online('dummy98:routable')
4c7d13f4
YW
4625
4626 output = check_output('tc qdisc show dev dummy98')
4627 print(output)
4628 self.assertRegex(output, 'qdisc teql1 31: root')
1578266b 4629
e6fa9119
YW
4630 @expectedFailureIfModuleIsNotAvailable('sch_fq', 'sch_sfq', 'sch_tbf')
4631 def test_qdisc_drop(self):
4632 copy_network_unit('12-dummy.netdev', '12-dummy.network')
4633 start_networkd()
4634 self.wait_online('dummy98:routable')
4635
4636 # Test case for issue #32247 and #32254.
4637 for _ in range(20):
4638 check_output('tc qdisc replace dev dummy98 root fq')
4639 self.assertFalse(networkd_is_failed())
4640 check_output('tc qdisc replace dev dummy98 root fq pacing')
4641 self.assertFalse(networkd_is_failed())
4642 check_output('tc qdisc replace dev dummy98 handle 10: root tbf rate 0.5mbit burst 5kb latency 70ms peakrate 1mbit minburst 1540')
4643 self.assertFalse(networkd_is_failed())
4644 check_output('tc qdisc add dev dummy98 parent 10:1 handle 100: sfq')
4645 self.assertFalse(networkd_is_failed())
4646
336d18f0 4647class NetworkdStateFileTests(unittest.TestCase, Utilities):
336d18f0
YW
4648
4649 def setUp(self):
a962d857 4650 setup_common()
336d18f0
YW
4651
4652 def tearDown(self):
a962d857 4653 tear_down_common()
336d18f0
YW
4654
4655 def test_state_file(self):
a962d857 4656 copy_network_unit('12-dummy.netdev', '25-state-file-tests.network')
336d18f0 4657 start_networkd()
95e1fbba 4658 self.wait_online('dummy98:routable')
336d18f0 4659
f91b2340 4660 # make link state file updated
10d670a3 4661 resolvectl('revert', 'dummy98')
336d18f0 4662
10d670a3 4663 check_json(networkctl_json())
94f0bd62 4664
1a8e1d78
YW
4665 output = read_link_state_file('dummy98')
4666 print(output)
4667 self.assertIn('IPV4_ADDRESS_STATE=routable', output)
4668 self.assertIn('IPV6_ADDRESS_STATE=routable', output)
4669 self.assertIn('ADMIN_STATE=configured', output)
4670 self.assertIn('OPER_STATE=routable', output)
4671 self.assertIn('REQUIRED_FOR_ONLINE=yes', output)
4672 self.assertIn('REQUIRED_OPER_STATE_FOR_ONLINE=routable', output)
4673 self.assertIn('REQUIRED_FAMILY_FOR_ONLINE=both', output)
4674 self.assertIn('ACTIVATION_POLICY=up', output)
4675 self.assertIn('NETWORK_FILE=/run/systemd/network/25-state-file-tests.network', output)
4676 self.assertIn('DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com', output)
4677 self.assertIn('NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org', output)
4678 self.assertIn('DOMAINS=hogehoge', output)
4679 self.assertIn('ROUTE_DOMAINS=foofoo', output)
4680 self.assertIn('LLMNR=no', output)
4681 self.assertIn('MDNS=yes', output)
4682 self.assertIn('DNSSEC=no', output)
336d18f0 4683
10d670a3
YW
4684 resolvectl('dns', 'dummy98', '10.10.10.12#ccc.com', '10.10.10.13', '1111:2222::3333')
4685 resolvectl('domain', 'dummy98', 'hogehogehoge', '~foofoofoo')
4686 resolvectl('llmnr', 'dummy98', 'yes')
4687 resolvectl('mdns', 'dummy98', 'no')
4688 resolvectl('dnssec', 'dummy98', 'yes')
4689 timedatectl('ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org')
336d18f0 4690
10d670a3 4691 check_json(networkctl_json())
94f0bd62 4692
1a8e1d78
YW
4693 output = read_link_state_file('dummy98')
4694 print(output)
4695 self.assertIn('DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333', output)
4696 self.assertIn('NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org', output)
4697 self.assertIn('DOMAINS=hogehogehoge', output)
4698 self.assertIn('ROUTE_DOMAINS=foofoofoo', output)
4699 self.assertIn('LLMNR=yes', output)
4700 self.assertIn('MDNS=no', output)
4701 self.assertIn('DNSSEC=yes', output)
336d18f0 4702
10d670a3 4703 timedatectl('revert', 'dummy98')
336d18f0 4704
10d670a3 4705 check_json(networkctl_json())
94f0bd62 4706
1a8e1d78
YW
4707 output = read_link_state_file('dummy98')
4708 print(output)
4709 self.assertIn('DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333', output)
4710 self.assertIn('NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org', output)
4711 self.assertIn('DOMAINS=hogehogehoge', output)
4712 self.assertIn('ROUTE_DOMAINS=foofoofoo', output)
4713 self.assertIn('LLMNR=yes', output)
4714 self.assertIn('MDNS=no', output)
4715 self.assertIn('DNSSEC=yes', output)
336d18f0 4716
10d670a3 4717 resolvectl('revert', 'dummy98')
336d18f0 4718
10d670a3 4719 check_json(networkctl_json())
94f0bd62 4720
1a8e1d78
YW
4721 output = read_link_state_file('dummy98')
4722 print(output)
4723 self.assertIn('DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com', output)
4724 self.assertIn('NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org', output)
4725 self.assertIn('DOMAINS=hogehoge', output)
4726 self.assertIn('ROUTE_DOMAINS=foofoo', output)
4727 self.assertIn('LLMNR=no', output)
4728 self.assertIn('MDNS=yes', output)
4729 self.assertIn('DNSSEC=no', output)
336d18f0 4730
ee3cbfdb
YW
4731 def test_address_state(self):
4732 copy_network_unit('12-dummy.netdev', '12-dummy-no-address.network')
4733 start_networkd()
4734
95e1fbba 4735 self.wait_online('dummy98:degraded')
ee3cbfdb
YW
4736
4737 output = read_link_state_file('dummy98')
4738 self.assertIn('IPV4_ADDRESS_STATE=off', output)
4739 self.assertIn('IPV6_ADDRESS_STATE=degraded', output)
4740
4741 # with a routable IPv4 address
4742 check_output('ip address add 10.1.2.3/16 dev dummy98')
95e1fbba
YW
4743 self.wait_online('dummy98:routable', ipv4=True)
4744 self.wait_online('dummy98:routable')
ee3cbfdb
YW
4745
4746 output = read_link_state_file('dummy98')
4747 self.assertIn('IPV4_ADDRESS_STATE=routable', output)
4748 self.assertIn('IPV6_ADDRESS_STATE=degraded', output)
4749
4750 check_output('ip address del 10.1.2.3/16 dev dummy98')
4751
4752 # with a routable IPv6 address
4753 check_output('ip address add 2002:da8:1:0:1034:56ff:fe78:9abc/64 dev dummy98')
95e1fbba
YW
4754 self.wait_online('dummy98:routable', ipv6=True)
4755 self.wait_online('dummy98:routable')
ee3cbfdb
YW
4756
4757 output = read_link_state_file('dummy98')
4758 self.assertIn('IPV4_ADDRESS_STATE=off', output)
4759 self.assertIn('IPV6_ADDRESS_STATE=routable', output)
4760
be68c2c9 4761class NetworkdBondTests(unittest.TestCase, Utilities):
c3a8853f
YW
4762
4763 def setUp(self):
a962d857 4764 setup_common()
c3a8853f
YW
4765
4766 def tearDown(self):
a962d857 4767 tear_down_common()
c3a8853f 4768
b06469a6
YW
4769 def test_bond_keep_master(self):
4770 check_output('ip link add bond199 type bond mode active-backup')
4771 check_output('ip link add dummy98 type dummy')
4772 check_output('ip link set dummy98 master bond199')
4773
a962d857 4774 copy_network_unit('23-keep-master.network')
b06469a6 4775 start_networkd()
95e1fbba 4776 self.wait_online('dummy98:enslaved')
b06469a6
YW
4777
4778 output = check_output('ip -d link show bond199')
4779 print(output)
4780 self.assertRegex(output, 'active_slave dummy98')
4781
4782 output = check_output('ip -d link show dummy98')
4783 print(output)
4784 self.assertRegex(output, 'master bond199')
4785
c2990ec3 4786 def test_bond_active_slave(self):
a962d857 4787 copy_network_unit('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2cf6fdff 4788 start_networkd()
95e1fbba 4789 self.wait_online('dummy98:enslaved', 'bond199:degraded')
c2990ec3 4790
371810d1 4791 output = check_output('ip -d link show bond199')
c2990ec3 4792 print(output)
b448fc0a 4793 self.assertIn('active_slave dummy98', output)
c2990ec3 4794
2bb1d3c1
YW
4795 # test case for issue #31165.
4796 since = datetime.datetime.now()
4797 networkctl_reconfigure('dummy98')
95e1fbba 4798 self.wait_online('dummy98:enslaved', 'bond199:degraded')
2bb1d3c1
YW
4799 self.assertNotIn('dummy98: Bringing link down', read_networkd_log(since=since))
4800
c2990ec3 4801 def test_bond_primary_slave(self):
a962d857 4802 copy_network_unit('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2cf6fdff 4803 start_networkd()
95e1fbba 4804 self.wait_online('dummy98:enslaved', 'bond199:degraded')
c2990ec3 4805
371810d1 4806 output = check_output('ip -d link show bond199')
c2990ec3 4807 print(output)
b448fc0a
YW
4808 self.assertIn('primary dummy98', output)
4809
4810 # for issue #25627
4811 mkdir_p(os.path.join(network_unit_dir, '23-bond199.network.d'))
4812 for mac in ['00:11:22:33:44:55', '00:11:22:33:44:56']:
4813 with open(os.path.join(network_unit_dir, '23-bond199.network.d/mac.conf'), mode='w', encoding='utf-8') as f:
4814 f.write(f'[Link]\nMACAddress={mac}\n')
4815
4816 networkctl_reload()
95e1fbba 4817 self.wait_online('dummy98:enslaved', 'bond199:degraded')
b448fc0a
YW
4818
4819 output = check_output('ip -d link show bond199')
4820 print(output)
4821 self.assertIn(f'link/ether {mac}', output)
c2990ec3 4822
cc3e488c 4823 def test_bond_operstate(self):
a962d857
YW
4824 copy_network_unit('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
4825 '25-bond99.network', '25-bond-slave.network')
2cf6fdff 4826 start_networkd()
95e1fbba 4827 self.wait_online('dummy98:enslaved', 'test1:enslaved', 'bond99:routable')
c3a8853f 4828
371810d1 4829 output = check_output('ip -d link show dummy98')
c3a8853f 4830 print(output)
cc3e488c 4831 self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
c3a8853f 4832
371810d1 4833 output = check_output('ip -d link show test1')
c3a8853f
YW
4834 print(output)
4835 self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
4836
371810d1 4837 output = check_output('ip -d link show bond99')
c3a8853f
YW
4838 print(output)
4839 self.assertRegex(output, 'MASTER,UP,LOWER_UP')
4840
19cf3143
DS
4841 self.wait_operstate('dummy98', 'enslaved')
4842 self.wait_operstate('test1', 'enslaved')
4843 self.wait_operstate('bond99', 'routable')
c3a8853f 4844
cefd6b3d 4845 check_output('ip link set dummy98 down')
c3a8853f 4846
19cf3143
DS
4847 self.wait_operstate('dummy98', 'off')
4848 self.wait_operstate('test1', 'enslaved')
cf4dbd84 4849 self.wait_operstate('bond99', 'routable')
c3a8853f 4850
cefd6b3d 4851 check_output('ip link set dummy98 up')
c3a8853f 4852
19cf3143
DS
4853 self.wait_operstate('dummy98', 'enslaved')
4854 self.wait_operstate('test1', 'enslaved')
4855 self.wait_operstate('bond99', 'routable')
c3a8853f 4856
cefd6b3d
ZJS
4857 check_output('ip link set dummy98 down')
4858 check_output('ip link set test1 down')
cc3e488c 4859
19cf3143
DS
4860 self.wait_operstate('dummy98', 'off')
4861 self.wait_operstate('test1', 'off')
2700d2c7 4862
a4632dc7 4863 if not self.wait_operstate('bond99', 'no-carrier', setup_timeout=30, fail_assert=False):
2700d2c7
YW
4864 # Huh? Kernel does not recognize that all slave interfaces are down?
4865 # Let's confirm that networkd's operstate is consistent with ip's result.
4866 self.assertNotRegex(output, 'NO-CARRIER')
cc3e488c 4867
be68c2c9 4868class NetworkdBridgeTests(unittest.TestCase, Utilities):
8d17c386 4869
1f0e3109 4870 def setUp(self):
a962d857 4871 setup_common()
1f0e3109
SS
4872
4873 def tearDown(self):
a962d857 4874 tear_down_common()
1f0e3109 4875
9540f8e2
YW
4876 def test_bridge_mac_none(self):
4877 copy_network_unit('12-dummy-mac.netdev', '26-bridge-mac-slave.network',
4878 '26-bridge-mac.netdev', '26-bridge-mac-master.network', '26-bridge-mac.link')
4879 start_networkd()
95e1fbba 4880 self.wait_online('dummy98:enslaved', 'bridge99:degraded')
9540f8e2
YW
4881
4882 output = check_output('ip link show dev dummy98')
4883 print(output)
4884 self.assertIn('link/ether 12:34:56:78:9a:01', output)
4885
4886 output = check_output('ip link show dev bridge99')
4887 print(output)
4888 self.assertIn('link/ether 12:34:56:78:9a:01', output)
4889
6f943798 4890 def test_bridge_vlan(self):
a962d857 4891 copy_network_unit('11-dummy.netdev', '26-bridge-vlan-slave.network',
60f4b2c5
YW
4892 '26-bridge.netdev', '26-bridge-vlan-master.network',
4893 copy_dropins=False)
6f943798 4894 start_networkd()
95e1fbba 4895 self.wait_online('test1:enslaved', 'bridge99:degraded')
6f943798
YW
4896
4897 output = check_output('bridge vlan show dev test1')
4898 print(output)
60f4b2c5
YW
4899 # check if the default VID is removed
4900 self.assertNotIn('1 Egress Untagged', output)
4901 for i in range(1000, 3000):
4902 if i == 1010:
4903 self.assertIn(f'{i} PVID', output)
4904 elif i in range(1012, 1016) or i in range(1103, 1109):
4905 self.assertIn(f'{i} Egress Untagged', output)
4906 elif i in range(1008, 1014) or i in range(1100, 1111):
4907 self.assertIn(f'{i}', output)
4908 else:
4909 self.assertNotIn(f'{i}', output)
4910
4911 output = check_output('bridge vlan show dev bridge99')
4912 print(output)
4913 # check if the default VID is removed
4914 self.assertNotIn('1 Egress Untagged', output)
4915 for i in range(1000, 3000):
4916 if i == 1020:
4917 self.assertIn(f'{i} PVID', output)
4918 elif i in range(1022, 1026) or i in range(1203, 1209):
4919 self.assertIn(f'{i} Egress Untagged', output)
4920 elif i in range(1018, 1024) or i in range(1200, 1211):
4921 self.assertIn(f'{i}', output)
4922 else:
4923 self.assertNotIn(f'{i}', output)
4924
4925 # Change vlan IDs
4926 copy_network_unit('26-bridge-vlan-slave.network.d/10-override.conf',
4927 '26-bridge-vlan-master.network.d/10-override.conf')
4928 networkctl_reload()
95e1fbba 4929 self.wait_online('test1:enslaved', 'bridge99:degraded')
60f4b2c5
YW
4930
4931 output = check_output('bridge vlan show dev test1')
4932 print(output)
4933 for i in range(1000, 3000):
4934 if i == 2010:
4935 self.assertIn(f'{i} PVID', output)
4936 elif i in range(2012, 2016) or i in range(2103, 2109):
4937 self.assertIn(f'{i} Egress Untagged', output)
4938 elif i in range(2008, 2014) or i in range(2100, 2111):
4939 self.assertIn(f'{i}', output)
4940 else:
4941 self.assertNotIn(f'{i}', output)
4942
4943 output = check_output('bridge vlan show dev bridge99')
4944 print(output)
4945 for i in range(1000, 3000):
4946 if i == 2020:
4947 self.assertIn(f'{i} PVID', output)
4948 elif i in range(2022, 2026) or i in range(2203, 2209):
4949 self.assertIn(f'{i} Egress Untagged', output)
4950 elif i in range(2018, 2024) or i in range(2200, 2211):
4951 self.assertIn(f'{i}', output)
4952 else:
4953 self.assertNotIn(f'{i}', output)
4954
4955 # Remove several vlan IDs
4956 copy_network_unit('26-bridge-vlan-slave.network.d/20-override.conf',
4957 '26-bridge-vlan-master.network.d/20-override.conf')
4958 networkctl_reload()
95e1fbba 4959 self.wait_online('test1:enslaved', 'bridge99:degraded')
60f4b2c5
YW
4960
4961 output = check_output('bridge vlan show dev test1')
4962 print(output)
4963 for i in range(1000, 3000):
4964 if i == 2010:
4965 self.assertIn(f'{i} PVID', output)
4966 elif i in range(2012, 2016):
4967 self.assertIn(f'{i} Egress Untagged', output)
4968 elif i in range(2008, 2014):
4969 self.assertIn(f'{i}', output)
4970 else:
4971 self.assertNotIn(f'{i}', output)
4972
4973 output = check_output('bridge vlan show dev bridge99')
4974 print(output)
4975 for i in range(1000, 3000):
4976 if i == 2020:
4977 self.assertIn(f'{i} PVID', output)
4978 elif i in range(2022, 2026):
4979 self.assertIn(f'{i} Egress Untagged', output)
4980 elif i in range(2018, 2024):
4981 self.assertIn(f'{i}', output)
4982 else:
4983 self.assertNotIn(f'{i}', output)
4984
4985 # Remove all vlan IDs
4986 copy_network_unit('26-bridge-vlan-slave.network.d/30-override.conf',
4987 '26-bridge-vlan-master.network.d/30-override.conf')
4988 networkctl_reload()
95e1fbba 4989 self.wait_online('test1:enslaved', 'bridge99:degraded')
60f4b2c5
YW
4990
4991 output = check_output('bridge vlan show dev test1')
4992 print(output)
4993 self.assertNotIn('PVID', output)
4994 for i in range(1000, 3000):
4995 self.assertNotIn(f'{i}', output)
6f943798
YW
4996
4997 output = check_output('bridge vlan show dev bridge99')
4998 print(output)
60f4b2c5
YW
4999 self.assertNotIn('PVID', output)
5000 for i in range(1000, 3000):
5001 self.assertNotIn(f'{i}', output)
6f943798 5002
988b0660 5003 def test_bridge_vlan_issue_20373(self):
a962d857
YW
5004 copy_network_unit('11-dummy.netdev', '26-bridge-vlan-slave-issue-20373.network',
5005 '26-bridge-issue-20373.netdev', '26-bridge-vlan-master-issue-20373.network',
5006 '21-vlan.netdev', '21-vlan.network')
988b0660 5007 start_networkd()
95e1fbba 5008 self.wait_online('test1:enslaved', 'bridge99:degraded', 'vlan99:routable')
988b0660
YW
5009
5010 output = check_output('bridge vlan show dev test1')
5011 print(output)
5012 self.assertIn('100 PVID Egress Untagged', output)
5013 self.assertIn('560', output)
5014 self.assertIn('600', output)
5015
5016 output = check_output('bridge vlan show dev bridge99')
5017 print(output)
5018 self.assertIn('1 PVID Egress Untagged', output)
5019 self.assertIn('100', output)
5020 self.assertIn('600', output)
5021
cc0276cc 5022 def test_bridge_mdb(self):
a962d857
YW
5023 copy_network_unit('11-dummy.netdev', '26-bridge-mdb-slave.network',
5024 '26-bridge.netdev', '26-bridge-mdb-master.network')
cc0276cc 5025 start_networkd()
95e1fbba 5026 self.wait_online('test1:enslaved', 'bridge99:degraded')
cc0276cc
YW
5027
5028 output = check_output('bridge mdb show dev bridge99')
5029 print(output)
5030 self.assertRegex(output, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064')
5031 self.assertRegex(output, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065')
5032
9f773037 5033 # Old kernel may not support bridge MDB entries on bridge master
a962d857 5034 if call_quiet('bridge mdb add dev bridge99 port bridge99 grp 224.0.1.3 temp vid 4068') == 0:
9f773037
YW
5035 self.assertRegex(output, 'dev bridge99 port bridge99 grp ff02:aaaa:fee5::1:4 temp *vid 4066')
5036 self.assertRegex(output, 'dev bridge99 port bridge99 grp 224.0.1.2 temp *vid 4067')
5037
b06469a6
YW
5038 def test_bridge_keep_master(self):
5039 check_output('ip link add bridge99 type bridge')
5040 check_output('ip link set bridge99 up')
5041 check_output('ip link add dummy98 type dummy')
5042 check_output('ip link set dummy98 master bridge99')
5043
a962d857 5044 copy_network_unit('23-keep-master.network')
b06469a6 5045 start_networkd()
95e1fbba 5046 self.wait_online('dummy98:enslaved')
b06469a6
YW
5047
5048 output = check_output('ip -d link show dummy98')
5049 print(output)
5050 self.assertRegex(output, 'master bridge99')
5051 self.assertRegex(output, 'bridge')
5052
5053 output = check_output('bridge -d link show dummy98')
5054 print(output)
a962d857
YW
5055 self.check_bridge_port_attr('bridge99', 'dummy98', 'path_cost', '400')
5056 self.check_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode', '1')
5057 self.check_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave', '1')
5058 self.check_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood', '1')
5059 self.check_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood', '0')
b06469a6 5060 # CONFIG_BRIDGE_IGMP_SNOOPING=y
a962d857
YW
5061 self.check_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast', '1', allow_enoent=True)
5062 self.check_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress', '1', allow_enoent=True)
5063 self.check_bridge_port_attr('bridge99', 'dummy98', 'learning', '0')
5064 self.check_bridge_port_attr('bridge99', 'dummy98', 'priority', '23')
3f504b89
YW
5065 self.check_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard', '0')
5066 self.check_bridge_port_attr('bridge99', 'dummy98', 'root_block', '0')
b06469a6 5067
1f0e3109 5068 def test_bridge_property(self):
a962d857
YW
5069 copy_network_unit('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
5070 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
5071 '25-bridge99.network')
2cf6fdff 5072 start_networkd()
95e1fbba 5073 self.wait_online('dummy98:enslaved', 'test1:enslaved', 'bridge99:routable')
1f0e3109 5074
21d0ed68
YW
5075 output = check_output('ip -d link show bridge99')
5076 print(output)
5077 self.assertIn('mtu 9000 ', output)
5078
371810d1 5079 output = check_output('ip -d link show test1')
1f0e3109 5080 print(output)
21d0ed68
YW
5081 self.assertIn('master bridge99 ', output)
5082 self.assertIn('bridge_slave', output)
5083 self.assertIn('mtu 9000 ', output)
1f0e3109 5084
371810d1 5085 output = check_output('ip -d link show dummy98')
1f0e3109 5086 print(output)
21d0ed68
YW
5087 self.assertIn('master bridge99 ', output)
5088 self.assertIn('bridge_slave', output)
5089 self.assertIn('mtu 9000 ', output)
1f0e3109 5090
371810d1 5091 output = check_output('ip addr show bridge99')
1f0e3109 5092 print(output)
21d0ed68 5093 self.assertIn('192.168.0.15/24', output)
1f0e3109 5094
371810d1 5095 output = check_output('bridge -d link show dummy98')
1f0e3109 5096 print(output)
a962d857
YW
5097 self.check_bridge_port_attr('bridge99', 'dummy98', 'path_cost', '400')
5098 self.check_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode', '1')
5099 self.check_bridge_port_attr('bridge99', 'dummy98', 'isolated', '1')
5100 self.check_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave', '1')
5101 self.check_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood', '1')
5102 self.check_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood', '0')
5424fd95 5103 # CONFIG_BRIDGE_IGMP_SNOOPING=y
a962d857
YW
5104 self.check_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast', '1', allow_enoent=True)
5105 self.check_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress', '1', allow_enoent=True)
5106 self.check_bridge_port_attr('bridge99', 'dummy98', 'learning', '0')
5107 self.check_bridge_port_attr('bridge99', 'dummy98', 'priority', '23')
3f504b89
YW
5108 self.check_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard', '0')
5109 self.check_bridge_port_attr('bridge99', 'dummy98', 'root_block', '0')
4d7ed14f 5110
5424fd95
YW
5111 output = check_output('bridge -d link show test1')
5112 print(output)
a962d857 5113 self.check_bridge_port_attr('bridge99', 'test1', 'priority', '0')
1f0e3109 5114
371810d1 5115 check_output('ip address add 192.168.0.16/24 dev bridge99')
371810d1 5116 output = check_output('ip addr show bridge99')
2be6c5d2 5117 print(output)
21d0ed68 5118 self.assertIn('192.168.0.16/24', output)
2be6c5d2 5119
e3cbaeab
YW
5120 # for issue #6088
5121 print('### ip -6 route list table all dev bridge99')
5122 output = check_output('ip -6 route list table all dev bridge99')
5123 print(output)
beb75dd3 5124 self.assertRegex(output, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
e3cbaeab 5125
a962d857 5126 remove_link('test1')
cf4dbd84 5127 self.wait_operstate('bridge99', 'routable')
2be6c5d2 5128
21d0ed68
YW
5129 output = check_output('ip -d link show bridge99')
5130 print(output)
5131 self.assertIn('mtu 9000 ', output)
5132
5133 output = check_output('ip -d link show dummy98')
5134 print(output)
5135 self.assertIn('master bridge99 ', output)
5136 self.assertIn('bridge_slave', output)
5137 self.assertIn('mtu 9000 ', output)
804b6cd2 5138
21d0ed68 5139 remove_link('dummy98')
19cf3143 5140 self.wait_operstate('bridge99', 'no-carrier')
2be6c5d2 5141
21d0ed68
YW
5142 output = check_output('ip -d link show bridge99')
5143 print(output)
5144 # When no carrier, the kernel may reset the MTU
5145 self.assertIn('NO-CARRIER', output)
5146
371810d1 5147 output = check_output('ip address show bridge99')
804b6cd2 5148 print(output)
21d0ed68
YW
5149 self.assertNotIn('192.168.0.15/24', output)
5150 self.assertIn('192.168.0.16/24', output) # foreign address is kept
804b6cd2 5151
e3cbaeab
YW
5152 print('### ip -6 route list table all dev bridge99')
5153 output = check_output('ip -6 route list table all dev bridge99')
5154 print(output)
beb75dd3 5155 self.assertRegex(output, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
e3cbaeab 5156
21d0ed68 5157 check_output('ip link add dummy98 type dummy')
95e1fbba 5158 self.wait_online('dummy98:enslaved', 'bridge99:routable')
21d0ed68
YW
5159
5160 output = check_output('ip -d link show bridge99')
5161 print(output)
5162 self.assertIn('mtu 9000 ', output)
5163
5164 output = check_output('ip -d link show dummy98')
5165 print(output)
5166 self.assertIn('master bridge99 ', output)
5167 self.assertIn('bridge_slave', output)
5168 self.assertIn('mtu 9000 ', output)
5169
0fc0d85f 5170 def test_bridge_configure_without_carrier(self):
a962d857
YW
5171 copy_network_unit('26-bridge.netdev', '26-bridge-configure-without-carrier.network',
5172 '11-dummy.netdev')
0fc0d85f
DS
5173 start_networkd()
5174
5175 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
5176 for test in ['no-slave', 'add-slave', 'slave-up', 'slave-no-carrier', 'slave-carrier', 'slave-down']:
5177 with self.subTest(test=test):
5178 if test == 'no-slave':
5179 # bridge has no slaves; it's up but *might* not have carrier
001c07cf 5180 self.wait_operstate('bridge99', operstate=r'(no-carrier|routable)', setup_state=None, setup_timeout=30)
0fc0d85f
DS
5181 # due to a bug in the kernel, newly-created bridges are brought up
5182 # *with* carrier, unless they have had any setting changed; e.g.
5183 # their mac set, priority set, etc. Then, they will lose carrier
5184 # as soon as a (down) slave interface is added, and regain carrier
5185 # again once the slave interface is brought up.
5186 #self.check_link_attr('bridge99', 'carrier', '0')
5187 elif test == 'add-slave':
5188 # add slave to bridge, but leave it down; bridge is definitely no-carrier
5189 self.check_link_attr('test1', 'operstate', 'down')
5190 check_output('ip link set dev test1 master bridge99')
001c07cf 5191 self.wait_operstate('bridge99', operstate='no-carrier', setup_state=None)
0fc0d85f
DS
5192 self.check_link_attr('bridge99', 'carrier', '0')
5193 elif test == 'slave-up':
5194 # bring up slave, which will have carrier; bridge gains carrier
5195 check_output('ip link set dev test1 up')
95e1fbba 5196 self.wait_online('bridge99:routable')
0fc0d85f
DS
5197 self.check_link_attr('bridge99', 'carrier', '1')
5198 elif test == 'slave-no-carrier':
5199 # drop slave carrier; bridge loses carrier
5200 check_output('ip link set dev test1 carrier off')
95e1fbba 5201 self.wait_online('bridge99:no-carrier:no-carrier')
0fc0d85f
DS
5202 self.check_link_attr('bridge99', 'carrier', '0')
5203 elif test == 'slave-carrier':
5204 # restore slave carrier; bridge gains carrier
5205 check_output('ip link set dev test1 carrier on')
95e1fbba 5206 self.wait_online('bridge99:routable')
0fc0d85f
DS
5207 self.check_link_attr('bridge99', 'carrier', '1')
5208 elif test == 'slave-down':
5209 # bring down slave; bridge loses carrier
5210 check_output('ip link set dev test1 down')
95e1fbba 5211 self.wait_online('bridge99:no-carrier:no-carrier')
0fc0d85f
DS
5212 self.check_link_attr('bridge99', 'carrier', '0')
5213
10d670a3 5214 output = networkctl_status('bridge99')
0fc0d85f
DS
5215 self.assertRegex(output, '10.1.2.3')
5216 self.assertRegex(output, '10.1.2.1')
5217
804b6cd2 5218 def test_bridge_ignore_carrier_loss(self):
a962d857
YW
5219 copy_network_unit('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
5220 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
5221 '25-bridge99-ignore-carrier-loss.network')
2cf6fdff 5222 start_networkd()
95e1fbba 5223 self.wait_online('dummy98:enslaved', 'test1:enslaved', 'bridge99:routable')
804b6cd2 5224
371810d1 5225 check_output('ip address add 192.168.0.16/24 dev bridge99')
a962d857 5226 remove_link('test1', 'dummy98')
804b6cd2
YW
5227 time.sleep(3)
5228
371810d1 5229 output = check_output('ip address show bridge99')
804b6cd2
YW
5230 print(output)
5231 self.assertRegex(output, 'NO-CARRIER')
5232 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
5233 self.assertRegex(output, 'inet 192.168.0.16/24 scope global secondary bridge99')
5234
6609924c 5235 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self):
a962d857
YW
5236 copy_network_unit('26-bridge.netdev', '26-bridge-slave-interface-1.network',
5237 '25-bridge99-ignore-carrier-loss.network')
2cf6fdff 5238 start_networkd()
95e1fbba 5239 self.wait_online('bridge99:no-carrier')
6609924c 5240
90e3bcbd
YW
5241 for trial in range(4):
5242 check_output('ip link add dummy98 type dummy')
5243 check_output('ip link set dummy98 up')
5244 if trial < 3:
a962d857 5245 remove_link('dummy98')
6609924c 5246
95e1fbba 5247 self.wait_online('bridge99:routable', 'dummy98:enslaved')
6609924c 5248
371810d1 5249 output = check_output('ip address show bridge99')
6609924c
YW
5250 print(output)
5251 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
5252
371810d1 5253 output = check_output('ip rule list table 100')
6609924c 5254 print(output)
c4f7a347 5255 self.assertIn('from all to 8.8.8.8 lookup 100', output)
6609924c 5256
a03ff4c0 5257class NetworkdSRIOVTests(unittest.TestCase, Utilities):
a03ff4c0
YW
5258
5259 def setUp(self):
a962d857 5260 setup_common()
a03ff4c0
YW
5261
5262 def tearDown(self):
a962d857 5263 tear_down_common()
a03ff4c0
YW
5264
5265 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable()
5266 def test_sriov(self):
d8746f16
YW
5267 copy_network_unit('25-default.link', '25-sriov.network')
5268
a962d857 5269 call('modprobe netdevsim')
a03ff4c0 5270
d45476ef 5271 with open('/sys/bus/netdevsim/new_device', mode='w', encoding='utf-8') as f:
a03ff4c0
YW
5272 f.write('99 1')
5273
a962d857 5274 with open('/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs', mode='w', encoding='utf-8') as f:
a03ff4c0
YW
5275 f.write('3')
5276
a03ff4c0 5277 start_networkd()
95e1fbba 5278 self.wait_online('eni99np1:routable')
a03ff4c0
YW
5279
5280 output = check_output('ip link show dev eni99np1')
5281 print(output)
5282 self.assertRegex(output,
5283 '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 *'
5284 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
5285 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
a962d857 5286 )
a03ff4c0 5287
1e8e9730
YW
5288 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable()
5289 def test_sriov_udev(self):
a962d857 5290 copy_network_unit('25-sriov.link', '25-sriov-udev.network')
1e8e9730 5291
a962d857
YW
5292 call('modprobe netdevsim')
5293
d45476ef 5294 with open('/sys/bus/netdevsim/new_device', mode='w', encoding='utf-8') as f:
1e8e9730
YW
5295 f.write('99 1')
5296
5297 start_networkd()
95e1fbba 5298 self.wait_online('eni99np1:routable')
1e8e9730 5299
b95d35b5
YW
5300 # the name eni99np1 may be an alternative name.
5301 ifname = link_resolve('eni99np1')
5302
1e8e9730
YW
5303 output = check_output('ip link show dev eni99np1')
5304 print(output)
5305 self.assertRegex(output,
5306 '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 *'
5307 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
5308 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
a962d857 5309 )
1e8e9730
YW
5310 self.assertNotIn('vf 3', output)
5311 self.assertNotIn('vf 4', output)
5312
a962d857 5313 with open(os.path.join(network_unit_dir, '25-sriov.link'), mode='a', encoding='utf-8') as f:
1e8e9730
YW
5314 f.write('[Link]\nSR-IOVVirtualFunctions=4\n')
5315
a39a2a81
YW
5316 udevadm_reload()
5317 udevadm_trigger(f'/sys/devices/netdevsim99/net/{ifname}')
1e8e9730
YW
5318
5319 output = check_output('ip link show dev eni99np1')
5320 print(output)
5321 self.assertRegex(output,
5322 '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 *'
5323 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
5324 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off\n *'
5325 'vf 3'
a962d857 5326 )
1e8e9730
YW
5327 self.assertNotIn('vf 4', output)
5328
a962d857 5329 with open(os.path.join(network_unit_dir, '25-sriov.link'), mode='a', encoding='utf-8') as f:
1e8e9730
YW
5330 f.write('[Link]\nSR-IOVVirtualFunctions=\n')
5331
a39a2a81
YW
5332 udevadm_reload()
5333 udevadm_trigger(f'/sys/devices/netdevsim99/net/{ifname}')
1e8e9730
YW
5334
5335 output = check_output('ip link show dev eni99np1')
5336 print(output)
5337 self.assertRegex(output,
5338 '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 *'
5339 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
5340 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off\n *'
5341 'vf 3'
a962d857 5342 )
1e8e9730
YW
5343 self.assertNotIn('vf 4', output)
5344
a962d857 5345 with open(os.path.join(network_unit_dir, '25-sriov.link'), mode='a', encoding='utf-8') as f:
1e8e9730
YW
5346 f.write('[Link]\nSR-IOVVirtualFunctions=2\n')
5347
a39a2a81
YW
5348 udevadm_reload()
5349 udevadm_trigger(f'/sys/devices/netdevsim99/net/{ifname}')
1e8e9730
YW
5350
5351 output = check_output('ip link show dev eni99np1')
5352 print(output)
5353 self.assertRegex(output,
5354 '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 *'
5355 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off'
a962d857 5356 )
1e8e9730
YW
5357 self.assertNotIn('vf 2', output)
5358 self.assertNotIn('vf 3', output)
5359 self.assertNotIn('vf 4', output)
5360
a962d857 5361 with open(os.path.join(network_unit_dir, '25-sriov.link'), mode='a', encoding='utf-8') as f:
1e8e9730
YW
5362 f.write('[Link]\nSR-IOVVirtualFunctions=\n')
5363
a39a2a81
YW
5364 udevadm_reload()
5365 udevadm_trigger(f'/sys/devices/netdevsim99/net/{ifname}')
1e8e9730
YW
5366
5367 output = check_output('ip link show dev eni99np1')
5368 print(output)
5369 self.assertRegex(output,
5370 '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 *'
5371 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
5372 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
a962d857 5373 )
1e8e9730
YW
5374 self.assertNotIn('vf 3', output)
5375 self.assertNotIn('vf 4', output)
5376
be68c2c9 5377class NetworkdLLDPTests(unittest.TestCase, Utilities):
1f0e3109
SS
5378
5379 def setUp(self):
a962d857 5380 setup_common()
1f0e3109
SS
5381
5382 def tearDown(self):
a962d857 5383 tear_down_common()
1f0e3109
SS
5384
5385 def test_lldp(self):
a962d857 5386 copy_network_unit('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
2cf6fdff 5387 start_networkd()
95e1fbba 5388 self.wait_online('veth99:degraded', 'veth-peer:degraded')
1f0e3109 5389
f0d87798
YW
5390 for trial in range(10):
5391 if trial > 0:
5392 time.sleep(1)
5393
10d670a3 5394 output = networkctl('lldp')
f0d87798 5395 print(output)
0f805b46 5396 if re.search(r'veth99 .* veth-peer .* .......a...', output):
f0d87798
YW
5397 break
5398 else:
5399 self.fail()
1f0e3109 5400
d6360819
YW
5401 # With interface name
5402 output = networkctl('lldp', 'veth99');
5403 print(output)
0f805b46 5404 self.assertRegex(output, r'veth99 .* veth-peer .* .......a...')
d6360819
YW
5405
5406 # With interface name pattern
5407 output = networkctl('lldp', 've*9');
5408 print(output)
0f805b46 5409 self.assertRegex(output, r'veth99 .* veth-peer .* .......a...')
d6360819
YW
5410
5411 # json format
5412 output = networkctl('--json=short', 'lldp')
5413 print(output)
5414 self.assertIn('"InterfaceName":"veth99"', output)
5415 self.assertIn('"PortID":"veth-peer"', output)
0f805b46 5416 self.assertIn('"EnabledCapabilities":128', output)
d6360819
YW
5417
5418 # json format with interface name
5419 output = networkctl('--json=short', 'lldp', 'veth99')
5420 print(output)
5421 self.assertIn('"InterfaceName":"veth99"', output)
5422 self.assertIn('"PortID":"veth-peer"', output)
0f805b46 5423 self.assertIn('"EnabledCapabilities":128', output)
d6360819
YW
5424
5425 # json format with interface name pattern
5426 output = networkctl('--json=short', 'lldp', 've*9')
5427 print(output)
5428 self.assertIn('"InterfaceName":"veth99"', output)
5429 self.assertIn('"PortID":"veth-peer"', output)
0f805b46
YW
5430 self.assertIn('"EnabledCapabilities":128', output)
5431
5432 # LLDP neighbors in status
5433 output = networkctl_status('veth99')
5434 print(output)
5435 self.assertRegex(output, r'Connected To: .* on port veth-peer')
5436
5437 # enable forwarding, to enable the Router flag
5438 with open(os.path.join(network_unit_dir, '23-emit-lldp.network'), mode='a', encoding='utf-8') as f:
5439 f.write('[Network]\nIPv4Forwarding=yes\n')
5440
5441 networkctl_reload()
5442 self.wait_online('veth-peer:degraded')
5443
5444 for trial in range(10):
5445 if trial > 0:
5446 time.sleep(1)
5447
5448 output = networkctl('lldp')
5449 print(output)
5450 if re.search(r'veth99 .* veth-peer .* ....r......', output):
5451 break
5452 else:
5453 self.fail()
5454
5455 # With interface name
5456 output = networkctl('lldp', 'veth99');
5457 print(output)
5458 self.assertRegex(output, r'veth99 .* veth-peer .* ....r......')
5459
5460 # With interface name pattern
5461 output = networkctl('lldp', 've*9');
5462 print(output)
5463 self.assertRegex(output, r'veth99 .* veth-peer .* ....r......')
5464
5465 # json format
5466 output = networkctl('--json=short', 'lldp')
5467 print(output)
5468 self.assertIn('"InterfaceName":"veth99"', output)
5469 self.assertIn('"PortID":"veth-peer"', output)
5470 self.assertIn('"EnabledCapabilities":16', output)
5471
5472 # json format with interface name
5473 output = networkctl('--json=short', 'lldp', 'veth99')
5474 print(output)
5475 self.assertIn('"InterfaceName":"veth99"', output)
5476 self.assertIn('"PortID":"veth-peer"', output)
5477 self.assertIn('"EnabledCapabilities":16', output)
5478
5479 # json format with interface name pattern
5480 output = networkctl('--json=short', 'lldp', 've*9')
5481 print(output)
5482 self.assertIn('"InterfaceName":"veth99"', output)
5483 self.assertIn('"PortID":"veth-peer"', output)
5484 self.assertIn('"EnabledCapabilities":16', output)
d6360819
YW
5485
5486 # LLDP neighbors in status
5487 output = networkctl_status('veth99')
5488 print(output)
5489 self.assertRegex(output, r'Connected To: .* on port veth-peer')
5490
be68c2c9 5491class NetworkdRATests(unittest.TestCase, Utilities):
1f0e3109
SS
5492
5493 def setUp(self):
a962d857 5494 setup_common()
1f0e3109
SS
5495
5496 def tearDown(self):
a962d857 5497 tear_down_common()
1f0e3109
SS
5498
5499 def test_ipv6_prefix_delegation(self):
a962d857 5500 copy_network_unit('25-veth.netdev', '25-ipv6-prefix.network', '25-ipv6-prefix-veth.network')
c742d7e8
TM
5501 self.setup_nftset('addr6', 'ipv6_addr')
5502 self.setup_nftset('network6', 'ipv6_addr', 'flags interval;')
5503 self.setup_nftset('ifindex', 'iface_index')
2cf6fdff 5504 start_networkd()
95e1fbba 5505 self.wait_online('veth99:routable', 'veth-peer:degraded')
1f0e3109 5506
3976c430
YW
5507 # IPv6SendRA=yes implies IPv6Forwarding.
5508 self.check_ipv6_sysctl_attr('veth-peer', 'forwarding', '1')
5509
10d670a3 5510 output = resolvectl('dns', 'veth99')
41fd8fe7
YW
5511 print(output)
5512 self.assertRegex(output, 'fe80::')
5513 self.assertRegex(output, '2002:da8:1::1')
5514
10d670a3 5515 output = resolvectl('domain', 'veth99')
80762ccc
YW
5516 print(output)
5517 self.assertIn('hogehoge.test', output)
5518
10d670a3 5519 output = networkctl_status('veth99')
1f0e3109
SS
5520 print(output)
5521 self.assertRegex(output, '2002:da8:1:0')
5522
0fe4a1c8
YW
5523 self.check_ipv6_neigh_sysctl_attr('veth99', 'base_reachable_time_ms', '42000')
5524 self.check_ipv6_neigh_sysctl_attr('veth99', 'retrans_time_ms', '500')
5525
a4640bed
TM
5526 self.check_netlabel('veth99', '2002:da8:1::/64')
5527 self.check_netlabel('veth99', '2002:da8:2::/64')
5528
c742d7e8
TM
5529 self.check_nftset('addr6', '2002:da8:1:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*')
5530 self.check_nftset('addr6', '2002:da8:2:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*')
5531 self.check_nftset('network6', '2002:da8:1::/64')
5532 self.check_nftset('network6', '2002:da8:2::/64')
5533 self.check_nftset('ifindex', 'veth99')
5534
5535 self.teardown_nftset('addr6', 'network6', 'ifindex')
5536
6d1cea7b 5537 def check_ipv6_token_static(self):
95e1fbba 5538 self.wait_online('veth99:routable', 'veth-peer:degraded')
b241fa00 5539
10d670a3 5540 output = networkctl_status('veth99')
b241fa00
KF
5541 print(output)
5542 self.assertRegex(output, '2002:da8:1:0:1a:2b:3c:4d')
68248f43
YW
5543 self.assertRegex(output, '2002:da8:1:0:fa:de:ca:fe')
5544 self.assertRegex(output, '2002:da8:2:0:1a:2b:3c:4d')
5545 self.assertRegex(output, '2002:da8:2:0:fa:de:ca:fe')
b241fa00 5546
6d1cea7b
YW
5547 def test_ipv6_token_static(self):
5548 copy_network_unit('25-veth.netdev', '25-ipv6-prefix.network', '25-ipv6-prefix-veth-token-static.network')
5549 start_networkd()
5550
5551 self.check_ipv6_token_static()
5552
5553 for _ in range(20):
5554 check_output('ip link set veth99 down')
5555 check_output('ip link set veth99 up')
5556
5557 self.check_ipv6_token_static()
5558
5559 for _ in range(20):
5560 check_output('ip link set veth99 down')
5561 time.sleep(random.uniform(0, 0.1))
5562 check_output('ip link set veth99 up')
5563 time.sleep(random.uniform(0, 0.1))
5564
5565 self.check_ipv6_token_static()
5566
9dcdf16b
YW
5567 def test_ndisc_redirect(self):
5568 if not os.path.exists(test_ndisc_send):
5569 self.skipTest(f"{test_ndisc_send} does not exist.")
5570
5571 copy_network_unit('25-veth.netdev', '25-ipv6-prefix.network', '25-ipv6-prefix-veth-token-static.network')
5572 start_networkd()
5573
5574 self.check_ipv6_token_static()
5575
5576 # Introduce two redirect routes.
5577 check_output(f'{test_ndisc_send} --interface veth-peer --type redirect --target-address 2002:da8:1:1:1a:2b:3c:4d --redirect-destination 2002:da8:1:1:1a:2b:3c:4d')
9944629e
YW
5578 check_output(f'{test_ndisc_send} --interface veth-peer --type redirect --target-address 2002:da8:1:2:1a:2b:3c:4d --redirect-destination 2002:da8:1:2:1a:2b:3c:4d')
5579 self.wait_route('veth99', '2002:da8:1:1:1a:2b:3c:4d proto redirect', ipv='-6', timeout_sec=10)
5580 self.wait_route('veth99', '2002:da8:1:2:1a:2b:3c:4d proto redirect', ipv='-6', timeout_sec=10)
9dcdf16b
YW
5581
5582 # Change the target address of the redirects.
9944629e
YW
5583 check_output(f'{test_ndisc_send} --interface veth-peer --type redirect --target-address fe80::1 --redirect-destination 2002:da8:1:1:1a:2b:3c:4d')
5584 check_output(f'{test_ndisc_send} --interface veth-peer --type redirect --target-address fe80::2 --redirect-destination 2002:da8:1:2:1a:2b:3c:4d')
5585 self.wait_route_dropped('veth99', '2002:da8:1:1:1a:2b:3c:4d proto redirect', ipv='-6', timeout_sec=10)
5586 self.wait_route_dropped('veth99', '2002:da8:1:2:1a:2b:3c:4d proto redirect', ipv='-6', timeout_sec=10)
5587 self.wait_route('veth99', '2002:da8:1:1:1a:2b:3c:4d via fe80::1 proto redirect', ipv='-6', timeout_sec=10)
5588 self.wait_route('veth99', '2002:da8:1:2:1a:2b:3c:4d via fe80::2 proto redirect', ipv='-6', timeout_sec=10)
9dcdf16b
YW
5589
5590 # Send Neighbor Advertisement without the router flag to announce the default router is not available anymore.
5591 # Then, verify that all redirect routes and the default route are dropped.
5592 output = check_output('ip -6 address show dev veth-peer scope link')
5593 veth_peer_ipv6ll = re.search('fe80:[:0-9a-f]*', output).group()
5594 print(f'veth-peer IPv6LL address: {veth_peer_ipv6ll}')
5595 check_output(f'{test_ndisc_send} --interface veth-peer --type neighbor-advertisement --target-address {veth_peer_ipv6ll} --is-router no')
9dcdf16b
YW
5596 self.wait_route_dropped('veth99', 'proto ra', ipv='-6', timeout_sec=10)
5597
9944629e
YW
5598 output = check_output('ip -6 route show dev veth99')
5599 print(output)
5600 self.assertIn('2002:da8:1:1:1a:2b:3c:4d via fe80::1 proto redirect', output)
5601 self.assertIn('2002:da8:1:2:1a:2b:3c:4d via fe80::2 proto redirect', output)
5602
3b4eeccd
YW
5603 # Check if sd-radv refuses RS from the same interface.
5604 # See https://github.com/systemd/systemd/pull/32267#discussion_r1566721306
5605 since = datetime.datetime.now()
5606 check_output(f'{test_ndisc_send} --interface veth-peer --type rs --dest {veth_peer_ipv6ll}')
5607 self.check_networkd_log('veth-peer: RADV: Received RS from the same interface, ignoring.', since=since)
5608
a0430b0d
YW
5609 def check_ndisc_mtu(self, mtu):
5610 for _ in range(20):
5611 output = read_ipv6_sysctl_attr('veth99', 'mtu')
5612 if output == f'{mtu}':
5613 break
5614 time.sleep(0.5)
5615 else:
5616 self.fail(f'IPv6 MTU does not matches: value={output}, expected={mtu}')
5617
5618 def test_ndisc_mtu(self):
5619 if not os.path.exists(test_ndisc_send):
5620 self.skipTest(f"{test_ndisc_send} does not exist.")
5621
5622 copy_network_unit('25-veth.netdev',
5623 '25-veth-peer-no-address.network',
5624 '25-ipv6-prefix-veth-token-static.network')
5625 start_networkd()
5626 self.wait_online('veth-peer:degraded')
5627
45c2bbba 5628 self.check_networkd_log('veth99: NDISC: Started IPv6 Router Solicitation client')
a0430b0d
YW
5629
5630 check_output(f'{test_ndisc_send} --interface veth-peer --type ra --lifetime 1hour --mtu 1400')
5631 self.check_ndisc_mtu(1400)
5632
5633 check_output(f'{test_ndisc_send} --interface veth-peer --type ra --lifetime 1hour --mtu 1410')
5634 self.check_ndisc_mtu(1410)
5635
5636 check_output('ip link set dev veth99 mtu 1600')
5637 self.check_ndisc_mtu(1410)
5638
5639 check_output(f'{test_ndisc_send} --interface veth-peer --type ra --lifetime 1hour --mtu 1700')
5640 self.check_ndisc_mtu(1600)
5641
5642 check_output('ip link set dev veth99 mtu 1800')
5643 self.check_ndisc_mtu(1700)
5644
68248f43 5645 def test_ipv6_token_prefixstable(self):
a962d857 5646 copy_network_unit('25-veth.netdev', '25-ipv6-prefix.network', '25-ipv6-prefix-veth-token-prefixstable.network')
c24c83dc 5647 start_networkd()
95e1fbba 5648 self.wait_online('veth99:routable', 'veth-peer:degraded')
c24c83dc 5649
ce4ed0ad 5650 output = check_output('ip -6 address show dev veth99')
c24c83dc 5651 print(output)
ce4ed0ad
YW
5652 self.assertIn('2002:da8:1:0:b47e:7975:fc7a:7d6e/64', output) # the 1st prefixstable
5653 self.assertIn('2002:da8:2:0:1034:56ff:fe78:9abc/64', output) # EUI64
5654
5655 with open(os.path.join(network_unit_dir, '25-ipv6-prefix-veth-token-prefixstable.network'), mode='a', encoding='utf-8') as f:
5656 f.write('\n[IPv6AcceptRA]\nPrefixAllowList=2002:da8:1:0::/64\n')
5657
5658 networkctl_reload()
5659 self.wait_online('veth99:routable')
5660
5661 output = check_output('ip -6 address show dev veth99')
5662 print(output)
5663 self.assertIn('2002:da8:1:0:b47e:7975:fc7a:7d6e/64', output) # the 1st prefixstable
5664 self.assertNotIn('2002:da8:2:0:1034:56ff:fe78:9abc/64', output) # EUI64
5665
5666 check_output('ip address del 2002:da8:1:0:b47e:7975:fc7a:7d6e/64 dev veth99')
5667 check_output('ip address add 2002:da8:1:0:b47e:7975:fc7a:7d6e/64 dev veth-peer nodad')
5668
5669 networkctl_reconfigure('veth99')
5670 self.wait_online('veth99:routable')
5671
5672 output = check_output('ip -6 address show dev veth99')
5673 print(output)
5674 self.assertNotIn('2002:da8:1:0:b47e:7975:fc7a:7d6e/64', output) # the 1st prefixstable
5675 self.assertIn('2002:da8:1:0:da5d:e50a:43fd:5d0f/64', output) # the 2nd prefixstable
5676
5677 check_output('ip address del 2002:da8:1:0:da5d:e50a:43fd:5d0f/64 dev veth99')
5678 check_output('ip address add 2002:da8:1:0:da5d:e50a:43fd:5d0f/64 dev veth-peer nodad')
5679
5680 networkctl_reconfigure('veth99')
5681 self.wait_online('veth99:routable')
5682
5683 output = check_output('ip -6 address show dev veth99')
5684 print(output)
5685 self.assertNotIn('2002:da8:1:0:b47e:7975:fc7a:7d6e/64', output) # the 1st prefixstable
5686 self.assertNotIn('2002:da8:1:0:da5d:e50a:43fd:5d0f/64', output) # the 2nd prefixstable
5687 self.assertIn('2002:da8:1:0:c7e4:77ec:eb31:1b0d/64', output) # the 3rd prefixstable
c24c83dc 5688
68248f43 5689 def test_ipv6_token_prefixstable_without_address(self):
a962d857 5690 copy_network_unit('25-veth.netdev', '25-ipv6-prefix.network', '25-ipv6-prefix-veth-token-prefixstable-without-address.network')
87bbebea 5691 start_networkd()
95e1fbba 5692 self.wait_online('veth99:routable', 'veth-peer:degraded')
87bbebea 5693
10d670a3 5694 output = networkctl_status('veth99')
87bbebea 5695 print(output)
7a2e124b
YW
5696 self.assertIn('2002:da8:1:0:b47e:7975:fc7a:7d6e', output)
5697 self.assertIn('2002:da8:2:0:f689:561a:8eda:7443', output)
87bbebea 5698
29fbbb13
YW
5699 def test_router_hop_limit(self):
5700 copy_network_unit('25-veth-client.netdev',
5701 '25-veth-router.netdev',
5702 '26-bridge.netdev',
5703 '25-veth-bridge.network',
5704 '25-veth-client.network',
5705 '25-veth-router-hop-limit.network',
5706 '25-bridge99.network')
5707 start_networkd()
2e73aa50 5708 self.wait_online('client:routable', 'client-p:enslaved',
29fbbb13
YW
5709 'router:degraded', 'router-p:enslaved',
5710 'bridge99:routable')
5711
2e73aa50 5712 self.check_ipv6_sysctl_attr('client', 'hop_limit', '42')
29fbbb13
YW
5713
5714 with open(os.path.join(network_unit_dir, '25-veth-router-hop-limit.network'), mode='a', encoding='utf-8') as f:
5715 f.write('\n[IPv6SendRA]\nHopLimit=43\n')
5716
5717 networkctl_reload()
5718
2e73aa50
YW
5719 for _ in range(20):
5720 output = read_ipv6_sysctl_attr('client', 'hop_limit')
5721 if output == '43':
5722 break
5723 time.sleep(0.5)
5724
5725 self.check_ipv6_sysctl_attr('client', 'hop_limit', '43')
29fbbb13 5726
bb80f633
YW
5727 def test_router_preference(self):
5728 copy_network_unit('25-veth-client.netdev',
5729 '25-veth-router-high.netdev',
5730 '25-veth-router-low.netdev',
5731 '26-bridge.netdev',
5732 '25-veth-bridge.network',
5733 '25-veth-client.network',
5734 '25-veth-router-high.network',
5735 '25-veth-router-low.network',
5736 '25-bridge99.network')
5737 start_networkd()
95e1fbba
YW
5738 self.wait_online('client-p:enslaved',
5739 'router-high:degraded', 'router-high-p:enslaved',
5740 'router-low:degraded', 'router-low-p:enslaved',
5741 'bridge99:routable')
bb80f633
YW
5742
5743 networkctl_reconfigure('client')
95e1fbba 5744 self.wait_online('client:routable')
bb80f633
YW
5745
5746 self.wait_address('client', '2002:da8:1:99:1034:56ff:fe78:9a00/64', ipv='-6', timeout_sec=10)
5747 self.wait_address('client', '2002:da8:1:98:1034:56ff:fe78:9a00/64', ipv='-6', timeout_sec=10)
5748 self.wait_route('client', 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 512', ipv='-6', timeout_sec=10)
5749 self.wait_route('client', 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 2048', ipv='-6', timeout_sec=10)
5750
5751 output = check_output('ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99')
5752 print(output)
9fbab82b 5753 self.assertIn('metric 512', output)
bb80f633
YW
5754 self.assertIn('pref high', output)
5755 output = check_output('ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98')
5756 print(output)
9fbab82b 5757 self.assertIn('metric 2048', output)
bb80f633
YW
5758 self.assertIn('pref low', output)
5759
5760 with open(os.path.join(network_unit_dir, '25-veth-client.network'), mode='a', encoding='utf-8') as f:
5761 f.write('\n[Link]\nMACAddress=12:34:56:78:9a:01\n[IPv6AcceptRA]\nRouteMetric=100:200:300\n')
5762
5763 networkctl_reload()
95e1fbba 5764 self.wait_online('client:routable')
bb80f633
YW
5765
5766 self.wait_address('client', '2002:da8:1:99:1034:56ff:fe78:9a01/64', ipv='-6', timeout_sec=10)
5767 self.wait_address('client', '2002:da8:1:98:1034:56ff:fe78:9a01/64', ipv='-6', timeout_sec=10)
5768 self.wait_route('client', 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 100', ipv='-6', timeout_sec=10)
5769 self.wait_route('client', 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 300', ipv='-6', timeout_sec=10)
5770
5771 output = check_output('ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99')
5772 print(output)
9fbab82b
YW
5773 self.assertIn('metric 100', output)
5774 self.assertNotIn('metric 512', output)
bb80f633
YW
5775 self.assertIn('pref high', output)
5776 output = check_output('ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98')
5777 print(output)
9fbab82b
YW
5778 self.assertIn('metric 300', output)
5779 self.assertNotIn('metric 2048', output)
bb80f633
YW
5780 self.assertIn('pref low', output)
5781
9fbab82b
YW
5782 # swap the preference (for issue #28439)
5783 remove_network_unit('25-veth-router-high.network', '25-veth-router-low.network')
5784 copy_network_unit('25-veth-router-high2.network', '25-veth-router-low2.network')
5785 networkctl_reload()
5786 self.wait_route('client', 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 300', ipv='-6', timeout_sec=10)
5787 self.wait_route('client', 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 100', ipv='-6', timeout_sec=10)
5788
5789 output = check_output('ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99')
5790 print(output)
5791 self.assertIn('metric 300', output)
5792 self.assertNotIn('metric 100', output)
5793 self.assertIn('pref low', output)
5794 self.assertNotIn('pref high', output)
5795 output = check_output('ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98')
5796 print(output)
5797 self.assertIn('metric 100', output)
5798 self.assertNotIn('metric 300', output)
5799 self.assertIn('pref high', output)
5800 self.assertNotIn('pref low', output)
5801
c1dd58b3
FS
5802 @unittest.skipUnless(radvd_check_config('captive-portal.conf'), "Installed radvd doesn't support captive portals")
5803 def test_captive_portal(self):
5804 copy_network_unit('25-veth-client.netdev',
5805 '25-veth-router-captive.netdev',
5806 '26-bridge.netdev',
5807 '25-veth-client-captive.network',
5808 '25-veth-router-captive.network',
5809 '25-veth-bridge-captive.network',
5810 '25-bridge99.network')
5811 start_networkd()
95e1fbba
YW
5812 self.wait_online('bridge99:routable', 'client-p:enslaved',
5813 'router-captive:degraded', 'router-captivep:enslaved')
c1dd58b3
FS
5814
5815 start_radvd(config_file='captive-portal.conf')
5816 networkctl_reconfigure('client')
95e1fbba 5817 self.wait_online('client:routable')
c1dd58b3
FS
5818
5819 self.wait_address('client', '2002:da8:1:99:1034:56ff:fe78:9a00/64', ipv='-6', timeout_sec=10)
10d670a3 5820 output = networkctl_status('client')
c1dd58b3
FS
5821 print(output)
5822 self.assertIn('Captive Portal: http://systemd.io', output)
5823
5824 @unittest.skipUnless(radvd_check_config('captive-portal.conf'), "Installed radvd doesn't support captive portals")
5825 def test_invalid_captive_portal(self):
5826 def radvd_write_config(captive_portal_uri):
5827 with open(os.path.join(networkd_ci_temp_dir, 'radvd/bogus-captive-portal.conf'), mode='w', encoding='utf-8') as f:
5828 f.write(f'interface router-captive {{ AdvSendAdvert on; AdvCaptivePortalAPI "{captive_portal_uri}"; prefix 2002:da8:1:99::/64 {{ AdvOnLink on; AdvAutonomous on; }}; }};')
5829
5830 captive_portal_uris = [
5831 "42ěščěškd ěšč ě s",
5832 " ",
5833 "🤔",
5834 ]
5835
5836 copy_network_unit('25-veth-client.netdev',
5837 '25-veth-router-captive.netdev',
5838 '26-bridge.netdev',
5839 '25-veth-client-captive.network',
5840 '25-veth-router-captive.network',
5841 '25-veth-bridge-captive.network',
5842 '25-bridge99.network')
5843 start_networkd()
95e1fbba
YW
5844 self.wait_online('bridge99:routable', 'client-p:enslaved',
5845 'router-captive:degraded', 'router-captivep:enslaved')
c1dd58b3
FS
5846
5847 for uri in captive_portal_uris:
5848 print(f"Captive portal: {uri}")
5849 radvd_write_config(uri)
5850 stop_radvd()
5851 start_radvd(config_file='bogus-captive-portal.conf')
5852 networkctl_reconfigure('client')
95e1fbba 5853 self.wait_online('client:routable')
c1dd58b3
FS
5854
5855 self.wait_address('client', '2002:da8:1:99:1034:56ff:fe78:9a00/64', ipv='-6', timeout_sec=10)
10d670a3 5856 output = networkctl_status('client')
c1dd58b3
FS
5857 print(output)
5858 self.assertNotIn('Captive Portal:', output)
5859
be68c2c9 5860class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
1f0e3109
SS
5861
5862 def setUp(self):
a962d857 5863 setup_common()
1f0e3109
SS
5864
5865 def tearDown(self):
a962d857 5866 tear_down_common()
1f0e3109 5867
bc91875a 5868 def check_dhcp_server(self, persist_leases=True):
10d670a3 5869 output = networkctl_status('veth99')
c5f7a087 5870 print(output)
e6c4b5dc 5871 self.assertRegex(output, r'Address: 192.168.5.[0-9]* \(DHCPv4 via 192.168.5.1\)')
c5f7a087
YW
5872 self.assertIn('Gateway: 192.168.5.3', output)
5873 self.assertRegex(output, 'DNS: 192.168.5.1\n *192.168.5.10')
5874 self.assertRegex(output, 'NTP: 192.168.5.1\n *192.168.5.11')
5875
10d670a3 5876 output = networkctl_status('veth-peer')
1c4411b7 5877 print(output)
8bdece74
FS
5878 self.assertRegex(output, "Offered DHCP leases: 192.168.5.[0-9]*")
5879
bc91875a
YW
5880 if persist_leases:
5881 with open('/var/lib/systemd/network/dhcp-server-lease/veth-peer', encoding='utf-8') as f:
5882 check_json(f.read())
5883 else:
5884 self.assertFalse(os.path.exists('/var/lib/systemd/network/dhcp-server-lease/veth-peer'))
5885
5886 def test_dhcp_server(self):
5887 copy_network_unit('25-veth.netdev', '25-dhcp-client.network', '25-dhcp-server.network')
5888 start_networkd()
5889 self.wait_online('veth99:routable', 'veth-peer:routable')
5890
5891 self.check_dhcp_server()
5892
1c4411b7
YW
5893 networkctl_reconfigure('veth-peer')
5894 self.wait_online('veth-peer:routable')
5895
5896 for _ in range(10):
5897 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth-peer', env=env)
5898 if 'Offered DHCP leases: 192.168.5.' in output:
5899 break
5900 time.sleep(.2)
5901 else:
5902 self.fail()
5903
bc91875a
YW
5904 def test_dhcp_server_persist_leases_no(self):
5905 copy_networkd_conf_dropin('persist-leases-no.conf')
5906 copy_network_unit('25-veth.netdev', '25-dhcp-client.network', '25-dhcp-server.network')
5907 start_networkd()
5908 self.wait_online('veth99:routable', 'veth-peer:routable')
5909
5910 self.check_dhcp_server(persist_leases=False)
5911
5912 remove_networkd_conf_dropin('persist-leases-no.conf')
5913 with open(os.path.join(network_unit_dir, '25-dhcp-server.network'), mode='a', encoding='utf-8') as f:
5914 f.write('[DHCPServer]\nPersistLeases=no')
5915 restart_networkd()
5916 self.wait_online('veth99:routable', 'veth-peer:routable')
5917
5918 self.check_dhcp_server(persist_leases=False)
5919
47f1ce16
YW
5920 def test_dhcp_server_null_server_address(self):
5921 copy_network_unit('25-veth.netdev', '25-dhcp-client.network', '25-dhcp-server-null-server-address.network')
5922 start_networkd()
95e1fbba 5923 self.wait_online('veth99:routable', 'veth-peer:routable')
47f1ce16
YW
5924
5925 output = check_output('ip --json address show dev veth-peer')
5926 server_address = json.loads(output)[0]['addr_info'][0]['local']
5927 print(server_address)
5928
5929 output = check_output('ip --json address show dev veth99')
5930 client_address = json.loads(output)[0]['addr_info'][0]['local']
5931 print(client_address)
5932
10d670a3 5933 output = networkctl_status('veth99')
47f1ce16 5934 print(output)
e6c4b5dc 5935 self.assertRegex(output, rf'Address: {client_address} \(DHCPv4 via {server_address}\)')
47f1ce16
YW
5936 self.assertIn(f'Gateway: {server_address}', output)
5937 self.assertIn(f'DNS: {server_address}', output)
5938 self.assertIn(f'NTP: {server_address}', output)
5939
10d670a3 5940 output = networkctl_status('veth-peer')
47f1ce16
YW
5941 self.assertIn(f'Offered DHCP leases: {client_address}', output)
5942
93126bb0
YW
5943 # Check if the same addresses are used even if the service is restarted.
5944 restart_networkd()
5945 self.wait_online('veth99:routable', 'veth-peer:routable')
5946
5947 output = check_output('ip -4 address show dev veth-peer')
5948 print(output)
5949 self.assertIn(f'{server_address}', output)
5950
5951 output = check_output('ip -4 address show dev veth99')
5952 print(output)
5953 self.assertIn(f'{client_address}', output)
5954
5955 output = networkctl_status('veth99')
5956 print(output)
e6c4b5dc 5957 self.assertRegex(output, rf'Address: {client_address} \(DHCPv4 via {server_address}\)')
93126bb0
YW
5958 self.assertIn(f'Gateway: {server_address}', output)
5959 self.assertIn(f'DNS: {server_address}', output)
5960 self.assertIn(f'NTP: {server_address}', output)
5961
5962 output = networkctl_status('veth-peer')
5963 self.assertIn(f'Offered DHCP leases: {client_address}', output)
5964
c5f7a087 5965 def test_dhcp_server_with_uplink(self):
a962d857
YW
5966 copy_network_unit('25-veth.netdev', '25-dhcp-client.network', '25-dhcp-server-downstream.network',
5967 '12-dummy.netdev', '25-dhcp-server-uplink.network')
2cf6fdff 5968 start_networkd()
95e1fbba 5969 self.wait_online('veth99:routable', 'veth-peer:routable')
1f0e3109 5970
10d670a3 5971 output = networkctl_status('veth99')
1f0e3109 5972 print(output)
e6c4b5dc 5973 self.assertRegex(output, r'Address: 192.168.5.[0-9]* \(DHCPv4 via 192.168.5.1\)')
32d97330
YW
5974 self.assertIn('Gateway: 192.168.5.3', output)
5975 self.assertIn('DNS: 192.168.5.1', output)
5976 self.assertIn('NTP: 192.168.5.1', output)
1f0e3109 5977
1f0e3109 5978 def test_emit_router_timezone(self):
a962d857 5979 copy_network_unit('25-veth.netdev', '25-dhcp-client-timezone-router.network', '25-dhcp-server-timezone-router.network')
2cf6fdff 5980 start_networkd()
95e1fbba 5981 self.wait_online('veth99:routable', 'veth-peer:routable')
1f0e3109 5982
10d670a3 5983 output = networkctl_status('veth99')
1f0e3109 5984 print(output)
e6c4b5dc 5985 self.assertRegex(output, r'Address: 192.168.5.[0-9]* \(DHCPv4 via 192.168.5.1\)')
32d97330
YW
5986 self.assertIn('Gateway: 192.168.5.1', output)
5987 self.assertIn('Time Zone: Europe/Berlin', output)
1f0e3109 5988
ffaece68 5989 def test_dhcp_server_static_lease(self):
a962d857 5990 copy_network_unit('25-veth.netdev', '25-dhcp-client-static-lease.network', '25-dhcp-server-static-lease.network')
ffaece68 5991 start_networkd()
95e1fbba 5992 self.wait_online('veth99:routable', 'veth-peer:routable')
ffaece68 5993
10d670a3 5994 output = networkctl_status('veth99')
ffaece68 5995 print(output)
e6c4b5dc
SP
5996 self.assertIn('Address: 10.1.1.200 (DHCPv4 via 10.1.1.1)', output)
5997 self.assertIn('DHCPv4 Client ID: 12:34:56:78:9a:bc', output)
82c60c93
YW
5998
5999 def test_dhcp_server_static_lease_default_client_id(self):
6000 copy_network_unit('25-veth.netdev', '25-dhcp-client.network', '25-dhcp-server-static-lease.network')
6001 start_networkd()
95e1fbba 6002 self.wait_online('veth99:routable', 'veth-peer:routable')
82c60c93 6003
10d670a3 6004 output = networkctl_status('veth99')
82c60c93 6005 print(output)
e6c4b5dc
SP
6006 self.assertIn('Address: 10.1.1.200 (DHCPv4 via 10.1.1.1)', output)
6007 self.assertRegex(output, 'DHCPv4 Client ID: IAID:[0-9a-z]*/DUID')
ffaece68 6008
c95df587 6009class NetworkdDHCPServerRelayAgentTests(unittest.TestCase, Utilities):
c95df587
YA
6010
6011 def setUp(self):
a962d857 6012 setup_common()
c95df587
YA
6013
6014 def tearDown(self):
a962d857 6015 tear_down_common()
c95df587
YA
6016
6017 def test_relay_agent(self):
a962d857
YW
6018 copy_network_unit('25-agent-veth-client.netdev',
6019 '25-agent-veth-server.netdev',
6020 '25-agent-client.network',
6021 '25-agent-server.network',
6022 '25-agent-client-peer.network',
6023 '25-agent-server-peer.network')
c95df587
YA
6024 start_networkd()
6025
95e1fbba 6026 self.wait_online('client:routable')
c95df587 6027
10d670a3 6028 output = networkctl_status('client')
c95df587 6029 print(output)
e6c4b5dc 6030 self.assertRegex(output, r'Address: 192.168.5.150 \(DHCPv4 via 192.168.5.1\)')
c95df587 6031
c4047829 6032 def test_relay_agent_on_bridge(self):
a663ddc0
YW
6033 copy_network_unit('25-agent-bridge.netdev',
6034 '25-agent-veth-client.netdev',
6035 '25-agent-bridge.network',
6036 '25-agent-bridge-port.network',
6037 '25-agent-client.network')
6038 start_networkd()
95e1fbba 6039 self.wait_online('bridge-relay:routable', 'client-peer:enslaved')
a663ddc0
YW
6040
6041 # For issue #30763.
45c2bbba 6042 self.check_networkd_log('bridge-relay: DHCPv4 server: STARTED')
a663ddc0 6043
be68c2c9 6044class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
1f0e3109
SS
6045
6046 def setUp(self):
a962d857 6047 setup_common()
1f0e3109
SS
6048
6049 def tearDown(self):
a962d857 6050 tear_down_common()
1f0e3109
SS
6051
6052 def test_dhcp_client_ipv6_only(self):
a962d857 6053 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-ipv6-only.network')
1f0e3109 6054
2cf6fdff 6055 start_networkd()
95e1fbba 6056 self.wait_online('veth-peer:carrier')
2d7ca6b4
YW
6057
6058 # information request mode
46f2eb51
YW
6059 # The name ipv6-only option may not be supported by older dnsmasq
6060 # start_dnsmasq('--dhcp-option=option:ipv6-only,300')
6061 start_dnsmasq('--dhcp-option=108,00:00:02:00',
6062 '--dhcp-option=option6:dns-server,[2600::ee]',
2d7ca6b4
YW
6063 '--dhcp-option=option6:ntp-server,[2600::ff]',
6064 ra_mode='ra-stateless')
95e1fbba 6065 self.wait_online('veth99:routable', 'veth-peer:routable')
2d7ca6b4 6066
0f9efffa
YW
6067 # DHCPv6 REPLY for INFORMATION-REQUEST may be received after the link entered configured state.
6068 # Let's wait for the expected DNS server being listed in the state file.
6069 for _ in range(100):
6070 output = read_link_state_file('veth99')
0f9efffa
YW
6071 if 'DNS=2600::ee' in output:
6072 break
6073 time.sleep(.2)
6074
2d7ca6b4
YW
6075 # Check link state file
6076 print('## link state file')
6077 output = read_link_state_file('veth99')
6078 print(output)
6079 self.assertIn('DNS=2600::ee', output)
6080 self.assertIn('NTP=2600::ff', output)
6081
6082 # Check manager state file
6083 print('## manager state file')
6084 output = read_manager_state_file()
6085 print(output)
6086 self.assertRegex(output, 'DNS=.*2600::ee')
6087 self.assertRegex(output, 'NTP=.*2600::ff')
6088
6089 print('## dnsmasq log')
6090 output = read_dnsmasq_log_file()
6091 print(output)
6092 self.assertIn('DHCPINFORMATION-REQUEST(veth-peer)', output)
6093 self.assertNotIn('DHCPSOLICIT(veth-peer)', output)
6094 self.assertNotIn('DHCPADVERTISE(veth-peer)', output)
6095 self.assertNotIn('DHCPREQUEST(veth-peer)', output)
6096 self.assertNotIn('DHCPREPLY(veth-peer)', output)
6097
3aa47694 6098 # Check json format
10d670a3 6099 check_json(networkctl_json('veth99'))
3aa47694 6100
2d7ca6b4
YW
6101 # solicit mode
6102 stop_dnsmasq()
46f2eb51
YW
6103 start_dnsmasq('--dhcp-option=108,00:00:02:00',
6104 '--dhcp-option=option6:dns-server,[2600::ee]',
34290c6a 6105 '--dhcp-option=option6:ntp-server,[2600::ff]')
2d7ca6b4 6106 networkctl_reconfigure('veth99')
95e1fbba 6107 self.wait_online('veth99:routable', 'veth-peer:routable')
1f0e3109 6108
18f2638f
YW
6109 # checking address
6110 output = check_output('ip address show dev veth99 scope global')
c5fcd8a7 6111 print(output)
18f2638f
YW
6112 self.assertRegex(output, r'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute')
6113 self.assertNotIn('192.168.5', output)
c5fcd8a7 6114
589af70b
YW
6115 # checking semi-static route
6116 output = check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
6117 print(output)
6118 self.assertRegex(output, 'via fe80::1034:56ff:fe78:9abd')
6119
3a956d38 6120 # Confirm that ipv6 token is not set in the kernel
371810d1 6121 output = check_output('ip token show dev veth99')
3a956d38
YW
6122 print(output)
6123 self.assertRegex(output, 'token :: dev veth99')
6124
0f9efffa 6125 # Make manager and link state file updated
10d670a3 6126 resolvectl('revert', 'veth99')
0f9efffa 6127
34290c6a
YW
6128 # Check link state file
6129 print('## link state file')
6130 output = read_link_state_file('veth99')
6131 print(output)
6132 self.assertIn('DNS=2600::ee', output)
6133 self.assertIn('NTP=2600::ff', output)
6134
6135 # Check manager state file
6136 print('## manager state file')
6137 output = read_manager_state_file()
6138 print(output)
6139 self.assertRegex(output, 'DNS=.*2600::ee')
6140 self.assertRegex(output, 'NTP=.*2600::ff')
6141
91a7afde
YW
6142 print('## dnsmasq log')
6143 output = read_dnsmasq_log_file()
6144 print(output)
2d7ca6b4 6145 self.assertNotIn('DHCPINFORMATION-REQUEST(veth-peer)', output)
91a7afde
YW
6146 self.assertIn('DHCPSOLICIT(veth-peer)', output)
6147 self.assertNotIn('DHCPADVERTISE(veth-peer)', output)
6148 self.assertNotIn('DHCPREQUEST(veth-peer)', output)
6149 self.assertIn('DHCPREPLY(veth-peer)', output)
6150 self.assertIn('sent size: 0 option: 14 rapid-commit', output)
6151
3aa47694 6152 # Check json format
10d670a3 6153 check_json(networkctl_json('veth99'))
3aa47694
YW
6154
6155 # Testing without rapid commit support
91a7afde
YW
6156 with open(os.path.join(network_unit_dir, '25-dhcp-client-ipv6-only.network'), mode='a', encoding='utf-8') as f:
6157 f.write('\n[DHCPv6]\nRapidCommit=no\n')
6158
6159 stop_dnsmasq()
46f2eb51
YW
6160 start_dnsmasq('--dhcp-option=108,00:00:02:00',
6161 '--dhcp-option=option6:dns-server,[2600::ee]',
34290c6a 6162 '--dhcp-option=option6:ntp-server,[2600::ff]')
91a7afde
YW
6163
6164 networkctl_reload()
95e1fbba 6165 self.wait_online('veth99:routable', 'veth-peer:routable')
91a7afde
YW
6166
6167 # checking address
6168 output = check_output('ip address show dev veth99 scope global')
6169 print(output)
6170 self.assertRegex(output, r'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute')
6171 self.assertNotIn('192.168.5', output)
6172
6173 # checking semi-static route
6174 output = check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
6175 print(output)
6176 self.assertRegex(output, 'via fe80::1034:56ff:fe78:9abd')
6177
0f9efffa 6178 # Make manager and link state file updated
10d670a3 6179 resolvectl('revert', 'veth99')
0f9efffa 6180
34290c6a
YW
6181 # Check link state file
6182 print('## link state file')
6183 output = read_link_state_file('veth99')
6184 print(output)
6185 self.assertIn('DNS=2600::ee', output)
6186 self.assertIn('NTP=2600::ff', output)
6187
6188 # Check manager state file
6189 print('## manager state file')
6190 output = read_manager_state_file()
6191 print(output)
6192 self.assertRegex(output, 'DNS=.*2600::ee')
6193 self.assertRegex(output, 'NTP=.*2600::ff')
6194
91a7afde
YW
6195 print('## dnsmasq log')
6196 output = read_dnsmasq_log_file()
6197 print(output)
2d7ca6b4 6198 self.assertNotIn('DHCPINFORMATION-REQUEST(veth-peer)', output)
91a7afde
YW
6199 self.assertIn('DHCPSOLICIT(veth-peer)', output)
6200 self.assertIn('DHCPADVERTISE(veth-peer)', output)
6201 self.assertIn('DHCPREQUEST(veth-peer)', output)
6202 self.assertIn('DHCPREPLY(veth-peer)', output)
6203 self.assertNotIn('rapid-commit', output)
6204
3aa47694 6205 # Check json format
10d670a3 6206 check_json(networkctl_json('veth99'))
3aa47694 6207
e1ef7771 6208 def test_dhcp_client_ipv6_dbus_status(self):
e1ef7771 6209 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-ipv6-only.network')
e1ef7771 6210 start_networkd()
95e1fbba 6211 self.wait_online('veth-peer:carrier')
e1ef7771 6212
6213 # Note that at this point the DHCPv6 client has not been started because no RA (with managed
fcdd21ec 6214 # bit set) has yet been received and the configuration does not include WithoutRA=true
e081ffc1 6215 state = get_dhcp6_client_state('veth99')
46f2eb51 6216 print(f"DHCPv6 client state = {state}")
e1ef7771 6217 self.assertEqual(state, 'stopped')
6218
46f2eb51
YW
6219 state = get_dhcp4_client_state('veth99')
6220 print(f"DHCPv4 client state = {state}")
6221 self.assertEqual(state, 'selecting')
6222
6223 start_dnsmasq('--dhcp-option=108,00:00:02:00')
95e1fbba 6224 self.wait_online('veth99:routable', 'veth-peer:routable')
e1ef7771 6225
e081ffc1 6226 state = get_dhcp6_client_state('veth99')
46f2eb51 6227 print(f"DHCPv6 client state = {state}")
e1ef7771 6228 self.assertEqual(state, 'bound')
6229
46f2eb51
YW
6230 # DHCPv4 client will stop after an DHCPOFFER message received, so we need to wait for a while.
6231 for _ in range(100):
6232 state = get_dhcp4_client_state('veth99')
6233 if state == 'stopped':
6234 break
6235 time.sleep(.2)
6236
6237 print(f"DHCPv4 client state = {state}")
6238 self.assertEqual(state, 'stopped')
6239
aa7336f1
YW
6240 # restart dnsmasq to clear log
6241 stop_dnsmasq()
6242 start_dnsmasq('--dhcp-option=108,00:00:02:00')
6243
6244 # Test renew command
6245 # See https://github.com/systemd/systemd/pull/29472#issuecomment-1759092138
10d670a3 6246 networkctl('renew', 'veth99')
aa7336f1
YW
6247
6248 for _ in range(100):
6249 state = get_dhcp4_client_state('veth99')
6250 if state == 'stopped':
6251 break
6252 time.sleep(.2)
6253
6254 print(f"DHCPv4 client state = {state}")
6255 self.assertEqual(state, 'stopped')
6256
6257 print('## dnsmasq log')
6258 output = read_dnsmasq_log_file()
6259 print(output)
6260 self.assertIn('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc', output)
6261 self.assertIn('DHCPOFFER(veth-peer)', output)
6262 self.assertNotIn('DHCPREQUEST(veth-peer)', output)
6263 self.assertNotIn('DHCPACK(veth-peer)', output)
6264
e448fcd0
SS
6265 def test_dhcp_client_ipv6_only_with_custom_client_identifier(self):
6266 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-ipv6-only-custom-client-identifier.network')
6267
6268 start_networkd()
95e1fbba 6269 self.wait_online('veth-peer:carrier')
e448fcd0 6270 start_dnsmasq()
95e1fbba 6271 self.wait_online('veth99:routable', 'veth-peer:routable')
e448fcd0
SS
6272
6273 # checking address
6274 output = check_output('ip address show dev veth99 scope global')
6275 print(output)
6276 self.assertRegex(output, r'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute')
6277 self.assertNotIn('192.168.5', output)
6278
6279 print('## dnsmasq log')
6280 output = read_dnsmasq_log_file()
6281 print(output)
6282 self.assertIn('DHCPSOLICIT(veth-peer) 00:42:00:00:ab:11:f9:2a:c2:77:29:f9:5c:00', output)
6283 self.assertNotIn('DHCPADVERTISE(veth-peer)', output)
6284 self.assertNotIn('DHCPREQUEST(veth-peer)', output)
6285 self.assertIn('DHCPREPLY(veth-peer)', output)
6286 self.assertIn('sent size: 0 option: 14 rapid-commit', output)
6287
1f0e3109 6288 def test_dhcp_client_ipv4_only(self):
a962d857 6289 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-ipv4-only.network')
1f0e3109 6290
c742d7e8
TM
6291 self.setup_nftset('addr4', 'ipv4_addr')
6292 self.setup_nftset('network4', 'ipv4_addr', 'flags interval;')
6293 self.setup_nftset('ifindex', 'iface_index')
6294
2cf6fdff 6295 start_networkd()
95e1fbba 6296 self.wait_online('veth-peer:carrier')
a962d857 6297 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7',
b5c8f471 6298 '--dhcp-option=option:sip-server,192.168.5.21,192.168.5.22',
a962d857
YW
6299 '--dhcp-option=option:domain-search,example.com',
6300 '--dhcp-alternate-port=67,5555',
6301 ipv4_range='192.168.5.110,192.168.5.119')
95e1fbba 6302 self.wait_online('veth99:routable', 'veth-peer:routable')
9e7d91ed 6303 self.wait_address('veth99', r'inet 192.168.5.11[0-9]*/24', ipv='-4')
1f0e3109 6304
18f2638f
YW
6305 print('## ip address show dev veth99 scope global')
6306 output = check_output('ip address show dev veth99 scope global')
1f0e3109 6307 print(output)
18f2638f
YW
6308 self.assertIn('mtu 1492', output)
6309 self.assertIn('inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99', output)
6310 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')
6311 self.assertNotIn('2600::', output)
195a18c1 6312
6b524d70
YW
6313 output = check_output('ip -4 --json address show dev veth99')
6314 for i in json.loads(output)[0]['addr_info']:
6315 if i['label'] == 'test-label':
6316 address1 = i['local']
6317 break
6318 else:
6319 self.assertFalse(True)
6320
6321 self.assertRegex(address1, r'^192.168.5.11[0-9]$')
6322
18f2638f
YW
6323 print('## ip route show table main dev veth99')
6324 output = check_output('ip route show table main dev veth99')
195a18c1 6325 print(output)
18f2638f
YW
6326 # no DHCP routes assigned to the main table
6327 self.assertNotIn('proto dhcp', output)
6328 # static routes
6329 self.assertIn('192.168.5.0/24 proto kernel scope link src 192.168.5.250', output)
6330 self.assertIn('192.168.5.0/24 proto static scope link', output)
6331 self.assertIn('192.168.6.0/24 proto static scope link', output)
6332 self.assertIn('192.168.7.0/24 proto static scope link', output)
6333
6334 print('## ip route show table 211 dev veth99')
6335 output = check_output('ip route show table 211 dev veth99')
6336 print(output)
6b524d70
YW
6337 self.assertRegex(output, f'default via 192.168.5.1 proto dhcp src {address1} metric 24')
6338 self.assertRegex(output, f'192.168.5.0/24 proto dhcp scope link src {address1} metric 24')
6339 self.assertRegex(output, f'192.168.5.1 proto dhcp scope link src {address1} metric 24')
6340 self.assertRegex(output, f'192.168.5.6 proto dhcp scope link src {address1} metric 24')
6341 self.assertRegex(output, f'192.168.5.7 proto dhcp scope link src {address1} metric 24')
18f2638f
YW
6342 self.assertIn('10.0.0.0/8 via 192.168.5.1 proto dhcp', output)
6343
1a8e1d78
YW
6344 print('## link state file')
6345 output = read_link_state_file('veth99')
6346 print(output)
b5c8f471 6347 # checking DNS server, SIP server, and Domains
1a8e1d78 6348 self.assertIn('DNS=192.168.5.6 192.168.5.7', output)
b5c8f471 6349 self.assertIn('SIP=192.168.5.21 192.168.5.22', output)
1a8e1d78 6350 self.assertIn('DOMAINS=example.com', output)
195a18c1 6351
b5c8f471 6352 print('## json')
10d670a3 6353 j = json.loads(networkctl_json('veth99'))
b5c8f471
YW
6354
6355 self.assertEqual(len(j['DNS']), 2)
6356 for i in j['DNS']:
6357 print(i)
6358 self.assertEqual(i['Family'], 2)
6359 a = socket.inet_ntop(socket.AF_INET, bytearray(i['Address']))
6360 self.assertRegex(a, '^192.168.5.[67]$')
6361 self.assertEqual(i['ConfigSource'], 'DHCPv4')
6362 a = socket.inet_ntop(socket.AF_INET, bytearray(i['ConfigProvider']))
6363 self.assertEqual('192.168.5.1', a)
6364
6365 self.assertEqual(len(j['SIP']), 2)
6366 for i in j['SIP']:
6367 print(i)
6368 self.assertEqual(i['Family'], 2)
6369 a = socket.inet_ntop(socket.AF_INET, bytearray(i['Address']))
6370 self.assertRegex(a, '^192.168.5.2[12]$')
6371 self.assertEqual(i['ConfigSource'], 'DHCPv4')
6372 a = socket.inet_ntop(socket.AF_INET, bytearray(i['ConfigProvider']))
6373 self.assertEqual('192.168.5.1', a)
6374
18f2638f 6375 print('## dnsmasq log')
063c7e9b
YW
6376 output = read_dnsmasq_log_file()
6377 print(output)
6378 self.assertIn('vendor class: FooBarVendorTest', output)
6b524d70 6379 self.assertIn('DHCPDISCOVER(veth-peer) 192.168.5.110 12:34:56:78:9a:bc', output)
063c7e9b
YW
6380 self.assertIn('client provides name: test-hostname', output)
6381 self.assertIn('26:mtu', output)
18f2638f
YW
6382
6383 # change address range, DNS servers, and Domains
888f57c1 6384 stop_dnsmasq()
a962d857 6385 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8',
b5c8f471 6386 '--dhcp-option=option:sip-server,192.168.5.23,192.168.5.24',
a962d857
YW
6387 '--dhcp-option=option:domain-search,foo.example.com',
6388 '--dhcp-alternate-port=67,5555',
6389 ipv4_range='192.168.5.120,192.168.5.129',)
195a18c1
YW
6390
6391 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
a102a52c 6392 print('Wait for the DHCP lease to be expired')
6b524d70 6393 self.wait_address_dropped('veth99', f'inet {address1}/24', ipv='-4', timeout_sec=120)
4b31fc88 6394 self.wait_address('veth99', r'inet 192.168.5.12[0-9]*/24', ipv='-4')
195a18c1 6395
95e1fbba 6396 self.wait_online('veth99:routable', 'veth-peer:routable')
195a18c1 6397
18f2638f
YW
6398 print('## ip address show dev veth99 scope global')
6399 output = check_output('ip address show dev veth99 scope global')
195a18c1 6400 print(output)
18f2638f
YW
6401 self.assertIn('mtu 1492', output)
6402 self.assertIn('inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99', output)
6b524d70 6403 self.assertNotIn(f'{address1}', output)
18f2638f
YW
6404 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')
6405 self.assertNotIn('2600::', output)
195a18c1 6406
6b524d70
YW
6407 output = check_output('ip -4 --json address show dev veth99')
6408 for i in json.loads(output)[0]['addr_info']:
6409 if i['label'] == 'test-label':
6410 address2 = i['local']
6411 break
6412 else:
6413 self.assertFalse(True)
6414
6415 self.assertRegex(address2, r'^192.168.5.12[0-9]$')
6416
18f2638f
YW
6417 print('## ip route show table main dev veth99')
6418 output = check_output('ip route show table main dev veth99')
195a18c1 6419 print(output)
18f2638f
YW
6420 # no DHCP routes assigned to the main table
6421 self.assertNotIn('proto dhcp', output)
6422 # static routes
6423 self.assertIn('192.168.5.0/24 proto kernel scope link src 192.168.5.250', output)
6424 self.assertIn('192.168.5.0/24 proto static scope link', output)
6425 self.assertIn('192.168.6.0/24 proto static scope link', output)
6426 self.assertIn('192.168.7.0/24 proto static scope link', output)
6427
6428 print('## ip route show table 211 dev veth99')
6429 output = check_output('ip route show table 211 dev veth99')
6430 print(output)
6b524d70
YW
6431 self.assertRegex(output, f'default via 192.168.5.1 proto dhcp src {address2} metric 24')
6432 self.assertRegex(output, f'192.168.5.0/24 proto dhcp scope link src {address2} metric 24')
6433 self.assertRegex(output, f'192.168.5.1 proto dhcp scope link src {address2} metric 24')
18f2638f 6434 self.assertNotIn('192.168.5.6', output)
6b524d70
YW
6435 self.assertRegex(output, f'192.168.5.7 proto dhcp scope link src {address2} metric 24')
6436 self.assertRegex(output, f'192.168.5.8 proto dhcp scope link src {address2} metric 24')
18f2638f
YW
6437 self.assertIn('10.0.0.0/8 via 192.168.5.1 proto dhcp', output)
6438
1a8e1d78
YW
6439 print('## link state file')
6440 output = read_link_state_file('veth99')
6441 print(output)
b5c8f471 6442 # checking DNS server, SIP server, and Domains
1a8e1d78 6443 self.assertIn('DNS=192.168.5.1 192.168.5.7 192.168.5.8', output)
b5c8f471 6444 self.assertIn('SIP=192.168.5.23 192.168.5.24', output)
1a8e1d78 6445 self.assertIn('DOMAINS=foo.example.com', output)
18f2638f 6446
b5c8f471 6447 print('## json')
10d670a3 6448 j = json.loads(networkctl_json('veth99'))
b5c8f471
YW
6449
6450 self.assertEqual(len(j['DNS']), 3)
6451 for i in j['DNS']:
6452 print(i)
6453 self.assertEqual(i['Family'], 2)
6454 a = socket.inet_ntop(socket.AF_INET, bytearray(i['Address']))
6455 self.assertRegex(a, '^192.168.5.[178]$')
6456 self.assertEqual(i['ConfigSource'], 'DHCPv4')
6457 a = socket.inet_ntop(socket.AF_INET, bytearray(i['ConfigProvider']))
6458 self.assertEqual('192.168.5.1', a)
6459
6460 self.assertEqual(len(j['SIP']), 2)
6461 for i in j['SIP']:
6462 print(i)
6463 self.assertEqual(i['Family'], 2)
6464 a = socket.inet_ntop(socket.AF_INET, bytearray(i['Address']))
6465 self.assertRegex(a, '^192.168.5.2[34]$')
6466 self.assertEqual(i['ConfigSource'], 'DHCPv4')
6467 a = socket.inet_ntop(socket.AF_INET, bytearray(i['ConfigProvider']))
6468 self.assertEqual('192.168.5.1', a)
6469
18f2638f 6470 print('## dnsmasq log')
063c7e9b
YW
6471 output = read_dnsmasq_log_file()
6472 print(output)
6473 self.assertIn('vendor class: FooBarVendorTest', output)
6b524d70 6474 self.assertIn(f'DHCPDISCOVER(veth-peer) {address1} 12:34:56:78:9a:bc', output)
063c7e9b
YW
6475 self.assertIn('client provides name: test-hostname', output)
6476 self.assertIn('26:mtu', output)
1f0e3109 6477
0677130e 6478 self.check_netlabel('veth99', r'192\.168\.5\.0/24')
a4640bed 6479
c742d7e8
TM
6480 self.check_nftset('addr4', r'192\.168\.5\.1')
6481 self.check_nftset('network4', r'192\.168\.5\.0/24')
6482 self.check_nftset('ifindex', 'veth99')
6483
6484 self.teardown_nftset('addr4', 'network4', 'ifindex')
6485
e1ef7771 6486 def test_dhcp_client_ipv4_dbus_status(self):
e1ef7771 6487 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-ipv4-only.network')
e1ef7771 6488 start_networkd()
95e1fbba 6489 self.wait_online('veth-peer:carrier')
e1ef7771 6490
e081ffc1 6491 state = get_dhcp4_client_state('veth99')
e1ef7771 6492 print(f"State = {state}")
6b524d70 6493 self.assertEqual(state, 'rebooting')
e1ef7771 6494
6495 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7',
6496 '--dhcp-option=option:domain-search,example.com',
6497 '--dhcp-alternate-port=67,5555',
6498 ipv4_range='192.168.5.110,192.168.5.119')
95e1fbba 6499 self.wait_online('veth99:routable', 'veth-peer:routable')
e1ef7771 6500 self.wait_address('veth99', r'inet 192.168.5.11[0-9]*/24', ipv='-4')
6501
e081ffc1 6502 state = get_dhcp4_client_state('veth99')
e1ef7771 6503 print(f"State = {state}")
6504 self.assertEqual(state, 'bound')
6505
b65c5390
YW
6506 def test_dhcp_client_allow_list(self):
6507 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-allow-list.network', copy_dropins=False)
6508
6509 start_networkd()
95e1fbba 6510 self.wait_online('veth-peer:carrier')
b65c5390
YW
6511 since = datetime.datetime.now()
6512 start_dnsmasq()
6513
45c2bbba 6514 self.check_networkd_log('veth99: DHCPv4 server IP address 192.168.5.1 not found in allow-list, ignoring offer.', since=since)
b65c5390
YW
6515
6516 copy_network_unit('25-dhcp-client-allow-list.network.d/00-allow-list.conf')
6517 since = datetime.datetime.now()
6518 networkctl_reload()
6519
45c2bbba 6520 self.check_networkd_log('veth99: DHCPv4 server IP address 192.168.5.1 not found in allow-list, ignoring offer.', since=since)
b65c5390
YW
6521
6522 copy_network_unit('25-dhcp-client-allow-list.network.d/10-deny-list.conf')
6523 since = datetime.datetime.now()
6524 networkctl_reload()
6525
45c2bbba 6526 self.check_networkd_log('veth99: DHCPv4 server IP address 192.168.5.1 found in deny-list, ignoring offer.', since=since)
b65c5390 6527
2beecc70
RP
6528 @unittest.skipUnless("--dhcp-rapid-commit" in run("dnsmasq --help").stdout, reason="dnsmasq is missing dhcp-rapid-commit support")
6529 def test_dhcp_client_rapid_commit(self):
6530 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client.network')
6531 start_networkd()
95e1fbba 6532 self.wait_online('veth-peer:carrier')
2beecc70
RP
6533
6534 start_dnsmasq('--dhcp-rapid-commit')
95e1fbba 6535 self.wait_online('veth99:routable', 'veth-peer:routable')
2beecc70
RP
6536 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24', ipv='-4')
6537
6538 state = get_dhcp4_client_state('veth99')
6539 print(f"DHCPv4 client state = {state}")
6540 self.assertEqual(state, 'bound')
6541
6542 output = read_dnsmasq_log_file()
6543 self.assertIn('DHCPDISCOVER(veth-peer)', output)
6544 self.assertNotIn('DHCPOFFER(veth-peer)', output)
6545 self.assertNotIn('DHCPREQUEST(veth-peer)', output)
6546 self.assertIn('DHCPACK(veth-peer)', output)
6547
46f2eb51
YW
6548 def test_dhcp_client_ipv6_only_mode_without_ipv6_connectivity(self):
6549 copy_network_unit('25-veth.netdev',
6550 '25-dhcp-server-ipv6-only-mode.network',
6551 '25-dhcp-client-ipv6-only-mode.network')
6552 start_networkd()
95e1fbba 6553 self.wait_online('veth99:routable', 'veth-peer:routable', timeout='40s')
46f2eb51
YW
6554 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24', ipv='-4')
6555
6556 state = get_dhcp4_client_state('veth99')
6557 print(f"State = {state}")
6558 self.assertEqual(state, 'bound')
6559
7c0d36ff 6560 def test_dhcp_client_ipv4_use_routes_gateway(self):
a962d857 6561 first = True
e1220a70 6562 for (routes, gateway, dns_and_ntp_routes, classless) in itertools.product([True, False], repeat=4):
a962d857
YW
6563 if first:
6564 first = False
6565 else:
6566 self.tearDown()
6567
6568 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
6569 with self.subTest(routes=routes, gateway=gateway, dns_and_ntp_routes=dns_and_ntp_routes, classless=classless):
6570 self._test_dhcp_client_ipv4_use_routes_gateway(routes, gateway, dns_and_ntp_routes, classless)
7c0d36ff 6571
e1220a70 6572 def _test_dhcp_client_ipv4_use_routes_gateway(self, use_routes, use_gateway, dns_and_ntp_routes, classless):
1e86c833
DDM
6573 testunit = '25-dhcp-client-ipv4-use-routes-use-gateway.network'
6574 testunits = ['25-veth.netdev', '25-dhcp-server-veth-peer.network', testunit]
6983bb0e
FS
6575 testunits.append(f'{testunit}.d/use-routes-{use_routes}.conf')
6576 testunits.append(f'{testunit}.d/use-gateway-{use_gateway}.conf')
6577 testunits.append(f'{testunit}.d/use-dns-and-ntp-routes-{dns_and_ntp_routes}.conf')
a962d857 6578 copy_network_unit(*testunits, copy_dropins=False)
4c2e1833
YW
6579
6580 start_networkd()
95e1fbba 6581 self.wait_online('veth-peer:carrier')
a962d857
YW
6582 additional_options = [
6583 '--dhcp-option=option:dns-server,192.168.5.10,8.8.8.8',
6584 '--dhcp-option=option:ntp-server,192.168.5.11,9.9.9.9',
4001653d 6585 '--dhcp-option=option:static-route,192.168.6.100,192.168.5.2,8.8.8.8,192.168.5.3'
a962d857 6586 ]
625772c9 6587 if classless:
a962d857 6588 additional_options += [
86f67600 6589 '--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
6590 ]
6591 start_dnsmasq(*additional_options)
95e1fbba 6592 self.wait_online('veth99:routable', 'veth-peer:routable')
4c2e1833 6593
625772c9 6594 output = check_output('ip -4 route show dev veth99')
4c2e1833 6595 print(output)
4c2e1833 6596
7c0d36ff 6597 # Check UseRoutes=
625772c9
YW
6598 if use_routes:
6599 if classless:
6600 self.assertRegex(output, r'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
6601 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 6602 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
6603 self.assertRegex(output, r'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
6604 self.assertRegex(output, r'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
6605 else:
4001653d 6606 self.assertRegex(output, r'192.168.6.0/24 via 192.168.5.2 proto dhcp src 192.168.5.[0-9]* metric 1024')
625772c9 6607 self.assertRegex(output, r'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024')
4001653d 6608 self.assertRegex(output, r'192.168.5.2 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
625772c9 6609 self.assertRegex(output, r'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
7c0d36ff 6610 else:
625772c9
YW
6611 self.assertNotRegex(output, r'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
6612 self.assertNotRegex(output, r'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
6613 self.assertNotRegex(output, r'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
6614 self.assertNotRegex(output, r'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4001653d 6615 self.assertNotRegex(output, r'192.168.6.0/24 via 192.168.5.2 proto dhcp src 192.168.5.[0-9]* metric 1024')
625772c9 6616 self.assertNotRegex(output, r'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024')
4001653d 6617 self.assertNotRegex(output, r'192.168.5.2 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
625772c9 6618 self.assertNotRegex(output, r'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
0d7bd445 6619
7c0d36ff 6620 # Check UseGateway=
625772c9
YW
6621 if use_gateway and (not classless or not use_routes):
6622 self.assertRegex(output, r'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
7c0d36ff 6623 else:
625772c9 6624 self.assertNotRegex(output, r'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
87e62d32
YW
6625
6626 # Check route to gateway
6627 if (use_gateway or dns_and_ntp_routes) and (not classless or not use_routes):
6628 self.assertRegex(output, r'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
6629 else:
625772c9 6630 self.assertNotRegex(output, r'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
7c0d36ff 6631
e1220a70
YW
6632 # Check RoutesToDNS= and RoutesToNTP=
6633 if dns_and_ntp_routes:
625772c9 6634 self.assertRegex(output, r'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
e1220a70 6635 self.assertRegex(output, r'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
0ce86f5e
YW
6636 if use_routes:
6637 if classless:
6638 self.assertRegex(output, r'8.8.8.8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
6639 self.assertRegex(output, r'9.9.9.9 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
6640 else:
6641 self.assertRegex(output, r'8.8.8.8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024')
6642 self.assertRegex(output, r'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
87e62d32 6643 else:
625772c9 6644 self.assertRegex(output, r'8.8.8.8 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
e1220a70 6645 self.assertRegex(output, r'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
7c0d36ff 6646 else:
625772c9 6647 self.assertNotRegex(output, r'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
e1220a70 6648 self.assertNotRegex(output, r'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
625772c9 6649 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 6650 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 6651
10d670a3 6652 check_json(networkctl_json())
94f0bd62 6653
1f0e3109 6654 def test_dhcp_client_settings_anonymize(self):
a962d857 6655 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-anonymize.network')
2cf6fdff 6656 start_networkd()
95e1fbba 6657 self.wait_online('veth-peer:carrier')
ec38833c 6658 start_dnsmasq()
95e1fbba 6659 self.wait_online('veth99:routable', 'veth-peer:routable')
e40a58b5 6660
063c7e9b
YW
6661 print('## dnsmasq log')
6662 output = read_dnsmasq_log_file()
6663 print(output)
6664 self.assertNotIn('VendorClassIdentifier=SusantVendorTest', output)
6665 self.assertNotIn('test-hostname', output)
6666 self.assertNotIn('26:mtu', output)
1f0e3109 6667
1e498853 6668 def test_dhcp_keep_configuration_dhcp(self):
a962d857
YW
6669 copy_network_unit('25-veth.netdev',
6670 '25-dhcp-server-veth-peer.network',
6671 '25-dhcp-client-keep-configuration-dhcp.network')
2cf6fdff 6672 start_networkd()
95e1fbba 6673 self.wait_online('veth-peer:carrier')
a962d857 6674 start_dnsmasq()
95e1fbba 6675 self.wait_online('veth99:routable', 'veth-peer:routable')
e40a58b5 6676
1e498853
YW
6677 output = check_output('ip address show dev veth99 scope global')
6678 print(output)
2b6a24a6
YW
6679 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
6680 'valid_lft forever preferred_lft forever')
e40a58b5 6681
5238e957 6682 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
888f57c1 6683 stop_dnsmasq()
1f0e3109
SS
6684
6685 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
a102a52c
YW
6686 print('Wait for the DHCP lease to be expired')
6687 time.sleep(120)
1f0e3109 6688
2b6a24a6 6689 # The lease address should be kept after the lease expired
1e498853
YW
6690 output = check_output('ip address show dev veth99 scope global')
6691 print(output)
2b6a24a6
YW
6692 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
6693 'valid_lft forever preferred_lft forever')
1e498853 6694
2b6a24a6 6695 stop_networkd()
1e498853 6696
2b6a24a6 6697 # The lease address should be kept after networkd stopped
1e498853
YW
6698 output = check_output('ip address show dev veth99 scope global')
6699 print(output)
2b6a24a6
YW
6700 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
6701 'valid_lft forever preferred_lft forever')
1e498853 6702
a962d857 6703 with open(os.path.join(network_unit_dir, '25-dhcp-client-keep-configuration-dhcp.network'), mode='a', encoding='utf-8') as f:
2347b6b9 6704 f.write('[Network]\nDHCP=no\n')
1e498853 6705
2347b6b9 6706 start_networkd()
95e1fbba 6707 self.wait_online('veth99:routable', 'veth-peer:routable')
1e498853 6708
2b6a24a6 6709 # Still the lease address should be kept after networkd restarted
1e498853
YW
6710 output = check_output('ip address show dev veth99 scope global')
6711 print(output)
2b6a24a6
YW
6712 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
6713 'valid_lft forever preferred_lft forever')
1e498853
YW
6714
6715 def test_dhcp_keep_configuration_dhcp_on_stop(self):
a962d857
YW
6716 copy_network_unit('25-veth.netdev',
6717 '25-dhcp-server-veth-peer.network',
6718 '25-dhcp-client-keep-configuration-dhcp-on-stop.network')
2cf6fdff 6719 start_networkd()
95e1fbba 6720 self.wait_online('veth-peer:carrier')
a962d857 6721 start_dnsmasq()
95e1fbba 6722 self.wait_online('veth99:routable', 'veth-peer:routable')
1e498853
YW
6723
6724 output = check_output('ip address show dev veth99 scope global')
6725 print(output)
2b6a24a6 6726 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
1e498853 6727
888f57c1 6728 stop_dnsmasq()
2b6a24a6 6729 stop_networkd()
1e498853
YW
6730
6731 output = check_output('ip address show dev veth99 scope global')
6732 print(output)
2b6a24a6 6733 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
1e498853 6734
a962d857 6735 start_networkd()
95e1fbba 6736 self.wait_online('veth-peer:routable')
1e498853
YW
6737
6738 output = check_output('ip address show dev veth99 scope global')
6739 print(output)
2b6a24a6 6740 self.assertNotIn('192.168.5.', output)
1f0e3109 6741
30d3b54e 6742 def test_dhcp_client_reuse_address_as_static(self):
a962d857 6743 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client.network')
2cf6fdff 6744 start_networkd()
95e1fbba 6745 self.wait_online('veth-peer:carrier')
ec38833c 6746 start_dnsmasq()
95e1fbba 6747 self.wait_online('veth99:routable', 'veth-peer:routable')
2629df47
YW
6748
6749 # link become 'routable' when at least one protocol provide an valid address.
3e726c15 6750 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 6751 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
30d3b54e 6752
371810d1 6753 output = check_output('ip address show dev veth99 scope global')
15519a81
YW
6754 ipv4_address = re.search(r'192.168.5.[0-9]*/24', output).group()
6755 ipv6_address = re.search(r'2600::[0-9a-f:]*/128', output).group()
6756 static_network = '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address, 'Address=' + ipv6_address])
30d3b54e
YW
6757 print(static_network)
6758
a962d857 6759 remove_network_unit('25-dhcp-client.network')
30d3b54e 6760
a962d857 6761 with open(os.path.join(network_unit_dir, '25-static.network'), mode='w', encoding='utf-8') as f:
30d3b54e
YW
6762 f.write(static_network)
6763
15519a81 6764 restart_networkd()
95e1fbba 6765 self.wait_online('veth99:routable')
30d3b54e 6766
371810d1 6767 output = check_output('ip -4 address show dev veth99 scope global')
30d3b54e 6768 print(output)
15519a81
YW
6769 self.assertRegex(output, f'inet {ipv4_address} brd 192.168.5.255 scope global veth99\n *'
6770 'valid_lft forever preferred_lft forever')
30d3b54e 6771
371810d1 6772 output = check_output('ip -6 address show dev veth99 scope global')
30d3b54e 6773 print(output)
15519a81
YW
6774 self.assertRegex(output, f'inet6 {ipv6_address} scope global *\n *'
6775 'valid_lft forever preferred_lft forever')
30d3b54e 6776
18c613dc
YW
6777 @expectedFailureIfModuleIsNotAvailable('vrf')
6778 def test_dhcp_client_vrf(self):
a962d857
YW
6779 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-vrf.network',
6780 '25-vrf.netdev', '25-vrf.network')
2cf6fdff 6781 start_networkd()
95e1fbba 6782 self.wait_online('veth-peer:carrier')
ec38833c 6783 start_dnsmasq()
95e1fbba 6784 self.wait_online('veth99:routable', 'veth-peer:routable', 'vrf99:carrier')
2629df47
YW
6785
6786 # link become 'routable' when at least one protocol provide an valid address.
3e726c15 6787 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 6788 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
18c613dc
YW
6789
6790 print('## ip -d link show dev vrf99')
371810d1 6791 output = check_output('ip -d link show dev vrf99')
18c613dc
YW
6792 print(output)
6793 self.assertRegex(output, 'vrf table 42')
6794
6795 print('## ip address show vrf vrf99')
371810d1 6796 output = check_output('ip address show vrf vrf99')
d90f4f7d 6797 print(output)
3e726c15 6798 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
426654d7 6799 self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
d90f4f7d 6800 self.assertRegex(output, 'inet6 .* scope link')
18c613dc
YW
6801
6802 print('## ip address show dev veth99')
371810d1 6803 output = check_output('ip address show dev veth99')
18c613dc 6804 print(output)
3e726c15 6805 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
426654d7 6806 self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
18c613dc
YW
6807 self.assertRegex(output, 'inet6 .* scope link')
6808
6809 print('## ip route show vrf vrf99')
371810d1 6810 output = check_output('ip route show vrf vrf99')
18c613dc
YW
6811 print(output)
6812 self.assertRegex(output, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
18c613dc 6813 self.assertRegex(output, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
18c613dc
YW
6814 self.assertRegex(output, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
6815
6816 print('## ip route show table main dev veth99')
371810d1 6817 output = check_output('ip route show table main dev veth99')
18c613dc
YW
6818 print(output)
6819 self.assertEqual(output, '')
6820
af3b1498 6821 def test_dhcp_client_gateway_onlink_implicit(self):
a962d857
YW
6822 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network',
6823 '25-dhcp-client-gateway-onlink-implicit.network')
2cf6fdff 6824 start_networkd()
95e1fbba 6825 self.wait_online('veth-peer:carrier')
ec38833c 6826 start_dnsmasq()
95e1fbba 6827 self.wait_online('veth99:routable', 'veth-peer:routable')
af3b1498 6828
10d670a3 6829 output = networkctl_status('veth99')
af3b1498
YW
6830 print(output)
6831 self.assertRegex(output, '192.168.5')
6832
371810d1 6833 output = check_output('ip route list dev veth99 10.0.0.0/8')
af3b1498
YW
6834 print(output)
6835 self.assertRegex(output, 'onlink')
371810d1 6836 output = check_output('ip route list dev veth99 192.168.100.0/24')
af3b1498
YW
6837 print(output)
6838 self.assertRegex(output, 'onlink')
6839
2d7a594f 6840 def test_dhcp_client_with_ipv4ll(self):
a962d857
YW
6841 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network',
6842 '25-dhcp-client-with-ipv4ll.network')
2cf6fdff 6843 start_networkd()
2d7a594f
YW
6844 # we need to increase timeout above default, as this will need to wait for
6845 # systemd-networkd to get the dhcpv4 transient failure event
95e1fbba 6846 self.wait_online('veth99:degraded', 'veth-peer:routable', timeout='60s')
63c598ed 6847
2d7a594f 6848 output = check_output('ip -4 address show dev veth99')
63c598ed 6849 print(output)
2d7a594f 6850 self.assertNotIn('192.168.5.', output)
72c747e6 6851 self.assertIn('inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link', output)
63c598ed 6852
a962d857 6853 start_dnsmasq()
2d7a594f
YW
6854 print('Wait for a DHCP lease to be acquired and the IPv4LL address to be dropped')
6855 self.wait_address('veth99', r'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic', ipv='-4')
6856 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')
95e1fbba 6857 self.wait_online('veth99:routable')
63c598ed 6858
2d7a594f 6859 output = check_output('ip -4 address show dev veth99')
63c598ed 6860 print(output)
3e726c15 6861 self.assertRegex(output, r'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99')
2d7a594f
YW
6862 self.assertNotIn('169.254.', output)
6863 self.assertNotIn('scope link', output)
63c598ed 6864
2d7a594f
YW
6865 stop_dnsmasq()
6866 print('Wait for the DHCP lease to be expired and an IPv4LL address to be acquired')
286bf3a9 6867 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 6868 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 6869
2d7a594f 6870 output = check_output('ip -4 address show dev veth99')
117a55c7 6871 print(output)
2d7a594f 6872 self.assertNotIn('192.168.5.', output)
72c747e6 6873 self.assertIn('inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link', output)
240e4137 6874
3d8e0aa2
YW
6875 def test_dhcp_client_use_dns(self):
6876 def check(self, ipv4, ipv6):
a962d857
YW
6877 os.makedirs(os.path.join(network_unit_dir, '25-dhcp-client.network.d'), exist_ok=True)
6878 with open(os.path.join(network_unit_dir, '25-dhcp-client.network.d/override.conf'), mode='w', encoding='utf-8') as f:
3d8e0aa2
YW
6879 f.write('[DHCPv4]\nUseDNS=')
6880 f.write('yes' if ipv4 else 'no')
6881 f.write('\n[DHCPv6]\nUseDNS=')
6882 f.write('yes' if ipv6 else 'no')
6883 f.write('\n[IPv6AcceptRA]\nUseDNS=no')
6884
a962d857 6885 networkctl_reload()
95e1fbba 6886 self.wait_online('veth99:routable')
e2d5aab3 6887
3d8e0aa2
YW
6888 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
6889 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
6890 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
e2d5aab3 6891
3d8e0aa2 6892 # make resolved re-read the link state file
10d670a3 6893 resolvectl('revert', 'veth99')
e2d5aab3 6894
10d670a3 6895 output = resolvectl('dns', 'veth99')
3d8e0aa2
YW
6896 print(output)
6897 if ipv4:
6898 self.assertIn('192.168.5.1', output)
6899 else:
6900 self.assertNotIn('192.168.5.1', output)
6901 if ipv6:
6902 self.assertIn('2600::1', output)
6903 else:
6904 self.assertNotIn('2600::1', output)
e2d5aab3 6905
10d670a3 6906 check_json(networkctl_json())
e2d5aab3 6907
a962d857 6908 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client.network', copy_dropins=False)
e2d5aab3
YW
6909
6910 start_networkd()
95e1fbba 6911 self.wait_online('veth-peer:carrier')
a962d857
YW
6912 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1',
6913 '--dhcp-option=option6:dns-server,[2600::1]')
e2d5aab3 6914
3d8e0aa2
YW
6915 check(self, True, True)
6916 check(self, True, False)
6917 check(self, False, True)
6918 check(self, False, False)
864c7980
YW
6919
6920 def test_dhcp_client_default_use_domains(self):
d51377ac 6921 def check(self, common, ipv4, ipv6):
fb573007
HL
6922 mkdir_p(networkd_conf_dropin_dir)
6923 with open(os.path.join(networkd_conf_dropin_dir, 'default_use_domains.conf'), mode='w', encoding='utf-8') as f:
d51377ac
YW
6924 f.write('[Network]\nUseDomains=')
6925 f.write('yes\n' if common else 'no\n')
fb573007
HL
6926 f.write('[DHCPv4]\nUseDomains=')
6927 f.write('yes\n' if ipv4 else 'no\n')
6928 f.write('[DHCPv6]\nUseDomains=')
6929 f.write('yes\n' if ipv6 else 'no\n')
864c7980 6930
fb573007
HL
6931 restart_networkd()
6932 self.wait_online('veth-peer:carrier')
6933 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1',
6934 '--dhcp-option=option6:dns-server,[2600::1]',
6935 '--dhcp-option=option:domain-search,example.com',
6936 '--dhcp-option=option6:domain-search,example.com')
6937
6938 self.wait_online('veth99:routable')
6939
6940 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
6941 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
6942 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
6943
6944 for _ in range(20):
6945 output = resolvectl('domain', 'veth99')
d51377ac 6946 if common or ipv4 or ipv6:
fb573007
HL
6947 if 'example.com' in output:
6948 break
6949 else:
6950 if 'example.com' not in output:
6951 break
6952 time.sleep(0.5)
6953 else:
6954 print(output)
d51377ac 6955 print(read_link_state_file('veth99'))
fb573007 6956 self.fail('unexpected domain setting in resolved...')
864c7980 6957
fb573007
HL
6958 stop_dnsmasq()
6959 remove_networkd_conf_dropin('default_use_domains.conf')
6960
6961 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client.network', copy_dropins=False)
d51377ac
YW
6962 check(self, True, False, False)
6963 check(self, False, True, True)
6964 check(self, False, True, False)
6965 check(self, False, False, True)
6966 check(self, False, False, False)
e2d5aab3 6967
dbe960f0
RP
6968 def test_dhcp_client_use_captive_portal(self):
6969 def check(self, ipv4, ipv6):
6970 os.makedirs(os.path.join(network_unit_dir, '25-dhcp-client.network.d'), exist_ok=True)
6971 with open(os.path.join(network_unit_dir, '25-dhcp-client.network.d/override.conf'), mode='w', encoding='utf-8') as f:
6972 f.write('[DHCPv4]\nUseCaptivePortal=')
6973 f.write('yes' if ipv4 else 'no')
6974 f.write('\n[DHCPv6]\nUseCaptivePortal=')
6975 f.write('yes' if ipv6 else 'no')
6976 f.write('\n[IPv6AcceptRA]\nUseCaptivePortal=no')
6977
6978 networkctl_reload()
95e1fbba 6979 self.wait_online('veth99:routable')
dbe960f0
RP
6980
6981 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
6982 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
6983 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
6984
10d670a3 6985 output = networkctl_status('veth99')
dbe960f0
RP
6986 print(output)
6987 if ipv4 or ipv6:
6988 self.assertIn('Captive Portal: http://systemd.io', output)
6989 else:
6990 self.assertNotIn('Captive Portal: http://systemd.io', output)
6991
10d670a3 6992 check_json(networkctl_json())
dbe960f0
RP
6993
6994 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client.network', copy_dropins=False)
6995
6996 start_networkd()
95e1fbba 6997 self.wait_online('veth-peer:carrier')
dbe960f0
RP
6998 start_dnsmasq('--dhcp-option=114,http://systemd.io',
6999 '--dhcp-option=option6:103,http://systemd.io')
7000
7001 check(self, True, True)
7002 check(self, True, False)
7003 check(self, False, True)
7004 check(self, False, False)
7005
1219391c
RP
7006 def test_dhcp_client_reject_captive_portal(self):
7007 def check(self, ipv4, ipv6):
7008 os.makedirs(os.path.join(network_unit_dir, '25-dhcp-client.network.d'), exist_ok=True)
7009 with open(os.path.join(network_unit_dir, '25-dhcp-client.network.d/override.conf'), mode='w', encoding='utf-8') as f:
7010 f.write('[DHCPv4]\nUseCaptivePortal=')
7011 f.write('yes' if ipv4 else 'no')
7012 f.write('\n[DHCPv6]\nUseCaptivePortal=')
7013 f.write('yes' if ipv6 else 'no')
7014 f.write('\n[IPv6AcceptRA]\nUseCaptivePortal=no')
7015
7016 networkctl_reload()
95e1fbba 7017 self.wait_online('veth99:routable')
1219391c
RP
7018
7019 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
7020 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
7021 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
7022
10d670a3 7023 output = networkctl_status('veth99')
1219391c
RP
7024 print(output)
7025 self.assertNotIn('Captive Portal: ', output)
7026 self.assertNotIn('invalid/url', output)
7027
10d670a3 7028 check_json(networkctl_json())
1219391c
RP
7029
7030 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client.network', copy_dropins=False)
7031
7032 start_networkd()
95e1fbba 7033 self.wait_online('veth-peer:carrier')
1219391c
RP
7034 masq = lambda bs: ':'.join(f'{b:02x}' for b in bs)
7035 start_dnsmasq('--dhcp-option=114,' + masq(b'http://\x00invalid/url'),
7036 '--dhcp-option=option6:103,' + masq(b'http://\x00/invalid/url'))
7037
7038 check(self, True, True)
7039 check(self, True, False)
7040 check(self, False, True)
7041 check(self, False, False)
7042
a27588d4 7043class NetworkdDHCPPDTests(unittest.TestCase, Utilities):
caad88a2
YW
7044
7045 def setUp(self):
a962d857 7046 setup_common()
caad88a2
YW
7047
7048 def tearDown(self):
a962d857 7049 tear_down_common()
caad88a2 7050
ab06b74f
YW
7051 def check_dhcp6_prefix(self, link):
7052 description = get_link_description(link)
8fb6320e 7053
ab06b74f
YW
7054 self.assertIn('DHCPv6Client', description.keys())
7055 self.assertIn('Prefixes', description['DHCPv6Client'])
8fb6320e 7056
ab06b74f 7057 prefixInfo = description['DHCPv6Client']['Prefixes']
8fb6320e 7058
ab06b74f 7059 self.assertEqual(len(prefixInfo), 1)
8fb6320e 7060
ab06b74f
YW
7061 self.assertIn('Prefix', prefixInfo[0].keys())
7062 self.assertIn('PrefixLength', prefixInfo[0].keys())
7063 self.assertIn('PreferredLifetimeUSec', prefixInfo[0].keys())
7064 self.assertIn('ValidLifetimeUSec', prefixInfo[0].keys())
caad88a2 7065
ab06b74f
YW
7066 self.assertEqual(prefixInfo[0]['Prefix'][0:6], [63, 254, 5, 1, 255, 255])
7067 self.assertEqual(prefixInfo[0]['PrefixLength'], 56)
7068 self.assertGreater(prefixInfo[0]['PreferredLifetimeUSec'], 0)
7069 self.assertGreater(prefixInfo[0]['ValidLifetimeUSec'], 0)
7070
7071 def test_dhcp6pd_no_address(self):
7072 # For issue #29979.
7073 copy_network_unit('25-veth.netdev', '25-dhcp6pd-server.network', '25-dhcp6pd-upstream-no-address.network')
c742d7e8 7074
caad88a2 7075 start_networkd()
95e1fbba 7076 self.wait_online('veth-peer:routable')
a962d857 7077 start_isc_dhcpd(conf_file='isc-dhcpd-dhcp6pd.conf', ipv='-6')
95e1fbba 7078 self.wait_online('veth99:degraded')
1805e2cb 7079
1805e2cb
YW
7080 print('### ip -6 address show dev veth99 scope global')
7081 output = check_output('ip -6 address show dev veth99 scope global')
7082 print(output)
7083 self.assertNotIn('inet6 3ffe:501:ffff', output)
caad88a2 7084
ab06b74f 7085 self.check_dhcp6_prefix('veth99')
8fb6320e 7086
3b677c6f
YW
7087 def test_dhcp6pd_no_assign(self):
7088 # Similar to test_dhcp6pd_no_assign(), but in this case UseAddress=yes (default),
7089 # However, the server does not provide IA_NA. For issue #31349.
7090 copy_network_unit('25-veth.netdev', '25-dhcp6pd-server.network', '25-dhcp6pd-upstream-no-assign.network')
7091
7092 start_networkd()
7093 self.wait_online('veth-peer:routable')
7094 start_isc_dhcpd(conf_file='isc-dhcpd-dhcp6pd-no-range.conf', ipv='-6')
7095 self.wait_online('veth99:degraded')
7096
7097 print('### ip -6 address show dev veth99 scope global')
7098 output = check_output('ip -6 address show dev veth99 scope global')
7099 print(output)
7100 self.assertNotIn('inet6 3ffe:501:ffff', output)
7101
7102 self.check_dhcp6_prefix('veth99')
7103
ab06b74f
YW
7104 def test_dhcp6pd(self):
7105 copy_network_unit('25-veth.netdev', '25-dhcp6pd-server.network', '25-dhcp6pd-upstream.network',
7106 '25-veth-downstream-veth97.netdev', '25-dhcp-pd-downstream-veth97.network', '25-dhcp-pd-downstream-veth97-peer.network',
7107 '25-veth-downstream-veth98.netdev', '25-dhcp-pd-downstream-veth98.network', '25-dhcp-pd-downstream-veth98-peer.network',
7108 '11-dummy.netdev', '25-dhcp-pd-downstream-test1.network',
7109 '25-dhcp-pd-downstream-dummy97.network',
7110 '12-dummy.netdev', '25-dhcp-pd-downstream-dummy98.network',
7111 '13-dummy.netdev', '25-dhcp-pd-downstream-dummy99.network')
8fb6320e 7112
ab06b74f
YW
7113 start_networkd()
7114 self.wait_online('veth-peer:routable')
7115 start_isc_dhcpd(conf_file='isc-dhcpd-dhcp6pd.conf', ipv='-6')
95e1fbba
YW
7116 self.wait_online('veth99:routable', 'test1:routable', 'dummy98:routable', 'dummy99:degraded',
7117 'veth97:routable', 'veth97-peer:routable', 'veth98:routable', 'veth98-peer:routable')
1805e2cb 7118
ab06b74f
YW
7119 self.setup_nftset('addr6', 'ipv6_addr')
7120 self.setup_nftset('network6', 'ipv6_addr', 'flags interval;')
7121 self.setup_nftset('ifindex', 'iface_index')
7122
7123 # Check DBus assigned prefix information to veth99
7124 self.check_dhcp6_prefix('veth99')
7125
caad88a2
YW
7126 print('### ip -6 address show dev veth-peer scope global')
7127 output = check_output('ip -6 address show dev veth-peer scope global')
7128 print(output)
7129 self.assertIn('inet6 3ffe:501:ffff:100::1/64 scope global', output)
7130
f7805a6c
FS
7131 # Link Subnet IDs
7132 # test1: 0x00
7133 # dummy97: 0x01 (The link will appear later)
07b7337a
YW
7134 # dummy98: 0x00
7135 # dummy99: auto -> 0x02 (No address assignment)
f7805a6c
FS
7136 # veth97: 0x08
7137 # veth98: 0x09
38488bab 7138 # veth99: 0x10
6016f1cf 7139
caad88a2
YW
7140 print('### ip -6 address show dev veth99 scope global')
7141 output = check_output('ip -6 address show dev veth99 scope global')
7142 print(output)
7143 # IA_NA
7144 self.assertRegex(output, 'inet6 3ffe:501:ffff:100::[0-9]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
7145 # address in IA_PD (Token=static)
38488bab 7146 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic')
caad88a2 7147 # address in IA_PD (Token=eui64)
38488bab
YW
7148 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic')
7149 # address in IA_PD (temporary)
7150 # Note that the temporary addresses may appear after the link enters configured state
7151 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
7152
7153 print('### ip -6 address show dev test1 scope global')
7154 output = check_output('ip -6 address show dev test1 scope global')
7155 print(output)
7156 # address in IA_PD (Token=static)
7157 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
7158 # address in IA_PD (temporary)
7159 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')
7160
7161 print('### ip -6 address show dev dummy98 scope global')
7162 output = check_output('ip -6 address show dev dummy98 scope global')
7163 print(output)
7164 # address in IA_PD (Token=static)
07b7337a 7165 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
caad88a2 7166 # address in IA_PD (temporary)
07b7337a 7167 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
7168
7169 print('### ip -6 address show dev dummy99 scope global')
7170 output = check_output('ip -6 address show dev dummy99 scope global')
7171 print(output)
7172 # Assign=no
07b7337a 7173 self.assertNotRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]02')
caad88a2 7174
6c8d6bdd
YW
7175 print('### ip -6 address show dev veth97 scope global')
7176 output = check_output('ip -6 address show dev veth97 scope global')
7177 print(output)
7178 # address in IA_PD (Token=static)
7179 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
7180 # address in IA_PD (Token=eui64)
7181 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr')
7182 # address in IA_PD (temporary)
7183 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')
7184
7185 print('### ip -6 address show dev veth97-peer scope global')
7186 output = check_output('ip -6 address show dev veth97-peer scope global')
7187 print(output)
7188 # NDisc address (Token=static)
7189 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
7190 # NDisc address (Token=eui64)
7191 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr')
7192 # NDisc address (temporary)
7193 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')
7194
caad88a2
YW
7195 print('### ip -6 address show dev veth98 scope global')
7196 output = check_output('ip -6 address show dev veth98 scope global')
7197 print(output)
7198 # address in IA_PD (Token=static)
7199 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
7200 # address in IA_PD (Token=eui64)
7201 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr')
7202 # address in IA_PD (temporary)
7203 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')
7204
7205 print('### ip -6 address show dev veth98-peer scope global')
7206 output = check_output('ip -6 address show dev veth98-peer scope global')
7207 print(output)
7208 # NDisc address (Token=static)
7209 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
7210 # NDisc address (Token=eui64)
7211 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr')
7212 # NDisc address (temporary)
7213 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')
7214
caad88a2
YW
7215 print('### ip -6 route show type unreachable')
7216 output = check_output('ip -6 route show type unreachable')
7217 print(output)
7218 self.assertRegex(output, 'unreachable 3ffe:501:ffff:[2-9a-f]00::/56 dev lo proto dhcp')
7219
7220 print('### ip -6 route show dev veth99')
7221 output = check_output('ip -6 route show dev veth99')
7222 print(output)
38488bab 7223 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]10::/64 proto kernel metric [0-9]* expires')
caad88a2
YW
7224
7225 print('### ip -6 route show dev test1')
7226 output = check_output('ip -6 route show dev test1')
7227 print(output)
7228 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires')
7229
7230 print('### ip -6 route show dev dummy98')
7231 output = check_output('ip -6 route show dev dummy98')
7232 print(output)
07b7337a 7233 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires')
caad88a2
YW
7234
7235 print('### ip -6 route show dev dummy99')
7236 output = check_output('ip -6 route show dev dummy99')
7237 print(output)
07b7337a 7238 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires')
6016f1cf
YW
7239
7240 print('### ip -6 route show dev veth97')
7241 output = check_output('ip -6 route show dev veth97')
7242 print(output)
7243 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]08::/64 proto kernel metric [0-9]* expires')
7244
7245 print('### ip -6 route show dev veth97-peer')
7246 output = check_output('ip -6 route show dev veth97-peer')
7247 print(output)
7248 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]08::/64 proto ra metric [0-9]* expires')
caad88a2
YW
7249
7250 print('### ip -6 route show dev veth98')
7251 output = check_output('ip -6 route show dev veth98')
7252 print(output)
7253 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]09::/64 proto kernel metric [0-9]* expires')
7254
7255 print('### ip -6 route show dev veth98-peer')
7256 output = check_output('ip -6 route show dev veth98-peer')
7257 print(output)
7258 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]09::/64 proto ra metric [0-9]* expires')
7259
7260 # Test case for a downstream which appears later
7261 check_output('ip link add dummy97 type dummy')
95e1fbba 7262 self.wait_online('dummy97:routable')
caad88a2
YW
7263
7264 print('### ip -6 address show dev dummy97 scope global')
7265 output = check_output('ip -6 address show dev dummy97 scope global')
7266 print(output)
7267 # address in IA_PD (Token=static)
6016f1cf 7268 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
caad88a2 7269 # address in IA_PD (temporary)
6016f1cf 7270 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
7271
7272 print('### ip -6 route show dev dummy97')
7273 output = check_output('ip -6 route show dev dummy97')
7274 print(output)
6016f1cf 7275 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]01::/64 proto kernel metric [0-9]* expires')
caad88a2
YW
7276
7277 # Test case for reconfigure
a962d857 7278 networkctl_reconfigure('dummy98', 'dummy99')
95e1fbba 7279 self.wait_online('dummy98:routable', 'dummy99:degraded')
caad88a2
YW
7280
7281 print('### ip -6 address show dev dummy98 scope global')
7282 output = check_output('ip -6 address show dev dummy98 scope global')
7283 print(output)
7284 # address in IA_PD (Token=static)
07b7337a 7285 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
caad88a2 7286 # address in IA_PD (temporary)
07b7337a 7287 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
7288
7289 print('### ip -6 address show dev dummy99 scope global')
7290 output = check_output('ip -6 address show dev dummy99 scope global')
7291 print(output)
7292 # Assign=no
07b7337a 7293 self.assertNotRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]02')
caad88a2
YW
7294
7295 print('### ip -6 route show dev dummy98')
7296 output = check_output('ip -6 route show dev dummy98')
7297 print(output)
07b7337a 7298 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires')
6016f1cf
YW
7299
7300 print('### ip -6 route show dev dummy99')
7301 output = check_output('ip -6 route show dev dummy99')
7302 print(output)
07b7337a 7303 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires')
caad88a2 7304
a4640bed
TM
7305 self.check_netlabel('dummy98', '3ffe:501:ffff:[2-9a-f]00::/64')
7306
c742d7e8
TM
7307 self.check_nftset('addr6', '3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d')
7308 self.check_nftset('addr6', '3ffe:501:ffff:[2-9a-f]00:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*')
7309 self.check_nftset('network6', '3ffe:501:ffff:[2-9a-f]00::/64')
7310 self.check_nftset('ifindex', 'dummy98')
7311
7312 self.teardown_nftset('addr6', 'network6', 'ifindex')
7313
6a936c9c 7314 def verify_dhcp4_6rd(self, tunnel_name):
84cc85f9
YW
7315 print('### ip -4 address show dev veth-peer scope global')
7316 output = check_output('ip -4 address show dev veth-peer scope global')
7317 print(output)
7318 self.assertIn('inet 10.0.0.1/8 brd 10.255.255.255 scope global veth-peer', output)
7319
f7805a6c
FS
7320 # Link Subnet IDs
7321 # test1: 0x00
7322 # dummy97: 0x01 (The link will appear later)
07b7337a
YW
7323 # dummy98: 0x00
7324 # dummy99: auto -> 0x0[23] (No address assignment)
7325 # 6rd-XXX: auto -> 0x0[23]
f7805a6c
FS
7326 # veth97: 0x08
7327 # veth98: 0x09
7328 # veth99: 0x10
84cc85f9
YW
7329
7330 print('### ip -4 address show dev veth99 scope global')
7331 output = check_output('ip -4 address show dev veth99 scope global')
7332 print(output)
7333 self.assertRegex(output, 'inet 10.100.100.[0-9]*/8 (metric 1024 |)brd 10.255.255.255 scope global dynamic veth99')
7334
7335 print('### ip -6 address show dev veth99 scope global')
7336 output = check_output('ip -6 address show dev veth99 scope global')
7337 print(output)
7338 # address in IA_PD (Token=static)
7339 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
7340 # address in IA_PD (Token=eui64)
7341 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic mngtmpaddr')
7342 # address in IA_PD (temporary)
7343 # Note that the temporary addresses may appear after the link enters configured state
7344 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')
7345
7346 print('### ip -6 address show dev test1 scope global')
7347 output = check_output('ip -6 address show dev test1 scope global')
7348 print(output)
7349 # address in IA_PD (Token=static)
7350 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
7351 # address in IA_PD (temporary)
7352 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')
7353
7354 print('### ip -6 address show dev dummy98 scope global')
7355 output = check_output('ip -6 address show dev dummy98 scope global')
7356 print(output)
7357 # address in IA_PD (Token=static)
07b7337a 7358 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
84cc85f9 7359 # address in IA_PD (temporary)
07b7337a 7360 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
7361
7362 print('### ip -6 address show dev dummy99 scope global')
7363 output = check_output('ip -6 address show dev dummy99 scope global')
7364 print(output)
7365 # Assign=no
07b7337a 7366 self.assertNotRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+0[23]')
84cc85f9
YW
7367
7368 print('### ip -6 address show dev veth97 scope global')
7369 output = check_output('ip -6 address show dev veth97 scope global')
7370 print(output)
7371 # address in IA_PD (Token=static)
7372 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
7373 # address in IA_PD (Token=eui64)
7374 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr')
7375 # address in IA_PD (temporary)
7376 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')
7377
7378 print('### ip -6 address show dev veth97-peer scope global')
7379 output = check_output('ip -6 address show dev veth97-peer scope global')
7380 print(output)
7381 # NDisc address (Token=static)
7382 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
7383 # NDisc address (Token=eui64)
7384 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr')
7385 # NDisc address (temporary)
7386 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')
7387
7388 print('### ip -6 address show dev veth98 scope global')
7389 output = check_output('ip -6 address show dev veth98 scope global')
7390 print(output)
7391 # address in IA_PD (Token=static)
7392 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
7393 # address in IA_PD (Token=eui64)
7394 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr')
7395 # address in IA_PD (temporary)
7396 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')
7397
7398 print('### ip -6 address show dev veth98-peer scope global')
7399 output = check_output('ip -6 address show dev veth98-peer scope global')
7400 print(output)
7401 # NDisc address (Token=static)
7402 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
7403 # NDisc address (Token=eui64)
7404 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr')
7405 # NDisc address (temporary)
7406 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')
7407
7408 print('### ip -6 route show type unreachable')
7409 output = check_output('ip -6 route show type unreachable')
7410 print(output)
7411 self.assertRegex(output, 'unreachable 2001:db8:6464:[0-9a-f]+00::/56 dev lo proto dhcp')
7412
7413 print('### ip -6 route show dev veth99')
7414 output = check_output('ip -6 route show dev veth99')
7415 print(output)
7416 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+10::/64 proto kernel metric [0-9]* expires')
7417
7418 print('### ip -6 route show dev test1')
7419 output = check_output('ip -6 route show dev test1')
7420 print(output)
7421 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires')
7422
7423 print('### ip -6 route show dev dummy98')
7424 output = check_output('ip -6 route show dev dummy98')
7425 print(output)
07b7337a 7426 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires')
84cc85f9
YW
7427
7428 print('### ip -6 route show dev dummy99')
7429 output = check_output('ip -6 route show dev dummy99')
7430 print(output)
07b7337a 7431 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto dhcp metric [0-9]* expires')
84cc85f9
YW
7432
7433 print('### ip -6 route show dev veth97')
7434 output = check_output('ip -6 route show dev veth97')
7435 print(output)
7436 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+08::/64 proto kernel metric [0-9]* expires')
7437
7438 print('### ip -6 route show dev veth97-peer')
7439 output = check_output('ip -6 route show dev veth97-peer')
7440 print(output)
7441 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+08::/64 proto ra metric [0-9]* expires')
7442
7443 print('### ip -6 route show dev veth98')
7444 output = check_output('ip -6 route show dev veth98')
7445 print(output)
7446 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+09::/64 proto kernel metric [0-9]* expires')
7447
7448 print('### ip -6 route show dev veth98-peer')
7449 output = check_output('ip -6 route show dev veth98-peer')
7450 print(output)
7451 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+09::/64 proto ra metric [0-9]* expires')
7452
84cc85f9
YW
7453 print('### ip -6 address show dev dummy97 scope global')
7454 output = check_output('ip -6 address show dev dummy97 scope global')
7455 print(output)
7456 # address in IA_PD (Token=static)
7457 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
7458 # address in IA_PD (temporary)
7459 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')
7460
7461 print('### ip -6 route show dev dummy97')
7462 output = check_output('ip -6 route show dev dummy97')
7463 print(output)
7464 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+01::/64 proto kernel metric [0-9]* expires')
7465
e4295d4d
FS
7466 print(f'### ip -d link show dev {tunnel_name}')
7467 output = check_output(f'ip -d link show dev {tunnel_name}')
84cc85f9
YW
7468 print(output)
7469 self.assertIn('link/sit 10.100.100.', output)
7470 self.assertIn('local 10.100.100.', output)
84cc85f9
YW
7471 self.assertIn('ttl 64', output)
7472 self.assertIn('6rd-prefix 2001:db8::/32', output)
7473 self.assertIn('6rd-relay_prefix 10.0.0.0/8', output)
7474
e4295d4d
FS
7475 print(f'### ip -6 address show dev {tunnel_name}')
7476 output = check_output(f'ip -6 address show dev {tunnel_name}')
84cc85f9 7477 print(output)
07b7337a 7478 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
7479 self.assertRegex(output, 'inet6 ::10.100.100.[0-9]+/96 scope global')
7480
e4295d4d
FS
7481 print(f'### ip -6 route show dev {tunnel_name}')
7482 output = check_output(f'ip -6 route show dev {tunnel_name}')
84cc85f9 7483 print(output)
07b7337a 7484 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto kernel metric [0-9]* expires')
84cc85f9
YW
7485 self.assertRegex(output, '::/96 proto kernel metric [0-9]*')
7486
7487 print('### ip -6 route show default')
7488 output = check_output('ip -6 route show default')
7489 print(output)
7490 self.assertIn('default', output)
e4295d4d 7491 self.assertIn(f'via ::10.0.0.1 dev {tunnel_name}', output)
84cc85f9 7492
6a936c9c 7493 def test_dhcp4_6rd(self):
e081ffc1
YW
7494 def get_dhcp_6rd_prefix(link):
7495 description = get_link_description(link)
8fb6320e 7496
7497 self.assertIn('DHCPv4Client', description.keys())
7498 self.assertIn('6rdPrefix', description['DHCPv4Client'].keys())
7499
7500 prefixInfo = description['DHCPv4Client']['6rdPrefix']
7501 self.assertIn('Prefix', prefixInfo.keys())
7502 self.assertIn('PrefixLength', prefixInfo.keys())
7503 self.assertIn('IPv4MaskLength', prefixInfo.keys())
7504 self.assertIn('BorderRouters', prefixInfo.keys())
7505
7506 return prefixInfo
7507
a962d857
YW
7508 copy_network_unit('25-veth.netdev', '25-dhcp4-6rd-server.network', '25-dhcp4-6rd-upstream.network',
7509 '25-veth-downstream-veth97.netdev', '25-dhcp-pd-downstream-veth97.network', '25-dhcp-pd-downstream-veth97-peer.network',
7510 '25-veth-downstream-veth98.netdev', '25-dhcp-pd-downstream-veth98.network', '25-dhcp-pd-downstream-veth98-peer.network',
7511 '11-dummy.netdev', '25-dhcp-pd-downstream-test1.network',
7512 '25-dhcp-pd-downstream-dummy97.network',
7513 '12-dummy.netdev', '25-dhcp-pd-downstream-dummy98.network',
7514 '13-dummy.netdev', '25-dhcp-pd-downstream-dummy99.network',
7515 '80-6rd-tunnel.network')
6a936c9c
YW
7516
7517 start_networkd()
95e1fbba 7518 self.wait_online('veth-peer:routable')
f7805a6c
FS
7519
7520 # ipv4masklen: 8
7521 # 6rd-prefix: 2001:db8::/32
7522 # br-addresss: 10.0.0.1
7523
a962d857
YW
7524 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',
7525 ipv4_range='10.100.100.100,10.100.100.200',
7526 ipv4_router='10.0.0.1')
95e1fbba
YW
7527 self.wait_online('veth99:routable', 'test1:routable', 'dummy98:routable', 'dummy99:degraded',
7528 'veth97:routable', 'veth97-peer:routable', 'veth98:routable', 'veth98-peer:routable')
6a936c9c 7529
8fb6320e 7530 # Check the DBus interface for assigned prefix information
e081ffc1 7531 prefixInfo = get_dhcp_6rd_prefix('veth99')
8fb6320e 7532
7533 self.assertEqual(prefixInfo['Prefix'], [32,1,13,184,0,0,0,0,0,0,0,0,0,0,0,0]) # 2001:db8::
7534 self.assertEqual(prefixInfo['PrefixLength'], 32)
7535 self.assertEqual(prefixInfo['IPv4MaskLength'], 8)
7536 self.assertEqual(prefixInfo['BorderRouters'], [[10,0,0,1]])
7537
6a936c9c
YW
7538 # Test case for a downstream which appears later
7539 check_output('ip link add dummy97 type dummy')
95e1fbba 7540 self.wait_online('dummy97:routable')
6a936c9c
YW
7541
7542 # Find tunnel name
7543 tunnel_name = None
7544 for name in os.listdir('/sys/class/net/'):
7545 if name.startswith('6rd-'):
7546 tunnel_name = name
7547 break
7548
95e1fbba 7549 self.wait_online(f'{tunnel_name}:routable')
6a936c9c
YW
7550
7551 self.verify_dhcp4_6rd(tunnel_name)
7552
7553 # Test case for reconfigure
a962d857 7554 networkctl_reconfigure('dummy98', 'dummy99')
95e1fbba 7555 self.wait_online('dummy98:routable', 'dummy99:degraded')
6a936c9c
YW
7556
7557 self.verify_dhcp4_6rd(tunnel_name)
7558
3af934bc 7559 print('Wait for the DHCP lease to be renewed/rebind')
a102a52c 7560 time.sleep(120)
6a936c9c 7561
95e1fbba
YW
7562 self.wait_online('veth99:routable', 'test1:routable', 'dummy97:routable', 'dummy98:routable', 'dummy99:degraded',
7563 'veth97:routable', 'veth97-peer:routable', 'veth98:routable', 'veth98-peer:routable')
6a936c9c
YW
7564
7565 self.verify_dhcp4_6rd(tunnel_name)
7566
9633f977 7567class NetworkdIPv6PrefixTests(unittest.TestCase, Utilities):
9633f977
SS
7568
7569 def setUp(self):
a962d857 7570 setup_common()
9633f977
SS
7571
7572 def tearDown(self):
a962d857 7573 tear_down_common()
9633f977
SS
7574
7575 def test_ipv6_route_prefix(self):
a962d857
YW
7576 copy_network_unit('25-veth.netdev', '25-ipv6ra-prefix-client.network', '25-ipv6ra-prefix.network',
7577 '12-dummy.netdev', '25-ipv6ra-uplink.network')
9633f977
SS
7578
7579 start_networkd()
95e1fbba 7580 self.wait_online('veth99:routable', 'veth-peer:routable', 'dummy98:routable')
9633f977 7581
635f2a66
YW
7582 output = check_output('ip address show dev veth-peer')
7583 print(output)
7584 self.assertIn('inet6 2001:db8:0:1:', output)
7585 self.assertNotIn('inet6 2001:db8:0:2:', output)
ab47f960 7586 self.assertNotIn('inet6 2001:db8:0:3:', output)
635f2a66 7587
3c874fd7 7588 output = check_output('ip -6 route show dev veth-peer')
9633f977 7589 print(output)
635f2a66
YW
7590 self.assertIn('2001:db8:0:1::/64 proto ra', output)
7591 self.assertNotIn('2001:db8:0:2::/64 proto ra', output)
ab47f960 7592 self.assertNotIn('2001:db8:0:3::/64 proto ra', output)
635f2a66
YW
7593 self.assertIn('2001:db0:fff::/64 via ', output)
7594 self.assertNotIn('2001:db1:fff::/64 via ', output)
ab47f960 7595 self.assertNotIn('2001:db2:fff::/64 via ', output)
9633f977 7596
635f2a66
YW
7597 output = check_output('ip address show dev veth99')
7598 print(output)
7599 self.assertNotIn('inet6 2001:db8:0:1:', output)
fe2a8b3d
YW
7600 self.assertIn('inet6 2001:db8:0:2:1a:2b:3c:4d', output)
7601 self.assertIn('inet6 2001:db8:0:2:fa:de:ca:fe', output)
ab47f960 7602 self.assertNotIn('inet6 2001:db8:0:3:', output)
635f2a66 7603
10d670a3 7604 output = resolvectl('dns', 'veth-peer')
4a906586
YW
7605 print(output)
7606 self.assertRegex(output, '2001:db8:1:1::2')
7607
10d670a3 7608 output = resolvectl('domain', 'veth-peer')
4a906586
YW
7609 print(output)
7610 self.assertIn('example.com', output)
7611
10d670a3 7612 check_json(networkctl_json())
94f0bd62 7613
10d670a3 7614 output = networkctl_json('veth-peer')
681007ac
SS
7615 check_json(output)
7616
7617 # PREF64 or NAT64
7618 pref64 = json.loads(output)['NDisc']['PREF64'][0]
7619
7620 prefix = socket.inet_ntop(socket.AF_INET6, bytearray(pref64['Prefix']))
7621 self.assertEqual(prefix, '64:ff9b::')
7622
7623 prefix_length = pref64['PrefixLength']
7624 self.assertEqual(prefix_length, 96)
7625
635f2a66 7626 def test_ipv6_route_prefix_deny_list(self):
a962d857
YW
7627 copy_network_unit('25-veth.netdev', '25-ipv6ra-prefix-client-deny-list.network', '25-ipv6ra-prefix.network',
7628 '12-dummy.netdev', '25-ipv6ra-uplink.network')
635f2a66
YW
7629
7630 start_networkd()
95e1fbba 7631 self.wait_online('veth99:routable', 'veth-peer:routable', 'dummy98:routable')
635f2a66
YW
7632
7633 output = check_output('ip address show dev veth-peer')
7634 print(output)
7635 self.assertIn('inet6 2001:db8:0:1:', output)
7636 self.assertNotIn('inet6 2001:db8:0:2:', output)
7637
7638 output = check_output('ip -6 route show dev veth-peer')
7639 print(output)
7640 self.assertIn('2001:db8:0:1::/64 proto ra', output)
7641 self.assertNotIn('2001:db8:0:2::/64 proto ra', output)
7642 self.assertIn('2001:db0:fff::/64 via ', output)
7643 self.assertNotIn('2001:db1:fff::/64 via ', output)
7644
7645 output = check_output('ip address show dev veth99')
3c874fd7 7646 print(output)
635f2a66
YW
7647 self.assertNotIn('inet6 2001:db8:0:1:', output)
7648 self.assertIn('inet6 2001:db8:0:2:', output)
3c874fd7 7649
10d670a3 7650 output = resolvectl('dns', 'veth-peer')
4a906586
YW
7651 print(output)
7652 self.assertRegex(output, '2001:db8:1:1::2')
7653
10d670a3 7654 output = resolvectl('domain', 'veth-peer')
4a906586
YW
7655 print(output)
7656 self.assertIn('example.com', output)
7657
7db05447 7658class NetworkdMTUTests(unittest.TestCase, Utilities):
7db05447
DS
7659
7660 def setUp(self):
a962d857 7661 setup_common()
7db05447
DS
7662
7663 def tearDown(self):
a962d857 7664 tear_down_common()
7db05447
DS
7665
7666 def check_mtu(self, mtu, ipv6_mtu=None, reset=True):
7667 if not ipv6_mtu:
7668 ipv6_mtu = mtu
7669
7670 # test normal start
7671 start_networkd()
95e1fbba 7672 self.wait_online('dummy98:routable')
a962d857
YW
7673 self.check_link_attr('dummy98', 'mtu', mtu)
7674 self.check_ipv6_sysctl_attr('dummy98', 'mtu', ipv6_mtu)
7db05447
DS
7675
7676 # test normal restart
7677 restart_networkd()
95e1fbba 7678 self.wait_online('dummy98:routable')
a962d857
YW
7679 self.check_link_attr('dummy98', 'mtu', mtu)
7680 self.check_ipv6_sysctl_attr('dummy98', 'mtu', ipv6_mtu)
7db05447
DS
7681
7682 if reset:
7683 self.reset_check_mtu(mtu, ipv6_mtu)
7684
7685 def reset_check_mtu(self, mtu, ipv6_mtu=None):
7686 ''' test setting mtu/ipv6_mtu with interface already up '''
7687 stop_networkd()
7688
7689 # note - changing the device mtu resets the ipv6 mtu
a962d857
YW
7690 check_output('ip link set up mtu 1501 dev dummy98')
7691 check_output('ip link set up mtu 1500 dev dummy98')
7692 self.check_link_attr('dummy98', 'mtu', '1500')
7693 self.check_ipv6_sysctl_attr('dummy98', 'mtu', '1500')
7db05447
DS
7694
7695 self.check_mtu(mtu, ipv6_mtu, reset=False)
7696
7697 def test_mtu_network(self):
a962d857 7698 copy_network_unit('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
7db05447
DS
7699 self.check_mtu('1600')
7700
7701 def test_mtu_netdev(self):
a962d857 7702 copy_network_unit('12-dummy-mtu.netdev', '12-dummy.network', copy_dropins=False)
7db05447
DS
7703 # note - MTU set by .netdev happens ONLY at device creation!
7704 self.check_mtu('1600', reset=False)
7705
7706 def test_mtu_link(self):
a962d857 7707 copy_network_unit('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', copy_dropins=False)
7db05447
DS
7708 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
7709 self.check_mtu('1600', reset=False)
7710
7711 def test_ipv6_mtu(self):
7712 ''' set ipv6 mtu without setting device mtu '''
a962d857 7713 copy_network_unit('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
7db05447
DS
7714 self.check_mtu('1500', '1400')
7715
7716 def test_ipv6_mtu_toolarge(self):
7717 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
a962d857 7718 copy_network_unit('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
7db05447
DS
7719 self.check_mtu('1500', '1500')
7720
7721 def test_mtu_network_ipv6_mtu(self):
7722 ''' set ipv6 mtu and set device mtu via network file '''
a962d857 7723 copy_network_unit('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
7db05447
DS
7724 self.check_mtu('1600', '1550')
7725
7726 def test_mtu_netdev_ipv6_mtu(self):
7727 ''' set ipv6 mtu and set device mtu via netdev file '''
a962d857 7728 copy_network_unit('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
7db05447
DS
7729 self.check_mtu('1600', '1550', reset=False)
7730
7731 def test_mtu_link_ipv6_mtu(self):
7732 ''' set ipv6 mtu and set device mtu via link file '''
a962d857 7733 copy_network_unit('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
7db05447
DS
7734 self.check_mtu('1600', '1550', reset=False)
7735
7736
1f0e3109 7737if __name__ == '__main__':
9c1ae484
YW
7738 parser = argparse.ArgumentParser()
7739 parser.add_argument('--build-dir', help='Path to build dir', dest='build_dir')
33b0e0c0 7740 parser.add_argument('--source-dir', help='Path to source dir/git tree', dest='source_dir')
9c1ae484
YW
7741 parser.add_argument('--valgrind', help='Enable valgrind', dest='use_valgrind', type=bool, nargs='?', const=True, default=use_valgrind)
7742 parser.add_argument('--debug', help='Generate debugging logs', dest='enable_debug', type=bool, nargs='?', const=True, default=enable_debug)
94c03122 7743 parser.add_argument('--asan-options', help='ASAN options', dest='asan_options')
fa4c6095 7744 parser.add_argument('--lsan-options', help='LSAN options', dest='lsan_options')
94c03122 7745 parser.add_argument('--ubsan-options', help='UBSAN options', dest='ubsan_options')
6c9efba6 7746 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 7747 ns, unknown_args = parser.parse_known_args(namespace=unittest)
9c1ae484
YW
7748
7749 if ns.build_dir:
9c1ae484 7750 networkd_bin = os.path.join(ns.build_dir, 'systemd-networkd')
b6d587d1 7751 resolved_bin = os.path.join(ns.build_dir, 'systemd-resolved')
b05c4d6b 7752 timesyncd_bin = os.path.join(ns.build_dir, 'systemd-timesyncd')
9c1ae484
YW
7753 wait_online_bin = os.path.join(ns.build_dir, 'systemd-networkd-wait-online')
7754 networkctl_bin = os.path.join(ns.build_dir, 'networkctl')
b6d587d1
YW
7755 resolvectl_bin = os.path.join(ns.build_dir, 'resolvectl')
7756 timedatectl_bin = os.path.join(ns.build_dir, 'timedatectl')
b05c4d6b 7757 udevadm_bin = os.path.join(ns.build_dir, 'udevadm')
f66045c7 7758 build_dir = ns.build_dir
9c1ae484 7759
33b0e0c0 7760 if ns.source_dir:
f66045c7 7761 source_dir = ns.source_dir
f2adc1de
DDM
7762 assert os.path.exists(os.path.join(source_dir, "meson_options.txt")), f"{source_dir} doesn't appear to be a systemd source tree."
7763 elif os.path.exists(os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../meson_options.txt"))):
f66045c7 7764 source_dir = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../"))
f2adc1de
DDM
7765 else:
7766 source_dir = None
33b0e0c0 7767
9c1ae484
YW
7768 use_valgrind = ns.use_valgrind
7769 enable_debug = ns.enable_debug
94c03122 7770 asan_options = ns.asan_options
fa4c6095 7771 lsan_options = ns.lsan_options
94c03122 7772 ubsan_options = ns.ubsan_options
6c9efba6 7773 with_coverage = ns.with_coverage
9c1ae484
YW
7774
7775 if use_valgrind:
b05c4d6b
YW
7776 # Do not forget the trailing space.
7777 valgrind_cmd = 'valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all '
7778
7779 networkctl_cmd = valgrind_cmd.split() + [networkctl_bin]
7780 resolvectl_cmd = valgrind_cmd.split() + [resolvectl_bin]
7781 timedatectl_cmd = valgrind_cmd.split() + [timedatectl_bin]
7782 udevadm_cmd = valgrind_cmd.split() + [udevadm_bin]
7783 wait_online_cmd = valgrind_cmd.split() + [wait_online_bin]
9c1ae484 7784
9dcdf16b
YW
7785 if build_dir:
7786 test_ndisc_send = os.path.normpath(os.path.join(build_dir, 'test-ndisc-send'))
7787 else:
7788 test_ndisc_send = '/usr/lib/tests/test-ndisc-send'
7789
94c03122 7790 if asan_options:
a962d857 7791 env.update({'ASAN_OPTIONS': asan_options})
fa4c6095 7792 if lsan_options:
a962d857 7793 env.update({'LSAN_OPTIONS': lsan_options})
94c03122 7794 if ubsan_options:
a962d857 7795 env.update({'UBSAN_OPTIONS': ubsan_options})
b05c4d6b
YW
7796 if use_valgrind:
7797 env.update({'SYSTEMD_MEMPOOL': '0'})
9c1ae484 7798
163d095f
YW
7799 wait_online_env = env.copy()
7800 if enable_debug:
a962d857 7801 wait_online_env.update({'SYSTEMD_LOG_LEVEL': 'debug'})
163d095f 7802
a561bcee 7803 sys.argv[1:] = unknown_args
0765763e 7804 unittest.main(verbosity=3)