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