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