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