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