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