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