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