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