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