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