]> git.ipfire.org Git - thirdparty/systemd.git/blame - test/test-network/systemd-networkd-tests.py
test-network: add test for macvlan BroadcastQueueMulticastLength= and BroadcastQueueT...
[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
cff83db9
YW
2462class NetworkdL2TPTests(unittest.TestCase, Utilities):
2463
cff83db9 2464 def setUp(self):
a962d857 2465 setup_common()
cff83db9
YW
2466
2467 def tearDown(self):
a962d857 2468 tear_down_common()
cff83db9 2469
59edcf2b 2470 @expectedFailureIfModuleIsNotAvailable('l2tp_eth', 'l2tp_netlink')
cff83db9 2471 def test_l2tp_udp(self):
a962d857
YW
2472 copy_network_unit('11-dummy.netdev', '25-l2tp-dummy.network',
2473 '25-l2tp-udp.netdev', '25-l2tp.network')
2cf6fdff 2474 start_networkd()
cff83db9 2475
95e1fbba 2476 self.wait_online('test1:routable', 'l2tp-ses1:degraded', 'l2tp-ses2:degraded')
cff83db9 2477
371810d1 2478 output = check_output('ip l2tp show tunnel tunnel_id 10')
cff83db9
YW
2479 print(output)
2480 self.assertRegex(output, "Tunnel 10, encap UDP")
2481 self.assertRegex(output, "From 192.168.30.100 to 192.168.30.101")
2482 self.assertRegex(output, "Peer tunnel 11")
2483 self.assertRegex(output, "UDP source / dest ports: 3000/4000")
2484 self.assertRegex(output, "UDP checksum: enabled")
2485
371810d1 2486 output = check_output('ip l2tp show session tid 10 session_id 15')
cff83db9
YW
2487 print(output)
2488 self.assertRegex(output, "Session 15 in tunnel 10")
2489 self.assertRegex(output, "Peer session 16, tunnel 11")
2490 self.assertRegex(output, "interface name: l2tp-ses1")
2491
371810d1 2492 output = check_output('ip l2tp show session tid 10 session_id 17')
cff83db9
YW
2493 print(output)
2494 self.assertRegex(output, "Session 17 in tunnel 10")
2495 self.assertRegex(output, "Peer session 18, tunnel 11")
2496 self.assertRegex(output, "interface name: l2tp-ses2")
2497
59edcf2b 2498 @expectedFailureIfModuleIsNotAvailable('l2tp_eth', 'l2tp_ip', 'l2tp_netlink')
cff83db9 2499 def test_l2tp_ip(self):
a962d857
YW
2500 copy_network_unit('11-dummy.netdev', '25-l2tp-dummy.network',
2501 '25-l2tp-ip.netdev', '25-l2tp.network')
2cf6fdff 2502 start_networkd()
cff83db9 2503
95e1fbba 2504 self.wait_online('test1:routable', 'l2tp-ses3:degraded', 'l2tp-ses4:degraded')
cff83db9 2505
371810d1 2506 output = check_output('ip l2tp show tunnel tunnel_id 10')
cff83db9
YW
2507 print(output)
2508 self.assertRegex(output, "Tunnel 10, encap IP")
2509 self.assertRegex(output, "From 192.168.30.100 to 192.168.30.101")
2510 self.assertRegex(output, "Peer tunnel 12")
2511
371810d1 2512 output = check_output('ip l2tp show session tid 10 session_id 25')
cff83db9
YW
2513 print(output)
2514 self.assertRegex(output, "Session 25 in tunnel 10")
2515 self.assertRegex(output, "Peer session 26, tunnel 12")
2516 self.assertRegex(output, "interface name: l2tp-ses3")
2517
371810d1 2518 output = check_output('ip l2tp show session tid 10 session_id 27')
cff83db9
YW
2519 print(output)
2520 self.assertRegex(output, "Session 27 in tunnel 10")
2521 self.assertRegex(output, "Peer session 28, tunnel 12")
2522 self.assertRegex(output, "interface name: l2tp-ses4")
2523
be68c2c9 2524class NetworkdNetworkTests(unittest.TestCase, Utilities):
95c74b0a 2525
1f0e3109 2526 def setUp(self):
a962d857 2527 setup_common()
1f0e3109
SS
2528
2529 def tearDown(self):
a962d857 2530 tear_down_common()
1f0e3109 2531
f2bcd324
YW
2532 def verify_address_static(
2533 self,
2534 label1: str,
2535 label2: str,
2536 label3: str,
2537 broadcast1: str,
2538 broadcast2: str,
2539 broadcast3: str,
2540 peer1: str,
2541 peer2: str,
2542 peer3: str,
2543 peer4: str,
2544 peer5: str,
2545 peer6: str,
2546 scope1: str,
2547 scope2: str,
2548 deprecated1: str,
2549 deprecated2: str,
2550 deprecated3: str,
2551 deprecated4: str,
2552 route_metric: int,
2553 flag1: str,
2554 flag2: str,
2555 flag3: str,
2556 flag4: str,
d5adff70
YW
2557 ip4_null_16: str,
2558 ip4_null_24: str,
2559 ip6_null_73: str,
2560 ip6_null_74: str,
f2bcd324
YW
2561 ):
2562 output = check_output('ip address show dev dummy98')
2563 print(output)
2564
2565 # simple settings
4a704501
YW
2566 self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output)
2567 self.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output)
2568 self.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output)
4a704501
YW
2569 self.assertIn('inet6 2001:db8:0:f101::15/64 scope global', output)
2570 self.assertIn('inet6 2001:db8:0:f101::16/64 scope global', output)
2571 self.assertIn('inet6 2001:db8:0:f102::15/64 scope global', output)
f2bcd324
YW
2572
2573 # label
2574 self.assertIn(f'inet 10.3.1.1/24 brd 10.3.1.255 scope global {label1}', output)
2575 self.assertIn(f'inet 10.3.2.1/24 brd 10.3.2.255 scope global {label2}', output)
2576 self.assertIn(f'inet 10.3.3.1/24 brd 10.3.3.255 scope global {label3}', output)
2577
2578 # broadcast
2579 self.assertIn(f'inet 10.4.1.1/24{broadcast1} scope global dummy98', output)
2580 self.assertIn(f'inet 10.4.2.1/24{broadcast2} scope global dummy98', output)
2581 self.assertIn(f'inet 10.4.3.1/24{broadcast3} scope global dummy98', output)
2582
2583 # peer
2584 self.assertIn(f'inet 10.5.1.1{peer1} scope global dummy98', output)
2585 self.assertIn(f'inet 10.5.2.1{peer2} scope global dummy98', output)
2586 self.assertIn(f'inet 10.5.3.1{peer3} scope global dummy98', output)
2587 self.assertIn(f'inet6 2001:db8:0:f103::1{peer4} scope global', output)
2588 self.assertIn(f'inet6 2001:db8:0:f103::2{peer5} scope global', output)
2589 self.assertIn(f'inet6 2001:db8:0:f103::3{peer6} scope global', output)
2590
2591 # scope
2592 self.assertIn(f'inet 10.6.1.1/24 brd 10.6.1.255 scope {scope1} dummy98', output)
2593 self.assertIn(f'inet 10.6.2.1/24 brd 10.6.2.255 scope {scope2} dummy98', output)
2594
2595 # lifetime
2596 self.assertIn(f'inet 10.7.1.1/24 brd 10.7.1.255 scope global{deprecated1} dummy98', output)
2597 self.assertIn(f'inet 10.7.2.1/24 brd 10.7.2.255 scope global{deprecated2} dummy98', output)
2598 self.assertIn(f'inet6 2001:db8:0:f104::1/64 scope global{deprecated3}', output)
2599 self.assertIn(f'inet6 2001:db8:0:f104::2/64 scope global{deprecated4}', output)
2600
2601 # route metric
2602 self.assertRegex(output, rf'inet 10.8.1.1/24 (metric {route_metric} |)brd 10.8.1.255 scope global dummy98')
2603 self.assertRegex(output, rf'inet6 2001:db8:0:f105::1/64 (metric {route_metric} |)scope global')
2604
2605 output_route = check_output('ip -4 route show dev dummy98 10.8.1.0/24')
2606 print(output_route)
2607 self.assertIn(f'10.8.1.0/24 proto kernel scope link src 10.8.1.1 metric {route_metric}', output_route)
2608
2609 output_route = check_output('ip -6 route show dev dummy98 2001:db8:0:f105::/64')
2610 print(output_route)
2611 self.assertIn(f'2001:db8:0:f105::/64 proto kernel metric {route_metric}', output_route)
2612
2613 # flags
2614 self.assertIn(f'inet 10.9.1.1/24 brd 10.9.1.255 scope global{flag1} dummy98', output)
2615 self.assertIn(f'inet 10.9.2.1/24 brd 10.9.2.255 scope global{flag2} dummy98', output)
2616 self.assertIn(f'inet6 2001:db8:0:f106::1/64 scope global{flag3}', output)
2617 self.assertIn(f'inet6 2001:db8:0:f106::2/64 scope global{flag4}', output)
2618
2619 # null address
d5adff70
YW
2620 self.assertTrue(ip4_null_16.endswith('.0.1'))
2621 prefix16 = ip4_null_16[:-len('.0.1')]
2622 self.assertTrue(ip4_null_24.endswith('.1'))
2623 prefix24 = ip4_null_24[:-len('.1')]
2624 self.assertIn(f'inet {ip4_null_16}/16 brd {prefix16}.255.255 scope global subnet16', output)
2625 self.assertIn(f'inet {ip4_null_24}/24 brd {prefix24}.255 scope global subnet24', output)
2626 self.assertIn(f'inet6 {ip6_null_73}/73 scope global', output)
2627 self.assertIn(f'inet6 {ip6_null_74}/74 scope global', output)
f2bcd324
YW
2628
2629 # invalid sections
2630 self.assertNotIn('10.4.4.1', output)
2631 self.assertNotIn('10.5.4.1', output)
2632 self.assertNotIn('10.5.5.1', output)
2633 self.assertNotIn('10.8.2.1', output)
2634 self.assertNotIn('10.9.3.1', output)
2635 self.assertNotIn('2001:db8:0:f101::2', output)
2636 self.assertNotIn('2001:db8:0:f103::4', output)
b8102725 2637
d19704cd 2638 # netlabel
f2bcd324 2639 self.check_netlabel('dummy98', r'10\.10\.1\.0/24')
a4640bed 2640
10d670a3 2641 check_json(networkctl_json())
d19704cd
YW
2642
2643 def test_address_static(self):
d19704cd 2644 copy_network_unit('25-address-static.network', '12-dummy.netdev', copy_dropins=False)
c742d7e8
TM
2645 self.setup_nftset('addr4', 'ipv4_addr')
2646 self.setup_nftset('network4', 'ipv4_addr', 'flags interval;')
2647 self.setup_nftset('ifindex', 'iface_index')
1ce2ffac 2648 start_networkd()
d19704cd 2649
95e1fbba 2650 self.wait_online('dummy98:routable')
d5adff70
YW
2651
2652 ip4_null_16 = None
2653 ip4_null_24 = None
2654 output = check_output('ip -4 --json address show dev dummy98')
2655 for i in json.loads(output)[0]['addr_info']:
2656 if i['label'] == 'subnet16':
2657 ip4_null_16 = i['local']
2658 elif i['label'] == 'subnet24':
2659 ip4_null_24 = i['local']
2660 self.assertTrue(ip4_null_16.endswith('.0.1'))
2661 self.assertTrue(ip4_null_24.endswith('.1'))
2662
2663 ip6_null_73 = None
2664 ip6_null_74 = None
2665 output = check_output('ip -6 --json address show dev dummy98')
2666 for i in json.loads(output)[0]['addr_info']:
2667 if i['prefixlen'] == 73:
2668 ip6_null_73 = i['local']
2669 elif i['prefixlen'] == 74:
2670 ip6_null_74 = i['local']
2671 self.assertTrue(ip6_null_73.endswith(':1'))
2672 self.assertTrue(ip6_null_74.endswith(':1'))
2673
f2bcd324
YW
2674 self.verify_address_static(
2675 label1='label1',
2676 label2='label2',
2677 label3='dummy98',
2678 broadcast1='',
2679 broadcast2=' brd 10.4.2.255',
2680 broadcast3=' brd 10.4.3.63',
2681 peer1=' peer 10.5.1.101/24',
2682 peer2=' peer 10.5.2.101/24',
2683 peer3='/24 brd 10.5.3.255',
2684 peer4=' peer 2001:db8:0:f103::101/128',
2685 peer5=' peer 2001:db8:0:f103::102/128',
2686 peer6='/128',
2687 scope1='global',
2688 scope2='link',
2689 deprecated1='',
2690 deprecated2=' deprecated',
2691 deprecated3='',
2692 deprecated4=' deprecated',
2693 route_metric=128,
2694 flag1=' noprefixroute',
2695 flag2='',
2696 flag3=' noprefixroute',
2697 flag4=' home mngtmpaddr',
d5adff70
YW
2698 ip4_null_16=ip4_null_16,
2699 ip4_null_24=ip4_null_24,
2700 ip6_null_73=ip6_null_73,
2701 ip6_null_74=ip6_null_74,
f2bcd324 2702 )
c742d7e8 2703 # nft set
f432aa90
TM
2704 self.check_nftset('addr4', r'10\.10\.1\.1')
2705 self.check_nftset('network4', r'10\.10\.1\.0/24')
2706 self.check_nftset('ifindex', 'dummy98')
c742d7e8
TM
2707
2708 self.teardown_nftset('addr4', 'network4', 'ifindex')
f2bcd324
YW
2709
2710 copy_network_unit('25-address-static.network.d/10-override.conf')
d19704cd 2711 networkctl_reload()
95e1fbba 2712 self.wait_online('dummy98:routable')
f2bcd324
YW
2713 self.verify_address_static(
2714 label1='new-label1',
2715 label2='dummy98',
2716 label3='new-label3',
2717 broadcast1=' brd 10.4.1.255',
2718 broadcast2='',
2719 broadcast3=' brd 10.4.3.31',
2720 peer1=' peer 10.5.1.102/24',
2721 peer2='/24 brd 10.5.2.255',
2722 peer3=' peer 10.5.3.102/24',
2723 peer4=' peer 2001:db8:0:f103::201/128',
2724 peer5='/128',
2725 peer6=' peer 2001:db8:0:f103::203/128',
2726 scope1='link',
2727 scope2='global',
2728 deprecated1=' deprecated',
2729 deprecated2='',
2730 deprecated3=' deprecated',
2731 deprecated4='',
2732 route_metric=256,
2733 flag1='',
2734 flag2=' noprefixroute',
2735 flag3=' home mngtmpaddr',
2736 flag4=' noprefixroute',
d5adff70
YW
2737 ip4_null_16=ip4_null_16,
2738 ip4_null_24=ip4_null_24,
2739 ip6_null_73=ip6_null_73,
2740 ip6_null_74=ip6_null_74,
f2bcd324 2741 )
d19704cd
YW
2742
2743 networkctl_reconfigure('dummy98')
95e1fbba 2744 self.wait_online('dummy98:routable')
f2bcd324
YW
2745 self.verify_address_static(
2746 label1='new-label1',
2747 label2='dummy98',
2748 label3='new-label3',
2749 broadcast1=' brd 10.4.1.255',
2750 broadcast2='',
2751 broadcast3=' brd 10.4.3.31',
2752 peer1=' peer 10.5.1.102/24',
2753 peer2='/24 brd 10.5.2.255',
2754 peer3=' peer 10.5.3.102/24',
2755 peer4=' peer 2001:db8:0:f103::201/128',
2756 peer5='/128',
2757 peer6=' peer 2001:db8:0:f103::203/128',
2758 scope1='link',
2759 scope2='global',
2760 deprecated1=' deprecated',
2761 deprecated2='',
2762 deprecated3=' deprecated',
2763 deprecated4='',
2764 route_metric=256,
2765 flag1='',
2766 flag2=' noprefixroute',
2767 flag3=' home mngtmpaddr',
2768 flag4=' noprefixroute',
d5adff70
YW
2769 ip4_null_16=ip4_null_16,
2770 ip4_null_24=ip4_null_24,
2771 ip6_null_73=ip6_null_73,
2772 ip6_null_74=ip6_null_74,
f2bcd324 2773 )
d19704cd 2774
40971657
YW
2775 # Tests for #20891.
2776 # 1. set preferred lifetime forever to drop the deprecated flag for testing #20891.
f2bcd324
YW
2777 check_output('ip address change 10.7.1.1/24 dev dummy98 preferred_lft forever')
2778 check_output('ip address change 2001:db8:0:f104::1/64 dev dummy98 preferred_lft forever')
2779 output = check_output('ip address show dev dummy98')
40971657 2780 print(output)
f2bcd324
YW
2781 self.assertNotRegex(output, '10.7.1.1/24 .* deprecated')
2782 self.assertNotRegex(output, '2001:db8:0:f104::1/64 .* deprecated')
40971657 2783
f2bcd324 2784 # 2. reconfigure the interface, and check the deprecated flag is set again
a962d857 2785 networkctl_reconfigure('dummy98')
95e1fbba 2786 self.wait_online('dummy98:routable')
f2bcd324
YW
2787 self.verify_address_static(
2788 label1='new-label1',
2789 label2='dummy98',
2790 label3='new-label3',
2791 broadcast1=' brd 10.4.1.255',
2792 broadcast2='',
2793 broadcast3=' brd 10.4.3.31',
2794 peer1=' peer 10.5.1.102/24',
2795 peer2='/24 brd 10.5.2.255',
2796 peer3=' peer 10.5.3.102/24',
2797 peer4=' peer 2001:db8:0:f103::201/128',
2798 peer5='/128',
2799 peer6=' peer 2001:db8:0:f103::203/128',
2800 scope1='link',
2801 scope2='global',
2802 deprecated1=' deprecated',
2803 deprecated2='',
2804 deprecated3=' deprecated',
2805 deprecated4='',
2806 route_metric=256,
2807 flag1='',
2808 flag2=' noprefixroute',
2809 flag3=' home mngtmpaddr',
2810 flag4=' noprefixroute',
d5adff70
YW
2811 ip4_null_16=ip4_null_16,
2812 ip4_null_24=ip4_null_24,
2813 ip6_null_73=ip6_null_73,
2814 ip6_null_74=ip6_null_74,
f2bcd324 2815 )
40971657 2816
d19704cd
YW
2817 # test for ENOBUFS issue #17012 (with reload)
2818 copy_network_unit('25-address-static.network.d/10-many-address.conf')
2819 networkctl_reload()
95e1fbba 2820 self.wait_online('dummy98:routable')
766f8f38 2821 output = check_output('ip -4 address show dev dummy98')
a962d857 2822 for i in range(1, 254):
4a704501 2823 self.assertIn(f'inet 10.3.3.{i}/16 brd 10.3.255.255', output)
e4783b54 2824
d19704cd
YW
2825 # (with reconfigure)
2826 networkctl_reconfigure('dummy98')
95e1fbba 2827 self.wait_online('dummy98:routable')
d19704cd
YW
2828 output = check_output('ip -4 address show dev dummy98')
2829 for i in range(1, 254):
2830 self.assertIn(f'inet 10.3.3.{i}/16 brd 10.3.255.255', output)
3a2ef59d
YW
2831
2832 # test for an empty string assignment for Address= in [Network]
2833 copy_network_unit('25-address-static.network.d/20-clear-addresses.conf')
2834 networkctl_reload()
95e1fbba 2835 self.wait_online('dummy98:routable')
3a2ef59d
YW
2836 output = check_output('ip -4 address show dev dummy98')
2837 for i in range(1, 254):
2838 self.assertNotIn(f'inet 10.3.3.{i}/16 brd 10.3.255.255', output)
2839 self.assertIn('inet 10.4.0.1/16 brd 10.4.255.255', output)
146726b2 2840
44924431
YW
2841 def test_address_ipv4acd(self):
2842 check_output('ip netns add ns99')
2843 check_output('ip link add veth99 type veth peer veth-peer')
2844 check_output('ip link set veth-peer netns ns99')
2845 check_output('ip link set veth99 up')
2846 check_output('ip netns exec ns99 ip link set veth-peer up')
2847 check_output('ip netns exec ns99 ip address add 192.168.100.10/24 dev veth-peer')
2848
a962d857 2849 copy_network_unit('25-address-ipv4acd-veth99.network', copy_dropins=False)
dc7d3c5f 2850 start_networkd()
95e1fbba 2851 self.wait_online('veth99:routable')
dc7d3c5f
YW
2852
2853 output = check_output('ip -4 address show dev veth99')
2854 print(output)
44924431
YW
2855 self.assertNotIn('192.168.100.10/24', output)
2856 self.assertIn('192.168.100.11/24', output)
dc7d3c5f 2857
a962d857
YW
2858 copy_network_unit('25-address-ipv4acd-veth99.network.d/conflict-address.conf')
2859 networkctl_reload()
37611ccb 2860 self.wait_operstate('veth99', operstate='routable', setup_state='configuring', setup_timeout=10)
44924431
YW
2861
2862 output = check_output('ip -4 address show dev veth99')
dc7d3c5f 2863 print(output)
44924431
YW
2864 self.assertNotIn('192.168.100.10/24', output)
2865 self.assertIn('192.168.100.11/24', output)
dc7d3c5f 2866
21266e60
YW
2867 def test_address_peer_ipv4(self):
2868 # test for issue #17304
a962d857 2869 copy_network_unit('25-address-peer-ipv4.network', '12-dummy.netdev')
21266e60
YW
2870
2871 for trial in range(2):
2872 if trial == 0:
2873 start_networkd()
2874 else:
2875 restart_networkd()
2876
95e1fbba 2877 self.wait_online('dummy98:routable')
21266e60
YW
2878
2879 output = check_output('ip -4 address show dev dummy98')
2880 self.assertIn('inet 100.64.0.1 peer 100.64.0.2/32 scope global', output)
2881
c9d223e8
YW
2882 @expectedFailureIfModuleIsNotAvailable('vrf')
2883 def test_prefix_route(self):
a962d857
YW
2884 copy_network_unit('25-prefix-route-with-vrf.network', '12-dummy.netdev',
2885 '25-prefix-route-without-vrf.network', '11-dummy.netdev',
2886 '25-vrf.netdev', '25-vrf.network')
c9d223e8
YW
2887 for trial in range(2):
2888 if trial == 0:
2889 start_networkd()
2890 else:
a962d857 2891 restart_networkd()
c9d223e8 2892
95e1fbba 2893 self.wait_online('dummy98:routable', 'test1:routable', 'vrf99:carrier')
c9d223e8
YW
2894
2895 output = check_output('ip route show table 42 dev dummy98')
2896 print('### ip route show table 42 dev dummy98')
2897 print(output)
2898 self.assertRegex(output, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1')
c9d223e8
YW
2899 self.assertRegex(output, '10.20.33.0/24 proto kernel scope link src 10.20.33.1')
2900 self.assertRegex(output, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1')
2901 self.assertRegex(output, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1')
2902 self.assertRegex(output, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1')
c9d223e8
YW
2903 self.assertRegex(output, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1')
2904 self.assertRegex(output, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1')
2905 output = check_output('ip -6 route show table 42 dev dummy98')
2906 print('### ip -6 route show table 42 dev dummy98')
2907 print(output)
2908 if trial == 0:
2909 # Kernel's bug?
2910 self.assertRegex(output, 'local fdde:11:22::1 proto kernel metric 0 pref medium')
2911 #self.assertRegex(output, 'fdde:11:22::1 proto kernel metric 256 pref medium')
2912 self.assertRegex(output, 'local fdde:11:33::1 proto kernel metric 0 pref medium')
2913 self.assertRegex(output, 'fdde:11:33::/64 proto kernel metric 256 pref medium')
2914 self.assertRegex(output, 'local fdde:11:44::1 proto kernel metric 0 pref medium')
2915 self.assertRegex(output, 'local fdde:11:55::1 proto kernel metric 0 pref medium')
2916 self.assertRegex(output, 'fe80::/64 proto kernel metric 256 pref medium')
beb75dd3 2917 self.assertRegex(output, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium')
c9d223e8
YW
2918
2919 print()
2920
2921 output = check_output('ip route show dev test1')
2922 print('### ip route show dev test1')
2923 print(output)
2924 self.assertRegex(output, '10.21.33.0/24 proto kernel scope link src 10.21.33.1')
2925 output = check_output('ip route show table local dev test1')
2926 print('### ip route show table local dev test1')
2927 print(output)
2928 self.assertRegex(output, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1')
c9d223e8
YW
2929 self.assertRegex(output, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1')
2930 self.assertRegex(output, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1')
2931 self.assertRegex(output, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1')
c9d223e8
YW
2932 self.assertRegex(output, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1')
2933 self.assertRegex(output, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1')
2934 output = check_output('ip -6 route show dev test1')
2935 print('### ip -6 route show dev test1')
2936 print(output)
2937 self.assertRegex(output, 'fdde:12:22::1 proto kernel metric 256 pref medium')
2938 self.assertRegex(output, 'fdde:12:33::/64 proto kernel metric 256 pref medium')
2939 self.assertRegex(output, 'fe80::/64 proto kernel metric 256 pref medium')
2940 output = check_output('ip -6 route show table local dev test1')
2941 print('### ip -6 route show table local dev test1')
2942 print(output)
2943 self.assertRegex(output, 'local fdde:12:22::1 proto kernel metric 0 pref medium')
2944 self.assertRegex(output, 'local fdde:12:33::1 proto kernel metric 0 pref medium')
2945 self.assertRegex(output, 'local fdde:12:44::1 proto kernel metric 0 pref medium')
2946 self.assertRegex(output, 'local fdde:12:55::1 proto kernel metric 0 pref medium')
beb75dd3 2947 self.assertRegex(output, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium')
c9d223e8 2948
1f0e3109 2949 def test_configure_without_carrier(self):
a962d857 2950 copy_network_unit('11-dummy.netdev')
2cf6fdff 2951 start_networkd()
9bacf431
DS
2952 self.wait_operstate('test1', 'off', '')
2953 check_output('ip link set dev test1 up carrier off')
2954
a962d857 2955 copy_network_unit('25-test1.network.d/configure-without-carrier.conf', copy_dropins=False)
9bacf431 2956 restart_networkd()
95e1fbba 2957 self.wait_online('test1:no-carrier')
9bacf431
DS
2958
2959 carrier_map = {'on': '1', 'off': '0'}
2960 routable_map = {'on': 'routable', 'off': 'no-carrier'}
2961 for carrier in ['off', 'on', 'off']:
2962 with self.subTest(carrier=carrier):
2963 if carrier_map[carrier] != read_link_attr('test1', 'carrier'):
2964 check_output(f'ip link set dev test1 carrier {carrier}')
95e1fbba 2965 self.wait_online(f'test1:{routable_map[carrier]}:{routable_map[carrier]}')
9bacf431 2966
10d670a3 2967 output = networkctl_status('test1')
9bacf431
DS
2968 print(output)
2969 self.assertRegex(output, '192.168.0.15')
2970 self.assertRegex(output, '192.168.0.1')
2971 self.assertRegex(output, routable_map[carrier])
e40a58b5 2972
9bacf431 2973 def test_configure_without_carrier_yes_ignore_carrier_loss_no(self):
a962d857 2974 copy_network_unit('11-dummy.netdev')
9bacf431
DS
2975 start_networkd()
2976 self.wait_operstate('test1', 'off', '')
2977 check_output('ip link set dev test1 up carrier off')
2978
a962d857 2979 copy_network_unit('25-test1.network')
9bacf431 2980 restart_networkd()
95e1fbba 2981 self.wait_online('test1:no-carrier')
9bacf431
DS
2982
2983 carrier_map = {'on': '1', 'off': '0'}
2984 routable_map = {'on': 'routable', 'off': 'no-carrier'}
2985 for (carrier, have_config) in [('off', True), ('on', True), ('off', False)]:
2986 with self.subTest(carrier=carrier, have_config=have_config):
2987 if carrier_map[carrier] != read_link_attr('test1', 'carrier'):
2988 check_output(f'ip link set dev test1 carrier {carrier}')
95e1fbba 2989 self.wait_online(f'test1:{routable_map[carrier]}:{routable_map[carrier]}')
9bacf431 2990
10d670a3 2991 output = networkctl_status('test1')
9bacf431
DS
2992 print(output)
2993 if have_config:
2994 self.assertRegex(output, '192.168.0.15')
2995 self.assertRegex(output, '192.168.0.1')
2996 else:
2997 self.assertNotRegex(output, '192.168.0.15')
2998 self.assertNotRegex(output, '192.168.0.1')
2999 self.assertRegex(output, routable_map[carrier])
1f0e3109 3000
1f0e3109 3001 def test_routing_policy_rule(self):
a962d857 3002 copy_network_unit('25-routing-policy-rule-test1.network', '11-dummy.netdev')
2cf6fdff 3003 start_networkd()
95e1fbba 3004 self.wait_online('test1:degraded')
e40a58b5 3005
65c24cd0 3006 output = check_output('ip rule list iif test1 priority 111')
1f0e3109 3007 print(output)
65c24cd0 3008 self.assertRegex(output, '111:')
1f0e3109 3009 self.assertRegex(output, 'from 192.168.100.18')
426654d7 3010 self.assertRegex(output, r'tos (0x08|throughput)\s')
1f0e3109
SS
3011 self.assertRegex(output, 'iif test1')
3012 self.assertRegex(output, 'oif test1')
3013 self.assertRegex(output, 'lookup 7')
3014
65c24cd0
YW
3015 output = check_output('ip rule list iif test1 priority 101')
3016 print(output)
3017 self.assertRegex(output, '101:')
3018 self.assertRegex(output, 'from all')
3019 self.assertRegex(output, 'iif test1')
3020 self.assertRegex(output, 'lookup 9')
3021
3022 output = check_output('ip -6 rule list iif test1 priority 100')
3023 print(output)
3024 self.assertRegex(output, '100:')
3025 self.assertRegex(output, 'from all')
3026 self.assertRegex(output, 'iif test1')
3027 self.assertRegex(output, 'lookup 8')
3028
2e8a32af
HV
3029 output = check_output('ip rule list iif test1 priority 102')
3030 print(output)
3031 self.assertRegex(output, '102:')
3032 self.assertRegex(output, 'from 0.0.0.0/8')
3033 self.assertRegex(output, 'iif test1')
3034 self.assertRegex(output, 'lookup 10')
3035
10d670a3 3036 check_json(networkctl_json())
146726b2 3037
b677774d 3038 def test_routing_policy_rule_issue_11280(self):
a962d857
YW
3039 copy_network_unit('25-routing-policy-rule-test1.network', '11-dummy.netdev',
3040 '25-routing-policy-rule-dummy98.network', '12-dummy.netdev')
b677774d 3041
a962d857
YW
3042 for trial in range(3):
3043 restart_networkd(show_logs=(trial > 0))
95e1fbba 3044 self.wait_online('test1:degraded', 'dummy98:degraded')
b677774d 3045
371810d1 3046 output = check_output('ip rule list table 7')
b677774d 3047 print(output)
426654d7 3048 self.assertRegex(output, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
b677774d 3049
371810d1 3050 output = check_output('ip rule list table 8')
b677774d 3051 print(output)
426654d7 3052 self.assertRegex(output, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
b677774d 3053
87adeabf 3054 def test_routing_policy_rule_reconfigure(self):
a962d857 3055 copy_network_unit('25-routing-policy-rule-reconfigure2.network', '11-dummy.netdev')
87adeabf 3056 start_networkd()
95e1fbba 3057 self.wait_online('test1:degraded')
87adeabf
YW
3058
3059 output = check_output('ip rule list table 1011')
3060 print(output)
49ff3f34
YW
3061 self.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output)
3062 self.assertIn('10112: from all oif test1 lookup 1011', output)
3063 self.assertIn('10113: from all iif test1 lookup 1011', output)
3064 self.assertIn('10114: from 192.168.8.254 lookup 1011', output)
3065
3066 output = check_output('ip -6 rule list table 1011')
3067 print(output)
3068 self.assertIn('10112: from all oif test1 lookup 1011', output)
3069
a962d857
YW
3070 copy_network_unit('25-routing-policy-rule-reconfigure1.network', '11-dummy.netdev')
3071 networkctl_reload()
95e1fbba 3072 self.wait_online('test1:degraded')
49ff3f34
YW
3073
3074 output = check_output('ip rule list table 1011')
3075 print(output)
3076 self.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output)
3077 self.assertIn('10112: from all oif test1 lookup 1011', output)
3078 self.assertIn('10113: from all iif test1 lookup 1011', output)
3079 self.assertIn('10114: from 192.168.8.254 lookup 1011', output)
3080
3081 output = check_output('ip -6 rule list table 1011')
3082 print(output)
3083 self.assertNotIn('10112: from all oif test1 lookup 1011', output)
3084 self.assertIn('10113: from all iif test1 lookup 1011', output)
87adeabf 3085
a962d857
YW
3086 call('ip rule delete priority 10111')
3087 call('ip rule delete priority 10112')
3088 call('ip rule delete priority 10113')
3089 call('ip rule delete priority 10114')
3090 call('ip -6 rule delete priority 10113')
87adeabf
YW
3091
3092 output = check_output('ip rule list table 1011')
3093 print(output)
3094 self.assertEqual(output, '')
3095
49ff3f34
YW
3096 output = check_output('ip -6 rule list table 1011')
3097 print(output)
3098 self.assertEqual(output, '')
87adeabf 3099
a962d857 3100 networkctl_reconfigure('test1')
95e1fbba 3101 self.wait_online('test1:degraded')
87adeabf
YW
3102
3103 output = check_output('ip rule list table 1011')
3104 print(output)
49ff3f34
YW
3105 self.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output)
3106 self.assertIn('10112: from all oif test1 lookup 1011', output)
3107 self.assertIn('10113: from all iif test1 lookup 1011', output)
3108 self.assertIn('10114: from 192.168.8.254 lookup 1011', output)
3109
3110 output = check_output('ip -6 rule list table 1011')
3111 print(output)
3112 self.assertIn('10113: from all iif test1 lookup 1011', output)
87adeabf 3113
d586a2c3 3114 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
926062f0 3115 def test_routing_policy_rule_port_range(self):
a962d857 3116 copy_network_unit('25-fibrule-port-range.network', '11-dummy.netdev')
2cf6fdff 3117 start_networkd()
95e1fbba 3118 self.wait_online('test1:degraded')
e40a58b5 3119
371810d1 3120 output = check_output('ip rule')
926062f0
SS
3121 print(output)
3122 self.assertRegex(output, '111')
3123 self.assertRegex(output, 'from 192.168.100.18')
3124 self.assertRegex(output, '1123-1150')
3125 self.assertRegex(output, '3224-3290')
3126 self.assertRegex(output, 'tcp')
3127 self.assertRegex(output, 'lookup 7')
1f0e3109 3128
d586a2c3 3129 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
efecf9cd 3130 def test_routing_policy_rule_invert(self):
a962d857 3131 copy_network_unit('25-fibrule-invert.network', '11-dummy.netdev')
2cf6fdff 3132 start_networkd()
95e1fbba 3133 self.wait_online('test1:degraded')
e40a58b5 3134
371810d1 3135 output = check_output('ip rule')
efecf9cd 3136 print(output)
efecf9cd
SS
3137 self.assertRegex(output, '111')
3138 self.assertRegex(output, 'not.*?from.*?192.168.100.18')
3139 self.assertRegex(output, 'tcp')
3140 self.assertRegex(output, 'lookup 7')
3141
4be1fc84
NC
3142 @expectedFailureIfRoutingPolicyL3MasterDeviceIsNotAvailable()
3143 def test_routing_policy_rule_l3mdev(self):
3144 copy_network_unit('25-fibrule-l3mdev.network', '11-dummy.netdev')
3145 start_networkd()
95e1fbba 3146 self.wait_online('test1:degraded')
4be1fc84
NC
3147
3148 output = check_output('ip rule')
3149 print(output)
3150 self.assertIn('1500: from all lookup [l3mdev-table]', output)
3151 self.assertIn('2000: from all lookup [l3mdev-table] unreachable', output)
3152
6be8e78e
YW
3153 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable()
3154 def test_routing_policy_rule_uidrange(self):
a962d857 3155 copy_network_unit('25-fibrule-uidrange.network', '11-dummy.netdev')
6be8e78e 3156 start_networkd()
95e1fbba 3157 self.wait_online('test1:degraded')
6be8e78e
YW
3158
3159 output = check_output('ip rule')
3160 print(output)
3161 self.assertRegex(output, '111')
3162 self.assertRegex(output, 'from 192.168.100.18')
3163 self.assertRegex(output, 'lookup 7')
3164 self.assertRegex(output, 'uidrange 100-200')
3165
1d26d4cd
YW
3166 def _test_route_static(self, manage_foreign_routes):
3167 if not manage_foreign_routes:
3168 copy_networkd_conf_dropin('networkd-manage-foreign-routes-no.conf')
3169
d3779490
YW
3170 copy_network_unit('25-route-static.network', '12-dummy.netdev',
3171 '25-route-static-test1.network', '11-dummy.netdev')
2cf6fdff 3172 start_networkd()
95e1fbba 3173 self.wait_online('dummy98:routable')
e2aea43f 3174
10d670a3 3175 output = networkctl_status('dummy98')
e2aea43f 3176 print(output)
0d34228f 3177
6d60f9db 3178 print('### ip -6 route show dev dummy98')
371810d1 3179 output = check_output('ip -6 route show dev dummy98')
0d34228f 3180 print(output)
0b5dc249
YW
3181 self.assertIn('2001:1234:5:8fff:ff:ff:ff:ff proto static', output)
3182 self.assertIn('2001:1234:5:8f63::1 proto kernel', output)
180c5116 3183 self.assertIn('2001:1234:5:afff:ff:ff:ff:ff via fe80:0:222:4dff:ff:ff:ff:ff proto static', output)
1f0e3109 3184
d9005dec
YW
3185 print('### ip -6 route show default')
3186 output = check_output('ip -6 route show default')
6d60f9db 3187 print(output)
0b5dc249
YW
3188 self.assertIn('default', output)
3189 self.assertIn('via 2001:1234:5:8fff:ff:ff:ff:ff', output)
1f0e3109 3190
6d60f9db 3191 print('### ip -4 route show dev dummy98')
371810d1 3192 output = check_output('ip -4 route show dev dummy98')
1f0e3109 3193 print(output)
0b5dc249
YW
3194 self.assertIn('149.10.124.48/28 proto kernel scope link src 149.10.124.58', output)
3195 self.assertIn('149.10.124.64 proto static scope link', output)
3196 self.assertIn('169.254.0.0/16 proto static scope link metric 2048', output)
902bbdc4
YW
3197 self.assertIn('192.168.1.1 proto static scope link initcwnd 20', output)
3198 self.assertIn('192.168.1.2 proto static scope link initrwnd 30', output)
3199 self.assertIn('192.168.1.3 proto static scope link advmss 30', output)
288f58c0 3200 self.assertIn('192.168.1.4 proto static scope link hoplimit 122', output)
0b5dc249 3201 self.assertIn('multicast 149.10.123.4 proto static', output)
1f0e3109 3202
6d60f9db 3203 print('### ip -4 route show dev dummy98 default')
371810d1 3204 output = check_output('ip -4 route show dev dummy98 default')
6d60f9db 3205 print(output)
0b5dc249
YW
3206 self.assertIn('default via 149.10.125.65 proto static onlink', output)
3207 self.assertIn('default via 149.10.124.64 proto static', output)
3208 self.assertIn('default proto static', output)
5e46ca98 3209 self.assertIn('default via 1.1.8.104 proto static', output)
1f0e3109 3210
6d60f9db
YW
3211 print('### ip -4 route show table local dev dummy98')
3212 output = check_output('ip -4 route show table local dev dummy98')
3213 print(output)
0b5dc249
YW
3214 self.assertIn('local 149.10.123.1 proto static scope host', output)
3215 self.assertIn('anycast 149.10.123.2 proto static scope link', output)
3216 self.assertIn('broadcast 149.10.123.3 proto static scope link', output)
6d60f9db 3217
b4f4f119
YW
3218 print('### ip -4 route show type blackhole')
3219 output = check_output('ip -4 route show type blackhole')
1f0e3109 3220 print(output)
0b5dc249 3221 self.assertIn('blackhole 202.54.1.2 proto static', output)
f5050e48 3222
b4f4f119
YW
3223 print('### ip -4 route show type unreachable')
3224 output = check_output('ip -4 route show type unreachable')
f5050e48 3225 print(output)
0b5dc249 3226 self.assertIn('unreachable 202.54.1.3 proto static', output)
f5050e48 3227
b4f4f119
YW
3228 print('### ip -4 route show type prohibit')
3229 output = check_output('ip -4 route show type prohibit')
f5050e48 3230 print(output)
0b5dc249 3231 self.assertIn('prohibit 202.54.1.4 proto static', output)
f5050e48 3232
452d86a5
YW
3233 print('### ip -6 route show type blackhole')
3234 output = check_output('ip -6 route show type blackhole')
3235 print(output)
3236 self.assertIn('blackhole 2001:1234:5678::2 dev lo proto static', output)
3237
3238 print('### ip -6 route show type unreachable')
3239 output = check_output('ip -6 route show type unreachable')
3240 print(output)
3241 self.assertIn('unreachable 2001:1234:5678::3 dev lo proto static', output)
3242
3243 print('### ip -6 route show type prohibit')
3244 output = check_output('ip -6 route show type prohibit')
3245 print(output)
3246 self.assertIn('prohibit 2001:1234:5678::4 dev lo proto static', output)
3247
a0ce990e
YW
3248 print('### ip route show 192.168.10.1')
3249 output = check_output('ip route show 192.168.10.1')
3250 print(output)
0b5dc249 3251 self.assertIn('192.168.10.1 proto static', output)
d3779490
YW
3252 self.assertIn('nexthop via 149.10.123.59 dev test1 weight 20', output)
3253 self.assertIn('nexthop via 149.10.123.60 dev test1 weight 30', output)
0b5dc249
YW
3254 self.assertIn('nexthop via 149.10.124.59 dev dummy98 weight 10', output)
3255 self.assertIn('nexthop via 149.10.124.60 dev dummy98 weight 5', output)
a0ce990e
YW
3256
3257 print('### ip route show 192.168.10.2')
3258 output = check_output('ip route show 192.168.10.2')
3259 print(output)
3260 # old ip command does not show IPv6 gateways...
0b5dc249
YW
3261 self.assertIn('192.168.10.2 proto static', output)
3262 self.assertIn('nexthop', output)
d3779490
YW
3263 self.assertIn('dev test1 weight 20', output)
3264 self.assertIn('dev test1 weight 30', output)
0b5dc249
YW
3265 self.assertIn('dev dummy98 weight 10', output)
3266 self.assertIn('dev dummy98 weight 5', output)
a0ce990e
YW
3267
3268 print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
3269 output = check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
3270 print(output)
3271 # old ip command does not show 'nexthop' keyword and weight...
0b5dc249 3272 self.assertIn('2001:1234:5:7fff:ff:ff:ff:ff', output)
d3779490
YW
3273 self.assertIn('via 2001:1234:5:6fff:ff:ff:ff:ff dev test1', output)
3274 self.assertIn('via 2001:1234:5:7fff:ff:ff:ff:ff dev test1', output)
0b5dc249
YW
3275 self.assertIn('via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98', output)
3276 self.assertIn('via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98', output)
a0ce990e 3277
10d670a3 3278 check_json(networkctl_json())
146726b2 3279
67150a7b 3280 copy_network_unit('25-address-static.network', copy_dropins=False)
a962d857 3281 networkctl_reload()
95e1fbba 3282 self.wait_online('dummy98:routable')
43d4bc9f
YW
3283
3284 # check all routes managed by Manager are removed
b4f4f119
YW
3285 print('### ip -4 route show type blackhole')
3286 output = check_output('ip -4 route show type blackhole')
43d4bc9f
YW
3287 print(output)
3288 self.assertEqual(output, '')
3289
b4f4f119
YW
3290 print('### ip -4 route show type unreachable')
3291 output = check_output('ip -4 route show type unreachable')
43d4bc9f
YW
3292 print(output)
3293 self.assertEqual(output, '')
3294
b4f4f119
YW
3295 print('### ip -4 route show type prohibit')
3296 output = check_output('ip -4 route show type prohibit')
43d4bc9f
YW
3297 print(output)
3298 self.assertEqual(output, '')
3299
452d86a5
YW
3300 print('### ip -6 route show type blackhole')
3301 output = check_output('ip -6 route show type blackhole')
3302 print(output)
3303 self.assertEqual(output, '')
3304
3305 print('### ip -6 route show type unreachable')
3306 output = check_output('ip -6 route show type unreachable')
3307 print(output)
3308 self.assertEqual(output, '')
3309
3310 print('### ip -6 route show type prohibit')
3311 output = check_output('ip -6 route show type prohibit')
3312 print(output)
3313 self.assertEqual(output, '')
3314
a962d857
YW
3315 remove_network_unit('25-address-static.network')
3316 networkctl_reload()
95e1fbba 3317 self.wait_online('dummy98:routable')
43d4bc9f
YW
3318
3319 # check all routes managed by Manager are reconfigured
b4f4f119
YW
3320 print('### ip -4 route show type blackhole')
3321 output = check_output('ip -4 route show type blackhole')
43d4bc9f 3322 print(output)
0b5dc249 3323 self.assertIn('blackhole 202.54.1.2 proto static', output)
43d4bc9f 3324
b4f4f119
YW
3325 print('### ip -4 route show type unreachable')
3326 output = check_output('ip -4 route show type unreachable')
43d4bc9f 3327 print(output)
0b5dc249 3328 self.assertIn('unreachable 202.54.1.3 proto static', output)
43d4bc9f 3329
b4f4f119
YW
3330 print('### ip -4 route show type prohibit')
3331 output = check_output('ip -4 route show type prohibit')
43d4bc9f 3332 print(output)
0b5dc249 3333 self.assertIn('prohibit 202.54.1.4 proto static', output)
43d4bc9f 3334
452d86a5
YW
3335 print('### ip -6 route show type blackhole')
3336 output = check_output('ip -6 route show type blackhole')
3337 print(output)
3338 self.assertIn('blackhole 2001:1234:5678::2 dev lo proto static', output)
3339
3340 print('### ip -6 route show type unreachable')
3341 output = check_output('ip -6 route show type unreachable')
3342 print(output)
3343 self.assertIn('unreachable 2001:1234:5678::3 dev lo proto static', output)
3344
3345 print('### ip -6 route show type prohibit')
3346 output = check_output('ip -6 route show type prohibit')
3347 print(output)
3348 self.assertIn('prohibit 2001:1234:5678::4 dev lo proto static', output)
3349
a962d857 3350 remove_link('dummy98')
43d4bc9f
YW
3351 time.sleep(2)
3352
3353 # check all routes managed by Manager are removed
b4f4f119
YW
3354 print('### ip -4 route show type blackhole')
3355 output = check_output('ip -4 route show type blackhole')
43d4bc9f
YW
3356 print(output)
3357 self.assertEqual(output, '')
3358
b4f4f119
YW
3359 print('### ip -4 route show type unreachable')
3360 output = check_output('ip -4 route show type unreachable')
43d4bc9f
YW
3361 print(output)
3362 self.assertEqual(output, '')
3363
b4f4f119
YW
3364 print('### ip -4 route show type prohibit')
3365 output = check_output('ip -4 route show type prohibit')
43d4bc9f
YW
3366 print(output)
3367 self.assertEqual(output, '')
3368
452d86a5
YW
3369 print('### ip -6 route show type blackhole')
3370 output = check_output('ip -6 route show type blackhole')
3371 print(output)
3372 self.assertEqual(output, '')
3373
3374 print('### ip -6 route show type unreachable')
3375 output = check_output('ip -6 route show type unreachable')
3376 print(output)
3377 self.assertEqual(output, '')
3378
3379 print('### ip -6 route show type prohibit')
3380 output = check_output('ip -6 route show type prohibit')
3381 print(output)
3382 self.assertEqual(output, '')
3383
1d26d4cd 3384 def test_route_static(self):
a962d857 3385 first = True
1d26d4cd 3386 for manage_foreign_routes in [True, False]:
a962d857
YW
3387 if first:
3388 first = False
3389 else:
3390 self.tearDown()
3391
3392 print(f'### test_route_static(manage_foreign_routes={manage_foreign_routes})')
1d26d4cd
YW
3393 with self.subTest(manage_foreign_routes=manage_foreign_routes):
3394 self._test_route_static(manage_foreign_routes)
3395
297f9d86
YW
3396 @expectedFailureIfRTA_VIAIsNotSupported()
3397 def test_route_via_ipv6(self):
a962d857 3398 copy_network_unit('25-route-via-ipv6.network', '12-dummy.netdev')
297f9d86 3399 start_networkd()
95e1fbba 3400 self.wait_online('dummy98:routable')
297f9d86 3401
10d670a3 3402 output = networkctl_status('dummy98')
297f9d86
YW
3403 print(output)
3404
3405 print('### ip -6 route show dev dummy98')
3406 output = check_output('ip -6 route show dev dummy98')
3407 print(output)
3408 self.assertRegex(output, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
3409 self.assertRegex(output, '2001:1234:5:8f63::1 proto kernel')
3410
3411 print('### ip -4 route show dev dummy98')
3412 output = check_output('ip -4 route show dev dummy98')
3413 print(output)
3414 self.assertRegex(output, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
3415 self.assertRegex(output, '149.10.124.66 via inet6 2001:1234:5:8fff:ff:ff:ff:ff proto static')
3416
93e898d6
YW
3417 @expectedFailureIfModuleIsNotAvailable('tcp_dctcp')
3418 def test_route_congctl(self):
3419 copy_network_unit('25-route-congctl.network', '12-dummy.netdev')
3420 start_networkd()
95e1fbba 3421 self.wait_online('dummy98:routable')
93e898d6
YW
3422
3423 print('### ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff')
3424 output = check_output('ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff')
3425 print(output)
3426 self.assertIn('2001:1234:5:8fff:ff:ff:ff:ff proto static', output)
3427 self.assertIn('congctl dctcp', output)
3428
3429 print('### ip -4 route show dev dummy98 149.10.124.66')
3430 output = check_output('ip -4 route show dev dummy98 149.10.124.66')
3431 print(output)
3432 self.assertIn('149.10.124.66 proto static', output)
3433 self.assertIn('congctl dctcp', output)
1791956e 3434 self.assertIn('rto_min 300s', output)
93e898d6 3435
40afe491
YW
3436 @expectedFailureIfModuleIsNotAvailable('vrf')
3437 def test_route_vrf(self):
a962d857
YW
3438 copy_network_unit('25-route-vrf.network', '12-dummy.netdev',
3439 '25-vrf.netdev', '25-vrf.network')
40afe491 3440 start_networkd()
95e1fbba 3441 self.wait_online('dummy98:routable', 'vrf99:carrier')
40afe491
YW
3442
3443 output = check_output('ip route show vrf vrf99')
3444 print(output)
3445 self.assertRegex(output, 'default via 192.168.100.1')
3446
3447 output = check_output('ip route show')
3448 print(output)
3449 self.assertNotRegex(output, 'default via 192.168.100.1')
3450
0b1cd3e2 3451 def test_gateway_reconfigure(self):
a962d857 3452 copy_network_unit('25-gateway-static.network', '12-dummy.netdev')
0b1cd3e2 3453 start_networkd()
95e1fbba 3454 self.wait_online('dummy98:routable')
0b1cd3e2
WKI
3455 print('### ip -4 route show dev dummy98 default')
3456 output = check_output('ip -4 route show dev dummy98 default')
3457 print(output)
a962d857
YW
3458 self.assertIn('default via 149.10.124.59 proto static', output)
3459 self.assertNotIn('149.10.124.60', output)
0b1cd3e2 3460
a962d857
YW
3461 remove_network_unit('25-gateway-static.network')
3462 copy_network_unit('25-gateway-next-static.network')
3463 networkctl_reload()
95e1fbba 3464 self.wait_online('dummy98:routable')
0b1cd3e2
WKI
3465 print('### ip -4 route show dev dummy98 default')
3466 output = check_output('ip -4 route show dev dummy98 default')
3467 print(output)
a962d857
YW
3468 self.assertNotIn('149.10.124.59', output)
3469 self.assertIn('default via 149.10.124.60 proto static', output)
0b1cd3e2 3470
20ca06a6
DA
3471 def test_ip_route_ipv6_src_route(self):
3472 # a dummy device does not make the addresses go through tentative state, so we
3473 # reuse a bond from an earlier test, which does make the addresses go through
3474 # tentative state, and do our test on that
a962d857 3475 copy_network_unit('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2cf6fdff 3476 start_networkd()
95e1fbba 3477 self.wait_online('dummy98:enslaved', 'bond199:routable')
20ca06a6 3478
371810d1 3479 output = check_output('ip -6 route list dev bond199')
20ca06a6 3480 print(output)
7e305278 3481 self.assertIn('abcd::/16 via 2001:1234:56:8f63::1:1 proto static src 2001:1234:56:8f63::2', output)
20ca06a6 3482
e4948bb2
YW
3483 def test_route_preferred_source_with_existing_address(self):
3484 # See issue #28009.
3485 copy_network_unit('25-route-preferred-source.network', '12-dummy.netdev')
3486 start_networkd()
3487
3488 for i in range(3):
3489 if i != 0:
3490 networkctl_reconfigure('dummy98')
3491
95e1fbba 3492 self.wait_online('dummy98:routable')
e4948bb2
YW
3493
3494 output = check_output('ip -6 route list dev dummy98')
3495 print(output)
3496 self.assertIn('abcd::/16 via 2001:1234:56:8f63::1:1 proto static src 2001:1234:56:8f63::1', output)
3497
1f0e3109 3498 def test_ip_link_mac_address(self):
a962d857 3499 copy_network_unit('25-address-link-section.network', '12-dummy.netdev')
2cf6fdff 3500 start_networkd()
95e1fbba 3501 self.wait_online('dummy98:degraded')
1f0e3109 3502
371810d1 3503 output = check_output('ip link show dummy98')
1f0e3109 3504 print(output)
45aa0e84 3505 self.assertRegex(output, '00:01:02:aa:bb:cc')
1f0e3109
SS
3506
3507 def test_ip_link_unmanaged(self):
a962d857
YW
3508 copy_network_unit('25-link-section-unmanaged.network', '12-dummy.netdev')
3509 start_networkd()
1f0e3109 3510
19cf3143 3511 self.wait_operstate('dummy98', 'off', setup_state='unmanaged')
1f0e3109
SS
3512
3513 def test_ipv6_address_label(self):
a962d857 3514 copy_network_unit('25-ipv6-address-label-section.network', '12-dummy.netdev')
2cf6fdff 3515 start_networkd()
95e1fbba 3516 self.wait_online('dummy98:degraded')
1f0e3109 3517
371810d1 3518 output = check_output('ip addrlabel list')
1f0e3109
SS
3519 print(output)
3520 self.assertRegex(output, '2004:da8:1::/64')
3521
cff0cadc 3522 def test_ipv6_proxy_ndp(self):
a962d857 3523 copy_network_unit('25-ipv6-proxy-ndp.network', '12-dummy.netdev')
cff0cadc
YW
3524 start_networkd()
3525
95e1fbba 3526 self.wait_online('dummy98:routable')
cff0cadc
YW
3527
3528 output = check_output('ip neighbor show proxy dev dummy98')
3529 print(output)
a962d857 3530 for i in range(1, 5):
cff0cadc
YW
3531 self.assertRegex(output, f'2607:5300:203:5215:{i}::1 *proxy')
3532
d4c8de21
MM
3533 def test_ipv6_neigh_retrans_time(self):
3534 link='test25'
3535 copy_network_unit('25-dummy.netdev', '25-dummy.network')
3536 start_networkd()
3537
95e1fbba 3538 self.wait_online(f'{link}:degraded')
d4c8de21
MM
3539 remove_network_unit('25-dummy.network')
3540
3541 # expect retrans_time_ms updated
3542 copy_network_unit('25-ipv6-neigh-retrans-time-3s.network')
3543 networkctl_reload()
95e1fbba 3544 self.wait_online(f'{link}:degraded')
d4c8de21
MM
3545 self.check_ipv6_neigh_sysctl_attr(link, 'retrans_time_ms', '3000')
3546 remove_network_unit('25-ipv6-neigh-retrans-time-3s.network')
3547
3548 # expect retrans_time_ms unchanged
3549 copy_network_unit('25-ipv6-neigh-retrans-time-0s.network')
3550 networkctl_reload()
95e1fbba 3551 self.wait_online(f'{link}:degraded')
d4c8de21
MM
3552 self.check_ipv6_neigh_sysctl_attr(link, 'retrans_time_ms', '3000')
3553 remove_network_unit('25-ipv6-neigh-retrans-time-0s.network')
3554
3555 # expect retrans_time_ms unchanged
3556 copy_network_unit('25-ipv6-neigh-retrans-time-toobig.network')
3557 networkctl_reload()
95e1fbba 3558 self.wait_online(f'{link}:degraded')
d4c8de21
MM
3559 self.check_ipv6_neigh_sysctl_attr(link, 'retrans_time_ms', '3000')
3560 remove_network_unit('25-ipv6-neigh-retrans-time-toobig.network')
3561
3562 # expect retrans_time_ms unchanged
3563 copy_network_unit('25-ipv6-neigh-retrans-time-infinity.network')
3564 networkctl_reload()
95e1fbba 3565 self.wait_online(f'{link}:degraded')
d4c8de21
MM
3566 self.check_ipv6_neigh_sysctl_attr(link, 'retrans_time_ms', '3000')
3567 remove_network_unit('25-ipv6-neigh-retrans-time-infinity.network')
3568
3569 # expect retrans_time_ms unchanged
3570 copy_network_unit('25-ipv6-neigh-retrans-time-invalid.network')
3571 networkctl_reload()
95e1fbba 3572 self.wait_online(f'{link}:degraded')
d4c8de21
MM
3573 self.check_ipv6_neigh_sysctl_attr(link, 'retrans_time_ms', '3000')
3574 remove_network_unit('25-ipv6-neigh-retrans-time-invalid.network')
3575
3576 # expect retrans_time_ms updated
3577 copy_network_unit('25-ipv6-neigh-retrans-time-4s.network')
3578 networkctl_reload()
95e1fbba 3579 self.wait_online(f'{link}:degraded')
d4c8de21
MM
3580 self.check_ipv6_neigh_sysctl_attr(link, 'retrans_time_ms', '4000')
3581 remove_network_unit('25-ipv6-neigh-retrans-time-4s.network')
3582
9362f7d5
YW
3583 def test_neighbor(self):
3584 copy_network_unit('12-dummy.netdev', '25-neighbor-dummy.network', '25-neighbor-dummy.network.d/10-step1.conf',
3585 '25-gre-tunnel-remote-any.netdev', '25-neighbor-ip.network',
3586 '25-ip6gre-tunnel-remote-any.netdev', '25-neighbor-ipv6.network',
3587 copy_dropins=False)
2cf6fdff 3588 start_networkd()
95e1fbba 3589 self.wait_online('dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable')
9362f7d5
YW
3590
3591 print('### ip neigh list dev gretun97')
3592 output = check_output('ip neigh list dev gretun97')
3593 print(output)
3594 self.assertIn('10.0.0.22 lladdr 10.65.223.239 PERMANENT', output)
3595 self.assertNotIn('10.0.0.23', output)
3596
3597 print('### ip neigh list dev ip6gretun97')
3598 output = check_output('ip neigh list dev ip6gretun97')
3599 print(output)
3600 self.assertRegex(output, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
3601 self.assertNotIn('2001:db8:0:f102::18', output)
e4a71bf3 3602
d1bdafd2 3603 print('### ip neigh list dev dummy98')
df7f9afa 3604 output = check_output('ip neigh list dev dummy98')
e4a71bf3 3605 print(output)
2ede3559
YW
3606 self.assertIn('192.168.10.1 lladdr 00:00:5e:00:02:65 PERMANENT', output)
3607 self.assertIn('2004:da8:1::1 lladdr 00:00:5e:00:02:66 PERMANENT', output)
3608 self.assertNotIn('2004:da8:1:0::2', output)
3609 self.assertNotIn('192.168.10.2', output)
3610 self.assertNotIn('00:00:5e:00:02:67', output)
e4a71bf3 3611
10d670a3 3612 check_json(networkctl_json())
146726b2 3613
9362f7d5
YW
3614 # Here, 10-step1.conf is intendedly kept, to verify that 10-step2.conf overrides
3615 # the valid configurations in 10-step1.conf.
3616 copy_network_unit('25-neighbor-dummy.network.d/10-step2.conf')
2ede3559 3617 networkctl_reload()
95e1fbba 3618 self.wait_online('dummy98:degraded')
2ede3559 3619
9362f7d5 3620 print('### ip neigh list dev dummy98')
2ede3559
YW
3621 output = check_output('ip neigh list dev dummy98')
3622 print(output)
3623 self.assertIn('192.168.10.1 lladdr 00:00:5e:00:03:65 PERMANENT', output)
3624 self.assertIn('2004:da8:1::1 lladdr 00:00:5e:00:03:66 PERMANENT', output)
3625 self.assertNotIn('2004:da8:1:0::2', output)
3626 self.assertNotIn('192.168.10.2', output)
9362f7d5 3627 self.assertNotIn('00:00:5e:00:02:67', output)
d1bdafd2 3628
10d670a3 3629 check_json(networkctl_json())
d1bdafd2 3630
9362f7d5
YW
3631 remove_network_unit('25-neighbor-dummy.network.d/10-step1.conf',
3632 '25-neighbor-dummy.network.d/10-step2.conf')
3633 copy_network_unit('25-neighbor-dummy.network.d/10-step3.conf')
a962d857 3634 networkctl_reload()
95e1fbba 3635 self.wait_online('dummy98:degraded')
9362f7d5 3636
d1bdafd2
WKI
3637 print('### ip neigh list dev dummy98')
3638 output = check_output('ip neigh list dev dummy98')
3639 print(output)
9362f7d5 3640 self.assertIn('192.168.10.1 lladdr 00:00:5e:00:03:66 PERMANENT', output)
2ede3559 3641 self.assertNotIn('00:00:5e:00:02:65', output)
9362f7d5
YW
3642 self.assertNotIn('00:00:5e:00:02:66', output)
3643 self.assertNotIn('00:00:5e:00:03:65', output)
2ede3559 3644 self.assertNotIn('2004:da8:1::1', output)
d1bdafd2 3645
05514ae1 3646 def test_link_local_addressing(self):
a962d857
YW
3647 copy_network_unit('25-link-local-addressing-yes.network', '11-dummy.netdev',
3648 '25-link-local-addressing-no.network', '12-dummy.netdev')
2cf6fdff 3649 start_networkd()
95e1fbba 3650 self.wait_online('test1:degraded', 'dummy98:carrier')
05514ae1 3651
371810d1 3652 output = check_output('ip address show dev test1')
05514ae1
YW
3653 print(output)
3654 self.assertRegex(output, 'inet .* scope link')
3655 self.assertRegex(output, 'inet6 .* scope link')
3656
371810d1 3657 output = check_output('ip address show dev dummy98')
05514ae1
YW
3658 print(output)
3659 self.assertNotRegex(output, 'inet6* .* scope link')
3660
f7805a6c
FS
3661 # Documentation/networking/ip-sysctl.txt
3662 #
3663 # addr_gen_mode - INTEGER
3664 # Defines how link-local and autoconf addresses are generated.
3665 #
3666 # 0: generate address based on EUI64 (default)
3667 # 1: do no generate a link-local address, use EUI64 for addresses generated
3668 # from autoconf
3669 # 2: generate stable privacy addresses, using the secret from
3670 # stable_secret (RFC7217)
3671 # 3: generate stable privacy addresses, using a random secret if unset
05514ae1 3672
a962d857
YW
3673 self.check_ipv6_sysctl_attr('test1', 'stable_secret', '0123:4567:89ab:cdef:0123:4567:89ab:cdef')
3674 self.check_ipv6_sysctl_attr('test1', 'addr_gen_mode', '2')
3675 self.check_ipv6_sysctl_attr('dummy98', 'addr_gen_mode', '1')
05514ae1 3676
2becdbcc 3677 def test_link_local_addressing_ipv6ll(self):
a962d857 3678 copy_network_unit('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
7b3770a7 3679 start_networkd()
95e1fbba 3680 self.wait_online('dummy98:degraded')
7b3770a7 3681
2becdbcc 3682 # An IPv6LL address exists by default.
7b3770a7
YW
3683 output = check_output('ip address show dev dummy98')
3684 print(output)
3685 self.assertRegex(output, 'inet6 .* scope link')
3686
a962d857
YW
3687 copy_network_unit('25-link-local-addressing-no.network')
3688 networkctl_reload()
95e1fbba 3689 self.wait_online('dummy98:carrier')
7b3770a7 3690
2becdbcc 3691 # Check if the IPv6LL address is removed.
7b3770a7
YW
3692 output = check_output('ip address show dev dummy98')
3693 print(output)
2becdbcc
YW
3694 self.assertNotRegex(output, 'inet6 .* scope link')
3695
a962d857
YW
3696 remove_network_unit('25-link-local-addressing-no.network')
3697 networkctl_reload()
95e1fbba 3698 self.wait_online('dummy98:degraded')
2becdbcc
YW
3699
3700 # Check if a new IPv6LL address is assigned.
3701 output = check_output('ip address show dev dummy98')
3702 print(output)
3703 self.assertRegex(output, 'inet6 .* scope link')
7b3770a7 3704
1f0e3109 3705 def test_sysctl(self):
856a247e
YW
3706 copy_networkd_conf_dropin('25-global-ipv6-privacy-extensions.conf')
3707 copy_network_unit('25-sysctl.network', '12-dummy.netdev', copy_dropins=False)
2cf6fdff 3708 start_networkd()
95e1fbba 3709 self.wait_online('dummy98:degraded')
ec38833c 3710
a962d857 3711 self.check_ipv6_sysctl_attr('dummy98', 'forwarding', '1')
856a247e 3712 self.check_ipv6_sysctl_attr('dummy98', 'use_tempaddr', '1')
a962d857
YW
3713 self.check_ipv6_sysctl_attr('dummy98', 'dad_transmits', '3')
3714 self.check_ipv6_sysctl_attr('dummy98', 'hop_limit', '5')
3715 self.check_ipv6_sysctl_attr('dummy98', 'proxy_ndp', '1')
3716 self.check_ipv4_sysctl_attr('dummy98', 'forwarding', '1')
3717 self.check_ipv4_sysctl_attr('dummy98', 'proxy_arp', '1')
b4959550 3718 self.check_ipv4_sysctl_attr('dummy98', 'proxy_arp_pvlan', '1')
a962d857 3719 self.check_ipv4_sysctl_attr('dummy98', 'accept_local', '1')
ab2d9e29 3720 self.check_ipv4_sysctl_attr('dummy98', 'rp_filter', '0')
1f0e3109 3721
856a247e
YW
3722 copy_network_unit('25-sysctl.network.d/25-ipv6-privacy-extensions.conf')
3723 networkctl_reload()
95e1fbba 3724 self.wait_online('dummy98:degraded')
856a247e
YW
3725
3726 self.check_ipv6_sysctl_attr('dummy98', 'use_tempaddr', '2')
3727
4da33154 3728 def test_sysctl_disable_ipv6(self):
a962d857 3729 copy_network_unit('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
4da33154
YW
3730
3731 print('## Disable ipv6')
cefd6b3d
ZJS
3732 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
3733 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
4da33154 3734
2cf6fdff 3735 start_networkd()
95e1fbba 3736 self.wait_online('dummy98:routable')
4da33154 3737
371810d1 3738 output = check_output('ip -4 address show dummy98')
4da33154
YW
3739 print(output)
3740 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
371810d1 3741 output = check_output('ip -6 address show dummy98')
4da33154 3742 print(output)
57ad7607
ZJS
3743 self.assertRegex(output, 'inet6 2607:5300:203:3906::/64 scope global')
3744 self.assertRegex(output, 'inet6 .* scope link')
4933b97d
YW
3745 output = check_output('ip -4 route show dev dummy98')
3746 print(output)
3d2c2692 3747 self.assertRegex(output, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
d9005dec 3748 output = check_output('ip -6 route show default')
4933b97d 3749 print(output)
d9005dec
YW
3750 self.assertRegex(output, 'default')
3751 self.assertRegex(output, 'via 2607:5300:203:39ff:ff:ff:ff:ff')
4da33154 3752
a962d857 3753 remove_link('dummy98')
4da33154
YW
3754
3755 print('## Enable ipv6')
cefd6b3d
ZJS
3756 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
3757 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
4da33154 3758
a962d857 3759 restart_networkd()
95e1fbba 3760 self.wait_online('dummy98:routable')
4da33154 3761
371810d1 3762 output = check_output('ip -4 address show dummy98')
4da33154
YW
3763 print(output)
3764 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
371810d1 3765 output = check_output('ip -6 address show dummy98')
4da33154 3766 print(output)
4933b97d 3767 self.assertRegex(output, 'inet6 2607:5300:203:3906::/64 scope global')
4da33154 3768 self.assertRegex(output, 'inet6 .* scope link')
4933b97d
YW
3769 output = check_output('ip -4 route show dev dummy98')
3770 print(output)
3d2c2692 3771 self.assertRegex(output, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
d9005dec 3772 output = check_output('ip -6 route show default')
4933b97d 3773 print(output)
d9005dec 3774 self.assertRegex(output, 'via 2607:5300:203:39ff:ff:ff:ff:ff')
4da33154 3775
cd65d067 3776 def test_bind_carrier(self):
a962d857 3777 copy_network_unit('25-bind-carrier.network', '11-dummy.netdev')
2cf6fdff 3778 start_networkd()
cd65d067 3779
3e2f7c46
YW
3780 # no bound interface.
3781 self.wait_operstate('test1', 'off', setup_state='configuring')
371810d1 3782 output = check_output('ip address show test1')
cd65d067 3783 print(output)
3e2f7c46
YW
3784 self.assertNotIn('UP,LOWER_UP', output)
3785 self.assertIn('DOWN', output)
3786 self.assertNotIn('192.168.10', output)
cd65d067 3787
3e2f7c46
YW
3788 # add one bound interface. The interface will be up.
3789 check_output('ip link add dummy98 type dummy')
3790 check_output('ip link set dummy98 up')
95e1fbba 3791 self.wait_online('test1:routable')
3e2f7c46
YW
3792 output = check_output('ip address show test1')
3793 print(output)
3794 self.assertIn('UP,LOWER_UP', output)
3795 self.assertIn('inet 192.168.10.30/24 brd 192.168.10.255 scope global test1', output)
3796
3797 # add another bound interface. The interface is still up.
cefd6b3d
ZJS
3798 check_output('ip link add dummy99 type dummy')
3799 check_output('ip link set dummy99 up')
fcd79988 3800 self.wait_operstate('dummy99', 'degraded', setup_state='unmanaged')
371810d1 3801 output = check_output('ip address show test1')
cd65d067 3802 print(output)
3e2f7c46
YW
3803 self.assertIn('UP,LOWER_UP', output)
3804 self.assertIn('inet 192.168.10.30/24 brd 192.168.10.255 scope global test1', output)
cd65d067 3805
3e2f7c46 3806 # remove one of the bound interfaces. The interface is still up
a962d857 3807 remove_link('dummy98')
371810d1 3808 output = check_output('ip address show test1')
cd65d067 3809 print(output)
3e2f7c46
YW
3810 self.assertIn('UP,LOWER_UP', output)
3811 self.assertIn('inet 192.168.10.30/24 brd 192.168.10.255 scope global test1', output)
cd65d067 3812
3e2f7c46 3813 # bring down the remaining bound interface. The interface will be down.
bc942f69 3814 check_output('ip link set dummy99 down')
3e2f7c46
YW
3815 self.wait_operstate('test1', 'off')
3816 self.wait_address_dropped('test1', r'192.168.10', ipv='-4', timeout_sec=10)
371810d1 3817 output = check_output('ip address show test1')
cd65d067 3818 print(output)
3e2f7c46
YW
3819 self.assertNotIn('UP,LOWER_UP', output)
3820 self.assertIn('DOWN', output)
3821 self.assertNotIn('192.168.10', output)
cd65d067 3822
3e2f7c46 3823 # bring up the bound interface. The interface will be up.
bc942f69 3824 check_output('ip link set dummy99 up')
95e1fbba 3825 self.wait_online('test1:routable')
371810d1 3826 output = check_output('ip address show test1')
cd65d067 3827 print(output)
3e2f7c46
YW
3828 self.assertIn('UP,LOWER_UP', output)
3829 self.assertIn('inet 192.168.10.30/24 brd 192.168.10.255 scope global test1', output)
3830
3831 # remove the remaining bound interface. The interface will be down.
3832 remove_link('dummy99')
3833 self.wait_operstate('test1', 'off')
3834 self.wait_address_dropped('test1', r'192.168.10', ipv='-4', timeout_sec=10)
3835 output = check_output('ip address show test1')
3836 print(output)
3837 self.assertNotIn('UP,LOWER_UP', output)
3838 self.assertIn('DOWN', output)
3839 self.assertNotIn('192.168.10', output)
3840
3841 # re-add one bound interface. The interface will be up.
3842 check_output('ip link add dummy98 type dummy')
3843 check_output('ip link set dummy98 up')
95e1fbba 3844 self.wait_online('test1:routable')
3e2f7c46
YW
3845 output = check_output('ip address show test1')
3846 print(output)
3847 self.assertIn('UP,LOWER_UP', output)
3848 self.assertIn('inet 192.168.10.30/24 brd 192.168.10.255 scope global test1', output)
cd65d067 3849
a962d857 3850 def _test_activation_policy(self, interface, test):
2236d75d
DS
3851 conffile = '25-activation-policy.network'
3852 if test:
3853 conffile = f'{conffile}.d/{test}.conf'
ee9918ae 3854 if interface == 'vlan99':
a962d857
YW
3855 copy_network_unit('21-vlan.netdev', '21-vlan-test1.network')
3856 copy_network_unit('11-dummy.netdev', conffile, copy_dropins=False)
2236d75d
DS
3857 start_networkd()
3858
3859 always = test.startswith('always')
ebb5036f 3860 initial_up = test != 'manual' and not test.endswith('down') # note: default is up
2236d75d
DS
3861 expect_up = initial_up
3862 next_up = not expect_up
3863
cfbdc438 3864 if test.endswith('down'):
ee9918ae 3865 self.wait_activated(interface)
cfbdc438 3866
2236d75d
DS
3867 for iteration in range(4):
3868 with self.subTest(iteration=iteration, expect_up=expect_up):
3869 operstate = 'routable' if expect_up else 'off'
618da3e7 3870 setup_state = 'configured' if expect_up else ('configuring' if iteration == 0 else None)
ee9918ae 3871 self.wait_operstate(interface, operstate, setup_state=setup_state, setup_timeout=20)
2236d75d
DS
3872
3873 if expect_up:
ee9918ae
YW
3874 self.assertIn('UP', check_output(f'ip link show {interface}'))
3875 self.assertIn('192.168.10.30/24', check_output(f'ip address show {interface}'))
3876 self.assertIn('default via 192.168.10.1', check_output(f'ip route show dev {interface}'))
2236d75d 3877 else:
ee9918ae 3878 self.assertIn('DOWN', check_output(f'ip link show {interface}'))
2236d75d
DS
3879
3880 if next_up:
ee9918ae 3881 check_output(f'ip link set dev {interface} up')
2236d75d 3882 else:
ee9918ae 3883 check_output(f'ip link set dev {interface} down')
2236d75d
DS
3884 expect_up = initial_up if always else next_up
3885 next_up = not next_up
073ad7ed
YW
3886 if always:
3887 time.sleep(1)
2236d75d 3888
2236d75d 3889 def test_activation_policy(self):
a962d857 3890 first = True
ee9918ae 3891 for interface in ['test1', 'vlan99']:
a962d857
YW
3892 for test in ['up', 'always-up', 'manual', 'always-down', 'down', '']:
3893 if first:
3894 first = False
3895 else:
3896 self.tearDown()
3897
3898 print(f'### test_activation_policy(interface={interface}, test={test})')
3899 with self.subTest(interface=interface, test=test):
3900 self._test_activation_policy(interface, test)
2236d75d 3901
61764fe4 3902 def _test_activation_policy_required_for_online(self, policy, required):
61764fe4
DS
3903 conffile = '25-activation-policy.network'
3904 units = ['11-dummy.netdev', '12-dummy.netdev', '12-dummy.network', conffile]
3905 if policy:
3906 units += [f'{conffile}.d/{policy}.conf']
3907 if required:
3908 units += [f'{conffile}.d/required-{required}.conf']
a962d857 3909 copy_network_unit(*units, copy_dropins=False)
61764fe4
DS
3910 start_networkd()
3911
cfbdc438
YW
3912 if policy.endswith('down'):
3913 self.wait_activated('test1')
3914
61764fe4
DS
3915 if policy.endswith('down') or policy == 'manual':
3916 self.wait_operstate('test1', 'off', setup_state='configuring')
3917 else:
95e1fbba 3918 self.wait_online('test1')
61764fe4
DS
3919
3920 if policy == 'always-down':
3921 # if always-down, required for online is forced to no
3922 expected = False
3923 elif required:
3924 # otherwise if required for online is specified, it should match that
3925 expected = required == 'yes'
3926 elif policy:
3927 # otherwise if only policy specified, required for online defaults to
3928 # true if policy is up, always-up, or bound
3929 expected = policy.endswith('up') or policy == 'bound'
3930 else:
3931 # default is true, if neither are specified
3932 expected = True
3933
10d670a3 3934 output = networkctl_status('test1')
61764fe4
DS
3935 print(output)
3936
3937 yesno = 'yes' if expected else 'no'
3938 self.assertRegex(output, f'Required For Online: {yesno}')
3939
61764fe4 3940 def test_activation_policy_required_for_online(self):
a962d857 3941 first = True
61764fe4
DS
3942 for policy in ['up', 'always-up', 'manual', 'always-down', 'down', 'bound', '']:
3943 for required in ['yes', 'no', '']:
a962d857
YW
3944 if first:
3945 first = False
3946 else:
3947 self.tearDown()
3948
3949 print(f'### test_activation_policy_required_for_online(policy={policy}, required={required})')
61764fe4
DS
3950 with self.subTest(policy=policy, required=required):
3951 self._test_activation_policy_required_for_online(policy, required)
3952
fdcd1ec5 3953 def test_domain(self):
a962d857 3954 copy_network_unit('12-dummy.netdev', '24-search-domain.network')
2cf6fdff 3955 start_networkd()
95e1fbba 3956 self.wait_online('dummy98:routable')
fdcd1ec5 3957
10d670a3 3958 output = networkctl_status('dummy98')
fdcd1ec5
YW
3959 print(output)
3960 self.assertRegex(output, 'Address: 192.168.42.100')
3961 self.assertRegex(output, 'DNS: 192.168.42.1')
3962 self.assertRegex(output, 'Search Domains: one')
3963
1e498853 3964 def test_keep_configuration_static(self):
1e498853
YW
3965 check_output('ip link add name dummy98 type dummy')
3966 check_output('ip address add 10.1.2.3/16 dev dummy98')
3967 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
3968 output = check_output('ip address show dummy98')
3969 print(output)
3970 self.assertRegex(output, 'inet 10.1.2.3/16 scope global dummy98')
3971 self.assertRegex(output, 'inet 10.2.3.4/16 scope global dynamic dummy98')
3972 output = check_output('ip route show dev dummy98')
3973 print(output)
3974
a962d857 3975 copy_network_unit('24-keep-configuration-static.network')
2cf6fdff 3976 start_networkd()
95e1fbba 3977 self.wait_online('dummy98:routable')
1e498853
YW
3978
3979 output = check_output('ip address show dummy98')
3980 print(output)
3981 self.assertRegex(output, 'inet 10.1.2.3/16 scope global dummy98')
3982 self.assertNotRegex(output, 'inet 10.2.3.4/16 scope global dynamic dummy98')
3983
78265b5b 3984 def check_nexthop(self, manage_foreign_nexthops, first):
95e1fbba 3985 self.wait_online('veth99:routable', 'veth-peer:routable', 'dummy98:routable')
086bcf5d 3986
e7660b9a
YW
3987 output = check_output('ip nexthop list dev veth99')
3988 print(output)
78265b5b
YW
3989 if first:
3990 self.assertIn('id 1 via 192.168.5.1 dev veth99', output)
3991 self.assertIn('id 2 via 2001:1234:5:8f63::2 dev veth99', output)
3992 else:
3993 self.assertIn('id 6 via 192.168.5.1 dev veth99', output)
3994 self.assertIn('id 7 via 2001:1234:5:8f63::2 dev veth99', output)
e7660b9a
YW
3995 self.assertIn('id 3 dev veth99', output)
3996 self.assertIn('id 4 dev veth99', output)
78265b5b
YW
3997 if first:
3998 self.assertRegex(output, 'id 5 via 192.168.10.1 dev veth99 .*onlink')
3999 else:
4000 self.assertIn('id 5 via 192.168.5.3 dev veth99', output)
4001 self.assertNotRegex(output, 'id 5 via 192.168.5.3 dev veth99 .*onlink')
e7660b9a 4002 self.assertIn('id 8 via fe80:0:222:4dff:ff:ff:ff:ff dev veth99', output)
41231f26
YW
4003 if manage_foreign_nexthops:
4004 self.assertRegex(output, r'id [0-9]* via 192.168.5.2 dev veth99')
086bcf5d 4005
e7660b9a
YW
4006 output = check_output('ip nexthop list dev dummy98')
4007 print(output)
78265b5b
YW
4008 if first:
4009 self.assertIn('id 20 via 192.168.20.1 dev dummy98', output)
4010 else:
4011 self.assertIn('id 21 via 192.168.20.1 dev dummy98', output)
41231f26
YW
4012 if manage_foreign_nexthops:
4013 self.assertNotIn('id 42 via 192.168.20.2 dev dummy98', output)
4014 else:
4015 self.assertIn('id 42 via 192.168.20.2 dev dummy98', output)
69a91c70 4016
e7660b9a
YW
4017 # kernel manages blackhole nexthops on lo
4018 output = check_output('ip nexthop list dev lo')
4019 print(output)
78265b5b
YW
4020 if first:
4021 self.assertIn('id 6 blackhole', output)
4022 self.assertIn('id 7 blackhole', output)
4023 else:
4024 self.assertIn('id 1 blackhole', output)
4025 self.assertIn('id 2 blackhole', output)
cee0f719 4026
e7660b9a 4027 # group nexthops are shown with -0 option
78265b5b
YW
4028 if first:
4029 output = check_output('ip -0 nexthop list id 21')
4030 print(output)
4031 self.assertRegex(output, r'id 21 group (1,3/20|20/1,3)')
4032 else:
4033 output = check_output('ip -0 nexthop list id 20')
4034 print(output)
4035 self.assertRegex(output, r'id 20 group (5,3/21|21/5,3)')
cee0f719 4036
e7660b9a
YW
4037 output = check_output('ip route show dev veth99 10.10.10.10')
4038 print(output)
78265b5b
YW
4039 if first:
4040 self.assertEqual('10.10.10.10 nhid 1 via 192.168.5.1 proto static', output)
4041 else:
4042 self.assertEqual('10.10.10.10 nhid 6 via 192.168.5.1 proto static', output)
e2d9bc5c 4043
e7660b9a
YW
4044 output = check_output('ip route show dev veth99 10.10.10.11')
4045 print(output)
78265b5b
YW
4046 if first:
4047 self.assertEqual('10.10.10.11 nhid 2 via inet6 2001:1234:5:8f63::2 proto static', output)
4048 else:
4049 self.assertEqual('10.10.10.11 nhid 7 via inet6 2001:1234:5:8f63::2 proto static', output)
cee0f719 4050
e7660b9a
YW
4051 output = check_output('ip route show dev veth99 10.10.10.12')
4052 print(output)
78265b5b
YW
4053 if first:
4054 self.assertEqual('10.10.10.12 nhid 5 via 192.168.10.1 proto static onlink', output)
4055 else:
4056 self.assertEqual('10.10.10.12 nhid 5 via 192.168.5.3 proto static', output)
69a91c70 4057
e7660b9a
YW
4058 output = check_output('ip -6 route show dev veth99 2001:1234:5:8f62::1')
4059 print(output)
78265b5b
YW
4060 if first:
4061 self.assertEqual('2001:1234:5:8f62::1 nhid 2 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium', output)
4062 else:
4063 self.assertEqual('2001:1234:5:8f62::1 nhid 7 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium', output)
9c8f90d0 4064
e7660b9a
YW
4065 output = check_output('ip route show 10.10.10.13')
4066 print(output)
78265b5b
YW
4067 if first:
4068 self.assertEqual('blackhole 10.10.10.13 nhid 6 dev lo proto static', output)
4069 else:
4070 self.assertEqual('blackhole 10.10.10.13 nhid 1 dev lo proto static', output)
9c8f90d0 4071
e7660b9a
YW
4072 output = check_output('ip -6 route show 2001:1234:5:8f62::2')
4073 print(output)
78265b5b
YW
4074 if first:
4075 self.assertEqual('blackhole 2001:1234:5:8f62::2 nhid 7 dev lo proto static metric 1024 pref medium', output)
4076 else:
4077 self.assertEqual('blackhole 2001:1234:5:8f62::2 nhid 2 dev lo proto static metric 1024 pref medium', output)
9c8f90d0 4078
e7660b9a
YW
4079 output = check_output('ip route show 10.10.10.14')
4080 print(output)
78265b5b
YW
4081 if first:
4082 self.assertIn('10.10.10.14 nhid 21 proto static', output)
4083 self.assertIn('nexthop via 192.168.5.1 dev veth99 weight 3', output)
4084 else:
4085 self.assertIn('10.10.10.14 nhid 20 proto static', output)
4086 self.assertIn('nexthop via 192.168.5.3 dev veth99 weight 3', output)
e7660b9a 4087 self.assertIn('nexthop via 192.168.20.1 dev dummy98 weight 1', output)
146726b2 4088
b5edf3a9
YW
4089 output = networkctl_json()
4090 check_json(output)
4091 self.assertNotIn('"Destination":[10.10.10.14]', output)
e7660b9a 4092
41231f26
YW
4093 def _test_nexthop(self, manage_foreign_nexthops):
4094 if not manage_foreign_nexthops:
4095 copy_networkd_conf_dropin('networkd-manage-foreign-nexthops-no.conf')
4096
4097 check_output('ip link add dummy98 type dummy')
4098 check_output('ip link set dummy98 up')
4099 check_output('ip address add 192.168.20.20/24 dev dummy98')
4100 check_output('ip nexthop add id 42 via 192.168.20.2 dev dummy98')
4101
78265b5b
YW
4102 copy_network_unit('25-nexthop-1.network', '25-veth.netdev', '25-veth-peer.network',
4103 '12-dummy.netdev', '25-nexthop-dummy-1.network')
9c8f90d0
YW
4104 start_networkd()
4105
78265b5b
YW
4106 self.check_nexthop(manage_foreign_nexthops, first=True)
4107
4108 remove_network_unit('25-nexthop-1.network', '25-nexthop-dummy-1.network')
4109 copy_network_unit('25-nexthop-2.network', '25-nexthop-dummy-2.network')
4110 networkctl_reload()
4111 self.check_nexthop(manage_foreign_nexthops, first=False)
69a91c70 4112
78265b5b 4113 remove_network_unit('25-nexthop-2.network')
a962d857
YW
4114 copy_network_unit('25-nexthop-nothing.network')
4115 networkctl_reload()
95e1fbba 4116 self.wait_online('veth99:routable', 'veth-peer:routable')
932e157b 4117
9947c7ba
YW
4118 output = check_output('ip nexthop list dev veth99')
4119 print(output)
4120 self.assertEqual(output, '')
4121 output = check_output('ip nexthop list dev lo')
4122 print(output)
4123 self.assertEqual(output, '')
4124
78265b5b
YW
4125 remove_network_unit('25-nexthop-nothing.network', '25-nexthop-dummy-2.network')
4126 copy_network_unit('25-nexthop-1.network', '25-nexthop-dummy-1.network')
2ec0e95e
YW
4127 # Of course, networkctl_reconfigure() below is unnecessary in normal operation, but it is intentional
4128 # here to test reconfiguring with different .network files does not trigger race.
4129 # See also comments in link_drop_requests().
4130 networkctl_reconfigure('dummy98') # reconfigured with 25-nexthop-dummy-2.network
4131 networkctl_reload() # reconfigured with 25-nexthop-dummy-1.network
9947c7ba 4132
78265b5b 4133 self.check_nexthop(manage_foreign_nexthops, first=True)
932e157b 4134
f9b5c276
YW
4135 # Remove nexthop with ID 20
4136 check_output('ip nexthop del id 20')
4137 copy_network_unit('11-dummy.netdev', '25-nexthop-test1.network')
4138 networkctl_reload()
4139
4140 # 25-nexthop-test1.network requests a route with nexthop ID 21,
4141 # which is silently removed by the kernel when nexthop with ID 20 is removed in the above,
4142 # hence test1 should be stuck in the configuring state.
4143 self.wait_operstate('test1', operstate='routable', setup_state='configuring')
4144
4145 # Wait for a while, and check if the interface is still in the configuring state.
4146 time.sleep(1)
4147 output = networkctl_status('test1')
4148 self.assertIn('State: routable (configuring)', output)
4149
b5edf3a9
YW
4150 # Check if the route which needs nexthop 20 and 21 are forgotten.
4151 output = networkctl_json()
4152 check_json(output)
4153 self.assertNotIn('"Destination":[10.10.10.14]', output)
4154
f9b5c276
YW
4155 # Reconfigure the interface that has nexthop with ID 20 and 21,
4156 # then the route requested by test1 can be configured.
4157 networkctl_reconfigure('dummy98')
95e1fbba 4158 self.wait_online('test1:routable')
f9b5c276
YW
4159
4160 # Check if the requested route actually configured.
4161 output = check_output('ip route show 10.10.11.10')
4162 print(output)
4163 self.assertIn('10.10.11.10 nhid 21 proto static', output)
4164 self.assertIn('nexthop via 192.168.5.1 dev veth99 weight 3', output)
4165 self.assertIn('nexthop via 192.168.20.1 dev dummy98 weight 1', output)
4166
a962d857 4167 remove_link('veth99')
9947c7ba
YW
4168 time.sleep(2)
4169
4170 output = check_output('ip nexthop list dev lo')
4171 print(output)
4172 self.assertEqual(output, '')
4173
41231f26
YW
4174 @expectedFailureIfNexthopIsNotAvailable()
4175 def test_nexthop(self):
4176 first = True
4177 for manage_foreign_nexthops in [True, False]:
4178 if first:
4179 first = False
4180 else:
4181 self.tearDown()
4182
4183 print(f'### test_nexthop(manage_foreign_nexthops={manage_foreign_nexthops})')
4184 with self.subTest(manage_foreign_nexthops=manage_foreign_nexthops):
4185 self._test_nexthop(manage_foreign_nexthops)
4186
23b38192
YW
4187class NetworkdTCTests(unittest.TestCase, Utilities):
4188
4189 def setUp(self):
4190 setup_common()
4191
4192 def tearDown(self):
4193 tear_down_common()
4194
4c7d13f4
YW
4195 @expectedFailureIfModuleIsNotAvailable('sch_cake')
4196 def test_qdisc_cake(self):
4197 copy_network_unit('25-qdisc-cake.network', '12-dummy.netdev')
ef3c8a92 4198 start_networkd()
95e1fbba 4199 self.wait_online('dummy98:routable')
ef3c8a92 4200
4c7d13f4 4201 output = check_output('tc qdisc show dev dummy98')
f1de1eb3 4202 print(output)
4c7d13f4
YW
4203 self.assertIn('qdisc cake 3a: root', output)
4204 self.assertIn('bandwidth 500Mbit', output)
4205 self.assertIn('autorate-ingress', output)
4206 self.assertIn('diffserv8', output)
4207 self.assertIn('dual-dsthost', output)
4208 self.assertIn(' nat', output)
4209 self.assertIn(' wash', output)
4210 self.assertIn(' split-gso', output)
4211 self.assertIn(' raw', output)
4212 self.assertIn(' atm', output)
4213 self.assertIn('overhead 128', output)
4214 self.assertIn('mpu 20', output)
4215 self.assertIn('fwmark 0xff00', output)
77d5f36d
YW
4216 self.assertIn('rtt 1s', output)
4217 self.assertIn('ack-filter-aggressive', output)
4c7d13f4
YW
4218
4219 @expectedFailureIfModuleIsNotAvailable('sch_codel')
4220 def test_qdisc_codel(self):
4221 copy_network_unit('25-qdisc-codel.network', '12-dummy.netdev')
4222 start_networkd()
95e1fbba 4223 self.wait_online('dummy98:routable')
f1de1eb3 4224
ef3c8a92
YW
4225 output = check_output('tc qdisc show dev dummy98')
4226 print(output)
4c7d13f4
YW
4227 self.assertRegex(output, 'qdisc codel 33: root')
4228 self.assertRegex(output, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn')
f1de1eb3 4229
4c7d13f4
YW
4230 @expectedFailureIfModuleIsNotAvailable('sch_drr')
4231 def test_qdisc_drr(self):
4232 copy_network_unit('25-qdisc-drr.network', '12-dummy.netdev')
4233 start_networkd()
95e1fbba 4234 self.wait_online('dummy98:routable')
f1de1eb3 4235
4c7d13f4
YW
4236 output = check_output('tc qdisc show dev dummy98')
4237 print(output)
4238 self.assertRegex(output, 'qdisc drr 2: root')
4239 output = check_output('tc class show dev dummy98')
4240 print(output)
4241 self.assertRegex(output, 'class drr 2:30 root quantum 2000b')
ef3c8a92 4242
4c7d13f4
YW
4243 @expectedFailureIfModuleIsNotAvailable('sch_ets')
4244 def test_qdisc_ets(self):
4245 copy_network_unit('25-qdisc-ets.network', '12-dummy.netdev')
4246 start_networkd()
95e1fbba 4247 self.wait_online('dummy98:routable')
4c7d13f4
YW
4248
4249 output = check_output('tc qdisc show dev dummy98')
4250 print(output)
4251
4252 self.assertRegex(output, 'qdisc ets 3a: root')
4253 self.assertRegex(output, 'bands 10 strict 3')
4254 self.assertRegex(output, 'quanta 1 2 3 4 5')
4255 self.assertRegex(output, 'priomap 3 4 5 6 7')
4256
4257 @expectedFailureIfModuleIsNotAvailable('sch_fq')
4258 def test_qdisc_fq(self):
4259 copy_network_unit('25-qdisc-fq.network', '12-dummy.netdev')
4260 start_networkd()
95e1fbba 4261 self.wait_online('dummy98:routable')
0baddbd5 4262
4c7d13f4
YW
4263 output = check_output('tc qdisc show dev dummy98')
4264 print(output)
4265 self.assertRegex(output, 'qdisc fq 32: root')
a05a6e8b
YW
4266 self.assertRegex(output, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
4267 self.assertRegex(output, 'quantum 1500')
4268 self.assertRegex(output, 'initial_quantum 13000')
4269 self.assertRegex(output, 'maxrate 1Mbit')
ab9dc1db 4270
4c7d13f4
YW
4271 @expectedFailureIfModuleIsNotAvailable('sch_fq_codel')
4272 def test_qdisc_fq_codel(self):
4273 copy_network_unit('25-qdisc-fq_codel.network', '12-dummy.netdev')
4274 start_networkd()
95e1fbba 4275 self.wait_online('dummy98:routable')
ab9dc1db 4276
4c7d13f4
YW
4277 output = check_output('tc qdisc show dev dummy98')
4278 print(output)
4279 self.assertRegex(output, 'qdisc fq_codel 34: root')
7887e580 4280 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 4281
4c7d13f4
YW
4282 @expectedFailureIfModuleIsNotAvailable('sch_fq_pie')
4283 def test_qdisc_fq_pie(self):
4284 copy_network_unit('25-qdisc-fq_pie.network', '12-dummy.netdev')
4285 start_networkd()
95e1fbba 4286 self.wait_online('dummy98:routable')
ab9dc1db 4287
4c7d13f4
YW
4288 output = check_output('tc qdisc show dev dummy98')
4289 print(output)
3d55b5a9 4290
4c7d13f4
YW
4291 self.assertRegex(output, 'qdisc fq_pie 3a: root')
4292 self.assertRegex(output, 'limit 200000p')
bc0769c9 4293
4c7d13f4
YW
4294 @expectedFailureIfModuleIsNotAvailable('sch_gred')
4295 def test_qdisc_gred(self):
4296 copy_network_unit('25-qdisc-gred.network', '12-dummy.netdev')
4297 start_networkd()
95e1fbba 4298 self.wait_online('dummy98:routable')
4c7d13f4
YW
4299
4300 output = check_output('tc qdisc show dev dummy98')
4301 print(output)
4302 self.assertRegex(output, 'qdisc gred 38: root')
95edcf3f
YW
4303 self.assertRegex(output, 'vqs 12 default 10 grio')
4304
4c7d13f4
YW
4305 @expectedFailureIfModuleIsNotAvailable('sch_hhf')
4306 def test_qdisc_hhf(self):
4307 copy_network_unit('25-qdisc-hhf.network', '12-dummy.netdev')
4308 start_networkd()
95e1fbba 4309 self.wait_online('dummy98:routable')
4c7d13f4
YW
4310
4311 output = check_output('tc qdisc show dev dummy98')
4312 print(output)
4313 self.assertRegex(output, 'qdisc hhf 3a: root')
4314 self.assertRegex(output, 'limit 1022p')
4315
4316 @expectedFailureIfModuleIsNotAvailable('sch_htb')
4317 def test_qdisc_htb_fifo(self):
4318 copy_network_unit('25-qdisc-htb-fifo.network', '12-dummy.netdev')
4319 start_networkd()
95e1fbba 4320 self.wait_online('dummy98:routable')
4c7d13f4
YW
4321
4322 output = check_output('tc qdisc show dev dummy98')
4323 print(output)
4324 self.assertRegex(output, 'qdisc htb 2: root')
4325 self.assertRegex(output, r'default (0x30|30)')
4326
4327 self.assertRegex(output, 'qdisc pfifo 37: parent 2:37')
4328 self.assertRegex(output, 'limit 100000p')
f2c5c129 4329
7b1a31a3
YW
4330 self.assertRegex(output, 'qdisc bfifo 3a: parent 2:3a')
4331 self.assertRegex(output, 'limit 1000000')
4332
73136507
YW
4333 self.assertRegex(output, 'qdisc pfifo_head_drop 3b: parent 2:3b')
4334 self.assertRegex(output, 'limit 1023p')
4335
41bb371b
YW
4336 self.assertRegex(output, 'qdisc pfifo_fast 3c: parent 2:3c')
4337
2ee7e54b 4338 output = check_output('tc -d class show dev dummy98')
ab9dc1db 4339 print(output)
8e2449a5
YW
4340 # Here (:|prio) is a workaround for a bug in iproute2 v6.2.0 caused by
4341 # https://github.com/shemminger/iproute2/commit/010a8388aea11e767ba3a2506728b9ad9760df0e
4342 # which is fixed in v6.3.0 by
4343 # https://github.com/shemminger/iproute2/commit/4e0e56e0ef05387f7f5d8ab41fe6ec6a1897b26d
4344 self.assertRegex(output, 'class htb 2:37 root leaf 37(:|prio) ')
4345 self.assertRegex(output, 'class htb 2:3a root leaf 3a(:|prio) ')
4346 self.assertRegex(output, 'class htb 2:3b root leaf 3b(:|prio) ')
4347 self.assertRegex(output, 'class htb 2:3c root leaf 3c(:|prio) ')
2ee7e54b
YW
4348 self.assertRegex(output, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit')
4349 self.assertRegex(output, 'burst 123456')
4350 self.assertRegex(output, 'cburst 123457')
0baddbd5 4351
4c7d13f4
YW
4352 @expectedFailureIfModuleIsNotAvailable('sch_ingress')
4353 def test_qdisc_ingress(self):
4354 copy_network_unit('25-qdisc-clsact.network', '12-dummy.netdev',
4355 '25-qdisc-ingress.network', '11-dummy.netdev')
557fa421 4356 start_networkd()
95e1fbba 4357 self.wait_online('dummy98:routable', 'test1:routable')
557fa421
YW
4358
4359 output = check_output('tc qdisc show dev dummy98')
4360 print(output)
4c7d13f4 4361 self.assertRegex(output, 'qdisc clsact')
557fa421 4362
891ff963
YW
4363 output = check_output('tc qdisc show dev test1')
4364 print(output)
4c7d13f4 4365 self.assertRegex(output, 'qdisc ingress')
891ff963 4366
4c7d13f4
YW
4367 @expectedFailureIfModuleIsNotAvailable('sch_netem')
4368 def test_qdisc_netem(self):
4369 copy_network_unit('25-qdisc-netem.network', '12-dummy.netdev',
4370 '25-qdisc-netem-compat.network', '11-dummy.netdev')
3d55b5a9 4371 start_networkd()
95e1fbba 4372 self.wait_online('dummy98:routable', 'test1:routable')
3d55b5a9
YW
4373
4374 output = check_output('tc qdisc show dev dummy98')
4375 print(output)
4c7d13f4
YW
4376 self.assertRegex(output, 'qdisc netem 30: root')
4377 self.assertRegex(output, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
4378
4379 output = check_output('tc qdisc show dev test1')
4380 print(output)
4381 self.assertRegex(output, 'qdisc netem [0-9a-f]*: root')
4382 self.assertRegex(output, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
3d55b5a9 4383
854f9899 4384 @expectedFailureIfModuleIsNotAvailable('sch_pie')
be94e591 4385 def test_qdisc_pie(self):
a962d857 4386 copy_network_unit('25-qdisc-pie.network', '12-dummy.netdev')
be94e591 4387 start_networkd()
95e1fbba 4388 self.wait_online('dummy98:routable')
be94e591
YW
4389
4390 output = check_output('tc qdisc show dev dummy98')
4391 print(output)
4392 self.assertRegex(output, 'qdisc pie 3a: root')
4393 self.assertRegex(output, 'limit 200000')
4394
4c7d13f4
YW
4395 @expectedFailureIfModuleIsNotAvailable('sch_qfq')
4396 def test_qdisc_qfq(self):
4397 copy_network_unit('25-qdisc-qfq.network', '12-dummy.netdev')
970ab1fc 4398 start_networkd()
95e1fbba 4399 self.wait_online('dummy98:routable')
970ab1fc
YW
4400
4401 output = check_output('tc qdisc show dev dummy98')
4402 print(output)
4c7d13f4
YW
4403 self.assertRegex(output, 'qdisc qfq 2: root')
4404 output = check_output('tc class show dev dummy98')
4405 print(output)
4406 self.assertRegex(output, 'class qfq 2:30 root weight 2 maxpkt 16000')
4407 self.assertRegex(output, 'class qfq 2:31 root weight 10 maxpkt 8000')
970ab1fc 4408
4c7d13f4
YW
4409 @expectedFailureIfModuleIsNotAvailable('sch_sfb')
4410 def test_qdisc_sfb(self):
4411 copy_network_unit('25-qdisc-sfb.network', '12-dummy.netdev')
b753e835 4412 start_networkd()
95e1fbba 4413 self.wait_online('dummy98:routable')
b753e835
YW
4414
4415 output = check_output('tc qdisc show dev dummy98')
4416 print(output)
4c7d13f4
YW
4417 self.assertRegex(output, 'qdisc sfb 39: root')
4418 self.assertRegex(output, 'limit 200000')
1578266b 4419
4c7d13f4
YW
4420 @expectedFailureIfModuleIsNotAvailable('sch_sfq')
4421 def test_qdisc_sfq(self):
4422 copy_network_unit('25-qdisc-sfq.network', '12-dummy.netdev')
4423 start_networkd()
95e1fbba 4424 self.wait_online('dummy98:routable')
b753e835 4425
4c7d13f4
YW
4426 output = check_output('tc qdisc show dev dummy98')
4427 print(output)
4428 self.assertRegex(output, 'qdisc sfq 36: root')
4429 self.assertRegex(output, 'perturb 5sec')
4430
4431 @expectedFailureIfModuleIsNotAvailable('sch_tbf')
4432 def test_qdisc_tbf(self):
4433 copy_network_unit('25-qdisc-tbf.network', '12-dummy.netdev')
1578266b 4434 start_networkd()
95e1fbba 4435 self.wait_online('dummy98:routable')
1578266b
YW
4436
4437 output = check_output('tc qdisc show dev dummy98')
4438 print(output)
4c7d13f4
YW
4439 self.assertRegex(output, 'qdisc tbf 35: root')
4440 self.assertRegex(output, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms')
1578266b 4441
4c7d13f4
YW
4442 @expectedFailureIfModuleIsNotAvailable('sch_teql')
4443 def test_qdisc_teql(self):
4444 call_quiet('rmmod sch_teql')
4445
4446 copy_network_unit('25-qdisc-teql.network', '12-dummy.netdev')
4447 start_networkd()
4448 self.wait_links('dummy98')
4449 check_output('modprobe sch_teql max_equalizers=2')
95e1fbba 4450 self.wait_online('dummy98:routable')
4c7d13f4
YW
4451
4452 output = check_output('tc qdisc show dev dummy98')
4453 print(output)
4454 self.assertRegex(output, 'qdisc teql1 31: root')
1578266b 4455
336d18f0 4456class NetworkdStateFileTests(unittest.TestCase, Utilities):
336d18f0
YW
4457
4458 def setUp(self):
a962d857 4459 setup_common()
336d18f0
YW
4460
4461 def tearDown(self):
a962d857 4462 tear_down_common()
336d18f0
YW
4463
4464 def test_state_file(self):
a962d857 4465 copy_network_unit('12-dummy.netdev', '25-state-file-tests.network')
336d18f0 4466 start_networkd()
95e1fbba 4467 self.wait_online('dummy98:routable')
336d18f0 4468
f91b2340 4469 # make link state file updated
10d670a3 4470 resolvectl('revert', 'dummy98')
336d18f0 4471
10d670a3 4472 check_json(networkctl_json())
94f0bd62 4473
1a8e1d78
YW
4474 output = read_link_state_file('dummy98')
4475 print(output)
4476 self.assertIn('IPV4_ADDRESS_STATE=routable', output)
4477 self.assertIn('IPV6_ADDRESS_STATE=routable', output)
4478 self.assertIn('ADMIN_STATE=configured', output)
4479 self.assertIn('OPER_STATE=routable', output)
4480 self.assertIn('REQUIRED_FOR_ONLINE=yes', output)
4481 self.assertIn('REQUIRED_OPER_STATE_FOR_ONLINE=routable', output)
4482 self.assertIn('REQUIRED_FAMILY_FOR_ONLINE=both', output)
4483 self.assertIn('ACTIVATION_POLICY=up', output)
4484 self.assertIn('NETWORK_FILE=/run/systemd/network/25-state-file-tests.network', output)
4485 self.assertIn('DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com', output)
4486 self.assertIn('NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org', output)
4487 self.assertIn('DOMAINS=hogehoge', output)
4488 self.assertIn('ROUTE_DOMAINS=foofoo', output)
4489 self.assertIn('LLMNR=no', output)
4490 self.assertIn('MDNS=yes', output)
4491 self.assertIn('DNSSEC=no', output)
336d18f0 4492
10d670a3
YW
4493 resolvectl('dns', 'dummy98', '10.10.10.12#ccc.com', '10.10.10.13', '1111:2222::3333')
4494 resolvectl('domain', 'dummy98', 'hogehogehoge', '~foofoofoo')
4495 resolvectl('llmnr', 'dummy98', 'yes')
4496 resolvectl('mdns', 'dummy98', 'no')
4497 resolvectl('dnssec', 'dummy98', 'yes')
4498 timedatectl('ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org')
336d18f0 4499
10d670a3 4500 check_json(networkctl_json())
94f0bd62 4501
1a8e1d78
YW
4502 output = read_link_state_file('dummy98')
4503 print(output)
4504 self.assertIn('DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333', output)
4505 self.assertIn('NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org', output)
4506 self.assertIn('DOMAINS=hogehogehoge', output)
4507 self.assertIn('ROUTE_DOMAINS=foofoofoo', output)
4508 self.assertIn('LLMNR=yes', output)
4509 self.assertIn('MDNS=no', output)
4510 self.assertIn('DNSSEC=yes', output)
336d18f0 4511
10d670a3 4512 timedatectl('revert', 'dummy98')
336d18f0 4513
10d670a3 4514 check_json(networkctl_json())
94f0bd62 4515
1a8e1d78
YW
4516 output = read_link_state_file('dummy98')
4517 print(output)
4518 self.assertIn('DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333', output)
4519 self.assertIn('NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org', output)
4520 self.assertIn('DOMAINS=hogehogehoge', output)
4521 self.assertIn('ROUTE_DOMAINS=foofoofoo', output)
4522 self.assertIn('LLMNR=yes', output)
4523 self.assertIn('MDNS=no', output)
4524 self.assertIn('DNSSEC=yes', output)
336d18f0 4525
10d670a3 4526 resolvectl('revert', 'dummy98')
336d18f0 4527
10d670a3 4528 check_json(networkctl_json())
94f0bd62 4529
1a8e1d78
YW
4530 output = read_link_state_file('dummy98')
4531 print(output)
4532 self.assertIn('DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com', output)
4533 self.assertIn('NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org', output)
4534 self.assertIn('DOMAINS=hogehoge', output)
4535 self.assertIn('ROUTE_DOMAINS=foofoo', output)
4536 self.assertIn('LLMNR=no', output)
4537 self.assertIn('MDNS=yes', output)
4538 self.assertIn('DNSSEC=no', output)
336d18f0 4539
ee3cbfdb
YW
4540 def test_address_state(self):
4541 copy_network_unit('12-dummy.netdev', '12-dummy-no-address.network')
4542 start_networkd()
4543
95e1fbba 4544 self.wait_online('dummy98:degraded')
ee3cbfdb
YW
4545
4546 output = read_link_state_file('dummy98')
4547 self.assertIn('IPV4_ADDRESS_STATE=off', output)
4548 self.assertIn('IPV6_ADDRESS_STATE=degraded', output)
4549
4550 # with a routable IPv4 address
4551 check_output('ip address add 10.1.2.3/16 dev dummy98')
95e1fbba
YW
4552 self.wait_online('dummy98:routable', ipv4=True)
4553 self.wait_online('dummy98:routable')
ee3cbfdb
YW
4554
4555 output = read_link_state_file('dummy98')
4556 self.assertIn('IPV4_ADDRESS_STATE=routable', output)
4557 self.assertIn('IPV6_ADDRESS_STATE=degraded', output)
4558
4559 check_output('ip address del 10.1.2.3/16 dev dummy98')
4560
4561 # with a routable IPv6 address
4562 check_output('ip address add 2002:da8:1:0:1034:56ff:fe78:9abc/64 dev dummy98')
95e1fbba
YW
4563 self.wait_online('dummy98:routable', ipv6=True)
4564 self.wait_online('dummy98:routable')
ee3cbfdb
YW
4565
4566 output = read_link_state_file('dummy98')
4567 self.assertIn('IPV4_ADDRESS_STATE=off', output)
4568 self.assertIn('IPV6_ADDRESS_STATE=routable', output)
4569
be68c2c9 4570class NetworkdBondTests(unittest.TestCase, Utilities):
c3a8853f
YW
4571
4572 def setUp(self):
a962d857 4573 setup_common()
c3a8853f
YW
4574
4575 def tearDown(self):
a962d857 4576 tear_down_common()
c3a8853f 4577
b06469a6
YW
4578 def test_bond_keep_master(self):
4579 check_output('ip link add bond199 type bond mode active-backup')
4580 check_output('ip link add dummy98 type dummy')
4581 check_output('ip link set dummy98 master bond199')
4582
a962d857 4583 copy_network_unit('23-keep-master.network')
b06469a6 4584 start_networkd()
95e1fbba 4585 self.wait_online('dummy98:enslaved')
b06469a6
YW
4586
4587 output = check_output('ip -d link show bond199')
4588 print(output)
4589 self.assertRegex(output, 'active_slave dummy98')
4590
4591 output = check_output('ip -d link show dummy98')
4592 print(output)
4593 self.assertRegex(output, 'master bond199')
4594
c2990ec3 4595 def test_bond_active_slave(self):
a962d857 4596 copy_network_unit('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2cf6fdff 4597 start_networkd()
95e1fbba 4598 self.wait_online('dummy98:enslaved', 'bond199:degraded')
c2990ec3 4599
371810d1 4600 output = check_output('ip -d link show bond199')
c2990ec3 4601 print(output)
b448fc0a 4602 self.assertIn('active_slave dummy98', output)
c2990ec3 4603
2bb1d3c1
YW
4604 # test case for issue #31165.
4605 since = datetime.datetime.now()
4606 networkctl_reconfigure('dummy98')
95e1fbba 4607 self.wait_online('dummy98:enslaved', 'bond199:degraded')
2bb1d3c1
YW
4608 self.assertNotIn('dummy98: Bringing link down', read_networkd_log(since=since))
4609
c2990ec3 4610 def test_bond_primary_slave(self):
a962d857 4611 copy_network_unit('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2cf6fdff 4612 start_networkd()
95e1fbba 4613 self.wait_online('dummy98:enslaved', 'bond199:degraded')
c2990ec3 4614
371810d1 4615 output = check_output('ip -d link show bond199')
c2990ec3 4616 print(output)
b448fc0a
YW
4617 self.assertIn('primary dummy98', output)
4618
4619 # for issue #25627
4620 mkdir_p(os.path.join(network_unit_dir, '23-bond199.network.d'))
4621 for mac in ['00:11:22:33:44:55', '00:11:22:33:44:56']:
4622 with open(os.path.join(network_unit_dir, '23-bond199.network.d/mac.conf'), mode='w', encoding='utf-8') as f:
4623 f.write(f'[Link]\nMACAddress={mac}\n')
4624
4625 networkctl_reload()
95e1fbba 4626 self.wait_online('dummy98:enslaved', 'bond199:degraded')
b448fc0a
YW
4627
4628 output = check_output('ip -d link show bond199')
4629 print(output)
4630 self.assertIn(f'link/ether {mac}', output)
c2990ec3 4631
cc3e488c 4632 def test_bond_operstate(self):
a962d857
YW
4633 copy_network_unit('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
4634 '25-bond99.network', '25-bond-slave.network')
2cf6fdff 4635 start_networkd()
95e1fbba 4636 self.wait_online('dummy98:enslaved', 'test1:enslaved', 'bond99:routable')
c3a8853f 4637
371810d1 4638 output = check_output('ip -d link show dummy98')
c3a8853f 4639 print(output)
cc3e488c 4640 self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
c3a8853f 4641
371810d1 4642 output = check_output('ip -d link show test1')
c3a8853f
YW
4643 print(output)
4644 self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
4645
371810d1 4646 output = check_output('ip -d link show bond99')
c3a8853f
YW
4647 print(output)
4648 self.assertRegex(output, 'MASTER,UP,LOWER_UP')
4649
19cf3143
DS
4650 self.wait_operstate('dummy98', 'enslaved')
4651 self.wait_operstate('test1', 'enslaved')
4652 self.wait_operstate('bond99', 'routable')
c3a8853f 4653
cefd6b3d 4654 check_output('ip link set dummy98 down')
c3a8853f 4655
19cf3143
DS
4656 self.wait_operstate('dummy98', 'off')
4657 self.wait_operstate('test1', 'enslaved')
cf4dbd84 4658 self.wait_operstate('bond99', 'routable')
c3a8853f 4659
cefd6b3d 4660 check_output('ip link set dummy98 up')
c3a8853f 4661
19cf3143
DS
4662 self.wait_operstate('dummy98', 'enslaved')
4663 self.wait_operstate('test1', 'enslaved')
4664 self.wait_operstate('bond99', 'routable')
c3a8853f 4665
cefd6b3d
ZJS
4666 check_output('ip link set dummy98 down')
4667 check_output('ip link set test1 down')
cc3e488c 4668
19cf3143
DS
4669 self.wait_operstate('dummy98', 'off')
4670 self.wait_operstate('test1', 'off')
2700d2c7 4671
a4632dc7 4672 if not self.wait_operstate('bond99', 'no-carrier', setup_timeout=30, fail_assert=False):
2700d2c7
YW
4673 # Huh? Kernel does not recognize that all slave interfaces are down?
4674 # Let's confirm that networkd's operstate is consistent with ip's result.
4675 self.assertNotRegex(output, 'NO-CARRIER')
cc3e488c 4676
be68c2c9 4677class NetworkdBridgeTests(unittest.TestCase, Utilities):
8d17c386 4678
1f0e3109 4679 def setUp(self):
a962d857 4680 setup_common()
1f0e3109
SS
4681
4682 def tearDown(self):
a962d857 4683 tear_down_common()
1f0e3109 4684
9540f8e2
YW
4685 def test_bridge_mac_none(self):
4686 copy_network_unit('12-dummy-mac.netdev', '26-bridge-mac-slave.network',
4687 '26-bridge-mac.netdev', '26-bridge-mac-master.network', '26-bridge-mac.link')
4688 start_networkd()
95e1fbba 4689 self.wait_online('dummy98:enslaved', 'bridge99:degraded')
9540f8e2
YW
4690
4691 output = check_output('ip link show dev dummy98')
4692 print(output)
4693 self.assertIn('link/ether 12:34:56:78:9a:01', output)
4694
4695 output = check_output('ip link show dev bridge99')
4696 print(output)
4697 self.assertIn('link/ether 12:34:56:78:9a:01', output)
4698
6f943798 4699 def test_bridge_vlan(self):
a962d857 4700 copy_network_unit('11-dummy.netdev', '26-bridge-vlan-slave.network',
60f4b2c5
YW
4701 '26-bridge.netdev', '26-bridge-vlan-master.network',
4702 copy_dropins=False)
6f943798 4703 start_networkd()
95e1fbba 4704 self.wait_online('test1:enslaved', 'bridge99:degraded')
6f943798
YW
4705
4706 output = check_output('bridge vlan show dev test1')
4707 print(output)
60f4b2c5
YW
4708 # check if the default VID is removed
4709 self.assertNotIn('1 Egress Untagged', output)
4710 for i in range(1000, 3000):
4711 if i == 1010:
4712 self.assertIn(f'{i} PVID', output)
4713 elif i in range(1012, 1016) or i in range(1103, 1109):
4714 self.assertIn(f'{i} Egress Untagged', output)
4715 elif i in range(1008, 1014) or i in range(1100, 1111):
4716 self.assertIn(f'{i}', output)
4717 else:
4718 self.assertNotIn(f'{i}', output)
4719
4720 output = check_output('bridge vlan show dev bridge99')
4721 print(output)
4722 # check if the default VID is removed
4723 self.assertNotIn('1 Egress Untagged', output)
4724 for i in range(1000, 3000):
4725 if i == 1020:
4726 self.assertIn(f'{i} PVID', output)
4727 elif i in range(1022, 1026) or i in range(1203, 1209):
4728 self.assertIn(f'{i} Egress Untagged', output)
4729 elif i in range(1018, 1024) or i in range(1200, 1211):
4730 self.assertIn(f'{i}', output)
4731 else:
4732 self.assertNotIn(f'{i}', output)
4733
4734 # Change vlan IDs
4735 copy_network_unit('26-bridge-vlan-slave.network.d/10-override.conf',
4736 '26-bridge-vlan-master.network.d/10-override.conf')
4737 networkctl_reload()
95e1fbba 4738 self.wait_online('test1:enslaved', 'bridge99:degraded')
60f4b2c5
YW
4739
4740 output = check_output('bridge vlan show dev test1')
4741 print(output)
4742 for i in range(1000, 3000):
4743 if i == 2010:
4744 self.assertIn(f'{i} PVID', output)
4745 elif i in range(2012, 2016) or i in range(2103, 2109):
4746 self.assertIn(f'{i} Egress Untagged', output)
4747 elif i in range(2008, 2014) or i in range(2100, 2111):
4748 self.assertIn(f'{i}', output)
4749 else:
4750 self.assertNotIn(f'{i}', output)
4751
4752 output = check_output('bridge vlan show dev bridge99')
4753 print(output)
4754 for i in range(1000, 3000):
4755 if i == 2020:
4756 self.assertIn(f'{i} PVID', output)
4757 elif i in range(2022, 2026) or i in range(2203, 2209):
4758 self.assertIn(f'{i} Egress Untagged', output)
4759 elif i in range(2018, 2024) or i in range(2200, 2211):
4760 self.assertIn(f'{i}', output)
4761 else:
4762 self.assertNotIn(f'{i}', output)
4763
4764 # Remove several vlan IDs
4765 copy_network_unit('26-bridge-vlan-slave.network.d/20-override.conf',
4766 '26-bridge-vlan-master.network.d/20-override.conf')
4767 networkctl_reload()
95e1fbba 4768 self.wait_online('test1:enslaved', 'bridge99:degraded')
60f4b2c5
YW
4769
4770 output = check_output('bridge vlan show dev test1')
4771 print(output)
4772 for i in range(1000, 3000):
4773 if i == 2010:
4774 self.assertIn(f'{i} PVID', output)
4775 elif i in range(2012, 2016):
4776 self.assertIn(f'{i} Egress Untagged', output)
4777 elif i in range(2008, 2014):
4778 self.assertIn(f'{i}', output)
4779 else:
4780 self.assertNotIn(f'{i}', output)
4781
4782 output = check_output('bridge vlan show dev bridge99')
4783 print(output)
4784 for i in range(1000, 3000):
4785 if i == 2020:
4786 self.assertIn(f'{i} PVID', output)
4787 elif i in range(2022, 2026):
4788 self.assertIn(f'{i} Egress Untagged', output)
4789 elif i in range(2018, 2024):
4790 self.assertIn(f'{i}', output)
4791 else:
4792 self.assertNotIn(f'{i}', output)
4793
4794 # Remove all vlan IDs
4795 copy_network_unit('26-bridge-vlan-slave.network.d/30-override.conf',
4796 '26-bridge-vlan-master.network.d/30-override.conf')
4797 networkctl_reload()
95e1fbba 4798 self.wait_online('test1:enslaved', 'bridge99:degraded')
60f4b2c5
YW
4799
4800 output = check_output('bridge vlan show dev test1')
4801 print(output)
4802 self.assertNotIn('PVID', output)
4803 for i in range(1000, 3000):
4804 self.assertNotIn(f'{i}', output)
6f943798
YW
4805
4806 output = check_output('bridge vlan show dev bridge99')
4807 print(output)
60f4b2c5
YW
4808 self.assertNotIn('PVID', output)
4809 for i in range(1000, 3000):
4810 self.assertNotIn(f'{i}', output)
6f943798 4811
988b0660 4812 def test_bridge_vlan_issue_20373(self):
a962d857
YW
4813 copy_network_unit('11-dummy.netdev', '26-bridge-vlan-slave-issue-20373.network',
4814 '26-bridge-issue-20373.netdev', '26-bridge-vlan-master-issue-20373.network',
4815 '21-vlan.netdev', '21-vlan.network')
988b0660 4816 start_networkd()
95e1fbba 4817 self.wait_online('test1:enslaved', 'bridge99:degraded', 'vlan99:routable')
988b0660
YW
4818
4819 output = check_output('bridge vlan show dev test1')
4820 print(output)
4821 self.assertIn('100 PVID Egress Untagged', output)
4822 self.assertIn('560', output)
4823 self.assertIn('600', output)
4824
4825 output = check_output('bridge vlan show dev bridge99')
4826 print(output)
4827 self.assertIn('1 PVID Egress Untagged', output)
4828 self.assertIn('100', output)
4829 self.assertIn('600', output)
4830
cc0276cc 4831 def test_bridge_mdb(self):
a962d857
YW
4832 copy_network_unit('11-dummy.netdev', '26-bridge-mdb-slave.network',
4833 '26-bridge.netdev', '26-bridge-mdb-master.network')
cc0276cc 4834 start_networkd()
95e1fbba 4835 self.wait_online('test1:enslaved', 'bridge99:degraded')
cc0276cc
YW
4836
4837 output = check_output('bridge mdb show dev bridge99')
4838 print(output)
4839 self.assertRegex(output, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064')
4840 self.assertRegex(output, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065')
4841
9f773037 4842 # Old kernel may not support bridge MDB entries on bridge master
a962d857 4843 if call_quiet('bridge mdb add dev bridge99 port bridge99 grp 224.0.1.3 temp vid 4068') == 0:
9f773037
YW
4844 self.assertRegex(output, 'dev bridge99 port bridge99 grp ff02:aaaa:fee5::1:4 temp *vid 4066')
4845 self.assertRegex(output, 'dev bridge99 port bridge99 grp 224.0.1.2 temp *vid 4067')
4846
b06469a6
YW
4847 def test_bridge_keep_master(self):
4848 check_output('ip link add bridge99 type bridge')
4849 check_output('ip link set bridge99 up')
4850 check_output('ip link add dummy98 type dummy')
4851 check_output('ip link set dummy98 master bridge99')
4852
a962d857 4853 copy_network_unit('23-keep-master.network')
b06469a6 4854 start_networkd()
95e1fbba 4855 self.wait_online('dummy98:enslaved')
b06469a6
YW
4856
4857 output = check_output('ip -d link show dummy98')
4858 print(output)
4859 self.assertRegex(output, 'master bridge99')
4860 self.assertRegex(output, 'bridge')
4861
4862 output = check_output('bridge -d link show dummy98')
4863 print(output)
a962d857
YW
4864 self.check_bridge_port_attr('bridge99', 'dummy98', 'path_cost', '400')
4865 self.check_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode', '1')
4866 self.check_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave', '1')
4867 self.check_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood', '1')
4868 self.check_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood', '0')
b06469a6 4869 # CONFIG_BRIDGE_IGMP_SNOOPING=y
a962d857
YW
4870 self.check_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast', '1', allow_enoent=True)
4871 self.check_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress', '1', allow_enoent=True)
4872 self.check_bridge_port_attr('bridge99', 'dummy98', 'learning', '0')
4873 self.check_bridge_port_attr('bridge99', 'dummy98', 'priority', '23')
3f504b89
YW
4874 self.check_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard', '0')
4875 self.check_bridge_port_attr('bridge99', 'dummy98', 'root_block', '0')
b06469a6 4876
1f0e3109 4877 def test_bridge_property(self):
a962d857
YW
4878 copy_network_unit('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
4879 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
4880 '25-bridge99.network')
2cf6fdff 4881 start_networkd()
95e1fbba 4882 self.wait_online('dummy98:enslaved', 'test1:enslaved', 'bridge99:routable')
1f0e3109 4883
21d0ed68
YW
4884 output = check_output('ip -d link show bridge99')
4885 print(output)
4886 self.assertIn('mtu 9000 ', output)
4887
371810d1 4888 output = check_output('ip -d link show test1')
1f0e3109 4889 print(output)
21d0ed68
YW
4890 self.assertIn('master bridge99 ', output)
4891 self.assertIn('bridge_slave', output)
4892 self.assertIn('mtu 9000 ', output)
1f0e3109 4893
371810d1 4894 output = check_output('ip -d link show dummy98')
1f0e3109 4895 print(output)
21d0ed68
YW
4896 self.assertIn('master bridge99 ', output)
4897 self.assertIn('bridge_slave', output)
4898 self.assertIn('mtu 9000 ', output)
1f0e3109 4899
371810d1 4900 output = check_output('ip addr show bridge99')
1f0e3109 4901 print(output)
21d0ed68 4902 self.assertIn('192.168.0.15/24', output)
1f0e3109 4903
371810d1 4904 output = check_output('bridge -d link show dummy98')
1f0e3109 4905 print(output)
a962d857
YW
4906 self.check_bridge_port_attr('bridge99', 'dummy98', 'path_cost', '400')
4907 self.check_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode', '1')
4908 self.check_bridge_port_attr('bridge99', 'dummy98', 'isolated', '1')
4909 self.check_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave', '1')
4910 self.check_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood', '1')
4911 self.check_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood', '0')
5424fd95 4912 # CONFIG_BRIDGE_IGMP_SNOOPING=y
a962d857
YW
4913 self.check_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast', '1', allow_enoent=True)
4914 self.check_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress', '1', allow_enoent=True)
4915 self.check_bridge_port_attr('bridge99', 'dummy98', 'learning', '0')
4916 self.check_bridge_port_attr('bridge99', 'dummy98', 'priority', '23')
3f504b89
YW
4917 self.check_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard', '0')
4918 self.check_bridge_port_attr('bridge99', 'dummy98', 'root_block', '0')
4d7ed14f 4919
5424fd95
YW
4920 output = check_output('bridge -d link show test1')
4921 print(output)
a962d857 4922 self.check_bridge_port_attr('bridge99', 'test1', 'priority', '0')
1f0e3109 4923
371810d1 4924 check_output('ip address add 192.168.0.16/24 dev bridge99')
371810d1 4925 output = check_output('ip addr show bridge99')
2be6c5d2 4926 print(output)
21d0ed68 4927 self.assertIn('192.168.0.16/24', output)
2be6c5d2 4928
e3cbaeab
YW
4929 # for issue #6088
4930 print('### ip -6 route list table all dev bridge99')
4931 output = check_output('ip -6 route list table all dev bridge99')
4932 print(output)
beb75dd3 4933 self.assertRegex(output, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
e3cbaeab 4934
a962d857 4935 remove_link('test1')
cf4dbd84 4936 self.wait_operstate('bridge99', 'routable')
2be6c5d2 4937
21d0ed68
YW
4938 output = check_output('ip -d link show bridge99')
4939 print(output)
4940 self.assertIn('mtu 9000 ', output)
4941
4942 output = check_output('ip -d link show dummy98')
4943 print(output)
4944 self.assertIn('master bridge99 ', output)
4945 self.assertIn('bridge_slave', output)
4946 self.assertIn('mtu 9000 ', output)
804b6cd2 4947
21d0ed68 4948 remove_link('dummy98')
19cf3143 4949 self.wait_operstate('bridge99', 'no-carrier')
2be6c5d2 4950
21d0ed68
YW
4951 output = check_output('ip -d link show bridge99')
4952 print(output)
4953 # When no carrier, the kernel may reset the MTU
4954 self.assertIn('NO-CARRIER', output)
4955
371810d1 4956 output = check_output('ip address show bridge99')
804b6cd2 4957 print(output)
21d0ed68
YW
4958 self.assertNotIn('192.168.0.15/24', output)
4959 self.assertIn('192.168.0.16/24', output) # foreign address is kept
804b6cd2 4960
e3cbaeab
YW
4961 print('### ip -6 route list table all dev bridge99')
4962 output = check_output('ip -6 route list table all dev bridge99')
4963 print(output)
beb75dd3 4964 self.assertRegex(output, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
e3cbaeab 4965
21d0ed68 4966 check_output('ip link add dummy98 type dummy')
95e1fbba 4967 self.wait_online('dummy98:enslaved', 'bridge99:routable')
21d0ed68
YW
4968
4969 output = check_output('ip -d link show bridge99')
4970 print(output)
4971 self.assertIn('mtu 9000 ', output)
4972
4973 output = check_output('ip -d link show dummy98')
4974 print(output)
4975 self.assertIn('master bridge99 ', output)
4976 self.assertIn('bridge_slave', output)
4977 self.assertIn('mtu 9000 ', output)
4978
0fc0d85f 4979 def test_bridge_configure_without_carrier(self):
a962d857
YW
4980 copy_network_unit('26-bridge.netdev', '26-bridge-configure-without-carrier.network',
4981 '11-dummy.netdev')
0fc0d85f
DS
4982 start_networkd()
4983
4984 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
4985 for test in ['no-slave', 'add-slave', 'slave-up', 'slave-no-carrier', 'slave-carrier', 'slave-down']:
4986 with self.subTest(test=test):
4987 if test == 'no-slave':
4988 # bridge has no slaves; it's up but *might* not have carrier
001c07cf 4989 self.wait_operstate('bridge99', operstate=r'(no-carrier|routable)', setup_state=None, setup_timeout=30)
0fc0d85f
DS
4990 # due to a bug in the kernel, newly-created bridges are brought up
4991 # *with* carrier, unless they have had any setting changed; e.g.
4992 # their mac set, priority set, etc. Then, they will lose carrier
4993 # as soon as a (down) slave interface is added, and regain carrier
4994 # again once the slave interface is brought up.
4995 #self.check_link_attr('bridge99', 'carrier', '0')
4996 elif test == 'add-slave':
4997 # add slave to bridge, but leave it down; bridge is definitely no-carrier
4998 self.check_link_attr('test1', 'operstate', 'down')
4999 check_output('ip link set dev test1 master bridge99')
001c07cf 5000 self.wait_operstate('bridge99', operstate='no-carrier', setup_state=None)
0fc0d85f
DS
5001 self.check_link_attr('bridge99', 'carrier', '0')
5002 elif test == 'slave-up':
5003 # bring up slave, which will have carrier; bridge gains carrier
5004 check_output('ip link set dev test1 up')
95e1fbba 5005 self.wait_online('bridge99:routable')
0fc0d85f
DS
5006 self.check_link_attr('bridge99', 'carrier', '1')
5007 elif test == 'slave-no-carrier':
5008 # drop slave carrier; bridge loses carrier
5009 check_output('ip link set dev test1 carrier off')
95e1fbba 5010 self.wait_online('bridge99:no-carrier:no-carrier')
0fc0d85f
DS
5011 self.check_link_attr('bridge99', 'carrier', '0')
5012 elif test == 'slave-carrier':
5013 # restore slave carrier; bridge gains carrier
5014 check_output('ip link set dev test1 carrier on')
95e1fbba 5015 self.wait_online('bridge99:routable')
0fc0d85f
DS
5016 self.check_link_attr('bridge99', 'carrier', '1')
5017 elif test == 'slave-down':
5018 # bring down slave; bridge loses carrier
5019 check_output('ip link set dev test1 down')
95e1fbba 5020 self.wait_online('bridge99:no-carrier:no-carrier')
0fc0d85f
DS
5021 self.check_link_attr('bridge99', 'carrier', '0')
5022
10d670a3 5023 output = networkctl_status('bridge99')
0fc0d85f
DS
5024 self.assertRegex(output, '10.1.2.3')
5025 self.assertRegex(output, '10.1.2.1')
5026
804b6cd2 5027 def test_bridge_ignore_carrier_loss(self):
a962d857
YW
5028 copy_network_unit('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
5029 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
5030 '25-bridge99-ignore-carrier-loss.network')
2cf6fdff 5031 start_networkd()
95e1fbba 5032 self.wait_online('dummy98:enslaved', 'test1:enslaved', 'bridge99:routable')
804b6cd2 5033
371810d1 5034 check_output('ip address add 192.168.0.16/24 dev bridge99')
a962d857 5035 remove_link('test1', 'dummy98')
804b6cd2
YW
5036 time.sleep(3)
5037
371810d1 5038 output = check_output('ip address show bridge99')
804b6cd2
YW
5039 print(output)
5040 self.assertRegex(output, 'NO-CARRIER')
5041 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
5042 self.assertRegex(output, 'inet 192.168.0.16/24 scope global secondary bridge99')
5043
6609924c 5044 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self):
a962d857
YW
5045 copy_network_unit('26-bridge.netdev', '26-bridge-slave-interface-1.network',
5046 '25-bridge99-ignore-carrier-loss.network')
2cf6fdff 5047 start_networkd()
95e1fbba 5048 self.wait_online('bridge99:no-carrier')
6609924c 5049
90e3bcbd
YW
5050 for trial in range(4):
5051 check_output('ip link add dummy98 type dummy')
5052 check_output('ip link set dummy98 up')
5053 if trial < 3:
a962d857 5054 remove_link('dummy98')
6609924c 5055
95e1fbba 5056 self.wait_online('bridge99:routable', 'dummy98:enslaved')
6609924c 5057
371810d1 5058 output = check_output('ip address show bridge99')
6609924c
YW
5059 print(output)
5060 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
5061
371810d1 5062 output = check_output('ip rule list table 100')
6609924c 5063 print(output)
c4f7a347 5064 self.assertIn('from all to 8.8.8.8 lookup 100', output)
6609924c 5065
a03ff4c0 5066class NetworkdSRIOVTests(unittest.TestCase, Utilities):
a03ff4c0
YW
5067
5068 def setUp(self):
a962d857 5069 setup_common()
a03ff4c0
YW
5070
5071 def tearDown(self):
a962d857 5072 tear_down_common()
a03ff4c0
YW
5073
5074 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable()
5075 def test_sriov(self):
d8746f16
YW
5076 copy_network_unit('25-default.link', '25-sriov.network')
5077
a962d857 5078 call('modprobe netdevsim')
a03ff4c0 5079
d45476ef 5080 with open('/sys/bus/netdevsim/new_device', mode='w', encoding='utf-8') as f:
a03ff4c0
YW
5081 f.write('99 1')
5082
a962d857 5083 with open('/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs', mode='w', encoding='utf-8') as f:
a03ff4c0
YW
5084 f.write('3')
5085
a03ff4c0 5086 start_networkd()
95e1fbba 5087 self.wait_online('eni99np1:routable')
a03ff4c0
YW
5088
5089 output = check_output('ip link show dev eni99np1')
5090 print(output)
5091 self.assertRegex(output,
5092 '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 *'
5093 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
5094 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
a962d857 5095 )
a03ff4c0 5096
1e8e9730
YW
5097 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable()
5098 def test_sriov_udev(self):
a962d857 5099 copy_network_unit('25-sriov.link', '25-sriov-udev.network')
1e8e9730 5100
a962d857
YW
5101 call('modprobe netdevsim')
5102
d45476ef 5103 with open('/sys/bus/netdevsim/new_device', mode='w', encoding='utf-8') as f:
1e8e9730
YW
5104 f.write('99 1')
5105
5106 start_networkd()
95e1fbba 5107 self.wait_online('eni99np1:routable')
1e8e9730 5108
b95d35b5
YW
5109 # the name eni99np1 may be an alternative name.
5110 ifname = link_resolve('eni99np1')
5111
1e8e9730
YW
5112 output = check_output('ip link show dev eni99np1')
5113 print(output)
5114 self.assertRegex(output,
5115 '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 *'
5116 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
5117 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
a962d857 5118 )
1e8e9730
YW
5119 self.assertNotIn('vf 3', output)
5120 self.assertNotIn('vf 4', output)
5121
a962d857 5122 with open(os.path.join(network_unit_dir, '25-sriov.link'), mode='a', encoding='utf-8') as f:
1e8e9730
YW
5123 f.write('[Link]\nSR-IOVVirtualFunctions=4\n')
5124
32ab27af 5125 udev_reload()
b95d35b5 5126 check_output(*udevadm_cmd, 'trigger', '--action=add', '--settle', f'/sys/devices/netdevsim99/net/{ifname}')
1e8e9730
YW
5127
5128 output = check_output('ip link show dev eni99np1')
5129 print(output)
5130 self.assertRegex(output,
5131 '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 *'
5132 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
5133 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off\n *'
5134 'vf 3'
a962d857 5135 )
1e8e9730
YW
5136 self.assertNotIn('vf 4', output)
5137
a962d857 5138 with open(os.path.join(network_unit_dir, '25-sriov.link'), mode='a', encoding='utf-8') as f:
1e8e9730
YW
5139 f.write('[Link]\nSR-IOVVirtualFunctions=\n')
5140
32ab27af 5141 udev_reload()
b95d35b5 5142 check_output(*udevadm_cmd, 'trigger', '--action=add', '--settle', f'/sys/devices/netdevsim99/net/{ifname}')
1e8e9730
YW
5143
5144 output = check_output('ip link show dev eni99np1')
5145 print(output)
5146 self.assertRegex(output,
5147 '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 *'
5148 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
5149 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off\n *'
5150 'vf 3'
a962d857 5151 )
1e8e9730
YW
5152 self.assertNotIn('vf 4', output)
5153
a962d857 5154 with open(os.path.join(network_unit_dir, '25-sriov.link'), mode='a', encoding='utf-8') as f:
1e8e9730
YW
5155 f.write('[Link]\nSR-IOVVirtualFunctions=2\n')
5156
32ab27af 5157 udev_reload()
b95d35b5 5158 check_output(*udevadm_cmd, 'trigger', '--action=add', '--settle', f'/sys/devices/netdevsim99/net/{ifname}')
1e8e9730
YW
5159
5160 output = check_output('ip link show dev eni99np1')
5161 print(output)
5162 self.assertRegex(output,
5163 '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 *'
5164 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off'
a962d857 5165 )
1e8e9730
YW
5166 self.assertNotIn('vf 2', output)
5167 self.assertNotIn('vf 3', output)
5168 self.assertNotIn('vf 4', output)
5169
a962d857 5170 with open(os.path.join(network_unit_dir, '25-sriov.link'), mode='a', encoding='utf-8') as f:
1e8e9730
YW
5171 f.write('[Link]\nSR-IOVVirtualFunctions=\n')
5172
32ab27af 5173 udev_reload()
b95d35b5 5174 check_output(*udevadm_cmd, 'trigger', '--action=add', '--settle', f'/sys/devices/netdevsim99/net/{ifname}')
1e8e9730
YW
5175
5176 output = check_output('ip link show dev eni99np1')
5177 print(output)
5178 self.assertRegex(output,
5179 '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 *'
5180 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
5181 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
a962d857 5182 )
1e8e9730
YW
5183 self.assertNotIn('vf 3', output)
5184 self.assertNotIn('vf 4', output)
5185
be68c2c9 5186class NetworkdLLDPTests(unittest.TestCase, Utilities):
1f0e3109
SS
5187
5188 def setUp(self):
a962d857 5189 setup_common()
1f0e3109
SS
5190
5191 def tearDown(self):
a962d857 5192 tear_down_common()
1f0e3109
SS
5193
5194 def test_lldp(self):
a962d857 5195 copy_network_unit('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
2cf6fdff 5196 start_networkd()
95e1fbba 5197 self.wait_online('veth99:degraded', 'veth-peer:degraded')
1f0e3109 5198
f0d87798
YW
5199 for trial in range(10):
5200 if trial > 0:
5201 time.sleep(1)
5202
10d670a3 5203 output = networkctl('lldp')
f0d87798
YW
5204 print(output)
5205 if re.search(r'veth99 .* veth-peer', output):
5206 break
5207 else:
5208 self.fail()
1f0e3109 5209
be68c2c9 5210class NetworkdRATests(unittest.TestCase, Utilities):
1f0e3109
SS
5211
5212 def setUp(self):
a962d857 5213 setup_common()
1f0e3109
SS
5214
5215 def tearDown(self):
a962d857 5216 tear_down_common()
1f0e3109
SS
5217
5218 def test_ipv6_prefix_delegation(self):
a962d857 5219 copy_network_unit('25-veth.netdev', '25-ipv6-prefix.network', '25-ipv6-prefix-veth.network')
c742d7e8
TM
5220 self.setup_nftset('addr6', 'ipv6_addr')
5221 self.setup_nftset('network6', 'ipv6_addr', 'flags interval;')
5222 self.setup_nftset('ifindex', 'iface_index')
2cf6fdff 5223 start_networkd()
95e1fbba 5224 self.wait_online('veth99:routable', 'veth-peer:degraded')
1f0e3109 5225
10d670a3 5226 output = resolvectl('dns', 'veth99')
41fd8fe7
YW
5227 print(output)
5228 self.assertRegex(output, 'fe80::')
5229 self.assertRegex(output, '2002:da8:1::1')
5230
10d670a3 5231 output = resolvectl('domain', 'veth99')
80762ccc
YW
5232 print(output)
5233 self.assertIn('hogehoge.test', output)
5234
10d670a3 5235 output = networkctl_status('veth99')
1f0e3109
SS
5236 print(output)
5237 self.assertRegex(output, '2002:da8:1:0')
5238
a4640bed
TM
5239 self.check_netlabel('veth99', '2002:da8:1::/64')
5240 self.check_netlabel('veth99', '2002:da8:2::/64')
5241
c742d7e8
TM
5242 self.check_nftset('addr6', '2002:da8:1:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*')
5243 self.check_nftset('addr6', '2002:da8:2:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*')
5244 self.check_nftset('network6', '2002:da8:1::/64')
5245 self.check_nftset('network6', '2002:da8:2::/64')
5246 self.check_nftset('ifindex', 'veth99')
5247
5248 self.teardown_nftset('addr6', 'network6', 'ifindex')
5249
6d1cea7b 5250 def check_ipv6_token_static(self):
95e1fbba 5251 self.wait_online('veth99:routable', 'veth-peer:degraded')
b241fa00 5252
10d670a3 5253 output = networkctl_status('veth99')
b241fa00
KF
5254 print(output)
5255 self.assertRegex(output, '2002:da8:1:0:1a:2b:3c:4d')
68248f43
YW
5256 self.assertRegex(output, '2002:da8:1:0:fa:de:ca:fe')
5257 self.assertRegex(output, '2002:da8:2:0:1a:2b:3c:4d')
5258 self.assertRegex(output, '2002:da8:2:0:fa:de:ca:fe')
b241fa00 5259
6d1cea7b
YW
5260 def test_ipv6_token_static(self):
5261 copy_network_unit('25-veth.netdev', '25-ipv6-prefix.network', '25-ipv6-prefix-veth-token-static.network')
5262 start_networkd()
5263
5264 self.check_ipv6_token_static()
5265
5266 for _ in range(20):
5267 check_output('ip link set veth99 down')
5268 check_output('ip link set veth99 up')
5269
5270 self.check_ipv6_token_static()
5271
5272 for _ in range(20):
5273 check_output('ip link set veth99 down')
5274 time.sleep(random.uniform(0, 0.1))
5275 check_output('ip link set veth99 up')
5276 time.sleep(random.uniform(0, 0.1))
5277
5278 self.check_ipv6_token_static()
5279
68248f43 5280 def test_ipv6_token_prefixstable(self):
a962d857 5281 copy_network_unit('25-veth.netdev', '25-ipv6-prefix.network', '25-ipv6-prefix-veth-token-prefixstable.network')
c24c83dc 5282 start_networkd()
95e1fbba 5283 self.wait_online('veth99:routable', 'veth-peer:degraded')
c24c83dc 5284
10d670a3 5285 output = networkctl_status('veth99')
c24c83dc 5286 print(output)
7a2e124b
YW
5287 self.assertIn('2002:da8:1:0:b47e:7975:fc7a:7d6e', output)
5288 self.assertIn('2002:da8:2:0:1034:56ff:fe78:9abc', output) # EUI64
c24c83dc 5289
68248f43 5290 def test_ipv6_token_prefixstable_without_address(self):
a962d857 5291 copy_network_unit('25-veth.netdev', '25-ipv6-prefix.network', '25-ipv6-prefix-veth-token-prefixstable-without-address.network')
87bbebea 5292 start_networkd()
95e1fbba 5293 self.wait_online('veth99:routable', 'veth-peer:degraded')
87bbebea 5294
10d670a3 5295 output = networkctl_status('veth99')
87bbebea 5296 print(output)
7a2e124b
YW
5297 self.assertIn('2002:da8:1:0:b47e:7975:fc7a:7d6e', output)
5298 self.assertIn('2002:da8:2:0:f689:561a:8eda:7443', output)
87bbebea 5299
29fbbb13
YW
5300 def check_router_hop_limit(self, hop_limit):
5301 self.wait_route('client', rf'default via fe80::1034:56ff:fe78:9a99 proto ra .* hoplimit {hop_limit}', ipv='-6', timeout_sec=10)
5302
5303 output = check_output('ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99')
5304 print(output)
5305 self.assertIn(f'hoplimit {hop_limit}', output)
5306
5307 self.check_ipv6_sysctl_attr('client', 'hop_limit', f'{hop_limit}')
5308
5309 def test_router_hop_limit(self):
5310 copy_network_unit('25-veth-client.netdev',
5311 '25-veth-router.netdev',
5312 '26-bridge.netdev',
5313 '25-veth-bridge.network',
5314 '25-veth-client.network',
5315 '25-veth-router-hop-limit.network',
5316 '25-bridge99.network')
5317 start_networkd()
5318 self.wait_online('client-p:enslaved',
5319 'router:degraded', 'router-p:enslaved',
5320 'bridge99:routable')
5321
5322 self.check_router_hop_limit(42)
5323
5324 with open(os.path.join(network_unit_dir, '25-veth-router-hop-limit.network'), mode='a', encoding='utf-8') as f:
5325 f.write('\n[IPv6SendRA]\nHopLimit=43\n')
5326
5327 networkctl_reload()
5328
5329 self.check_router_hop_limit(43)
5330
bb80f633
YW
5331 def test_router_preference(self):
5332 copy_network_unit('25-veth-client.netdev',
5333 '25-veth-router-high.netdev',
5334 '25-veth-router-low.netdev',
5335 '26-bridge.netdev',
5336 '25-veth-bridge.network',
5337 '25-veth-client.network',
5338 '25-veth-router-high.network',
5339 '25-veth-router-low.network',
5340 '25-bridge99.network')
5341 start_networkd()
95e1fbba
YW
5342 self.wait_online('client-p:enslaved',
5343 'router-high:degraded', 'router-high-p:enslaved',
5344 'router-low:degraded', 'router-low-p:enslaved',
5345 'bridge99:routable')
bb80f633
YW
5346
5347 networkctl_reconfigure('client')
95e1fbba 5348 self.wait_online('client:routable')
bb80f633
YW
5349
5350 self.wait_address('client', '2002:da8:1:99:1034:56ff:fe78:9a00/64', ipv='-6', timeout_sec=10)
5351 self.wait_address('client', '2002:da8:1:98:1034:56ff:fe78:9a00/64', ipv='-6', timeout_sec=10)
5352 self.wait_route('client', 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 512', ipv='-6', timeout_sec=10)
5353 self.wait_route('client', 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 2048', ipv='-6', timeout_sec=10)
5354
5355 output = check_output('ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99')
5356 print(output)
9fbab82b 5357 self.assertIn('metric 512', output)
bb80f633
YW
5358 self.assertIn('pref high', output)
5359 output = check_output('ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98')
5360 print(output)
9fbab82b 5361 self.assertIn('metric 2048', output)
bb80f633
YW
5362 self.assertIn('pref low', output)
5363
5364 with open(os.path.join(network_unit_dir, '25-veth-client.network'), mode='a', encoding='utf-8') as f:
5365 f.write('\n[Link]\nMACAddress=12:34:56:78:9a:01\n[IPv6AcceptRA]\nRouteMetric=100:200:300\n')
5366
5367 networkctl_reload()
95e1fbba 5368 self.wait_online('client:routable')
bb80f633
YW
5369
5370 self.wait_address('client', '2002:da8:1:99:1034:56ff:fe78:9a01/64', ipv='-6', timeout_sec=10)
5371 self.wait_address('client', '2002:da8:1:98:1034:56ff:fe78:9a01/64', ipv='-6', timeout_sec=10)
5372 self.wait_route('client', 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 100', ipv='-6', timeout_sec=10)
5373 self.wait_route('client', 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 300', ipv='-6', timeout_sec=10)
5374
5375 output = check_output('ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99')
5376 print(output)
9fbab82b
YW
5377 self.assertIn('metric 100', output)
5378 self.assertNotIn('metric 512', output)
bb80f633
YW
5379 self.assertIn('pref high', output)
5380 output = check_output('ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98')
5381 print(output)
9fbab82b
YW
5382 self.assertIn('metric 300', output)
5383 self.assertNotIn('metric 2048', output)
bb80f633
YW
5384 self.assertIn('pref low', output)
5385
9fbab82b
YW
5386 # swap the preference (for issue #28439)
5387 remove_network_unit('25-veth-router-high.network', '25-veth-router-low.network')
5388 copy_network_unit('25-veth-router-high2.network', '25-veth-router-low2.network')
5389 networkctl_reload()
5390 self.wait_route('client', 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 300', ipv='-6', timeout_sec=10)
5391 self.wait_route('client', 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 100', ipv='-6', timeout_sec=10)
5392
5393 output = check_output('ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99')
5394 print(output)
5395 self.assertIn('metric 300', output)
5396 self.assertNotIn('metric 100', output)
5397 self.assertIn('pref low', output)
5398 self.assertNotIn('pref high', output)
5399 output = check_output('ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98')
5400 print(output)
5401 self.assertIn('metric 100', output)
5402 self.assertNotIn('metric 300', output)
5403 self.assertIn('pref high', output)
5404 self.assertNotIn('pref low', output)
5405
c1dd58b3
FS
5406 @unittest.skipUnless(radvd_check_config('captive-portal.conf'), "Installed radvd doesn't support captive portals")
5407 def test_captive_portal(self):
5408 copy_network_unit('25-veth-client.netdev',
5409 '25-veth-router-captive.netdev',
5410 '26-bridge.netdev',
5411 '25-veth-client-captive.network',
5412 '25-veth-router-captive.network',
5413 '25-veth-bridge-captive.network',
5414 '25-bridge99.network')
5415 start_networkd()
95e1fbba
YW
5416 self.wait_online('bridge99:routable', 'client-p:enslaved',
5417 'router-captive:degraded', 'router-captivep:enslaved')
c1dd58b3
FS
5418
5419 start_radvd(config_file='captive-portal.conf')
5420 networkctl_reconfigure('client')
95e1fbba 5421 self.wait_online('client:routable')
c1dd58b3
FS
5422
5423 self.wait_address('client', '2002:da8:1:99:1034:56ff:fe78:9a00/64', ipv='-6', timeout_sec=10)
10d670a3 5424 output = networkctl_status('client')
c1dd58b3
FS
5425 print(output)
5426 self.assertIn('Captive Portal: http://systemd.io', output)
5427
5428 @unittest.skipUnless(radvd_check_config('captive-portal.conf'), "Installed radvd doesn't support captive portals")
5429 def test_invalid_captive_portal(self):
5430 def radvd_write_config(captive_portal_uri):
5431 with open(os.path.join(networkd_ci_temp_dir, 'radvd/bogus-captive-portal.conf'), mode='w', encoding='utf-8') as f:
5432 f.write(f'interface router-captive {{ AdvSendAdvert on; AdvCaptivePortalAPI "{captive_portal_uri}"; prefix 2002:da8:1:99::/64 {{ AdvOnLink on; AdvAutonomous on; }}; }};')
5433
5434 captive_portal_uris = [
5435 "42ěščěškd ěšč ě s",
5436 " ",
5437 "🤔",
5438 ]
5439
5440 copy_network_unit('25-veth-client.netdev',
5441 '25-veth-router-captive.netdev',
5442 '26-bridge.netdev',
5443 '25-veth-client-captive.network',
5444 '25-veth-router-captive.network',
5445 '25-veth-bridge-captive.network',
5446 '25-bridge99.network')
5447 start_networkd()
95e1fbba
YW
5448 self.wait_online('bridge99:routable', 'client-p:enslaved',
5449 'router-captive:degraded', 'router-captivep:enslaved')
c1dd58b3
FS
5450
5451 for uri in captive_portal_uris:
5452 print(f"Captive portal: {uri}")
5453 radvd_write_config(uri)
5454 stop_radvd()
5455 start_radvd(config_file='bogus-captive-portal.conf')
5456 networkctl_reconfigure('client')
95e1fbba 5457 self.wait_online('client:routable')
c1dd58b3
FS
5458
5459 self.wait_address('client', '2002:da8:1:99:1034:56ff:fe78:9a00/64', ipv='-6', timeout_sec=10)
10d670a3 5460 output = networkctl_status('client')
c1dd58b3
FS
5461 print(output)
5462 self.assertNotIn('Captive Portal:', output)
5463
be68c2c9 5464class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
1f0e3109
SS
5465
5466 def setUp(self):
a962d857 5467 setup_common()
1f0e3109
SS
5468
5469 def tearDown(self):
a962d857 5470 tear_down_common()
1f0e3109
SS
5471
5472 def test_dhcp_server(self):
a962d857 5473 copy_network_unit('25-veth.netdev', '25-dhcp-client.network', '25-dhcp-server.network')
c5f7a087 5474 start_networkd()
95e1fbba 5475 self.wait_online('veth99:routable', 'veth-peer:routable')
c5f7a087 5476
10d670a3 5477 output = networkctl_status('veth99')
c5f7a087 5478 print(output)
283863a1 5479 self.assertRegex(output, r'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)')
c5f7a087
YW
5480 self.assertIn('Gateway: 192.168.5.3', output)
5481 self.assertRegex(output, 'DNS: 192.168.5.1\n *192.168.5.10')
5482 self.assertRegex(output, 'NTP: 192.168.5.1\n *192.168.5.11')
5483
10d670a3 5484 output = networkctl_status('veth-peer')
8bdece74
FS
5485 self.assertRegex(output, "Offered DHCP leases: 192.168.5.[0-9]*")
5486
47f1ce16
YW
5487 def test_dhcp_server_null_server_address(self):
5488 copy_network_unit('25-veth.netdev', '25-dhcp-client.network', '25-dhcp-server-null-server-address.network')
5489 start_networkd()
95e1fbba 5490 self.wait_online('veth99:routable', 'veth-peer:routable')
47f1ce16
YW
5491
5492 output = check_output('ip --json address show dev veth-peer')
5493 server_address = json.loads(output)[0]['addr_info'][0]['local']
5494 print(server_address)
5495
5496 output = check_output('ip --json address show dev veth99')
5497 client_address = json.loads(output)[0]['addr_info'][0]['local']
5498 print(client_address)
5499
10d670a3 5500 output = networkctl_status('veth99')
47f1ce16
YW
5501 print(output)
5502 self.assertRegex(output, rf'Address: {client_address} \(DHCP4 via {server_address}\)')
5503 self.assertIn(f'Gateway: {server_address}', output)
5504 self.assertIn(f'DNS: {server_address}', output)
5505 self.assertIn(f'NTP: {server_address}', output)
5506
10d670a3 5507 output = networkctl_status('veth-peer')
47f1ce16
YW
5508 self.assertIn(f'Offered DHCP leases: {client_address}', output)
5509
c5f7a087 5510 def test_dhcp_server_with_uplink(self):
a962d857
YW
5511 copy_network_unit('25-veth.netdev', '25-dhcp-client.network', '25-dhcp-server-downstream.network',
5512 '12-dummy.netdev', '25-dhcp-server-uplink.network')
2cf6fdff 5513 start_networkd()
95e1fbba 5514 self.wait_online('veth99:routable', 'veth-peer:routable')
1f0e3109 5515
10d670a3 5516 output = networkctl_status('veth99')
1f0e3109 5517 print(output)
283863a1 5518 self.assertRegex(output, r'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)')
32d97330
YW
5519 self.assertIn('Gateway: 192.168.5.3', output)
5520 self.assertIn('DNS: 192.168.5.1', output)
5521 self.assertIn('NTP: 192.168.5.1', output)
1f0e3109 5522
1f0e3109 5523 def test_emit_router_timezone(self):
a962d857 5524 copy_network_unit('25-veth.netdev', '25-dhcp-client-timezone-router.network', '25-dhcp-server-timezone-router.network')
2cf6fdff 5525 start_networkd()
95e1fbba 5526 self.wait_online('veth99:routable', 'veth-peer:routable')
1f0e3109 5527
10d670a3 5528 output = networkctl_status('veth99')
1f0e3109 5529 print(output)
283863a1 5530 self.assertRegex(output, r'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)')
32d97330
YW
5531 self.assertIn('Gateway: 192.168.5.1', output)
5532 self.assertIn('Time Zone: Europe/Berlin', output)
1f0e3109 5533
ffaece68 5534 def test_dhcp_server_static_lease(self):
a962d857 5535 copy_network_unit('25-veth.netdev', '25-dhcp-client-static-lease.network', '25-dhcp-server-static-lease.network')
ffaece68 5536 start_networkd()
95e1fbba 5537 self.wait_online('veth99:routable', 'veth-peer:routable')
ffaece68 5538
10d670a3 5539 output = networkctl_status('veth99')
ffaece68 5540 print(output)
32d97330 5541 self.assertIn('Address: 10.1.1.200 (DHCP4 via 10.1.1.1)', output)
82c60c93
YW
5542 self.assertIn('DHCP4 Client ID: 12:34:56:78:9a:bc', output)
5543
5544 def test_dhcp_server_static_lease_default_client_id(self):
5545 copy_network_unit('25-veth.netdev', '25-dhcp-client.network', '25-dhcp-server-static-lease.network')
5546 start_networkd()
95e1fbba 5547 self.wait_online('veth99:routable', 'veth-peer:routable')
82c60c93 5548
10d670a3 5549 output = networkctl_status('veth99')
82c60c93
YW
5550 print(output)
5551 self.assertIn('Address: 10.1.1.200 (DHCP4 via 10.1.1.1)', output)
5552 self.assertRegex(output, 'DHCP4 Client ID: IAID:[0-9a-z]*/DUID')
ffaece68 5553
c95df587 5554class NetworkdDHCPServerRelayAgentTests(unittest.TestCase, Utilities):
c95df587
YA
5555
5556 def setUp(self):
a962d857 5557 setup_common()
c95df587
YA
5558
5559 def tearDown(self):
a962d857 5560 tear_down_common()
c95df587
YA
5561
5562 def test_relay_agent(self):
a962d857
YW
5563 copy_network_unit('25-agent-veth-client.netdev',
5564 '25-agent-veth-server.netdev',
5565 '25-agent-client.network',
5566 '25-agent-server.network',
5567 '25-agent-client-peer.network',
5568 '25-agent-server-peer.network')
c95df587
YA
5569 start_networkd()
5570
95e1fbba 5571 self.wait_online('client:routable')
c95df587 5572
10d670a3 5573 output = networkctl_status('client')
c95df587 5574 print(output)
283863a1 5575 self.assertRegex(output, r'Address: 192.168.5.150 \(DHCP4 via 192.168.5.1\)')
c95df587 5576
a663ddc0
YW
5577 def test_replay_agent_on_bridge(self):
5578 copy_network_unit('25-agent-bridge.netdev',
5579 '25-agent-veth-client.netdev',
5580 '25-agent-bridge.network',
5581 '25-agent-bridge-port.network',
5582 '25-agent-client.network')
5583 start_networkd()
95e1fbba 5584 self.wait_online('bridge-relay:routable', 'client-peer:enslaved')
a663ddc0
YW
5585
5586 # For issue #30763.
5587 expect = 'bridge-relay: DHCPv4 server: STARTED'
5588 for _ in range(20):
5589 if expect in read_networkd_log():
5590 break
5591 time.sleep(0.5)
5592 else:
5593 self.fail()
5594
be68c2c9 5595class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
1f0e3109
SS
5596
5597 def setUp(self):
a962d857 5598 setup_common()
1f0e3109
SS
5599
5600 def tearDown(self):
a962d857 5601 tear_down_common()
1f0e3109
SS
5602
5603 def test_dhcp_client_ipv6_only(self):
a962d857 5604 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-ipv6-only.network')
1f0e3109 5605
2cf6fdff 5606 start_networkd()
95e1fbba 5607 self.wait_online('veth-peer:carrier')
2d7ca6b4
YW
5608
5609 # information request mode
46f2eb51
YW
5610 # The name ipv6-only option may not be supported by older dnsmasq
5611 # start_dnsmasq('--dhcp-option=option:ipv6-only,300')
5612 start_dnsmasq('--dhcp-option=108,00:00:02:00',
5613 '--dhcp-option=option6:dns-server,[2600::ee]',
2d7ca6b4
YW
5614 '--dhcp-option=option6:ntp-server,[2600::ff]',
5615 ra_mode='ra-stateless')
95e1fbba 5616 self.wait_online('veth99:routable', 'veth-peer:routable')
2d7ca6b4 5617
0f9efffa
YW
5618 # DHCPv6 REPLY for INFORMATION-REQUEST may be received after the link entered configured state.
5619 # Let's wait for the expected DNS server being listed in the state file.
5620 for _ in range(100):
5621 output = read_link_state_file('veth99')
0f9efffa
YW
5622 if 'DNS=2600::ee' in output:
5623 break
5624 time.sleep(.2)
5625
2d7ca6b4
YW
5626 # Check link state file
5627 print('## link state file')
5628 output = read_link_state_file('veth99')
5629 print(output)
5630 self.assertIn('DNS=2600::ee', output)
5631 self.assertIn('NTP=2600::ff', output)
5632
5633 # Check manager state file
5634 print('## manager state file')
5635 output = read_manager_state_file()
5636 print(output)
5637 self.assertRegex(output, 'DNS=.*2600::ee')
5638 self.assertRegex(output, 'NTP=.*2600::ff')
5639
5640 print('## dnsmasq log')
5641 output = read_dnsmasq_log_file()
5642 print(output)
5643 self.assertIn('DHCPINFORMATION-REQUEST(veth-peer)', output)
5644 self.assertNotIn('DHCPSOLICIT(veth-peer)', output)
5645 self.assertNotIn('DHCPADVERTISE(veth-peer)', output)
5646 self.assertNotIn('DHCPREQUEST(veth-peer)', output)
5647 self.assertNotIn('DHCPREPLY(veth-peer)', output)
5648
3aa47694 5649 # Check json format
10d670a3 5650 check_json(networkctl_json('veth99'))
3aa47694 5651
2d7ca6b4
YW
5652 # solicit mode
5653 stop_dnsmasq()
46f2eb51
YW
5654 start_dnsmasq('--dhcp-option=108,00:00:02:00',
5655 '--dhcp-option=option6:dns-server,[2600::ee]',
34290c6a 5656 '--dhcp-option=option6:ntp-server,[2600::ff]')
2d7ca6b4 5657 networkctl_reconfigure('veth99')
95e1fbba 5658 self.wait_online('veth99:routable', 'veth-peer:routable')
1f0e3109 5659
18f2638f
YW
5660 # checking address
5661 output = check_output('ip address show dev veth99 scope global')
c5fcd8a7 5662 print(output)
18f2638f
YW
5663 self.assertRegex(output, r'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute')
5664 self.assertNotIn('192.168.5', output)
c5fcd8a7 5665
589af70b
YW
5666 # checking semi-static route
5667 output = check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
5668 print(output)
5669 self.assertRegex(output, 'via fe80::1034:56ff:fe78:9abd')
5670
3a956d38 5671 # Confirm that ipv6 token is not set in the kernel
371810d1 5672 output = check_output('ip token show dev veth99')
3a956d38
YW
5673 print(output)
5674 self.assertRegex(output, 'token :: dev veth99')
5675
0f9efffa 5676 # Make manager and link state file updated
10d670a3 5677 resolvectl('revert', 'veth99')
0f9efffa 5678
34290c6a
YW
5679 # Check link state file
5680 print('## link state file')
5681 output = read_link_state_file('veth99')
5682 print(output)
5683 self.assertIn('DNS=2600::ee', output)
5684 self.assertIn('NTP=2600::ff', output)
5685
5686 # Check manager state file
5687 print('## manager state file')
5688 output = read_manager_state_file()
5689 print(output)
5690 self.assertRegex(output, 'DNS=.*2600::ee')
5691 self.assertRegex(output, 'NTP=.*2600::ff')
5692
91a7afde
YW
5693 print('## dnsmasq log')
5694 output = read_dnsmasq_log_file()
5695 print(output)
2d7ca6b4 5696 self.assertNotIn('DHCPINFORMATION-REQUEST(veth-peer)', output)
91a7afde
YW
5697 self.assertIn('DHCPSOLICIT(veth-peer)', output)
5698 self.assertNotIn('DHCPADVERTISE(veth-peer)', output)
5699 self.assertNotIn('DHCPREQUEST(veth-peer)', output)
5700 self.assertIn('DHCPREPLY(veth-peer)', output)
5701 self.assertIn('sent size: 0 option: 14 rapid-commit', output)
5702
3aa47694 5703 # Check json format
10d670a3 5704 check_json(networkctl_json('veth99'))
3aa47694
YW
5705
5706 # Testing without rapid commit support
91a7afde
YW
5707 with open(os.path.join(network_unit_dir, '25-dhcp-client-ipv6-only.network'), mode='a', encoding='utf-8') as f:
5708 f.write('\n[DHCPv6]\nRapidCommit=no\n')
5709
5710 stop_dnsmasq()
46f2eb51
YW
5711 start_dnsmasq('--dhcp-option=108,00:00:02:00',
5712 '--dhcp-option=option6:dns-server,[2600::ee]',
34290c6a 5713 '--dhcp-option=option6:ntp-server,[2600::ff]')
91a7afde
YW
5714
5715 networkctl_reload()
95e1fbba 5716 self.wait_online('veth99:routable', 'veth-peer:routable')
91a7afde
YW
5717
5718 # checking address
5719 output = check_output('ip address show dev veth99 scope global')
5720 print(output)
5721 self.assertRegex(output, r'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute')
5722 self.assertNotIn('192.168.5', output)
5723
5724 # checking semi-static route
5725 output = check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
5726 print(output)
5727 self.assertRegex(output, 'via fe80::1034:56ff:fe78:9abd')
5728
0f9efffa 5729 # Make manager and link state file updated
10d670a3 5730 resolvectl('revert', 'veth99')
0f9efffa 5731
34290c6a
YW
5732 # Check link state file
5733 print('## link state file')
5734 output = read_link_state_file('veth99')
5735 print(output)
5736 self.assertIn('DNS=2600::ee', output)
5737 self.assertIn('NTP=2600::ff', output)
5738
5739 # Check manager state file
5740 print('## manager state file')
5741 output = read_manager_state_file()
5742 print(output)
5743 self.assertRegex(output, 'DNS=.*2600::ee')
5744 self.assertRegex(output, 'NTP=.*2600::ff')
5745
91a7afde
YW
5746 print('## dnsmasq log')
5747 output = read_dnsmasq_log_file()
5748 print(output)
2d7ca6b4 5749 self.assertNotIn('DHCPINFORMATION-REQUEST(veth-peer)', output)
91a7afde
YW
5750 self.assertIn('DHCPSOLICIT(veth-peer)', output)
5751 self.assertIn('DHCPADVERTISE(veth-peer)', output)
5752 self.assertIn('DHCPREQUEST(veth-peer)', output)
5753 self.assertIn('DHCPREPLY(veth-peer)', output)
5754 self.assertNotIn('rapid-commit', output)
5755
3aa47694 5756 # Check json format
10d670a3 5757 check_json(networkctl_json('veth99'))
3aa47694 5758
e1ef7771 5759 def test_dhcp_client_ipv6_dbus_status(self):
e1ef7771 5760 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-ipv6-only.network')
e1ef7771 5761 start_networkd()
95e1fbba 5762 self.wait_online('veth-peer:carrier')
e1ef7771 5763
5764 # Note that at this point the DHCPv6 client has not been started because no RA (with managed
fcdd21ec 5765 # bit set) has yet been received and the configuration does not include WithoutRA=true
e081ffc1 5766 state = get_dhcp6_client_state('veth99')
46f2eb51 5767 print(f"DHCPv6 client state = {state}")
e1ef7771 5768 self.assertEqual(state, 'stopped')
5769
46f2eb51
YW
5770 state = get_dhcp4_client_state('veth99')
5771 print(f"DHCPv4 client state = {state}")
5772 self.assertEqual(state, 'selecting')
5773
5774 start_dnsmasq('--dhcp-option=108,00:00:02:00')
95e1fbba 5775 self.wait_online('veth99:routable', 'veth-peer:routable')
e1ef7771 5776
e081ffc1 5777 state = get_dhcp6_client_state('veth99')
46f2eb51 5778 print(f"DHCPv6 client state = {state}")
e1ef7771 5779 self.assertEqual(state, 'bound')
5780
46f2eb51
YW
5781 # DHCPv4 client will stop after an DHCPOFFER message received, so we need to wait for a while.
5782 for _ in range(100):
5783 state = get_dhcp4_client_state('veth99')
5784 if state == 'stopped':
5785 break
5786 time.sleep(.2)
5787
5788 print(f"DHCPv4 client state = {state}")
5789 self.assertEqual(state, 'stopped')
5790
aa7336f1
YW
5791 # restart dnsmasq to clear log
5792 stop_dnsmasq()
5793 start_dnsmasq('--dhcp-option=108,00:00:02:00')
5794
5795 # Test renew command
5796 # See https://github.com/systemd/systemd/pull/29472#issuecomment-1759092138
10d670a3 5797 networkctl('renew', 'veth99')
aa7336f1
YW
5798
5799 for _ in range(100):
5800 state = get_dhcp4_client_state('veth99')
5801 if state == 'stopped':
5802 break
5803 time.sleep(.2)
5804
5805 print(f"DHCPv4 client state = {state}")
5806 self.assertEqual(state, 'stopped')
5807
5808 print('## dnsmasq log')
5809 output = read_dnsmasq_log_file()
5810 print(output)
5811 self.assertIn('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc', output)
5812 self.assertIn('DHCPOFFER(veth-peer)', output)
5813 self.assertNotIn('DHCPREQUEST(veth-peer)', output)
5814 self.assertNotIn('DHCPACK(veth-peer)', output)
5815
e448fcd0
SS
5816 def test_dhcp_client_ipv6_only_with_custom_client_identifier(self):
5817 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-ipv6-only-custom-client-identifier.network')
5818
5819 start_networkd()
95e1fbba 5820 self.wait_online('veth-peer:carrier')
e448fcd0 5821 start_dnsmasq()
95e1fbba 5822 self.wait_online('veth99:routable', 'veth-peer:routable')
e448fcd0
SS
5823
5824 # checking address
5825 output = check_output('ip address show dev veth99 scope global')
5826 print(output)
5827 self.assertRegex(output, r'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute')
5828 self.assertNotIn('192.168.5', output)
5829
5830 print('## dnsmasq log')
5831 output = read_dnsmasq_log_file()
5832 print(output)
5833 self.assertIn('DHCPSOLICIT(veth-peer) 00:42:00:00:ab:11:f9:2a:c2:77:29:f9:5c:00', output)
5834 self.assertNotIn('DHCPADVERTISE(veth-peer)', output)
5835 self.assertNotIn('DHCPREQUEST(veth-peer)', output)
5836 self.assertIn('DHCPREPLY(veth-peer)', output)
5837 self.assertIn('sent size: 0 option: 14 rapid-commit', output)
5838
1f0e3109 5839 def test_dhcp_client_ipv4_only(self):
a962d857 5840 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-ipv4-only.network')
1f0e3109 5841
c742d7e8
TM
5842 self.setup_nftset('addr4', 'ipv4_addr')
5843 self.setup_nftset('network4', 'ipv4_addr', 'flags interval;')
5844 self.setup_nftset('ifindex', 'iface_index')
5845
2cf6fdff 5846 start_networkd()
95e1fbba 5847 self.wait_online('veth-peer:carrier')
a962d857 5848 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7',
b5c8f471 5849 '--dhcp-option=option:sip-server,192.168.5.21,192.168.5.22',
a962d857
YW
5850 '--dhcp-option=option:domain-search,example.com',
5851 '--dhcp-alternate-port=67,5555',
5852 ipv4_range='192.168.5.110,192.168.5.119')
95e1fbba 5853 self.wait_online('veth99:routable', 'veth-peer:routable')
9e7d91ed 5854 self.wait_address('veth99', r'inet 192.168.5.11[0-9]*/24', ipv='-4')
1f0e3109 5855
18f2638f
YW
5856 print('## ip address show dev veth99 scope global')
5857 output = check_output('ip address show dev veth99 scope global')
1f0e3109 5858 print(output)
18f2638f
YW
5859 self.assertIn('mtu 1492', output)
5860 self.assertIn('inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99', output)
5861 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')
5862 self.assertNotIn('2600::', output)
195a18c1 5863
6b524d70
YW
5864 output = check_output('ip -4 --json address show dev veth99')
5865 for i in json.loads(output)[0]['addr_info']:
5866 if i['label'] == 'test-label':
5867 address1 = i['local']
5868 break
5869 else:
5870 self.assertFalse(True)
5871
5872 self.assertRegex(address1, r'^192.168.5.11[0-9]$')
5873
18f2638f
YW
5874 print('## ip route show table main dev veth99')
5875 output = check_output('ip route show table main dev veth99')
195a18c1 5876 print(output)
18f2638f
YW
5877 # no DHCP routes assigned to the main table
5878 self.assertNotIn('proto dhcp', output)
5879 # static routes
5880 self.assertIn('192.168.5.0/24 proto kernel scope link src 192.168.5.250', output)
5881 self.assertIn('192.168.5.0/24 proto static scope link', output)
5882 self.assertIn('192.168.6.0/24 proto static scope link', output)
5883 self.assertIn('192.168.7.0/24 proto static scope link', output)
5884
5885 print('## ip route show table 211 dev veth99')
5886 output = check_output('ip route show table 211 dev veth99')
5887 print(output)
6b524d70
YW
5888 self.assertRegex(output, f'default via 192.168.5.1 proto dhcp src {address1} metric 24')
5889 self.assertRegex(output, f'192.168.5.0/24 proto dhcp scope link src {address1} metric 24')
5890 self.assertRegex(output, f'192.168.5.1 proto dhcp scope link src {address1} metric 24')
5891 self.assertRegex(output, f'192.168.5.6 proto dhcp scope link src {address1} metric 24')
5892 self.assertRegex(output, f'192.168.5.7 proto dhcp scope link src {address1} metric 24')
18f2638f
YW
5893 self.assertIn('10.0.0.0/8 via 192.168.5.1 proto dhcp', output)
5894
1a8e1d78
YW
5895 print('## link state file')
5896 output = read_link_state_file('veth99')
5897 print(output)
b5c8f471 5898 # checking DNS server, SIP server, and Domains
1a8e1d78 5899 self.assertIn('DNS=192.168.5.6 192.168.5.7', output)
b5c8f471 5900 self.assertIn('SIP=192.168.5.21 192.168.5.22', output)
1a8e1d78 5901 self.assertIn('DOMAINS=example.com', output)
195a18c1 5902
b5c8f471 5903 print('## json')
10d670a3 5904 j = json.loads(networkctl_json('veth99'))
b5c8f471
YW
5905
5906 self.assertEqual(len(j['DNS']), 2)
5907 for i in j['DNS']:
5908 print(i)
5909 self.assertEqual(i['Family'], 2)
5910 a = socket.inet_ntop(socket.AF_INET, bytearray(i['Address']))
5911 self.assertRegex(a, '^192.168.5.[67]$')
5912 self.assertEqual(i['ConfigSource'], 'DHCPv4')
5913 a = socket.inet_ntop(socket.AF_INET, bytearray(i['ConfigProvider']))
5914 self.assertEqual('192.168.5.1', a)
5915
5916 self.assertEqual(len(j['SIP']), 2)
5917 for i in j['SIP']:
5918 print(i)
5919 self.assertEqual(i['Family'], 2)
5920 a = socket.inet_ntop(socket.AF_INET, bytearray(i['Address']))
5921 self.assertRegex(a, '^192.168.5.2[12]$')
5922 self.assertEqual(i['ConfigSource'], 'DHCPv4')
5923 a = socket.inet_ntop(socket.AF_INET, bytearray(i['ConfigProvider']))
5924 self.assertEqual('192.168.5.1', a)
5925
18f2638f 5926 print('## dnsmasq log')
063c7e9b
YW
5927 output = read_dnsmasq_log_file()
5928 print(output)
5929 self.assertIn('vendor class: FooBarVendorTest', output)
6b524d70 5930 self.assertIn('DHCPDISCOVER(veth-peer) 192.168.5.110 12:34:56:78:9a:bc', output)
063c7e9b
YW
5931 self.assertIn('client provides name: test-hostname', output)
5932 self.assertIn('26:mtu', output)
18f2638f
YW
5933
5934 # change address range, DNS servers, and Domains
888f57c1 5935 stop_dnsmasq()
a962d857 5936 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8',
b5c8f471 5937 '--dhcp-option=option:sip-server,192.168.5.23,192.168.5.24',
a962d857
YW
5938 '--dhcp-option=option:domain-search,foo.example.com',
5939 '--dhcp-alternate-port=67,5555',
5940 ipv4_range='192.168.5.120,192.168.5.129',)
195a18c1
YW
5941
5942 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
a102a52c 5943 print('Wait for the DHCP lease to be expired')
6b524d70 5944 self.wait_address_dropped('veth99', f'inet {address1}/24', ipv='-4', timeout_sec=120)
4b31fc88 5945 self.wait_address('veth99', r'inet 192.168.5.12[0-9]*/24', ipv='-4')
195a18c1 5946
95e1fbba 5947 self.wait_online('veth99:routable', 'veth-peer:routable')
195a18c1 5948
18f2638f
YW
5949 print('## ip address show dev veth99 scope global')
5950 output = check_output('ip address show dev veth99 scope global')
195a18c1 5951 print(output)
18f2638f
YW
5952 self.assertIn('mtu 1492', output)
5953 self.assertIn('inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99', output)
6b524d70 5954 self.assertNotIn(f'{address1}', output)
18f2638f
YW
5955 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')
5956 self.assertNotIn('2600::', output)
195a18c1 5957
6b524d70
YW
5958 output = check_output('ip -4 --json address show dev veth99')
5959 for i in json.loads(output)[0]['addr_info']:
5960 if i['label'] == 'test-label':
5961 address2 = i['local']
5962 break
5963 else:
5964 self.assertFalse(True)
5965
5966 self.assertRegex(address2, r'^192.168.5.12[0-9]$')
5967
18f2638f
YW
5968 print('## ip route show table main dev veth99')
5969 output = check_output('ip route show table main dev veth99')
195a18c1 5970 print(output)
18f2638f
YW
5971 # no DHCP routes assigned to the main table
5972 self.assertNotIn('proto dhcp', output)
5973 # static routes
5974 self.assertIn('192.168.5.0/24 proto kernel scope link src 192.168.5.250', output)
5975 self.assertIn('192.168.5.0/24 proto static scope link', output)
5976 self.assertIn('192.168.6.0/24 proto static scope link', output)
5977 self.assertIn('192.168.7.0/24 proto static scope link', output)
5978
5979 print('## ip route show table 211 dev veth99')
5980 output = check_output('ip route show table 211 dev veth99')
5981 print(output)
6b524d70
YW
5982 self.assertRegex(output, f'default via 192.168.5.1 proto dhcp src {address2} metric 24')
5983 self.assertRegex(output, f'192.168.5.0/24 proto dhcp scope link src {address2} metric 24')
5984 self.assertRegex(output, f'192.168.5.1 proto dhcp scope link src {address2} metric 24')
18f2638f 5985 self.assertNotIn('192.168.5.6', output)
6b524d70
YW
5986 self.assertRegex(output, f'192.168.5.7 proto dhcp scope link src {address2} metric 24')
5987 self.assertRegex(output, f'192.168.5.8 proto dhcp scope link src {address2} metric 24')
18f2638f
YW
5988 self.assertIn('10.0.0.0/8 via 192.168.5.1 proto dhcp', output)
5989
1a8e1d78
YW
5990 print('## link state file')
5991 output = read_link_state_file('veth99')
5992 print(output)
b5c8f471 5993 # checking DNS server, SIP server, and Domains
1a8e1d78 5994 self.assertIn('DNS=192.168.5.1 192.168.5.7 192.168.5.8', output)
b5c8f471 5995 self.assertIn('SIP=192.168.5.23 192.168.5.24', output)
1a8e1d78 5996 self.assertIn('DOMAINS=foo.example.com', output)
18f2638f 5997
b5c8f471 5998 print('## json')
10d670a3 5999 j = json.loads(networkctl_json('veth99'))
b5c8f471
YW
6000
6001 self.assertEqual(len(j['DNS']), 3)
6002 for i in j['DNS']:
6003 print(i)
6004 self.assertEqual(i['Family'], 2)
6005 a = socket.inet_ntop(socket.AF_INET, bytearray(i['Address']))
6006 self.assertRegex(a, '^192.168.5.[178]$')
6007 self.assertEqual(i['ConfigSource'], 'DHCPv4')
6008 a = socket.inet_ntop(socket.AF_INET, bytearray(i['ConfigProvider']))
6009 self.assertEqual('192.168.5.1', a)
6010
6011 self.assertEqual(len(j['SIP']), 2)
6012 for i in j['SIP']:
6013 print(i)
6014 self.assertEqual(i['Family'], 2)
6015 a = socket.inet_ntop(socket.AF_INET, bytearray(i['Address']))
6016 self.assertRegex(a, '^192.168.5.2[34]$')
6017 self.assertEqual(i['ConfigSource'], 'DHCPv4')
6018 a = socket.inet_ntop(socket.AF_INET, bytearray(i['ConfigProvider']))
6019 self.assertEqual('192.168.5.1', a)
6020
18f2638f 6021 print('## dnsmasq log')
063c7e9b
YW
6022 output = read_dnsmasq_log_file()
6023 print(output)
6024 self.assertIn('vendor class: FooBarVendorTest', output)
6b524d70 6025 self.assertIn(f'DHCPDISCOVER(veth-peer) {address1} 12:34:56:78:9a:bc', output)
063c7e9b
YW
6026 self.assertIn('client provides name: test-hostname', output)
6027 self.assertIn('26:mtu', output)
1f0e3109 6028
0677130e 6029 self.check_netlabel('veth99', r'192\.168\.5\.0/24')
a4640bed 6030
c742d7e8
TM
6031 self.check_nftset('addr4', r'192\.168\.5\.1')
6032 self.check_nftset('network4', r'192\.168\.5\.0/24')
6033 self.check_nftset('ifindex', 'veth99')
6034
6035 self.teardown_nftset('addr4', 'network4', 'ifindex')
6036
e1ef7771 6037 def test_dhcp_client_ipv4_dbus_status(self):
e1ef7771 6038 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-ipv4-only.network')
e1ef7771 6039 start_networkd()
95e1fbba 6040 self.wait_online('veth-peer:carrier')
e1ef7771 6041
e081ffc1 6042 state = get_dhcp4_client_state('veth99')
e1ef7771 6043 print(f"State = {state}")
6b524d70 6044 self.assertEqual(state, 'rebooting')
e1ef7771 6045
6046 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7',
6047 '--dhcp-option=option:domain-search,example.com',
6048 '--dhcp-alternate-port=67,5555',
6049 ipv4_range='192.168.5.110,192.168.5.119')
95e1fbba 6050 self.wait_online('veth99:routable', 'veth-peer:routable')
e1ef7771 6051 self.wait_address('veth99', r'inet 192.168.5.11[0-9]*/24', ipv='-4')
6052
e081ffc1 6053 state = get_dhcp4_client_state('veth99')
e1ef7771 6054 print(f"State = {state}")
6055 self.assertEqual(state, 'bound')
6056
b65c5390
YW
6057 def test_dhcp_client_allow_list(self):
6058 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-allow-list.network', copy_dropins=False)
6059
6060 start_networkd()
95e1fbba 6061 self.wait_online('veth-peer:carrier')
b65c5390
YW
6062 since = datetime.datetime.now()
6063 start_dnsmasq()
6064
6065 expect = 'veth99: DHCPv4 server IP address 192.168.5.1 not found in allow-list, ignoring offer.'
6066 for _ in range(20):
6067 if expect in read_networkd_log(since=since):
6068 break
6069 time.sleep(0.5)
6070 else:
6071 self.fail()
6072
6073 copy_network_unit('25-dhcp-client-allow-list.network.d/00-allow-list.conf')
6074 since = datetime.datetime.now()
6075 networkctl_reload()
6076
6077 expect = 'veth99: DHCPv4 server IP address 192.168.5.1 not found in allow-list, ignoring offer.'
6078 for _ in range(20):
6079 if expect in read_networkd_log(since=since):
6080 break
6081 time.sleep(0.5)
6082 else:
6083 self.fail()
6084
6085 copy_network_unit('25-dhcp-client-allow-list.network.d/10-deny-list.conf')
6086 since = datetime.datetime.now()
6087 networkctl_reload()
6088
6089 expect = 'veth99: DHCPv4 server IP address 192.168.5.1 found in deny-list, ignoring offer.'
6090 for _ in range(20):
6091 if expect in read_networkd_log(since=since):
6092 break
6093 time.sleep(0.5)
6094 else:
6095 self.fail()
6096
2beecc70
RP
6097 @unittest.skipUnless("--dhcp-rapid-commit" in run("dnsmasq --help").stdout, reason="dnsmasq is missing dhcp-rapid-commit support")
6098 def test_dhcp_client_rapid_commit(self):
6099 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client.network')
6100 start_networkd()
95e1fbba 6101 self.wait_online('veth-peer:carrier')
2beecc70
RP
6102
6103 start_dnsmasq('--dhcp-rapid-commit')
95e1fbba 6104 self.wait_online('veth99:routable', 'veth-peer:routable')
2beecc70
RP
6105 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24', ipv='-4')
6106
6107 state = get_dhcp4_client_state('veth99')
6108 print(f"DHCPv4 client state = {state}")
6109 self.assertEqual(state, 'bound')
6110
6111 output = read_dnsmasq_log_file()
6112 self.assertIn('DHCPDISCOVER(veth-peer)', output)
6113 self.assertNotIn('DHCPOFFER(veth-peer)', output)
6114 self.assertNotIn('DHCPREQUEST(veth-peer)', output)
6115 self.assertIn('DHCPACK(veth-peer)', output)
6116
46f2eb51
YW
6117 def test_dhcp_client_ipv6_only_mode_without_ipv6_connectivity(self):
6118 copy_network_unit('25-veth.netdev',
6119 '25-dhcp-server-ipv6-only-mode.network',
6120 '25-dhcp-client-ipv6-only-mode.network')
6121 start_networkd()
95e1fbba 6122 self.wait_online('veth99:routable', 'veth-peer:routable', timeout='40s')
46f2eb51
YW
6123 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24', ipv='-4')
6124
6125 state = get_dhcp4_client_state('veth99')
6126 print(f"State = {state}")
6127 self.assertEqual(state, 'bound')
6128
7c0d36ff 6129 def test_dhcp_client_ipv4_use_routes_gateway(self):
a962d857 6130 first = True
e1220a70 6131 for (routes, gateway, dns_and_ntp_routes, classless) in itertools.product([True, False], repeat=4):
a962d857
YW
6132 if first:
6133 first = False
6134 else:
6135 self.tearDown()
6136
6137 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
6138 with self.subTest(routes=routes, gateway=gateway, dns_and_ntp_routes=dns_and_ntp_routes, classless=classless):
6139 self._test_dhcp_client_ipv4_use_routes_gateway(routes, gateway, dns_and_ntp_routes, classless)
7c0d36ff 6140
e1220a70 6141 def _test_dhcp_client_ipv4_use_routes_gateway(self, use_routes, use_gateway, dns_and_ntp_routes, classless):
1e86c833
DDM
6142 testunit = '25-dhcp-client-ipv4-use-routes-use-gateway.network'
6143 testunits = ['25-veth.netdev', '25-dhcp-server-veth-peer.network', testunit]
6983bb0e
FS
6144 testunits.append(f'{testunit}.d/use-routes-{use_routes}.conf')
6145 testunits.append(f'{testunit}.d/use-gateway-{use_gateway}.conf')
6146 testunits.append(f'{testunit}.d/use-dns-and-ntp-routes-{dns_and_ntp_routes}.conf')
a962d857 6147 copy_network_unit(*testunits, copy_dropins=False)
4c2e1833
YW
6148
6149 start_networkd()
95e1fbba 6150 self.wait_online('veth-peer:carrier')
a962d857
YW
6151 additional_options = [
6152 '--dhcp-option=option:dns-server,192.168.5.10,8.8.8.8',
6153 '--dhcp-option=option:ntp-server,192.168.5.11,9.9.9.9',
4001653d 6154 '--dhcp-option=option:static-route,192.168.6.100,192.168.5.2,8.8.8.8,192.168.5.3'
a962d857 6155 ]
625772c9 6156 if classless:
a962d857 6157 additional_options += [
86f67600 6158 '--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
6159 ]
6160 start_dnsmasq(*additional_options)
95e1fbba 6161 self.wait_online('veth99:routable', 'veth-peer:routable')
4c2e1833 6162
625772c9 6163 output = check_output('ip -4 route show dev veth99')
4c2e1833 6164 print(output)
4c2e1833 6165
7c0d36ff 6166 # Check UseRoutes=
625772c9
YW
6167 if use_routes:
6168 if classless:
6169 self.assertRegex(output, r'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
6170 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 6171 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
6172 self.assertRegex(output, r'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
6173 self.assertRegex(output, r'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
6174 else:
4001653d 6175 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 6176 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 6177 self.assertRegex(output, r'192.168.5.2 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
625772c9 6178 self.assertRegex(output, r'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
7c0d36ff 6179 else:
625772c9
YW
6180 self.assertNotRegex(output, r'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
6181 self.assertNotRegex(output, r'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
6182 self.assertNotRegex(output, r'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
6183 self.assertNotRegex(output, r'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4001653d 6184 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 6185 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 6186 self.assertNotRegex(output, r'192.168.5.2 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
625772c9 6187 self.assertNotRegex(output, r'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
0d7bd445 6188
7c0d36ff 6189 # Check UseGateway=
625772c9
YW
6190 if use_gateway and (not classless or not use_routes):
6191 self.assertRegex(output, r'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
7c0d36ff 6192 else:
625772c9 6193 self.assertNotRegex(output, r'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
87e62d32
YW
6194
6195 # Check route to gateway
6196 if (use_gateway or dns_and_ntp_routes) and (not classless or not use_routes):
6197 self.assertRegex(output, r'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
6198 else:
625772c9 6199 self.assertNotRegex(output, r'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
7c0d36ff 6200
e1220a70
YW
6201 # Check RoutesToDNS= and RoutesToNTP=
6202 if dns_and_ntp_routes:
625772c9 6203 self.assertRegex(output, r'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
e1220a70 6204 self.assertRegex(output, r'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
0ce86f5e
YW
6205 if use_routes:
6206 if classless:
6207 self.assertRegex(output, r'8.8.8.8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
6208 self.assertRegex(output, r'9.9.9.9 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
6209 else:
6210 self.assertRegex(output, r'8.8.8.8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024')
6211 self.assertRegex(output, r'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
87e62d32 6212 else:
625772c9 6213 self.assertRegex(output, r'8.8.8.8 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
e1220a70 6214 self.assertRegex(output, r'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
7c0d36ff 6215 else:
625772c9 6216 self.assertNotRegex(output, r'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
e1220a70 6217 self.assertNotRegex(output, r'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
625772c9 6218 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 6219 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 6220
10d670a3 6221 check_json(networkctl_json())
94f0bd62 6222
1f0e3109 6223 def test_dhcp_client_settings_anonymize(self):
a962d857 6224 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-anonymize.network')
2cf6fdff 6225 start_networkd()
95e1fbba 6226 self.wait_online('veth-peer:carrier')
ec38833c 6227 start_dnsmasq()
95e1fbba 6228 self.wait_online('veth99:routable', 'veth-peer:routable')
e40a58b5 6229
063c7e9b
YW
6230 print('## dnsmasq log')
6231 output = read_dnsmasq_log_file()
6232 print(output)
6233 self.assertNotIn('VendorClassIdentifier=SusantVendorTest', output)
6234 self.assertNotIn('test-hostname', output)
6235 self.assertNotIn('26:mtu', output)
1f0e3109 6236
1e498853 6237 def test_dhcp_keep_configuration_dhcp(self):
a962d857
YW
6238 copy_network_unit('25-veth.netdev',
6239 '25-dhcp-server-veth-peer.network',
6240 '25-dhcp-client-keep-configuration-dhcp.network')
2cf6fdff 6241 start_networkd()
95e1fbba 6242 self.wait_online('veth-peer:carrier')
a962d857 6243 start_dnsmasq()
95e1fbba 6244 self.wait_online('veth99:routable', 'veth-peer:routable')
e40a58b5 6245
1e498853
YW
6246 output = check_output('ip address show dev veth99 scope global')
6247 print(output)
2b6a24a6
YW
6248 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
6249 'valid_lft forever preferred_lft forever')
e40a58b5 6250
5238e957 6251 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
888f57c1 6252 stop_dnsmasq()
1f0e3109
SS
6253
6254 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
a102a52c
YW
6255 print('Wait for the DHCP lease to be expired')
6256 time.sleep(120)
1f0e3109 6257
2b6a24a6 6258 # The lease address should be kept after the lease expired
1e498853
YW
6259 output = check_output('ip address show dev veth99 scope global')
6260 print(output)
2b6a24a6
YW
6261 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
6262 'valid_lft forever preferred_lft forever')
1e498853 6263
2b6a24a6 6264 stop_networkd()
1e498853 6265
2b6a24a6 6266 # The lease address should be kept after networkd stopped
1e498853
YW
6267 output = check_output('ip address show dev veth99 scope global')
6268 print(output)
2b6a24a6
YW
6269 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
6270 'valid_lft forever preferred_lft forever')
1e498853 6271
a962d857 6272 with open(os.path.join(network_unit_dir, '25-dhcp-client-keep-configuration-dhcp.network'), mode='a', encoding='utf-8') as f:
2347b6b9 6273 f.write('[Network]\nDHCP=no\n')
1e498853 6274
2347b6b9 6275 start_networkd()
95e1fbba 6276 self.wait_online('veth99:routable', 'veth-peer:routable')
1e498853 6277
2b6a24a6 6278 # Still the lease address should be kept after networkd restarted
1e498853
YW
6279 output = check_output('ip address show dev veth99 scope global')
6280 print(output)
2b6a24a6
YW
6281 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
6282 'valid_lft forever preferred_lft forever')
1e498853
YW
6283
6284 def test_dhcp_keep_configuration_dhcp_on_stop(self):
a962d857
YW
6285 copy_network_unit('25-veth.netdev',
6286 '25-dhcp-server-veth-peer.network',
6287 '25-dhcp-client-keep-configuration-dhcp-on-stop.network')
2cf6fdff 6288 start_networkd()
95e1fbba 6289 self.wait_online('veth-peer:carrier')
a962d857 6290 start_dnsmasq()
95e1fbba 6291 self.wait_online('veth99:routable', 'veth-peer:routable')
1e498853
YW
6292
6293 output = check_output('ip address show dev veth99 scope global')
6294 print(output)
2b6a24a6 6295 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
1e498853 6296
888f57c1 6297 stop_dnsmasq()
2b6a24a6 6298 stop_networkd()
1e498853
YW
6299
6300 output = check_output('ip address show dev veth99 scope global')
6301 print(output)
2b6a24a6 6302 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
1e498853 6303
a962d857 6304 start_networkd()
95e1fbba 6305 self.wait_online('veth-peer:routable')
1e498853
YW
6306
6307 output = check_output('ip address show dev veth99 scope global')
6308 print(output)
2b6a24a6 6309 self.assertNotIn('192.168.5.', output)
1f0e3109 6310
30d3b54e 6311 def test_dhcp_client_reuse_address_as_static(self):
a962d857 6312 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client.network')
2cf6fdff 6313 start_networkd()
95e1fbba 6314 self.wait_online('veth-peer:carrier')
ec38833c 6315 start_dnsmasq()
95e1fbba 6316 self.wait_online('veth99:routable', 'veth-peer:routable')
2629df47
YW
6317
6318 # link become 'routable' when at least one protocol provide an valid address.
3e726c15 6319 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 6320 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
30d3b54e 6321
371810d1 6322 output = check_output('ip address show dev veth99 scope global')
15519a81
YW
6323 ipv4_address = re.search(r'192.168.5.[0-9]*/24', output).group()
6324 ipv6_address = re.search(r'2600::[0-9a-f:]*/128', output).group()
6325 static_network = '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address, 'Address=' + ipv6_address])
30d3b54e
YW
6326 print(static_network)
6327
a962d857 6328 remove_network_unit('25-dhcp-client.network')
30d3b54e 6329
a962d857 6330 with open(os.path.join(network_unit_dir, '25-static.network'), mode='w', encoding='utf-8') as f:
30d3b54e
YW
6331 f.write(static_network)
6332
15519a81 6333 restart_networkd()
95e1fbba 6334 self.wait_online('veth99:routable')
30d3b54e 6335
371810d1 6336 output = check_output('ip -4 address show dev veth99 scope global')
30d3b54e 6337 print(output)
15519a81
YW
6338 self.assertRegex(output, f'inet {ipv4_address} brd 192.168.5.255 scope global veth99\n *'
6339 'valid_lft forever preferred_lft forever')
30d3b54e 6340
371810d1 6341 output = check_output('ip -6 address show dev veth99 scope global')
30d3b54e 6342 print(output)
15519a81
YW
6343 self.assertRegex(output, f'inet6 {ipv6_address} scope global *\n *'
6344 'valid_lft forever preferred_lft forever')
30d3b54e 6345
18c613dc
YW
6346 @expectedFailureIfModuleIsNotAvailable('vrf')
6347 def test_dhcp_client_vrf(self):
a962d857
YW
6348 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-vrf.network',
6349 '25-vrf.netdev', '25-vrf.network')
2cf6fdff 6350 start_networkd()
95e1fbba 6351 self.wait_online('veth-peer:carrier')
ec38833c 6352 start_dnsmasq()
95e1fbba 6353 self.wait_online('veth99:routable', 'veth-peer:routable', 'vrf99:carrier')
2629df47
YW
6354
6355 # link become 'routable' when at least one protocol provide an valid address.
3e726c15 6356 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 6357 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
18c613dc
YW
6358
6359 print('## ip -d link show dev vrf99')
371810d1 6360 output = check_output('ip -d link show dev vrf99')
18c613dc
YW
6361 print(output)
6362 self.assertRegex(output, 'vrf table 42')
6363
6364 print('## ip address show vrf vrf99')
371810d1 6365 output = check_output('ip address show vrf vrf99')
d90f4f7d 6366 print(output)
3e726c15 6367 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
426654d7 6368 self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
d90f4f7d 6369 self.assertRegex(output, 'inet6 .* scope link')
18c613dc
YW
6370
6371 print('## ip address show dev veth99')
371810d1 6372 output = check_output('ip address show dev veth99')
18c613dc 6373 print(output)
3e726c15 6374 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
426654d7 6375 self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
18c613dc
YW
6376 self.assertRegex(output, 'inet6 .* scope link')
6377
6378 print('## ip route show vrf vrf99')
371810d1 6379 output = check_output('ip route show vrf vrf99')
18c613dc
YW
6380 print(output)
6381 self.assertRegex(output, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
18c613dc 6382 self.assertRegex(output, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
18c613dc
YW
6383 self.assertRegex(output, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
6384
6385 print('## ip route show table main dev veth99')
371810d1 6386 output = check_output('ip route show table main dev veth99')
18c613dc
YW
6387 print(output)
6388 self.assertEqual(output, '')
6389
af3b1498 6390 def test_dhcp_client_gateway_onlink_implicit(self):
a962d857
YW
6391 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network',
6392 '25-dhcp-client-gateway-onlink-implicit.network')
2cf6fdff 6393 start_networkd()
95e1fbba 6394 self.wait_online('veth-peer:carrier')
ec38833c 6395 start_dnsmasq()
95e1fbba 6396 self.wait_online('veth99:routable', 'veth-peer:routable')
af3b1498 6397
10d670a3 6398 output = networkctl_status('veth99')
af3b1498
YW
6399 print(output)
6400 self.assertRegex(output, '192.168.5')
6401
371810d1 6402 output = check_output('ip route list dev veth99 10.0.0.0/8')
af3b1498
YW
6403 print(output)
6404 self.assertRegex(output, 'onlink')
371810d1 6405 output = check_output('ip route list dev veth99 192.168.100.0/24')
af3b1498
YW
6406 print(output)
6407 self.assertRegex(output, 'onlink')
6408
2d7a594f 6409 def test_dhcp_client_with_ipv4ll(self):
a962d857
YW
6410 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network',
6411 '25-dhcp-client-with-ipv4ll.network')
2cf6fdff 6412 start_networkd()
2d7a594f
YW
6413 # we need to increase timeout above default, as this will need to wait for
6414 # systemd-networkd to get the dhcpv4 transient failure event
95e1fbba 6415 self.wait_online('veth99:degraded', 'veth-peer:routable', timeout='60s')
63c598ed 6416
2d7a594f 6417 output = check_output('ip -4 address show dev veth99')
63c598ed 6418 print(output)
2d7a594f 6419 self.assertNotIn('192.168.5.', output)
72c747e6 6420 self.assertIn('inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link', output)
63c598ed 6421
a962d857 6422 start_dnsmasq()
2d7a594f
YW
6423 print('Wait for a DHCP lease to be acquired and the IPv4LL address to be dropped')
6424 self.wait_address('veth99', r'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic', ipv='-4')
6425 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 6426 self.wait_online('veth99:routable')
63c598ed 6427
2d7a594f 6428 output = check_output('ip -4 address show dev veth99')
63c598ed 6429 print(output)
3e726c15 6430 self.assertRegex(output, r'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99')
2d7a594f
YW
6431 self.assertNotIn('169.254.', output)
6432 self.assertNotIn('scope link', output)
63c598ed 6433
2d7a594f
YW
6434 stop_dnsmasq()
6435 print('Wait for the DHCP lease to be expired and an IPv4LL address to be acquired')
286bf3a9 6436 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 6437 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 6438
2d7a594f 6439 output = check_output('ip -4 address show dev veth99')
117a55c7 6440 print(output)
2d7a594f 6441 self.assertNotIn('192.168.5.', output)
72c747e6 6442 self.assertIn('inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link', output)
240e4137 6443
3d8e0aa2
YW
6444 def test_dhcp_client_use_dns(self):
6445 def check(self, ipv4, ipv6):
a962d857
YW
6446 os.makedirs(os.path.join(network_unit_dir, '25-dhcp-client.network.d'), exist_ok=True)
6447 with open(os.path.join(network_unit_dir, '25-dhcp-client.network.d/override.conf'), mode='w', encoding='utf-8') as f:
3d8e0aa2
YW
6448 f.write('[DHCPv4]\nUseDNS=')
6449 f.write('yes' if ipv4 else 'no')
6450 f.write('\n[DHCPv6]\nUseDNS=')
6451 f.write('yes' if ipv6 else 'no')
6452 f.write('\n[IPv6AcceptRA]\nUseDNS=no')
6453
a962d857 6454 networkctl_reload()
95e1fbba 6455 self.wait_online('veth99:routable')
e2d5aab3 6456
3d8e0aa2
YW
6457 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
6458 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
6459 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
e2d5aab3 6460
3d8e0aa2 6461 # make resolved re-read the link state file
10d670a3 6462 resolvectl('revert', 'veth99')
e2d5aab3 6463
10d670a3 6464 output = resolvectl('dns', 'veth99')
3d8e0aa2
YW
6465 print(output)
6466 if ipv4:
6467 self.assertIn('192.168.5.1', output)
6468 else:
6469 self.assertNotIn('192.168.5.1', output)
6470 if ipv6:
6471 self.assertIn('2600::1', output)
6472 else:
6473 self.assertNotIn('2600::1', output)
e2d5aab3 6474
10d670a3 6475 check_json(networkctl_json())
e2d5aab3 6476
a962d857 6477 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client.network', copy_dropins=False)
e2d5aab3
YW
6478
6479 start_networkd()
95e1fbba 6480 self.wait_online('veth-peer:carrier')
a962d857
YW
6481 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1',
6482 '--dhcp-option=option6:dns-server,[2600::1]')
e2d5aab3 6483
3d8e0aa2
YW
6484 check(self, True, True)
6485 check(self, True, False)
6486 check(self, False, True)
6487 check(self, False, False)
e2d5aab3 6488
dbe960f0
RP
6489 def test_dhcp_client_use_captive_portal(self):
6490 def check(self, ipv4, ipv6):
6491 os.makedirs(os.path.join(network_unit_dir, '25-dhcp-client.network.d'), exist_ok=True)
6492 with open(os.path.join(network_unit_dir, '25-dhcp-client.network.d/override.conf'), mode='w', encoding='utf-8') as f:
6493 f.write('[DHCPv4]\nUseCaptivePortal=')
6494 f.write('yes' if ipv4 else 'no')
6495 f.write('\n[DHCPv6]\nUseCaptivePortal=')
6496 f.write('yes' if ipv6 else 'no')
6497 f.write('\n[IPv6AcceptRA]\nUseCaptivePortal=no')
6498
6499 networkctl_reload()
95e1fbba 6500 self.wait_online('veth99:routable')
dbe960f0
RP
6501
6502 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
6503 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
6504 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
6505
10d670a3 6506 output = networkctl_status('veth99')
dbe960f0
RP
6507 print(output)
6508 if ipv4 or ipv6:
6509 self.assertIn('Captive Portal: http://systemd.io', output)
6510 else:
6511 self.assertNotIn('Captive Portal: http://systemd.io', output)
6512
10d670a3 6513 check_json(networkctl_json())
dbe960f0
RP
6514
6515 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client.network', copy_dropins=False)
6516
6517 start_networkd()
95e1fbba 6518 self.wait_online('veth-peer:carrier')
dbe960f0
RP
6519 start_dnsmasq('--dhcp-option=114,http://systemd.io',
6520 '--dhcp-option=option6:103,http://systemd.io')
6521
6522 check(self, True, True)
6523 check(self, True, False)
6524 check(self, False, True)
6525 check(self, False, False)
6526
1219391c
RP
6527 def test_dhcp_client_reject_captive_portal(self):
6528 def check(self, ipv4, ipv6):
6529 os.makedirs(os.path.join(network_unit_dir, '25-dhcp-client.network.d'), exist_ok=True)
6530 with open(os.path.join(network_unit_dir, '25-dhcp-client.network.d/override.conf'), mode='w', encoding='utf-8') as f:
6531 f.write('[DHCPv4]\nUseCaptivePortal=')
6532 f.write('yes' if ipv4 else 'no')
6533 f.write('\n[DHCPv6]\nUseCaptivePortal=')
6534 f.write('yes' if ipv6 else 'no')
6535 f.write('\n[IPv6AcceptRA]\nUseCaptivePortal=no')
6536
6537 networkctl_reload()
95e1fbba 6538 self.wait_online('veth99:routable')
1219391c
RP
6539
6540 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
6541 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
6542 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
6543
10d670a3 6544 output = networkctl_status('veth99')
1219391c
RP
6545 print(output)
6546 self.assertNotIn('Captive Portal: ', output)
6547 self.assertNotIn('invalid/url', output)
6548
10d670a3 6549 check_json(networkctl_json())
1219391c
RP
6550
6551 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client.network', copy_dropins=False)
6552
6553 start_networkd()
95e1fbba 6554 self.wait_online('veth-peer:carrier')
1219391c
RP
6555 masq = lambda bs: ':'.join(f'{b:02x}' for b in bs)
6556 start_dnsmasq('--dhcp-option=114,' + masq(b'http://\x00invalid/url'),
6557 '--dhcp-option=option6:103,' + masq(b'http://\x00/invalid/url'))
6558
6559 check(self, True, True)
6560 check(self, True, False)
6561 check(self, False, True)
6562 check(self, False, False)
6563
a27588d4 6564class NetworkdDHCPPDTests(unittest.TestCase, Utilities):
caad88a2
YW
6565
6566 def setUp(self):
a962d857 6567 setup_common()
caad88a2
YW
6568
6569 def tearDown(self):
a962d857 6570 tear_down_common()
caad88a2 6571
ab06b74f
YW
6572 def check_dhcp6_prefix(self, link):
6573 description = get_link_description(link)
8fb6320e 6574
ab06b74f
YW
6575 self.assertIn('DHCPv6Client', description.keys())
6576 self.assertIn('Prefixes', description['DHCPv6Client'])
8fb6320e 6577
ab06b74f 6578 prefixInfo = description['DHCPv6Client']['Prefixes']
8fb6320e 6579
ab06b74f 6580 self.assertEqual(len(prefixInfo), 1)
8fb6320e 6581
ab06b74f
YW
6582 self.assertIn('Prefix', prefixInfo[0].keys())
6583 self.assertIn('PrefixLength', prefixInfo[0].keys())
6584 self.assertIn('PreferredLifetimeUSec', prefixInfo[0].keys())
6585 self.assertIn('ValidLifetimeUSec', prefixInfo[0].keys())
caad88a2 6586
ab06b74f
YW
6587 self.assertEqual(prefixInfo[0]['Prefix'][0:6], [63, 254, 5, 1, 255, 255])
6588 self.assertEqual(prefixInfo[0]['PrefixLength'], 56)
6589 self.assertGreater(prefixInfo[0]['PreferredLifetimeUSec'], 0)
6590 self.assertGreater(prefixInfo[0]['ValidLifetimeUSec'], 0)
6591
6592 def test_dhcp6pd_no_address(self):
6593 # For issue #29979.
6594 copy_network_unit('25-veth.netdev', '25-dhcp6pd-server.network', '25-dhcp6pd-upstream-no-address.network')
c742d7e8 6595
caad88a2 6596 start_networkd()
95e1fbba 6597 self.wait_online('veth-peer:routable')
a962d857 6598 start_isc_dhcpd(conf_file='isc-dhcpd-dhcp6pd.conf', ipv='-6')
95e1fbba 6599 self.wait_online('veth99:degraded')
1805e2cb 6600
1805e2cb
YW
6601 print('### ip -6 address show dev veth99 scope global')
6602 output = check_output('ip -6 address show dev veth99 scope global')
6603 print(output)
6604 self.assertNotIn('inet6 3ffe:501:ffff', output)
caad88a2 6605
ab06b74f 6606 self.check_dhcp6_prefix('veth99')
8fb6320e 6607
3b677c6f
YW
6608 def test_dhcp6pd_no_assign(self):
6609 # Similar to test_dhcp6pd_no_assign(), but in this case UseAddress=yes (default),
6610 # However, the server does not provide IA_NA. For issue #31349.
6611 copy_network_unit('25-veth.netdev', '25-dhcp6pd-server.network', '25-dhcp6pd-upstream-no-assign.network')
6612
6613 start_networkd()
6614 self.wait_online('veth-peer:routable')
6615 start_isc_dhcpd(conf_file='isc-dhcpd-dhcp6pd-no-range.conf', ipv='-6')
6616 self.wait_online('veth99:degraded')
6617
6618 print('### ip -6 address show dev veth99 scope global')
6619 output = check_output('ip -6 address show dev veth99 scope global')
6620 print(output)
6621 self.assertNotIn('inet6 3ffe:501:ffff', output)
6622
6623 self.check_dhcp6_prefix('veth99')
6624
ab06b74f
YW
6625 def test_dhcp6pd(self):
6626 copy_network_unit('25-veth.netdev', '25-dhcp6pd-server.network', '25-dhcp6pd-upstream.network',
6627 '25-veth-downstream-veth97.netdev', '25-dhcp-pd-downstream-veth97.network', '25-dhcp-pd-downstream-veth97-peer.network',
6628 '25-veth-downstream-veth98.netdev', '25-dhcp-pd-downstream-veth98.network', '25-dhcp-pd-downstream-veth98-peer.network',
6629 '11-dummy.netdev', '25-dhcp-pd-downstream-test1.network',
6630 '25-dhcp-pd-downstream-dummy97.network',
6631 '12-dummy.netdev', '25-dhcp-pd-downstream-dummy98.network',
6632 '13-dummy.netdev', '25-dhcp-pd-downstream-dummy99.network')
8fb6320e 6633
ab06b74f
YW
6634 start_networkd()
6635 self.wait_online('veth-peer:routable')
6636 start_isc_dhcpd(conf_file='isc-dhcpd-dhcp6pd.conf', ipv='-6')
95e1fbba
YW
6637 self.wait_online('veth99:routable', 'test1:routable', 'dummy98:routable', 'dummy99:degraded',
6638 'veth97:routable', 'veth97-peer:routable', 'veth98:routable', 'veth98-peer:routable')
1805e2cb 6639
ab06b74f
YW
6640 self.setup_nftset('addr6', 'ipv6_addr')
6641 self.setup_nftset('network6', 'ipv6_addr', 'flags interval;')
6642 self.setup_nftset('ifindex', 'iface_index')
6643
6644 # Check DBus assigned prefix information to veth99
6645 self.check_dhcp6_prefix('veth99')
6646
caad88a2
YW
6647 print('### ip -6 address show dev veth-peer scope global')
6648 output = check_output('ip -6 address show dev veth-peer scope global')
6649 print(output)
6650 self.assertIn('inet6 3ffe:501:ffff:100::1/64 scope global', output)
6651
f7805a6c
FS
6652 # Link Subnet IDs
6653 # test1: 0x00
6654 # dummy97: 0x01 (The link will appear later)
07b7337a
YW
6655 # dummy98: 0x00
6656 # dummy99: auto -> 0x02 (No address assignment)
f7805a6c
FS
6657 # veth97: 0x08
6658 # veth98: 0x09
38488bab 6659 # veth99: 0x10
6016f1cf 6660
caad88a2
YW
6661 print('### ip -6 address show dev veth99 scope global')
6662 output = check_output('ip -6 address show dev veth99 scope global')
6663 print(output)
6664 # IA_NA
6665 self.assertRegex(output, 'inet6 3ffe:501:ffff:100::[0-9]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
6666 # address in IA_PD (Token=static)
38488bab 6667 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic')
caad88a2 6668 # address in IA_PD (Token=eui64)
38488bab
YW
6669 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic')
6670 # address in IA_PD (temporary)
6671 # Note that the temporary addresses may appear after the link enters configured state
6672 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
6673
6674 print('### ip -6 address show dev test1 scope global')
6675 output = check_output('ip -6 address show dev test1 scope global')
6676 print(output)
6677 # address in IA_PD (Token=static)
6678 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
6679 # address in IA_PD (temporary)
6680 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')
6681
6682 print('### ip -6 address show dev dummy98 scope global')
6683 output = check_output('ip -6 address show dev dummy98 scope global')
6684 print(output)
6685 # address in IA_PD (Token=static)
07b7337a 6686 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
caad88a2 6687 # address in IA_PD (temporary)
07b7337a 6688 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
6689
6690 print('### ip -6 address show dev dummy99 scope global')
6691 output = check_output('ip -6 address show dev dummy99 scope global')
6692 print(output)
6693 # Assign=no
07b7337a 6694 self.assertNotRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]02')
caad88a2 6695
6c8d6bdd
YW
6696 print('### ip -6 address show dev veth97 scope global')
6697 output = check_output('ip -6 address show dev veth97 scope global')
6698 print(output)
6699 # address in IA_PD (Token=static)
6700 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
6701 # address in IA_PD (Token=eui64)
6702 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr')
6703 # address in IA_PD (temporary)
6704 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')
6705
6706 print('### ip -6 address show dev veth97-peer scope global')
6707 output = check_output('ip -6 address show dev veth97-peer scope global')
6708 print(output)
6709 # NDisc address (Token=static)
6710 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
6711 # NDisc address (Token=eui64)
6712 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr')
6713 # NDisc address (temporary)
6714 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')
6715
caad88a2
YW
6716 print('### ip -6 address show dev veth98 scope global')
6717 output = check_output('ip -6 address show dev veth98 scope global')
6718 print(output)
6719 # address in IA_PD (Token=static)
6720 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
6721 # address in IA_PD (Token=eui64)
6722 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr')
6723 # address in IA_PD (temporary)
6724 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')
6725
6726 print('### ip -6 address show dev veth98-peer scope global')
6727 output = check_output('ip -6 address show dev veth98-peer scope global')
6728 print(output)
6729 # NDisc address (Token=static)
6730 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
6731 # NDisc address (Token=eui64)
6732 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr')
6733 # NDisc address (temporary)
6734 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')
6735
caad88a2
YW
6736 print('### ip -6 route show type unreachable')
6737 output = check_output('ip -6 route show type unreachable')
6738 print(output)
6739 self.assertRegex(output, 'unreachable 3ffe:501:ffff:[2-9a-f]00::/56 dev lo proto dhcp')
6740
6741 print('### ip -6 route show dev veth99')
6742 output = check_output('ip -6 route show dev veth99')
6743 print(output)
38488bab 6744 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]10::/64 proto kernel metric [0-9]* expires')
caad88a2
YW
6745
6746 print('### ip -6 route show dev test1')
6747 output = check_output('ip -6 route show dev test1')
6748 print(output)
6749 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires')
6750
6751 print('### ip -6 route show dev dummy98')
6752 output = check_output('ip -6 route show dev dummy98')
6753 print(output)
07b7337a 6754 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires')
caad88a2
YW
6755
6756 print('### ip -6 route show dev dummy99')
6757 output = check_output('ip -6 route show dev dummy99')
6758 print(output)
07b7337a 6759 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires')
6016f1cf
YW
6760
6761 print('### ip -6 route show dev veth97')
6762 output = check_output('ip -6 route show dev veth97')
6763 print(output)
6764 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]08::/64 proto kernel metric [0-9]* expires')
6765
6766 print('### ip -6 route show dev veth97-peer')
6767 output = check_output('ip -6 route show dev veth97-peer')
6768 print(output)
6769 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]08::/64 proto ra metric [0-9]* expires')
caad88a2
YW
6770
6771 print('### ip -6 route show dev veth98')
6772 output = check_output('ip -6 route show dev veth98')
6773 print(output)
6774 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]09::/64 proto kernel metric [0-9]* expires')
6775
6776 print('### ip -6 route show dev veth98-peer')
6777 output = check_output('ip -6 route show dev veth98-peer')
6778 print(output)
6779 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]09::/64 proto ra metric [0-9]* expires')
6780
6781 # Test case for a downstream which appears later
6782 check_output('ip link add dummy97 type dummy')
95e1fbba 6783 self.wait_online('dummy97:routable')
caad88a2
YW
6784
6785 print('### ip -6 address show dev dummy97 scope global')
6786 output = check_output('ip -6 address show dev dummy97 scope global')
6787 print(output)
6788 # address in IA_PD (Token=static)
6016f1cf 6789 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
caad88a2 6790 # address in IA_PD (temporary)
6016f1cf 6791 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
6792
6793 print('### ip -6 route show dev dummy97')
6794 output = check_output('ip -6 route show dev dummy97')
6795 print(output)
6016f1cf 6796 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]01::/64 proto kernel metric [0-9]* expires')
caad88a2
YW
6797
6798 # Test case for reconfigure
a962d857 6799 networkctl_reconfigure('dummy98', 'dummy99')
95e1fbba 6800 self.wait_online('dummy98:routable', 'dummy99:degraded')
caad88a2
YW
6801
6802 print('### ip -6 address show dev dummy98 scope global')
6803 output = check_output('ip -6 address show dev dummy98 scope global')
6804 print(output)
6805 # address in IA_PD (Token=static)
07b7337a 6806 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
caad88a2 6807 # address in IA_PD (temporary)
07b7337a 6808 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
6809
6810 print('### ip -6 address show dev dummy99 scope global')
6811 output = check_output('ip -6 address show dev dummy99 scope global')
6812 print(output)
6813 # Assign=no
07b7337a 6814 self.assertNotRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]02')
caad88a2
YW
6815
6816 print('### ip -6 route show dev dummy98')
6817 output = check_output('ip -6 route show dev dummy98')
6818 print(output)
07b7337a 6819 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires')
6016f1cf
YW
6820
6821 print('### ip -6 route show dev dummy99')
6822 output = check_output('ip -6 route show dev dummy99')
6823 print(output)
07b7337a 6824 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires')
caad88a2 6825
a4640bed
TM
6826 self.check_netlabel('dummy98', '3ffe:501:ffff:[2-9a-f]00::/64')
6827
c742d7e8
TM
6828 self.check_nftset('addr6', '3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d')
6829 self.check_nftset('addr6', '3ffe:501:ffff:[2-9a-f]00:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*:[0-9a-f]*')
6830 self.check_nftset('network6', '3ffe:501:ffff:[2-9a-f]00::/64')
6831 self.check_nftset('ifindex', 'dummy98')
6832
6833 self.teardown_nftset('addr6', 'network6', 'ifindex')
6834
6a936c9c 6835 def verify_dhcp4_6rd(self, tunnel_name):
84cc85f9
YW
6836 print('### ip -4 address show dev veth-peer scope global')
6837 output = check_output('ip -4 address show dev veth-peer scope global')
6838 print(output)
6839 self.assertIn('inet 10.0.0.1/8 brd 10.255.255.255 scope global veth-peer', output)
6840
f7805a6c
FS
6841 # Link Subnet IDs
6842 # test1: 0x00
6843 # dummy97: 0x01 (The link will appear later)
07b7337a
YW
6844 # dummy98: 0x00
6845 # dummy99: auto -> 0x0[23] (No address assignment)
6846 # 6rd-XXX: auto -> 0x0[23]
f7805a6c
FS
6847 # veth97: 0x08
6848 # veth98: 0x09
6849 # veth99: 0x10
84cc85f9
YW
6850
6851 print('### ip -4 address show dev veth99 scope global')
6852 output = check_output('ip -4 address show dev veth99 scope global')
6853 print(output)
6854 self.assertRegex(output, 'inet 10.100.100.[0-9]*/8 (metric 1024 |)brd 10.255.255.255 scope global dynamic veth99')
6855
6856 print('### ip -6 address show dev veth99 scope global')
6857 output = check_output('ip -6 address show dev veth99 scope global')
6858 print(output)
6859 # address in IA_PD (Token=static)
6860 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
6861 # address in IA_PD (Token=eui64)
6862 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic mngtmpaddr')
6863 # address in IA_PD (temporary)
6864 # Note that the temporary addresses may appear after the link enters configured state
6865 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')
6866
6867 print('### ip -6 address show dev test1 scope global')
6868 output = check_output('ip -6 address show dev test1 scope global')
6869 print(output)
6870 # address in IA_PD (Token=static)
6871 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
6872 # address in IA_PD (temporary)
6873 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')
6874
6875 print('### ip -6 address show dev dummy98 scope global')
6876 output = check_output('ip -6 address show dev dummy98 scope global')
6877 print(output)
6878 # address in IA_PD (Token=static)
07b7337a 6879 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
84cc85f9 6880 # address in IA_PD (temporary)
07b7337a 6881 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
6882
6883 print('### ip -6 address show dev dummy99 scope global')
6884 output = check_output('ip -6 address show dev dummy99 scope global')
6885 print(output)
6886 # Assign=no
07b7337a 6887 self.assertNotRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+0[23]')
84cc85f9
YW
6888
6889 print('### ip -6 address show dev veth97 scope global')
6890 output = check_output('ip -6 address show dev veth97 scope global')
6891 print(output)
6892 # address in IA_PD (Token=static)
6893 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
6894 # address in IA_PD (Token=eui64)
6895 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr')
6896 # address in IA_PD (temporary)
6897 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')
6898
6899 print('### ip -6 address show dev veth97-peer scope global')
6900 output = check_output('ip -6 address show dev veth97-peer scope global')
6901 print(output)
6902 # NDisc address (Token=static)
6903 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
6904 # NDisc address (Token=eui64)
6905 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr')
6906 # NDisc address (temporary)
6907 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')
6908
6909 print('### ip -6 address show dev veth98 scope global')
6910 output = check_output('ip -6 address show dev veth98 scope global')
6911 print(output)
6912 # address in IA_PD (Token=static)
6913 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
6914 # address in IA_PD (Token=eui64)
6915 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr')
6916 # address in IA_PD (temporary)
6917 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')
6918
6919 print('### ip -6 address show dev veth98-peer scope global')
6920 output = check_output('ip -6 address show dev veth98-peer scope global')
6921 print(output)
6922 # NDisc address (Token=static)
6923 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
6924 # NDisc address (Token=eui64)
6925 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr')
6926 # NDisc address (temporary)
6927 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')
6928
6929 print('### ip -6 route show type unreachable')
6930 output = check_output('ip -6 route show type unreachable')
6931 print(output)
6932 self.assertRegex(output, 'unreachable 2001:db8:6464:[0-9a-f]+00::/56 dev lo proto dhcp')
6933
6934 print('### ip -6 route show dev veth99')
6935 output = check_output('ip -6 route show dev veth99')
6936 print(output)
6937 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+10::/64 proto kernel metric [0-9]* expires')
6938
6939 print('### ip -6 route show dev test1')
6940 output = check_output('ip -6 route show dev test1')
6941 print(output)
6942 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires')
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, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires')
84cc85f9
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, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto dhcp metric [0-9]* expires')
84cc85f9
YW
6953
6954 print('### ip -6 route show dev veth97')
6955 output = check_output('ip -6 route show dev veth97')
6956 print(output)
6957 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+08::/64 proto kernel metric [0-9]* expires')
6958
6959 print('### ip -6 route show dev veth97-peer')
6960 output = check_output('ip -6 route show dev veth97-peer')
6961 print(output)
6962 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+08::/64 proto ra metric [0-9]* expires')
6963
6964 print('### ip -6 route show dev veth98')
6965 output = check_output('ip -6 route show dev veth98')
6966 print(output)
6967 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+09::/64 proto kernel metric [0-9]* expires')
6968
6969 print('### ip -6 route show dev veth98-peer')
6970 output = check_output('ip -6 route show dev veth98-peer')
6971 print(output)
6972 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+09::/64 proto ra metric [0-9]* expires')
6973
84cc85f9
YW
6974 print('### ip -6 address show dev dummy97 scope global')
6975 output = check_output('ip -6 address show dev dummy97 scope global')
6976 print(output)
6977 # address in IA_PD (Token=static)
6978 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
6979 # address in IA_PD (temporary)
6980 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')
6981
6982 print('### ip -6 route show dev dummy97')
6983 output = check_output('ip -6 route show dev dummy97')
6984 print(output)
6985 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+01::/64 proto kernel metric [0-9]* expires')
6986
e4295d4d
FS
6987 print(f'### ip -d link show dev {tunnel_name}')
6988 output = check_output(f'ip -d link show dev {tunnel_name}')
84cc85f9
YW
6989 print(output)
6990 self.assertIn('link/sit 10.100.100.', output)
6991 self.assertIn('local 10.100.100.', output)
84cc85f9
YW
6992 self.assertIn('ttl 64', output)
6993 self.assertIn('6rd-prefix 2001:db8::/32', output)
6994 self.assertIn('6rd-relay_prefix 10.0.0.0/8', output)
6995
e4295d4d
FS
6996 print(f'### ip -6 address show dev {tunnel_name}')
6997 output = check_output(f'ip -6 address show dev {tunnel_name}')
84cc85f9 6998 print(output)
07b7337a 6999 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
7000 self.assertRegex(output, 'inet6 ::10.100.100.[0-9]+/96 scope global')
7001
e4295d4d
FS
7002 print(f'### ip -6 route show dev {tunnel_name}')
7003 output = check_output(f'ip -6 route show dev {tunnel_name}')
84cc85f9 7004 print(output)
07b7337a 7005 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto kernel metric [0-9]* expires')
84cc85f9
YW
7006 self.assertRegex(output, '::/96 proto kernel metric [0-9]*')
7007
7008 print('### ip -6 route show default')
7009 output = check_output('ip -6 route show default')
7010 print(output)
7011 self.assertIn('default', output)
e4295d4d 7012 self.assertIn(f'via ::10.0.0.1 dev {tunnel_name}', output)
84cc85f9 7013
6a936c9c 7014 def test_dhcp4_6rd(self):
e081ffc1
YW
7015 def get_dhcp_6rd_prefix(link):
7016 description = get_link_description(link)
8fb6320e 7017
7018 self.assertIn('DHCPv4Client', description.keys())
7019 self.assertIn('6rdPrefix', description['DHCPv4Client'].keys())
7020
7021 prefixInfo = description['DHCPv4Client']['6rdPrefix']
7022 self.assertIn('Prefix', prefixInfo.keys())
7023 self.assertIn('PrefixLength', prefixInfo.keys())
7024 self.assertIn('IPv4MaskLength', prefixInfo.keys())
7025 self.assertIn('BorderRouters', prefixInfo.keys())
7026
7027 return prefixInfo
7028
a962d857
YW
7029 copy_network_unit('25-veth.netdev', '25-dhcp4-6rd-server.network', '25-dhcp4-6rd-upstream.network',
7030 '25-veth-downstream-veth97.netdev', '25-dhcp-pd-downstream-veth97.network', '25-dhcp-pd-downstream-veth97-peer.network',
7031 '25-veth-downstream-veth98.netdev', '25-dhcp-pd-downstream-veth98.network', '25-dhcp-pd-downstream-veth98-peer.network',
7032 '11-dummy.netdev', '25-dhcp-pd-downstream-test1.network',
7033 '25-dhcp-pd-downstream-dummy97.network',
7034 '12-dummy.netdev', '25-dhcp-pd-downstream-dummy98.network',
7035 '13-dummy.netdev', '25-dhcp-pd-downstream-dummy99.network',
7036 '80-6rd-tunnel.network')
6a936c9c
YW
7037
7038 start_networkd()
95e1fbba 7039 self.wait_online('veth-peer:routable')
f7805a6c
FS
7040
7041 # ipv4masklen: 8
7042 # 6rd-prefix: 2001:db8::/32
7043 # br-addresss: 10.0.0.1
7044
a962d857
YW
7045 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',
7046 ipv4_range='10.100.100.100,10.100.100.200',
7047 ipv4_router='10.0.0.1')
95e1fbba
YW
7048 self.wait_online('veth99:routable', 'test1:routable', 'dummy98:routable', 'dummy99:degraded',
7049 'veth97:routable', 'veth97-peer:routable', 'veth98:routable', 'veth98-peer:routable')
6a936c9c 7050
8fb6320e 7051 # Check the DBus interface for assigned prefix information
e081ffc1 7052 prefixInfo = get_dhcp_6rd_prefix('veth99')
8fb6320e 7053
7054 self.assertEqual(prefixInfo['Prefix'], [32,1,13,184,0,0,0,0,0,0,0,0,0,0,0,0]) # 2001:db8::
7055 self.assertEqual(prefixInfo['PrefixLength'], 32)
7056 self.assertEqual(prefixInfo['IPv4MaskLength'], 8)
7057 self.assertEqual(prefixInfo['BorderRouters'], [[10,0,0,1]])
7058
6a936c9c
YW
7059 # Test case for a downstream which appears later
7060 check_output('ip link add dummy97 type dummy')
95e1fbba 7061 self.wait_online('dummy97:routable')
6a936c9c
YW
7062
7063 # Find tunnel name
7064 tunnel_name = None
7065 for name in os.listdir('/sys/class/net/'):
7066 if name.startswith('6rd-'):
7067 tunnel_name = name
7068 break
7069
95e1fbba 7070 self.wait_online(f'{tunnel_name}:routable')
6a936c9c
YW
7071
7072 self.verify_dhcp4_6rd(tunnel_name)
7073
7074 # Test case for reconfigure
a962d857 7075 networkctl_reconfigure('dummy98', 'dummy99')
95e1fbba 7076 self.wait_online('dummy98:routable', 'dummy99:degraded')
6a936c9c
YW
7077
7078 self.verify_dhcp4_6rd(tunnel_name)
7079
3af934bc 7080 print('Wait for the DHCP lease to be renewed/rebind')
a102a52c 7081 time.sleep(120)
6a936c9c 7082
95e1fbba
YW
7083 self.wait_online('veth99:routable', 'test1:routable', 'dummy97:routable', 'dummy98:routable', 'dummy99:degraded',
7084 'veth97:routable', 'veth97-peer:routable', 'veth98:routable', 'veth98-peer:routable')
6a936c9c
YW
7085
7086 self.verify_dhcp4_6rd(tunnel_name)
7087
9633f977 7088class NetworkdIPv6PrefixTests(unittest.TestCase, Utilities):
9633f977
SS
7089
7090 def setUp(self):
a962d857 7091 setup_common()
9633f977
SS
7092
7093 def tearDown(self):
a962d857 7094 tear_down_common()
9633f977
SS
7095
7096 def test_ipv6_route_prefix(self):
a962d857
YW
7097 copy_network_unit('25-veth.netdev', '25-ipv6ra-prefix-client.network', '25-ipv6ra-prefix.network',
7098 '12-dummy.netdev', '25-ipv6ra-uplink.network')
9633f977
SS
7099
7100 start_networkd()
95e1fbba 7101 self.wait_online('veth99:routable', 'veth-peer:routable', 'dummy98:routable')
9633f977 7102
635f2a66
YW
7103 output = check_output('ip address show dev veth-peer')
7104 print(output)
7105 self.assertIn('inet6 2001:db8:0:1:', output)
7106 self.assertNotIn('inet6 2001:db8:0:2:', output)
ab47f960 7107 self.assertNotIn('inet6 2001:db8:0:3:', output)
635f2a66 7108
3c874fd7 7109 output = check_output('ip -6 route show dev veth-peer')
9633f977 7110 print(output)
635f2a66
YW
7111 self.assertIn('2001:db8:0:1::/64 proto ra', output)
7112 self.assertNotIn('2001:db8:0:2::/64 proto ra', output)
ab47f960 7113 self.assertNotIn('2001:db8:0:3::/64 proto ra', output)
635f2a66
YW
7114 self.assertIn('2001:db0:fff::/64 via ', output)
7115 self.assertNotIn('2001:db1:fff::/64 via ', output)
ab47f960 7116 self.assertNotIn('2001:db2:fff::/64 via ', output)
9633f977 7117
635f2a66
YW
7118 output = check_output('ip address show dev veth99')
7119 print(output)
7120 self.assertNotIn('inet6 2001:db8:0:1:', output)
fe2a8b3d
YW
7121 self.assertIn('inet6 2001:db8:0:2:1a:2b:3c:4d', output)
7122 self.assertIn('inet6 2001:db8:0:2:fa:de:ca:fe', output)
ab47f960 7123 self.assertNotIn('inet6 2001:db8:0:3:', output)
635f2a66 7124
10d670a3 7125 output = resolvectl('dns', 'veth-peer')
4a906586
YW
7126 print(output)
7127 self.assertRegex(output, '2001:db8:1:1::2')
7128
10d670a3 7129 output = resolvectl('domain', 'veth-peer')
4a906586
YW
7130 print(output)
7131 self.assertIn('example.com', output)
7132
10d670a3 7133 check_json(networkctl_json())
94f0bd62 7134
10d670a3 7135 output = networkctl_json('veth-peer')
681007ac
SS
7136 check_json(output)
7137
7138 # PREF64 or NAT64
7139 pref64 = json.loads(output)['NDisc']['PREF64'][0]
7140
7141 prefix = socket.inet_ntop(socket.AF_INET6, bytearray(pref64['Prefix']))
7142 self.assertEqual(prefix, '64:ff9b::')
7143
7144 prefix_length = pref64['PrefixLength']
7145 self.assertEqual(prefix_length, 96)
7146
635f2a66 7147 def test_ipv6_route_prefix_deny_list(self):
a962d857
YW
7148 copy_network_unit('25-veth.netdev', '25-ipv6ra-prefix-client-deny-list.network', '25-ipv6ra-prefix.network',
7149 '12-dummy.netdev', '25-ipv6ra-uplink.network')
635f2a66
YW
7150
7151 start_networkd()
95e1fbba 7152 self.wait_online('veth99:routable', 'veth-peer:routable', 'dummy98:routable')
635f2a66
YW
7153
7154 output = check_output('ip address show dev veth-peer')
7155 print(output)
7156 self.assertIn('inet6 2001:db8:0:1:', output)
7157 self.assertNotIn('inet6 2001:db8:0:2:', output)
7158
7159 output = check_output('ip -6 route show dev veth-peer')
7160 print(output)
7161 self.assertIn('2001:db8:0:1::/64 proto ra', output)
7162 self.assertNotIn('2001:db8:0:2::/64 proto ra', output)
7163 self.assertIn('2001:db0:fff::/64 via ', output)
7164 self.assertNotIn('2001:db1:fff::/64 via ', output)
7165
7166 output = check_output('ip address show dev veth99')
3c874fd7 7167 print(output)
635f2a66
YW
7168 self.assertNotIn('inet6 2001:db8:0:1:', output)
7169 self.assertIn('inet6 2001:db8:0:2:', output)
3c874fd7 7170
10d670a3 7171 output = resolvectl('dns', 'veth-peer')
4a906586
YW
7172 print(output)
7173 self.assertRegex(output, '2001:db8:1:1::2')
7174
10d670a3 7175 output = resolvectl('domain', 'veth-peer')
4a906586
YW
7176 print(output)
7177 self.assertIn('example.com', output)
7178
7db05447 7179class NetworkdMTUTests(unittest.TestCase, Utilities):
7db05447
DS
7180
7181 def setUp(self):
a962d857 7182 setup_common()
7db05447
DS
7183
7184 def tearDown(self):
a962d857 7185 tear_down_common()
7db05447
DS
7186
7187 def check_mtu(self, mtu, ipv6_mtu=None, reset=True):
7188 if not ipv6_mtu:
7189 ipv6_mtu = mtu
7190
7191 # test normal start
7192 start_networkd()
95e1fbba 7193 self.wait_online('dummy98:routable')
a962d857
YW
7194 self.check_link_attr('dummy98', 'mtu', mtu)
7195 self.check_ipv6_sysctl_attr('dummy98', 'mtu', ipv6_mtu)
7db05447
DS
7196
7197 # test normal restart
7198 restart_networkd()
95e1fbba 7199 self.wait_online('dummy98:routable')
a962d857
YW
7200 self.check_link_attr('dummy98', 'mtu', mtu)
7201 self.check_ipv6_sysctl_attr('dummy98', 'mtu', ipv6_mtu)
7db05447
DS
7202
7203 if reset:
7204 self.reset_check_mtu(mtu, ipv6_mtu)
7205
7206 def reset_check_mtu(self, mtu, ipv6_mtu=None):
7207 ''' test setting mtu/ipv6_mtu with interface already up '''
7208 stop_networkd()
7209
7210 # note - changing the device mtu resets the ipv6 mtu
a962d857
YW
7211 check_output('ip link set up mtu 1501 dev dummy98')
7212 check_output('ip link set up mtu 1500 dev dummy98')
7213 self.check_link_attr('dummy98', 'mtu', '1500')
7214 self.check_ipv6_sysctl_attr('dummy98', 'mtu', '1500')
7db05447
DS
7215
7216 self.check_mtu(mtu, ipv6_mtu, reset=False)
7217
7218 def test_mtu_network(self):
a962d857 7219 copy_network_unit('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
7db05447
DS
7220 self.check_mtu('1600')
7221
7222 def test_mtu_netdev(self):
a962d857 7223 copy_network_unit('12-dummy-mtu.netdev', '12-dummy.network', copy_dropins=False)
7db05447
DS
7224 # note - MTU set by .netdev happens ONLY at device creation!
7225 self.check_mtu('1600', reset=False)
7226
7227 def test_mtu_link(self):
a962d857 7228 copy_network_unit('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', copy_dropins=False)
7db05447
DS
7229 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
7230 self.check_mtu('1600', reset=False)
7231
7232 def test_ipv6_mtu(self):
7233 ''' set ipv6 mtu without setting device mtu '''
a962d857 7234 copy_network_unit('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
7db05447
DS
7235 self.check_mtu('1500', '1400')
7236
7237 def test_ipv6_mtu_toolarge(self):
7238 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
a962d857 7239 copy_network_unit('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
7db05447
DS
7240 self.check_mtu('1500', '1500')
7241
7242 def test_mtu_network_ipv6_mtu(self):
7243 ''' set ipv6 mtu and set device mtu via network file '''
a962d857 7244 copy_network_unit('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
7db05447
DS
7245 self.check_mtu('1600', '1550')
7246
7247 def test_mtu_netdev_ipv6_mtu(self):
7248 ''' set ipv6 mtu and set device mtu via netdev file '''
a962d857 7249 copy_network_unit('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
7db05447
DS
7250 self.check_mtu('1600', '1550', reset=False)
7251
7252 def test_mtu_link_ipv6_mtu(self):
7253 ''' set ipv6 mtu and set device mtu via link file '''
a962d857 7254 copy_network_unit('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
7db05447
DS
7255 self.check_mtu('1600', '1550', reset=False)
7256
7257
1f0e3109 7258if __name__ == '__main__':
9c1ae484
YW
7259 parser = argparse.ArgumentParser()
7260 parser.add_argument('--build-dir', help='Path to build dir', dest='build_dir')
33b0e0c0 7261 parser.add_argument('--source-dir', help='Path to source dir/git tree', dest='source_dir')
9c1ae484 7262 parser.add_argument('--networkd', help='Path to systemd-networkd', dest='networkd_bin')
b6d587d1 7263 parser.add_argument('--resolved', help='Path to systemd-resolved', dest='resolved_bin')
b05c4d6b 7264 parser.add_argument('--timesyncd', help='Path to systemd-timesyncd', dest='timesyncd_bin')
641aa412 7265 parser.add_argument('--udevd', help='Path to systemd-udevd', dest='udevd_bin')
9c1ae484
YW
7266 parser.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest='wait_online_bin')
7267 parser.add_argument('--networkctl', help='Path to networkctl', dest='networkctl_bin')
b6d587d1
YW
7268 parser.add_argument('--resolvectl', help='Path to resolvectl', dest='resolvectl_bin')
7269 parser.add_argument('--timedatectl', help='Path to timedatectl', dest='timedatectl_bin')
b05c4d6b 7270 parser.add_argument('--udevadm', help='Path to udevadm', dest='udevadm_bin')
9c1ae484
YW
7271 parser.add_argument('--valgrind', help='Enable valgrind', dest='use_valgrind', type=bool, nargs='?', const=True, default=use_valgrind)
7272 parser.add_argument('--debug', help='Generate debugging logs', dest='enable_debug', type=bool, nargs='?', const=True, default=enable_debug)
94c03122 7273 parser.add_argument('--asan-options', help='ASAN options', dest='asan_options')
fa4c6095 7274 parser.add_argument('--lsan-options', help='LSAN options', dest='lsan_options')
94c03122 7275 parser.add_argument('--ubsan-options', help='UBSAN options', dest='ubsan_options')
6c9efba6 7276 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 7277 ns, unknown_args = parser.parse_known_args(namespace=unittest)
9c1ae484
YW
7278
7279 if ns.build_dir:
b05c4d6b
YW
7280 if ns.networkd_bin or ns.resolved_bin or ns.timesyncd_bin or ns.udevd_bin or \
7281 ns.wait_online_bin or ns.networkctl_bin or ns.resolvectl_bin or ns.timedatectl_bin or ns.udevadm_bin:
7282 print('WARNING: --networkd, --resolved, --timesyncd, --udevd, --wait-online, --networkctl, --resolvectl, --timedatectl, or --udevadm options are ignored when --build-dir is specified.')
9c1ae484 7283 networkd_bin = os.path.join(ns.build_dir, 'systemd-networkd')
b6d587d1 7284 resolved_bin = os.path.join(ns.build_dir, 'systemd-resolved')
b05c4d6b 7285 timesyncd_bin = os.path.join(ns.build_dir, 'systemd-timesyncd')
5a000cd4 7286 udevd_bin = os.path.join(ns.build_dir, 'udevadm')
9c1ae484
YW
7287 wait_online_bin = os.path.join(ns.build_dir, 'systemd-networkd-wait-online')
7288 networkctl_bin = os.path.join(ns.build_dir, 'networkctl')
b6d587d1
YW
7289 resolvectl_bin = os.path.join(ns.build_dir, 'resolvectl')
7290 timedatectl_bin = os.path.join(ns.build_dir, 'timedatectl')
b05c4d6b 7291 udevadm_bin = os.path.join(ns.build_dir, 'udevadm')
33b0e0c0 7292 systemd_udev_rules_build_dir = os.path.join(ns.build_dir, 'rules.d')
9c1ae484
YW
7293 else:
7294 if ns.networkd_bin:
7295 networkd_bin = ns.networkd_bin
b6d587d1
YW
7296 if ns.resolved_bin:
7297 resolved_bin = ns.resolved_bin
b05c4d6b
YW
7298 if ns.timesyncd_bin:
7299 timesyncd_bin = ns.timesyncd_bin
641aa412
YW
7300 if ns.udevd_bin:
7301 udevd_bin = ns.udevd_bin
9c1ae484
YW
7302 if ns.wait_online_bin:
7303 wait_online_bin = ns.wait_online_bin
7304 if ns.networkctl_bin:
7305 networkctl_bin = ns.networkctl_bin
b6d587d1
YW
7306 if ns.resolvectl_bin:
7307 resolvectl_bin = ns.resolvectl_bin
7308 if ns.timedatectl_bin:
7309 timedatectl_bin = ns.timedatectl_bin
b05c4d6b
YW
7310 if ns.udevadm_bin:
7311 udevadm_bin = ns.udevadm_bin
9c1ae484 7312
33b0e0c0
FS
7313 if ns.source_dir:
7314 systemd_source_dir = ns.source_dir
7315 else:
7316 systemd_source_dir = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../"))
7317 if not os.path.exists(os.path.join(systemd_source_dir, "meson_options.txt")):
7318 raise RuntimeError(f"{systemd_source_dir} doesn't appear to be a systemd source tree")
7319
9c1ae484
YW
7320 use_valgrind = ns.use_valgrind
7321 enable_debug = ns.enable_debug
94c03122 7322 asan_options = ns.asan_options
fa4c6095 7323 lsan_options = ns.lsan_options
94c03122 7324 ubsan_options = ns.ubsan_options
6c9efba6 7325 with_coverage = ns.with_coverage
9c1ae484
YW
7326
7327 if use_valgrind:
b05c4d6b
YW
7328 # Do not forget the trailing space.
7329 valgrind_cmd = 'valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all '
7330
7331 networkctl_cmd = valgrind_cmd.split() + [networkctl_bin]
7332 resolvectl_cmd = valgrind_cmd.split() + [resolvectl_bin]
7333 timedatectl_cmd = valgrind_cmd.split() + [timedatectl_bin]
7334 udevadm_cmd = valgrind_cmd.split() + [udevadm_bin]
7335 wait_online_cmd = valgrind_cmd.split() + [wait_online_bin]
9c1ae484 7336
94c03122 7337 if asan_options:
a962d857 7338 env.update({'ASAN_OPTIONS': asan_options})
fa4c6095 7339 if lsan_options:
a962d857 7340 env.update({'LSAN_OPTIONS': lsan_options})
94c03122 7341 if ubsan_options:
a962d857 7342 env.update({'UBSAN_OPTIONS': ubsan_options})
b05c4d6b
YW
7343 if use_valgrind:
7344 env.update({'SYSTEMD_MEMPOOL': '0'})
9c1ae484 7345
163d095f
YW
7346 wait_online_env = env.copy()
7347 if enable_debug:
a962d857 7348 wait_online_env.update({'SYSTEMD_LOG_LEVEL': 'debug'})
163d095f 7349
a561bcee 7350 sys.argv[1:] = unknown_args
0765763e 7351 unittest.main(verbosity=3)