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