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