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