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