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