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