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