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