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