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