]> git.ipfire.org Git - thirdparty/systemd.git/blame_incremental - test/test-network/systemd-networkd-tests.py
test-network: merge two more tests with test_dhcp_client_ipv4_only
[thirdparty/systemd.git] / test / test-network / systemd-networkd-tests.py
... / ...
CommitLineData
1#!/usr/bin/env python3
2# SPDX-License-Identifier: LGPL-2.1-or-later
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
6# systemd-networkd tests
7
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
11import argparse
12import errno
13import itertools
14import os
15import re
16import shutil
17import signal
18import subprocess
19import sys
20import time
21import unittest
22from shutil import copytree
23from pathlib import Path
24
25network_unit_file_path='/run/systemd/network'
26networkd_runtime_directory='/run/systemd/netif'
27networkd_conf_dropin_path='/run/systemd/networkd.conf.d'
28networkd_ci_path='/run/networkd-ci'
29network_sysctl_ipv6_path='/proc/sys/net/ipv6/conf'
30network_sysctl_ipv4_path='/proc/sys/net/ipv4/conf'
31
32udev_rules_dir='/run/udev/rules.d'
33
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'
37
38isc_dhcpd_pid_file='/run/networkd-ci/test-isc-dhcpd.pid'
39isc_dhcpd_lease_file='/run/networkd-ci/test-isc-dhcpd.lease'
40
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)
46udevd_bin=shutil.which('systemd-udevd', path=which_paths)
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
52use_valgrind=False
53enable_debug=True
54env = {}
55asan_options=None
56lsan_options=None
57ubsan_options=None
58with_coverage=False
59
60running_units = []
61
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:])
73 return subprocess.run(command, universal_newlines=True, check=False, **kwargs)
74
75def is_module_available(module_name):
76 lsmod_output = check_output('lsmod')
77 module_re = re.compile(rf'^{re.escape(module_name)}\b', re.MULTILINE)
78 return module_re.search(lsmod_output) or not call('modprobe', module_name, stderr=subprocess.DEVNULL)
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
88def expectedFailureIfERSPANv0IsNotSupported():
89 # erspan version 0 is supported since f989d546a2d5a9f001f6f8be49d98c10ab9b1897 (v5.8)
90 def f(func):
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)
104 if rc == 0:
105 call('ip link del erspan99')
106 return func
107
108 return unittest.expectedFailure(func)
109
110 return f
111
112def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable():
113 def f(func):
114 rc = call('ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7', stderr=subprocess.DEVNULL)
115 if rc == 0:
116 call('ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
117 return func
118
119 return unittest.expectedFailure(func)
120
121 return f
122
123def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
124 def f(func):
125 rc = call('ip rule add not from 192.168.100.19 ipproto tcp table 7', stderr=subprocess.DEVNULL)
126 if rc == 0:
127 call('ip rule del not from 192.168.100.19 ipproto tcp table 7')
128 return func
129
130 return unittest.expectedFailure(func)
131
132 return f
133
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
146
147 return unittest.expectedFailure(func)
148
149 return f
150
151def expectedFailureIfLinkFileFieldIsNotSet():
152 def f(func):
153 support = False
154 rc = call('ip link add name dummy99 type dummy', stderr=subprocess.DEVNULL)
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
163
164 return unittest.expectedFailure(func)
165
166 return f
167
168def expectedFailureIfNexthopIsNotAvailable():
169 def f(func):
170 rc = call('ip nexthop list', stderr=subprocess.DEVNULL)
171 if rc == 0:
172 return func
173
174 return unittest.expectedFailure(func)
175
176 return f
177
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
187
188 return unittest.expectedFailure(func)
189
190 return f
191
192def expectedFailureIfAlternativeNameIsNotAvailable():
193 def f(func):
194 supported = False
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:
198 rc = call('ip link show dev hogehogehogehogehoge', stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
199 if rc == 0:
200 supported = True
201
202 call('ip link del dummy98', stderr=subprocess.DEVNULL)
203 if supported:
204 return func
205
206 return unittest.expectedFailure(func)
207
208 return f
209
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:
218 with open('/sys/bus/netdevsim/new_device', mode='w', encoding='utf-8') as f:
219 f.write('99 1')
220 except OSError:
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:
226 with open('/sys/class/net/eni99np1/device/sriov_numvfs', mode='w', encoding='utf-8') as f:
227 f.write('3')
228 except OSError:
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
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
244
245 return unittest.expectedFailure(func)
246
247 return f
248
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
256
257 return unittest.expectedFailure(func)
258
259 return f
260
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
268
269 return unittest.expectedFailure(func)
270
271 return f
272
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
280
281 return unittest.expectedFailure(func)
282
283 return f
284
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
292
293 return unittest.expectedFailure(func)
294
295 return f
296
297def setUpModule():
298 os.makedirs(network_unit_file_path, exist_ok=True)
299 os.makedirs(networkd_conf_dropin_path, exist_ok=True)
300 os.makedirs(networkd_ci_path, exist_ok=True)
301 os.makedirs(udev_rules_dir, exist_ok=True)
302
303 shutil.rmtree(networkd_ci_path)
304 copytree(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'conf'), networkd_ci_path)
305
306 shutil.copy(os.path.join(networkd_ci_path, '00-debug-net.rules'), udev_rules_dir)
307
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']:
311 if call(f'systemctl is-active --quiet {u}') == 0:
312 check_output(f'systemctl stop {u}')
313 running_units.append(u)
314
315 drop_in = [
316 '[Unit]',
317 'StartLimitIntervalSec=0',
318 '[Service]',
319 'Restart=no',
320 'ExecStart=',
321 'ExecReload=',
322 ]
323 if use_valgrind:
324 drop_in += [
325 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin,
326 f'ExecReload=valgrind {networkctl_bin} reload',
327 'PrivateTmp=yes'
328 ]
329 else:
330 drop_in += [
331 'ExecStart=!!' + networkd_bin,
332 f'ExecReload={networkctl_bin} reload',
333 ]
334 if enable_debug:
335 drop_in += ['Environment=SYSTEMD_LOG_LEVEL=debug']
336 if asan_options:
337 drop_in += ['Environment=ASAN_OPTIONS="' + asan_options + '"']
338 if lsan_options:
339 drop_in += ['Environment=LSAN_OPTIONS="' + lsan_options + '"']
340 if ubsan_options:
341 drop_in += ['Environment=UBSAN_OPTIONS="' + ubsan_options + '"']
342 if asan_options or lsan_options or ubsan_options:
343 drop_in += ['SystemCallFilter=']
344 if use_valgrind or asan_options or lsan_options or ubsan_options:
345 drop_in += ['MemoryDenyWriteExecute=no']
346 if with_coverage:
347 drop_in += [
348 'ProtectSystem=no',
349 'ProtectHome=no',
350 ]
351
352 os.makedirs('/run/systemd/system/systemd-networkd.service.d', exist_ok=True)
353 with open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode='w', encoding='utf-8') as f:
354 f.write('\n'.join(drop_in))
355
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']
377 if with_coverage:
378 drop_in += [
379 'ProtectSystem=no',
380 'ProtectHome=no',
381 ]
382
383 os.makedirs('/run/systemd/system/systemd-resolved.service.d', exist_ok=True)
384 with open('/run/systemd/system/systemd-resolved.service.d/00-override.conf', mode='w', encoding='utf-8') as f:
385 f.write('\n'.join(drop_in))
386
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)
394 with open('/run/systemd/system/systemd-udevd.service.d/00-override.conf', mode='w', encoding='utf-8') as f:
395 f.write('\n'.join(drop_in))
396
397 check_output('systemctl daemon-reload')
398 print(check_output('systemctl cat systemd-networkd.service'))
399 print(check_output('systemctl cat systemd-resolved.service'))
400 print(check_output('systemctl cat systemd-udevd.service'))
401 check_output('systemctl restart systemd-resolved')
402 check_output('systemctl restart systemd-udevd')
403
404def tearDownModule():
405 shutil.rmtree(networkd_ci_path)
406 os.remove(os.path.join(udev_rules_dir, '00-debug-net.rules'))
407
408 for u in ['systemd-networkd.socket', 'systemd-networkd.service', 'systemd-resolved.service']:
409 check_output(f'systemctl stop {u}')
410
411 shutil.rmtree('/run/systemd/system/systemd-networkd.service.d')
412 shutil.rmtree('/run/systemd/system/systemd-resolved.service.d')
413 shutil.rmtree('/run/systemd/system/systemd-udevd.service.d')
414 check_output('systemctl daemon-reload')
415 check_output('systemctl restart systemd-udevd.service')
416
417 for u in running_units:
418 check_output(f'systemctl start {u}')
419
420def read_link_attr(*args):
421 with open(os.path.join('/sys/class/net/', *args), encoding='utf-8') as f:
422 return f.readline().strip()
423
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
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
438 with open(os.path.join(path, attribute), encoding='utf-8') as f:
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:
452 call('ip fou del port', port, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
453
454def remove_routing_policy_rule_tables(tables):
455 for table in tables:
456 rc = 0
457 while rc == 0:
458 rc = call('ip rule del table', table, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
459 rc = 0
460 while rc == 0:
461 rc = call('ip -6 rule del table', table, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
462
463def remove_routes(routes):
464 for route_type, addr in routes:
465 call('ip route del', route_type, addr, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
466
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():
471 dev_id = line.split()[1]
472 call(f'ip nexthop del id {dev_id}')
473
474def remove_l2tp_tunnels(tunnel_ids):
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):
483 with open(os.path.join(os.path.join(network_sysctl_ipv6_path, link), attribute), encoding='utf-8') as f:
484 return f.readline().strip()
485
486def read_ipv4_sysctl_attr(link, attribute):
487 with open(os.path.join(os.path.join(network_sysctl_ipv4_path, link), attribute), encoding='utf-8') as f:
488 return f.readline().strip()
489
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 """
500 print()
501 for unit in units:
502 if dropins and os.path.exists(os.path.join(networkd_ci_path, unit + '.d')):
503 copytree(os.path.join(networkd_ci_path, unit + '.d'), os.path.join(network_unit_file_path, unit + '.d'))
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)
511
512def remove_unit_from_networkd_path(units):
513 """Remove previously copied unit files from the testbed.
514
515 Drop-ins will be removed automatically.
516 """
517 for unit in units:
518 if os.path.exists(os.path.join(network_unit_file_path, unit)):
519 os.remove(os.path.join(network_unit_file_path, unit))
520 if os.path.exists(os.path.join(network_unit_file_path, unit + '.d')):
521 shutil.rmtree(os.path.join(network_unit_file_path, unit + '.d'))
522
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:
531 if os.path.exists(os.path.join(networkd_conf_dropin_path, dropin)):
532 os.remove(os.path.join(networkd_conf_dropin_path, dropin))
533
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
536 check_output(dnsmasq_command)
537
538def stop_by_pid_file(pid_file):
539 if os.path.exists(pid_file):
540 with open(pid_file, 'r', encoding='utf-8') as f:
541 pid = f.read().rstrip(' \t\r\n\0')
542 os.kill(int(pid), signal.SIGTERM)
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}")
552
553 os.remove(pid_file)
554
555def stop_dnsmasq():
556 stop_by_pid_file(dnsmasq_pid_file)
557
558def read_dnsmasq_log_file():
559 if os.path.exists(dnsmasq_log_file):
560 with open(dnsmasq_log_file, encoding='utf-8') as f:
561 return f.read()
562
563def remove_dnsmasq_lease_file():
564 if os.path.exists(dnsmasq_lease_file):
565 os.remove(dnsmasq_lease_file)
566
567def remove_dnsmasq_log_file():
568 if os.path.exists(dnsmasq_log_file):
569 os.remove(dnsmasq_log_file)
570
571def start_isc_dhcpd(interface, conf_file, ip):
572 conf_file_path = os.path.join(networkd_ci_path, conf_file)
573 isc_dhcpd_command = f'dhcpd {ip} -cf {conf_file_path} -lf {isc_dhcpd_lease_file} -pf {isc_dhcpd_pid_file} {interface}'
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
582def remove_networkd_state_files():
583 if os.path.exists(os.path.join(networkd_runtime_directory, 'state')):
584 os.remove(os.path.join(networkd_runtime_directory, 'state'))
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')
589 check_output('systemctl stop systemd-networkd.socket')
590 check_output('systemctl stop systemd-networkd.service')
591 if show_logs:
592 print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id))
593 if remove_state_files:
594 remove_networkd_state_files()
595
596def start_networkd(sleep_sec=0):
597 check_output('systemctl start systemd-networkd')
598 if sleep_sec > 0:
599 time.sleep(sleep_sec)
600
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
605class Utilities():
606 # pylint: disable=no-member
607
608 def check_link_exists(self, link):
609 self.assertTrue(link_exists(link))
610
611 def check_link_attr(self, *args):
612 self.assertEqual(read_link_attr(*args[:-1]), args[-1])
613
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):
620 if iteration != 0:
621 time.sleep(1)
622 if not link_exists(link):
623 continue
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
627 if fail_assert:
628 self.fail(f'Timed out waiting for {link} activated.')
629 return False
630
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):
651 if secs != 0:
652 time.sleep(1)
653 if not link_exists(link):
654 continue
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
659 if fail_assert:
660 self.fail(f'Timed out waiting for {link} to reach state {operstate}/{setup_state}')
661 return False
662
663 def wait_online(self, links_with_operstate, timeout='20s', bool_any=False, ipv4=False, ipv6=False, setup_state='configured', setup_timeout=5):
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
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
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 """
686 args = wait_online_cmd + [f'--timeout={timeout}'] + [f'--interface={link}' for link in links_with_operstate]
687 if bool_any:
688 args += ['--any']
689 if ipv4:
690 args += ['--ipv4']
691 if ipv6:
692 args += ['--ipv6']
693 try:
694 check_output(*args, env=env)
695 except subprocess.CalledProcessError:
696 for link in links_with_operstate:
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)
701 raise
702 if not bool_any and setup_state:
703 for link in links_with_operstate:
704 self.wait_operstate(link.split(':')[0], None, setup_state, setup_timeout)
705
706 def wait_address(self, link, address_regex, scope='global', ipv='', timeout_sec=100):
707 for i in range(timeout_sec):
708 if i > 0:
709 time.sleep(1)
710 output = check_output(f'ip {ipv} address show dev {link} scope {scope}')
711 if re.search(address_regex, output) and 'tentative' not in output:
712 break
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)
725
726class NetworkctlTests(unittest.TestCase, Utilities):
727
728 links = [
729 'dummy98',
730 'test1',
731 'veth99',
732 ]
733
734 units = [
735 '11-dummy.netdev',
736 '11-dummy-mtu.netdev',
737 '11-dummy.network',
738 '12-dummy.netdev',
739 '12-dummy.link',
740 '25-address-static.network',
741 '25-veth.netdev',
742 '26-netdev-link-local-addressing-yes.network',
743 ]
744
745 def setUp(self):
746 remove_links(self.links)
747 stop_networkd(show_logs=False)
748
749 def tearDown(self):
750 remove_links(self.links)
751 remove_unit_from_networkd_path(self.units)
752 stop_networkd(show_logs=True)
753
754 @expectedFailureIfAlternativeNameIsNotAvailable()
755 def test_altname(self):
756 copy_unit_to_networkd_unit_path('26-netdev-link-local-addressing-yes.network', '12-dummy.netdev', '12-dummy.link')
757 check_output('udevadm control --reload')
758 start_networkd()
759 self.wait_online(['dummy98:degraded'])
760
761 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98', env=env)
762 self.assertRegex(output, 'hogehogehogehogehogehoge')
763
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)
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)
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)
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)
808
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)
814 self.wait_operstate('test1', 'off', setup_state='unmanaged')
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)
822 self.wait_operstate('test1', 'degraded', setup_state='unmanaged')
823
824 remove_unit_from_networkd_path(['11-dummy.netdev'])
825 check_output(*networkctl_cmd, 'reload', env=env)
826 self.wait_operstate('test1', 'degraded', setup_state='unmanaged')
827
828 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
829 check_output(*networkctl_cmd, 'reload', env=env)
830 self.wait_operstate('test1', 'degraded')
831
832 def test_glob(self):
833 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
834 start_networkd()
835
836 self.wait_online(['test1:degraded'])
837
838 output = check_output(*networkctl_cmd, 'list', env=env)
839 self.assertRegex(output, '1 lo ')
840 self.assertRegex(output, 'test1')
841
842 output = check_output(*networkctl_cmd, 'list', 'test1', env=env)
843 self.assertNotRegex(output, '1 lo ')
844 self.assertRegex(output, 'test1')
845
846 output = check_output(*networkctl_cmd, 'list', 'te*', env=env)
847 self.assertNotRegex(output, '1 lo ')
848 self.assertRegex(output, 'test1')
849
850 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'te*', env=env)
851 self.assertNotRegex(output, '1: lo ')
852 self.assertRegex(output, 'test1')
853
854 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'tes[a-z][0-9]', env=env)
855 self.assertNotRegex(output, '1: lo ')
856 self.assertRegex(output, 'test1')
857
858 def test_mtu(self):
859 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
860 start_networkd()
861
862 self.wait_online(['test1:degraded'])
863
864 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'test1', env=env)
865 self.assertRegex(output, 'MTU: 1600')
866
867 def test_type(self):
868 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
869 start_networkd()
870 self.wait_online(['test1:degraded'])
871
872 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'test1', env=env)
873 print(output)
874 self.assertRegex(output, 'Type: ether')
875
876 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'lo', env=env)
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()
884 self.wait_online(['test1:degraded'])
885
886 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'test1', env=env)
887 print(output)
888 self.assertRegex(output, r'Link File: (/usr)?/lib/systemd/network/99-default.link')
889 self.assertRegex(output, r'Network File: /run/systemd/network/11-dummy.network')
890
891 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'lo', env=env)
892 print(output)
893 self.assertRegex(output, r'Link File: n/a')
894 self.assertRegex(output, r'Network File: n/a')
895
896 def test_delete_links(self):
897 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
898 '25-veth.netdev', '26-netdev-link-local-addressing-yes.network')
899 start_networkd()
900
901 self.wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
902
903 check_output(*networkctl_cmd, 'delete', 'test1', 'veth99', env=env)
904 self.assertFalse(link_exists('test1'))
905 self.assertFalse(link_exists('veth99'))
906 self.assertFalse(link_exists('veth-peer'))
907
908class NetworkdNetDevTests(unittest.TestCase, Utilities):
909
910 links_remove_earlier = [
911 'xfrm98',
912 'xfrm99',
913 ]
914
915 links = [
916 '6rdtun99',
917 'bareudp99',
918 'batadv99',
919 'bond98',
920 'bond99',
921 'bridge99',
922 'dropin-test',
923 'dummy98',
924 'erspan98',
925 'erspan99',
926 'geneve99',
927 'gretap96',
928 'gretap98',
929 'gretap99',
930 'gretun96',
931 'gretun97',
932 'gretun98',
933 'gretun99',
934 'ifb99',
935 'ip6gretap98',
936 'ip6gretap99',
937 'ip6gretun96',
938 'ip6gretun97',
939 'ip6gretun98',
940 'ip6gretun99',
941 'ip6tnl-external',
942 'ip6tnl-slaac',
943 'ip6tnl97',
944 'ip6tnl98',
945 'ip6tnl99',
946 'ipiptun96',
947 'ipiptun97',
948 'ipiptun98',
949 'ipiptun99',
950 'ipvlan99',
951 'ipvtap99',
952 'isataptun99',
953 'macvlan99',
954 'macvtap99',
955 'nlmon99',
956 'sittun96',
957 'sittun97',
958 'sittun98',
959 'sittun99',
960 'tap99',
961 'test1',
962 'tun99',
963 'vcan99',
964 'veth-mtu',
965 'veth99',
966 'vlan99',
967 'vrf99',
968 'vti6tun97',
969 'vti6tun98',
970 'vti6tun99',
971 'vtitun96',
972 'vtitun97',
973 'vtitun98',
974 'vtitun99',
975 'vxcan99',
976 'vxlan-slaac',
977 'vxlan97',
978 'vxlan98',
979 'vxlan99',
980 'wg97',
981 'wg98',
982 'wg99',
983 ]
984
985 units = [
986 '10-dropin-test.netdev',
987 '11-dummy.netdev',
988 '11-dummy.network',
989 '12-dummy.netdev',
990 '13-not-match-udev-property.network',
991 '14-match-udev-property.network',
992 '15-name-conflict-test.netdev',
993 '21-macvlan.netdev',
994 '21-macvtap.netdev',
995 '21-vlan-test1.network',
996 '21-vlan.netdev',
997 '21-vlan.network',
998 '25-6rd-tunnel.netdev',
999 '25-bareudp.netdev',
1000 '25-batadv.netdev',
1001 '25-bond.netdev',
1002 '25-bond-balanced-tlb.netdev',
1003 '25-bridge.netdev',
1004 '25-bridge-configure-without-carrier.network',
1005 '25-bridge.network',
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',
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',
1018 '25-geneve.netdev',
1019 '25-gretap-tunnel-local-any.netdev',
1020 '25-gretap-tunnel.netdev',
1021 '25-gre-tunnel-any-any.netdev',
1022 '25-gre-tunnel-local-any.netdev',
1023 '25-gre-tunnel-remote-any.netdev',
1024 '25-gre-tunnel.netdev',
1025 '25-ifb.netdev',
1026 '25-ip6gretap-tunnel-local-any.netdev',
1027 '25-ip6gretap-tunnel.netdev',
1028 '25-ip6gre-tunnel-any-any.netdev',
1029 '25-ip6gre-tunnel-local-any.netdev',
1030 '25-ip6gre-tunnel-remote-any.netdev',
1031 '25-ip6gre-tunnel.netdev',
1032 '25-ip6tnl-tunnel-external.netdev',
1033 '25-ip6tnl-tunnel-local-any.netdev',
1034 '25-ip6tnl-tunnel-local-slaac.netdev',
1035 '25-ip6tnl-tunnel-local-slaac.network',
1036 '25-ip6tnl-tunnel-remote-any.netdev',
1037 '25-ip6tnl-tunnel.netdev',
1038 '25-ipip-tunnel-any-any.netdev',
1039 '25-ipip-tunnel-independent.netdev',
1040 '25-ipip-tunnel-independent-loopback.netdev',
1041 '25-ipip-tunnel-local-any.netdev',
1042 '25-ipip-tunnel-remote-any.netdev',
1043 '25-ipip-tunnel.netdev',
1044 '25-ipvlan.netdev',
1045 '25-ipvtap.netdev',
1046 '25-isatap-tunnel.netdev',
1047 '25-macsec.key',
1048 '25-macsec.netdev',
1049 '25-macsec.network',
1050 '25-nlmon.netdev',
1051 '25-sit-tunnel-any-any.netdev',
1052 '25-sit-tunnel-local-any.netdev',
1053 '25-sit-tunnel-remote-any.netdev',
1054 '25-sit-tunnel.netdev',
1055 '25-tap.netdev',
1056 '25-tun.netdev',
1057 '25-tunnel-any-any.network',
1058 '25-tunnel-local-any.network',
1059 '25-tunnel-remote-any.network',
1060 '25-tunnel.network',
1061 '25-vcan.netdev',
1062 '25-veth-mtu.netdev',
1063 '25-veth.netdev',
1064 '25-vrf.netdev',
1065 '25-vti6-tunnel-any-any.netdev',
1066 '25-vti6-tunnel-local-any.netdev',
1067 '25-vti6-tunnel-remote-any.netdev',
1068 '25-vti6-tunnel.netdev',
1069 '25-vti-tunnel-any-any.netdev',
1070 '25-vti-tunnel-local-any.netdev',
1071 '25-vti-tunnel-remote-any.netdev',
1072 '25-vti-tunnel.netdev',
1073 '25-vxcan.netdev',
1074 '25-vxlan-independent.netdev',
1075 '25-vxlan-ipv6.netdev',
1076 '25-vxlan-local-slaac.netdev',
1077 '25-vxlan-local-slaac.network',
1078 '25-vxlan-veth99.network',
1079 '25-vxlan.netdev',
1080 '25-wireguard-23-peers.netdev',
1081 '25-wireguard-23-peers.network',
1082 '25-wireguard-no-peer.netdev',
1083 '25-wireguard-no-peer.network',
1084 '25-wireguard-preshared-key.txt',
1085 '25-wireguard-private-key.txt',
1086 '25-wireguard.netdev',
1087 '25-wireguard.network',
1088 '25-xfrm.netdev',
1089 '25-xfrm-independent.netdev',
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',
1115 ]
1116
1117 fou_ports = [
1118 '55555',
1119 '55556']
1120
1121 def setUp(self):
1122 remove_fou_ports(self.fou_ports)
1123 remove_links(self.links_remove_earlier)
1124 remove_links(self.links)
1125 stop_networkd(show_logs=False)
1126
1127 def tearDown(self):
1128 remove_fou_ports(self.fou_ports)
1129 remove_links(self.links_remove_earlier)
1130 remove_links(self.links)
1131 remove_unit_from_networkd_path(self.units)
1132 stop_networkd(show_logs=True)
1133
1134 def test_dropin_and_name_conflict(self):
1135 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
1136 start_networkd()
1137
1138 self.wait_online(['dropin-test:off'], setup_state='unmanaged')
1139
1140 output = check_output('ip link show dropin-test')
1141 print(output)
1142 self.assertRegex(output, '00:50:56:c0:00:28')
1143
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()
1147 self.wait_online(['dummy98:routable'])
1148
1149 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98', env=env)
1150 print(output)
1151 self.assertRegex(output, 'Network File: /run/systemd/network/14-match-udev-property')
1152
1153 def test_wait_online_any(self):
1154 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
1155 start_networkd()
1156
1157 self.wait_online(['bridge99', 'test1:degraded'], bool_any=True)
1158
1159 self.wait_operstate('bridge99', '(off|no-carrier)', setup_state='configuring')
1160 self.wait_operstate('test1', 'degraded')
1161
1162 @expectedFailureIfModuleIsNotAvailable('bareudp')
1163 def test_bareudp(self):
1164 copy_unit_to_networkd_unit_path('25-bareudp.netdev', '26-netdev-link-local-addressing-yes.network')
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
1174 @expectedFailureIfModuleIsNotAvailable('batman-adv')
1175 def test_batadv(self):
1176 copy_unit_to_networkd_unit_path('25-batadv.netdev', '26-netdev-link-local-addressing-yes.network')
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
1185 def test_bridge(self):
1186 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
1187 start_networkd()
1188
1189 self.wait_online(['bridge99:no-carrier'])
1190
1191 tick = os.sysconf('SC_CLK_TCK')
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))
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')))
1201
1202 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'bridge99', env=env)
1203 print(output)
1204 self.assertRegex(output, 'Priority: 9')
1205 self.assertRegex(output, 'STP: yes')
1206 self.assertRegex(output, 'Multicast IGMP Version: 3')
1207
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
1214 def test_bond(self):
1215 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
1216 start_networkd()
1217
1218 self.wait_online(['bond99:off', 'bond98:off'], setup_state='unmanaged')
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'))
1234
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
1246 def test_vlan(self):
1247 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
1248 '21-vlan.network', '21-vlan-test1.network')
1249 start_networkd()
1250
1251 self.wait_online(['test1:degraded', 'vlan99:routable'])
1252
1253 output = check_output('ip -d link show test1')
1254 print(output)
1255 self.assertRegex(output, ' mtu 2000 ')
1256
1257 output = check_output('ip -d link show vlan99')
1258 print(output)
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 ')
1265
1266 output = check_output('ip -4 address show dev test1')
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
1271 output = check_output('ip -4 address show dev vlan99')
1272 print(output)
1273 self.assertRegex(output, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
1274
1275 def test_macvtap(self):
1276 for mode in ['private', 'vepa', 'bridge', 'passthru']:
1277 with self.subTest(mode=mode):
1278 if mode != 'private':
1279 self.tearDown()
1280 copy_unit_to_networkd_unit_path('21-macvtap.netdev', '26-netdev-link-local-addressing-yes.network',
1281 '11-dummy.netdev', '25-macvtap.network')
1282 with open(os.path.join(network_unit_file_path, '21-macvtap.netdev'), mode='a', encoding='utf-8') as f:
1283 f.write('[MACVTAP]\nMode=' + mode)
1284 start_networkd()
1285
1286 self.wait_online(['macvtap99:degraded',
1287 'test1:carrier' if mode == 'passthru' else 'test1:degraded'])
1288
1289 output = check_output('ip -d link show macvtap99')
1290 print(output)
1291 self.assertRegex(output, 'macvtap mode ' + mode + ' ')
1292
1293 def test_macvlan(self):
1294 for mode in ['private', 'vepa', 'bridge', 'passthru']:
1295 with self.subTest(mode=mode):
1296 if mode != 'private':
1297 self.tearDown()
1298 copy_unit_to_networkd_unit_path('21-macvlan.netdev', '26-netdev-link-local-addressing-yes.network',
1299 '11-dummy.netdev', '25-macvlan.network')
1300 with open(os.path.join(network_unit_file_path, '21-macvlan.netdev'), mode='a', encoding='utf-8') as f:
1301 f.write('[MACVLAN]\nMode=' + mode)
1302 start_networkd()
1303
1304 self.wait_online(['macvlan99:degraded',
1305 'test1:carrier' if mode == 'passthru' else 'test1:degraded'])
1306
1307 output = check_output('ip -d link show test1')
1308 print(output)
1309 self.assertRegex(output, ' mtu 2000 ')
1310
1311 output = check_output('ip -d link show macvlan99')
1312 print(output)
1313 self.assertRegex(output, ' mtu 2000 ')
1314 self.assertRegex(output, 'macvlan mode ' + mode + ' ')
1315
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
1324 self.wait_online(['macvlan99:degraded',
1325 'test1:carrier' if mode == 'passthru' else 'test1:degraded'])
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
1336 @expectedFailureIfModuleIsNotAvailable('ipvlan')
1337 def test_ipvlan(self):
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()
1342 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', '26-netdev-link-local-addressing-yes.network',
1343 '11-dummy.netdev', '25-ipvlan.network')
1344 with open(os.path.join(network_unit_file_path, '25-ipvlan.netdev'), mode='a', encoding='utf-8') as f:
1345 f.write('[IPVLAN]\nMode=' + mode + '\nFlags=' + flag)
1346
1347 start_networkd()
1348 self.wait_online(['ipvlan99:degraded', 'test1:degraded'])
1349
1350 output = check_output('ip -d link show ipvlan99')
1351 print(output)
1352 self.assertRegex(output, 'ipvlan *mode ' + mode.lower() + ' ' + flag)
1353
1354 @expectedFailureIfModuleIsNotAvailable('ipvtap')
1355 def test_ipvtap(self):
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()
1360 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', '26-netdev-link-local-addressing-yes.network',
1361 '11-dummy.netdev', '25-ipvtap.network')
1362 with open(os.path.join(network_unit_file_path, '25-ipvtap.netdev'), mode='a', encoding='utf-8') as f:
1363 f.write('[IPVTAP]\nMode=' + mode + '\nFlags=' + flag)
1364
1365 start_networkd()
1366 self.wait_online(['ipvtap99:degraded', 'test1:degraded'])
1367
1368 output = check_output('ip -d link show ipvtap99')
1369 print(output)
1370 self.assertRegex(output, 'ipvtap *mode ' + mode.lower() + ' ' + flag)
1371
1372 def test_veth(self):
1373 copy_unit_to_networkd_unit_path('25-veth.netdev', '26-netdev-link-local-addressing-yes.network',
1374 '25-veth-mtu.netdev')
1375 start_networkd()
1376
1377 self.wait_online(['veth99:degraded', 'veth-peer:degraded', 'veth-mtu:degraded', 'veth-mtu-peer:degraded'])
1378
1379 output = check_output('ip -d link show veth99')
1380 print(output)
1381 self.assertRegex(output, 'link/ether 12:34:56:78:9a:bc')
1382 output = check_output('ip -d link show veth-peer')
1383 print(output)
1384 self.assertRegex(output, 'link/ether 12:34:56:78:9a:bd')
1385
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
1395 def test_tun(self):
1396 copy_unit_to_networkd_unit_path('25-tun.netdev')
1397 start_networkd()
1398
1399 self.wait_online(['tun99:off'], setup_state='unmanaged')
1400
1401 output = check_output('ip -d link show tun99')
1402 print(output)
1403 # Old ip command does not support IFF_ flags
1404 self.assertRegex(output, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
1405
1406 def test_tap(self):
1407 copy_unit_to_networkd_unit_path('25-tap.netdev')
1408 start_networkd()
1409
1410 self.wait_online(['tap99:off'], setup_state='unmanaged')
1411
1412 output = check_output('ip -d link show tap99')
1413 print(output)
1414 # Old ip command does not support IFF_ flags
1415 self.assertRegex(output, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
1416
1417 @expectedFailureIfModuleIsNotAvailable('vrf')
1418 def test_vrf(self):
1419 copy_unit_to_networkd_unit_path('25-vrf.netdev', '26-netdev-link-local-addressing-yes.network')
1420 start_networkd()
1421
1422 self.wait_online(['vrf99:carrier'])
1423
1424 @expectedFailureIfModuleIsNotAvailable('vcan')
1425 def test_vcan(self):
1426 copy_unit_to_networkd_unit_path('25-vcan.netdev', '26-netdev-link-local-addressing-yes.network')
1427 start_networkd()
1428
1429 self.wait_online(['vcan99:carrier'])
1430
1431 @expectedFailureIfModuleIsNotAvailable('vxcan')
1432 def test_vxcan(self):
1433 copy_unit_to_networkd_unit_path('25-vxcan.netdev', '26-netdev-link-local-addressing-yes.network')
1434 start_networkd()
1435
1436 self.wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
1437
1438 @expectedFailureIfModuleIsNotAvailable('wireguard')
1439 def test_wireguard(self):
1440 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
1441 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
1442 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt',
1443 '25-wireguard-no-peer.netdev', '25-wireguard-no-peer.network')
1444 start_networkd()
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)
1450
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
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
1516 if shutil.which('wg'):
1517 call('wg')
1518
1519 output = check_output('wg show wg99 listen-port')
1520 self.assertEqual(output, '51820')
1521 output = check_output('wg show wg99 fwmark')
1522 self.assertEqual(output, '0x4d2')
1523 output = check_output('wg show wg99 private-key')
1524 self.assertEqual(output, 'EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=')
1525 output = check_output('wg show wg99 allowed-ips')
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)
1530 output = check_output('wg show wg99 persistent-keepalive')
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)
1535 output = check_output('wg show wg99 endpoints')
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)
1540 output = check_output('wg show wg99 preshared-keys')
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)
1545
1546 output = check_output('wg show wg98 private-key')
1547 self.assertEqual(output, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr+WHtZLZ90FU=')
1548
1549 output = check_output('wg show wg97 listen-port')
1550 self.assertEqual(output, '51821')
1551 output = check_output('wg show wg97 fwmark')
1552 self.assertEqual(output, '0x4d3')
1553
1554 def test_geneve(self):
1555 copy_unit_to_networkd_unit_path('25-geneve.netdev', '26-netdev-link-local-addressing-yes.network')
1556 start_networkd()
1557
1558 self.wait_online(['geneve99:degraded'])
1559
1560 output = check_output('ip -d link show geneve99')
1561 print(output)
1562 self.assertRegex(output, '192.168.22.1')
1563 self.assertRegex(output, '6082')
1564 self.assertRegex(output, 'udpcsum')
1565 self.assertRegex(output, 'udp6zerocsumrx')
1566
1567 def test_ipip_tunnel(self):
1568 copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-ipip.network',
1569 '25-ipip-tunnel.netdev', '25-tunnel.network',
1570 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1571 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1572 '25-ipip-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1573 start_networkd()
1574 self.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'ipiptun96:routable', 'dummy98:degraded'])
1575
1576 output = check_output('ip -d link show ipiptun99')
1577 print(output)
1578 self.assertRegex(output, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98')
1579 output = check_output('ip -d link show ipiptun98')
1580 print(output)
1581 self.assertRegex(output, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98')
1582 output = check_output('ip -d link show ipiptun97')
1583 print(output)
1584 self.assertRegex(output, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98')
1585 output = check_output('ip -d link show ipiptun96')
1586 print(output)
1587 self.assertRegex(output, 'ipip (ipip )?remote any local any dev dummy98')
1588
1589 def test_gre_tunnel(self):
1590 copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-gretun.network',
1591 '25-gre-tunnel.netdev', '25-tunnel.network',
1592 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1593 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1594 '25-gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1595 start_networkd()
1596 self.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'gretun96:routable', 'dummy98:degraded'])
1597
1598 output = check_output('ip -d link show gretun99')
1599 print(output)
1600 self.assertRegex(output, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
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')
1605 output = check_output('ip -d link show gretun98')
1606 print(output)
1607 self.assertRegex(output, 'gre remote 10.65.223.239 local any dev dummy98')
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')
1612 output = check_output('ip -d link show gretun97')
1613 print(output)
1614 self.assertRegex(output, 'gre remote any local 10.65.223.238 dev dummy98')
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')
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')
1626
1627 def test_ip6gre_tunnel(self):
1628 copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-ip6gretun.network',
1629 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
1630 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1631 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1632 '25-ip6gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1633 start_networkd(5)
1634
1635 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1636
1637 self.check_link_exists('dummy98')
1638 self.check_link_exists('ip6gretun99')
1639 self.check_link_exists('ip6gretun98')
1640 self.check_link_exists('ip6gretun97')
1641 self.check_link_exists('ip6gretun96')
1642
1643 output = check_output('ip -d link show ip6gretun99')
1644 print(output)
1645 self.assertRegex(output, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1646 output = check_output('ip -d link show ip6gretun98')
1647 print(output)
1648 self.assertRegex(output, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
1649 output = check_output('ip -d link show ip6gretun97')
1650 print(output)
1651 self.assertRegex(output, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
1652 output = check_output('ip -d link show ip6gretun96')
1653 print(output)
1654 self.assertRegex(output, 'ip6gre remote any local any dev dummy98')
1655
1656 def test_gretap_tunnel(self):
1657 copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-gretap.network',
1658 '25-gretap-tunnel.netdev', '25-tunnel.network',
1659 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1660 start_networkd()
1661 self.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
1662
1663 output = check_output('ip -d link show gretap99')
1664 print(output)
1665 self.assertRegex(output, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
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')
1670 output = check_output('ip -d link show gretap98')
1671 print(output)
1672 self.assertRegex(output, 'gretap remote 10.65.223.239 local any dev dummy98')
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')
1677
1678 def test_ip6gretap_tunnel(self):
1679 copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-ip6gretap.network',
1680 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1681 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1682 start_networkd()
1683 self.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
1684
1685 output = check_output('ip -d link show ip6gretap99')
1686 print(output)
1687 self.assertRegex(output, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1688 output = check_output('ip -d link show ip6gretap98')
1689 print(output)
1690 self.assertRegex(output, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1691
1692 def test_vti_tunnel(self):
1693 copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-vti.network',
1694 '25-vti-tunnel.netdev', '25-tunnel.network',
1695 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1696 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1697 '25-vti-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1698 start_networkd()
1699 self.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'vtitun96:routable', 'dummy98:degraded'])
1700
1701 output = check_output('ip -d link show vtitun99')
1702 print(output)
1703 self.assertRegex(output, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1704 output = check_output('ip -d link show vtitun98')
1705 print(output)
1706 self.assertRegex(output, 'vti remote 10.65.223.239 local any dev dummy98')
1707 output = check_output('ip -d link show vtitun97')
1708 print(output)
1709 self.assertRegex(output, 'vti remote any local 10.65.223.238 dev dummy98')
1710 output = check_output('ip -d link show vtitun96')
1711 print(output)
1712 self.assertRegex(output, 'vti remote any local any dev dummy98')
1713
1714 def test_vti6_tunnel(self):
1715 copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-vti6.network',
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')
1719 start_networkd()
1720 self.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
1721
1722 output = check_output('ip -d link show vti6tun99')
1723 print(output)
1724 self.assertRegex(output, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1725 output = check_output('ip -d link show vti6tun98')
1726 print(output)
1727 self.assertRegex(output, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1728 output = check_output('ip -d link show vti6tun97')
1729 print(output)
1730 self.assertRegex(output, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1731
1732 def test_ip6tnl_tunnel(self):
1733 copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-ip6tnl.network',
1734 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1735 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1736 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1737 '25-veth.netdev', '25-ip6tnl-slaac.network', '25-ipv6-prefix.network',
1738 '25-ip6tnl-tunnel-local-slaac.netdev', '25-ip6tnl-tunnel-local-slaac.network',
1739 '25-ip6tnl-tunnel-external.netdev', '26-netdev-link-local-addressing-yes.network')
1740 start_networkd()
1741 self.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable',
1742 'ip6tnl-slaac:degraded', 'ip6tnl-external:degraded',
1743 'dummy98:degraded', 'veth99:routable', 'veth-peer:degraded'])
1744
1745 output = check_output('ip -d link show ip6tnl99')
1746 print(output)
1747 self.assertIn('ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98', output)
1748 output = check_output('ip -d link show ip6tnl98')
1749 print(output)
1750 self.assertRegex(output, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1751 output = check_output('ip -d link show ip6tnl97')
1752 print(output)
1753 self.assertRegex(output, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
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)
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)
1769
1770 def test_sit_tunnel(self):
1771 copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-sit.network',
1772 '25-sit-tunnel.netdev', '25-tunnel.network',
1773 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1774 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1775 '25-sit-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1776 start_networkd()
1777 self.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'sittun96:routable', 'dummy98:degraded'])
1778
1779 output = check_output('ip -d link show sittun99')
1780 print(output)
1781 self.assertRegex(output, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1782 output = check_output('ip -d link show sittun98')
1783 print(output)
1784 self.assertRegex(output, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98")
1785 output = check_output('ip -d link show sittun97')
1786 print(output)
1787 self.assertRegex(output, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98")
1788 output = check_output('ip -d link show sittun96')
1789 print(output)
1790 self.assertRegex(output, "sit (ip6ip )?remote any local any dev dummy98")
1791
1792 def test_isatap_tunnel(self):
1793 copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-isatap.network',
1794 '25-isatap-tunnel.netdev', '25-tunnel.network')
1795 start_networkd()
1796 self.wait_online(['isataptun99:routable', 'dummy98:degraded'])
1797
1798 output = check_output('ip -d link show isataptun99')
1799 print(output)
1800 self.assertRegex(output, "isatap ")
1801
1802 def test_6rd_tunnel(self):
1803 copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-6rd.network',
1804 '25-6rd-tunnel.netdev', '25-tunnel.network')
1805 start_networkd()
1806 self.wait_online(['sittun99:routable', 'dummy98:degraded'])
1807
1808 output = check_output('ip -d link show sittun99')
1809 print(output)
1810 self.assertRegex(output, '6rd-prefix 2602::/24')
1811
1812 @expectedFailureIfERSPANv0IsNotSupported()
1813 def test_erspan_tunnel_v0(self):
1814 copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-erspan.network',
1815 '25-erspan0-tunnel.netdev', '25-tunnel.network',
1816 '25-erspan0-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1817 start_networkd()
1818 self.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1819
1820 output = check_output('ip -d link show erspan99')
1821 print(output)
1822 self.assertIn('erspan remote 172.16.1.100 local 172.16.1.200', output)
1823 self.assertIn('erspan_ver 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)
1829 output = check_output('ip -d link show erspan98')
1830 print(output)
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)
1899
1900 def test_tunnel_independent(self):
1901 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', '26-netdev-link-local-addressing-yes.network')
1902 start_networkd()
1903
1904 self.wait_online(['ipiptun99:carrier'])
1905
1906 def test_tunnel_independent_loopback(self):
1907 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent-loopback.netdev', '26-netdev-link-local-addressing-yes.network')
1908 start_networkd()
1909
1910 self.wait_online(['ipiptun99:carrier'])
1911
1912 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1913 def test_xfrm(self):
1914 copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-xfrm.network',
1915 '25-xfrm.netdev', '25-xfrm-independent.netdev',
1916 '26-netdev-link-local-addressing-yes.network')
1917 start_networkd()
1918
1919 self.wait_online(['dummy98:degraded', 'xfrm98:degraded', 'xfrm99:degraded'])
1920
1921 output = check_output('ip -d link show dev xfrm98')
1922 print(output)
1923 self.assertIn('xfrm98@dummy98:', output)
1924 self.assertIn('xfrm if_id 0x98 ', output)
1925
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)
1930
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
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')
1940 start_networkd()
1941
1942 self.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'], setup_state='unmanaged')
1943
1944 output = check_output('ip fou show')
1945 print(output)
1946 self.assertRegex(output, 'port 55555 ipproto 4')
1947 self.assertRegex(output, 'port 55556 ipproto 47')
1948
1949 output = check_output('ip -d link show ipiptun96')
1950 print(output)
1951 self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55555')
1952 output = check_output('ip -d link show sittun96')
1953 print(output)
1954 self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55555')
1955 output = check_output('ip -d link show gretun96')
1956 print(output)
1957 self.assertRegex(output, 'encap fou encap-sport 1001 encap-dport 55556')
1958 output = check_output('ip -d link show gretap96')
1959 print(output)
1960 self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55556')
1961
1962 def test_vxlan(self):
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',
1968 '25-vxlan-local-slaac.netdev', '25-vxlan-local-slaac.network')
1969 start_networkd()
1970
1971 self.wait_online(['test1:degraded', 'veth99:routable', 'veth-peer:degraded',
1972 'vxlan99:degraded', 'vxlan98:degraded', 'vxlan97:degraded', 'vxlan-slaac:degraded'])
1973
1974 output = check_output('ip -d link show vxlan99')
1975 print(output)
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)
1986
1987 output = check_output('bridge fdb show dev vxlan99')
1988 print(output)
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)
1992
1993 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'vxlan99', env=env)
1994 print(output)
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)
2004
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
2013 @unittest.skip(reason="Causes kernel panic on recent kernels: https://bugzilla.kernel.org/show_bug.cgi?id=208315")
2014 def test_macsec(self):
2015 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
2016 '26-macsec.network', '12-dummy.netdev')
2017 start_networkd()
2018
2019 self.wait_online(['dummy98:degraded', 'macsec99:routable'])
2020
2021 output = check_output('ip -d link show macsec99')
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
2027 output = check_output('ip macsec show macsec99')
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
2042 def test_nlmon(self):
2043 copy_unit_to_networkd_unit_path('25-nlmon.netdev', '26-netdev-link-local-addressing-yes.network')
2044 start_networkd()
2045
2046 self.wait_online(['nlmon99:carrier'])
2047
2048 @expectedFailureIfModuleIsNotAvailable('ifb')
2049 def test_ifb(self):
2050 copy_unit_to_networkd_unit_path('25-ifb.netdev', '26-netdev-link-local-addressing-yes.network')
2051 start_networkd()
2052
2053 self.wait_online(['ifb99:degraded'])
2054
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',
2067 '25-l2tp.network',
2068 '25-l2tp-ip.netdev',
2069 '25-l2tp-udp.netdev']
2070
2071 l2tp_tunnel_ids = [ '10' ]
2072
2073 def setUp(self):
2074 remove_l2tp_tunnels(self.l2tp_tunnel_ids)
2075 remove_links(self.links)
2076 stop_networkd(show_logs=False)
2077
2078 def tearDown(self):
2079 remove_l2tp_tunnels(self.l2tp_tunnel_ids)
2080 remove_links(self.links)
2081 remove_unit_from_networkd_path(self.units)
2082 stop_networkd(show_logs=True)
2083
2084 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
2085 def test_l2tp_udp(self):
2086 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
2087 '25-l2tp-udp.netdev', '25-l2tp.network')
2088 start_networkd()
2089
2090 self.wait_online(['test1:routable', 'l2tp-ses1:degraded', 'l2tp-ses2:degraded'])
2091
2092 output = check_output('ip l2tp show tunnel tunnel_id 10')
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
2100 output = check_output('ip l2tp show session tid 10 session_id 15')
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
2106 output = check_output('ip l2tp show session tid 10 session_id 17')
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):
2114 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
2115 '25-l2tp-ip.netdev', '25-l2tp.network')
2116 start_networkd()
2117
2118 self.wait_online(['test1:routable', 'l2tp-ses3:degraded', 'l2tp-ses4:degraded'])
2119
2120 output = check_output('ip l2tp show tunnel tunnel_id 10')
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
2126 output = check_output('ip l2tp show session tid 10 session_id 25')
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
2132 output = check_output('ip l2tp show session tid 10 session_id 27')
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
2138class NetworkdNetworkTests(unittest.TestCase, Utilities):
2139 links = [
2140 'bond199',
2141 'dummy98',
2142 'dummy99',
2143 'gretun97',
2144 'ip6gretun97',
2145 'test1',
2146 'veth-peer',
2147 'veth99',
2148 'vlan99',
2149 'vrf99',
2150 ]
2151
2152 units = [
2153 '11-dummy.netdev',
2154 '12-dummy.netdev',
2155 '12-dummy.network',
2156 '21-vlan.netdev',
2157 '21-vlan-test1.network',
2158 '23-active-slave.network',
2159 '24-keep-configuration-static.network',
2160 '24-search-domain.network',
2161 '25-address-ipv4acd-veth99.network',
2162 '25-address-link-section.network',
2163 '25-address-peer-ipv4.network',
2164 '25-address-static.network',
2165 '25-activation-policy.network',
2166 '25-bind-carrier.network',
2167 '25-bond-active-backup-slave.netdev',
2168 '25-fibrule-invert.network',
2169 '25-fibrule-port-range.network',
2170 '25-fibrule-uidrange.network',
2171 '25-gre-tunnel-remote-any.netdev',
2172 '25-ip6gre-tunnel-remote-any.netdev',
2173 '25-ipv6-address-label-section.network',
2174 '25-ipv6-proxy-ndp.network',
2175 '25-link-local-addressing-no.network',
2176 '25-link-local-addressing-yes.network',
2177 '25-link-section-unmanaged.network',
2178 '25-neighbor-section.network',
2179 '25-neighbor-next.network',
2180 '25-neighbor-ipv6.network',
2181 '25-neighbor-ip-dummy.network',
2182 '25-neighbor-ip.network',
2183 '25-nexthop-dummy.network',
2184 '25-nexthop-nothing.network',
2185 '25-nexthop.network',
2186 '25-qdisc-cake.network',
2187 '25-qdisc-clsact-and-htb.network',
2188 '25-qdisc-drr.network',
2189 '25-qdisc-ets.network',
2190 '25-qdisc-fq_pie.network',
2191 '25-qdisc-hhf.network',
2192 '25-qdisc-ingress-netem-compat.network',
2193 '25-qdisc-pie.network',
2194 '25-qdisc-qfq.network',
2195 '25-prefix-route-with-vrf.network',
2196 '25-prefix-route-without-vrf.network',
2197 '25-route-ipv6-src.network',
2198 '25-route-static.network',
2199 '25-route-via-ipv6.network',
2200 '25-route-vrf.network',
2201 '25-gateway-static.network',
2202 '25-gateway-next-static.network',
2203 '25-sysctl-disable-ipv6.network',
2204 '25-sysctl.network',
2205 '25-test1.network',
2206 '25-veth-peer.network',
2207 '25-veth.netdev',
2208 '25-vrf.netdev',
2209 '25-vrf.network',
2210 '26-link-local-addressing-ipv6.network',
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',
2219 ]
2220
2221 networkd_conf_dropins = [
2222 'networkd-manage-foreign-routes-no.conf',
2223 ]
2224
2225 routing_policy_rule_tables = ['7', '8', '9', '10', '1011']
2226 routes = [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
2227
2228 def setUp(self):
2229 remove_blackhole_nexthops()
2230 remove_routing_policy_rule_tables(self.routing_policy_rule_tables)
2231 remove_routes(self.routes)
2232 remove_links(self.links)
2233 stop_networkd(show_logs=False)
2234 call('ip netns del ns99', stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
2235
2236 def tearDown(self):
2237 remove_blackhole_nexthops()
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)
2242 remove_networkd_conf_dropin(self.networkd_conf_dropins)
2243 stop_networkd(show_logs=True)
2244 call('ip netns del ns99', stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
2245
2246 def test_address_static(self):
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
2259 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
2260 start_networkd()
2261
2262 self.wait_online(['dummy98:routable'])
2263
2264 output = check_output('ip -4 address show dev dummy98')
2265 print(output)
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)
2270 self.assertIn('inet 10.8.8.1/16 scope global dummy98', output)
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')
2273
2274 # test for ENOBUFS issue #17012
2275 for i in range(1,254):
2276 self.assertIn(f'inet 10.3.3.{i}/16 brd 10.3.255.255', output)
2277
2278 # invalid sections
2279 self.assertNotIn('10.10.0.1/16', output)
2280 self.assertNotIn('10.10.0.2/16', output)
2281
2282 output = check_output('ip -4 address show dev dummy98 label 32')
2283 self.assertIn('inet 10.3.2.3/16 brd 10.3.255.255 scope global 32', output)
2284
2285 output = check_output('ip -4 address show dev dummy98 label 33')
2286 self.assertIn('inet 10.4.2.3 peer 10.4.2.4/16 scope global 33', output)
2287
2288 output = check_output('ip -4 address show dev dummy98 label 34')
2289 self.assertRegex(output, r'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
2290
2291 output = check_output('ip -4 address show dev dummy98 label 35')
2292 self.assertRegex(output, r'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
2293
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
2298 output = check_output('ip -6 address show dev dummy98')
2299 print(output)
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')
2307
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
2319 # 2. reconfigure the interface.
2320 check_output(*networkctl_cmd, 'reconfigure', 'dummy98', env=env)
2321 self.wait_online(['dummy98:routable'])
2322
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
2331 # test for ENOBUFS issue #17012
2332 output = check_output('ip -4 address show dev dummy98')
2333 for i in range(1,254):
2334 self.assertIn(f'inet 10.3.3.{i}/16 brd 10.3.255.255', output)
2335
2336 # TODO: check json string
2337 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
2338
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)
2348 start_networkd()
2349 self.wait_online(['veth99:routable'])
2350
2351 output = check_output('ip -4 address show dev veth99')
2352 print(output)
2353 self.assertNotIn('192.168.100.10/24', output)
2354 self.assertIn('192.168.100.11/24', output)
2355
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')
2363 print(output)
2364 self.assertNotIn('192.168.100.10/24', output)
2365 self.assertIn('192.168.100.11/24', output)
2366
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
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')
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')
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')
2417 self.assertRegex(output, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium')
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')
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')
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')
2447 self.assertRegex(output, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium')
2448
2449 def test_configure_without_carrier(self):
2450 copy_unit_to_networkd_unit_path('11-dummy.netdev')
2451 start_networkd()
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}')
2465 self.wait_online([f'test1:{routable_map[carrier]}:{routable_map[carrier]}'])
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])
2472
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}')
2489 self.wait_online([f'test1:{routable_map[carrier]}:{routable_map[carrier]}'])
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])
2500
2501 def test_routing_policy_rule(self):
2502 copy_unit_to_networkd_unit_path('25-routing-policy-rule-test1.network', '11-dummy.netdev')
2503 start_networkd()
2504 self.wait_online(['test1:degraded'])
2505
2506 output = check_output('ip rule list iif test1 priority 111')
2507 print(output)
2508 self.assertRegex(output, '111:')
2509 self.assertRegex(output, 'from 192.168.100.18')
2510 self.assertRegex(output, r'tos (0x08|throughput)\s')
2511 self.assertRegex(output, 'iif test1')
2512 self.assertRegex(output, 'oif test1')
2513 self.assertRegex(output, 'lookup 7')
2514
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
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
2536 # TODO: check json string
2537 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
2538
2539 def test_routing_policy_rule_issue_11280(self):
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')
2542
2543 for _ in range(3):
2544 # Remove state files only first time
2545 start_networkd(3)
2546 self.wait_online(['test1:degraded', 'dummy98:degraded'])
2547 time.sleep(1)
2548
2549 output = check_output('ip rule list table 7')
2550 print(output)
2551 self.assertRegex(output, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
2552
2553 output = check_output('ip rule list table 8')
2554 print(output)
2555 self.assertRegex(output, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
2556
2557 stop_networkd(remove_state_files=False)
2558
2559 def test_routing_policy_rule_reconfigure(self):
2560 copy_unit_to_networkd_unit_path('25-routing-policy-rule-reconfigure2.network', '11-dummy.netdev')
2561 start_networkd()
2562 self.wait_online(['test1:degraded'])
2563
2564 output = check_output('ip rule list table 1011')
2565 print(output)
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
2575 copy_unit_to_networkd_unit_path('25-routing-policy-rule-reconfigure1.network', '11-dummy.netdev')
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)
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')
2596 run('ip -6 rule delete priority 10113')
2597
2598 output = check_output('ip rule list table 1011')
2599 print(output)
2600 self.assertEqual(output, '')
2601
2602 output = check_output('ip -6 rule list table 1011')
2603 print(output)
2604 self.assertEqual(output, '')
2605
2606 run(*networkctl_cmd, 'reconfigure', 'test1', env=env)
2607 self.wait_online(['test1:degraded'])
2608
2609 output = check_output('ip rule list table 1011')
2610 print(output)
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)
2619
2620 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
2621 def test_routing_policy_rule_port_range(self):
2622 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
2623 start_networkd()
2624 self.wait_online(['test1:degraded'])
2625
2626 output = check_output('ip rule')
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')
2634
2635 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
2636 def test_routing_policy_rule_invert(self):
2637 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
2638 start_networkd()
2639 self.wait_online(['test1:degraded'])
2640
2641 output = check_output('ip rule')
2642 print(output)
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
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
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
2665 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
2666 start_networkd()
2667 self.wait_online(['dummy98:routable'])
2668
2669 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98', env=env)
2670 print(output)
2671
2672 print('### ip -6 route show dev dummy98')
2673 output = check_output('ip -6 route show dev dummy98')
2674 print(output)
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)
2677 self.assertIn('2001:1234:5:afff:ff:ff:ff:ff via fe80:0:222:4dff:ff:ff:ff:ff proto static', output)
2678
2679 print('### ip -6 route show default')
2680 output = check_output('ip -6 route show default')
2681 print(output)
2682 self.assertIn('default', output)
2683 self.assertIn('via 2001:1234:5:8fff:ff:ff:ff:ff', output)
2684
2685 print('### ip -4 route show dev dummy98')
2686 output = check_output('ip -4 route show dev dummy98')
2687 print(output)
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)
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)
2694 self.assertIn('multicast 149.10.123.4 proto static', output)
2695
2696 print('### ip -4 route show dev dummy98 default')
2697 output = check_output('ip -4 route show dev dummy98 default')
2698 print(output)
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)
2702
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)
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)
2709
2710 print('### ip route show type blackhole')
2711 output = check_output('ip route show type blackhole')
2712 print(output)
2713 self.assertIn('blackhole 202.54.1.2 proto static', output)
2714
2715 print('### ip route show type unreachable')
2716 output = check_output('ip route show type unreachable')
2717 print(output)
2718 self.assertIn('unreachable 202.54.1.3 proto static', output)
2719
2720 print('### ip route show type prohibit')
2721 output = check_output('ip route show type prohibit')
2722 print(output)
2723 self.assertIn('prohibit 202.54.1.4 proto static', output)
2724
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
2740 print('### ip route show 192.168.10.1')
2741 output = check_output('ip route show 192.168.10.1')
2742 print(output)
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)
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...
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)
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...
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)
2763
2764 # TODO: check json string
2765 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
2766
2767 copy_unit_to_networkd_unit_path('25-address-static.network')
2768 check_output(*networkctl_cmd, 'reload', env=env)
2769 time.sleep(1)
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
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
2803 remove_unit_from_networkd_path(['25-address-static.network'])
2804 check_output(*networkctl_cmd, 'reload', env=env)
2805 time.sleep(1)
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)
2812 self.assertIn('blackhole 202.54.1.2 proto static', output)
2813
2814 print('### ip route show type unreachable')
2815 output = check_output('ip route show type unreachable')
2816 print(output)
2817 self.assertIn('unreachable 202.54.1.3 proto static', output)
2818
2819 print('### ip route show type prohibit')
2820 output = check_output('ip route show type prohibit')
2821 print(output)
2822 self.assertIn('prohibit 202.54.1.4 proto static', output)
2823
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
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
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
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
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
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
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
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
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')
2942 start_networkd()
2943 self.wait_online(['dummy98:enslaved', 'bond199:routable'])
2944
2945 output = check_output('ip -6 route list dev bond199')
2946 print(output)
2947 self.assertRegex(output, 'abcd::/16')
2948 self.assertRegex(output, 'src')
2949 self.assertRegex(output, '2001:1234:56:8f63::2')
2950
2951 def test_ip_link_mac_address(self):
2952 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
2953 start_networkd()
2954 self.wait_online(['dummy98:degraded'])
2955
2956 output = check_output('ip link show dummy98')
2957 print(output)
2958 self.assertRegex(output, '00:01:02:aa:bb:cc')
2959
2960 def test_ip_link_unmanaged(self):
2961 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
2962 start_networkd(5)
2963
2964 self.check_link_exists('dummy98')
2965
2966 self.wait_operstate('dummy98', 'off', setup_state='unmanaged')
2967
2968 def test_ipv6_address_label(self):
2969 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
2970 start_networkd()
2971 self.wait_online(['dummy98:degraded'])
2972
2973 output = check_output('ip addrlabel list')
2974 print(output)
2975 self.assertRegex(output, '2004:da8:1::/64')
2976
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
2988 def test_neighbor_section(self):
2989 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2990 start_networkd()
2991 self.wait_online(['dummy98:degraded'], timeout='40s')
2992
2993 print('### ip neigh list dev dummy98')
2994 output = check_output('ip neigh list dev dummy98')
2995 print(output)
2996 self.assertRegex(output, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2997 self.assertRegex(output, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2998
2999 # TODO: check json string
3000 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
3001
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
3024 def test_neighbor_gre(self):
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')
3027 start_networkd()
3028 self.wait_online(['dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable'], timeout='40s')
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')
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')
3037
3038 # TODO: check json string
3039 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
3040
3041 def test_link_local_addressing(self):
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')
3044 start_networkd()
3045 self.wait_online(['test1:degraded', 'dummy98:carrier'])
3046
3047 output = check_output('ip address show dev test1')
3048 print(output)
3049 self.assertRegex(output, 'inet .* scope link')
3050 self.assertRegex(output, 'inet6 .* scope link')
3051
3052 output = check_output('ip address show dev dummy98')
3053 print(output)
3054 self.assertNotRegex(output, 'inet6* .* scope link')
3055
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
3067
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')
3071
3072 def test_link_local_addressing_ipv6ll(self):
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
3077 # An IPv6LL address exists by default.
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')
3083 check_output(*networkctl_cmd, 'reload', env=env)
3084 time.sleep(1)
3085 self.wait_online(['dummy98:carrier'])
3086
3087 # Check if the IPv6LL address is removed.
3088 output = check_output('ip address show dev dummy98')
3089 print(output)
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')
3101
3102 def test_sysctl(self):
3103 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
3104 start_networkd()
3105 self.wait_online(['dummy98:degraded'])
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')
3114 self.assertEqual(read_ipv4_sysctl_attr('dummy98', 'accept_local'), '1')
3115
3116 def test_sysctl_disable_ipv6(self):
3117 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
3118
3119 print('## Disable ipv6')
3120 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
3121 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
3122
3123 start_networkd()
3124 self.wait_online(['dummy98:routable'])
3125
3126 output = check_output('ip -4 address show dummy98')
3127 print(output)
3128 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
3129 output = check_output('ip -6 address show dummy98')
3130 print(output)
3131 self.assertRegex(output, 'inet6 2607:5300:203:3906::/64 scope global')
3132 self.assertRegex(output, 'inet6 .* scope link')
3133 output = check_output('ip -4 route show dev dummy98')
3134 print(output)
3135 self.assertRegex(output, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
3136 output = check_output('ip -6 route show default')
3137 print(output)
3138 self.assertRegex(output, 'default')
3139 self.assertRegex(output, 'via 2607:5300:203:39ff:ff:ff:ff:ff')
3140
3141 check_output('ip link del dummy98')
3142
3143 print('## Enable ipv6')
3144 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
3145 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
3146
3147 restart_networkd(3)
3148 self.wait_online(['dummy98:routable'])
3149
3150 output = check_output('ip -4 address show dummy98')
3151 print(output)
3152 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
3153 output = check_output('ip -6 address show dummy98')
3154 print(output)
3155 self.assertRegex(output, 'inet6 2607:5300:203:3906::/64 scope global')
3156 self.assertRegex(output, 'inet6 .* scope link')
3157 output = check_output('ip -4 route show dev dummy98')
3158 print(output)
3159 self.assertRegex(output, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
3160 output = check_output('ip -6 route show default')
3161 print(output)
3162 self.assertRegex(output, 'via 2607:5300:203:39ff:ff:ff:ff:ff')
3163
3164 def test_bind_carrier(self):
3165 check_output('ip link add dummy98 type dummy')
3166 check_output('ip link set dummy98 up')
3167 time.sleep(2)
3168
3169 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
3170 start_networkd()
3171 self.wait_online(['test1:routable'])
3172
3173 output = check_output('ip address show test1')
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')
3177 self.wait_operstate('test1', 'routable')
3178
3179 check_output('ip link add dummy99 type dummy')
3180 check_output('ip link set dummy99 up')
3181 time.sleep(2)
3182 output = check_output('ip address show test1')
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')
3186 self.wait_operstate('test1', 'routable')
3187
3188 check_output('ip link del dummy98')
3189 time.sleep(2)
3190 output = check_output('ip address show test1')
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')
3194 self.wait_operstate('test1', 'routable')
3195
3196 check_output('ip link set dummy99 down')
3197 time.sleep(2)
3198 output = check_output('ip address show test1')
3199 print(output)
3200 self.assertNotRegex(output, 'UP,LOWER_UP')
3201 self.assertRegex(output, 'DOWN')
3202 self.assertNotRegex(output, '192.168.10')
3203 self.wait_operstate('test1', 'off')
3204
3205 check_output('ip link set dummy99 up')
3206 time.sleep(2)
3207 output = check_output('ip address show test1')
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')
3211 self.wait_operstate('test1', 'routable')
3212
3213 def _test_activation_policy(self, test, interface):
3214 conffile = '25-activation-policy.network'
3215 if test:
3216 conffile = f'{conffile}.d/{test}.conf'
3217 if interface == 'vlan99':
3218 copy_unit_to_networkd_unit_path('21-vlan.netdev', '21-vlan-test1.network')
3219 copy_unit_to_networkd_unit_path('11-dummy.netdev', conffile, dropins=False)
3220 start_networkd()
3221
3222 always = test.startswith('always')
3223 initial_up = test != 'manual' and not test.endswith('down') # note: default is up
3224 expect_up = initial_up
3225 next_up = not expect_up
3226
3227 if test.endswith('down'):
3228 self.wait_activated(interface)
3229
3230 for iteration in range(4):
3231 with self.subTest(iteration=iteration, expect_up=expect_up):
3232 operstate = 'routable' if expect_up else 'off'
3233 setup_state = 'configured' if expect_up else ('configuring' if iteration == 0 else None)
3234 self.wait_operstate(interface, operstate, setup_state=setup_state, setup_timeout=20)
3235
3236 if expect_up:
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}'))
3240 else:
3241 self.assertIn('DOWN', check_output(f'ip link show {interface}'))
3242
3243 if next_up:
3244 check_output(f'ip link set dev {interface} up')
3245 else:
3246 check_output(f'ip link set dev {interface} down')
3247 expect_up = initial_up if always else next_up
3248 next_up = not next_up
3249 if always:
3250 time.sleep(1)
3251
3252 def test_activation_policy(self):
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()
3260
3261 def _test_activation_policy_required_for_online(self, policy, required):
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
3271 if policy.endswith('down'):
3272 self.wait_activated('test1')
3273
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
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):
3303 self.setUp()
3304 self._test_activation_policy_required_for_online(policy, required)
3305 self.tearDown()
3306
3307 def test_domain(self):
3308 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
3309 start_networkd()
3310 self.wait_online(['dummy98:routable'])
3311
3312 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98', env=env)
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
3318 def test_keep_configuration_static(self):
3319 check_output('systemctl stop systemd-networkd.socket')
3320 check_output('systemctl stop systemd-networkd.service')
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')
3333 start_networkd()
3334 self.wait_online(['dummy98:routable'])
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
3341 @expectedFailureIfNexthopIsNotAvailable()
3342 def test_nexthop(self):
3343 def check_nexthop(self):
3344 self.wait_online(['veth99:routable', 'veth-peer:routable', 'dummy98:routable'])
3345
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')
3353 self.assertIn('id 8 via fe80:0:222:4dff:ff:ff:ff:ff dev veth99', output)
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)
3359
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)
3365
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)')
3370
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)
3374
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)
3378
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)
3382
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)
3386
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
3401 # TODO: check json string
3402 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
3403
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)
3409
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
3416 self.wait_online(['veth99:routable', 'veth-peer:routable'])
3417
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')
3427 rc = call(*networkctl_cmd, 'reconfigure', 'dummy98', env=env)
3428 self.assertEqual(rc, 0)
3429 rc = call(*networkctl_cmd, 'reload', env=env)
3430 self.assertEqual(rc, 0)
3431 time.sleep(1)
3432
3433 check_nexthop(self)
3434
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
3443 def test_qdisc(self):
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')
3447 start_networkd()
3448
3449 self.wait_online(['dummy98:routable', 'test1:routable'])
3450
3451 output = check_output('tc qdisc show dev test1')
3452 print(output)
3453 self.assertRegex(output, 'qdisc netem')
3454 self.assertRegex(output, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
3455 self.assertRegex(output, 'qdisc ingress')
3456
3457 output = check_output('tc qdisc show dev dummy98')
3458 print(output)
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')
3465 self.assertRegex(output, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
3466 self.assertRegex(output, 'qdisc fq_codel')
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')
3468
3469 self.assertRegex(output, 'qdisc teql1 31: parent 2:31')
3470
3471 self.assertRegex(output, 'qdisc fq 32: parent 2:32')
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')
3476
3477 self.assertRegex(output, 'qdisc codel 33: parent 2:33')
3478 self.assertRegex(output, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn')
3479
3480 self.assertRegex(output, 'qdisc fq_codel 34: parent 2:34')
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')
3482
3483 self.assertRegex(output, 'qdisc tbf 35: parent 2:35')
3484 self.assertRegex(output, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms')
3485
3486 self.assertRegex(output, 'qdisc sfq 36: parent 2:36')
3487 self.assertRegex(output, 'perturb 5sec')
3488
3489 self.assertRegex(output, 'qdisc pfifo 37: parent 2:37')
3490 self.assertRegex(output, 'limit 100000p')
3491
3492 self.assertRegex(output, 'qdisc gred 38: parent 2:38')
3493 self.assertRegex(output, 'vqs 12 default 10 grio')
3494
3495 self.assertRegex(output, 'qdisc sfb 39: parent 2:39')
3496 self.assertRegex(output, 'limit 200000')
3497
3498 self.assertRegex(output, 'qdisc bfifo 3a: parent 2:3a')
3499 self.assertRegex(output, 'limit 1000000')
3500
3501 self.assertRegex(output, 'qdisc pfifo_head_drop 3b: parent 2:3b')
3502 self.assertRegex(output, 'limit 1023p')
3503
3504 self.assertRegex(output, 'qdisc pfifo_fast 3c: parent 2:3c')
3505
3506 output = check_output('tc -d class show dev dummy98')
3507 print(output)
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:')
3515 self.assertRegex(output, 'class htb 2:37 root leaf 37:')
3516 self.assertRegex(output, 'class htb 2:38 root leaf 38:')
3517 self.assertRegex(output, 'class htb 2:39 root leaf 39:')
3518 self.assertRegex(output, 'class htb 2:3a root leaf 3a:')
3519 self.assertRegex(output, 'class htb 2:3b root leaf 3b:')
3520 self.assertRegex(output, 'class htb 2:3c root leaf 3c:')
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')
3524
3525 def test_qdisc2(self):
3526 copy_unit_to_networkd_unit_path('25-qdisc-drr.network', '12-dummy.netdev',
3527 '25-qdisc-qfq.network', '11-dummy.netdev')
3528 start_networkd()
3529
3530 self.wait_online(['dummy98:routable', 'test1:routable'])
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
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
3547 @expectedFailureIfCAKEIsNotAvailable()
3548 def test_qdisc_cake(self):
3549 copy_unit_to_networkd_unit_path('25-qdisc-cake.network', '12-dummy.netdev')
3550 start_networkd()
3551 self.wait_online(['dummy98:routable'])
3552
3553 output = check_output('tc qdisc show dev dummy98')
3554 print(output)
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)
3568
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
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
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)
3599
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
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
3617 def test_wait_online_ipv4(self):
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')
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):
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')
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
3633class NetworkdStateFileTests(unittest.TestCase, Utilities):
3634 links = [
3635 'dummy98',
3636 ]
3637
3638 units = [
3639 '12-dummy.netdev',
3640 '25-state-file-tests.network',
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):
3653 copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-state-file-tests.network')
3654 start_networkd()
3655 self.wait_online(['dummy98:routable'])
3656
3657 # make link state file updated
3658 check_output(*resolvectl_cmd, 'revert', 'dummy98', env=env)
3659
3660 # TODO: check json string
3661 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
3662
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)
3681
3682 check_output(*resolvectl_cmd, 'dns', 'dummy98', '10.10.10.12#ccc.com', '10.10.10.13', '1111:2222::3333', env=env)
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)
3688
3689 # TODO: check json string
3690 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
3691
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)
3701
3702 check_output(*timedatectl_cmd, 'revert', 'dummy98', env=env)
3703
3704 # TODO: check json string
3705 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
3706
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)
3716
3717 check_output(*resolvectl_cmd, 'revert', 'dummy98', env=env)
3718
3719 # TODO: check json string
3720 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
3721
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)
3731
3732class NetworkdBondTests(unittest.TestCase, Utilities):
3733 links = [
3734 'bond199',
3735 'bond99',
3736 'dummy98',
3737 'test1']
3738
3739 units = [
3740 '11-dummy.netdev',
3741 '12-dummy.netdev',
3742 '23-active-slave.network',
3743 '23-bond199.network',
3744 '23-keep-master.network',
3745 '23-primary-slave.network',
3746 '25-bond-active-backup-slave.netdev',
3747 '25-bond.netdev',
3748 '25-bond99.network',
3749 '25-bond-slave.network']
3750
3751 def setUp(self):
3752 remove_links(self.links)
3753 stop_networkd(show_logs=False)
3754
3755 def tearDown(self):
3756 remove_links(self.links)
3757 remove_unit_from_networkd_path(self.units)
3758 stop_networkd(show_logs=True)
3759
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
3777 def test_bond_active_slave(self):
3778 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
3779 start_networkd()
3780 self.wait_online(['dummy98:enslaved', 'bond199:degraded'])
3781
3782 output = check_output('ip -d link show bond199')
3783 print(output)
3784 self.assertRegex(output, 'active_slave dummy98')
3785
3786 def test_bond_primary_slave(self):
3787 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
3788 start_networkd()
3789 self.wait_online(['dummy98:enslaved', 'bond199:degraded'])
3790
3791 output = check_output('ip -d link show bond199')
3792 print(output)
3793 self.assertRegex(output, 'primary dummy98')
3794
3795 def test_bond_operstate(self):
3796 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
3797 '25-bond99.network','25-bond-slave.network')
3798 start_networkd()
3799 self.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
3800
3801 output = check_output('ip -d link show dummy98')
3802 print(output)
3803 self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
3804
3805 output = check_output('ip -d link show test1')
3806 print(output)
3807 self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
3808
3809 output = check_output('ip -d link show bond99')
3810 print(output)
3811 self.assertRegex(output, 'MASTER,UP,LOWER_UP')
3812
3813 self.wait_operstate('dummy98', 'enslaved')
3814 self.wait_operstate('test1', 'enslaved')
3815 self.wait_operstate('bond99', 'routable')
3816
3817 check_output('ip link set dummy98 down')
3818
3819 self.wait_operstate('dummy98', 'off')
3820 self.wait_operstate('test1', 'enslaved')
3821 self.wait_operstate('bond99', 'degraded-carrier')
3822
3823 check_output('ip link set dummy98 up')
3824
3825 self.wait_operstate('dummy98', 'enslaved')
3826 self.wait_operstate('test1', 'enslaved')
3827 self.wait_operstate('bond99', 'routable')
3828
3829 check_output('ip link set dummy98 down')
3830 check_output('ip link set test1 down')
3831
3832 self.wait_operstate('dummy98', 'off')
3833 self.wait_operstate('test1', 'off')
3834
3835 if not self.wait_operstate('bond99', 'no-carrier', setup_timeout=30, fail_assert=False):
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')
3839
3840class NetworkdBridgeTests(unittest.TestCase, Utilities):
3841 links = [
3842 'bridge99',
3843 'dummy98',
3844 'test1',
3845 'vlan99',
3846 ]
3847
3848 units = [
3849 '11-dummy.netdev',
3850 '12-dummy.netdev',
3851 '21-vlan.netdev',
3852 '21-vlan.network',
3853 '23-keep-master.network',
3854 '26-bridge.netdev',
3855 '26-bridge-configure-without-carrier.network',
3856 '26-bridge-issue-20373.netdev',
3857 '26-bridge-mdb-master.network',
3858 '26-bridge-mdb-slave.network',
3859 '26-bridge-slave-interface-1.network',
3860 '26-bridge-slave-interface-2.network',
3861 '26-bridge-vlan-master-issue-20373.network',
3862 '26-bridge-vlan-master.network',
3863 '26-bridge-vlan-slave-issue-20373.network',
3864 '26-bridge-vlan-slave.network',
3865 '25-bridge99-ignore-carrier-loss.network',
3866 '25-bridge99.network'
3867 ]
3868
3869 routing_policy_rule_tables = ['100']
3870
3871 def setUp(self):
3872 remove_routing_policy_rule_tables(self.routing_policy_rule_tables)
3873 remove_links(self.links)
3874 stop_networkd(show_logs=False)
3875
3876 def tearDown(self):
3877 remove_routing_policy_rule_tables(self.routing_policy_rule_tables)
3878 remove_links(self.links)
3879 remove_unit_from_networkd_path(self.units)
3880 stop_networkd(show_logs=True)
3881
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()
3886 self.wait_online(['test1:enslaved', 'bridge99:degraded'])
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
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
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
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
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
3960 if os.path.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast'):
3961 self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
3962 if os.path.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress'):
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
3969 def test_bridge_property(self):
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',
3972 '25-bridge99.network')
3973 start_networkd()
3974 self.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
3975
3976 output = check_output('ip -d link show test1')
3977 print(output)
3978 self.assertRegex(output, 'master')
3979 self.assertRegex(output, 'bridge')
3980
3981 output = check_output('ip -d link show dummy98')
3982 print(output)
3983 self.assertRegex(output, 'master')
3984 self.assertRegex(output, 'bridge')
3985
3986 output = check_output('ip addr show bridge99')
3987 print(output)
3988 self.assertRegex(output, '192.168.0.15/24')
3989
3990 output = check_output('bridge -d link show dummy98')
3991 print(output)
3992 self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
3993 self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
3994 self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'isolated'), '1')
3995 self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
3996 self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
3997 self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
3998 # CONFIG_BRIDGE_IGMP_SNOOPING=y
3999 if os.path.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast'):
4000 self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
4001 if os.path.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress'):
4002 self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
4003 self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
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')
4007
4008 output = check_output('bridge -d link show test1')
4009 print(output)
4010 self.assertEqual(read_bridge_port_attr('bridge99', 'test1', 'priority'), '0')
4011
4012 check_output('ip address add 192.168.0.16/24 dev bridge99')
4013 time.sleep(1)
4014
4015 output = check_output('ip addr show bridge99')
4016 print(output)
4017 self.assertRegex(output, '192.168.0.16/24')
4018
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)
4023 self.assertRegex(output, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
4024
4025 self.assertEqual(call('ip link del test1'), 0)
4026
4027 self.wait_operstate('bridge99', 'degraded-carrier')
4028
4029 check_output('ip link del dummy98')
4030
4031 self.wait_operstate('bridge99', 'no-carrier')
4032
4033 output = check_output('ip address show bridge99')
4034 print(output)
4035 self.assertRegex(output, 'NO-CARRIER')
4036 self.assertNotRegex(output, '192.168.0.15/24')
4037 self.assertRegex(output, '192.168.0.16/24') # foreign address is kept
4038
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)
4042 self.assertRegex(output, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
4043
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
4054 self.wait_operstate('bridge99', operstate=r'(no-carrier|routable)', setup_state=None, setup_timeout=30)
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')
4065 self.wait_operstate('bridge99', operstate='no-carrier', setup_state=None)
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)
4089 self.assertRegex(output, '10.1.2.3')
4090 self.assertRegex(output, '10.1.2.1')
4091
4092 def test_bridge_ignore_carrier_loss(self):
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',
4095 '25-bridge99-ignore-carrier-loss.network')
4096 start_networkd()
4097 self.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
4098
4099 check_output('ip address add 192.168.0.16/24 dev bridge99')
4100 time.sleep(1)
4101
4102 check_output('ip link del test1')
4103 check_output('ip link del dummy98')
4104 time.sleep(3)
4105
4106 output = check_output('ip address show bridge99')
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
4112 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self):
4113 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
4114 '25-bridge99-ignore-carrier-loss.network')
4115 start_networkd()
4116 self.wait_online(['bridge99:no-carrier'])
4117
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')
4123
4124 self.wait_online(['bridge99:routable', 'dummy98:enslaved'])
4125
4126 output = check_output('ip address show bridge99')
4127 print(output)
4128 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
4129
4130 output = check_output('ip rule list table 100')
4131 print(output)
4132 self.assertIn('from all to 8.8.8.8 lookup 100', output)
4133
4134class NetworkdSRIOVTests(unittest.TestCase, Utilities):
4135 units = [
4136 '25-sriov-udev.network',
4137 '25-sriov.link',
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
4154 with open('/sys/bus/netdevsim/new_device', mode='w', encoding='utf-8') as f:
4155 f.write('99 1')
4156
4157 call('udevadm settle')
4158 call('udevadm info -w10s /sys/devices/netdevsim99/net/eni99np1', stderr=subprocess.DEVNULL)
4159 with open('/sys/class/net/eni99np1/device/sriov_numvfs', mode='w', encoding='utf-8') as f:
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
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
4181 with open('/sys/bus/netdevsim/new_device', mode='w', encoding='utf-8') as f:
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
4197 with open(os.path.join(network_unit_file_path, '25-sriov.link'), mode='a', encoding='utf-8') as f:
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
4213 with open(os.path.join(network_unit_file_path, '25-sriov.link'), mode='a', encoding='utf-8') as f:
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
4229 with open(os.path.join(network_unit_file_path, '25-sriov.link'), mode='a', encoding='utf-8') as f:
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
4245 with open(os.path.join(network_unit_file_path, '25-sriov.link'), mode='a', encoding='utf-8') as f:
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
4261class NetworkdLLDPTests(unittest.TestCase, Utilities):
4262 links = ['veth99']
4263
4264 units = [
4265 '23-emit-lldp.network',
4266 '24-lldp.network',
4267 '25-veth.netdev']
4268
4269 def setUp(self):
4270 remove_links(self.links)
4271 stop_networkd(show_logs=False)
4272
4273 def tearDown(self):
4274 remove_links(self.links)
4275 remove_unit_from_networkd_path(self.units)
4276 stop_networkd(show_logs=True)
4277
4278 def test_lldp(self):
4279 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
4280 start_networkd()
4281 self.wait_online(['veth99:degraded', 'veth-peer:degraded'])
4282
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()
4293
4294class NetworkdRATests(unittest.TestCase, Utilities):
4295 links = ['veth99']
4296
4297 units = [
4298 '25-veth.netdev',
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']
4304
4305 def setUp(self):
4306 remove_links(self.links)
4307 stop_networkd(show_logs=False)
4308
4309 def tearDown(self):
4310 remove_links(self.links)
4311 remove_unit_from_networkd_path(self.units)
4312 stop_networkd(show_logs=True)
4313
4314 def test_ipv6_prefix_delegation(self):
4315 copy_unit_to_networkd_unit_path('25-veth.netdev', '25-ipv6-prefix.network', '25-ipv6-prefix-veth.network')
4316 start_networkd()
4317 self.wait_online(['veth99:routable', 'veth-peer:degraded'])
4318
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
4324 output = check_output(*resolvectl_cmd, 'domain', 'veth99', env=env)
4325 print(output)
4326 self.assertIn('hogehoge.test', output)
4327
4328 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
4329 print(output)
4330 self.assertRegex(output, '2002:da8:1:0')
4331
4332 def test_ipv6_token_static(self):
4333 copy_unit_to_networkd_unit_path('25-veth.netdev', '25-ipv6-prefix.network', '25-ipv6-prefix-veth-token-static.network')
4334 start_networkd()
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')
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')
4343
4344 def test_ipv6_token_prefixstable(self):
4345 copy_unit_to_networkd_unit_path('25-veth.netdev', '25-ipv6-prefix.network', '25-ipv6-prefix-veth-token-prefixstable.network')
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)
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
4353
4354 def test_ipv6_token_prefixstable_without_address(self):
4355 copy_unit_to_networkd_unit_path('25-veth.netdev', '25-ipv6-prefix.network', '25-ipv6-prefix-veth-token-prefixstable-without-address.network')
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)
4361 self.assertIn('2002:da8:1:0:b47e:7975:fc7a:7d6e', output)
4362 self.assertIn('2002:da8:2:0:f689:561a:8eda:7443', output)
4363
4364class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
4365 links = [
4366 'dummy98',
4367 'veth99',
4368 ]
4369
4370 units = [
4371 '12-dummy.netdev',
4372 '25-veth.netdev',
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',
4381 ]
4382
4383 def setUp(self):
4384 remove_links(self.links)
4385 stop_networkd(show_logs=False)
4386
4387 def tearDown(self):
4388 remove_links(self.links)
4389 remove_unit_from_networkd_path(self.units)
4390 stop_networkd(show_logs=True)
4391
4392 def test_dhcp_server(self):
4393 copy_unit_to_networkd_unit_path('25-veth.netdev', '25-dhcp-client.network', '25-dhcp-server.network')
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)
4399 self.assertRegex(output, r'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)')
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):
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')
4407 start_networkd()
4408 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4409
4410 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
4411 print(output)
4412 self.assertRegex(output, r'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)')
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)
4416
4417 def test_emit_router_timezone(self):
4418 copy_unit_to_networkd_unit_path('25-veth.netdev', '25-dhcp-client-timezone-router.network', '25-dhcp-server-timezone-router.network')
4419 start_networkd()
4420 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4421
4422 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
4423 print(output)
4424 self.assertRegex(output, r'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)')
4425 self.assertIn('Gateway: 192.168.5.1', output)
4426 self.assertIn('Time Zone: Europe/Berlin', output)
4427
4428 def test_dhcp_server_static_lease(self):
4429 copy_unit_to_networkd_unit_path('25-veth.netdev', '25-dhcp-client-static-lease.network', '25-dhcp-server-static-lease.network')
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)
4435 self.assertIn('Address: 10.1.1.200 (DHCP4 via 10.1.1.1)', output)
4436
4437class NetworkdDHCPServerRelayAgentTests(unittest.TestCase, Utilities):
4438 links = [
4439 'client',
4440 'server',
4441 'client-peer',
4442 'server-peer',
4443 ]
4444
4445 units = [
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',
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
4467 self.wait_online(['client:routable'])
4468
4469 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'client', env=env)
4470 print(output)
4471 self.assertRegex(output, r'Address: 192.168.5.150 \(DHCP4 via 192.168.5.1\)')
4472
4473class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
4474 links = [
4475 'veth99',
4476 'vrf99']
4477
4478 units = [
4479 '25-veth.netdev',
4480 '25-vrf.netdev',
4481 '25-vrf.network',
4482 '25-dhcp-client-anonymize.network',
4483 '25-dhcp-client-gateway-ipv6.network',
4484 '25-dhcp-client-gateway-onlink-implicit.network',
4485 '25-dhcp-client-ipv4-only.network',
4486 '25-dhcp-client-ipv4-use-routes-use-gateway.network',
4487 '25-dhcp-client-ipv6-only.network',
4488 '25-dhcp-client-keep-configuration-dhcp-on-stop.network',
4489 '25-dhcp-client-keep-configuration-dhcp.network',
4490 '25-dhcp-client-vrf.network',
4491 '25-dhcp-client-with-ipv4ll.network',
4492 '25-dhcp-client.network',
4493 '25-dhcp-server-veth-peer.network',
4494 '25-static.network']
4495
4496 def setUp(self):
4497 stop_dnsmasq()
4498 remove_dnsmasq_lease_file()
4499 remove_dnsmasq_log_file()
4500 remove_links(self.links)
4501 stop_networkd(show_logs=False)
4502
4503 def tearDown(self):
4504 stop_dnsmasq()
4505 remove_dnsmasq_lease_file()
4506 remove_dnsmasq_log_file()
4507 remove_links(self.links)
4508 remove_unit_from_networkd_path(self.units)
4509 stop_networkd(show_logs=True)
4510
4511 def test_dhcp_client_ipv6_only(self):
4512 copy_unit_to_networkd_unit_path('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-ipv6-only.network')
4513
4514 start_networkd()
4515 self.wait_online(['veth-peer:carrier'])
4516 start_dnsmasq()
4517 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4518
4519 # checking address
4520 output = check_output('ip address show dev veth99 scope global')
4521 print(output)
4522 self.assertRegex(output, r'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute')
4523 self.assertNotIn('192.168.5', output)
4524
4525 # Confirm that ipv6 token is not set in the kernel
4526 output = check_output('ip token show dev veth99')
4527 print(output)
4528 self.assertRegex(output, 'token :: dev veth99')
4529
4530 def test_dhcp_client_ipv4_only(self):
4531 copy_unit_to_networkd_unit_path('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-ipv4-only.network')
4532
4533 start_networkd()
4534 self.wait_online(['veth-peer:carrier'])
4535 start_dnsmasq(ipv4_range='192.168.5.110,192.168.5.119',
4536 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',
4537 lease_time='2m')
4538 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4539
4540 print('## ip address show dev veth99 scope global')
4541 output = check_output('ip address show dev veth99 scope global')
4542 print(output)
4543 self.assertIn('mtu 1492', output)
4544 self.assertIn('inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99', output)
4545 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')
4546 self.assertNotIn('2600::', output)
4547
4548 print('## ip route show table main dev veth99')
4549 output = check_output('ip route show table main dev veth99')
4550 print(output)
4551 # no DHCP routes assigned to the main table
4552 self.assertNotIn('proto dhcp', output)
4553 # static routes
4554 self.assertIn('192.168.5.0/24 proto kernel scope link src 192.168.5.250', output)
4555 self.assertIn('192.168.5.0/24 proto static scope link', output)
4556 self.assertIn('192.168.6.0/24 proto static scope link', output)
4557 self.assertIn('192.168.7.0/24 proto static scope link', output)
4558
4559 print('## ip route show table 211 dev veth99')
4560 output = check_output('ip route show table 211 dev veth99')
4561 print(output)
4562 self.assertRegex(output, 'default via 192.168.5.1 proto dhcp src 192.168.5.11[0-9] metric 24')
4563 self.assertRegex(output, '192.168.5.0/24 proto dhcp scope link src 192.168.5.11[0-9] metric 24')
4564 self.assertRegex(output, '192.168.5.1 proto dhcp scope link src 192.168.5.11[0-9] metric 24')
4565 self.assertRegex(output, '192.168.5.6 proto dhcp scope link src 192.168.5.11[0-9] metric 24')
4566 self.assertRegex(output, '192.168.5.7 proto dhcp scope link src 192.168.5.11[0-9] metric 24')
4567 self.assertIn('10.0.0.0/8 via 192.168.5.1 proto dhcp', output)
4568
4569 print('## link state file')
4570 output = read_link_state_file('veth99')
4571 print(output)
4572 # checking DNS server and Domains
4573 self.assertIn('DNS=192.168.5.6 192.168.5.7', output)
4574 self.assertIn('DOMAINS=example.com', output)
4575
4576 print('## dnsmasq log')
4577 output = read_dnsmasq_log_file()
4578 print(output)
4579 self.assertIn('vendor class: FooBarVendorTest', output)
4580 self.assertIn('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc', output)
4581 self.assertIn('client provides name: test-hostname', output)
4582 self.assertIn('26:mtu', output)
4583
4584 # change address range, DNS servers, and Domains
4585 stop_dnsmasq()
4586 remove_dnsmasq_log_file()
4587 start_dnsmasq(ipv4_range='192.168.5.120,192.168.5.129',
4588 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',
4589 lease_time='2m')
4590
4591 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4592 print('Wait for the DHCP lease to be expired')
4593 time.sleep(120)
4594
4595 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4596
4597 print('## ip address show dev veth99 scope global')
4598 output = check_output('ip address show dev veth99 scope global')
4599 print(output)
4600 self.assertIn('mtu 1492', output)
4601 self.assertIn('inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99', output)
4602 self.assertNotIn('192.168.5.11', output)
4603 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')
4604 self.assertNotIn('2600::', output)
4605
4606 print('## ip route show table main dev veth99')
4607 output = check_output('ip route show table main dev veth99')
4608 print(output)
4609 # no DHCP routes assigned to the main table
4610 self.assertNotIn('proto dhcp', output)
4611 # static routes
4612 self.assertIn('192.168.5.0/24 proto kernel scope link src 192.168.5.250', output)
4613 self.assertIn('192.168.5.0/24 proto static scope link', output)
4614 self.assertIn('192.168.6.0/24 proto static scope link', output)
4615 self.assertIn('192.168.7.0/24 proto static scope link', output)
4616
4617 print('## ip route show table 211 dev veth99')
4618 output = check_output('ip route show table 211 dev veth99')
4619 print(output)
4620 self.assertRegex(output, 'default via 192.168.5.1 proto dhcp src 192.168.5.12[0-9] metric 24')
4621 self.assertRegex(output, '192.168.5.0/24 proto dhcp scope link src 192.168.5.12[0-9] metric 24')
4622 self.assertRegex(output, '192.168.5.1 proto dhcp scope link src 192.168.5.12[0-9] metric 24')
4623 self.assertNotIn('192.168.5.6', output)
4624 self.assertRegex(output, '192.168.5.7 proto dhcp scope link src 192.168.5.12[0-9] metric 24')
4625 self.assertRegex(output, '192.168.5.8 proto dhcp scope link src 192.168.5.12[0-9] metric 24')
4626 self.assertIn('10.0.0.0/8 via 192.168.5.1 proto dhcp', output)
4627
4628 print('## link state file')
4629 output = read_link_state_file('veth99')
4630 print(output)
4631 # checking DNS server and Domains
4632 self.assertIn('DNS=192.168.5.1 192.168.5.7 192.168.5.8', output)
4633 self.assertIn('DOMAINS=foo.example.com', output)
4634
4635 print('## dnsmasq log')
4636 output = read_dnsmasq_log_file()
4637 print(output)
4638 self.assertIn('vendor class: FooBarVendorTest', output)
4639 self.assertIn('DHCPDISCOVER(veth-peer) 192.168.5.11', output)
4640 self.assertIn('client provides name: test-hostname', output)
4641 self.assertIn('26:mtu', output)
4642
4643 def test_dhcp_client_ipv4_use_routes_gateway(self):
4644 for (routes, gateway, dns_and_ntp_routes, classless) in itertools.product([True, False], repeat=4):
4645 self.setUp()
4646 with self.subTest(routes=routes, gateway=gateway, dns_and_ntp_routes=dns_and_ntp_routes, classless=classless):
4647 self._test_dhcp_client_ipv4_use_routes_gateway(routes, gateway, dns_and_ntp_routes, classless)
4648 self.tearDown()
4649
4650 def _test_dhcp_client_ipv4_use_routes_gateway(self, use_routes, use_gateway, dns_and_ntp_routes, classless):
4651 testunit = '25-dhcp-client-ipv4-use-routes-use-gateway.network'
4652 testunits = ['25-veth.netdev', '25-dhcp-server-veth-peer.network', testunit]
4653 testunits.append(f'{testunit}.d/use-routes-{use_routes}.conf')
4654 testunits.append(f'{testunit}.d/use-gateway-{use_gateway}.conf')
4655 testunits.append(f'{testunit}.d/use-dns-and-ntp-routes-{dns_and_ntp_routes}.conf')
4656 copy_unit_to_networkd_unit_path(*testunits, dropins=False)
4657
4658 start_networkd()
4659 self.wait_online(['veth-peer:carrier'])
4660 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'
4661 if classless:
4662 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'
4663 start_dnsmasq(additional_options=additional_options, lease_time='2m')
4664 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4665
4666 output = check_output('ip -4 route show dev veth99')
4667 print(output)
4668
4669 # Check UseRoutes=
4670 if use_routes:
4671 if classless:
4672 self.assertRegex(output, r'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
4673 self.assertRegex(output, r'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
4674 self.assertRegex(output, r'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4675 self.assertRegex(output, r'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4676 else:
4677 self.assertRegex(output, r'192.168.5.0/24 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4678 self.assertRegex(output, r'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024')
4679 self.assertRegex(output, r'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4680 else:
4681 self.assertNotRegex(output, r'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
4682 self.assertNotRegex(output, r'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
4683 self.assertNotRegex(output, r'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4684 self.assertNotRegex(output, r'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4685 self.assertNotRegex(output, r'192.168.5.0/24 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4686 self.assertNotRegex(output, r'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024')
4687 self.assertNotRegex(output, r'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4688
4689 # Check UseGateway=
4690 if use_gateway and (not classless or not use_routes):
4691 self.assertRegex(output, r'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
4692 else:
4693 self.assertNotRegex(output, r'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
4694
4695 # Check route to gateway
4696 if (use_gateway or dns_and_ntp_routes) and (not classless or not use_routes):
4697 self.assertRegex(output, r'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4698 else:
4699 self.assertNotRegex(output, r'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4700
4701 # Check RoutesToDNS= and RoutesToNTP=
4702 if dns_and_ntp_routes:
4703 self.assertRegex(output, r'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4704 self.assertRegex(output, r'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4705 if classless and use_routes:
4706 self.assertRegex(output, r'8.8.8.8 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
4707 self.assertRegex(output, r'9.9.9.9 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
4708 else:
4709 self.assertRegex(output, r'8.8.8.8 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
4710 self.assertRegex(output, r'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
4711 else:
4712 self.assertNotRegex(output, r'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4713 self.assertNotRegex(output, r'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
4714 self.assertNotRegex(output, r'8.8.8.8 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024')
4715 self.assertNotRegex(output, r'9.9.9.9 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024')
4716
4717 # TODO: check json string
4718 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
4719
4720 def test_dhcp_client_settings_anonymize(self):
4721 copy_unit_to_networkd_unit_path('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-anonymize.network')
4722 start_networkd()
4723 self.wait_online(['veth-peer:carrier'])
4724 start_dnsmasq()
4725 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4726
4727 print('## dnsmasq log')
4728 output = read_dnsmasq_log_file()
4729 print(output)
4730 self.assertNotIn('VendorClassIdentifier=SusantVendorTest', output)
4731 self.assertNotIn('test-hostname', output)
4732 self.assertNotIn('26:mtu', output)
4733
4734 def test_dhcp_keep_configuration_dhcp(self):
4735 copy_unit_to_networkd_unit_path('25-veth.netdev',
4736 '25-dhcp-server-veth-peer.network',
4737 '25-dhcp-client-keep-configuration-dhcp.network')
4738 start_networkd()
4739 self.wait_online(['veth-peer:carrier'])
4740 start_dnsmasq(lease_time='2m')
4741 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4742
4743 output = check_output('ip address show dev veth99 scope global')
4744 print(output)
4745 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4746 'valid_lft forever preferred_lft forever')
4747
4748 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
4749 stop_dnsmasq()
4750
4751 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
4752 print('Wait for the DHCP lease to be expired')
4753 time.sleep(120)
4754
4755 # The lease address should be kept after the lease expired
4756 output = check_output('ip address show dev veth99 scope global')
4757 print(output)
4758 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4759 'valid_lft forever preferred_lft forever')
4760
4761 stop_networkd()
4762
4763 # The lease address should be kept after networkd stopped
4764 output = check_output('ip address show dev veth99 scope global')
4765 print(output)
4766 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4767 'valid_lft forever preferred_lft forever')
4768
4769 with open(os.path.join(network_unit_file_path, '25-dhcp-client-keep-configuration-dhcp.network'), mode='a', encoding='utf-8') as f:
4770 f.write('[Network]\nDHCP=no\n')
4771
4772 start_networkd()
4773 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4774
4775 # Still the lease address should be kept after networkd restarted
4776 output = check_output('ip address show dev veth99 scope global')
4777 print(output)
4778 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
4779 'valid_lft forever preferred_lft forever')
4780
4781 def test_dhcp_keep_configuration_dhcp_on_stop(self):
4782 copy_unit_to_networkd_unit_path('25-veth.netdev',
4783 '25-dhcp-server-veth-peer.network',
4784 '25-dhcp-client-keep-configuration-dhcp-on-stop.network')
4785 start_networkd()
4786 self.wait_online(['veth-peer:carrier'])
4787 start_dnsmasq(lease_time='2m')
4788 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4789
4790 output = check_output('ip address show dev veth99 scope global')
4791 print(output)
4792 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
4793
4794 stop_dnsmasq()
4795 stop_networkd()
4796
4797 output = check_output('ip address show dev veth99 scope global')
4798 print(output)
4799 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
4800
4801 start_networkd(3)
4802 self.wait_online(['veth-peer:routable'])
4803
4804 output = check_output('ip address show dev veth99 scope global')
4805 print(output)
4806 self.assertNotIn('192.168.5.', output)
4807
4808 def test_dhcp_client_reuse_address_as_static(self):
4809 copy_unit_to_networkd_unit_path('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client.network')
4810 start_networkd()
4811 self.wait_online(['veth-peer:carrier'])
4812 start_dnsmasq()
4813 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4814
4815 # link become 'routable' when at least one protocol provide an valid address.
4816 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
4817 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
4818
4819 output = check_output('ip address show dev veth99 scope global')
4820 ipv4_address = re.search(r'192.168.5.[0-9]*/24', output).group()
4821 ipv6_address = re.search(r'2600::[0-9a-f:]*/128', output).group()
4822 static_network = '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address, 'Address=' + ipv6_address])
4823 print(static_network)
4824
4825 remove_unit_from_networkd_path(['25-dhcp-client.network'])
4826
4827 with open(os.path.join(network_unit_file_path, '25-static.network'), mode='w', encoding='utf-8') as f:
4828 f.write(static_network)
4829
4830 restart_networkd()
4831 self.wait_online(['veth99:routable'])
4832
4833 output = check_output('ip -4 address show dev veth99 scope global')
4834 print(output)
4835 self.assertRegex(output, f'inet {ipv4_address} brd 192.168.5.255 scope global veth99\n *'
4836 'valid_lft forever preferred_lft forever')
4837
4838 output = check_output('ip -6 address show dev veth99 scope global')
4839 print(output)
4840 self.assertRegex(output, f'inet6 {ipv6_address} scope global *\n *'
4841 'valid_lft forever preferred_lft forever')
4842
4843 @expectedFailureIfModuleIsNotAvailable('vrf')
4844 def test_dhcp_client_vrf(self):
4845 copy_unit_to_networkd_unit_path('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-vrf.network',
4846 '25-vrf.netdev', '25-vrf.network')
4847 start_networkd()
4848 self.wait_online(['veth-peer:carrier'])
4849 start_dnsmasq()
4850 self.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
4851
4852 # link become 'routable' when at least one protocol provide an valid address.
4853 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
4854 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
4855
4856 print('## ip -d link show dev vrf99')
4857 output = check_output('ip -d link show dev vrf99')
4858 print(output)
4859 self.assertRegex(output, 'vrf table 42')
4860
4861 print('## ip address show vrf vrf99')
4862 output = check_output('ip address show vrf vrf99')
4863 print(output)
4864 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
4865 self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
4866 self.assertRegex(output, 'inet6 .* scope link')
4867
4868 print('## ip address show dev veth99')
4869 output = check_output('ip address show dev veth99')
4870 print(output)
4871 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
4872 self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
4873 self.assertRegex(output, 'inet6 .* scope link')
4874
4875 print('## ip route show vrf vrf99')
4876 output = check_output('ip route show vrf vrf99')
4877 print(output)
4878 self.assertRegex(output, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
4879 self.assertRegex(output, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
4880 self.assertRegex(output, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
4881
4882 print('## ip route show table main dev veth99')
4883 output = check_output('ip route show table main dev veth99')
4884 print(output)
4885 self.assertEqual(output, '')
4886
4887 def test_dhcp_client_gateway_ipv6(self):
4888 copy_unit_to_networkd_unit_path('25-veth.netdev', '25-dhcp-server-veth-peer.network',
4889 '25-dhcp-client-gateway-ipv6.network')
4890 start_networkd()
4891 self.wait_online(['veth-peer:carrier'])
4892 start_dnsmasq()
4893 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4894
4895 output = check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
4896 print(output)
4897 self.assertRegex(output, 'via fe80::1034:56ff:fe78:9abd')
4898
4899 def test_dhcp_client_gateway_onlink_implicit(self):
4900 copy_unit_to_networkd_unit_path('25-veth.netdev', '25-dhcp-server-veth-peer.network',
4901 '25-dhcp-client-gateway-onlink-implicit.network')
4902 start_networkd()
4903 self.wait_online(['veth-peer:carrier'])
4904 start_dnsmasq()
4905 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4906
4907 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
4908 print(output)
4909 self.assertRegex(output, '192.168.5')
4910
4911 output = check_output('ip route list dev veth99 10.0.0.0/8')
4912 print(output)
4913 self.assertRegex(output, 'onlink')
4914 output = check_output('ip route list dev veth99 192.168.100.0/24')
4915 print(output)
4916 self.assertRegex(output, 'onlink')
4917
4918 def test_dhcp_client_with_ipv4ll(self):
4919 copy_unit_to_networkd_unit_path('25-veth.netdev', '25-dhcp-server-veth-peer.network',
4920 '25-dhcp-client-with-ipv4ll.network')
4921 start_networkd()
4922 # we need to increase timeout above default, as this will need to wait for
4923 # systemd-networkd to get the dhcpv4 transient failure event
4924 self.wait_online(['veth99:degraded', 'veth-peer:routable'], timeout='60s')
4925
4926 output = check_output('ip -4 address show dev veth99')
4927 print(output)
4928 self.assertNotIn('192.168.5.', output)
4929 self.assertRegex(output, r'inet 169\.254\.\d+\.\d+/16 metric 2048 brd 169\.254\.255\.255 scope link')
4930
4931 start_dnsmasq(lease_time='2m')
4932 print('Wait for a DHCP lease to be acquired and the IPv4LL address to be dropped')
4933 self.wait_address('veth99', r'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic', ipv='-4')
4934 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')
4935 self.wait_online(['veth99:routable'])
4936
4937 output = check_output('ip -4 address show dev veth99')
4938 print(output)
4939 self.assertRegex(output, r'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99')
4940 self.assertNotIn('169.254.', output)
4941 self.assertNotIn('scope link', output)
4942
4943 stop_dnsmasq()
4944 print('Wait for the DHCP lease to be expired and an IPv4LL address to be acquired')
4945 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)
4946 self.wait_address('veth99', r'inet 169\.254\.\d+\.\d+/16 metric 2048 brd 169\.254\.255\.255 scope link', scope='link', ipv='-4')
4947
4948 output = check_output('ip -4 address show dev veth99')
4949 print(output)
4950 self.assertNotIn('192.168.5.', output)
4951 self.assertRegex(output, r'inet 169\.254\.\d+\.\d+/16 metric 2048 brd 169\.254\.255\.255 scope link')
4952
4953 def test_dhcp_client_use_dns(self):
4954 def check(self, ipv4, ipv6):
4955 os.makedirs(os.path.join(network_unit_file_path, '25-dhcp-client.network.d'), exist_ok=True)
4956 with open(os.path.join(network_unit_file_path, '25-dhcp-client.network.d/override.conf'), mode='w', encoding='utf-8') as f:
4957 f.write('[DHCPv4]\nUseDNS=')
4958 f.write('yes' if ipv4 else 'no')
4959 f.write('\n[DHCPv6]\nUseDNS=')
4960 f.write('yes' if ipv6 else 'no')
4961 f.write('\n[IPv6AcceptRA]\nUseDNS=no')
4962
4963 check_output(*networkctl_cmd, 'reload', env=env)
4964 # 'networkctl reload' asynchronously reconfigure links.
4965 # Hence, we need to wait for a short time for the link to be in configuring state.
4966 time.sleep(1)
4967 self.wait_online(['veth99:routable'])
4968
4969 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
4970 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
4971 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
4972
4973 # make resolved re-read the link state file
4974 check_output(*resolvectl_cmd, 'revert', 'veth99', env=env)
4975
4976 output = check_output(*resolvectl_cmd, 'dns', 'veth99', env=env)
4977 print(output)
4978 if ipv4:
4979 self.assertIn('192.168.5.1', output)
4980 else:
4981 self.assertNotIn('192.168.5.1', output)
4982 if ipv6:
4983 self.assertIn('2600::1', output)
4984 else:
4985 self.assertNotIn('2600::1', output)
4986
4987 # TODO: check json string
4988 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
4989
4990 copy_unit_to_networkd_unit_path('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client.network', dropins=False)
4991
4992 start_networkd()
4993 self.wait_online(['veth-peer:carrier'])
4994 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
4995
4996 check(self, True, True)
4997 check(self, True, False)
4998 check(self, False, True)
4999 check(self, False, False)
5000
5001class NetworkdDHCPPDTests(unittest.TestCase, Utilities):
5002 links = [
5003 'dummy97',
5004 'dummy98',
5005 'dummy99',
5006 'test1',
5007 'veth97',
5008 'veth98',
5009 'veth99',
5010 ]
5011
5012 units = [
5013 '11-dummy.netdev',
5014 '12-dummy.netdev',
5015 '13-dummy.netdev',
5016 '25-veth.netdev',
5017 '25-veth-downstream-veth97.netdev',
5018 '25-veth-downstream-veth98.netdev',
5019 '80-6rd-tunnel.network',
5020 '25-dhcp-pd-downstream-dummy97.network',
5021 '25-dhcp-pd-downstream-dummy98.network',
5022 '25-dhcp-pd-downstream-dummy99.network',
5023 '25-dhcp-pd-downstream-test1.network',
5024 '25-dhcp-pd-downstream-veth97.network',
5025 '25-dhcp-pd-downstream-veth97-peer.network',
5026 '25-dhcp-pd-downstream-veth98.network',
5027 '25-dhcp-pd-downstream-veth98-peer.network',
5028 '25-dhcp4-6rd-server.network',
5029 '25-dhcp4-6rd-upstream.network',
5030 '25-dhcp6pd-server.network',
5031 '25-dhcp6pd-upstream.network',
5032 ]
5033
5034 def setUp(self):
5035 stop_isc_dhcpd()
5036 stop_dnsmasq()
5037 remove_links(self.links)
5038 stop_networkd(show_logs=False)
5039
5040 def tearDown(self):
5041 stop_isc_dhcpd()
5042 stop_dnsmasq()
5043 remove_links(self.links)
5044 remove_unit_from_networkd_path(self.units)
5045 stop_networkd(show_logs=True)
5046
5047 def test_dhcp6pd(self):
5048 copy_unit_to_networkd_unit_path('25-veth.netdev', '25-dhcp6pd-server.network', '25-dhcp6pd-upstream.network',
5049 '25-veth-downstream-veth97.netdev', '25-dhcp-pd-downstream-veth97.network', '25-dhcp-pd-downstream-veth97-peer.network',
5050 '25-veth-downstream-veth98.netdev', '25-dhcp-pd-downstream-veth98.network', '25-dhcp-pd-downstream-veth98-peer.network',
5051 '11-dummy.netdev', '25-dhcp-pd-downstream-test1.network',
5052 '25-dhcp-pd-downstream-dummy97.network',
5053 '12-dummy.netdev', '25-dhcp-pd-downstream-dummy98.network',
5054 '13-dummy.netdev', '25-dhcp-pd-downstream-dummy99.network')
5055
5056 start_networkd()
5057 self.wait_online(['veth-peer:routable'])
5058 start_isc_dhcpd('veth-peer', 'isc-dhcpd-dhcp6pd.conf', ip='-6')
5059 self.wait_online(['veth99:routable', 'test1:routable', 'dummy98:routable', 'dummy99:degraded',
5060 'veth97:routable', 'veth97-peer:routable', 'veth98:routable', 'veth98-peer:routable'])
5061
5062 print('### ip -6 address show dev veth-peer scope global')
5063 output = check_output('ip -6 address show dev veth-peer scope global')
5064 print(output)
5065 self.assertIn('inet6 3ffe:501:ffff:100::1/64 scope global', output)
5066
5067 # Link Subnet IDs
5068 # test1: 0x00
5069 # dummy97: 0x01 (The link will appear later)
5070 # dummy98: 0x00
5071 # dummy99: auto -> 0x02 (No address assignment)
5072 # veth97: 0x08
5073 # veth98: 0x09
5074 # veth99: 0x10
5075
5076 print('### ip -6 address show dev veth99 scope global')
5077 output = check_output('ip -6 address show dev veth99 scope global')
5078 print(output)
5079 # IA_NA
5080 self.assertRegex(output, 'inet6 3ffe:501:ffff:100::[0-9]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
5081 # address in IA_PD (Token=static)
5082 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic')
5083 # address in IA_PD (Token=eui64)
5084 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic')
5085 # address in IA_PD (temporary)
5086 # Note that the temporary addresses may appear after the link enters configured state
5087 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')
5088
5089 print('### ip -6 address show dev test1 scope global')
5090 output = check_output('ip -6 address show dev test1 scope global')
5091 print(output)
5092 # address in IA_PD (Token=static)
5093 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5094 # address in IA_PD (temporary)
5095 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')
5096
5097 print('### ip -6 address show dev dummy98 scope global')
5098 output = check_output('ip -6 address show dev dummy98 scope global')
5099 print(output)
5100 # address in IA_PD (Token=static)
5101 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5102 # address in IA_PD (temporary)
5103 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')
5104
5105 print('### ip -6 address show dev dummy99 scope global')
5106 output = check_output('ip -6 address show dev dummy99 scope global')
5107 print(output)
5108 # Assign=no
5109 self.assertNotRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]02')
5110
5111 print('### ip -6 address show dev veth97 scope global')
5112 output = check_output('ip -6 address show dev veth97 scope global')
5113 print(output)
5114 # address in IA_PD (Token=static)
5115 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5116 # address in IA_PD (Token=eui64)
5117 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr')
5118 # address in IA_PD (temporary)
5119 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')
5120
5121 print('### ip -6 address show dev veth97-peer scope global')
5122 output = check_output('ip -6 address show dev veth97-peer scope global')
5123 print(output)
5124 # NDisc address (Token=static)
5125 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
5126 # NDisc address (Token=eui64)
5127 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr')
5128 # NDisc address (temporary)
5129 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')
5130
5131 print('### ip -6 address show dev veth98 scope global')
5132 output = check_output('ip -6 address show dev veth98 scope global')
5133 print(output)
5134 # address in IA_PD (Token=static)
5135 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5136 # address in IA_PD (Token=eui64)
5137 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr')
5138 # address in IA_PD (temporary)
5139 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')
5140
5141 print('### ip -6 address show dev veth98-peer scope global')
5142 output = check_output('ip -6 address show dev veth98-peer scope global')
5143 print(output)
5144 # NDisc address (Token=static)
5145 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
5146 # NDisc address (Token=eui64)
5147 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr')
5148 # NDisc address (temporary)
5149 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')
5150
5151 print('### ip -6 route show type unreachable')
5152 output = check_output('ip -6 route show type unreachable')
5153 print(output)
5154 self.assertRegex(output, 'unreachable 3ffe:501:ffff:[2-9a-f]00::/56 dev lo proto dhcp')
5155
5156 print('### ip -6 route show dev veth99')
5157 output = check_output('ip -6 route show dev veth99')
5158 print(output)
5159 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]10::/64 proto kernel metric [0-9]* expires')
5160
5161 print('### ip -6 route show dev test1')
5162 output = check_output('ip -6 route show dev test1')
5163 print(output)
5164 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires')
5165
5166 print('### ip -6 route show dev dummy98')
5167 output = check_output('ip -6 route show dev dummy98')
5168 print(output)
5169 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires')
5170
5171 print('### ip -6 route show dev dummy99')
5172 output = check_output('ip -6 route show dev dummy99')
5173 print(output)
5174 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires')
5175
5176 print('### ip -6 route show dev veth97')
5177 output = check_output('ip -6 route show dev veth97')
5178 print(output)
5179 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]08::/64 proto kernel metric [0-9]* expires')
5180
5181 print('### ip -6 route show dev veth97-peer')
5182 output = check_output('ip -6 route show dev veth97-peer')
5183 print(output)
5184 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]08::/64 proto ra metric [0-9]* expires')
5185
5186 print('### ip -6 route show dev veth98')
5187 output = check_output('ip -6 route show dev veth98')
5188 print(output)
5189 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]09::/64 proto kernel metric [0-9]* expires')
5190
5191 print('### ip -6 route show dev veth98-peer')
5192 output = check_output('ip -6 route show dev veth98-peer')
5193 print(output)
5194 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]09::/64 proto ra metric [0-9]* expires')
5195
5196 # Test case for a downstream which appears later
5197 check_output('ip link add dummy97 type dummy')
5198 self.wait_online(['dummy97:routable'])
5199
5200 print('### ip -6 address show dev dummy97 scope global')
5201 output = check_output('ip -6 address show dev dummy97 scope global')
5202 print(output)
5203 # address in IA_PD (Token=static)
5204 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5205 # address in IA_PD (temporary)
5206 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')
5207
5208 print('### ip -6 route show dev dummy97')
5209 output = check_output('ip -6 route show dev dummy97')
5210 print(output)
5211 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]01::/64 proto kernel metric [0-9]* expires')
5212
5213 # Test case for reconfigure
5214 check_output(*networkctl_cmd, 'reconfigure', 'dummy98', 'dummy99', env=env)
5215 self.wait_online(['dummy98:routable'])
5216
5217 print('### ip -6 address show dev dummy98 scope global')
5218 output = check_output('ip -6 address show dev dummy98 scope global')
5219 print(output)
5220 # address in IA_PD (Token=static)
5221 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5222 # address in IA_PD (temporary)
5223 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')
5224
5225 print('### ip -6 address show dev dummy99 scope global')
5226 output = check_output('ip -6 address show dev dummy99 scope global')
5227 print(output)
5228 # Assign=no
5229 self.assertNotRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]02')
5230
5231 print('### ip -6 route show dev dummy98')
5232 output = check_output('ip -6 route show dev dummy98')
5233 print(output)
5234 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires')
5235
5236 print('### ip -6 route show dev dummy99')
5237 output = check_output('ip -6 route show dev dummy99')
5238 print(output)
5239 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires')
5240
5241 def verify_dhcp4_6rd(self, tunnel_name):
5242 print('### ip -4 address show dev veth-peer scope global')
5243 output = check_output('ip -4 address show dev veth-peer scope global')
5244 print(output)
5245 self.assertIn('inet 10.0.0.1/8 brd 10.255.255.255 scope global veth-peer', output)
5246
5247 # Link Subnet IDs
5248 # test1: 0x00
5249 # dummy97: 0x01 (The link will appear later)
5250 # dummy98: 0x00
5251 # dummy99: auto -> 0x0[23] (No address assignment)
5252 # 6rd-XXX: auto -> 0x0[23]
5253 # veth97: 0x08
5254 # veth98: 0x09
5255 # veth99: 0x10
5256
5257 print('### ip -4 address show dev veth99 scope global')
5258 output = check_output('ip -4 address show dev veth99 scope global')
5259 print(output)
5260 self.assertRegex(output, 'inet 10.100.100.[0-9]*/8 (metric 1024 |)brd 10.255.255.255 scope global dynamic veth99')
5261
5262 print('### ip -6 address show dev veth99 scope global')
5263 output = check_output('ip -6 address show dev veth99 scope global')
5264 print(output)
5265 # address in IA_PD (Token=static)
5266 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5267 # address in IA_PD (Token=eui64)
5268 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic mngtmpaddr')
5269 # address in IA_PD (temporary)
5270 # Note that the temporary addresses may appear after the link enters configured state
5271 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')
5272
5273 print('### ip -6 address show dev test1 scope global')
5274 output = check_output('ip -6 address show dev test1 scope global')
5275 print(output)
5276 # address in IA_PD (Token=static)
5277 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5278 # address in IA_PD (temporary)
5279 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')
5280
5281 print('### ip -6 address show dev dummy98 scope global')
5282 output = check_output('ip -6 address show dev dummy98 scope global')
5283 print(output)
5284 # address in IA_PD (Token=static)
5285 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5286 # address in IA_PD (temporary)
5287 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')
5288
5289 print('### ip -6 address show dev dummy99 scope global')
5290 output = check_output('ip -6 address show dev dummy99 scope global')
5291 print(output)
5292 # Assign=no
5293 self.assertNotRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+0[23]')
5294
5295 print('### ip -6 address show dev veth97 scope global')
5296 output = check_output('ip -6 address show dev veth97 scope global')
5297 print(output)
5298 # address in IA_PD (Token=static)
5299 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5300 # address in IA_PD (Token=eui64)
5301 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr')
5302 # address in IA_PD (temporary)
5303 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')
5304
5305 print('### ip -6 address show dev veth97-peer scope global')
5306 output = check_output('ip -6 address show dev veth97-peer scope global')
5307 print(output)
5308 # NDisc address (Token=static)
5309 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
5310 # NDisc address (Token=eui64)
5311 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr')
5312 # NDisc address (temporary)
5313 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')
5314
5315 print('### ip -6 address show dev veth98 scope global')
5316 output = check_output('ip -6 address show dev veth98 scope global')
5317 print(output)
5318 # address in IA_PD (Token=static)
5319 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5320 # address in IA_PD (Token=eui64)
5321 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr')
5322 # address in IA_PD (temporary)
5323 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')
5324
5325 print('### ip -6 address show dev veth98-peer scope global')
5326 output = check_output('ip -6 address show dev veth98-peer scope global')
5327 print(output)
5328 # NDisc address (Token=static)
5329 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
5330 # NDisc address (Token=eui64)
5331 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr')
5332 # NDisc address (temporary)
5333 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')
5334
5335 print('### ip -6 route show type unreachable')
5336 output = check_output('ip -6 route show type unreachable')
5337 print(output)
5338 self.assertRegex(output, 'unreachable 2001:db8:6464:[0-9a-f]+00::/56 dev lo proto dhcp')
5339
5340 print('### ip -6 route show dev veth99')
5341 output = check_output('ip -6 route show dev veth99')
5342 print(output)
5343 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+10::/64 proto kernel metric [0-9]* expires')
5344
5345 print('### ip -6 route show dev test1')
5346 output = check_output('ip -6 route show dev test1')
5347 print(output)
5348 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires')
5349
5350 print('### ip -6 route show dev dummy98')
5351 output = check_output('ip -6 route show dev dummy98')
5352 print(output)
5353 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires')
5354
5355 print('### ip -6 route show dev dummy99')
5356 output = check_output('ip -6 route show dev dummy99')
5357 print(output)
5358 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto dhcp metric [0-9]* expires')
5359
5360 print('### ip -6 route show dev veth97')
5361 output = check_output('ip -6 route show dev veth97')
5362 print(output)
5363 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+08::/64 proto kernel metric [0-9]* expires')
5364
5365 print('### ip -6 route show dev veth97-peer')
5366 output = check_output('ip -6 route show dev veth97-peer')
5367 print(output)
5368 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+08::/64 proto ra metric [0-9]* expires')
5369
5370 print('### ip -6 route show dev veth98')
5371 output = check_output('ip -6 route show dev veth98')
5372 print(output)
5373 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+09::/64 proto kernel metric [0-9]* expires')
5374
5375 print('### ip -6 route show dev veth98-peer')
5376 output = check_output('ip -6 route show dev veth98-peer')
5377 print(output)
5378 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+09::/64 proto ra metric [0-9]* expires')
5379
5380 print('### ip -6 address show dev dummy97 scope global')
5381 output = check_output('ip -6 address show dev dummy97 scope global')
5382 print(output)
5383 # address in IA_PD (Token=static)
5384 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5385 # address in IA_PD (temporary)
5386 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')
5387
5388 print('### ip -6 route show dev dummy97')
5389 output = check_output('ip -6 route show dev dummy97')
5390 print(output)
5391 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+01::/64 proto kernel metric [0-9]* expires')
5392
5393 print(f'### ip -d link show dev {tunnel_name}')
5394 output = check_output(f'ip -d link show dev {tunnel_name}')
5395 print(output)
5396 self.assertIn('link/sit 10.100.100.', output)
5397 self.assertIn('local 10.100.100.', output)
5398 self.assertIn('ttl 64', output)
5399 self.assertIn('6rd-prefix 2001:db8::/32', output)
5400 self.assertIn('6rd-relay_prefix 10.0.0.0/8', output)
5401
5402 print(f'### ip -6 address show dev {tunnel_name}')
5403 output = check_output(f'ip -6 address show dev {tunnel_name}')
5404 print(output)
5405 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')
5406 self.assertRegex(output, 'inet6 ::10.100.100.[0-9]+/96 scope global')
5407
5408 print(f'### ip -6 route show dev {tunnel_name}')
5409 output = check_output(f'ip -6 route show dev {tunnel_name}')
5410 print(output)
5411 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto kernel metric [0-9]* expires')
5412 self.assertRegex(output, '::/96 proto kernel metric [0-9]*')
5413
5414 print('### ip -6 route show default')
5415 output = check_output('ip -6 route show default')
5416 print(output)
5417 self.assertIn('default', output)
5418 self.assertIn(f'via ::10.0.0.1 dev {tunnel_name}', output)
5419
5420 def test_dhcp4_6rd(self):
5421 copy_unit_to_networkd_unit_path('25-veth.netdev', '25-dhcp4-6rd-server.network', '25-dhcp4-6rd-upstream.network',
5422 '25-veth-downstream-veth97.netdev', '25-dhcp-pd-downstream-veth97.network', '25-dhcp-pd-downstream-veth97-peer.network',
5423 '25-veth-downstream-veth98.netdev', '25-dhcp-pd-downstream-veth98.network', '25-dhcp-pd-downstream-veth98-peer.network',
5424 '11-dummy.netdev', '25-dhcp-pd-downstream-test1.network',
5425 '25-dhcp-pd-downstream-dummy97.network',
5426 '12-dummy.netdev', '25-dhcp-pd-downstream-dummy98.network',
5427 '13-dummy.netdev', '25-dhcp-pd-downstream-dummy99.network',
5428 '80-6rd-tunnel.network')
5429
5430 start_networkd()
5431 self.wait_online(['veth-peer:routable'])
5432
5433 # ipv4masklen: 8
5434 # 6rd-prefix: 2001:db8::/32
5435 # br-addresss: 10.0.0.1
5436
5437 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')
5438 self.wait_online(['veth99:routable', 'test1:routable', 'dummy98:routable', 'dummy99:degraded',
5439 'veth97:routable', 'veth97-peer:routable', 'veth98:routable', 'veth98-peer:routable'])
5440
5441 # Test case for a downstream which appears later
5442 check_output('ip link add dummy97 type dummy')
5443 self.wait_online(['dummy97:routable'])
5444
5445 # Find tunnel name
5446 tunnel_name = None
5447 for name in os.listdir('/sys/class/net/'):
5448 if name.startswith('6rd-'):
5449 tunnel_name = name
5450 break
5451
5452 self.wait_online([f'{tunnel_name}:routable'])
5453
5454 self.verify_dhcp4_6rd(tunnel_name)
5455
5456 # Test case for reconfigure
5457 check_output(*networkctl_cmd, 'reconfigure', 'dummy98', 'dummy99', env=env)
5458 self.wait_online(['dummy98:routable', 'dummy99:degraded'])
5459
5460 self.verify_dhcp4_6rd(tunnel_name)
5461
5462 print('Wait for the DHCP lease to be expired')
5463 time.sleep(120)
5464
5465 self.wait_online(['veth99:routable', 'test1:routable', 'dummy97:routable', 'dummy98:routable', 'dummy99:degraded',
5466 'veth97:routable', 'veth97-peer:routable', 'veth98:routable', 'veth98-peer:routable'])
5467
5468 self.verify_dhcp4_6rd(tunnel_name)
5469
5470class NetworkdIPv6PrefixTests(unittest.TestCase, Utilities):
5471 links = [
5472 'dummy98',
5473 'veth99',
5474 ]
5475
5476 units = [
5477 '12-dummy.netdev',
5478 '25-veth.netdev',
5479 '25-ipv6ra-prefix-client-deny-list.network',
5480 '25-ipv6ra-prefix-client.network',
5481 '25-ipv6ra-prefix.network',
5482 '25-ipv6ra-uplink.network',
5483 ]
5484
5485 def setUp(self):
5486 remove_links(self.links)
5487 stop_networkd(show_logs=False)
5488
5489 def tearDown(self):
5490 remove_links(self.links)
5491 remove_unit_from_networkd_path(self.units)
5492 stop_networkd(show_logs=True)
5493
5494 def test_ipv6_route_prefix(self):
5495 copy_unit_to_networkd_unit_path('25-veth.netdev', '25-ipv6ra-prefix-client.network', '25-ipv6ra-prefix.network',
5496 '12-dummy.netdev', '25-ipv6ra-uplink.network')
5497
5498 start_networkd()
5499 self.wait_online(['veth99:routable', 'veth-peer:routable', 'dummy98:routable'])
5500
5501 output = check_output('ip address show dev veth-peer')
5502 print(output)
5503 self.assertIn('inet6 2001:db8:0:1:', output)
5504 self.assertNotIn('inet6 2001:db8:0:2:', output)
5505 self.assertNotIn('inet6 2001:db8:0:3:', output)
5506
5507 output = check_output('ip -6 route show dev veth-peer')
5508 print(output)
5509 self.assertIn('2001:db8:0:1::/64 proto ra', output)
5510 self.assertNotIn('2001:db8:0:2::/64 proto ra', output)
5511 self.assertNotIn('2001:db8:0:3::/64 proto ra', output)
5512 self.assertIn('2001:db0:fff::/64 via ', output)
5513 self.assertNotIn('2001:db1:fff::/64 via ', output)
5514 self.assertNotIn('2001:db2:fff::/64 via ', output)
5515
5516 output = check_output('ip address show dev veth99')
5517 print(output)
5518 self.assertNotIn('inet6 2001:db8:0:1:', output)
5519 self.assertIn('inet6 2001:db8:0:2:1a:2b:3c:4d', output)
5520 self.assertIn('inet6 2001:db8:0:2:fa:de:ca:fe', output)
5521 self.assertNotIn('inet6 2001:db8:0:3:', output)
5522
5523 output = check_output(*resolvectl_cmd, 'dns', 'veth-peer', env=env)
5524 print(output)
5525 self.assertRegex(output, '2001:db8:1:1::2')
5526
5527 output = check_output(*resolvectl_cmd, 'domain', 'veth-peer', env=env)
5528 print(output)
5529 self.assertIn('example.com', output)
5530
5531 # TODO: check json string
5532 check_output(*networkctl_cmd, '--json=short', 'status', env=env)
5533
5534 def test_ipv6_route_prefix_deny_list(self):
5535 copy_unit_to_networkd_unit_path('25-veth.netdev', '25-ipv6ra-prefix-client-deny-list.network', '25-ipv6ra-prefix.network',
5536 '12-dummy.netdev', '25-ipv6ra-uplink.network')
5537
5538 start_networkd()
5539 self.wait_online(['veth99:routable', 'veth-peer:routable', 'dummy98:routable'])
5540
5541 output = check_output('ip address show dev veth-peer')
5542 print(output)
5543 self.assertIn('inet6 2001:db8:0:1:', output)
5544 self.assertNotIn('inet6 2001:db8:0:2:', output)
5545
5546 output = check_output('ip -6 route show dev veth-peer')
5547 print(output)
5548 self.assertIn('2001:db8:0:1::/64 proto ra', output)
5549 self.assertNotIn('2001:db8:0:2::/64 proto ra', output)
5550 self.assertIn('2001:db0:fff::/64 via ', output)
5551 self.assertNotIn('2001:db1:fff::/64 via ', output)
5552
5553 output = check_output('ip address show dev veth99')
5554 print(output)
5555 self.assertNotIn('inet6 2001:db8:0:1:', output)
5556 self.assertIn('inet6 2001:db8:0:2:', output)
5557
5558 output = check_output(*resolvectl_cmd, 'dns', 'veth-peer', env=env)
5559 print(output)
5560 self.assertRegex(output, '2001:db8:1:1::2')
5561
5562 output = check_output(*resolvectl_cmd, 'domain', 'veth-peer', env=env)
5563 print(output)
5564 self.assertIn('example.com', output)
5565
5566class NetworkdMTUTests(unittest.TestCase, Utilities):
5567 links = ['dummy98']
5568
5569 units = [
5570 '12-dummy.netdev',
5571 '12-dummy-mtu.netdev',
5572 '12-dummy-mtu.link',
5573 '12-dummy.network',
5574 ]
5575
5576 def setUp(self):
5577 remove_links(self.links)
5578 stop_networkd(show_logs=False)
5579
5580 def tearDown(self):
5581 remove_links(self.links)
5582 remove_unit_from_networkd_path(self.units)
5583 stop_networkd(show_logs=True)
5584
5585 def check_mtu(self, mtu, ipv6_mtu=None, reset=True):
5586 if not ipv6_mtu:
5587 ipv6_mtu = mtu
5588
5589 # test normal start
5590 start_networkd()
5591 self.wait_online(['dummy98:routable'])
5592 self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu)
5593 self.assertEqual(read_link_attr('dummy98', 'mtu'), mtu)
5594
5595 # test normal restart
5596 restart_networkd()
5597 self.wait_online(['dummy98:routable'])
5598 self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu)
5599 self.assertEqual(read_link_attr('dummy98', 'mtu'), mtu)
5600
5601 if reset:
5602 self.reset_check_mtu(mtu, ipv6_mtu)
5603
5604 def reset_check_mtu(self, mtu, ipv6_mtu=None):
5605 ''' test setting mtu/ipv6_mtu with interface already up '''
5606 stop_networkd()
5607
5608 # note - changing the device mtu resets the ipv6 mtu
5609 run('ip link set up mtu 1501 dev dummy98')
5610 run('ip link set up mtu 1500 dev dummy98')
5611 self.assertEqual(read_link_attr('dummy98', 'mtu'), '1500')
5612 self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), '1500')
5613
5614 self.check_mtu(mtu, ipv6_mtu, reset=False)
5615
5616 def test_mtu_network(self):
5617 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
5618 self.check_mtu('1600')
5619
5620 def test_mtu_netdev(self):
5621 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network', dropins=False)
5622 # note - MTU set by .netdev happens ONLY at device creation!
5623 self.check_mtu('1600', reset=False)
5624
5625 def test_mtu_link(self):
5626 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', dropins=False)
5627 # must reload udev because it only picks up new files after 3 second delay
5628 call('udevadm control --reload')
5629 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
5630 self.check_mtu('1600', reset=False)
5631
5632 def test_ipv6_mtu(self):
5633 ''' set ipv6 mtu without setting device mtu '''
5634 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
5635 self.check_mtu('1500', '1400')
5636
5637 def test_ipv6_mtu_toolarge(self):
5638 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
5639 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
5640 self.check_mtu('1500', '1500')
5641
5642 def test_mtu_network_ipv6_mtu(self):
5643 ''' set ipv6 mtu and set device mtu via network file '''
5644 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
5645 self.check_mtu('1600', '1550')
5646
5647 def test_mtu_netdev_ipv6_mtu(self):
5648 ''' set ipv6 mtu and set device mtu via netdev file '''
5649 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
5650 self.check_mtu('1600', '1550', reset=False)
5651
5652 def test_mtu_link_ipv6_mtu(self):
5653 ''' set ipv6 mtu and set device mtu via link file '''
5654 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
5655 # must reload udev because it only picks up new files after 3 second delay
5656 call('udevadm control --reload')
5657 self.check_mtu('1600', '1550', reset=False)
5658
5659
5660if __name__ == '__main__':
5661 parser = argparse.ArgumentParser()
5662 parser.add_argument('--build-dir', help='Path to build dir', dest='build_dir')
5663 parser.add_argument('--networkd', help='Path to systemd-networkd', dest='networkd_bin')
5664 parser.add_argument('--resolved', help='Path to systemd-resolved', dest='resolved_bin')
5665 parser.add_argument('--udevd', help='Path to systemd-udevd', dest='udevd_bin')
5666 parser.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest='wait_online_bin')
5667 parser.add_argument('--networkctl', help='Path to networkctl', dest='networkctl_bin')
5668 parser.add_argument('--resolvectl', help='Path to resolvectl', dest='resolvectl_bin')
5669 parser.add_argument('--timedatectl', help='Path to timedatectl', dest='timedatectl_bin')
5670 parser.add_argument('--valgrind', help='Enable valgrind', dest='use_valgrind', type=bool, nargs='?', const=True, default=use_valgrind)
5671 parser.add_argument('--debug', help='Generate debugging logs', dest='enable_debug', type=bool, nargs='?', const=True, default=enable_debug)
5672 parser.add_argument('--asan-options', help='ASAN options', dest='asan_options')
5673 parser.add_argument('--lsan-options', help='LSAN options', dest='lsan_options')
5674 parser.add_argument('--ubsan-options', help='UBSAN options', dest='ubsan_options')
5675 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)
5676 ns, unknown_args = parser.parse_known_args(namespace=unittest)
5677
5678 if ns.build_dir:
5679 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:
5680 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
5681 networkd_bin = os.path.join(ns.build_dir, 'systemd-networkd')
5682 resolved_bin = os.path.join(ns.build_dir, 'systemd-resolved')
5683 udevd_bin = os.path.join(ns.build_dir, 'systemd-udevd')
5684 wait_online_bin = os.path.join(ns.build_dir, 'systemd-networkd-wait-online')
5685 networkctl_bin = os.path.join(ns.build_dir, 'networkctl')
5686 resolvectl_bin = os.path.join(ns.build_dir, 'resolvectl')
5687 timedatectl_bin = os.path.join(ns.build_dir, 'timedatectl')
5688 else:
5689 if ns.networkd_bin:
5690 networkd_bin = ns.networkd_bin
5691 if ns.resolved_bin:
5692 resolved_bin = ns.resolved_bin
5693 if ns.udevd_bin:
5694 udevd_bin = ns.udevd_bin
5695 if ns.wait_online_bin:
5696 wait_online_bin = ns.wait_online_bin
5697 if ns.networkctl_bin:
5698 networkctl_bin = ns.networkctl_bin
5699 if ns.resolvectl_bin:
5700 resolvectl_bin = ns.resolvectl_bin
5701 if ns.timedatectl_bin:
5702 timedatectl_bin = ns.timedatectl_bin
5703
5704 use_valgrind = ns.use_valgrind
5705 enable_debug = ns.enable_debug
5706 asan_options = ns.asan_options
5707 lsan_options = ns.lsan_options
5708 ubsan_options = ns.ubsan_options
5709 with_coverage = ns.with_coverage
5710
5711 if use_valgrind:
5712 networkctl_cmd = ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin]
5713 resolvectl_cmd = ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin]
5714 timedatectl_cmd = ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin]
5715 wait_online_cmd = ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin]
5716 else:
5717 networkctl_cmd = [networkctl_bin]
5718 resolvectl_cmd = [resolvectl_bin]
5719 timedatectl_cmd = [timedatectl_bin]
5720 wait_online_cmd = [wait_online_bin]
5721
5722 if enable_debug:
5723 env.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
5724 if asan_options:
5725 env.update({ 'ASAN_OPTIONS' : asan_options })
5726 if lsan_options:
5727 env.update({ 'LSAN_OPTIONS' : lsan_options })
5728 if ubsan_options:
5729 env.update({ 'UBSAN_OPTIONS' : ubsan_options })
5730
5731 sys.argv[1:] = unknown_args
5732 unittest.main(verbosity=3)