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