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