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