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