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