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