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