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