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