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