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