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