]> git.ipfire.org Git - thirdparty/systemd.git/blob - test/test-network/systemd-networkd-tests.py
Merge pull request #28697 from 1awesomeJ/new_bsod
[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('multicast 149.10.123.4 proto static', output)
2950
2951 print('### ip -4 route show dev dummy98 default')
2952 output = check_output('ip -4 route show dev dummy98 default')
2953 print(output)
2954 self.assertIn('default via 149.10.125.65 proto static onlink', output)
2955 self.assertIn('default via 149.10.124.64 proto static', output)
2956 self.assertIn('default proto static', output)
2957
2958 print('### ip -4 route show table local dev dummy98')
2959 output = check_output('ip -4 route show table local dev dummy98')
2960 print(output)
2961 self.assertIn('local 149.10.123.1 proto static scope host', output)
2962 self.assertIn('anycast 149.10.123.2 proto static scope link', output)
2963 self.assertIn('broadcast 149.10.123.3 proto static scope link', output)
2964
2965 print('### ip -4 route show type blackhole')
2966 output = check_output('ip -4 route show type blackhole')
2967 print(output)
2968 self.assertIn('blackhole 202.54.1.2 proto static', output)
2969
2970 print('### ip -4 route show type unreachable')
2971 output = check_output('ip -4 route show type unreachable')
2972 print(output)
2973 self.assertIn('unreachable 202.54.1.3 proto static', output)
2974
2975 print('### ip -4 route show type prohibit')
2976 output = check_output('ip -4 route show type prohibit')
2977 print(output)
2978 self.assertIn('prohibit 202.54.1.4 proto static', output)
2979
2980 print('### ip -6 route show type blackhole')
2981 output = check_output('ip -6 route show type blackhole')
2982 print(output)
2983 self.assertIn('blackhole 2001:1234:5678::2 dev lo proto static', output)
2984
2985 print('### ip -6 route show type unreachable')
2986 output = check_output('ip -6 route show type unreachable')
2987 print(output)
2988 self.assertIn('unreachable 2001:1234:5678::3 dev lo proto static', output)
2989
2990 print('### ip -6 route show type prohibit')
2991 output = check_output('ip -6 route show type prohibit')
2992 print(output)
2993 self.assertIn('prohibit 2001:1234:5678::4 dev lo proto static', output)
2994
2995 print('### ip route show 192.168.10.1')
2996 output = check_output('ip route show 192.168.10.1')
2997 print(output)
2998 self.assertIn('192.168.10.1 proto static', output)
2999 self.assertIn('nexthop via 149.10.124.59 dev dummy98 weight 10', output)
3000 self.assertIn('nexthop via 149.10.124.60 dev dummy98 weight 5', output)
3001
3002 print('### ip route show 192.168.10.2')
3003 output = check_output('ip route show 192.168.10.2')
3004 print(output)
3005 # old ip command does not show IPv6 gateways...
3006 self.assertIn('192.168.10.2 proto static', output)
3007 self.assertIn('nexthop', output)
3008 self.assertIn('dev dummy98 weight 10', output)
3009 self.assertIn('dev dummy98 weight 5', output)
3010
3011 print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
3012 output = check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
3013 print(output)
3014 # old ip command does not show 'nexthop' keyword and weight...
3015 self.assertIn('2001:1234:5:7fff:ff:ff:ff:ff', output)
3016 self.assertIn('via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98', output)
3017 self.assertIn('via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98', output)
3018
3019 output = check_output(*networkctl_cmd, '--json=short', 'status', env=env)
3020 check_json(output)
3021
3022 copy_network_unit('25-address-static.network')
3023 networkctl_reload()
3024 self.wait_online(['dummy98:routable'])
3025
3026 # check all routes managed by Manager are removed
3027 print('### ip -4 route show type blackhole')
3028 output = check_output('ip -4 route show type blackhole')
3029 print(output)
3030 self.assertEqual(output, '')
3031
3032 print('### ip -4 route show type unreachable')
3033 output = check_output('ip -4 route show type unreachable')
3034 print(output)
3035 self.assertEqual(output, '')
3036
3037 print('### ip -4 route show type prohibit')
3038 output = check_output('ip -4 route show type prohibit')
3039 print(output)
3040 self.assertEqual(output, '')
3041
3042 print('### ip -6 route show type blackhole')
3043 output = check_output('ip -6 route show type blackhole')
3044 print(output)
3045 self.assertEqual(output, '')
3046
3047 print('### ip -6 route show type unreachable')
3048 output = check_output('ip -6 route show type unreachable')
3049 print(output)
3050 self.assertEqual(output, '')
3051
3052 print('### ip -6 route show type prohibit')
3053 output = check_output('ip -6 route show type prohibit')
3054 print(output)
3055 self.assertEqual(output, '')
3056
3057 remove_network_unit('25-address-static.network')
3058 networkctl_reload()
3059 self.wait_online(['dummy98:routable'])
3060
3061 # check all routes managed by Manager are reconfigured
3062 print('### ip -4 route show type blackhole')
3063 output = check_output('ip -4 route show type blackhole')
3064 print(output)
3065 self.assertIn('blackhole 202.54.1.2 proto static', output)
3066
3067 print('### ip -4 route show type unreachable')
3068 output = check_output('ip -4 route show type unreachable')
3069 print(output)
3070 self.assertIn('unreachable 202.54.1.3 proto static', output)
3071
3072 print('### ip -4 route show type prohibit')
3073 output = check_output('ip -4 route show type prohibit')
3074 print(output)
3075 self.assertIn('prohibit 202.54.1.4 proto static', output)
3076
3077 print('### ip -6 route show type blackhole')
3078 output = check_output('ip -6 route show type blackhole')
3079 print(output)
3080 self.assertIn('blackhole 2001:1234:5678::2 dev lo proto static', output)
3081
3082 print('### ip -6 route show type unreachable')
3083 output = check_output('ip -6 route show type unreachable')
3084 print(output)
3085 self.assertIn('unreachable 2001:1234:5678::3 dev lo proto static', output)
3086
3087 print('### ip -6 route show type prohibit')
3088 output = check_output('ip -6 route show type prohibit')
3089 print(output)
3090 self.assertIn('prohibit 2001:1234:5678::4 dev lo proto static', output)
3091
3092 remove_link('dummy98')
3093 time.sleep(2)
3094
3095 # check all routes managed by Manager are removed
3096 print('### ip -4 route show type blackhole')
3097 output = check_output('ip -4 route show type blackhole')
3098 print(output)
3099 self.assertEqual(output, '')
3100
3101 print('### ip -4 route show type unreachable')
3102 output = check_output('ip -4 route show type unreachable')
3103 print(output)
3104 self.assertEqual(output, '')
3105
3106 print('### ip -4 route show type prohibit')
3107 output = check_output('ip -4 route show type prohibit')
3108 print(output)
3109 self.assertEqual(output, '')
3110
3111 print('### ip -6 route show type blackhole')
3112 output = check_output('ip -6 route show type blackhole')
3113 print(output)
3114 self.assertEqual(output, '')
3115
3116 print('### ip -6 route show type unreachable')
3117 output = check_output('ip -6 route show type unreachable')
3118 print(output)
3119 self.assertEqual(output, '')
3120
3121 print('### ip -6 route show type prohibit')
3122 output = check_output('ip -6 route show type prohibit')
3123 print(output)
3124 self.assertEqual(output, '')
3125
3126 self.tearDown()
3127
3128 def test_route_static(self):
3129 first = True
3130 for manage_foreign_routes in [True, False]:
3131 if first:
3132 first = False
3133 else:
3134 self.tearDown()
3135
3136 print(f'### test_route_static(manage_foreign_routes={manage_foreign_routes})')
3137 with self.subTest(manage_foreign_routes=manage_foreign_routes):
3138 self._test_route_static(manage_foreign_routes)
3139
3140 @expectedFailureIfRTA_VIAIsNotSupported()
3141 def test_route_via_ipv6(self):
3142 copy_network_unit('25-route-via-ipv6.network', '12-dummy.netdev')
3143 start_networkd()
3144 self.wait_online(['dummy98:routable'])
3145
3146 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98', env=env)
3147 print(output)
3148
3149 print('### ip -6 route show dev dummy98')
3150 output = check_output('ip -6 route show dev dummy98')
3151 print(output)
3152 self.assertRegex(output, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
3153 self.assertRegex(output, '2001:1234:5:8f63::1 proto kernel')
3154
3155 print('### ip -4 route show dev dummy98')
3156 output = check_output('ip -4 route show dev dummy98')
3157 print(output)
3158 self.assertRegex(output, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
3159 self.assertRegex(output, '149.10.124.66 via inet6 2001:1234:5:8fff:ff:ff:ff:ff proto static')
3160
3161 @expectedFailureIfModuleIsNotAvailable('tcp_dctcp')
3162 def test_route_congctl(self):
3163 copy_network_unit('25-route-congctl.network', '12-dummy.netdev')
3164 start_networkd()
3165 self.wait_online(['dummy98:routable'])
3166
3167 print('### ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff')
3168 output = check_output('ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff')
3169 print(output)
3170 self.assertIn('2001:1234:5:8fff:ff:ff:ff:ff proto static', output)
3171 self.assertIn('congctl dctcp', output)
3172
3173 print('### ip -4 route show dev dummy98 149.10.124.66')
3174 output = check_output('ip -4 route show dev dummy98 149.10.124.66')
3175 print(output)
3176 self.assertIn('149.10.124.66 proto static', output)
3177 self.assertIn('congctl dctcp', output)
3178
3179 @expectedFailureIfModuleIsNotAvailable('vrf')
3180 def test_route_vrf(self):
3181 copy_network_unit('25-route-vrf.network', '12-dummy.netdev',
3182 '25-vrf.netdev', '25-vrf.network')
3183 start_networkd()
3184 self.wait_online(['dummy98:routable', 'vrf99:carrier'])
3185
3186 output = check_output('ip route show vrf vrf99')
3187 print(output)
3188 self.assertRegex(output, 'default via 192.168.100.1')
3189
3190 output = check_output('ip route show')
3191 print(output)
3192 self.assertNotRegex(output, 'default via 192.168.100.1')
3193
3194 def test_gateway_reconfigure(self):
3195 copy_network_unit('25-gateway-static.network', '12-dummy.netdev')
3196 start_networkd()
3197 self.wait_online(['dummy98:routable'])
3198 print('### ip -4 route show dev dummy98 default')
3199 output = check_output('ip -4 route show dev dummy98 default')
3200 print(output)
3201 self.assertIn('default via 149.10.124.59 proto static', output)
3202 self.assertNotIn('149.10.124.60', output)
3203
3204 remove_network_unit('25-gateway-static.network')
3205 copy_network_unit('25-gateway-next-static.network')
3206 networkctl_reload()
3207 self.wait_online(['dummy98:routable'])
3208 print('### ip -4 route show dev dummy98 default')
3209 output = check_output('ip -4 route show dev dummy98 default')
3210 print(output)
3211 self.assertNotIn('149.10.124.59', output)
3212 self.assertIn('default via 149.10.124.60 proto static', output)
3213
3214 def test_ip_route_ipv6_src_route(self):
3215 # a dummy device does not make the addresses go through tentative state, so we
3216 # reuse a bond from an earlier test, which does make the addresses go through
3217 # tentative state, and do our test on that
3218 copy_network_unit('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
3219 start_networkd()
3220 self.wait_online(['dummy98:enslaved', 'bond199:routable'])
3221
3222 output = check_output('ip -6 route list dev bond199')
3223 print(output)
3224 self.assertIn('abcd::/16 via 2001:1234:56:8f63::1:1 proto static src 2001:1234:56:8f63::2', output)
3225
3226 def test_route_preferred_source_with_existing_address(self):
3227 # See issue #28009.
3228 copy_network_unit('25-route-preferred-source.network', '12-dummy.netdev')
3229 start_networkd()
3230
3231 for i in range(3):
3232 if i != 0:
3233 networkctl_reconfigure('dummy98')
3234
3235 self.wait_online(['dummy98:routable'])
3236
3237 output = check_output('ip -6 route list dev dummy98')
3238 print(output)
3239 self.assertIn('abcd::/16 via 2001:1234:56:8f63::1:1 proto static src 2001:1234:56:8f63::1', output)
3240
3241 def test_ip_link_mac_address(self):
3242 copy_network_unit('25-address-link-section.network', '12-dummy.netdev')
3243 start_networkd()
3244 self.wait_online(['dummy98:degraded'])
3245
3246 output = check_output('ip link show dummy98')
3247 print(output)
3248 self.assertRegex(output, '00:01:02:aa:bb:cc')
3249
3250 def test_ip_link_unmanaged(self):
3251 copy_network_unit('25-link-section-unmanaged.network', '12-dummy.netdev')
3252 start_networkd()
3253
3254 self.wait_operstate('dummy98', 'off', setup_state='unmanaged')
3255
3256 def test_ipv6_address_label(self):
3257 copy_network_unit('25-ipv6-address-label-section.network', '12-dummy.netdev')
3258 start_networkd()
3259 self.wait_online(['dummy98:degraded'])
3260
3261 output = check_output('ip addrlabel list')
3262 print(output)
3263 self.assertRegex(output, '2004:da8:1::/64')
3264
3265 def test_ipv6_proxy_ndp(self):
3266 copy_network_unit('25-ipv6-proxy-ndp.network', '12-dummy.netdev')
3267 start_networkd()
3268
3269 self.wait_online(['dummy98:routable'])
3270
3271 output = check_output('ip neighbor show proxy dev dummy98')
3272 print(output)
3273 for i in range(1, 5):
3274 self.assertRegex(output, f'2607:5300:203:5215:{i}::1 *proxy')
3275
3276 def test_neighbor_section(self):
3277 copy_network_unit('25-neighbor-section.network', '12-dummy.netdev', copy_dropins=False)
3278 start_networkd()
3279 self.wait_online(['dummy98:degraded'])
3280
3281 print('### ip neigh list dev dummy98')
3282 output = check_output('ip neigh list dev dummy98')
3283 print(output)
3284 self.assertIn('192.168.10.1 lladdr 00:00:5e:00:02:65 PERMANENT', output)
3285 self.assertIn('2004:da8:1::1 lladdr 00:00:5e:00:02:66 PERMANENT', output)
3286 self.assertNotIn('2004:da8:1:0::2', output)
3287 self.assertNotIn('192.168.10.2', output)
3288 self.assertNotIn('00:00:5e:00:02:67', output)
3289
3290 output = check_output(*networkctl_cmd, '--json=short', 'status', env=env)
3291 check_json(output)
3292
3293 copy_network_unit('25-neighbor-section.network.d/override.conf')
3294 networkctl_reload()
3295 self.wait_online(['dummy98:degraded'])
3296
3297 print('### ip neigh list dev dummy98 (after reloading)')
3298 output = check_output('ip neigh list dev dummy98')
3299 print(output)
3300 self.assertIn('192.168.10.1 lladdr 00:00:5e:00:03:65 PERMANENT', output)
3301 self.assertIn('2004:da8:1::1 lladdr 00:00:5e:00:03:66 PERMANENT', output)
3302 self.assertNotIn('2004:da8:1:0::2', output)
3303 self.assertNotIn('192.168.10.2', output)
3304 self.assertNotIn('00:00:5e:00:02', output)
3305
3306 def test_neighbor_reconfigure(self):
3307 copy_network_unit('25-neighbor-section.network', '12-dummy.netdev', copy_dropins=False)
3308 start_networkd()
3309 self.wait_online(['dummy98:degraded'])
3310
3311 print('### ip neigh list dev dummy98')
3312 output = check_output('ip neigh list dev dummy98')
3313 print(output)
3314 self.assertIn('192.168.10.1 lladdr 00:00:5e:00:02:65 PERMANENT', output)
3315 self.assertIn('2004:da8:1::1 lladdr 00:00:5e:00:02:66 PERMANENT', output)
3316
3317 remove_network_unit('25-neighbor-section.network')
3318 copy_network_unit('25-neighbor-next.network')
3319 networkctl_reload()
3320 self.wait_online(['dummy98:degraded'])
3321 print('### ip neigh list dev dummy98')
3322 output = check_output('ip neigh list dev dummy98')
3323 print(output)
3324 self.assertNotIn('00:00:5e:00:02:65', output)
3325 self.assertIn('192.168.10.1 lladdr 00:00:5e:00:02:66 PERMANENT', output)
3326 self.assertNotIn('2004:da8:1::1', output)
3327
3328 def test_neighbor_gre(self):
3329 copy_network_unit('25-neighbor-ip.network', '25-neighbor-ipv6.network', '25-neighbor-ip-dummy.network',
3330 '12-dummy.netdev', '25-gre-tunnel-remote-any.netdev', '25-ip6gre-tunnel-remote-any.netdev')
3331 start_networkd()
3332 self.wait_online(['dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable'], timeout='40s')
3333
3334 output = check_output('ip neigh list dev gretun97')
3335 print(output)
3336 self.assertIn('10.0.0.22 lladdr 10.65.223.239 PERMANENT', output)
3337 self.assertNotIn('10.0.0.23', output)
3338
3339 output = check_output('ip neigh list dev ip6gretun97')
3340 print(output)
3341 self.assertRegex(output, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
3342 self.assertNotIn('2001:db8:0:f102::18', output)
3343
3344 output = check_output(*networkctl_cmd, '--json=short', 'status', env=env)
3345 check_json(output)
3346
3347 def test_link_local_addressing(self):
3348 copy_network_unit('25-link-local-addressing-yes.network', '11-dummy.netdev',
3349 '25-link-local-addressing-no.network', '12-dummy.netdev')
3350 start_networkd()
3351 self.wait_online(['test1:degraded', 'dummy98:carrier'])
3352
3353 output = check_output('ip address show dev test1')
3354 print(output)
3355 self.assertRegex(output, 'inet .* scope link')
3356 self.assertRegex(output, 'inet6 .* scope link')
3357
3358 output = check_output('ip address show dev dummy98')
3359 print(output)
3360 self.assertNotRegex(output, 'inet6* .* scope link')
3361
3362 # Documentation/networking/ip-sysctl.txt
3363 #
3364 # addr_gen_mode - INTEGER
3365 # Defines how link-local and autoconf addresses are generated.
3366 #
3367 # 0: generate address based on EUI64 (default)
3368 # 1: do no generate a link-local address, use EUI64 for addresses generated
3369 # from autoconf
3370 # 2: generate stable privacy addresses, using the secret from
3371 # stable_secret (RFC7217)
3372 # 3: generate stable privacy addresses, using a random secret if unset
3373
3374 self.check_ipv6_sysctl_attr('test1', 'stable_secret', '0123:4567:89ab:cdef:0123:4567:89ab:cdef')
3375 self.check_ipv6_sysctl_attr('test1', 'addr_gen_mode', '2')
3376 self.check_ipv6_sysctl_attr('dummy98', 'addr_gen_mode', '1')
3377
3378 def test_link_local_addressing_ipv6ll(self):
3379 copy_network_unit('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
3380 start_networkd()
3381 self.wait_online(['dummy98:degraded'])
3382
3383 # An IPv6LL address exists by default.
3384 output = check_output('ip address show dev dummy98')
3385 print(output)
3386 self.assertRegex(output, 'inet6 .* scope link')
3387
3388 copy_network_unit('25-link-local-addressing-no.network')
3389 networkctl_reload()
3390 self.wait_online(['dummy98:carrier'])
3391
3392 # Check if the IPv6LL address is removed.
3393 output = check_output('ip address show dev dummy98')
3394 print(output)
3395 self.assertNotRegex(output, 'inet6 .* scope link')
3396
3397 remove_network_unit('25-link-local-addressing-no.network')
3398 networkctl_reload()
3399 self.wait_online(['dummy98:degraded'])
3400
3401 # Check if a new IPv6LL address is assigned.
3402 output = check_output('ip address show dev dummy98')
3403 print(output)
3404 self.assertRegex(output, 'inet6 .* scope link')
3405
3406 def test_sysctl(self):
3407 copy_networkd_conf_dropin('25-global-ipv6-privacy-extensions.conf')
3408 copy_network_unit('25-sysctl.network', '12-dummy.netdev', copy_dropins=False)
3409 start_networkd()
3410 self.wait_online(['dummy98:degraded'])
3411
3412 self.check_ipv6_sysctl_attr('dummy98', 'forwarding', '1')
3413 self.check_ipv6_sysctl_attr('dummy98', 'use_tempaddr', '1')
3414 self.check_ipv6_sysctl_attr('dummy98', 'dad_transmits', '3')
3415 self.check_ipv6_sysctl_attr('dummy98', 'hop_limit', '5')
3416 self.check_ipv6_sysctl_attr('dummy98', 'proxy_ndp', '1')
3417 self.check_ipv4_sysctl_attr('dummy98', 'forwarding', '1')
3418 self.check_ipv4_sysctl_attr('dummy98', 'proxy_arp', '1')
3419 self.check_ipv4_sysctl_attr('dummy98', 'accept_local', '1')
3420 self.check_ipv4_sysctl_attr('dummy98', 'rp_filter', '0')
3421
3422 copy_network_unit('25-sysctl.network.d/25-ipv6-privacy-extensions.conf')
3423 networkctl_reload()
3424 self.wait_online(['dummy98:degraded'])
3425
3426 self.check_ipv6_sysctl_attr('dummy98', 'use_tempaddr', '2')
3427
3428 def test_sysctl_disable_ipv6(self):
3429 copy_network_unit('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
3430
3431 print('## Disable ipv6')
3432 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
3433 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
3434
3435 start_networkd()
3436 self.wait_online(['dummy98:routable'])
3437
3438 output = check_output('ip -4 address show dummy98')
3439 print(output)
3440 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
3441 output = check_output('ip -6 address show dummy98')
3442 print(output)
3443 self.assertRegex(output, 'inet6 2607:5300:203:3906::/64 scope global')
3444 self.assertRegex(output, 'inet6 .* scope link')
3445 output = check_output('ip -4 route show dev dummy98')
3446 print(output)
3447 self.assertRegex(output, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
3448 output = check_output('ip -6 route show default')
3449 print(output)
3450 self.assertRegex(output, 'default')
3451 self.assertRegex(output, 'via 2607:5300:203:39ff:ff:ff:ff:ff')
3452
3453 remove_link('dummy98')
3454
3455 print('## Enable ipv6')
3456 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
3457 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
3458
3459 restart_networkd()
3460 self.wait_online(['dummy98:routable'])
3461
3462 output = check_output('ip -4 address show dummy98')
3463 print(output)
3464 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
3465 output = check_output('ip -6 address show dummy98')
3466 print(output)
3467 self.assertRegex(output, 'inet6 2607:5300:203:3906::/64 scope global')
3468 self.assertRegex(output, 'inet6 .* scope link')
3469 output = check_output('ip -4 route show dev dummy98')
3470 print(output)
3471 self.assertRegex(output, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
3472 output = check_output('ip -6 route show default')
3473 print(output)
3474 self.assertRegex(output, 'via 2607:5300:203:39ff:ff:ff:ff:ff')
3475
3476 def test_bind_carrier(self):
3477 copy_network_unit('25-bind-carrier.network', '11-dummy.netdev')
3478 start_networkd()
3479
3480 # no bound interface.
3481 self.wait_operstate('test1', 'off', setup_state='configuring')
3482 output = check_output('ip address show test1')
3483 print(output)
3484 self.assertNotIn('UP,LOWER_UP', output)
3485 self.assertIn('DOWN', output)
3486 self.assertNotIn('192.168.10', output)
3487
3488 # add one bound interface. The interface will be up.
3489 check_output('ip link add dummy98 type dummy')
3490 check_output('ip link set dummy98 up')
3491 self.wait_online(['test1:routable'])
3492 output = check_output('ip address show test1')
3493 print(output)
3494 self.assertIn('UP,LOWER_UP', output)
3495 self.assertIn('inet 192.168.10.30/24 brd 192.168.10.255 scope global test1', output)
3496
3497 # add another bound interface. The interface is still up.
3498 check_output('ip link add dummy99 type dummy')
3499 check_output('ip link set dummy99 up')
3500 self.wait_operstate('dummy99', 'degraded', setup_state='unmanaged')
3501 output = check_output('ip address show test1')
3502 print(output)
3503 self.assertIn('UP,LOWER_UP', output)
3504 self.assertIn('inet 192.168.10.30/24 brd 192.168.10.255 scope global test1', output)
3505
3506 # remove one of the bound interfaces. The interface is still up
3507 remove_link('dummy98')
3508 output = check_output('ip address show test1')
3509 print(output)
3510 self.assertIn('UP,LOWER_UP', output)
3511 self.assertIn('inet 192.168.10.30/24 brd 192.168.10.255 scope global test1', output)
3512
3513 # bring down the remaining bound interface. The interface will be down.
3514 check_output('ip link set dummy99 down')
3515 self.wait_operstate('test1', 'off')
3516 self.wait_address_dropped('test1', r'192.168.10', ipv='-4', timeout_sec=10)
3517 output = check_output('ip address show test1')
3518 print(output)
3519 self.assertNotIn('UP,LOWER_UP', output)
3520 self.assertIn('DOWN', output)
3521 self.assertNotIn('192.168.10', output)
3522
3523 # bring up the bound interface. The interface will be up.
3524 check_output('ip link set dummy99 up')
3525 self.wait_online(['test1:routable'])
3526 output = check_output('ip address show test1')
3527 print(output)
3528 self.assertIn('UP,LOWER_UP', output)
3529 self.assertIn('inet 192.168.10.30/24 brd 192.168.10.255 scope global test1', output)
3530
3531 # remove the remaining bound interface. The interface will be down.
3532 remove_link('dummy99')
3533 self.wait_operstate('test1', 'off')
3534 self.wait_address_dropped('test1', r'192.168.10', ipv='-4', timeout_sec=10)
3535 output = check_output('ip address show test1')
3536 print(output)
3537 self.assertNotIn('UP,LOWER_UP', output)
3538 self.assertIn('DOWN', output)
3539 self.assertNotIn('192.168.10', output)
3540
3541 # re-add one bound interface. The interface will be up.
3542 check_output('ip link add dummy98 type dummy')
3543 check_output('ip link set dummy98 up')
3544 self.wait_online(['test1:routable'])
3545 output = check_output('ip address show test1')
3546 print(output)
3547 self.assertIn('UP,LOWER_UP', output)
3548 self.assertIn('inet 192.168.10.30/24 brd 192.168.10.255 scope global test1', output)
3549
3550 def _test_activation_policy(self, interface, test):
3551 conffile = '25-activation-policy.network'
3552 if test:
3553 conffile = f'{conffile}.d/{test}.conf'
3554 if interface == 'vlan99':
3555 copy_network_unit('21-vlan.netdev', '21-vlan-test1.network')
3556 copy_network_unit('11-dummy.netdev', conffile, copy_dropins=False)
3557 start_networkd()
3558
3559 always = test.startswith('always')
3560 initial_up = test != 'manual' and not test.endswith('down') # note: default is up
3561 expect_up = initial_up
3562 next_up = not expect_up
3563
3564 if test.endswith('down'):
3565 self.wait_activated(interface)
3566
3567 for iteration in range(4):
3568 with self.subTest(iteration=iteration, expect_up=expect_up):
3569 operstate = 'routable' if expect_up else 'off'
3570 setup_state = 'configured' if expect_up else ('configuring' if iteration == 0 else None)
3571 self.wait_operstate(interface, operstate, setup_state=setup_state, setup_timeout=20)
3572
3573 if expect_up:
3574 self.assertIn('UP', check_output(f'ip link show {interface}'))
3575 self.assertIn('192.168.10.30/24', check_output(f'ip address show {interface}'))
3576 self.assertIn('default via 192.168.10.1', check_output(f'ip route show dev {interface}'))
3577 else:
3578 self.assertIn('DOWN', check_output(f'ip link show {interface}'))
3579
3580 if next_up:
3581 check_output(f'ip link set dev {interface} up')
3582 else:
3583 check_output(f'ip link set dev {interface} down')
3584 expect_up = initial_up if always else next_up
3585 next_up = not next_up
3586 if always:
3587 time.sleep(1)
3588
3589 def test_activation_policy(self):
3590 first = True
3591 for interface in ['test1', 'vlan99']:
3592 for test in ['up', 'always-up', 'manual', 'always-down', 'down', '']:
3593 if first:
3594 first = False
3595 else:
3596 self.tearDown()
3597
3598 print(f'### test_activation_policy(interface={interface}, test={test})')
3599 with self.subTest(interface=interface, test=test):
3600 self._test_activation_policy(interface, test)
3601
3602 def _test_activation_policy_required_for_online(self, policy, required):
3603 conffile = '25-activation-policy.network'
3604 units = ['11-dummy.netdev', '12-dummy.netdev', '12-dummy.network', conffile]
3605 if policy:
3606 units += [f'{conffile}.d/{policy}.conf']
3607 if required:
3608 units += [f'{conffile}.d/required-{required}.conf']
3609 copy_network_unit(*units, copy_dropins=False)
3610 start_networkd()
3611
3612 if policy.endswith('down'):
3613 self.wait_activated('test1')
3614
3615 if policy.endswith('down') or policy == 'manual':
3616 self.wait_operstate('test1', 'off', setup_state='configuring')
3617 else:
3618 self.wait_online(['test1'])
3619
3620 if policy == 'always-down':
3621 # if always-down, required for online is forced to no
3622 expected = False
3623 elif required:
3624 # otherwise if required for online is specified, it should match that
3625 expected = required == 'yes'
3626 elif policy:
3627 # otherwise if only policy specified, required for online defaults to
3628 # true if policy is up, always-up, or bound
3629 expected = policy.endswith('up') or policy == 'bound'
3630 else:
3631 # default is true, if neither are specified
3632 expected = True
3633
3634 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'test1', env=env)
3635 print(output)
3636
3637 yesno = 'yes' if expected else 'no'
3638 self.assertRegex(output, f'Required For Online: {yesno}')
3639
3640 def test_activation_policy_required_for_online(self):
3641 first = True
3642 for policy in ['up', 'always-up', 'manual', 'always-down', 'down', 'bound', '']:
3643 for required in ['yes', 'no', '']:
3644 if first:
3645 first = False
3646 else:
3647 self.tearDown()
3648
3649 print(f'### test_activation_policy_required_for_online(policy={policy}, required={required})')
3650 with self.subTest(policy=policy, required=required):
3651 self._test_activation_policy_required_for_online(policy, required)
3652
3653 def test_domain(self):
3654 copy_network_unit('12-dummy.netdev', '24-search-domain.network')
3655 start_networkd()
3656 self.wait_online(['dummy98:routable'])
3657
3658 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98', env=env)
3659 print(output)
3660 self.assertRegex(output, 'Address: 192.168.42.100')
3661 self.assertRegex(output, 'DNS: 192.168.42.1')
3662 self.assertRegex(output, 'Search Domains: one')
3663
3664 def test_keep_configuration_static(self):
3665 check_output('ip link add name dummy98 type dummy')
3666 check_output('ip address add 10.1.2.3/16 dev dummy98')
3667 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
3668 output = check_output('ip address show dummy98')
3669 print(output)
3670 self.assertRegex(output, 'inet 10.1.2.3/16 scope global dummy98')
3671 self.assertRegex(output, 'inet 10.2.3.4/16 scope global dynamic dummy98')
3672 output = check_output('ip route show dev dummy98')
3673 print(output)
3674
3675 copy_network_unit('24-keep-configuration-static.network')
3676 start_networkd()
3677 self.wait_online(['dummy98:routable'])
3678
3679 output = check_output('ip address show dummy98')
3680 print(output)
3681 self.assertRegex(output, 'inet 10.1.2.3/16 scope global dummy98')
3682 self.assertNotRegex(output, 'inet 10.2.3.4/16 scope global dynamic dummy98')
3683
3684 @expectedFailureIfNexthopIsNotAvailable()
3685 def test_nexthop(self):
3686 def check_nexthop(self):
3687 self.wait_online(['veth99:routable', 'veth-peer:routable', 'dummy98:routable'])
3688
3689 output = check_output('ip nexthop list dev veth99')
3690 print(output)
3691 self.assertIn('id 1 via 192.168.5.1 dev veth99', output)
3692 self.assertIn('id 2 via 2001:1234:5:8f63::2 dev veth99', output)
3693 self.assertIn('id 3 dev veth99', output)
3694 self.assertIn('id 4 dev veth99', output)
3695 self.assertRegex(output, 'id 5 via 192.168.10.1 dev veth99 .*onlink')
3696 self.assertIn('id 8 via fe80:0:222:4dff:ff:ff:ff:ff dev veth99', output)
3697 self.assertRegex(output, r'id [0-9]* via 192.168.5.2 dev veth99')
3698
3699 output = check_output('ip nexthop list dev dummy98')
3700 print(output)
3701 self.assertIn('id 20 via 192.168.20.1 dev dummy98', output)
3702
3703 # kernel manages blackhole nexthops on lo
3704 output = check_output('ip nexthop list dev lo')
3705 print(output)
3706 self.assertIn('id 6 blackhole', output)
3707 self.assertIn('id 7 blackhole', output)
3708
3709 # group nexthops are shown with -0 option
3710 output = check_output('ip -0 nexthop list id 21')
3711 print(output)
3712 self.assertRegex(output, r'id 21 group (1,3/20|20/1,3)')
3713
3714 output = check_output('ip route show dev veth99 10.10.10.10')
3715 print(output)
3716 self.assertEqual('10.10.10.10 nhid 1 via 192.168.5.1 proto static', output)
3717
3718 output = check_output('ip route show dev veth99 10.10.10.11')
3719 print(output)
3720 self.assertEqual('10.10.10.11 nhid 2 via inet6 2001:1234:5:8f63::2 proto static', output)
3721
3722 output = check_output('ip route show dev veth99 10.10.10.12')
3723 print(output)
3724 self.assertEqual('10.10.10.12 nhid 5 via 192.168.10.1 proto static onlink', output)
3725
3726 output = check_output('ip -6 route show dev veth99 2001:1234:5:8f62::1')
3727 print(output)
3728 self.assertEqual('2001:1234:5:8f62::1 nhid 2 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium', output)
3729
3730 output = check_output('ip route show 10.10.10.13')
3731 print(output)
3732 self.assertEqual('blackhole 10.10.10.13 nhid 6 dev lo proto static', output)
3733
3734 output = check_output('ip -6 route show 2001:1234:5:8f62::2')
3735 print(output)
3736 self.assertEqual('blackhole 2001:1234:5:8f62::2 nhid 7 dev lo proto static metric 1024 pref medium', output)
3737
3738 output = check_output('ip route show 10.10.10.14')
3739 print(output)
3740 self.assertIn('10.10.10.14 nhid 21 proto static', output)
3741 self.assertIn('nexthop via 192.168.20.1 dev dummy98 weight 1', output)
3742 self.assertIn('nexthop via 192.168.5.1 dev veth99 weight 3', output)
3743
3744 output = check_output(*networkctl_cmd, '--json=short', 'status', env=env)
3745 check_json(output)
3746
3747 copy_network_unit('25-nexthop.network', '25-veth.netdev', '25-veth-peer.network',
3748 '12-dummy.netdev', '25-nexthop-dummy.network')
3749 start_networkd()
3750
3751 check_nexthop(self)
3752
3753 remove_network_unit('25-nexthop.network')
3754 copy_network_unit('25-nexthop-nothing.network')
3755 networkctl_reload()
3756 self.wait_online(['veth99:routable', 'veth-peer:routable'])
3757
3758 output = check_output('ip nexthop list dev veth99')
3759 print(output)
3760 self.assertEqual(output, '')
3761 output = check_output('ip nexthop list dev lo')
3762 print(output)
3763 self.assertEqual(output, '')
3764
3765 remove_network_unit('25-nexthop-nothing.network')
3766 copy_network_unit('25-nexthop.network')
3767 networkctl_reconfigure('dummy98')
3768 networkctl_reload()
3769
3770 check_nexthop(self)
3771
3772 remove_link('veth99')
3773 time.sleep(2)
3774
3775 output = check_output('ip nexthop list dev lo')
3776 print(output)
3777 self.assertEqual(output, '')
3778
3779 class NetworkdTCTests(unittest.TestCase, Utilities):
3780
3781 def setUp(self):
3782 setup_common()
3783
3784 def tearDown(self):
3785 tear_down_common()
3786
3787 @expectedFailureIfModuleIsNotAvailable('sch_cake')
3788 def test_qdisc_cake(self):
3789 copy_network_unit('25-qdisc-cake.network', '12-dummy.netdev')
3790 start_networkd()
3791 self.wait_online(['dummy98:routable'])
3792
3793 output = check_output('tc qdisc show dev dummy98')
3794 print(output)
3795 self.assertIn('qdisc cake 3a: root', output)
3796 self.assertIn('bandwidth 500Mbit', output)
3797 self.assertIn('autorate-ingress', output)
3798 self.assertIn('diffserv8', output)
3799 self.assertIn('dual-dsthost', output)
3800 self.assertIn(' nat', output)
3801 self.assertIn(' wash', output)
3802 self.assertIn(' split-gso', output)
3803 self.assertIn(' raw', output)
3804 self.assertIn(' atm', output)
3805 self.assertIn('overhead 128', output)
3806 self.assertIn('mpu 20', output)
3807 self.assertIn('fwmark 0xff00', output)
3808 self.assertIn('rtt 1s', output)
3809 self.assertIn('ack-filter-aggressive', output)
3810
3811 @expectedFailureIfModuleIsNotAvailable('sch_codel')
3812 def test_qdisc_codel(self):
3813 copy_network_unit('25-qdisc-codel.network', '12-dummy.netdev')
3814 start_networkd()
3815 self.wait_online(['dummy98:routable'])
3816
3817 output = check_output('tc qdisc show dev dummy98')
3818 print(output)
3819 self.assertRegex(output, 'qdisc codel 33: root')
3820 self.assertRegex(output, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn')
3821
3822 @expectedFailureIfModuleIsNotAvailable('sch_drr')
3823 def test_qdisc_drr(self):
3824 copy_network_unit('25-qdisc-drr.network', '12-dummy.netdev')
3825 start_networkd()
3826 self.wait_online(['dummy98:routable'])
3827
3828 output = check_output('tc qdisc show dev dummy98')
3829 print(output)
3830 self.assertRegex(output, 'qdisc drr 2: root')
3831 output = check_output('tc class show dev dummy98')
3832 print(output)
3833 self.assertRegex(output, 'class drr 2:30 root quantum 2000b')
3834
3835 @expectedFailureIfModuleIsNotAvailable('sch_ets')
3836 def test_qdisc_ets(self):
3837 copy_network_unit('25-qdisc-ets.network', '12-dummy.netdev')
3838 start_networkd()
3839 self.wait_online(['dummy98:routable'])
3840
3841 output = check_output('tc qdisc show dev dummy98')
3842 print(output)
3843
3844 self.assertRegex(output, 'qdisc ets 3a: root')
3845 self.assertRegex(output, 'bands 10 strict 3')
3846 self.assertRegex(output, 'quanta 1 2 3 4 5')
3847 self.assertRegex(output, 'priomap 3 4 5 6 7')
3848
3849 @expectedFailureIfModuleIsNotAvailable('sch_fq')
3850 def test_qdisc_fq(self):
3851 copy_network_unit('25-qdisc-fq.network', '12-dummy.netdev')
3852 start_networkd()
3853 self.wait_online(['dummy98:routable'])
3854
3855 output = check_output('tc qdisc show dev dummy98')
3856 print(output)
3857 self.assertRegex(output, 'qdisc fq 32: root')
3858 self.assertRegex(output, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
3859 self.assertRegex(output, 'quantum 1500')
3860 self.assertRegex(output, 'initial_quantum 13000')
3861 self.assertRegex(output, 'maxrate 1Mbit')
3862
3863 @expectedFailureIfModuleIsNotAvailable('sch_fq_codel')
3864 def test_qdisc_fq_codel(self):
3865 copy_network_unit('25-qdisc-fq_codel.network', '12-dummy.netdev')
3866 start_networkd()
3867 self.wait_online(['dummy98:routable'])
3868
3869 output = check_output('tc qdisc show dev dummy98')
3870 print(output)
3871 self.assertRegex(output, 'qdisc fq_codel 34: root')
3872 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')
3873
3874 @expectedFailureIfModuleIsNotAvailable('sch_fq_pie')
3875 def test_qdisc_fq_pie(self):
3876 copy_network_unit('25-qdisc-fq_pie.network', '12-dummy.netdev')
3877 start_networkd()
3878 self.wait_online(['dummy98:routable'])
3879
3880 output = check_output('tc qdisc show dev dummy98')
3881 print(output)
3882
3883 self.assertRegex(output, 'qdisc fq_pie 3a: root')
3884 self.assertRegex(output, 'limit 200000p')
3885
3886 @expectedFailureIfModuleIsNotAvailable('sch_gred')
3887 def test_qdisc_gred(self):
3888 copy_network_unit('25-qdisc-gred.network', '12-dummy.netdev')
3889 start_networkd()
3890 self.wait_online(['dummy98:routable'])
3891
3892 output = check_output('tc qdisc show dev dummy98')
3893 print(output)
3894 self.assertRegex(output, 'qdisc gred 38: root')
3895 self.assertRegex(output, 'vqs 12 default 10 grio')
3896
3897 @expectedFailureIfModuleIsNotAvailable('sch_hhf')
3898 def test_qdisc_hhf(self):
3899 copy_network_unit('25-qdisc-hhf.network', '12-dummy.netdev')
3900 start_networkd()
3901 self.wait_online(['dummy98:routable'])
3902
3903 output = check_output('tc qdisc show dev dummy98')
3904 print(output)
3905 self.assertRegex(output, 'qdisc hhf 3a: root')
3906 self.assertRegex(output, 'limit 1022p')
3907
3908 @expectedFailureIfModuleIsNotAvailable('sch_htb')
3909 def test_qdisc_htb_fifo(self):
3910 copy_network_unit('25-qdisc-htb-fifo.network', '12-dummy.netdev')
3911 start_networkd()
3912 self.wait_online(['dummy98:routable'])
3913
3914 output = check_output('tc qdisc show dev dummy98')
3915 print(output)
3916 self.assertRegex(output, 'qdisc htb 2: root')
3917 self.assertRegex(output, r'default (0x30|30)')
3918
3919 self.assertRegex(output, 'qdisc pfifo 37: parent 2:37')
3920 self.assertRegex(output, 'limit 100000p')
3921
3922 self.assertRegex(output, 'qdisc bfifo 3a: parent 2:3a')
3923 self.assertRegex(output, 'limit 1000000')
3924
3925 self.assertRegex(output, 'qdisc pfifo_head_drop 3b: parent 2:3b')
3926 self.assertRegex(output, 'limit 1023p')
3927
3928 self.assertRegex(output, 'qdisc pfifo_fast 3c: parent 2:3c')
3929
3930 output = check_output('tc -d class show dev dummy98')
3931 print(output)
3932 # Here (:|prio) is a workaround for a bug in iproute2 v6.2.0 caused by
3933 # https://github.com/shemminger/iproute2/commit/010a8388aea11e767ba3a2506728b9ad9760df0e
3934 # which is fixed in v6.3.0 by
3935 # https://github.com/shemminger/iproute2/commit/4e0e56e0ef05387f7f5d8ab41fe6ec6a1897b26d
3936 self.assertRegex(output, 'class htb 2:37 root leaf 37(:|prio) ')
3937 self.assertRegex(output, 'class htb 2:3a root leaf 3a(:|prio) ')
3938 self.assertRegex(output, 'class htb 2:3b root leaf 3b(:|prio) ')
3939 self.assertRegex(output, 'class htb 2:3c root leaf 3c(:|prio) ')
3940 self.assertRegex(output, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit')
3941 self.assertRegex(output, 'burst 123456')
3942 self.assertRegex(output, 'cburst 123457')
3943
3944 @expectedFailureIfModuleIsNotAvailable('sch_ingress')
3945 def test_qdisc_ingress(self):
3946 copy_network_unit('25-qdisc-clsact.network', '12-dummy.netdev',
3947 '25-qdisc-ingress.network', '11-dummy.netdev')
3948 start_networkd()
3949 self.wait_online(['dummy98:routable', 'test1:routable'])
3950
3951 output = check_output('tc qdisc show dev dummy98')
3952 print(output)
3953 self.assertRegex(output, 'qdisc clsact')
3954
3955 output = check_output('tc qdisc show dev test1')
3956 print(output)
3957 self.assertRegex(output, 'qdisc ingress')
3958
3959 @expectedFailureIfModuleIsNotAvailable('sch_netem')
3960 def test_qdisc_netem(self):
3961 copy_network_unit('25-qdisc-netem.network', '12-dummy.netdev',
3962 '25-qdisc-netem-compat.network', '11-dummy.netdev')
3963 start_networkd()
3964 self.wait_online(['dummy98:routable', 'test1:routable'])
3965
3966 output = check_output('tc qdisc show dev dummy98')
3967 print(output)
3968 self.assertRegex(output, 'qdisc netem 30: root')
3969 self.assertRegex(output, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
3970
3971 output = check_output('tc qdisc show dev test1')
3972 print(output)
3973 self.assertRegex(output, 'qdisc netem [0-9a-f]*: root')
3974 self.assertRegex(output, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
3975
3976 @expectedFailureIfModuleIsNotAvailable('sch_pie')
3977 def test_qdisc_pie(self):
3978 copy_network_unit('25-qdisc-pie.network', '12-dummy.netdev')
3979 start_networkd()
3980 self.wait_online(['dummy98:routable'])
3981
3982 output = check_output('tc qdisc show dev dummy98')
3983 print(output)
3984 self.assertRegex(output, 'qdisc pie 3a: root')
3985 self.assertRegex(output, 'limit 200000')
3986
3987 @expectedFailureIfModuleIsNotAvailable('sch_qfq')
3988 def test_qdisc_qfq(self):
3989 copy_network_unit('25-qdisc-qfq.network', '12-dummy.netdev')
3990 start_networkd()
3991 self.wait_online(['dummy98:routable'])
3992
3993 output = check_output('tc qdisc show dev dummy98')
3994 print(output)
3995 self.assertRegex(output, 'qdisc qfq 2: root')
3996 output = check_output('tc class show dev dummy98')
3997 print(output)
3998 self.assertRegex(output, 'class qfq 2:30 root weight 2 maxpkt 16000')
3999 self.assertRegex(output, 'class qfq 2:31 root weight 10 maxpkt 8000')
4000
4001 @expectedFailureIfModuleIsNotAvailable('sch_sfb')
4002 def test_qdisc_sfb(self):
4003 copy_network_unit('25-qdisc-sfb.network', '12-dummy.netdev')
4004 start_networkd()
4005 self.wait_online(['dummy98:routable'])
4006
4007 output = check_output('tc qdisc show dev dummy98')
4008 print(output)
4009 self.assertRegex(output, 'qdisc sfb 39: root')
4010 self.assertRegex(output, 'limit 200000')
4011
4012 @expectedFailureIfModuleIsNotAvailable('sch_sfq')
4013 def test_qdisc_sfq(self):
4014 copy_network_unit('25-qdisc-sfq.network', '12-dummy.netdev')
4015 start_networkd()
4016 self.wait_online(['dummy98:routable'])
4017
4018 output = check_output('tc qdisc show dev dummy98')
4019 print(output)
4020 self.assertRegex(output, 'qdisc sfq 36: root')
4021 self.assertRegex(output, 'perturb 5sec')
4022
4023 @expectedFailureIfModuleIsNotAvailable('sch_tbf')
4024 def test_qdisc_tbf(self):
4025 copy_network_unit('25-qdisc-tbf.network', '12-dummy.netdev')
4026 start_networkd()
4027 self.wait_online(['dummy98:routable'])
4028
4029 output = check_output('tc qdisc show dev dummy98')
4030 print(output)
4031 self.assertRegex(output, 'qdisc tbf 35: root')
4032 self.assertRegex(output, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms')
4033
4034 @expectedFailureIfModuleIsNotAvailable('sch_teql')
4035 def test_qdisc_teql(self):
4036 call_quiet('rmmod sch_teql')
4037
4038 copy_network_unit('25-qdisc-teql.network', '12-dummy.netdev')
4039 start_networkd()
4040 self.wait_links('dummy98')
4041 check_output('modprobe sch_teql max_equalizers=2')
4042 self.wait_online(['dummy98:routable'])
4043
4044 output = check_output('tc qdisc show dev dummy98')
4045 print(output)
4046 self.assertRegex(output, 'qdisc teql1 31: root')
4047
4048 class NetworkdStateFileTests(unittest.TestCase, Utilities):
4049
4050 def setUp(self):
4051 setup_common()
4052
4053 def tearDown(self):
4054 tear_down_common()
4055
4056 def test_state_file(self):
4057 copy_network_unit('12-dummy.netdev', '25-state-file-tests.network')
4058 start_networkd()
4059 self.wait_online(['dummy98:routable'])
4060
4061 # make link state file updated
4062 check_output(*resolvectl_cmd, 'revert', 'dummy98', env=env)
4063
4064 output = check_output(*networkctl_cmd, '--json=short', 'status', env=env)
4065 check_json(output)
4066
4067 output = read_link_state_file('dummy98')
4068 print(output)
4069 self.assertIn('IPV4_ADDRESS_STATE=routable', output)
4070 self.assertIn('IPV6_ADDRESS_STATE=routable', output)
4071 self.assertIn('ADMIN_STATE=configured', output)
4072 self.assertIn('OPER_STATE=routable', output)
4073 self.assertIn('REQUIRED_FOR_ONLINE=yes', output)
4074 self.assertIn('REQUIRED_OPER_STATE_FOR_ONLINE=routable', output)
4075 self.assertIn('REQUIRED_FAMILY_FOR_ONLINE=both', output)
4076 self.assertIn('ACTIVATION_POLICY=up', output)
4077 self.assertIn('NETWORK_FILE=/run/systemd/network/25-state-file-tests.network', output)
4078 self.assertIn('DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com', output)
4079 self.assertIn('NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org', output)
4080 self.assertIn('DOMAINS=hogehoge', output)
4081 self.assertIn('ROUTE_DOMAINS=foofoo', output)
4082 self.assertIn('LLMNR=no', output)
4083 self.assertIn('MDNS=yes', output)
4084 self.assertIn('DNSSEC=no', output)
4085
4086 check_output(*resolvectl_cmd, 'dns', 'dummy98', '10.10.10.12#ccc.com', '10.10.10.13', '1111:2222::3333', env=env)
4087 check_output(*resolvectl_cmd, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env=env)
4088 check_output(*resolvectl_cmd, 'llmnr', 'dummy98', 'yes', env=env)
4089 check_output(*resolvectl_cmd, 'mdns', 'dummy98', 'no', env=env)
4090 check_output(*resolvectl_cmd, 'dnssec', 'dummy98', 'yes', env=env)
4091 check_output(*timedatectl_cmd, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env=env)
4092
4093 output = check_output(*networkctl_cmd, '--json=short', 'status', env=env)
4094 check_json(output)
4095
4096 output = read_link_state_file('dummy98')
4097 print(output)
4098 self.assertIn('DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333', output)
4099 self.assertIn('NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org', output)
4100 self.assertIn('DOMAINS=hogehogehoge', output)
4101 self.assertIn('ROUTE_DOMAINS=foofoofoo', output)
4102 self.assertIn('LLMNR=yes', output)
4103 self.assertIn('MDNS=no', output)
4104 self.assertIn('DNSSEC=yes', output)
4105
4106 check_output(*timedatectl_cmd, 'revert', 'dummy98', env=env)
4107
4108 output = check_output(*networkctl_cmd, '--json=short', 'status', env=env)
4109 check_json(output)
4110
4111 output = read_link_state_file('dummy98')
4112 print(output)
4113 self.assertIn('DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333', output)
4114 self.assertIn('NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org', output)
4115 self.assertIn('DOMAINS=hogehogehoge', output)
4116 self.assertIn('ROUTE_DOMAINS=foofoofoo', output)
4117 self.assertIn('LLMNR=yes', output)
4118 self.assertIn('MDNS=no', output)
4119 self.assertIn('DNSSEC=yes', output)
4120
4121 check_output(*resolvectl_cmd, 'revert', 'dummy98', env=env)
4122
4123 output = check_output(*networkctl_cmd, '--json=short', 'status', env=env)
4124 check_json(output)
4125
4126 output = read_link_state_file('dummy98')
4127 print(output)
4128 self.assertIn('DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com', output)
4129 self.assertIn('NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org', output)
4130 self.assertIn('DOMAINS=hogehoge', output)
4131 self.assertIn('ROUTE_DOMAINS=foofoo', output)
4132 self.assertIn('LLMNR=no', output)
4133 self.assertIn('MDNS=yes', output)
4134 self.assertIn('DNSSEC=no', output)
4135
4136 def test_address_state(self):
4137 copy_network_unit('12-dummy.netdev', '12-dummy-no-address.network')
4138 start_networkd()
4139
4140 self.wait_online(['dummy98:degraded'])
4141
4142 output = read_link_state_file('dummy98')
4143 self.assertIn('IPV4_ADDRESS_STATE=off', output)
4144 self.assertIn('IPV6_ADDRESS_STATE=degraded', output)
4145
4146 # with a routable IPv4 address
4147 check_output('ip address add 10.1.2.3/16 dev dummy98')
4148 self.wait_online(['dummy98:routable'], ipv4=True)
4149 self.wait_online(['dummy98:routable'])
4150
4151 output = read_link_state_file('dummy98')
4152 self.assertIn('IPV4_ADDRESS_STATE=routable', output)
4153 self.assertIn('IPV6_ADDRESS_STATE=degraded', output)
4154
4155 check_output('ip address del 10.1.2.3/16 dev dummy98')
4156
4157 # with a routable IPv6 address
4158 check_output('ip address add 2002:da8:1:0:1034:56ff:fe78:9abc/64 dev dummy98')
4159 self.wait_online(['dummy98:routable'], ipv6=True)
4160 self.wait_online(['dummy98:routable'])
4161
4162 output = read_link_state_file('dummy98')
4163 self.assertIn('IPV4_ADDRESS_STATE=off', output)
4164 self.assertIn('IPV6_ADDRESS_STATE=routable', output)
4165
4166 class NetworkdBondTests(unittest.TestCase, Utilities):
4167
4168 def setUp(self):
4169 setup_common()
4170
4171 def tearDown(self):
4172 tear_down_common()
4173
4174 def test_bond_keep_master(self):
4175 check_output('ip link add bond199 type bond mode active-backup')
4176 check_output('ip link add dummy98 type dummy')
4177 check_output('ip link set dummy98 master bond199')
4178
4179 copy_network_unit('23-keep-master.network')
4180 start_networkd()
4181 self.wait_online(['dummy98:enslaved'])
4182
4183 output = check_output('ip -d link show bond199')
4184 print(output)
4185 self.assertRegex(output, 'active_slave dummy98')
4186
4187 output = check_output('ip -d link show dummy98')
4188 print(output)
4189 self.assertRegex(output, 'master bond199')
4190
4191 def test_bond_active_slave(self):
4192 copy_network_unit('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
4193 start_networkd()
4194 self.wait_online(['dummy98:enslaved', 'bond199:degraded'])
4195
4196 output = check_output('ip -d link show bond199')
4197 print(output)
4198 self.assertIn('active_slave dummy98', output)
4199
4200 def test_bond_primary_slave(self):
4201 copy_network_unit('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
4202 start_networkd()
4203 self.wait_online(['dummy98:enslaved', 'bond199:degraded'])
4204
4205 output = check_output('ip -d link show bond199')
4206 print(output)
4207 self.assertIn('primary dummy98', output)
4208
4209 # for issue #25627
4210 mkdir_p(os.path.join(network_unit_dir, '23-bond199.network.d'))
4211 for mac in ['00:11:22:33:44:55', '00:11:22:33:44:56']:
4212 with open(os.path.join(network_unit_dir, '23-bond199.network.d/mac.conf'), mode='w', encoding='utf-8') as f:
4213 f.write(f'[Link]\nMACAddress={mac}\n')
4214
4215 networkctl_reload()
4216 self.wait_online(['dummy98:enslaved', 'bond199:degraded'])
4217
4218 output = check_output('ip -d link show bond199')
4219 print(output)
4220 self.assertIn(f'link/ether {mac}', output)
4221
4222 def test_bond_operstate(self):
4223 copy_network_unit('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
4224 '25-bond99.network', '25-bond-slave.network')
4225 start_networkd()
4226 self.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
4227
4228 output = check_output('ip -d link show dummy98')
4229 print(output)
4230 self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
4231
4232 output = check_output('ip -d link show test1')
4233 print(output)
4234 self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
4235
4236 output = check_output('ip -d link show bond99')
4237 print(output)
4238 self.assertRegex(output, 'MASTER,UP,LOWER_UP')
4239
4240 self.wait_operstate('dummy98', 'enslaved')
4241 self.wait_operstate('test1', 'enslaved')
4242 self.wait_operstate('bond99', 'routable')
4243
4244 check_output('ip link set dummy98 down')
4245
4246 self.wait_operstate('dummy98', 'off')
4247 self.wait_operstate('test1', 'enslaved')
4248 self.wait_operstate('bond99', 'routable')
4249
4250 check_output('ip link set dummy98 up')
4251
4252 self.wait_operstate('dummy98', 'enslaved')
4253 self.wait_operstate('test1', 'enslaved')
4254 self.wait_operstate('bond99', 'routable')
4255
4256 check_output('ip link set dummy98 down')
4257 check_output('ip link set test1 down')
4258
4259 self.wait_operstate('dummy98', 'off')
4260 self.wait_operstate('test1', 'off')
4261
4262 if not self.wait_operstate('bond99', 'no-carrier', setup_timeout=30, fail_assert=False):
4263 # Huh? Kernel does not recognize that all slave interfaces are down?
4264 # Let's confirm that networkd's operstate is consistent with ip's result.
4265 self.assertNotRegex(output, 'NO-CARRIER')
4266
4267 class NetworkdBridgeTests(unittest.TestCase, Utilities):
4268
4269 def setUp(self):
4270 setup_common()
4271
4272 def tearDown(self):
4273 tear_down_common()
4274
4275 def test_bridge_vlan(self):
4276 copy_network_unit('11-dummy.netdev', '26-bridge-vlan-slave.network',
4277 '26-bridge.netdev', '26-bridge-vlan-master.network')
4278 start_networkd()
4279 self.wait_online(['test1:enslaved', 'bridge99:degraded'])
4280
4281 output = check_output('bridge vlan show dev test1')
4282 print(output)
4283 self.assertNotRegex(output, '4063')
4284 for i in range(4064, 4095):
4285 self.assertRegex(output, f'{i}')
4286 self.assertNotRegex(output, '4095')
4287
4288 output = check_output('bridge vlan show dev bridge99')
4289 print(output)
4290 self.assertNotRegex(output, '4059')
4291 for i in range(4060, 4095):
4292 self.assertRegex(output, f'{i}')
4293 self.assertNotRegex(output, '4095')
4294
4295 def test_bridge_vlan_issue_20373(self):
4296 copy_network_unit('11-dummy.netdev', '26-bridge-vlan-slave-issue-20373.network',
4297 '26-bridge-issue-20373.netdev', '26-bridge-vlan-master-issue-20373.network',
4298 '21-vlan.netdev', '21-vlan.network')
4299 start_networkd()
4300 self.wait_online(['test1:enslaved', 'bridge99:degraded', 'vlan99:routable'])
4301
4302 output = check_output('bridge vlan show dev test1')
4303 print(output)
4304 self.assertIn('100 PVID Egress Untagged', output)
4305 self.assertIn('560', output)
4306 self.assertIn('600', output)
4307
4308 output = check_output('bridge vlan show dev bridge99')
4309 print(output)
4310 self.assertIn('1 PVID Egress Untagged', output)
4311 self.assertIn('100', output)
4312 self.assertIn('600', output)
4313
4314 def test_bridge_mdb(self):
4315 copy_network_unit('11-dummy.netdev', '26-bridge-mdb-slave.network',
4316 '26-bridge.netdev', '26-bridge-mdb-master.network')
4317 start_networkd()
4318 self.wait_online(['test1:enslaved', 'bridge99:degraded'])
4319
4320 output = check_output('bridge mdb show dev bridge99')
4321 print(output)
4322 self.assertRegex(output, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064')
4323 self.assertRegex(output, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065')
4324
4325 # Old kernel may not support bridge MDB entries on bridge master
4326 if call_quiet('bridge mdb add dev bridge99 port bridge99 grp 224.0.1.3 temp vid 4068') == 0:
4327 self.assertRegex(output, 'dev bridge99 port bridge99 grp ff02:aaaa:fee5::1:4 temp *vid 4066')
4328 self.assertRegex(output, 'dev bridge99 port bridge99 grp 224.0.1.2 temp *vid 4067')
4329
4330 def test_bridge_keep_master(self):
4331 check_output('ip link add bridge99 type bridge')
4332 check_output('ip link set bridge99 up')
4333 check_output('ip link add dummy98 type dummy')
4334 check_output('ip link set dummy98 master bridge99')
4335
4336 copy_network_unit('23-keep-master.network')
4337 start_networkd()
4338 self.wait_online(['dummy98:enslaved'])
4339
4340 output = check_output('ip -d link show dummy98')
4341 print(output)
4342 self.assertRegex(output, 'master bridge99')
4343 self.assertRegex(output, 'bridge')
4344
4345 output = check_output('bridge -d link show dummy98')
4346 print(output)
4347 self.check_bridge_port_attr('bridge99', 'dummy98', 'path_cost', '400')
4348 self.check_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode', '1')
4349 self.check_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave', '1')
4350 self.check_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood', '1')
4351 self.check_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood', '0')
4352 # CONFIG_BRIDGE_IGMP_SNOOPING=y
4353 self.check_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast', '1', allow_enoent=True)
4354 self.check_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress', '1', allow_enoent=True)
4355 self.check_bridge_port_attr('bridge99', 'dummy98', 'learning', '0')
4356 self.check_bridge_port_attr('bridge99', 'dummy98', 'priority', '23')
4357 self.check_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard', '0')
4358 self.check_bridge_port_attr('bridge99', 'dummy98', 'root_block', '0')
4359
4360 def test_bridge_property(self):
4361 copy_network_unit('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
4362 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
4363 '25-bridge99.network')
4364 start_networkd()
4365 self.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
4366
4367 output = check_output('ip -d link show bridge99')
4368 print(output)
4369 self.assertIn('mtu 9000 ', output)
4370
4371 output = check_output('ip -d link show test1')
4372 print(output)
4373 self.assertIn('master bridge99 ', output)
4374 self.assertIn('bridge_slave', output)
4375 self.assertIn('mtu 9000 ', output)
4376
4377 output = check_output('ip -d link show dummy98')
4378 print(output)
4379 self.assertIn('master bridge99 ', output)
4380 self.assertIn('bridge_slave', output)
4381 self.assertIn('mtu 9000 ', output)
4382
4383 output = check_output('ip addr show bridge99')
4384 print(output)
4385 self.assertIn('192.168.0.15/24', output)
4386
4387 output = check_output('bridge -d link show dummy98')
4388 print(output)
4389 self.check_bridge_port_attr('bridge99', 'dummy98', 'path_cost', '400')
4390 self.check_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode', '1')
4391 self.check_bridge_port_attr('bridge99', 'dummy98', 'isolated', '1')
4392 self.check_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave', '1')
4393 self.check_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood', '1')
4394 self.check_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood', '0')
4395 # CONFIG_BRIDGE_IGMP_SNOOPING=y
4396 self.check_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast', '1', allow_enoent=True)
4397 self.check_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress', '1', allow_enoent=True)
4398 self.check_bridge_port_attr('bridge99', 'dummy98', 'learning', '0')
4399 self.check_bridge_port_attr('bridge99', 'dummy98', 'priority', '23')
4400 self.check_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard', '0')
4401 self.check_bridge_port_attr('bridge99', 'dummy98', 'root_block', '0')
4402
4403 output = check_output('bridge -d link show test1')
4404 print(output)
4405 self.check_bridge_port_attr('bridge99', 'test1', 'priority', '0')
4406
4407 check_output('ip address add 192.168.0.16/24 dev bridge99')
4408 output = check_output('ip addr show bridge99')
4409 print(output)
4410 self.assertIn('192.168.0.16/24', output)
4411
4412 # for issue #6088
4413 print('### ip -6 route list table all dev bridge99')
4414 output = check_output('ip -6 route list table all dev bridge99')
4415 print(output)
4416 self.assertRegex(output, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
4417
4418 remove_link('test1')
4419 self.wait_operstate('bridge99', 'routable')
4420
4421 output = check_output('ip -d link show bridge99')
4422 print(output)
4423 self.assertIn('mtu 9000 ', output)
4424
4425 output = check_output('ip -d link show dummy98')
4426 print(output)
4427 self.assertIn('master bridge99 ', output)
4428 self.assertIn('bridge_slave', output)
4429 self.assertIn('mtu 9000 ', output)
4430
4431 remove_link('dummy98')
4432 self.wait_operstate('bridge99', 'no-carrier')
4433
4434 output = check_output('ip -d link show bridge99')
4435 print(output)
4436 # When no carrier, the kernel may reset the MTU
4437 self.assertIn('NO-CARRIER', output)
4438
4439 output = check_output('ip address show bridge99')
4440 print(output)
4441 self.assertNotIn('192.168.0.15/24', output)
4442 self.assertIn('192.168.0.16/24', output) # foreign address is kept
4443
4444 print('### ip -6 route list table all dev bridge99')
4445 output = check_output('ip -6 route list table all dev bridge99')
4446 print(output)
4447 self.assertRegex(output, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
4448
4449 check_output('ip link add dummy98 type dummy')
4450 self.wait_online(['dummy98:enslaved', 'bridge99:routable'])
4451
4452 output = check_output('ip -d link show bridge99')
4453 print(output)
4454 self.assertIn('mtu 9000 ', output)
4455
4456 output = check_output('ip -d link show dummy98')
4457 print(output)
4458 self.assertIn('master bridge99 ', output)
4459 self.assertIn('bridge_slave', output)
4460 self.assertIn('mtu 9000 ', output)
4461
4462 def test_bridge_configure_without_carrier(self):
4463 copy_network_unit('26-bridge.netdev', '26-bridge-configure-without-carrier.network',
4464 '11-dummy.netdev')
4465 start_networkd()
4466
4467 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
4468 for test in ['no-slave', 'add-slave', 'slave-up', 'slave-no-carrier', 'slave-carrier', 'slave-down']:
4469 with self.subTest(test=test):
4470 if test == 'no-slave':
4471 # bridge has no slaves; it's up but *might* not have carrier
4472 self.wait_operstate('bridge99', operstate=r'(no-carrier|routable)', setup_state=None, setup_timeout=30)
4473 # due to a bug in the kernel, newly-created bridges are brought up
4474 # *with* carrier, unless they have had any setting changed; e.g.
4475 # their mac set, priority set, etc. Then, they will lose carrier
4476 # as soon as a (down) slave interface is added, and regain carrier
4477 # again once the slave interface is brought up.
4478 #self.check_link_attr('bridge99', 'carrier', '0')
4479 elif test == 'add-slave':
4480 # add slave to bridge, but leave it down; bridge is definitely no-carrier
4481 self.check_link_attr('test1', 'operstate', 'down')
4482 check_output('ip link set dev test1 master bridge99')
4483 self.wait_operstate('bridge99', operstate='no-carrier', setup_state=None)
4484 self.check_link_attr('bridge99', 'carrier', '0')
4485 elif test == 'slave-up':
4486 # bring up slave, which will have carrier; bridge gains carrier
4487 check_output('ip link set dev test1 up')
4488 self.wait_online(['bridge99:routable'])
4489 self.check_link_attr('bridge99', 'carrier', '1')
4490 elif test == 'slave-no-carrier':
4491 # drop slave carrier; bridge loses carrier
4492 check_output('ip link set dev test1 carrier off')
4493 self.wait_online(['bridge99:no-carrier:no-carrier'])
4494 self.check_link_attr('bridge99', 'carrier', '0')
4495 elif test == 'slave-carrier':
4496 # restore slave carrier; bridge gains carrier
4497 check_output('ip link set dev test1 carrier on')
4498 self.wait_online(['bridge99:routable'])
4499 self.check_link_attr('bridge99', 'carrier', '1')
4500 elif test == 'slave-down':
4501 # bring down slave; bridge loses carrier
4502 check_output('ip link set dev test1 down')
4503 self.wait_online(['bridge99:no-carrier:no-carrier'])
4504 self.check_link_attr('bridge99', 'carrier', '0')
4505
4506 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'bridge99', env=env)
4507 self.assertRegex(output, '10.1.2.3')
4508 self.assertRegex(output, '10.1.2.1')
4509
4510 def test_bridge_ignore_carrier_loss(self):
4511 copy_network_unit('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
4512 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
4513 '25-bridge99-ignore-carrier-loss.network')
4514 start_networkd()
4515 self.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
4516
4517 check_output('ip address add 192.168.0.16/24 dev bridge99')
4518 remove_link('test1', 'dummy98')
4519 time.sleep(3)
4520
4521 output = check_output('ip address show bridge99')
4522 print(output)
4523 self.assertRegex(output, 'NO-CARRIER')
4524 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
4525 self.assertRegex(output, 'inet 192.168.0.16/24 scope global secondary bridge99')
4526
4527 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self):
4528 copy_network_unit('26-bridge.netdev', '26-bridge-slave-interface-1.network',
4529 '25-bridge99-ignore-carrier-loss.network')
4530 start_networkd()
4531 self.wait_online(['bridge99:no-carrier'])
4532
4533 for trial in range(4):
4534 check_output('ip link add dummy98 type dummy')
4535 check_output('ip link set dummy98 up')
4536 if trial < 3:
4537 remove_link('dummy98')
4538
4539 self.wait_online(['bridge99:routable', 'dummy98:enslaved'])
4540
4541 output = check_output('ip address show bridge99')
4542 print(output)
4543 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
4544
4545 output = check_output('ip rule list table 100')
4546 print(output)
4547 self.assertIn('from all to 8.8.8.8 lookup 100', output)
4548
4549 class NetworkdSRIOVTests(unittest.TestCase, Utilities):
4550
4551 def setUp(self):
4552 setup_common()
4553
4554 def tearDown(self):
4555 tear_down_common()
4556
4557 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable()
4558 def test_sriov(self):
4559 copy_network_unit('25-default.link', '25-sriov.network')
4560
4561 call('modprobe netdevsim')
4562
4563 with open('/sys/bus/netdevsim/new_device', mode='w', encoding='utf-8') as f:
4564 f.write('99 1')
4565
4566 with open('/sys/bus/netdevsim/devices/netdevsim99/sriov_numvfs', mode='w', encoding='utf-8') as f:
4567 f.write('3')
4568
4569 start_networkd()
4570 self.wait_online(['eni99np1:routable'])
4571
4572 output = check_output('ip link show dev eni99np1')
4573 print(output)
4574 self.assertRegex(output,
4575 '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 *'
4576 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
4577 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4578 )
4579
4580 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable()
4581 def test_sriov_udev(self):
4582 copy_network_unit('25-sriov.link', '25-sriov-udev.network')
4583
4584 call('modprobe netdevsim')
4585
4586 with open('/sys/bus/netdevsim/new_device', mode='w', encoding='utf-8') as f:
4587 f.write('99 1')
4588
4589 start_networkd()
4590 self.wait_online(['eni99np1:routable'])
4591
4592 # the name eni99np1 may be an alternative name.
4593 ifname = link_resolve('eni99np1')
4594
4595 output = check_output('ip link show dev eni99np1')
4596 print(output)
4597 self.assertRegex(output,
4598 '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 *'
4599 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
4600 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4601 )
4602 self.assertNotIn('vf 3', output)
4603 self.assertNotIn('vf 4', output)
4604
4605 with open(os.path.join(network_unit_dir, '25-sriov.link'), mode='a', encoding='utf-8') as f:
4606 f.write('[Link]\nSR-IOVVirtualFunctions=4\n')
4607
4608 udev_reload()
4609 check_output(*udevadm_cmd, 'trigger', '--action=add', '--settle', f'/sys/devices/netdevsim99/net/{ifname}')
4610
4611 output = check_output('ip link show dev eni99np1')
4612 print(output)
4613 self.assertRegex(output,
4614 '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 *'
4615 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
4616 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off\n *'
4617 'vf 3'
4618 )
4619 self.assertNotIn('vf 4', output)
4620
4621 with open(os.path.join(network_unit_dir, '25-sriov.link'), mode='a', encoding='utf-8') as f:
4622 f.write('[Link]\nSR-IOVVirtualFunctions=\n')
4623
4624 udev_reload()
4625 check_output(*udevadm_cmd, 'trigger', '--action=add', '--settle', f'/sys/devices/netdevsim99/net/{ifname}')
4626
4627 output = check_output('ip link show dev eni99np1')
4628 print(output)
4629 self.assertRegex(output,
4630 '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 *'
4631 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
4632 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off\n *'
4633 'vf 3'
4634 )
4635 self.assertNotIn('vf 4', output)
4636
4637 with open(os.path.join(network_unit_dir, '25-sriov.link'), mode='a', encoding='utf-8') as f:
4638 f.write('[Link]\nSR-IOVVirtualFunctions=2\n')
4639
4640 udev_reload()
4641 check_output(*udevadm_cmd, 'trigger', '--action=add', '--settle', f'/sys/devices/netdevsim99/net/{ifname}')
4642
4643 output = check_output('ip link show dev eni99np1')
4644 print(output)
4645 self.assertRegex(output,
4646 '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 *'
4647 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off'
4648 )
4649 self.assertNotIn('vf 2', output)
4650 self.assertNotIn('vf 3', output)
4651 self.assertNotIn('vf 4', output)
4652
4653 with open(os.path.join(network_unit_dir, '25-sriov.link'), mode='a', encoding='utf-8') as f:
4654 f.write('[Link]\nSR-IOVVirtualFunctions=\n')
4655
4656 udev_reload()
4657 check_output(*udevadm_cmd, 'trigger', '--action=add', '--settle', f'/sys/devices/netdevsim99/net/{ifname}')
4658
4659 output = check_output('ip link show dev eni99np1')
4660 print(output)
4661 self.assertRegex(output,
4662 '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 *'
4663 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
4664 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
4665 )
4666 self.assertNotIn('vf 3', output)
4667 self.assertNotIn('vf 4', output)
4668
4669 class NetworkdLLDPTests(unittest.TestCase, Utilities):
4670
4671 def setUp(self):
4672 setup_common()
4673
4674 def tearDown(self):
4675 tear_down_common()
4676
4677 def test_lldp(self):
4678 copy_network_unit('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
4679 start_networkd()
4680 self.wait_online(['veth99:degraded', 'veth-peer:degraded'])
4681
4682 for trial in range(10):
4683 if trial > 0:
4684 time.sleep(1)
4685
4686 output = check_output(*networkctl_cmd, 'lldp', env=env)
4687 print(output)
4688 if re.search(r'veth99 .* veth-peer', output):
4689 break
4690 else:
4691 self.fail()
4692
4693 class NetworkdRATests(unittest.TestCase, Utilities):
4694
4695 def setUp(self):
4696 setup_common()
4697
4698 def tearDown(self):
4699 tear_down_common()
4700
4701 def test_ipv6_prefix_delegation(self):
4702 copy_network_unit('25-veth.netdev', '25-ipv6-prefix.network', '25-ipv6-prefix-veth.network')
4703 start_networkd()
4704 self.wait_online(['veth99:routable', 'veth-peer:degraded'])
4705
4706 output = check_output(*resolvectl_cmd, 'dns', 'veth99', env=env)
4707 print(output)
4708 self.assertRegex(output, 'fe80::')
4709 self.assertRegex(output, '2002:da8:1::1')
4710
4711 output = check_output(*resolvectl_cmd, 'domain', 'veth99', env=env)
4712 print(output)
4713 self.assertIn('hogehoge.test', output)
4714
4715 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
4716 print(output)
4717 self.assertRegex(output, '2002:da8:1:0')
4718
4719 self.check_netlabel('veth99', '2002:da8:1::/64')
4720 self.check_netlabel('veth99', '2002:da8:2::/64')
4721
4722 def test_ipv6_token_static(self):
4723 copy_network_unit('25-veth.netdev', '25-ipv6-prefix.network', '25-ipv6-prefix-veth-token-static.network')
4724 start_networkd()
4725 self.wait_online(['veth99:routable', 'veth-peer:degraded'])
4726
4727 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
4728 print(output)
4729 self.assertRegex(output, '2002:da8:1:0:1a:2b:3c:4d')
4730 self.assertRegex(output, '2002:da8:1:0:fa:de:ca:fe')
4731 self.assertRegex(output, '2002:da8:2:0:1a:2b:3c:4d')
4732 self.assertRegex(output, '2002:da8:2:0:fa:de:ca:fe')
4733
4734 def test_ipv6_token_prefixstable(self):
4735 copy_network_unit('25-veth.netdev', '25-ipv6-prefix.network', '25-ipv6-prefix-veth-token-prefixstable.network')
4736 start_networkd()
4737 self.wait_online(['veth99:routable', 'veth-peer:degraded'])
4738
4739 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
4740 print(output)
4741 self.assertIn('2002:da8:1:0:b47e:7975:fc7a:7d6e', output)
4742 self.assertIn('2002:da8:2:0:1034:56ff:fe78:9abc', output) # EUI64
4743
4744 def test_ipv6_token_prefixstable_without_address(self):
4745 copy_network_unit('25-veth.netdev', '25-ipv6-prefix.network', '25-ipv6-prefix-veth-token-prefixstable-without-address.network')
4746 start_networkd()
4747 self.wait_online(['veth99:routable', 'veth-peer:degraded'])
4748
4749 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
4750 print(output)
4751 self.assertIn('2002:da8:1:0:b47e:7975:fc7a:7d6e', output)
4752 self.assertIn('2002:da8:2:0:f689:561a:8eda:7443', output)
4753
4754 def test_router_preference(self):
4755 copy_network_unit('25-veth-client.netdev',
4756 '25-veth-router-high.netdev',
4757 '25-veth-router-low.netdev',
4758 '26-bridge.netdev',
4759 '25-veth-bridge.network',
4760 '25-veth-client.network',
4761 '25-veth-router-high.network',
4762 '25-veth-router-low.network',
4763 '25-bridge99.network')
4764 start_networkd()
4765 self.wait_online(['client-p:enslaved',
4766 'router-high:degraded', 'router-high-p:enslaved',
4767 'router-low:degraded', 'router-low-p:enslaved',
4768 'bridge99:routable'])
4769
4770 networkctl_reconfigure('client')
4771 self.wait_online(['client:routable'])
4772
4773 self.wait_address('client', '2002:da8:1:99:1034:56ff:fe78:9a00/64', ipv='-6', timeout_sec=10)
4774 self.wait_address('client', '2002:da8:1:98:1034:56ff:fe78:9a00/64', ipv='-6', timeout_sec=10)
4775 self.wait_route('client', 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 512', ipv='-6', timeout_sec=10)
4776 self.wait_route('client', 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 2048', ipv='-6', timeout_sec=10)
4777
4778 output = check_output('ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99')
4779 print(output)
4780 self.assertIn('pref high', output)
4781 output = check_output('ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98')
4782 print(output)
4783 self.assertIn('pref low', output)
4784
4785 with open(os.path.join(network_unit_dir, '25-veth-client.network'), mode='a', encoding='utf-8') as f:
4786 f.write('\n[Link]\nMACAddress=12:34:56:78:9a:01\n[IPv6AcceptRA]\nRouteMetric=100:200:300\n')
4787
4788 networkctl_reload()
4789 self.wait_online(['client:routable'])
4790
4791 self.wait_address('client', '2002:da8:1:99:1034:56ff:fe78:9a01/64', ipv='-6', timeout_sec=10)
4792 self.wait_address('client', '2002:da8:1:98:1034:56ff:fe78:9a01/64', ipv='-6', timeout_sec=10)
4793 self.wait_route('client', 'default via fe80::1034:56ff:fe78:9a99 proto ra metric 100', ipv='-6', timeout_sec=10)
4794 self.wait_route('client', 'default via fe80::1034:56ff:fe78:9a98 proto ra metric 300', ipv='-6', timeout_sec=10)
4795
4796 output = check_output('ip -6 route show dev client default via fe80::1034:56ff:fe78:9a99')
4797 print(output)
4798 self.assertIn('pref high', output)
4799 output = check_output('ip -6 route show dev client default via fe80::1034:56ff:fe78:9a98')
4800 print(output)
4801 self.assertIn('pref low', output)
4802
4803 @unittest.skipUnless(radvd_check_config('captive-portal.conf'), "Installed radvd doesn't support captive portals")
4804 def test_captive_portal(self):
4805 copy_network_unit('25-veth-client.netdev',
4806 '25-veth-router-captive.netdev',
4807 '26-bridge.netdev',
4808 '25-veth-client-captive.network',
4809 '25-veth-router-captive.network',
4810 '25-veth-bridge-captive.network',
4811 '25-bridge99.network')
4812 start_networkd()
4813 self.wait_online(['bridge99:routable', 'client-p:enslaved',
4814 'router-captive:degraded', 'router-captivep:enslaved'])
4815
4816 start_radvd(config_file='captive-portal.conf')
4817 networkctl_reconfigure('client')
4818 self.wait_online(['client:routable'])
4819
4820 self.wait_address('client', '2002:da8:1:99:1034:56ff:fe78:9a00/64', ipv='-6', timeout_sec=10)
4821 output = check_output(*networkctl_cmd, 'status', 'client', env=env)
4822 print(output)
4823 self.assertIn('Captive Portal: http://systemd.io', output)
4824
4825 @unittest.skipUnless(radvd_check_config('captive-portal.conf'), "Installed radvd doesn't support captive portals")
4826 def test_invalid_captive_portal(self):
4827 def radvd_write_config(captive_portal_uri):
4828 with open(os.path.join(networkd_ci_temp_dir, 'radvd/bogus-captive-portal.conf'), mode='w', encoding='utf-8') as f:
4829 f.write(f'interface router-captive {{ AdvSendAdvert on; AdvCaptivePortalAPI "{captive_portal_uri}"; prefix 2002:da8:1:99::/64 {{ AdvOnLink on; AdvAutonomous on; }}; }};')
4830
4831 captive_portal_uris = [
4832 "42ěščěškd ěšč ě s",
4833 " ",
4834 "🤔",
4835 ]
4836
4837 copy_network_unit('25-veth-client.netdev',
4838 '25-veth-router-captive.netdev',
4839 '26-bridge.netdev',
4840 '25-veth-client-captive.network',
4841 '25-veth-router-captive.network',
4842 '25-veth-bridge-captive.network',
4843 '25-bridge99.network')
4844 start_networkd()
4845 self.wait_online(['bridge99:routable', 'client-p:enslaved',
4846 'router-captive:degraded', 'router-captivep:enslaved'])
4847
4848 for uri in captive_portal_uris:
4849 print(f"Captive portal: {uri}")
4850 radvd_write_config(uri)
4851 stop_radvd()
4852 start_radvd(config_file='bogus-captive-portal.conf')
4853 networkctl_reconfigure('client')
4854 self.wait_online(['client:routable'])
4855
4856 self.wait_address('client', '2002:da8:1:99:1034:56ff:fe78:9a00/64', ipv='-6', timeout_sec=10)
4857 output = check_output(*networkctl_cmd, 'status', 'client', env=env)
4858 print(output)
4859 self.assertNotIn('Captive Portal:', output)
4860
4861 class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
4862
4863 def setUp(self):
4864 setup_common()
4865
4866 def tearDown(self):
4867 tear_down_common()
4868
4869 def test_dhcp_server(self):
4870 copy_network_unit('25-veth.netdev', '25-dhcp-client.network', '25-dhcp-server.network')
4871 start_networkd()
4872 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4873
4874 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
4875 print(output)
4876 self.assertRegex(output, r'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)')
4877 self.assertIn('Gateway: 192.168.5.3', output)
4878 self.assertRegex(output, 'DNS: 192.168.5.1\n *192.168.5.10')
4879 self.assertRegex(output, 'NTP: 192.168.5.1\n *192.168.5.11')
4880
4881 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth-peer', env=env)
4882 self.assertRegex(output, "Offered DHCP leases: 192.168.5.[0-9]*")
4883
4884 def test_dhcp_server_with_uplink(self):
4885 copy_network_unit('25-veth.netdev', '25-dhcp-client.network', '25-dhcp-server-downstream.network',
4886 '12-dummy.netdev', '25-dhcp-server-uplink.network')
4887 start_networkd()
4888 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4889
4890 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
4891 print(output)
4892 self.assertRegex(output, r'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)')
4893 self.assertIn('Gateway: 192.168.5.3', output)
4894 self.assertIn('DNS: 192.168.5.1', output)
4895 self.assertIn('NTP: 192.168.5.1', output)
4896
4897 def test_emit_router_timezone(self):
4898 copy_network_unit('25-veth.netdev', '25-dhcp-client-timezone-router.network', '25-dhcp-server-timezone-router.network')
4899 start_networkd()
4900 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4901
4902 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
4903 print(output)
4904 self.assertRegex(output, r'Address: 192.168.5.[0-9]* \(DHCP4 via 192.168.5.1\)')
4905 self.assertIn('Gateway: 192.168.5.1', output)
4906 self.assertIn('Time Zone: Europe/Berlin', output)
4907
4908 def test_dhcp_server_static_lease(self):
4909 copy_network_unit('25-veth.netdev', '25-dhcp-client-static-lease.network', '25-dhcp-server-static-lease.network')
4910 start_networkd()
4911 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4912
4913 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
4914 print(output)
4915 self.assertIn('Address: 10.1.1.200 (DHCP4 via 10.1.1.1)', output)
4916 self.assertIn('DHCP4 Client ID: 12:34:56:78:9a:bc', output)
4917
4918 def test_dhcp_server_static_lease_default_client_id(self):
4919 copy_network_unit('25-veth.netdev', '25-dhcp-client.network', '25-dhcp-server-static-lease.network')
4920 start_networkd()
4921 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4922
4923 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
4924 print(output)
4925 self.assertIn('Address: 10.1.1.200 (DHCP4 via 10.1.1.1)', output)
4926 self.assertRegex(output, 'DHCP4 Client ID: IAID:[0-9a-z]*/DUID')
4927
4928 class NetworkdDHCPServerRelayAgentTests(unittest.TestCase, Utilities):
4929
4930 def setUp(self):
4931 setup_common()
4932
4933 def tearDown(self):
4934 tear_down_common()
4935
4936 def test_relay_agent(self):
4937 copy_network_unit('25-agent-veth-client.netdev',
4938 '25-agent-veth-server.netdev',
4939 '25-agent-client.network',
4940 '25-agent-server.network',
4941 '25-agent-client-peer.network',
4942 '25-agent-server-peer.network')
4943 start_networkd()
4944
4945 self.wait_online(['client:routable'])
4946
4947 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'client', env=env)
4948 print(output)
4949 self.assertRegex(output, r'Address: 192.168.5.150 \(DHCP4 via 192.168.5.1\)')
4950
4951 class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
4952
4953 def setUp(self):
4954 setup_common()
4955
4956 def tearDown(self):
4957 tear_down_common()
4958
4959 def test_dhcp_client_ipv6_only(self):
4960 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-ipv6-only.network')
4961
4962 start_networkd()
4963 self.wait_online(['veth-peer:carrier'])
4964 start_dnsmasq()
4965 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4966
4967 # checking address
4968 output = check_output('ip address show dev veth99 scope global')
4969 print(output)
4970 self.assertRegex(output, r'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute')
4971 self.assertNotIn('192.168.5', output)
4972
4973 # checking semi-static route
4974 output = check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
4975 print(output)
4976 self.assertRegex(output, 'via fe80::1034:56ff:fe78:9abd')
4977
4978 # Confirm that ipv6 token is not set in the kernel
4979 output = check_output('ip token show dev veth99')
4980 print(output)
4981 self.assertRegex(output, 'token :: dev veth99')
4982
4983 print('## dnsmasq log')
4984 output = read_dnsmasq_log_file()
4985 print(output)
4986 self.assertIn('DHCPSOLICIT(veth-peer)', output)
4987 self.assertNotIn('DHCPADVERTISE(veth-peer)', output)
4988 self.assertNotIn('DHCPREQUEST(veth-peer)', output)
4989 self.assertIn('DHCPREPLY(veth-peer)', output)
4990 self.assertIn('sent size: 0 option: 14 rapid-commit', output)
4991
4992 with open(os.path.join(network_unit_dir, '25-dhcp-client-ipv6-only.network'), mode='a', encoding='utf-8') as f:
4993 f.write('\n[DHCPv6]\nRapidCommit=no\n')
4994
4995 stop_dnsmasq()
4996 start_dnsmasq()
4997
4998 networkctl_reload()
4999 self.wait_online(['veth99:routable', 'veth-peer:routable'])
5000
5001 # checking address
5002 output = check_output('ip address show dev veth99 scope global')
5003 print(output)
5004 self.assertRegex(output, r'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute')
5005 self.assertNotIn('192.168.5', output)
5006
5007 # checking semi-static route
5008 output = check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
5009 print(output)
5010 self.assertRegex(output, 'via fe80::1034:56ff:fe78:9abd')
5011
5012 print('## dnsmasq log')
5013 output = read_dnsmasq_log_file()
5014 print(output)
5015 self.assertIn('DHCPSOLICIT(veth-peer)', output)
5016 self.assertIn('DHCPADVERTISE(veth-peer)', output)
5017 self.assertIn('DHCPREQUEST(veth-peer)', output)
5018 self.assertIn('DHCPREPLY(veth-peer)', output)
5019 self.assertNotIn('rapid-commit', output)
5020
5021 def test_dhcp_client_ipv4_only(self):
5022 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-ipv4-only.network')
5023
5024 start_networkd()
5025 self.wait_online(['veth-peer:carrier'])
5026 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7',
5027 '--dhcp-option=option:domain-search,example.com',
5028 '--dhcp-alternate-port=67,5555',
5029 ipv4_range='192.168.5.110,192.168.5.119')
5030 self.wait_online(['veth99:routable', 'veth-peer:routable'])
5031 self.wait_address('veth99', r'inet 192.168.5.11[0-9]*/24', ipv='-4')
5032
5033 print('## ip address show dev veth99 scope global')
5034 output = check_output('ip address show dev veth99 scope global')
5035 print(output)
5036 self.assertIn('mtu 1492', output)
5037 self.assertIn('inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99', output)
5038 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')
5039 self.assertNotIn('2600::', output)
5040
5041 print('## ip route show table main dev veth99')
5042 output = check_output('ip route show table main dev veth99')
5043 print(output)
5044 # no DHCP routes assigned to the main table
5045 self.assertNotIn('proto dhcp', output)
5046 # static routes
5047 self.assertIn('192.168.5.0/24 proto kernel scope link src 192.168.5.250', output)
5048 self.assertIn('192.168.5.0/24 proto static scope link', output)
5049 self.assertIn('192.168.6.0/24 proto static scope link', output)
5050 self.assertIn('192.168.7.0/24 proto static scope link', output)
5051
5052 print('## ip route show table 211 dev veth99')
5053 output = check_output('ip route show table 211 dev veth99')
5054 print(output)
5055 self.assertRegex(output, 'default via 192.168.5.1 proto dhcp src 192.168.5.11[0-9] metric 24')
5056 self.assertRegex(output, '192.168.5.0/24 proto dhcp scope link src 192.168.5.11[0-9] metric 24')
5057 self.assertRegex(output, '192.168.5.1 proto dhcp scope link src 192.168.5.11[0-9] metric 24')
5058 self.assertRegex(output, '192.168.5.6 proto dhcp scope link src 192.168.5.11[0-9] metric 24')
5059 self.assertRegex(output, '192.168.5.7 proto dhcp scope link src 192.168.5.11[0-9] metric 24')
5060 self.assertIn('10.0.0.0/8 via 192.168.5.1 proto dhcp', output)
5061
5062 print('## link state file')
5063 output = read_link_state_file('veth99')
5064 print(output)
5065 # checking DNS server and Domains
5066 self.assertIn('DNS=192.168.5.6 192.168.5.7', output)
5067 self.assertIn('DOMAINS=example.com', output)
5068
5069 print('## dnsmasq log')
5070 output = read_dnsmasq_log_file()
5071 print(output)
5072 self.assertIn('vendor class: FooBarVendorTest', output)
5073 self.assertIn('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc', output)
5074 self.assertIn('client provides name: test-hostname', output)
5075 self.assertIn('26:mtu', output)
5076
5077 # change address range, DNS servers, and Domains
5078 stop_dnsmasq()
5079 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8',
5080 '--dhcp-option=option:domain-search,foo.example.com',
5081 '--dhcp-alternate-port=67,5555',
5082 ipv4_range='192.168.5.120,192.168.5.129',)
5083
5084 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
5085 print('Wait for the DHCP lease to be expired')
5086 self.wait_address_dropped('veth99', r'inet 192.168.5.11[0-9]*/24', ipv='-4', timeout_sec=120)
5087 self.wait_address('veth99', r'inet 192.168.5.12[0-9]*/24', ipv='-4')
5088
5089 self.wait_online(['veth99:routable', 'veth-peer:routable'])
5090
5091 print('## ip address show dev veth99 scope global')
5092 output = check_output('ip address show dev veth99 scope global')
5093 print(output)
5094 self.assertIn('mtu 1492', output)
5095 self.assertIn('inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99', output)
5096 self.assertNotIn('192.168.5.11', output)
5097 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')
5098 self.assertNotIn('2600::', output)
5099
5100 print('## ip route show table main dev veth99')
5101 output = check_output('ip route show table main dev veth99')
5102 print(output)
5103 # no DHCP routes assigned to the main table
5104 self.assertNotIn('proto dhcp', output)
5105 # static routes
5106 self.assertIn('192.168.5.0/24 proto kernel scope link src 192.168.5.250', output)
5107 self.assertIn('192.168.5.0/24 proto static scope link', output)
5108 self.assertIn('192.168.6.0/24 proto static scope link', output)
5109 self.assertIn('192.168.7.0/24 proto static scope link', output)
5110
5111 print('## ip route show table 211 dev veth99')
5112 output = check_output('ip route show table 211 dev veth99')
5113 print(output)
5114 self.assertRegex(output, 'default via 192.168.5.1 proto dhcp src 192.168.5.12[0-9] metric 24')
5115 self.assertRegex(output, '192.168.5.0/24 proto dhcp scope link src 192.168.5.12[0-9] metric 24')
5116 self.assertRegex(output, '192.168.5.1 proto dhcp scope link src 192.168.5.12[0-9] metric 24')
5117 self.assertNotIn('192.168.5.6', output)
5118 self.assertRegex(output, '192.168.5.7 proto dhcp scope link src 192.168.5.12[0-9] metric 24')
5119 self.assertRegex(output, '192.168.5.8 proto dhcp scope link src 192.168.5.12[0-9] metric 24')
5120 self.assertIn('10.0.0.0/8 via 192.168.5.1 proto dhcp', output)
5121
5122 print('## link state file')
5123 output = read_link_state_file('veth99')
5124 print(output)
5125 # checking DNS server and Domains
5126 self.assertIn('DNS=192.168.5.1 192.168.5.7 192.168.5.8', output)
5127 self.assertIn('DOMAINS=foo.example.com', output)
5128
5129 print('## dnsmasq log')
5130 output = read_dnsmasq_log_file()
5131 print(output)
5132 self.assertIn('vendor class: FooBarVendorTest', output)
5133 self.assertIn('DHCPDISCOVER(veth-peer) 192.168.5.11', output)
5134 self.assertIn('client provides name: test-hostname', output)
5135 self.assertIn('26:mtu', output)
5136
5137 self.check_netlabel('veth99', r'192\.168\.5\.0/24')
5138
5139 def test_dhcp_client_ipv4_use_routes_gateway(self):
5140 first = True
5141 for (routes, gateway, dns_and_ntp_routes, classless) in itertools.product([True, False], repeat=4):
5142 if first:
5143 first = False
5144 else:
5145 self.tearDown()
5146
5147 print(f'### test_dhcp_client_ipv4_use_routes_gateway(routes={routes}, gateway={gateway}, dns_and_ntp_routes={dns_and_ntp_routes}, classless={classless})')
5148 with self.subTest(routes=routes, gateway=gateway, dns_and_ntp_routes=dns_and_ntp_routes, classless=classless):
5149 self._test_dhcp_client_ipv4_use_routes_gateway(routes, gateway, dns_and_ntp_routes, classless)
5150
5151 def _test_dhcp_client_ipv4_use_routes_gateway(self, use_routes, use_gateway, dns_and_ntp_routes, classless):
5152 testunit = '25-dhcp-client-ipv4-use-routes-use-gateway.network'
5153 testunits = ['25-veth.netdev', '25-dhcp-server-veth-peer.network', testunit]
5154 testunits.append(f'{testunit}.d/use-routes-{use_routes}.conf')
5155 testunits.append(f'{testunit}.d/use-gateway-{use_gateway}.conf')
5156 testunits.append(f'{testunit}.d/use-dns-and-ntp-routes-{dns_and_ntp_routes}.conf')
5157 copy_network_unit(*testunits, copy_dropins=False)
5158
5159 start_networkd()
5160 self.wait_online(['veth-peer:carrier'])
5161 additional_options = [
5162 '--dhcp-option=option:dns-server,192.168.5.10,8.8.8.8',
5163 '--dhcp-option=option:ntp-server,192.168.5.11,9.9.9.9',
5164 '--dhcp-option=option:static-route,192.168.6.100,192.168.5.2,8.8.8.8,192.168.5.3'
5165 ]
5166 if classless:
5167 additional_options += [
5168 '--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'
5169 ]
5170 start_dnsmasq(*additional_options)
5171 self.wait_online(['veth99:routable', 'veth-peer:routable'])
5172
5173 output = check_output('ip -4 route show dev veth99')
5174 print(output)
5175
5176 # Check UseRoutes=
5177 if use_routes:
5178 if classless:
5179 self.assertRegex(output, r'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
5180 self.assertRegex(output, r'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
5181 self.assertRegex(output, r'192.168.5.64/26 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
5182 self.assertRegex(output, r'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
5183 self.assertRegex(output, r'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
5184 else:
5185 self.assertRegex(output, r'192.168.6.0/24 via 192.168.5.2 proto dhcp src 192.168.5.[0-9]* metric 1024')
5186 self.assertRegex(output, r'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024')
5187 self.assertRegex(output, r'192.168.5.2 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
5188 self.assertRegex(output, r'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
5189 else:
5190 self.assertNotRegex(output, r'default via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
5191 self.assertNotRegex(output, r'8.0.0.0/8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
5192 self.assertNotRegex(output, r'192.168.5.4 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
5193 self.assertNotRegex(output, r'192.168.5.5 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
5194 self.assertNotRegex(output, r'192.168.6.0/24 via 192.168.5.2 proto dhcp src 192.168.5.[0-9]* metric 1024')
5195 self.assertNotRegex(output, r'8.0.0.0/8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024')
5196 self.assertNotRegex(output, r'192.168.5.2 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
5197 self.assertNotRegex(output, r'192.168.5.3 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
5198
5199 # Check UseGateway=
5200 if use_gateway and (not classless or not use_routes):
5201 self.assertRegex(output, r'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
5202 else:
5203 self.assertNotRegex(output, r'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
5204
5205 # Check route to gateway
5206 if (use_gateway or dns_and_ntp_routes) and (not classless or not use_routes):
5207 self.assertRegex(output, r'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
5208 else:
5209 self.assertNotRegex(output, r'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
5210
5211 # Check RoutesToDNS= and RoutesToNTP=
5212 if dns_and_ntp_routes:
5213 self.assertRegex(output, r'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
5214 self.assertRegex(output, r'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
5215 if use_routes:
5216 if classless:
5217 self.assertRegex(output, r'8.8.8.8 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
5218 self.assertRegex(output, r'9.9.9.9 via 192.168.5.4 proto dhcp src 192.168.5.[0-9]* metric 1024')
5219 else:
5220 self.assertRegex(output, r'8.8.8.8 via 192.168.5.3 proto dhcp src 192.168.5.[0-9]* metric 1024')
5221 self.assertRegex(output, r'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
5222 else:
5223 self.assertRegex(output, r'8.8.8.8 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
5224 self.assertRegex(output, r'9.9.9.9 via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
5225 else:
5226 self.assertNotRegex(output, r'192.168.5.10 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
5227 self.assertNotRegex(output, r'192.168.5.11 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
5228 self.assertNotRegex(output, r'8.8.8.8 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024')
5229 self.assertNotRegex(output, r'9.9.9.9 via 192.168.5.[0-9]* proto dhcp src 192.168.5.[0-9]* metric 1024')
5230
5231 output = check_output(*networkctl_cmd, '--json=short', 'status', env=env)
5232 check_json(output)
5233
5234 def test_dhcp_client_settings_anonymize(self):
5235 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-anonymize.network')
5236 start_networkd()
5237 self.wait_online(['veth-peer:carrier'])
5238 start_dnsmasq()
5239 self.wait_online(['veth99:routable', 'veth-peer:routable'])
5240
5241 print('## dnsmasq log')
5242 output = read_dnsmasq_log_file()
5243 print(output)
5244 self.assertNotIn('VendorClassIdentifier=SusantVendorTest', output)
5245 self.assertNotIn('test-hostname', output)
5246 self.assertNotIn('26:mtu', output)
5247
5248 def test_dhcp_keep_configuration_dhcp(self):
5249 copy_network_unit('25-veth.netdev',
5250 '25-dhcp-server-veth-peer.network',
5251 '25-dhcp-client-keep-configuration-dhcp.network')
5252 start_networkd()
5253 self.wait_online(['veth-peer:carrier'])
5254 start_dnsmasq()
5255 self.wait_online(['veth99:routable', 'veth-peer:routable'])
5256
5257 output = check_output('ip address show dev veth99 scope global')
5258 print(output)
5259 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5260 'valid_lft forever preferred_lft forever')
5261
5262 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
5263 stop_dnsmasq()
5264
5265 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
5266 print('Wait for the DHCP lease to be expired')
5267 time.sleep(120)
5268
5269 # The lease address should be kept after the lease expired
5270 output = check_output('ip address show dev veth99 scope global')
5271 print(output)
5272 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5273 'valid_lft forever preferred_lft forever')
5274
5275 stop_networkd()
5276
5277 # The lease address should be kept after networkd stopped
5278 output = check_output('ip address show dev veth99 scope global')
5279 print(output)
5280 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5281 'valid_lft forever preferred_lft forever')
5282
5283 with open(os.path.join(network_unit_dir, '25-dhcp-client-keep-configuration-dhcp.network'), mode='a', encoding='utf-8') as f:
5284 f.write('[Network]\nDHCP=no\n')
5285
5286 start_networkd()
5287 self.wait_online(['veth99:routable', 'veth-peer:routable'])
5288
5289 # Still the lease address should be kept after networkd restarted
5290 output = check_output('ip address show dev veth99 scope global')
5291 print(output)
5292 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global veth99\n *'
5293 'valid_lft forever preferred_lft forever')
5294
5295 def test_dhcp_keep_configuration_dhcp_on_stop(self):
5296 copy_network_unit('25-veth.netdev',
5297 '25-dhcp-server-veth-peer.network',
5298 '25-dhcp-client-keep-configuration-dhcp-on-stop.network')
5299 start_networkd()
5300 self.wait_online(['veth-peer:carrier'])
5301 start_dnsmasq()
5302 self.wait_online(['veth99:routable', 'veth-peer:routable'])
5303
5304 output = check_output('ip address show dev veth99 scope global')
5305 print(output)
5306 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
5307
5308 stop_dnsmasq()
5309 stop_networkd()
5310
5311 output = check_output('ip address show dev veth99 scope global')
5312 print(output)
5313 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
5314
5315 start_networkd()
5316 self.wait_online(['veth-peer:routable'])
5317
5318 output = check_output('ip address show dev veth99 scope global')
5319 print(output)
5320 self.assertNotIn('192.168.5.', output)
5321
5322 def test_dhcp_client_reuse_address_as_static(self):
5323 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client.network')
5324 start_networkd()
5325 self.wait_online(['veth-peer:carrier'])
5326 start_dnsmasq()
5327 self.wait_online(['veth99:routable', 'veth-peer:routable'])
5328
5329 # link become 'routable' when at least one protocol provide an valid address.
5330 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
5331 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
5332
5333 output = check_output('ip address show dev veth99 scope global')
5334 ipv4_address = re.search(r'192.168.5.[0-9]*/24', output).group()
5335 ipv6_address = re.search(r'2600::[0-9a-f:]*/128', output).group()
5336 static_network = '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address, 'Address=' + ipv6_address])
5337 print(static_network)
5338
5339 remove_network_unit('25-dhcp-client.network')
5340
5341 with open(os.path.join(network_unit_dir, '25-static.network'), mode='w', encoding='utf-8') as f:
5342 f.write(static_network)
5343
5344 restart_networkd()
5345 self.wait_online(['veth99:routable'])
5346
5347 output = check_output('ip -4 address show dev veth99 scope global')
5348 print(output)
5349 self.assertRegex(output, f'inet {ipv4_address} brd 192.168.5.255 scope global veth99\n *'
5350 'valid_lft forever preferred_lft forever')
5351
5352 output = check_output('ip -6 address show dev veth99 scope global')
5353 print(output)
5354 self.assertRegex(output, f'inet6 {ipv6_address} scope global *\n *'
5355 'valid_lft forever preferred_lft forever')
5356
5357 @expectedFailureIfModuleIsNotAvailable('vrf')
5358 def test_dhcp_client_vrf(self):
5359 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-vrf.network',
5360 '25-vrf.netdev', '25-vrf.network')
5361 start_networkd()
5362 self.wait_online(['veth-peer:carrier'])
5363 start_dnsmasq()
5364 self.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
5365
5366 # link become 'routable' when at least one protocol provide an valid address.
5367 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
5368 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
5369
5370 print('## ip -d link show dev vrf99')
5371 output = check_output('ip -d link show dev vrf99')
5372 print(output)
5373 self.assertRegex(output, 'vrf table 42')
5374
5375 print('## ip address show vrf vrf99')
5376 output = check_output('ip address show vrf vrf99')
5377 print(output)
5378 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
5379 self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
5380 self.assertRegex(output, 'inet6 .* scope link')
5381
5382 print('## ip address show dev veth99')
5383 output = check_output('ip address show dev veth99')
5384 print(output)
5385 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic veth99')
5386 self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
5387 self.assertRegex(output, 'inet6 .* scope link')
5388
5389 print('## ip route show vrf vrf99')
5390 output = check_output('ip route show vrf vrf99')
5391 print(output)
5392 self.assertRegex(output, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
5393 self.assertRegex(output, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
5394 self.assertRegex(output, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
5395
5396 print('## ip route show table main dev veth99')
5397 output = check_output('ip route show table main dev veth99')
5398 print(output)
5399 self.assertEqual(output, '')
5400
5401 def test_dhcp_client_gateway_onlink_implicit(self):
5402 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network',
5403 '25-dhcp-client-gateway-onlink-implicit.network')
5404 start_networkd()
5405 self.wait_online(['veth-peer:carrier'])
5406 start_dnsmasq()
5407 self.wait_online(['veth99:routable', 'veth-peer:routable'])
5408
5409 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
5410 print(output)
5411 self.assertRegex(output, '192.168.5')
5412
5413 output = check_output('ip route list dev veth99 10.0.0.0/8')
5414 print(output)
5415 self.assertRegex(output, 'onlink')
5416 output = check_output('ip route list dev veth99 192.168.100.0/24')
5417 print(output)
5418 self.assertRegex(output, 'onlink')
5419
5420 def test_dhcp_client_with_ipv4ll(self):
5421 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network',
5422 '25-dhcp-client-with-ipv4ll.network')
5423 start_networkd()
5424 # we need to increase timeout above default, as this will need to wait for
5425 # systemd-networkd to get the dhcpv4 transient failure event
5426 self.wait_online(['veth99:degraded', 'veth-peer:routable'], timeout='60s')
5427
5428 output = check_output('ip -4 address show dev veth99')
5429 print(output)
5430 self.assertNotIn('192.168.5.', output)
5431 self.assertIn('inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link', output)
5432
5433 start_dnsmasq()
5434 print('Wait for a DHCP lease to be acquired and the IPv4LL address to be dropped')
5435 self.wait_address('veth99', r'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic', ipv='-4')
5436 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')
5437 self.wait_online(['veth99:routable'])
5438
5439 output = check_output('ip -4 address show dev veth99')
5440 print(output)
5441 self.assertRegex(output, r'inet 192\.168\.5\.\d+/24 metric 1024 brd 192\.168\.5\.255 scope global dynamic veth99')
5442 self.assertNotIn('169.254.', output)
5443 self.assertNotIn('scope link', output)
5444
5445 stop_dnsmasq()
5446 print('Wait for the DHCP lease to be expired and an IPv4LL address to be acquired')
5447 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)
5448 self.wait_address('veth99', r'inet 169\.254\.133\.11/16 metric 2048 brd 169\.254\.255\.255 scope link', scope='link', ipv='-4')
5449
5450 output = check_output('ip -4 address show dev veth99')
5451 print(output)
5452 self.assertNotIn('192.168.5.', output)
5453 self.assertIn('inet 169.254.133.11/16 metric 2048 brd 169.254.255.255 scope link', output)
5454
5455 def test_dhcp_client_use_dns(self):
5456 def check(self, ipv4, ipv6):
5457 os.makedirs(os.path.join(network_unit_dir, '25-dhcp-client.network.d'), exist_ok=True)
5458 with open(os.path.join(network_unit_dir, '25-dhcp-client.network.d/override.conf'), mode='w', encoding='utf-8') as f:
5459 f.write('[DHCPv4]\nUseDNS=')
5460 f.write('yes' if ipv4 else 'no')
5461 f.write('\n[DHCPv6]\nUseDNS=')
5462 f.write('yes' if ipv6 else 'no')
5463 f.write('\n[IPv6AcceptRA]\nUseDNS=no')
5464
5465 networkctl_reload()
5466 self.wait_online(['veth99:routable'])
5467
5468 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5469 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
5470 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
5471
5472 # make resolved re-read the link state file
5473 check_output(*resolvectl_cmd, 'revert', 'veth99', env=env)
5474
5475 output = check_output(*resolvectl_cmd, 'dns', 'veth99', env=env)
5476 print(output)
5477 if ipv4:
5478 self.assertIn('192.168.5.1', output)
5479 else:
5480 self.assertNotIn('192.168.5.1', output)
5481 if ipv6:
5482 self.assertIn('2600::1', output)
5483 else:
5484 self.assertNotIn('2600::1', output)
5485
5486 output = check_output(*networkctl_cmd, '--json=short', 'status', env=env)
5487 check_json(output)
5488
5489 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client.network', copy_dropins=False)
5490
5491 start_networkd()
5492 self.wait_online(['veth-peer:carrier'])
5493 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1',
5494 '--dhcp-option=option6:dns-server,[2600::1]')
5495
5496 check(self, True, True)
5497 check(self, True, False)
5498 check(self, False, True)
5499 check(self, False, False)
5500
5501 def test_dhcp_client_use_captive_portal(self):
5502 def check(self, ipv4, ipv6):
5503 os.makedirs(os.path.join(network_unit_dir, '25-dhcp-client.network.d'), exist_ok=True)
5504 with open(os.path.join(network_unit_dir, '25-dhcp-client.network.d/override.conf'), mode='w', encoding='utf-8') as f:
5505 f.write('[DHCPv4]\nUseCaptivePortal=')
5506 f.write('yes' if ipv4 else 'no')
5507 f.write('\n[DHCPv6]\nUseCaptivePortal=')
5508 f.write('yes' if ipv6 else 'no')
5509 f.write('\n[IPv6AcceptRA]\nUseCaptivePortal=no')
5510
5511 networkctl_reload()
5512 self.wait_online(['veth99:routable'])
5513
5514 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5515 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
5516 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
5517
5518 output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
5519 print(output)
5520 if ipv4 or ipv6:
5521 self.assertIn('Captive Portal: http://systemd.io', output)
5522 else:
5523 self.assertNotIn('Captive Portal: http://systemd.io', output)
5524
5525 output = check_output(*networkctl_cmd, '--json=short', 'status', env=env)
5526 check_json(output)
5527
5528 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client.network', copy_dropins=False)
5529
5530 start_networkd()
5531 self.wait_online(['veth-peer:carrier'])
5532 start_dnsmasq('--dhcp-option=114,http://systemd.io',
5533 '--dhcp-option=option6:103,http://systemd.io')
5534
5535 check(self, True, True)
5536 check(self, True, False)
5537 check(self, False, True)
5538 check(self, False, False)
5539
5540 def test_dhcp_client_reject_captive_portal(self):
5541 def check(self, ipv4, ipv6):
5542 os.makedirs(os.path.join(network_unit_dir, '25-dhcp-client.network.d'), exist_ok=True)
5543 with open(os.path.join(network_unit_dir, '25-dhcp-client.network.d/override.conf'), mode='w', encoding='utf-8') as f:
5544 f.write('[DHCPv4]\nUseCaptivePortal=')
5545 f.write('yes' if ipv4 else 'no')
5546 f.write('\n[DHCPv6]\nUseCaptivePortal=')
5547 f.write('yes' if ipv6 else 'no')
5548 f.write('\n[IPv6AcceptRA]\nUseCaptivePortal=no')
5549
5550 networkctl_reload()
5551 self.wait_online(['veth99:routable'])
5552
5553 # link becomes 'routable' when at least one protocol provide an valid address. Hence, we need to explicitly wait for both addresses.
5554 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 metric 1024 brd 192.168.5.255 scope global dynamic', ipv='-4')
5555 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
5556
5557 output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
5558 print(output)
5559 self.assertNotIn('Captive Portal: ', output)
5560 self.assertNotIn('invalid/url', output)
5561
5562 output = check_output(*networkctl_cmd, '--json=short', 'status', env=env)
5563 check_json(output)
5564
5565 copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client.network', copy_dropins=False)
5566
5567 start_networkd()
5568 self.wait_online(['veth-peer:carrier'])
5569 masq = lambda bs: ':'.join(f'{b:02x}' for b in bs)
5570 start_dnsmasq('--dhcp-option=114,' + masq(b'http://\x00invalid/url'),
5571 '--dhcp-option=option6:103,' + masq(b'http://\x00/invalid/url'))
5572
5573 check(self, True, True)
5574 check(self, True, False)
5575 check(self, False, True)
5576 check(self, False, False)
5577
5578 class NetworkdDHCPPDTests(unittest.TestCase, Utilities):
5579
5580 def setUp(self):
5581 setup_common()
5582
5583 def tearDown(self):
5584 tear_down_common()
5585
5586 def test_dhcp6pd(self):
5587 copy_network_unit('25-veth.netdev', '25-dhcp6pd-server.network', '25-dhcp6pd-upstream.network',
5588 '25-veth-downstream-veth97.netdev', '25-dhcp-pd-downstream-veth97.network', '25-dhcp-pd-downstream-veth97-peer.network',
5589 '25-veth-downstream-veth98.netdev', '25-dhcp-pd-downstream-veth98.network', '25-dhcp-pd-downstream-veth98-peer.network',
5590 '11-dummy.netdev', '25-dhcp-pd-downstream-test1.network',
5591 '25-dhcp-pd-downstream-dummy97.network',
5592 '12-dummy.netdev', '25-dhcp-pd-downstream-dummy98.network',
5593 '13-dummy.netdev', '25-dhcp-pd-downstream-dummy99.network')
5594
5595 start_networkd()
5596 self.wait_online(['veth-peer:routable'])
5597 start_isc_dhcpd(conf_file='isc-dhcpd-dhcp6pd.conf', ipv='-6')
5598 self.wait_online(['veth99:routable', 'test1:routable', 'dummy98:routable', 'dummy99:degraded',
5599 'veth97:routable', 'veth97-peer:routable', 'veth98:routable', 'veth98-peer:routable'])
5600
5601 print('### ip -6 address show dev veth-peer scope global')
5602 output = check_output('ip -6 address show dev veth-peer scope global')
5603 print(output)
5604 self.assertIn('inet6 3ffe:501:ffff:100::1/64 scope global', output)
5605
5606 # Link Subnet IDs
5607 # test1: 0x00
5608 # dummy97: 0x01 (The link will appear later)
5609 # dummy98: 0x00
5610 # dummy99: auto -> 0x02 (No address assignment)
5611 # veth97: 0x08
5612 # veth98: 0x09
5613 # veth99: 0x10
5614
5615 print('### ip -6 address show dev veth99 scope global')
5616 output = check_output('ip -6 address show dev veth99 scope global')
5617 print(output)
5618 # IA_NA
5619 self.assertRegex(output, 'inet6 3ffe:501:ffff:100::[0-9]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
5620 # address in IA_PD (Token=static)
5621 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic')
5622 # address in IA_PD (Token=eui64)
5623 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic')
5624 # address in IA_PD (temporary)
5625 # Note that the temporary addresses may appear after the link enters configured state
5626 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')
5627
5628 print('### ip -6 address show dev test1 scope global')
5629 output = check_output('ip -6 address show dev test1 scope global')
5630 print(output)
5631 # address in IA_PD (Token=static)
5632 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5633 # address in IA_PD (temporary)
5634 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')
5635
5636 print('### ip -6 address show dev dummy98 scope global')
5637 output = check_output('ip -6 address show dev dummy98 scope global')
5638 print(output)
5639 # address in IA_PD (Token=static)
5640 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5641 # address in IA_PD (temporary)
5642 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')
5643
5644 print('### ip -6 address show dev dummy99 scope global')
5645 output = check_output('ip -6 address show dev dummy99 scope global')
5646 print(output)
5647 # Assign=no
5648 self.assertNotRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]02')
5649
5650 print('### ip -6 address show dev veth97 scope global')
5651 output = check_output('ip -6 address show dev veth97 scope global')
5652 print(output)
5653 # address in IA_PD (Token=static)
5654 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5655 # address in IA_PD (Token=eui64)
5656 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr')
5657 # address in IA_PD (temporary)
5658 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')
5659
5660 print('### ip -6 address show dev veth97-peer scope global')
5661 output = check_output('ip -6 address show dev veth97-peer scope global')
5662 print(output)
5663 # NDisc address (Token=static)
5664 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
5665 # NDisc address (Token=eui64)
5666 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr')
5667 # NDisc address (temporary)
5668 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')
5669
5670 print('### ip -6 address show dev veth98 scope global')
5671 output = check_output('ip -6 address show dev veth98 scope global')
5672 print(output)
5673 # address in IA_PD (Token=static)
5674 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5675 # address in IA_PD (Token=eui64)
5676 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr')
5677 # address in IA_PD (temporary)
5678 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')
5679
5680 print('### ip -6 address show dev veth98-peer scope global')
5681 output = check_output('ip -6 address show dev veth98-peer scope global')
5682 print(output)
5683 # NDisc address (Token=static)
5684 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
5685 # NDisc address (Token=eui64)
5686 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr')
5687 # NDisc address (temporary)
5688 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')
5689
5690 print('### ip -6 route show type unreachable')
5691 output = check_output('ip -6 route show type unreachable')
5692 print(output)
5693 self.assertRegex(output, 'unreachable 3ffe:501:ffff:[2-9a-f]00::/56 dev lo proto dhcp')
5694
5695 print('### ip -6 route show dev veth99')
5696 output = check_output('ip -6 route show dev veth99')
5697 print(output)
5698 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]10::/64 proto kernel metric [0-9]* expires')
5699
5700 print('### ip -6 route show dev test1')
5701 output = check_output('ip -6 route show dev test1')
5702 print(output)
5703 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires')
5704
5705 print('### ip -6 route show dev dummy98')
5706 output = check_output('ip -6 route show dev dummy98')
5707 print(output)
5708 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires')
5709
5710 print('### ip -6 route show dev dummy99')
5711 output = check_output('ip -6 route show dev dummy99')
5712 print(output)
5713 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires')
5714
5715 print('### ip -6 route show dev veth97')
5716 output = check_output('ip -6 route show dev veth97')
5717 print(output)
5718 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]08::/64 proto kernel metric [0-9]* expires')
5719
5720 print('### ip -6 route show dev veth97-peer')
5721 output = check_output('ip -6 route show dev veth97-peer')
5722 print(output)
5723 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]08::/64 proto ra metric [0-9]* expires')
5724
5725 print('### ip -6 route show dev veth98')
5726 output = check_output('ip -6 route show dev veth98')
5727 print(output)
5728 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]09::/64 proto kernel metric [0-9]* expires')
5729
5730 print('### ip -6 route show dev veth98-peer')
5731 output = check_output('ip -6 route show dev veth98-peer')
5732 print(output)
5733 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]09::/64 proto ra metric [0-9]* expires')
5734
5735 # Test case for a downstream which appears later
5736 check_output('ip link add dummy97 type dummy')
5737 self.wait_online(['dummy97:routable'])
5738
5739 print('### ip -6 address show dev dummy97 scope global')
5740 output = check_output('ip -6 address show dev dummy97 scope global')
5741 print(output)
5742 # address in IA_PD (Token=static)
5743 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5744 # address in IA_PD (temporary)
5745 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')
5746
5747 print('### ip -6 route show dev dummy97')
5748 output = check_output('ip -6 route show dev dummy97')
5749 print(output)
5750 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]01::/64 proto kernel metric [0-9]* expires')
5751
5752 # Test case for reconfigure
5753 networkctl_reconfigure('dummy98', 'dummy99')
5754 self.wait_online(['dummy98:routable', 'dummy99:degraded'])
5755
5756 print('### ip -6 address show dev dummy98 scope global')
5757 output = check_output('ip -6 address show dev dummy98 scope global')
5758 print(output)
5759 # address in IA_PD (Token=static)
5760 self.assertRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5761 # address in IA_PD (temporary)
5762 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')
5763
5764 print('### ip -6 address show dev dummy99 scope global')
5765 output = check_output('ip -6 address show dev dummy99 scope global')
5766 print(output)
5767 # Assign=no
5768 self.assertNotRegex(output, 'inet6 3ffe:501:ffff:[2-9a-f]02')
5769
5770 print('### ip -6 route show dev dummy98')
5771 output = check_output('ip -6 route show dev dummy98')
5772 print(output)
5773 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]00::/64 proto kernel metric [0-9]* expires')
5774
5775 print('### ip -6 route show dev dummy99')
5776 output = check_output('ip -6 route show dev dummy99')
5777 print(output)
5778 self.assertRegex(output, '3ffe:501:ffff:[2-9a-f]02::/64 proto dhcp metric [0-9]* expires')
5779
5780 self.check_netlabel('dummy98', '3ffe:501:ffff:[2-9a-f]00::/64')
5781
5782 def verify_dhcp4_6rd(self, tunnel_name):
5783 print('### ip -4 address show dev veth-peer scope global')
5784 output = check_output('ip -4 address show dev veth-peer scope global')
5785 print(output)
5786 self.assertIn('inet 10.0.0.1/8 brd 10.255.255.255 scope global veth-peer', output)
5787
5788 # Link Subnet IDs
5789 # test1: 0x00
5790 # dummy97: 0x01 (The link will appear later)
5791 # dummy98: 0x00
5792 # dummy99: auto -> 0x0[23] (No address assignment)
5793 # 6rd-XXX: auto -> 0x0[23]
5794 # veth97: 0x08
5795 # veth98: 0x09
5796 # veth99: 0x10
5797
5798 print('### ip -4 address show dev veth99 scope global')
5799 output = check_output('ip -4 address show dev veth99 scope global')
5800 print(output)
5801 self.assertRegex(output, 'inet 10.100.100.[0-9]*/8 (metric 1024 |)brd 10.255.255.255 scope global dynamic veth99')
5802
5803 print('### ip -6 address show dev veth99 scope global')
5804 output = check_output('ip -6 address show dev veth99 scope global')
5805 print(output)
5806 # address in IA_PD (Token=static)
5807 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+10:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5808 # address in IA_PD (Token=eui64)
5809 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+10:1034:56ff:fe78:9abc/64 (metric 256 |)scope global dynamic mngtmpaddr')
5810 # address in IA_PD (temporary)
5811 # Note that the temporary addresses may appear after the link enters configured state
5812 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')
5813
5814 print('### ip -6 address show dev test1 scope global')
5815 output = check_output('ip -6 address show dev test1 scope global')
5816 print(output)
5817 # address in IA_PD (Token=static)
5818 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5819 # address in IA_PD (temporary)
5820 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')
5821
5822 print('### ip -6 address show dev dummy98 scope global')
5823 output = check_output('ip -6 address show dev dummy98 scope global')
5824 print(output)
5825 # address in IA_PD (Token=static)
5826 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+00:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5827 # address in IA_PD (temporary)
5828 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')
5829
5830 print('### ip -6 address show dev dummy99 scope global')
5831 output = check_output('ip -6 address show dev dummy99 scope global')
5832 print(output)
5833 # Assign=no
5834 self.assertNotRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+0[23]')
5835
5836 print('### ip -6 address show dev veth97 scope global')
5837 output = check_output('ip -6 address show dev veth97 scope global')
5838 print(output)
5839 # address in IA_PD (Token=static)
5840 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5841 # address in IA_PD (Token=eui64)
5842 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9ace/64 (metric 256 |)scope global dynamic mngtmpaddr')
5843 # address in IA_PD (temporary)
5844 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')
5845
5846 print('### ip -6 address show dev veth97-peer scope global')
5847 output = check_output('ip -6 address show dev veth97-peer scope global')
5848 print(output)
5849 # NDisc address (Token=static)
5850 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+08:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
5851 # NDisc address (Token=eui64)
5852 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+08:1034:56ff:fe78:9acf/64 (metric 256 |)scope global dynamic mngtmpaddr')
5853 # NDisc address (temporary)
5854 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')
5855
5856 print('### ip -6 address show dev veth98 scope global')
5857 output = check_output('ip -6 address show dev veth98 scope global')
5858 print(output)
5859 # address in IA_PD (Token=static)
5860 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5861 # address in IA_PD (Token=eui64)
5862 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abe/64 (metric 256 |)scope global dynamic mngtmpaddr')
5863 # address in IA_PD (temporary)
5864 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')
5865
5866 print('### ip -6 address show dev veth98-peer scope global')
5867 output = check_output('ip -6 address show dev veth98-peer scope global')
5868 print(output)
5869 # NDisc address (Token=static)
5870 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+09:1a:2b:3c:4e/64 (metric 256 |)scope global dynamic mngtmpaddr')
5871 # NDisc address (Token=eui64)
5872 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+09:1034:56ff:fe78:9abf/64 (metric 256 |)scope global dynamic mngtmpaddr')
5873 # NDisc address (temporary)
5874 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')
5875
5876 print('### ip -6 route show type unreachable')
5877 output = check_output('ip -6 route show type unreachable')
5878 print(output)
5879 self.assertRegex(output, 'unreachable 2001:db8:6464:[0-9a-f]+00::/56 dev lo proto dhcp')
5880
5881 print('### ip -6 route show dev veth99')
5882 output = check_output('ip -6 route show dev veth99')
5883 print(output)
5884 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+10::/64 proto kernel metric [0-9]* expires')
5885
5886 print('### ip -6 route show dev test1')
5887 output = check_output('ip -6 route show dev test1')
5888 print(output)
5889 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires')
5890
5891 print('### ip -6 route show dev dummy98')
5892 output = check_output('ip -6 route show dev dummy98')
5893 print(output)
5894 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+00::/64 proto kernel metric [0-9]* expires')
5895
5896 print('### ip -6 route show dev dummy99')
5897 output = check_output('ip -6 route show dev dummy99')
5898 print(output)
5899 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto dhcp metric [0-9]* expires')
5900
5901 print('### ip -6 route show dev veth97')
5902 output = check_output('ip -6 route show dev veth97')
5903 print(output)
5904 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+08::/64 proto kernel metric [0-9]* expires')
5905
5906 print('### ip -6 route show dev veth97-peer')
5907 output = check_output('ip -6 route show dev veth97-peer')
5908 print(output)
5909 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+08::/64 proto ra metric [0-9]* expires')
5910
5911 print('### ip -6 route show dev veth98')
5912 output = check_output('ip -6 route show dev veth98')
5913 print(output)
5914 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+09::/64 proto kernel metric [0-9]* expires')
5915
5916 print('### ip -6 route show dev veth98-peer')
5917 output = check_output('ip -6 route show dev veth98-peer')
5918 print(output)
5919 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+09::/64 proto ra metric [0-9]* expires')
5920
5921 print('### ip -6 address show dev dummy97 scope global')
5922 output = check_output('ip -6 address show dev dummy97 scope global')
5923 print(output)
5924 # address in IA_PD (Token=static)
5925 self.assertRegex(output, 'inet6 2001:db8:6464:[0-9a-f]+01:1a:2b:3c:4d/64 (metric 256 |)scope global dynamic mngtmpaddr')
5926 # address in IA_PD (temporary)
5927 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')
5928
5929 print('### ip -6 route show dev dummy97')
5930 output = check_output('ip -6 route show dev dummy97')
5931 print(output)
5932 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+01::/64 proto kernel metric [0-9]* expires')
5933
5934 print(f'### ip -d link show dev {tunnel_name}')
5935 output = check_output(f'ip -d link show dev {tunnel_name}')
5936 print(output)
5937 self.assertIn('link/sit 10.100.100.', output)
5938 self.assertIn('local 10.100.100.', output)
5939 self.assertIn('ttl 64', output)
5940 self.assertIn('6rd-prefix 2001:db8::/32', output)
5941 self.assertIn('6rd-relay_prefix 10.0.0.0/8', output)
5942
5943 print(f'### ip -6 address show dev {tunnel_name}')
5944 output = check_output(f'ip -6 address show dev {tunnel_name}')
5945 print(output)
5946 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')
5947 self.assertRegex(output, 'inet6 ::10.100.100.[0-9]+/96 scope global')
5948
5949 print(f'### ip -6 route show dev {tunnel_name}')
5950 output = check_output(f'ip -6 route show dev {tunnel_name}')
5951 print(output)
5952 self.assertRegex(output, '2001:db8:6464:[0-9a-f]+0[23]::/64 proto kernel metric [0-9]* expires')
5953 self.assertRegex(output, '::/96 proto kernel metric [0-9]*')
5954
5955 print('### ip -6 route show default')
5956 output = check_output('ip -6 route show default')
5957 print(output)
5958 self.assertIn('default', output)
5959 self.assertIn(f'via ::10.0.0.1 dev {tunnel_name}', output)
5960
5961 def test_dhcp4_6rd(self):
5962 copy_network_unit('25-veth.netdev', '25-dhcp4-6rd-server.network', '25-dhcp4-6rd-upstream.network',
5963 '25-veth-downstream-veth97.netdev', '25-dhcp-pd-downstream-veth97.network', '25-dhcp-pd-downstream-veth97-peer.network',
5964 '25-veth-downstream-veth98.netdev', '25-dhcp-pd-downstream-veth98.network', '25-dhcp-pd-downstream-veth98-peer.network',
5965 '11-dummy.netdev', '25-dhcp-pd-downstream-test1.network',
5966 '25-dhcp-pd-downstream-dummy97.network',
5967 '12-dummy.netdev', '25-dhcp-pd-downstream-dummy98.network',
5968 '13-dummy.netdev', '25-dhcp-pd-downstream-dummy99.network',
5969 '80-6rd-tunnel.network')
5970
5971 start_networkd()
5972 self.wait_online(['veth-peer:routable'])
5973
5974 # ipv4masklen: 8
5975 # 6rd-prefix: 2001:db8::/32
5976 # br-addresss: 10.0.0.1
5977
5978 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',
5979 ipv4_range='10.100.100.100,10.100.100.200',
5980 ipv4_router='10.0.0.1')
5981 self.wait_online(['veth99:routable', 'test1:routable', 'dummy98:routable', 'dummy99:degraded',
5982 'veth97:routable', 'veth97-peer:routable', 'veth98:routable', 'veth98-peer:routable'])
5983
5984 # Test case for a downstream which appears later
5985 check_output('ip link add dummy97 type dummy')
5986 self.wait_online(['dummy97:routable'])
5987
5988 # Find tunnel name
5989 tunnel_name = None
5990 for name in os.listdir('/sys/class/net/'):
5991 if name.startswith('6rd-'):
5992 tunnel_name = name
5993 break
5994
5995 self.wait_online([f'{tunnel_name}:routable'])
5996
5997 self.verify_dhcp4_6rd(tunnel_name)
5998
5999 # Test case for reconfigure
6000 networkctl_reconfigure('dummy98', 'dummy99')
6001 self.wait_online(['dummy98:routable', 'dummy99:degraded'])
6002
6003 self.verify_dhcp4_6rd(tunnel_name)
6004
6005 print('Wait for the DHCP lease to be renewed/rebind')
6006 time.sleep(120)
6007
6008 self.wait_online(['veth99:routable', 'test1:routable', 'dummy97:routable', 'dummy98:routable', 'dummy99:degraded',
6009 'veth97:routable', 'veth97-peer:routable', 'veth98:routable', 'veth98-peer:routable'])
6010
6011 self.verify_dhcp4_6rd(tunnel_name)
6012
6013 class NetworkdIPv6PrefixTests(unittest.TestCase, Utilities):
6014
6015 def setUp(self):
6016 setup_common()
6017
6018 def tearDown(self):
6019 tear_down_common()
6020
6021 def test_ipv6_route_prefix(self):
6022 copy_network_unit('25-veth.netdev', '25-ipv6ra-prefix-client.network', '25-ipv6ra-prefix.network',
6023 '12-dummy.netdev', '25-ipv6ra-uplink.network')
6024
6025 start_networkd()
6026 self.wait_online(['veth99:routable', 'veth-peer:routable', 'dummy98:routable'])
6027
6028 output = check_output('ip address show dev veth-peer')
6029 print(output)
6030 self.assertIn('inet6 2001:db8:0:1:', output)
6031 self.assertNotIn('inet6 2001:db8:0:2:', output)
6032 self.assertNotIn('inet6 2001:db8:0:3:', output)
6033
6034 output = check_output('ip -6 route show dev veth-peer')
6035 print(output)
6036 self.assertIn('2001:db8:0:1::/64 proto ra', output)
6037 self.assertNotIn('2001:db8:0:2::/64 proto ra', output)
6038 self.assertNotIn('2001:db8:0:3::/64 proto ra', output)
6039 self.assertIn('2001:db0:fff::/64 via ', output)
6040 self.assertNotIn('2001:db1:fff::/64 via ', output)
6041 self.assertNotIn('2001:db2:fff::/64 via ', output)
6042
6043 output = check_output('ip address show dev veth99')
6044 print(output)
6045 self.assertNotIn('inet6 2001:db8:0:1:', output)
6046 self.assertIn('inet6 2001:db8:0:2:1a:2b:3c:4d', output)
6047 self.assertIn('inet6 2001:db8:0:2:fa:de:ca:fe', output)
6048 self.assertNotIn('inet6 2001:db8:0:3:', output)
6049
6050 output = check_output(*resolvectl_cmd, 'dns', 'veth-peer', env=env)
6051 print(output)
6052 self.assertRegex(output, '2001:db8:1:1::2')
6053
6054 output = check_output(*resolvectl_cmd, 'domain', 'veth-peer', env=env)
6055 print(output)
6056 self.assertIn('example.com', output)
6057
6058 output = check_output(*networkctl_cmd, '--json=short', 'status', env=env)
6059 check_json(output)
6060
6061 def test_ipv6_route_prefix_deny_list(self):
6062 copy_network_unit('25-veth.netdev', '25-ipv6ra-prefix-client-deny-list.network', '25-ipv6ra-prefix.network',
6063 '12-dummy.netdev', '25-ipv6ra-uplink.network')
6064
6065 start_networkd()
6066 self.wait_online(['veth99:routable', 'veth-peer:routable', 'dummy98:routable'])
6067
6068 output = check_output('ip address show dev veth-peer')
6069 print(output)
6070 self.assertIn('inet6 2001:db8:0:1:', output)
6071 self.assertNotIn('inet6 2001:db8:0:2:', output)
6072
6073 output = check_output('ip -6 route show dev veth-peer')
6074 print(output)
6075 self.assertIn('2001:db8:0:1::/64 proto ra', output)
6076 self.assertNotIn('2001:db8:0:2::/64 proto ra', output)
6077 self.assertIn('2001:db0:fff::/64 via ', output)
6078 self.assertNotIn('2001:db1:fff::/64 via ', output)
6079
6080 output = check_output('ip address show dev veth99')
6081 print(output)
6082 self.assertNotIn('inet6 2001:db8:0:1:', output)
6083 self.assertIn('inet6 2001:db8:0:2:', output)
6084
6085 output = check_output(*resolvectl_cmd, 'dns', 'veth-peer', env=env)
6086 print(output)
6087 self.assertRegex(output, '2001:db8:1:1::2')
6088
6089 output = check_output(*resolvectl_cmd, 'domain', 'veth-peer', env=env)
6090 print(output)
6091 self.assertIn('example.com', output)
6092
6093 class NetworkdMTUTests(unittest.TestCase, Utilities):
6094
6095 def setUp(self):
6096 setup_common()
6097
6098 def tearDown(self):
6099 tear_down_common()
6100
6101 def check_mtu(self, mtu, ipv6_mtu=None, reset=True):
6102 if not ipv6_mtu:
6103 ipv6_mtu = mtu
6104
6105 # test normal start
6106 start_networkd()
6107 self.wait_online(['dummy98:routable'])
6108 self.check_link_attr('dummy98', 'mtu', mtu)
6109 self.check_ipv6_sysctl_attr('dummy98', 'mtu', ipv6_mtu)
6110
6111 # test normal restart
6112 restart_networkd()
6113 self.wait_online(['dummy98:routable'])
6114 self.check_link_attr('dummy98', 'mtu', mtu)
6115 self.check_ipv6_sysctl_attr('dummy98', 'mtu', ipv6_mtu)
6116
6117 if reset:
6118 self.reset_check_mtu(mtu, ipv6_mtu)
6119
6120 def reset_check_mtu(self, mtu, ipv6_mtu=None):
6121 ''' test setting mtu/ipv6_mtu with interface already up '''
6122 stop_networkd()
6123
6124 # note - changing the device mtu resets the ipv6 mtu
6125 check_output('ip link set up mtu 1501 dev dummy98')
6126 check_output('ip link set up mtu 1500 dev dummy98')
6127 self.check_link_attr('dummy98', 'mtu', '1500')
6128 self.check_ipv6_sysctl_attr('dummy98', 'mtu', '1500')
6129
6130 self.check_mtu(mtu, ipv6_mtu, reset=False)
6131
6132 def test_mtu_network(self):
6133 copy_network_unit('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
6134 self.check_mtu('1600')
6135
6136 def test_mtu_netdev(self):
6137 copy_network_unit('12-dummy-mtu.netdev', '12-dummy.network', copy_dropins=False)
6138 # note - MTU set by .netdev happens ONLY at device creation!
6139 self.check_mtu('1600', reset=False)
6140
6141 def test_mtu_link(self):
6142 copy_network_unit('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', copy_dropins=False)
6143 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
6144 self.check_mtu('1600', reset=False)
6145
6146 def test_ipv6_mtu(self):
6147 ''' set ipv6 mtu without setting device mtu '''
6148 copy_network_unit('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
6149 self.check_mtu('1500', '1400')
6150
6151 def test_ipv6_mtu_toolarge(self):
6152 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
6153 copy_network_unit('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
6154 self.check_mtu('1500', '1500')
6155
6156 def test_mtu_network_ipv6_mtu(self):
6157 ''' set ipv6 mtu and set device mtu via network file '''
6158 copy_network_unit('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
6159 self.check_mtu('1600', '1550')
6160
6161 def test_mtu_netdev_ipv6_mtu(self):
6162 ''' set ipv6 mtu and set device mtu via netdev file '''
6163 copy_network_unit('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
6164 self.check_mtu('1600', '1550', reset=False)
6165
6166 def test_mtu_link_ipv6_mtu(self):
6167 ''' set ipv6 mtu and set device mtu via link file '''
6168 copy_network_unit('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
6169 self.check_mtu('1600', '1550', reset=False)
6170
6171
6172 if __name__ == '__main__':
6173 parser = argparse.ArgumentParser()
6174 parser.add_argument('--build-dir', help='Path to build dir', dest='build_dir')
6175 parser.add_argument('--networkd', help='Path to systemd-networkd', dest='networkd_bin')
6176 parser.add_argument('--resolved', help='Path to systemd-resolved', dest='resolved_bin')
6177 parser.add_argument('--timesyncd', help='Path to systemd-timesyncd', dest='timesyncd_bin')
6178 parser.add_argument('--udevd', help='Path to systemd-udevd', dest='udevd_bin')
6179 parser.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest='wait_online_bin')
6180 parser.add_argument('--networkctl', help='Path to networkctl', dest='networkctl_bin')
6181 parser.add_argument('--resolvectl', help='Path to resolvectl', dest='resolvectl_bin')
6182 parser.add_argument('--timedatectl', help='Path to timedatectl', dest='timedatectl_bin')
6183 parser.add_argument('--udevadm', help='Path to udevadm', dest='udevadm_bin')
6184 parser.add_argument('--valgrind', help='Enable valgrind', dest='use_valgrind', type=bool, nargs='?', const=True, default=use_valgrind)
6185 parser.add_argument('--debug', help='Generate debugging logs', dest='enable_debug', type=bool, nargs='?', const=True, default=enable_debug)
6186 parser.add_argument('--asan-options', help='ASAN options', dest='asan_options')
6187 parser.add_argument('--lsan-options', help='LSAN options', dest='lsan_options')
6188 parser.add_argument('--ubsan-options', help='UBSAN options', dest='ubsan_options')
6189 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)
6190 ns, unknown_args = parser.parse_known_args(namespace=unittest)
6191
6192 if ns.build_dir:
6193 if ns.networkd_bin or ns.resolved_bin or ns.timesyncd_bin or ns.udevd_bin or \
6194 ns.wait_online_bin or ns.networkctl_bin or ns.resolvectl_bin or ns.timedatectl_bin or ns.udevadm_bin:
6195 print('WARNING: --networkd, --resolved, --timesyncd, --udevd, --wait-online, --networkctl, --resolvectl, --timedatectl, or --udevadm options are ignored when --build-dir is specified.')
6196 networkd_bin = os.path.join(ns.build_dir, 'systemd-networkd')
6197 resolved_bin = os.path.join(ns.build_dir, 'systemd-resolved')
6198 timesyncd_bin = os.path.join(ns.build_dir, 'systemd-timesyncd')
6199 udevd_bin = os.path.join(ns.build_dir, 'udevadm')
6200 wait_online_bin = os.path.join(ns.build_dir, 'systemd-networkd-wait-online')
6201 networkctl_bin = os.path.join(ns.build_dir, 'networkctl')
6202 resolvectl_bin = os.path.join(ns.build_dir, 'resolvectl')
6203 timedatectl_bin = os.path.join(ns.build_dir, 'timedatectl')
6204 udevadm_bin = os.path.join(ns.build_dir, 'udevadm')
6205 else:
6206 if ns.networkd_bin:
6207 networkd_bin = ns.networkd_bin
6208 if ns.resolved_bin:
6209 resolved_bin = ns.resolved_bin
6210 if ns.timesyncd_bin:
6211 timesyncd_bin = ns.timesyncd_bin
6212 if ns.udevd_bin:
6213 udevd_bin = ns.udevd_bin
6214 if ns.wait_online_bin:
6215 wait_online_bin = ns.wait_online_bin
6216 if ns.networkctl_bin:
6217 networkctl_bin = ns.networkctl_bin
6218 if ns.resolvectl_bin:
6219 resolvectl_bin = ns.resolvectl_bin
6220 if ns.timedatectl_bin:
6221 timedatectl_bin = ns.timedatectl_bin
6222 if ns.udevadm_bin:
6223 udevadm_bin = ns.udevadm_bin
6224
6225 use_valgrind = ns.use_valgrind
6226 enable_debug = ns.enable_debug
6227 asan_options = ns.asan_options
6228 lsan_options = ns.lsan_options
6229 ubsan_options = ns.ubsan_options
6230 with_coverage = ns.with_coverage
6231
6232 if use_valgrind:
6233 # Do not forget the trailing space.
6234 valgrind_cmd = 'valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all '
6235
6236 networkctl_cmd = valgrind_cmd.split() + [networkctl_bin]
6237 resolvectl_cmd = valgrind_cmd.split() + [resolvectl_bin]
6238 timedatectl_cmd = valgrind_cmd.split() + [timedatectl_bin]
6239 udevadm_cmd = valgrind_cmd.split() + [udevadm_bin]
6240 wait_online_cmd = valgrind_cmd.split() + [wait_online_bin]
6241
6242 if asan_options:
6243 env.update({'ASAN_OPTIONS': asan_options})
6244 if lsan_options:
6245 env.update({'LSAN_OPTIONS': lsan_options})
6246 if ubsan_options:
6247 env.update({'UBSAN_OPTIONS': ubsan_options})
6248 if use_valgrind:
6249 env.update({'SYSTEMD_MEMPOOL': '0'})
6250
6251 wait_online_env = env.copy()
6252 if enable_debug:
6253 wait_online_env.update({'SYSTEMD_LOG_LEVEL': 'debug'})
6254
6255 sys.argv[1:] = unknown_args
6256 unittest.main(verbosity=3)