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