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