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