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