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