]> git.ipfire.org Git - thirdparty/systemd.git/blame - test/test-network/systemd-networkd-tests.py
network: refuse to configure IPv4LL for bareudp netdev
[thirdparty/systemd.git] / test / test-network / systemd-networkd-tests.py
CommitLineData
1f0e3109
SS
1#!/usr/bin/env python3
2# SPDX-License-Identifier: LGPL-2.1+
3# systemd-networkd tests
4
9c1ae484 5import argparse
7c0d36ff 6import itertools
1f0e3109 7import os
201bf07f 8import re
1f0e3109
SS
9import shutil
10import signal
a9bc5e37
YW
11import subprocess
12import sys
a9bc5e37
YW
13import time
14import unittest
1f0e3109
SS
15from shutil import copytree
16
d486a2d0 17network_unit_file_path='/run/systemd/network'
bad4969b 18networkd_runtime_directory='/run/systemd/netif'
d486a2d0 19networkd_ci_path='/run/networkd-ci'
1f0e3109
SS
20network_sysctl_ipv6_path='/proc/sys/net/ipv6/conf'
21network_sysctl_ipv4_path='/proc/sys/net/ipv4/conf'
22
d486a2d0
YW
23dnsmasq_pid_file='/run/networkd-ci/test-test-dnsmasq.pid'
24dnsmasq_log_file='/run/networkd-ci/test-dnsmasq-log-file'
1f0e3109 25
7471bcb0
DS
26systemd_lib_paths=['/usr/lib/systemd', '/lib/systemd']
27which_paths=':'.join(systemd_lib_paths + os.getenv('PATH', os.defpath).lstrip(':').split(':'))
28
29networkd_bin=shutil.which('systemd-networkd', path=which_paths)
30resolved_bin=shutil.which('systemd-resolved', path=which_paths)
641aa412 31udevd_bin=shutil.which('systemd-udevd', path=which_paths)
7471bcb0
DS
32wait_online_bin=shutil.which('systemd-networkd-wait-online', path=which_paths)
33networkctl_bin=shutil.which('networkctl', path=which_paths)
34resolvectl_bin=shutil.which('resolvectl', path=which_paths)
35timedatectl_bin=shutil.which('timedatectl', path=which_paths)
36
9c1ae484 37use_valgrind=False
aaae5713 38enable_debug=True
9c1ae484 39env = {}
94c03122 40asan_options=None
fa4c6095 41lsan_options=None
94c03122 42ubsan_options=None
5aa58329 43
2225e7fd
YW
44running_units = []
45
371810d1
ZJS
46def check_output(*command, **kwargs):
47 # This replaces both check_output and check_call (output can be ignored)
48 command = command[0].split() + list(command[1:])
49 return subprocess.check_output(command, universal_newlines=True, **kwargs).rstrip()
50
51def call(*command, **kwargs):
52 command = command[0].split() + list(command[1:])
53 return subprocess.call(command, universal_newlines=True, **kwargs)
54
55def run(*command, **kwargs):
56 command = command[0].split() + list(command[1:])
57 return subprocess.run(command, universal_newlines=True, **kwargs)
58
7a0a37b2 59def is_module_available(module_name):
371810d1
ZJS
60 lsmod_output = check_output('lsmod')
61 module_re = re.compile(rf'^{re.escape(module_name)}\b', re.MULTILINE)
856423f1 62 return module_re.search(lsmod_output) or not call('modprobe', module_name, stderr=subprocess.DEVNULL)
7a0a37b2
EV
63
64def expectedFailureIfModuleIsNotAvailable(module_name):
65 def f(func):
66 if not is_module_available(module_name):
67 return unittest.expectedFailure(func)
68 return func
69
70 return f
71
7bea7f9b
SS
72def expectedFailureIfERSPANModuleIsNotAvailable():
73 def f(func):
856423f1 74 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)
7bea7f9b 75 if rc == 0:
371810d1 76 call('ip link del erspan99')
7bea7f9b
SS
77 return func
78 else:
79 return unittest.expectedFailure(func)
80
81 return f
82
d586a2c3
YW
83def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable():
84 def f(func):
856423f1 85 rc = call('ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7', stderr=subprocess.DEVNULL)
d586a2c3 86 if rc == 0:
371810d1 87 call('ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
d586a2c3
YW
88 return func
89 else:
90 return unittest.expectedFailure(func)
91
92 return f
93
94def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
95 def f(func):
856423f1 96 rc = call('ip rule add not from 192.168.100.19 ipproto tcp table 7', stderr=subprocess.DEVNULL)
d586a2c3 97 if rc == 0:
371810d1 98 call('ip rule del not from 192.168.100.19 ipproto tcp table 7')
d586a2c3
YW
99 return func
100 else:
101 return unittest.expectedFailure(func)
102
103 return f
104
6be8e78e
YW
105def expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable():
106 def f(func):
107 support = False
108 rc = call('ip rule add from 192.168.100.19 table 7 uidrange 200-300', stderr=subprocess.DEVNULL)
109 if rc == 0:
110 ret = run('ip rule list from 192.168.100.19 table 7', stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
111 if ret.returncode == 0 and 'uidrange 200-300' in ret.stdout.rstrip():
112 support = True
113 call('ip rule del from 192.168.100.19 table 7 uidrange 200-300')
114
115 if support:
116 return func
117 else:
118 return unittest.expectedFailure(func)
119
120 return f
121
e28fd95f
YW
122def expectedFailureIfLinkFileFieldIsNotSet():
123 def f(func):
124 support = False
856423f1 125 rc = call('ip link add name dummy99 type dummy', stderr=subprocess.DEVNULL)
e28fd95f
YW
126 if rc == 0:
127 ret = run('udevadm info -w10s /sys/class/net/dummy99', stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
128 if ret.returncode == 0 and 'E: ID_NET_LINK_FILE=' in ret.stdout.rstrip():
129 support = True
130 call('ip link del dummy99')
131
132 if support:
133 return func
134 else:
135 return unittest.expectedFailure(func)
136
137 return f
138
086bcf5d
YW
139def expectedFailureIfNexthopIsNotAvailable():
140 def f(func):
856423f1 141 rc = call('ip nexthop list', stderr=subprocess.DEVNULL)
086bcf5d
YW
142 if rc == 0:
143 return func
144 else:
145 return unittest.expectedFailure(func)
146
147 return f
148
6934ace0
YW
149def expectedFailureIfAlternativeNameIsNotAvailable():
150 def f(func):
151 call('ip link add dummy98 type dummy', stderr=subprocess.DEVNULL)
152 rc = call('ip link prop add dev dummy98 altname hogehogehogehogehoge', stderr=subprocess.DEVNULL)
834ea1a4 153 call('ip link del dummy98', stderr=subprocess.DEVNULL)
6934ace0
YW
154 if rc == 0:
155 return func
156 else:
157 return unittest.expectedFailure(func)
158
159 return f
160
3d2c2692
YW
161def expectedFailureIfNetdevsimWithSRIOVIsNotAvailable():
162 def f(func):
163 call('rmmod netdevsim', stderr=subprocess.DEVNULL)
164 rc = call('modprobe netdevsim', stderr=subprocess.DEVNULL)
165 if rc != 0:
166 return unittest.expectedFailure(func)
167
168 try:
169 with open('/sys/bus/netdevsim/new_device', mode='w') as f:
170 f.write('99 1')
171 except Exception as error:
172 return unittest.expectedFailure(func)
173
174 call('udevadm settle')
175 call('udevadm info -w10s /sys/devices/netdevsim99/net/eni99np1', stderr=subprocess.DEVNULL)
176 try:
177 with open('/sys/class/net/eni99np1/device/sriov_numvfs', mode='w') as f:
178 f.write('3')
179 except Exception as error:
180 call('rmmod netdevsim', stderr=subprocess.DEVNULL)
181 return unittest.expectedFailure(func)
182
183 call('rmmod netdevsim', stderr=subprocess.DEVNULL)
184 return func
185
186 return f
187
f6c6af38
YW
188def expectedFailureIfCAKEIsNotAvailable():
189 def f(func):
190 call('ip link add dummy98 type dummy', stderr=subprocess.DEVNULL)
191 rc = call('tc qdisc add dev dummy98 parent root cake', stderr=subprocess.DEVNULL)
192 call('ip link del dummy98', stderr=subprocess.DEVNULL)
193 if rc == 0:
194 return func
195 else:
196 return unittest.expectedFailure(func)
197
198 return f
199
be94e591
YW
200def expectedFailureIfPIEIsNotAvailable():
201 def f(func):
202 call('ip link add dummy98 type dummy', stderr=subprocess.DEVNULL)
203 rc = call('tc qdisc add dev dummy98 parent root pie', stderr=subprocess.DEVNULL)
204 call('ip link del dummy98', stderr=subprocess.DEVNULL)
205 if rc == 0:
206 return func
207 else:
208 return unittest.expectedFailure(func)
209
210 return f
211
970ab1fc
YW
212def expectedFailureIfHHFIsNotAvailable():
213 def f(func):
214 call('ip link add dummy98 type dummy', stderr=subprocess.DEVNULL)
215 rc = call('tc qdisc add dev dummy98 parent root hhf', stderr=subprocess.DEVNULL)
216 call('ip link del dummy98', stderr=subprocess.DEVNULL)
217 if rc == 0:
218 return func
219 else:
220 return unittest.expectedFailure(func)
221
222 return f
223
b753e835
YW
224def expectedFailureIfETSIsNotAvailable():
225 def f(func):
226 call('ip link add dummy98 type dummy', stderr=subprocess.DEVNULL)
227 rc = call('tc qdisc add dev dummy98 parent root ets bands 10', stderr=subprocess.DEVNULL)
228 call('ip link del dummy98', stderr=subprocess.DEVNULL)
229 if rc == 0:
230 return func
231 else:
232 return unittest.expectedFailure(func)
233
234 return f
235
1f0e3109 236def setUpModule():
2225e7fd
YW
237 global running_units
238
1f0e3109
SS
239 os.makedirs(network_unit_file_path, exist_ok=True)
240 os.makedirs(networkd_ci_path, exist_ok=True)
241
242 shutil.rmtree(networkd_ci_path)
6aea9276 243 copytree(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'conf'), networkd_ci_path)
1f0e3109 244
f7ada4b8
YW
245 for u in ['systemd-networkd.socket', 'systemd-networkd.service', 'systemd-resolved.service',
246 'systemd-udevd-kernel.socket', 'systemd-udevd-control.socket', 'systemd-udevd.service',
247 'firewalld.service']:
2225e7fd
YW
248 if call(f'systemctl is-active --quiet {u}') == 0:
249 check_output(f'systemctl stop {u}')
250 running_units.append(u)
c0bf6733 251
9c1ae484 252 drop_in = [
3e821525
DS
253 '[Unit]',
254 'StartLimitIntervalSec=0',
9c1ae484
YW
255 '[Service]',
256 'Restart=no',
257 'ExecStart=',
258 ]
259 if use_valgrind:
260 drop_in += [
261 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin,
94c03122 262 'PrivateTmp=yes'
9c1ae484
YW
263 ]
264 else:
265 drop_in += ['ExecStart=!!' + networkd_bin]
266 if enable_debug:
267 drop_in += ['Environment=SYSTEMD_LOG_LEVEL=debug']
94c03122
YW
268 if asan_options:
269 drop_in += ['Environment=ASAN_OPTIONS="' + asan_options + '"']
fa4c6095
YW
270 if lsan_options:
271 drop_in += ['Environment=LSAN_OPTIONS="' + lsan_options + '"']
94c03122
YW
272 if ubsan_options:
273 drop_in += ['Environment=UBSAN_OPTIONS="' + ubsan_options + '"']
78690bb5
YW
274 if asan_options or lsan_options or ubsan_options:
275 drop_in += ['SystemCallFilter=']
fa4c6095 276 if use_valgrind or asan_options or lsan_options or ubsan_options:
94c03122 277 drop_in += ['MemoryDenyWriteExecute=no']
9c1ae484 278
9c1ae484
YW
279 os.makedirs('/run/systemd/system/systemd-networkd.service.d', exist_ok=True)
280 with open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode='w') as f:
72917fcc 281 f.write('\n'.join(drop_in))
9c1ae484 282
b6d587d1
YW
283 drop_in = [
284 '[Service]',
285 'Restart=no',
286 'ExecStart=',
287 ]
288 if use_valgrind:
289 drop_in += ['ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + resolved_bin]
290 else:
291 drop_in += ['ExecStart=!!' + resolved_bin]
292 if enable_debug:
293 drop_in += ['Environment=SYSTEMD_LOG_LEVEL=debug']
294 if asan_options:
295 drop_in += ['Environment=ASAN_OPTIONS="' + asan_options + '"']
296 if lsan_options:
297 drop_in += ['Environment=LSAN_OPTIONS="' + lsan_options + '"']
298 if ubsan_options:
299 drop_in += ['Environment=UBSAN_OPTIONS="' + ubsan_options + '"']
300 if asan_options or lsan_options or ubsan_options:
301 drop_in += ['SystemCallFilter=']
302 if use_valgrind or asan_options or lsan_options or ubsan_options:
303 drop_in += ['MemoryDenyWriteExecute=no']
304
305 os.makedirs('/run/systemd/system/systemd-resolved.service.d', exist_ok=True)
306 with open('/run/systemd/system/systemd-resolved.service.d/00-override.conf', mode='w') as f:
307 f.write('\n'.join(drop_in))
308
641aa412
YW
309 drop_in = [
310 '[Service]',
311 'ExecStart=',
312 'ExecStart=!!' + udevd_bin,
313 ]
314
315 os.makedirs('/run/systemd/system/systemd-udevd.service.d', exist_ok=True)
316 with open('/run/systemd/system/systemd-udevd.service.d/00-override.conf', mode='w') as f:
317 f.write('\n'.join(drop_in))
318
371810d1
ZJS
319 check_output('systemctl daemon-reload')
320 print(check_output('systemctl cat systemd-networkd.service'))
b6d587d1 321 print(check_output('systemctl cat systemd-resolved.service'))
641aa412 322 print(check_output('systemctl cat systemd-udevd.service'))
b6d587d1 323 check_output('systemctl restart systemd-resolved')
641aa412 324 check_output('systemctl restart systemd-udevd')
9c1ae484 325
1f0e3109 326def tearDownModule():
2225e7fd
YW
327 global running_units
328
1f0e3109 329 shutil.rmtree(networkd_ci_path)
d4fda2a5 330
3aa645f0 331 for u in ['systemd-networkd.socket', 'systemd-networkd.service', 'systemd-resolved.service']:
2225e7fd 332 check_output(f'systemctl stop {u}')
d4fda2a5 333
9c1ae484 334 shutil.rmtree('/run/systemd/system/systemd-networkd.service.d')
b6d587d1 335 shutil.rmtree('/run/systemd/system/systemd-resolved.service.d')
641aa412 336 shutil.rmtree('/run/systemd/system/systemd-udevd.service.d')
371810d1 337 check_output('systemctl daemon-reload')
f7ada4b8 338 check_output('systemctl restart systemd-udevd.service')
1f0e3109 339
2225e7fd
YW
340 for u in running_units:
341 check_output(f'systemctl start {u}')
c0bf6733 342
befd4b8b
DS
343def read_link_attr(*args):
344 with open(os.path.join('/sys/class/net/', *args)) as f:
ec38833c
ZJS
345 return f.readline().strip()
346
347def read_bridge_port_attr(bridge, link, attribute):
348 path_bridge = os.path.join('/sys/devices/virtual/net', bridge)
349 path_port = 'lower_' + link + '/brport'
350 path = os.path.join(path_bridge, path_port)
351
352 with open(os.path.join(path, attribute)) as f:
353 return f.readline().strip()
354
355def link_exists(link):
356 return os.path.exists(os.path.join('/sys/class/net', link))
357
358def remove_links(links):
359 for link in links:
360 if link_exists(link):
361 call('ip link del dev', link)
362 time.sleep(1)
363
364def remove_fou_ports(ports):
365 for port in ports:
5239d7b3 366 call('ip fou del port', port, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
ec38833c
ZJS
367
368def remove_routing_policy_rule_tables(tables):
369 for table in tables:
4ef39b49
YW
370 rc = 0
371 while rc == 0:
372 rc = call('ip rule del table', table, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
ec38833c
ZJS
373
374def remove_routes(routes):
375 for route_type, addr in routes:
5239d7b3 376 call('ip route del', route_type, addr, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
ec38833c 377
ad78d7b0 378def remove_l2tp_tunnels(tunnel_ids):
ec38833c
ZJS
379 output = check_output('ip l2tp show tunnel')
380 for tid in tunnel_ids:
381 words='Tunnel ' + tid + ', encap'
382 if words in output:
383 call('ip l2tp del tunnel tid', tid)
384 time.sleep(1)
385
386def read_ipv6_sysctl_attr(link, attribute):
387 with open(os.path.join(os.path.join(network_sysctl_ipv6_path, link), attribute)) as f:
388 return f.readline().strip()
389
390def read_ipv4_sysctl_attr(link, attribute):
391 with open(os.path.join(os.path.join(network_sysctl_ipv4_path, link), attribute)) as f:
392 return f.readline().strip()
393
9dfc1a93
DS
394def copy_unit_to_networkd_unit_path(*units, dropins=True):
395 """Copy networkd unit files into the testbed.
396
397 Any networkd unit file type can be specified, as well as drop-in files.
398
399 By default, all drop-ins for a specified unit file are copied in;
400 to avoid that specify dropins=False.
401
402 When a drop-in file is specified, its unit file is also copied in automatically.
403 """
ec38833c
ZJS
404 print()
405 for unit in units:
9dfc1a93 406 if dropins and os.path.exists(os.path.join(networkd_ci_path, unit + '.d')):
ec38833c 407 copytree(os.path.join(networkd_ci_path, unit + '.d'), os.path.join(network_unit_file_path, unit + '.d'))
9dfc1a93
DS
408 if unit.endswith('.conf'):
409 dropin = unit
410 dropindir = os.path.join(network_unit_file_path, os.path.dirname(dropin))
411 os.makedirs(dropindir, exist_ok=True)
412 shutil.copy(os.path.join(networkd_ci_path, dropin), dropindir)
413 unit = os.path.dirname(dropin).rstrip('.d')
414 shutil.copy(os.path.join(networkd_ci_path, unit), network_unit_file_path)
ec38833c
ZJS
415
416def remove_unit_from_networkd_path(units):
9dfc1a93
DS
417 """Remove previously copied unit files from the testbed.
418
419 Drop-ins will be removed automatically.
420 """
ec38833c
ZJS
421 for unit in units:
422 if (os.path.exists(os.path.join(network_unit_file_path, unit))):
423 os.remove(os.path.join(network_unit_file_path, unit))
424 if (os.path.exists(os.path.join(network_unit_file_path, unit + '.d'))):
425 shutil.rmtree(os.path.join(network_unit_file_path, unit + '.d'))
426
ec38833c 427def start_dnsmasq(additional_options='', ipv4_range='192.168.5.10,192.168.5.200', ipv6_range='2600::10,2600::20', lease_time='1h'):
ec38833c
ZJS
428 dnsmasq_command = f'dnsmasq -8 /var/run/networkd-ci/test-dnsmasq-log-file --log-queries=extra --log-dhcp --pid-file=/var/run/networkd-ci/test-test-dnsmasq.pid --conf-file=/dev/null --interface=veth-peer --enable-ra --dhcp-range={ipv6_range},{lease_time} --dhcp-range={ipv4_range},{lease_time} -R --dhcp-leasefile=/var/run/networkd-ci/lease --dhcp-option=26,1492 --dhcp-option=option:router,192.168.5.1 --dhcp-option=33,192.168.5.4,192.168.5.5 --port=0 ' + additional_options
429 check_output(dnsmasq_command)
430
431def stop_dnsmasq(pid_file):
432 if os.path.exists(pid_file):
433 with open(pid_file, 'r') as f:
434 pid = f.read().rstrip(' \t\r\n\0')
435 os.kill(int(pid), signal.SIGTERM)
436
437 os.remove(pid_file)
438
439def search_words_in_dnsmasq_log(words, show_all=False):
440 if os.path.exists(dnsmasq_log_file):
441 with open (dnsmasq_log_file) as in_file:
442 contents = in_file.read()
443 if show_all:
444 print(contents)
445 for line in contents.splitlines():
446 if words in line:
447 in_file.close()
448 print("%s, %s" % (words, line))
449 return True
450 return False
451
452def remove_lease_file():
453 if os.path.exists(os.path.join(networkd_ci_path, 'lease')):
454 os.remove(os.path.join(networkd_ci_path, 'lease'))
455
456def remove_log_file():
457 if os.path.exists(dnsmasq_log_file):
458 os.remove(dnsmasq_log_file)
459
aaae5713
YW
460def remove_networkd_state_files():
461 if os.path.exists(os.path.join(networkd_runtime_directory, 'state')):
ec38833c 462 os.remove(os.path.join(networkd_runtime_directory, 'state'))
aaae5713
YW
463
464def stop_networkd(show_logs=True, remove_state_files=True):
465 if show_logs:
466 invocation_id = check_output('systemctl show systemd-networkd -p InvocationID --value')
3aa645f0
MB
467 check_output('systemctl stop systemd-networkd.socket')
468 check_output('systemctl stop systemd-networkd.service')
aaae5713
YW
469 if show_logs:
470 print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id))
471 if remove_state_files:
472 remove_networkd_state_files()
473
474def start_networkd(sleep_sec=0):
475 check_output('systemctl start systemd-networkd')
ec38833c
ZJS
476 if sleep_sec > 0:
477 time.sleep(sleep_sec)
478
aaae5713
YW
479def restart_networkd(sleep_sec=0, show_logs=True, remove_state_files=True):
480 stop_networkd(show_logs, remove_state_files)
481 start_networkd(sleep_sec)
482
1f0e3109 483
ec38833c 484class Utilities():
e39cc445 485 def check_link_exists(self, link):
ec38833c 486 self.assertTrue(link_exists(link))
2be0b6fc 487
0fc0d85f
DS
488 def check_link_attr(self, *args):
489 self.assertEqual(read_link_attr(*args[:-1]), args[-1]);
490
a4632dc7
DS
491 def wait_operstate(self, link, operstate='degraded', setup_state='configured', setup_timeout=5, fail_assert=True):
492 """Wait for the link to reach the specified operstate and/or setup state.
493
494 Specify None or '' for either operstate or setup_state to ignore that state.
495 This will recheck until the state conditions are met or the timeout expires.
496
497 If the link successfully matches the requested state, this returns True.
498 If this times out waiting for the link to match, the behavior depends on the
499 'fail_assert' parameter; if True, this causes a test assertion failure,
500 otherwise this returns False. The default is to cause assertion failure.
501
502 Note that this function matches on *exactly* the given operstate and setup_state.
503 To wait for a link to reach *or exceed* a given operstate, use wait_online().
504 """
505 if not operstate:
506 operstate = r'\S+'
507 if not setup_state:
508 setup_state = r'\S+'
509
510 for secs in range(setup_timeout + 1):
511 output = check_output(*networkctl_cmd, '-n', '0', 'status', link, env=env)
512 print(output)
513 if re.search(rf'(?m)^\s*State:\s+{operstate}\s+\({setup_state}\)\s*$', output):
514 return True
515 # don't bother sleeping if time is up
516 if secs < setup_timeout:
517 time.sleep(1)
518 if fail_assert:
519 self.fail(f'Timed out waiting for {link} to reach state {operstate}/{setup_state}')
520 return False
2be0b6fc 521
fd372b1a 522 def wait_online(self, links_with_operstate, timeout='20s', bool_any=False, setup_state='configured', setup_timeout=5):
0c020321
DS
523 """Wait for the link(s) to reach the specified operstate and/or setup state.
524
525 This is similar to wait_operstate() but can be used for multiple links,
526 and it also calls systemd-networkd-wait-online to wait for the given operstate.
527 The operstate should be specified in the link name, like 'eth0:degraded'.
528 If just a link name is provided, wait-online's default operstate to wait for is degraded.
529
530 The 'timeout' parameter controls the systemd-networkd-wait-online timeout, and the
531 'setup_timeout' controls the per-link timeout waiting for the setup_state.
532
533 Set 'bool_any' to True to wait for any (instead of all) of the given links.
534 If this is set, no setup_state checks are done.
535
536 Note that this function waits for the link(s) to reach *or exceed* the given operstate.
537 However, the setup_state, if specified, must be matched *exactly*.
538
539 This returns if the link(s) reached the requested operstate/setup_state; otherwise it
540 raises CalledProcessError or fails test assertion.
541 """
e2aea43f
YW
542 args = wait_online_cmd + [f'--timeout={timeout}'] + [f'--interface={link}' for link in links_with_operstate]
543 if bool_any:
544 args += ['--any']
545 try:
546 check_output(*args, env=env)
547 except subprocess.CalledProcessError:
548 for link in links_with_operstate:
fc79e6ff 549 output = check_output(*networkctl_cmd, '-n', '0', 'status', link.split(':')[0], env=env)
e2aea43f
YW
550 print(output)
551 raise
fd372b1a 552 if not bool_any and setup_state:
0c020321
DS
553 for link in links_with_operstate:
554 self.wait_operstate(link.split(':')[0], None, setup_state, setup_timeout)
e2aea43f 555
53c32c2b 556 def wait_address(self, link, address_regex, scope='global', ipv='', timeout_sec=100):
2629df47
YW
557 for i in range(timeout_sec):
558 if i > 0:
559 time.sleep(1)
371810d1 560 output = check_output(f'ip {ipv} address show dev {link} scope {scope}')
571f9539 561 if re.search(address_regex, output) and 'tentative' not in output:
2629df47
YW
562 break
563 else:
564 self.assertRegex(output, address_regex)
565
1ca44d7d
YW
566class NetworkctlTests(unittest.TestCase, Utilities):
567
568 links = [
dcd9f07c 569 'dummy98',
1ca44d7d
YW
570 'test1',
571 'veth99',
572 ]
573
574 units = [
575 '11-dummy.netdev',
6d5b4efe 576 '11-dummy-mtu.netdev',
1ca44d7d 577 '11-dummy.network',
dcd9f07c 578 '12-dummy.netdev',
6934ace0 579 '12-dummy.link',
dcd9f07c 580 '25-address-static.network',
1ca44d7d
YW
581 '25-veth.netdev',
582 'netdev-link-local-addressing-yes.network',
583 ]
584
585 def setUp(self):
ec38833c 586 remove_links(self.links)
aaae5713 587 stop_networkd(show_logs=False)
1ca44d7d
YW
588
589 def tearDown(self):
ec38833c
ZJS
590 remove_links(self.links)
591 remove_unit_from_networkd_path(self.units)
aaae5713 592 stop_networkd(show_logs=True)
1ca44d7d 593
6934ace0
YW
594 @expectedFailureIfAlternativeNameIsNotAvailable()
595 def test_altname(self):
596 copy_unit_to_networkd_unit_path('netdev-link-local-addressing-yes.network', '12-dummy.netdev', '12-dummy.link')
597 check_output('udevadm control --reload')
598 start_networkd()
599 self.wait_online(['dummy98:degraded'])
600
fc79e6ff 601 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98', env=env)
6934ace0
YW
602 self.assertRegex(output, 'hogehogehogehogehogehoge')
603
dcd9f07c
YW
604 def test_reconfigure(self):
605 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
606 start_networkd()
607 self.wait_online(['dummy98:routable'])
608
609 output = check_output('ip -4 address show dev dummy98')
610 print(output)
611 self.assertRegex(output, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
612 self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
613 self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
614
615 check_output('ip address del 10.1.2.3/16 dev dummy98')
616 check_output('ip address del 10.1.2.4/16 dev dummy98')
617 check_output('ip address del 10.2.2.4/16 dev dummy98')
618
619 check_output(*networkctl_cmd, 'reconfigure', 'dummy98', env=env)
620 self.wait_online(['dummy98:routable'])
621
622 output = check_output('ip -4 address show dev dummy98')
623 print(output)
624 self.assertRegex(output, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
625 self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
626 self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
627
66de8671
YW
628 def test_reload(self):
629 start_networkd(3)
630
631 copy_unit_to_networkd_unit_path('11-dummy.netdev')
632 check_output(*networkctl_cmd, 'reload', env=env)
19cf3143 633 self.wait_operstate('test1', 'off', setup_state='unmanaged')
66de8671
YW
634
635 copy_unit_to_networkd_unit_path('11-dummy.network')
636 check_output(*networkctl_cmd, 'reload', env=env)
637 self.wait_online(['test1:degraded'])
638
639 remove_unit_from_networkd_path(['11-dummy.network'])
640 check_output(*networkctl_cmd, 'reload', env=env)
19cf3143 641 self.wait_operstate('test1', 'degraded', setup_state='unmanaged')
66de8671
YW
642
643 remove_unit_from_networkd_path(['11-dummy.netdev'])
644 check_output(*networkctl_cmd, 'reload', env=env)
19cf3143 645 self.wait_operstate('test1', 'degraded', setup_state='unmanaged')
66de8671
YW
646
647 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
648 check_output(*networkctl_cmd, 'reload', env=env)
19cf3143 649 self.wait_operstate('test1', 'degraded')
66de8671 650
1ca44d7d 651 def test_glob(self):
ec38833c 652 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
2cf6fdff 653 start_networkd()
1ca44d7d 654
e2aea43f 655 self.wait_online(['test1:degraded'])
1ca44d7d 656
371810d1 657 output = check_output(*networkctl_cmd, 'list', env=env)
1ca44d7d
YW
658 self.assertRegex(output, '1 lo ')
659 self.assertRegex(output, 'test1')
660
371810d1 661 output = check_output(*networkctl_cmd, 'list', 'test1', env=env)
1ca44d7d
YW
662 self.assertNotRegex(output, '1 lo ')
663 self.assertRegex(output, 'test1')
664
371810d1 665 output = check_output(*networkctl_cmd, 'list', 'te*', env=env)
1ca44d7d
YW
666 self.assertNotRegex(output, '1 lo ')
667 self.assertRegex(output, 'test1')
668
fc79e6ff 669 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'te*', env=env)
1ca44d7d
YW
670 self.assertNotRegex(output, '1: lo ')
671 self.assertRegex(output, 'test1')
672
fc79e6ff 673 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'tes[a-z][0-9]', env=env)
1ca44d7d
YW
674 self.assertNotRegex(output, '1: lo ')
675 self.assertRegex(output, 'test1')
676
6d5b4efe 677 def test_mtu(self):
ec38833c 678 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
2cf6fdff 679 start_networkd()
6d5b4efe 680
e2aea43f 681 self.wait_online(['test1:degraded'])
6d5b4efe 682
fc79e6ff 683 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'test1', env=env)
6d5b4efe
YW
684 self.assertRegex(output, 'MTU: 1600')
685
e28fd95f
YW
686 def test_type(self):
687 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
688 start_networkd()
e2aea43f 689 self.wait_online(['test1:degraded'])
e28fd95f 690
fc79e6ff 691 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'test1', env=env)
e28fd95f
YW
692 print(output)
693 self.assertRegex(output, 'Type: ether')
694
fc79e6ff 695 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'lo', env=env)
e28fd95f
YW
696 print(output)
697 self.assertRegex(output, 'Type: loopback')
698
699 @expectedFailureIfLinkFileFieldIsNotSet()
700 def test_udev_link_file(self):
701 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
702 start_networkd()
e2aea43f 703 self.wait_online(['test1:degraded'])
e28fd95f 704
fc79e6ff 705 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'test1', env=env)
e28fd95f 706 print(output)
426654d7 707 self.assertRegex(output, r'Link File: (/usr)?/lib/systemd/network/99-default.link')
e28fd95f
YW
708 self.assertRegex(output, r'Network File: /run/systemd/network/11-dummy.network')
709
fc79e6ff 710 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'lo', env=env)
e28fd95f 711 print(output)
426654d7 712 self.assertRegex(output, r'Link File: (/usr)?/lib/systemd/network/99-default.link')
e28fd95f
YW
713 self.assertRegex(output, r'Network File: n/a')
714
bee692fd 715 def test_delete_links(self):
ec38833c
ZJS
716 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
717 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
2cf6fdff 718 start_networkd()
bee692fd 719
e2aea43f 720 self.wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
bee692fd 721
7a2f6fb6 722 check_output(*networkctl_cmd, 'delete', 'test1', 'veth99', env=env)
ec38833c
ZJS
723 self.assertFalse(link_exists('test1'))
724 self.assertFalse(link_exists('veth99'))
725 self.assertFalse(link_exists('veth-peer'))
bee692fd 726
1f0e3109
SS
727class NetworkdNetDevTests(unittest.TestCase, Utilities):
728
e64dc406
YW
729 links_remove_earlier = [
730 'xfrm99',
731 ]
732
733 links = [
09ea6724
YW
734 '6rdtun99',
735 'bond99',
736 'bridge99',
737 'dropin-test',
738 'dummy98',
6a97a864
YW
739 'erspan98',
740 'erspan99',
09ea6724 741 'geneve99',
4b6a6d1e 742 'gretap96',
6a97a864 743 'gretap98',
09ea6724 744 'gretap99',
4b6a6d1e 745 'gretun96',
6a97a864
YW
746 'gretun97',
747 'gretun98',
09ea6724 748 'gretun99',
b076d5d7 749 'ifb99',
6a97a864 750 'ip6gretap98',
09ea6724 751 'ip6gretap99',
42a29fcb 752 'ip6gretun96',
6a97a864
YW
753 'ip6gretun97',
754 'ip6gretun98',
755 'ip6gretun99',
756 'ip6tnl97',
757 'ip6tnl98',
09ea6724 758 'ip6tnl99',
4b6a6d1e 759 'ipiptun96',
6a97a864
YW
760 'ipiptun97',
761 'ipiptun98',
09ea6724
YW
762 'ipiptun99',
763 'ipvlan99',
956c8fec 764 'ipvtap99',
09ea6724
YW
765 'isataptun99',
766 'macvlan99',
767 'macvtap99',
811f33d0 768 'nlmon99',
4b6a6d1e 769 'sittun96',
6a97a864
YW
770 'sittun97',
771 'sittun98',
09ea6724
YW
772 'sittun99',
773 'tap99',
774 'test1',
775 'tun99',
776 'vcan99',
777 'veth99',
778 'vlan99',
779 'vrf99',
6a97a864
YW
780 'vti6tun97',
781 'vti6tun98',
09ea6724 782 'vti6tun99',
42a29fcb 783 'vtitun96',
6a97a864
YW
784 'vtitun97',
785 'vtitun98',
09ea6724 786 'vtitun99',
f63b14d3 787 'vxcan99',
09ea6724 788 'vxlan99',
da3509f0 789 'wg97',
da44fb8a 790 'wg98',
e64dc406
YW
791 'wg99',
792 ]
09ea6724
YW
793
794 units = [
795 '10-dropin-test.netdev',
796 '11-dummy.netdev',
03db80b2 797 '11-dummy.network',
09ea6724 798 '12-dummy.netdev',
6b9518a0
YW
799 '13-not-match-udev-property.network',
800 '14-match-udev-property.network',
753e0a24 801 '15-name-conflict-test.netdev',
09ea6724
YW
802 '21-macvlan.netdev',
803 '21-macvtap.netdev',
7f45d738 804 '21-vlan-test1.network',
09ea6724
YW
805 '21-vlan.netdev',
806 '21-vlan.network',
807 '25-6rd-tunnel.netdev',
808 '25-bond.netdev',
fde60a42 809 '25-bond-balanced-tlb.netdev',
09ea6724 810 '25-bridge.netdev',
1285edf3 811 '25-bridge-configure-without-carrier.network',
03db80b2 812 '25-bridge.network',
6a97a864 813 '25-erspan-tunnel-local-any.netdev',
09ea6724 814 '25-erspan-tunnel.netdev',
4b6a6d1e
YW
815 '25-fou-gretap.netdev',
816 '25-fou-gre.netdev',
817 '25-fou-ipip.netdev',
818 '25-fou-ipproto-gre.netdev',
819 '25-fou-ipproto-ipip.netdev',
820 '25-fou-sit.netdev',
09ea6724 821 '25-geneve.netdev',
6a97a864 822 '25-gretap-tunnel-local-any.netdev',
09ea6724 823 '25-gretap-tunnel.netdev',
42a29fcb 824 '25-gre-tunnel-any-any.netdev',
6a97a864
YW
825 '25-gre-tunnel-local-any.netdev',
826 '25-gre-tunnel-remote-any.netdev',
09ea6724 827 '25-gre-tunnel.netdev',
b076d5d7 828 '25-ifb.netdev',
6a97a864
YW
829 '25-ip6gretap-tunnel-local-any.netdev',
830 '25-ip6gretap-tunnel.netdev',
42a29fcb 831 '25-ip6gre-tunnel-any-any.netdev',
6a97a864
YW
832 '25-ip6gre-tunnel-local-any.netdev',
833 '25-ip6gre-tunnel-remote-any.netdev',
09ea6724 834 '25-ip6gre-tunnel.netdev',
42a29fcb 835 '25-ip6tnl-tunnel-any-any.netdev',
6a97a864 836 '25-ip6tnl-tunnel-local-any.netdev',
42a29fcb 837 '25-ip6tnl-tunnel-remote-any.netdev',
09ea6724 838 '25-ip6tnl-tunnel.netdev',
42a29fcb 839 '25-ipip-tunnel-any-any.netdev',
09ea6724 840 '25-ipip-tunnel-independent.netdev',
95082dbe 841 '25-ipip-tunnel-independent-loopback.netdev',
6a97a864
YW
842 '25-ipip-tunnel-local-any.netdev',
843 '25-ipip-tunnel-remote-any.netdev',
09ea6724
YW
844 '25-ipip-tunnel.netdev',
845 '25-ipvlan.netdev',
956c8fec 846 '25-ipvtap.netdev',
09ea6724 847 '25-isatap-tunnel.netdev',
02849d8b
YW
848 '25-macsec.key',
849 '25-macsec.netdev',
850 '25-macsec.network',
811f33d0 851 '25-nlmon.netdev',
42a29fcb 852 '25-sit-tunnel-any-any.netdev',
6a97a864
YW
853 '25-sit-tunnel-local-any.netdev',
854 '25-sit-tunnel-remote-any.netdev',
09ea6724
YW
855 '25-sit-tunnel.netdev',
856 '25-tap.netdev',
857 '25-tun.netdev',
11309591
YW
858 '25-tunnel-local-any.network',
859 '25-tunnel-remote-any.network',
860 '25-tunnel.network',
09ea6724
YW
861 '25-vcan.netdev',
862 '25-veth.netdev',
863 '25-vrf.netdev',
42a29fcb 864 '25-vti6-tunnel-any-any.netdev',
6a97a864
YW
865 '25-vti6-tunnel-local-any.netdev',
866 '25-vti6-tunnel-remote-any.netdev',
09ea6724 867 '25-vti6-tunnel.netdev',
42a29fcb 868 '25-vti-tunnel-any-any.netdev',
6a97a864
YW
869 '25-vti-tunnel-local-any.netdev',
870 '25-vti-tunnel-remote-any.netdev',
09ea6724 871 '25-vti-tunnel.netdev',
f63b14d3 872 '25-vxcan.netdev',
09ea6724 873 '25-vxlan.netdev',
da44fb8a
YW
874 '25-wireguard-23-peers.netdev',
875 '25-wireguard-23-peers.network',
da3509f0
YW
876 '25-wireguard-no-peer.netdev',
877 '25-wireguard-no-peer.network',
9e5d79e7 878 '25-wireguard-preshared-key.txt',
39bcff3b 879 '25-wireguard-private-key.txt',
09ea6724 880 '25-wireguard.netdev',
5a0bd90b 881 '25-wireguard.network',
e64dc406
YW
882 '25-xfrm.netdev',
883 '25-xfrm-independent.netdev',
09ea6724 884 '6rd.network',
6730a1f3 885 'erspan.network',
09ea6724
YW
886 'gre.network',
887 'gretap.network',
888 'gretun.network',
889 'ip6gretap.network',
6a97a864 890 'ip6gretun.network',
09ea6724
YW
891 'ip6tnl.network',
892 'ipip.network',
893 'ipvlan.network',
956c8fec 894 'ipvtap.network',
09ea6724 895 'isatap.network',
02849d8b 896 'macsec.network',
09ea6724
YW
897 'macvlan.network',
898 'macvtap.network',
077f9abc 899 'netdev-link-local-addressing-yes.network',
09ea6724
YW
900 'sit.network',
901 'vti6.network',
902 'vti.network',
1c862fe0 903 'vxlan-test1.network',
e64dc406
YW
904 'vxlan.network',
905 'xfrm.network',
906 ]
1f0e3109 907
def9fc0d
YW
908 fou_ports = [
909 '55555',
910 '55556']
911
1f0e3109 912 def setUp(self):
ec38833c 913 remove_fou_ports(self.fou_ports)
e64dc406 914 remove_links(self.links_remove_earlier)
ec38833c 915 remove_links(self.links)
aaae5713 916 stop_networkd(show_logs=False)
1f0e3109
SS
917
918 def tearDown(self):
ec38833c 919 remove_fou_ports(self.fou_ports)
e64dc406 920 remove_links(self.links_remove_earlier)
ec38833c
ZJS
921 remove_links(self.links)
922 remove_unit_from_networkd_path(self.units)
aaae5713 923 stop_networkd(show_logs=True)
1f0e3109 924
1ca44d7d 925 def test_dropin_and_name_conflict(self):
ec38833c 926 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
2cf6fdff 927 start_networkd()
d80734f7 928
e2aea43f 929 self.wait_online(['dropin-test:off'], setup_state='unmanaged')
d80734f7 930
371810d1 931 output = check_output('ip link show dropin-test')
d80734f7
YW
932 print(output)
933 self.assertRegex(output, '00:50:56:c0:00:28')
934
6b9518a0
YW
935 def test_match_udev_property(self):
936 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
937 start_networkd()
e2aea43f 938 self.wait_online(['dummy98:routable'])
6b9518a0 939
fc79e6ff 940 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98', env=env)
6b9518a0
YW
941 print(output)
942 self.assertRegex(output, 'Network File: /run/systemd/network/14-match-udev-property')
943
03db80b2 944 def test_wait_online_any(self):
ec38833c 945 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
2cf6fdff 946 start_networkd()
03db80b2 947
e2aea43f 948 self.wait_online(['bridge99', 'test1:degraded'], bool_any=True)
03db80b2 949
19cf3143
DS
950 self.wait_operstate('bridge99', '(off|no-carrier)', setup_state='configuring')
951 self.wait_operstate('test1', 'degraded')
03db80b2 952
1f0e3109 953 def test_bridge(self):
1285edf3 954 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
2cf6fdff 955 start_networkd()
1f0e3109 956
e2aea43f 957 self.wait_online(['bridge99:no-carrier'])
1f0e3109 958
3d165124 959 tick = os.sysconf('SC_CLK_TCK')
ec38833c
ZJS
960 self.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick))
961 self.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick))
c9047092
YW
962 self.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'forward_delay')) / tick))
963 self.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'ageing_time')) / tick))
964 self.assertEqual(9, int(read_link_attr('bridge99', 'bridge', 'priority')))
965 self.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_querier')))
966 self.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_snooping')))
967 self.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'stp_state')))
968 self.assertEqual(3, int(read_link_attr('bridge99', 'bridge', 'multicast_igmp_version')))
1f0e3109 969
fc79e6ff 970 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'bridge99', env=env)
36bc2ffb
YW
971 print(output)
972 self.assertRegex(output, 'Priority: 9')
973 self.assertRegex(output, 'STP: yes')
974 self.assertRegex(output, 'Multicast IGMP Version: 3')
975
1f0e3109 976 def test_bond(self):
ec38833c 977 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
2cf6fdff 978 start_networkd()
ec38833c 979
e2aea43f 980 self.wait_online(['bond99:off', 'bond98:off'], setup_state='unmanaged')
ec38833c
ZJS
981
982 self.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
983 self.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
984 self.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
985 self.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
986 self.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
987 self.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
988 self.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
989 self.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
990 self.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
991 self.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
992 self.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
993
994 self.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
995 self.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
fde60a42 996
1f0e3109 997 def test_vlan(self):
ec38833c
ZJS
998 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
999 '21-vlan.network', '21-vlan-test1.network')
2cf6fdff 1000 start_networkd()
1f0e3109 1001
e2aea43f 1002 self.wait_online(['test1:degraded', 'vlan99:routable'])
1f0e3109 1003
371810d1 1004 output = check_output('ip -d link show test1')
72b7f1b9 1005 print(output)
7d7be1b9 1006 self.assertRegex(output, ' mtu 2000 ')
72b7f1b9 1007
371810d1 1008 output = check_output('ip -d link show vlan99')
14ecd604 1009 print(output)
06895a1d
YW
1010 self.assertRegex(output, ' mtu 2000 ')
1011 self.assertRegex(output, 'REORDER_HDR')
1012 self.assertRegex(output, 'LOOSE_BINDING')
1013 self.assertRegex(output, 'GVRP')
1014 self.assertRegex(output, 'MVRP')
1015 self.assertRegex(output, ' id 99 ')
1f0e3109 1016
371810d1 1017 output = check_output('ip -4 address show dev test1')
7f45d738
YW
1018 print(output)
1019 self.assertRegex(output, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
1020 self.assertRegex(output, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
1021
371810d1 1022 output = check_output('ip -4 address show dev vlan99')
7f45d738
YW
1023 print(output)
1024 self.assertRegex(output, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
1025
1f0e3109 1026 def test_macvtap(self):
460feb61
YW
1027 for mode in ['private', 'vepa', 'bridge', 'passthru']:
1028 with self.subTest(mode=mode):
1029 if mode != 'private':
1030 self.tearDown()
ec38833c
ZJS
1031 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
1032 '11-dummy.netdev', 'macvtap.network')
460feb61
YW
1033 with open(os.path.join(network_unit_file_path, '21-macvtap.netdev'), mode='a') as f:
1034 f.write('[MACVTAP]\nMode=' + mode)
2cf6fdff 1035 start_networkd()
1f0e3109 1036
e2aea43f 1037 self.wait_online(['macvtap99:degraded', 'test1:degraded'])
460feb61 1038
371810d1 1039 output = check_output('ip -d link show macvtap99')
460feb61
YW
1040 print(output)
1041 self.assertRegex(output, 'macvtap mode ' + mode + ' ')
1f0e3109
SS
1042
1043 def test_macvlan(self):
dff9792b
YW
1044 for mode in ['private', 'vepa', 'bridge', 'passthru']:
1045 with self.subTest(mode=mode):
1046 if mode != 'private':
1047 self.tearDown()
ec38833c
ZJS
1048 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
1049 '11-dummy.netdev', 'macvlan.network')
dff9792b
YW
1050 with open(os.path.join(network_unit_file_path, '21-macvlan.netdev'), mode='a') as f:
1051 f.write('[MACVLAN]\nMode=' + mode)
2cf6fdff 1052 start_networkd()
dff9792b 1053
e2aea43f 1054 self.wait_online(['macvlan99:degraded', 'test1:degraded'])
dff9792b 1055
371810d1 1056 output = check_output('ip -d link show test1')
dff9792b
YW
1057 print(output)
1058 self.assertRegex(output, ' mtu 2000 ')
72b7f1b9 1059
371810d1 1060 output = check_output('ip -d link show macvlan99')
dff9792b
YW
1061 print(output)
1062 self.assertRegex(output, ' mtu 2000 ')
1063 self.assertRegex(output, 'macvlan mode ' + mode + ' ')
72b7f1b9 1064
7a0a37b2 1065 @expectedFailureIfModuleIsNotAvailable('ipvlan')
1f0e3109 1066 def test_ipvlan(self):
bc6dff6e
YW
1067 for mode, flag in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1068 with self.subTest(mode=mode, flag=flag):
1069 if mode != 'L2':
1070 self.tearDown()
ec38833c
ZJS
1071 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
1072 '11-dummy.netdev', 'ipvlan.network')
bc6dff6e
YW
1073 with open(os.path.join(network_unit_file_path, '25-ipvlan.netdev'), mode='a') as f:
1074 f.write('[IPVLAN]\nMode=' + mode + '\nFlags=' + flag)
1f0e3109 1075
2cf6fdff 1076 start_networkd()
e2aea43f 1077 self.wait_online(['ipvlan99:degraded', 'test1:degraded'])
bc6dff6e 1078
371810d1 1079 output = check_output('ip -d link show ipvlan99')
bc6dff6e
YW
1080 print(output)
1081 self.assertRegex(output, 'ipvlan *mode ' + mode.lower() + ' ' + flag)
1f0e3109 1082
956c8fec
YW
1083 @expectedFailureIfModuleIsNotAvailable('ipvtap')
1084 def test_ipvtap(self):
40921f08
YW
1085 for mode, flag in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
1086 with self.subTest(mode=mode, flag=flag):
1087 if mode != 'L2':
1088 self.tearDown()
ec38833c
ZJS
1089 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
1090 '11-dummy.netdev', 'ipvtap.network')
40921f08
YW
1091 with open(os.path.join(network_unit_file_path, '25-ipvtap.netdev'), mode='a') as f:
1092 f.write('[IPVTAP]\nMode=' + mode + '\nFlags=' + flag)
1093
2cf6fdff 1094 start_networkd()
e2aea43f 1095 self.wait_online(['ipvtap99:degraded', 'test1:degraded'])
956c8fec 1096
371810d1 1097 output = check_output('ip -d link show ipvtap99')
40921f08
YW
1098 print(output)
1099 self.assertRegex(output, 'ipvtap *mode ' + mode.lower() + ' ' + flag)
956c8fec 1100
1f0e3109 1101 def test_veth(self):
ec38833c 1102 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
2cf6fdff 1103 start_networkd()
1f0e3109 1104
e2aea43f 1105 self.wait_online(['veth99:degraded', 'veth-peer:degraded'])
671dacdf 1106
371810d1 1107 output = check_output('ip -d link show veth99')
671dacdf
YW
1108 print(output)
1109 self.assertRegex(output, 'link/ether 12:34:56:78:9a:bc')
371810d1 1110 output = check_output('ip -d link show veth-peer')
671dacdf
YW
1111 print(output)
1112 self.assertRegex(output, 'link/ether 12:34:56:78:9a:bd')
1f0e3109 1113
1f0e3109 1114 def test_tun(self):
ec38833c 1115 copy_unit_to_networkd_unit_path('25-tun.netdev')
2cf6fdff 1116 start_networkd()
1f0e3109 1117
e2aea43f 1118 self.wait_online(['tun99:off'], setup_state='unmanaged')
1f0e3109 1119
371810d1 1120 output = check_output('ip -d link show tun99')
2746d307
YW
1121 print(output)
1122 # Old ip command does not support IFF_ flags
426654d7 1123 self.assertRegex(output, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
2746d307 1124
1f0e3109 1125 def test_tap(self):
ec38833c 1126 copy_unit_to_networkd_unit_path('25-tap.netdev')
2cf6fdff 1127 start_networkd()
1f0e3109 1128
e2aea43f 1129 self.wait_online(['tap99:off'], setup_state='unmanaged')
1f0e3109 1130
371810d1 1131 output = check_output('ip -d link show tap99')
2746d307
YW
1132 print(output)
1133 # Old ip command does not support IFF_ flags
426654d7 1134 self.assertRegex(output, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
2746d307 1135
7a0a37b2 1136 @expectedFailureIfModuleIsNotAvailable('vrf')
1f0e3109 1137 def test_vrf(self):
ec38833c 1138 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
2cf6fdff 1139 start_networkd()
1f0e3109 1140
e2aea43f 1141 self.wait_online(['vrf99:carrier'])
1f0e3109 1142
7a0a37b2 1143 @expectedFailureIfModuleIsNotAvailable('vcan')
1f0e3109 1144 def test_vcan(self):
ec38833c 1145 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
2cf6fdff 1146 start_networkd()
1f0e3109 1147
e2aea43f 1148 self.wait_online(['vcan99:carrier'])
1f0e3109 1149
f63b14d3
YW
1150 @expectedFailureIfModuleIsNotAvailable('vxcan')
1151 def test_vxcan(self):
ec38833c 1152 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
2cf6fdff 1153 start_networkd()
f63b14d3 1154
e2aea43f 1155 self.wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
f63b14d3 1156
7a3bc5a8
EV
1157 @expectedFailureIfModuleIsNotAvailable('wireguard')
1158 def test_wireguard(self):
ec38833c
ZJS
1159 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
1160 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
da3509f0
YW
1161 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt',
1162 '25-wireguard-no-peer.netdev', '25-wireguard-no-peer.network')
2cf6fdff 1163 start_networkd()
da3509f0 1164 self.wait_online(['wg99:carrier', 'wg98:routable', 'wg97:carrier'])
5a0bd90b 1165
7a3bc5a8 1166 if shutil.which('wg'):
371810d1 1167 call('wg')
5a0bd90b 1168
371810d1 1169 output = check_output('wg show wg99 listen-port')
06895a1d 1170 self.assertRegex(output, '51820')
371810d1 1171 output = check_output('wg show wg99 fwmark')
06895a1d 1172 self.assertRegex(output, '0x4d2')
371810d1 1173 output = check_output('wg show wg99 allowed-ips')
88aaf89e
ZJS
1174 self.assertRegex(output, r'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
1175 self.assertRegex(output, r'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
371810d1 1176 output = check_output('wg show wg99 persistent-keepalive')
88aaf89e 1177 self.assertRegex(output, r'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
371810d1 1178 output = check_output('wg show wg99 endpoints')
88aaf89e 1179 self.assertRegex(output, r'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
371810d1 1180 output = check_output('wg show wg99 private-key')
88aaf89e 1181 self.assertRegex(output, r'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
371810d1 1182 output = check_output('wg show wg99 preshared-keys')
88aaf89e
ZJS
1183 self.assertRegex(output, r'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
1184 self.assertRegex(output, r'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
7a3bc5a8 1185
371810d1 1186 output = check_output('wg show wg98 private-key')
88aaf89e 1187 self.assertRegex(output, r'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
da44fb8a 1188
da3509f0
YW
1189 output = check_output('wg show wg97 listen-port')
1190 self.assertRegex(output, '51821')
1191 output = check_output('wg show wg97 fwmark')
1192 self.assertRegex(output, '0x4d3')
1193
1f0e3109 1194 def test_geneve(self):
ec38833c 1195 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
2cf6fdff 1196 start_networkd()
1f0e3109 1197
e2aea43f 1198 self.wait_online(['geneve99:degraded'])
1f0e3109 1199
371810d1 1200 output = check_output('ip -d link show geneve99')
14ecd604 1201 print(output)
06895a1d
YW
1202 self.assertRegex(output, '192.168.22.1')
1203 self.assertRegex(output, '6082')
1204 self.assertRegex(output, 'udpcsum')
1205 self.assertRegex(output, 'udp6zerocsumrx')
1f0e3109
SS
1206
1207 def test_ipip_tunnel(self):
ec38833c
ZJS
1208 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
1209 '25-ipip-tunnel.netdev', '25-tunnel.network',
1210 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
42a29fcb
YW
1211 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1212 '25-ipip-tunnel-any-any.netdev', '25-tunnel-any-any.network')
2cf6fdff 1213 start_networkd()
e2aea43f 1214 self.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'ipiptun96:routable', 'dummy98:degraded'])
6a97a864 1215
371810d1 1216 output = check_output('ip -d link show ipiptun99')
6a97a864 1217 print(output)
426654d7 1218 self.assertRegex(output, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98')
371810d1 1219 output = check_output('ip -d link show ipiptun98')
6a97a864 1220 print(output)
426654d7 1221 self.assertRegex(output, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98')
371810d1 1222 output = check_output('ip -d link show ipiptun97')
6a97a864 1223 print(output)
426654d7 1224 self.assertRegex(output, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98')
42a29fcb
YW
1225 output = check_output('ip -d link show ipiptun96')
1226 print(output)
426654d7 1227 self.assertRegex(output, 'ipip (ipip )?remote any local any dev dummy98')
1f0e3109
SS
1228
1229 def test_gre_tunnel(self):
ec38833c
ZJS
1230 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
1231 '25-gre-tunnel.netdev', '25-tunnel.network',
1232 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
42a29fcb
YW
1233 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1234 '25-gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
2cf6fdff 1235 start_networkd()
e2aea43f 1236 self.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'gretun96:routable', 'dummy98:degraded'])
6a97a864 1237
371810d1 1238 output = check_output('ip -d link show gretun99')
6a97a864
YW
1239 print(output)
1240 self.assertRegex(output, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
38f4bb44
YW
1241 self.assertRegex(output, 'ikey 1.2.3.103')
1242 self.assertRegex(output, 'okey 1.2.4.103')
1243 self.assertRegex(output, 'iseq')
1244 self.assertRegex(output, 'oseq')
371810d1 1245 output = check_output('ip -d link show gretun98')
6a97a864
YW
1246 print(output)
1247 self.assertRegex(output, 'gre remote 10.65.223.239 local any dev dummy98')
38f4bb44
YW
1248 self.assertRegex(output, 'ikey 0.0.0.104')
1249 self.assertRegex(output, 'okey 0.0.0.104')
1250 self.assertNotRegex(output, 'iseq')
1251 self.assertNotRegex(output, 'oseq')
371810d1 1252 output = check_output('ip -d link show gretun97')
6a97a864
YW
1253 print(output)
1254 self.assertRegex(output, 'gre remote any local 10.65.223.238 dev dummy98')
38f4bb44
YW
1255 self.assertRegex(output, 'ikey 0.0.0.105')
1256 self.assertRegex(output, 'okey 0.0.0.105')
1257 self.assertNotRegex(output, 'iseq')
1258 self.assertNotRegex(output, 'oseq')
42a29fcb
YW
1259 output = check_output('ip -d link show gretun96')
1260 print(output)
1261 self.assertRegex(output, 'gre remote any local any dev dummy98')
1262 self.assertRegex(output, 'ikey 0.0.0.106')
1263 self.assertRegex(output, 'okey 0.0.0.106')
1264 self.assertNotRegex(output, 'iseq')
1265 self.assertNotRegex(output, 'oseq')
6a97a864
YW
1266
1267 def test_ip6gre_tunnel(self):
ec38833c
ZJS
1268 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
1269 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
1270 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
42a29fcb
YW
1271 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1272 '25-ip6gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
01943d43 1273 start_networkd(5)
6a97a864 1274
17bcf0a0
YW
1275 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1276
e39cc445
YW
1277 self.check_link_exists('dummy98')
1278 self.check_link_exists('ip6gretun99')
1279 self.check_link_exists('ip6gretun98')
1280 self.check_link_exists('ip6gretun97')
42a29fcb 1281 self.check_link_exists('ip6gretun96')
6a97a864 1282
371810d1 1283 output = check_output('ip -d link show ip6gretun99')
6a97a864
YW
1284 print(output)
1285 self.assertRegex(output, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
371810d1 1286 output = check_output('ip -d link show ip6gretun98')
6a97a864
YW
1287 print(output)
1288 self.assertRegex(output, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
371810d1 1289 output = check_output('ip -d link show ip6gretun97')
6a97a864
YW
1290 print(output)
1291 self.assertRegex(output, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
42a29fcb
YW
1292 output = check_output('ip -d link show ip6gretun96')
1293 print(output)
1294 self.assertRegex(output, 'ip6gre remote any local any dev dummy98')
1f0e3109 1295
11309591 1296 def test_gretap_tunnel(self):
ec38833c
ZJS
1297 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
1298 '25-gretap-tunnel.netdev', '25-tunnel.network',
1299 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
2cf6fdff 1300 start_networkd()
e2aea43f 1301 self.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
6a97a864 1302
371810d1 1303 output = check_output('ip -d link show gretap99')
6a97a864
YW
1304 print(output)
1305 self.assertRegex(output, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
38f4bb44
YW
1306 self.assertRegex(output, 'ikey 0.0.0.106')
1307 self.assertRegex(output, 'okey 0.0.0.106')
1308 self.assertRegex(output, 'iseq')
1309 self.assertRegex(output, 'oseq')
371810d1 1310 output = check_output('ip -d link show gretap98')
6a97a864
YW
1311 print(output)
1312 self.assertRegex(output, 'gretap remote 10.65.223.239 local any dev dummy98')
38f4bb44
YW
1313 self.assertRegex(output, 'ikey 0.0.0.107')
1314 self.assertRegex(output, 'okey 0.0.0.107')
1315 self.assertRegex(output, 'iseq')
1316 self.assertRegex(output, 'oseq')
1f0e3109
SS
1317
1318 def test_ip6gretap_tunnel(self):
ec38833c
ZJS
1319 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
1320 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1321 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
2cf6fdff 1322 start_networkd()
e2aea43f 1323 self.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
6a97a864 1324
371810d1 1325 output = check_output('ip -d link show ip6gretap99')
6a97a864
YW
1326 print(output)
1327 self.assertRegex(output, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
371810d1 1328 output = check_output('ip -d link show ip6gretap98')
6a97a864
YW
1329 print(output)
1330 self.assertRegex(output, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1f0e3109
SS
1331
1332 def test_vti_tunnel(self):
ec38833c
ZJS
1333 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
1334 '25-vti-tunnel.netdev', '25-tunnel.network',
1335 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
42a29fcb
YW
1336 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1337 '25-vti-tunnel-any-any.netdev', '25-tunnel-any-any.network')
2cf6fdff 1338 start_networkd()
e2aea43f 1339 self.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'vtitun96:routable', 'dummy98:degraded'])
6a97a864 1340
371810d1 1341 output = check_output('ip -d link show vtitun99')
6a97a864
YW
1342 print(output)
1343 self.assertRegex(output, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
371810d1 1344 output = check_output('ip -d link show vtitun98')
6a97a864
YW
1345 print(output)
1346 self.assertRegex(output, 'vti remote 10.65.223.239 local any dev dummy98')
371810d1 1347 output = check_output('ip -d link show vtitun97')
6a97a864
YW
1348 print(output)
1349 self.assertRegex(output, 'vti remote any local 10.65.223.238 dev dummy98')
42a29fcb
YW
1350 output = check_output('ip -d link show vtitun96')
1351 print(output)
1352 self.assertRegex(output, 'vti remote any local any dev dummy98')
1f0e3109
SS
1353
1354 def test_vti6_tunnel(self):
ec38833c
ZJS
1355 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
1356 '25-vti6-tunnel.netdev', '25-tunnel.network',
1357 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1358 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
2cf6fdff 1359 start_networkd()
e2aea43f 1360 self.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
6a97a864 1361
371810d1 1362 output = check_output('ip -d link show vti6tun99')
6a97a864
YW
1363 print(output)
1364 self.assertRegex(output, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
371810d1 1365 output = check_output('ip -d link show vti6tun98')
6a97a864 1366 print(output)
426654d7 1367 self.assertRegex(output, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
371810d1 1368 output = check_output('ip -d link show vti6tun97')
6a97a864 1369 print(output)
426654d7 1370 self.assertRegex(output, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1f0e3109
SS
1371
1372 def test_ip6tnl_tunnel(self):
ec38833c
ZJS
1373 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
1374 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1375 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1376 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
2cf6fdff 1377 start_networkd()
e2aea43f 1378 self.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
6a97a864 1379
371810d1 1380 output = check_output('ip -d link show ip6tnl99')
6a97a864
YW
1381 print(output)
1382 self.assertRegex(output, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
371810d1 1383 output = check_output('ip -d link show ip6tnl98')
6a97a864 1384 print(output)
426654d7 1385 self.assertRegex(output, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
371810d1 1386 output = check_output('ip -d link show ip6tnl97')
6a97a864 1387 print(output)
426654d7 1388 self.assertRegex(output, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1f0e3109
SS
1389
1390 def test_sit_tunnel(self):
ec38833c
ZJS
1391 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1392 '25-sit-tunnel.netdev', '25-tunnel.network',
1393 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
42a29fcb
YW
1394 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1395 '25-sit-tunnel-any-any.netdev', '25-tunnel-any-any.network')
2cf6fdff 1396 start_networkd()
e2aea43f 1397 self.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'sittun96:routable', 'dummy98:degraded'])
6a97a864 1398
371810d1 1399 output = check_output('ip -d link show sittun99')
6a97a864 1400 print(output)
426654d7 1401 self.assertRegex(output, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98")
371810d1 1402 output = check_output('ip -d link show sittun98')
6a97a864 1403 print(output)
426654d7 1404 self.assertRegex(output, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98")
371810d1 1405 output = check_output('ip -d link show sittun97')
6a97a864 1406 print(output)
426654d7 1407 self.assertRegex(output, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98")
42a29fcb
YW
1408 output = check_output('ip -d link show sittun96')
1409 print(output)
426654d7 1410 self.assertRegex(output, "sit (ip6ip )?remote any local any dev dummy98")
1f0e3109 1411
d0e728b6 1412 def test_isatap_tunnel(self):
ec38833c
ZJS
1413 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1414 '25-isatap-tunnel.netdev', '25-tunnel.network')
2cf6fdff 1415 start_networkd()
e2aea43f 1416 self.wait_online(['isataptun99:routable', 'dummy98:degraded'])
d0e728b6 1417
371810d1 1418 output = check_output('ip -d link show isataptun99')
14ecd604 1419 print(output)
d0e728b6
SS
1420 self.assertRegex(output, "isatap ")
1421
d29dc4f1 1422 def test_6rd_tunnel(self):
ec38833c
ZJS
1423 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1424 '25-6rd-tunnel.netdev', '25-tunnel.network')
2cf6fdff 1425 start_networkd()
e2aea43f 1426 self.wait_online(['sittun99:routable', 'dummy98:degraded'])
d29dc4f1 1427
371810d1 1428 output = check_output('ip -d link show sittun99')
6a97a864
YW
1429 print(output)
1430 self.assertRegex(output, '6rd-prefix 2602::/24')
1431
7bea7f9b 1432 @expectedFailureIfERSPANModuleIsNotAvailable()
2266864b 1433 def test_erspan_tunnel(self):
ec38833c
ZJS
1434 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1435 '25-erspan-tunnel.netdev', '25-tunnel.network',
1436 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
2cf6fdff 1437 start_networkd()
e2aea43f 1438 self.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
2266864b 1439
371810d1 1440 output = check_output('ip -d link show erspan99')
6a97a864
YW
1441 print(output)
1442 self.assertRegex(output, 'erspan remote 172.16.1.100 local 172.16.1.200')
38f4bb44
YW
1443 self.assertRegex(output, 'ikey 0.0.0.101')
1444 self.assertRegex(output, 'okey 0.0.0.101')
1445 self.assertRegex(output, 'iseq')
1446 self.assertRegex(output, 'oseq')
371810d1 1447 output = check_output('ip -d link show erspan98')
2266864b 1448 print(output)
6a97a864
YW
1449 self.assertRegex(output, 'erspan remote 172.16.1.100 local any')
1450 self.assertRegex(output, '102')
38f4bb44
YW
1451 self.assertRegex(output, 'ikey 0.0.0.102')
1452 self.assertRegex(output, 'okey 0.0.0.102')
1453 self.assertRegex(output, 'iseq')
1454 self.assertRegex(output, 'oseq')
2266864b 1455
1f0e3109 1456 def test_tunnel_independent(self):
ec38833c 1457 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
2cf6fdff 1458 start_networkd()
e40a58b5 1459
e2aea43f 1460 self.wait_online(['ipiptun99:carrier'])
1f0e3109 1461
95082dbe
YW
1462 def test_tunnel_independent_loopback(self):
1463 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent-loopback.netdev', 'netdev-link-local-addressing-yes.network')
1464 start_networkd()
1465
e2aea43f 1466 self.wait_online(['ipiptun99:carrier'])
95082dbe 1467
e64dc406
YW
1468 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1469 def test_xfrm(self):
1470 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'xfrm.network',
1471 '25-xfrm.netdev', 'netdev-link-local-addressing-yes.network')
1472 start_networkd()
1473
e2aea43f 1474 self.wait_online(['xfrm99:degraded', 'dummy98:degraded'])
e64dc406
YW
1475
1476 output = check_output('ip link show dev xfrm99')
1477 print(output)
1478
1479 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1480 def test_xfrm_independent(self):
1481 copy_unit_to_networkd_unit_path('25-xfrm-independent.netdev', 'netdev-link-local-addressing-yes.network')
1482 start_networkd()
1483
e2aea43f 1484 self.wait_online(['xfrm99:degraded'])
e64dc406 1485
4b6a6d1e
YW
1486 @expectedFailureIfModuleIsNotAvailable('fou')
1487 def test_fou(self):
1488 # The following redundant check is necessary for CentOS CI.
1489 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1490 self.assertTrue(is_module_available('fou'))
1491
ec38833c
ZJS
1492 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1493 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1494 '25-fou-gre.netdev', '25-fou-gretap.netdev')
2cf6fdff 1495 start_networkd()
4b6a6d1e 1496
e2aea43f 1497 self.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'], setup_state='unmanaged')
4b6a6d1e 1498
371810d1 1499 output = check_output('ip fou show')
4b6a6d1e
YW
1500 print(output)
1501 self.assertRegex(output, 'port 55555 ipproto 4')
1502 self.assertRegex(output, 'port 55556 ipproto 47')
1503
371810d1 1504 output = check_output('ip -d link show ipiptun96')
4b6a6d1e
YW
1505 print(output)
1506 self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55555')
371810d1 1507 output = check_output('ip -d link show sittun96')
4b6a6d1e
YW
1508 print(output)
1509 self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55555')
371810d1 1510 output = check_output('ip -d link show gretun96')
4b6a6d1e
YW
1511 print(output)
1512 self.assertRegex(output, 'encap fou encap-sport 1001 encap-dport 55556')
371810d1 1513 output = check_output('ip -d link show gretap96')
4b6a6d1e
YW
1514 print(output)
1515 self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55556')
1516
1f0e3109 1517 def test_vxlan(self):
ec38833c
ZJS
1518 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1519 '11-dummy.netdev', 'vxlan-test1.network')
2cf6fdff 1520 start_networkd()
1f0e3109 1521
e2aea43f 1522 self.wait_online(['test1:degraded', 'vxlan99:degraded'])
1f0e3109 1523
371810d1 1524 output = check_output('ip -d link show vxlan99')
14ecd604 1525 print(output)
1c862fe0 1526 self.assertRegex(output, '999')
1f0e3109
SS
1527 self.assertRegex(output, '5555')
1528 self.assertRegex(output, 'l2miss')
1529 self.assertRegex(output, 'l3miss')
1530 self.assertRegex(output, 'udpcsum')
1531 self.assertRegex(output, 'udp6zerocsumtx')
1532 self.assertRegex(output, 'udp6zerocsumrx')
1533 self.assertRegex(output, 'remcsumtx')
1534 self.assertRegex(output, 'remcsumrx')
1535 self.assertRegex(output, 'gbp')
1536
371810d1 1537 output = check_output('bridge fdb show dev vxlan99')
1c862fe0
YW
1538 print(output)
1539 self.assertRegex(output, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1540 self.assertRegex(output, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1541 self.assertRegex(output, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1542
fc79e6ff 1543 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'vxlan99', env=env)
36bc2ffb
YW
1544 print(output)
1545 self.assertRegex(output, 'VNI: 999')
1546 self.assertRegex(output, 'Destination Port: 5555')
1547 self.assertRegex(output, 'Underlying Device: test1')
1548
02849d8b 1549 def test_macsec(self):
ec38833c
ZJS
1550 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1551 'macsec.network', '12-dummy.netdev')
2cf6fdff 1552 start_networkd()
02849d8b 1553
e2aea43f 1554 self.wait_online(['dummy98:degraded', 'macsec99:routable'])
02849d8b 1555
371810d1 1556 output = check_output('ip -d link show macsec99')
02849d8b
YW
1557 print(output)
1558 self.assertRegex(output, 'macsec99@dummy98')
1559 self.assertRegex(output, 'macsec sci [0-9a-f]*000b')
1560 self.assertRegex(output, 'encrypt on')
1561
371810d1 1562 output = check_output('ip macsec show macsec99')
02849d8b
YW
1563 print(output)
1564 self.assertRegex(output, 'encrypt on')
1565 self.assertRegex(output, 'TXSC: [0-9a-f]*000b on SA 1')
1566 self.assertRegex(output, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1567 self.assertRegex(output, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1568 self.assertRegex(output, 'RXSC: c619528fe6a00100, state on')
1569 self.assertRegex(output, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1570 self.assertRegex(output, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1571 self.assertRegex(output, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1572 self.assertRegex(output, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1573 self.assertNotRegex(output, 'key 02030405067080900000000000000000')
1574 self.assertRegex(output, 'RXSC: 8c16456c83a90002, state on')
1575 self.assertRegex(output, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1576
811f33d0 1577 def test_nlmon(self):
ec38833c 1578 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
2cf6fdff 1579 start_networkd()
811f33d0 1580
e2aea43f 1581 self.wait_online(['nlmon99:carrier'])
02849d8b 1582
b076d5d7
YW
1583 @expectedFailureIfModuleIsNotAvailable('ifb')
1584 def test_ifb(self):
1585 copy_unit_to_networkd_unit_path('25-ifb.netdev', 'netdev-link-local-addressing-yes.network')
1586 start_networkd()
1587
1588 self.wait_online(['ifb99:degraded'])
1589
cff83db9
YW
1590class NetworkdL2TPTests(unittest.TestCase, Utilities):
1591
1592 links =[
1593 'l2tp-ses1',
1594 'l2tp-ses2',
1595 'l2tp-ses3',
1596 'l2tp-ses4',
1597 'test1']
1598
1599 units = [
1600 '11-dummy.netdev',
1601 '25-l2tp-dummy.network',
e2aea43f 1602 '25-l2tp.network',
cff83db9
YW
1603 '25-l2tp-ip.netdev',
1604 '25-l2tp-udp.netdev']
1605
1606 l2tp_tunnel_ids = [ '10' ]
1607
1608 def setUp(self):
ad78d7b0 1609 remove_l2tp_tunnels(self.l2tp_tunnel_ids)
ec38833c 1610 remove_links(self.links)
aaae5713 1611 stop_networkd(show_logs=False)
cff83db9
YW
1612
1613 def tearDown(self):
ad78d7b0 1614 remove_l2tp_tunnels(self.l2tp_tunnel_ids)
ec38833c
ZJS
1615 remove_links(self.links)
1616 remove_unit_from_networkd_path(self.units)
aaae5713 1617 stop_networkd(show_logs=True)
cff83db9
YW
1618
1619 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1620 def test_l2tp_udp(self):
e2aea43f
YW
1621 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1622 '25-l2tp-udp.netdev', '25-l2tp.network')
2cf6fdff 1623 start_networkd()
cff83db9 1624
e2aea43f 1625 self.wait_online(['test1:routable', 'l2tp-ses1:degraded', 'l2tp-ses2:degraded'])
cff83db9 1626
371810d1 1627 output = check_output('ip l2tp show tunnel tunnel_id 10')
cff83db9
YW
1628 print(output)
1629 self.assertRegex(output, "Tunnel 10, encap UDP")
1630 self.assertRegex(output, "From 192.168.30.100 to 192.168.30.101")
1631 self.assertRegex(output, "Peer tunnel 11")
1632 self.assertRegex(output, "UDP source / dest ports: 3000/4000")
1633 self.assertRegex(output, "UDP checksum: enabled")
1634
371810d1 1635 output = check_output('ip l2tp show session tid 10 session_id 15')
cff83db9
YW
1636 print(output)
1637 self.assertRegex(output, "Session 15 in tunnel 10")
1638 self.assertRegex(output, "Peer session 16, tunnel 11")
1639 self.assertRegex(output, "interface name: l2tp-ses1")
1640
371810d1 1641 output = check_output('ip l2tp show session tid 10 session_id 17')
cff83db9
YW
1642 print(output)
1643 self.assertRegex(output, "Session 17 in tunnel 10")
1644 self.assertRegex(output, "Peer session 18, tunnel 11")
1645 self.assertRegex(output, "interface name: l2tp-ses2")
1646
1647 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1648 def test_l2tp_ip(self):
e2aea43f
YW
1649 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1650 '25-l2tp-ip.netdev', '25-l2tp.network')
2cf6fdff 1651 start_networkd()
cff83db9 1652
e2aea43f 1653 self.wait_online(['test1:routable', 'l2tp-ses3:degraded', 'l2tp-ses4:degraded'])
cff83db9 1654
371810d1 1655 output = check_output('ip l2tp show tunnel tunnel_id 10')
cff83db9
YW
1656 print(output)
1657 self.assertRegex(output, "Tunnel 10, encap IP")
1658 self.assertRegex(output, "From 192.168.30.100 to 192.168.30.101")
1659 self.assertRegex(output, "Peer tunnel 12")
1660
371810d1 1661 output = check_output('ip l2tp show session tid 10 session_id 25')
cff83db9
YW
1662 print(output)
1663 self.assertRegex(output, "Session 25 in tunnel 10")
1664 self.assertRegex(output, "Peer session 26, tunnel 12")
1665 self.assertRegex(output, "interface name: l2tp-ses3")
1666
371810d1 1667 output = check_output('ip l2tp show session tid 10 session_id 27')
cff83db9
YW
1668 print(output)
1669 self.assertRegex(output, "Session 27 in tunnel 10")
1670 self.assertRegex(output, "Peer session 28, tunnel 12")
1671 self.assertRegex(output, "interface name: l2tp-ses4")
1672
be68c2c9 1673class NetworkdNetworkTests(unittest.TestCase, Utilities):
09ea6724
YW
1674 links = [
1675 'bond199',
1676 'dummy98',
cd65d067 1677 'dummy99',
74761cf3 1678 'gretun97',
fb2ba330 1679 'ip6gretun97',
086bcf5d
YW
1680 'test1',
1681 'veth99',
40afe491 1682 'vrf99',
74761cf3 1683 ]
09ea6724
YW
1684
1685 units = [
1686 '11-dummy.netdev',
1687 '12-dummy.netdev',
1688 '23-active-slave.network',
1e498853 1689 '24-keep-configuration-static.network',
fdcd1ec5 1690 '24-search-domain.network',
dc7d3c5f
YW
1691 '25-address-dad-veth-peer.network',
1692 '25-address-dad-veth99.network',
09ea6724 1693 '25-address-link-section.network',
e4783b54 1694 '25-address-preferred-lifetime-zero.network',
b8102725 1695 '25-address-static.network',
cd65d067 1696 '25-bind-carrier.network',
09ea6724
YW
1697 '25-bond-active-backup-slave.netdev',
1698 '25-fibrule-invert.network',
1699 '25-fibrule-port-range.network',
6be8e78e 1700 '25-fibrule-uidrange.network',
74761cf3 1701 '25-gre-tunnel-remote-any.netdev',
fb2ba330 1702 '25-ip6gre-tunnel-remote-any.netdev',
09ea6724 1703 '25-ipv6-address-label-section.network',
ef3c8a92
YW
1704 '25-link-local-addressing-no.network',
1705 '25-link-local-addressing-yes.network',
1706 '25-link-section-unmanaged.network',
e4a71bf3 1707 '25-neighbor-section.network',
d1bdafd2 1708 '25-neighbor-next.network',
fb2ba330 1709 '25-neighbor-ipv6.network',
74761cf3
YW
1710 '25-neighbor-ip-dummy.network',
1711 '25-neighbor-ip.network',
086bcf5d 1712 '25-nexthop.network',
f6c6af38 1713 '25-qdisc-cake.network',
f1de1eb3 1714 '25-qdisc-clsact-and-htb.network',
557fa421 1715 '25-qdisc-drr.network',
b753e835 1716 '25-qdisc-ets.network',
970ab1fc 1717 '25-qdisc-hhf.network',
ab9dc1db 1718 '25-qdisc-ingress-netem-compat.network',
be94e591 1719 '25-qdisc-pie.network',
891ff963 1720 '25-qdisc-qfq.network',
c9d223e8
YW
1721 '25-prefix-route-with-vrf.network',
1722 '25-prefix-route-without-vrf.network',
20ca06a6 1723 '25-route-ipv6-src.network',
0ef830cf 1724 '25-route-static.network',
40afe491 1725 '25-route-vrf.network',
0b1cd3e2
WKI
1726 '25-gateway-static.network',
1727 '25-gateway-next-static.network',
3d2c2692 1728 '25-sriov.network',
4da33154 1729 '25-sysctl-disable-ipv6.network',
09ea6724 1730 '25-sysctl.network',
9bacf431 1731 '25-test1.network',
086bcf5d
YW
1732 '25-veth-peer.network',
1733 '25-veth.netdev',
40afe491 1734 '25-vrf.netdev',
c9d223e8 1735 '25-vrf.network',
7b3770a7 1736 '26-link-local-addressing-ipv6.network',
b677774d 1737 'routing-policy-rule-dummy98.network',
87adeabf
YW
1738 'routing-policy-rule-test1.network',
1739 'routing-policy-rule-reconfigure.network',
1740 ]
1f0e3109 1741
87adeabf 1742 routing_policy_rule_tables = ['7', '8', '9', '1011']
5f68a6a4 1743 routes = [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
95c74b0a 1744
1f0e3109 1745 def setUp(self):
ec38833c
ZJS
1746 remove_routing_policy_rule_tables(self.routing_policy_rule_tables)
1747 remove_routes(self.routes)
1748 remove_links(self.links)
aaae5713 1749 stop_networkd(show_logs=False)
1f0e3109
SS
1750
1751 def tearDown(self):
ec38833c
ZJS
1752 remove_routing_policy_rule_tables(self.routing_policy_rule_tables)
1753 remove_routes(self.routes)
1754 remove_links(self.links)
1755 remove_unit_from_networkd_path(self.units)
aaae5713 1756 stop_networkd(show_logs=True)
1f0e3109 1757
b8102725 1758 def test_address_static(self):
ec38833c 1759 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
2cf6fdff 1760 start_networkd()
b8102725 1761
e2aea43f 1762 self.wait_online(['dummy98:routable'])
b8102725 1763
371810d1 1764 output = check_output('ip -4 address show dev dummy98')
b8102725
YW
1765 print(output)
1766 self.assertRegex(output, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1767 self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1768 self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1769
766f8f38
YW
1770 # test for ENOBUFS issue #17012
1771 for i in range(1,254):
1772 self.assertRegex(output, f'inet 10.3.3.{i}/16 brd 10.3.255.255')
1773
b8102725
YW
1774 # invalid sections
1775 self.assertNotRegex(output, '10.10.0.1/16')
1776 self.assertNotRegex(output, '10.10.0.2/16')
1777
371810d1 1778 output = check_output('ip -4 address show dev dummy98 label 32')
b8102725
YW
1779 self.assertRegex(output, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1780
371810d1 1781 output = check_output('ip -4 address show dev dummy98 label 33')
b8102725
YW
1782 self.assertRegex(output, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1783
371810d1 1784 output = check_output('ip -4 address show dev dummy98 label 34')
b8102725
YW
1785 self.assertRegex(output, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1786
371810d1 1787 output = check_output('ip -4 address show dev dummy98 label 35')
b8102725
YW
1788 self.assertRegex(output, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1789
371810d1 1790 output = check_output('ip -6 address show dev dummy98')
b8102725
YW
1791 print(output)
1792 self.assertRegex(output, 'inet6 2001:db8:0:f101::15/64 scope global')
1793 self.assertRegex(output, 'inet6 2001:db8:0:f101::16/64 scope global')
1794 self.assertRegex(output, 'inet6 2001:db8:0:f102::15/64 scope global')
1795 self.assertRegex(output, 'inet6 2001:db8:0:f102::16/64 scope global')
1796 self.assertRegex(output, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1797 self.assertRegex(output, 'inet6 fd[0-9a-f:]*1/64 scope global')
1798
766f8f38
YW
1799 restart_networkd()
1800 self.wait_online(['dummy98:routable'])
1801
1802 # test for ENOBUFS issue #17012
1803 output = check_output('ip -4 address show dev dummy98')
1804 for i in range(1,254):
1805 self.assertRegex(output, f'inet 10.3.3.{i}/16 brd 10.3.255.255')
1806
b8102725 1807 def test_address_preferred_lifetime_zero_ipv6(self):
e4783b54 1808 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero.network', '12-dummy.netdev')
01943d43 1809 start_networkd(5)
1f0e3109 1810
e4783b54 1811 self.wait_online(['dummy98:routable'])
b8102725 1812
371810d1 1813 output = check_output('ip address show dummy98')
b8102725
YW
1814 print(output)
1815 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1816 self.assertRegex(output, 'inet6 2001:db8:0:f101::1/64 scope global')
1f0e3109 1817
e4783b54
YW
1818 output = check_output('ip route show dev dummy98')
1819 print(output)
1820 self.assertRegex(output, 'default via 20.20.20.1 proto static')
1821
dc7d3c5f
YW
1822 def test_address_dad(self):
1823 copy_unit_to_networkd_unit_path('25-address-dad-veth99.network', '25-address-dad-veth-peer.network',
1824 '25-veth.netdev')
1825 start_networkd()
1826 self.wait_online(['veth99:routable', 'veth-peer:degraded'])
1827
1828 output = check_output('ip -4 address show dev veth99')
1829 print(output)
1830 self.assertRegex(output, '192.168.100.10/24')
1831
1832 output = check_output('ip -4 address show dev veth-peer')
1833 print(output)
1834 self.assertNotRegex(output, '192.168.100.10/24')
1835
c9d223e8
YW
1836 @expectedFailureIfModuleIsNotAvailable('vrf')
1837 def test_prefix_route(self):
1838 copy_unit_to_networkd_unit_path('25-prefix-route-with-vrf.network', '12-dummy.netdev',
1839 '25-prefix-route-without-vrf.network', '11-dummy.netdev',
1840 '25-vrf.netdev', '25-vrf.network')
1841 for trial in range(2):
1842 if trial == 0:
1843 start_networkd()
1844 else:
1845 restart_networkd(3)
1846
1847 self.wait_online(['dummy98:routable', 'test1:routable', 'vrf99:carrier'])
1848
1849 output = check_output('ip route show table 42 dev dummy98')
1850 print('### ip route show table 42 dev dummy98')
1851 print(output)
1852 self.assertRegex(output, 'local 10.20.22.1 proto kernel scope host src 10.20.22.1')
1853 self.assertRegex(output, 'broadcast 10.20.33.0 proto kernel scope link src 10.20.33.1')
1854 self.assertRegex(output, '10.20.33.0/24 proto kernel scope link src 10.20.33.1')
1855 self.assertRegex(output, 'local 10.20.33.1 proto kernel scope host src 10.20.33.1')
1856 self.assertRegex(output, 'broadcast 10.20.33.255 proto kernel scope link src 10.20.33.1')
1857 self.assertRegex(output, 'local 10.20.44.1 proto kernel scope host src 10.20.44.1')
1858 self.assertRegex(output, 'broadcast 10.20.55.0 proto kernel scope link src 10.20.55.1')
1859 self.assertRegex(output, 'local 10.20.55.1 proto kernel scope host src 10.20.55.1')
1860 self.assertRegex(output, 'broadcast 10.20.55.255 proto kernel scope link src 10.20.55.1')
1861 output = check_output('ip -6 route show table 42 dev dummy98')
1862 print('### ip -6 route show table 42 dev dummy98')
1863 print(output)
1864 if trial == 0:
1865 # Kernel's bug?
1866 self.assertRegex(output, 'local fdde:11:22::1 proto kernel metric 0 pref medium')
1867 #self.assertRegex(output, 'fdde:11:22::1 proto kernel metric 256 pref medium')
1868 self.assertRegex(output, 'local fdde:11:33::1 proto kernel metric 0 pref medium')
1869 self.assertRegex(output, 'fdde:11:33::/64 proto kernel metric 256 pref medium')
1870 self.assertRegex(output, 'local fdde:11:44::1 proto kernel metric 0 pref medium')
1871 self.assertRegex(output, 'local fdde:11:55::1 proto kernel metric 0 pref medium')
1872 self.assertRegex(output, 'fe80::/64 proto kernel metric 256 pref medium')
1873 self.assertRegex(output, 'ff00::/8 metric 256 pref medium')
1874
1875 print()
1876
1877 output = check_output('ip route show dev test1')
1878 print('### ip route show dev test1')
1879 print(output)
1880 self.assertRegex(output, '10.21.33.0/24 proto kernel scope link src 10.21.33.1')
1881 output = check_output('ip route show table local dev test1')
1882 print('### ip route show table local dev test1')
1883 print(output)
1884 self.assertRegex(output, 'local 10.21.22.1 proto kernel scope host src 10.21.22.1')
1885 self.assertRegex(output, 'broadcast 10.21.33.0 proto kernel scope link src 10.21.33.1')
1886 self.assertRegex(output, 'local 10.21.33.1 proto kernel scope host src 10.21.33.1')
1887 self.assertRegex(output, 'broadcast 10.21.33.255 proto kernel scope link src 10.21.33.1')
1888 self.assertRegex(output, 'local 10.21.44.1 proto kernel scope host src 10.21.44.1')
1889 self.assertRegex(output, 'broadcast 10.21.55.0 proto kernel scope link src 10.21.55.1')
1890 self.assertRegex(output, 'local 10.21.55.1 proto kernel scope host src 10.21.55.1')
1891 self.assertRegex(output, 'broadcast 10.21.55.255 proto kernel scope link src 10.21.55.1')
1892 output = check_output('ip -6 route show dev test1')
1893 print('### ip -6 route show dev test1')
1894 print(output)
1895 self.assertRegex(output, 'fdde:12:22::1 proto kernel metric 256 pref medium')
1896 self.assertRegex(output, 'fdde:12:33::/64 proto kernel metric 256 pref medium')
1897 self.assertRegex(output, 'fe80::/64 proto kernel metric 256 pref medium')
1898 output = check_output('ip -6 route show table local dev test1')
1899 print('### ip -6 route show table local dev test1')
1900 print(output)
1901 self.assertRegex(output, 'local fdde:12:22::1 proto kernel metric 0 pref medium')
1902 self.assertRegex(output, 'local fdde:12:33::1 proto kernel metric 0 pref medium')
1903 self.assertRegex(output, 'local fdde:12:44::1 proto kernel metric 0 pref medium')
1904 self.assertRegex(output, 'local fdde:12:55::1 proto kernel metric 0 pref medium')
1905 self.assertRegex(output, 'ff00::/8 metric 256 pref medium')
1906
1f0e3109 1907 def test_configure_without_carrier(self):
9bacf431 1908 copy_unit_to_networkd_unit_path('11-dummy.netdev')
2cf6fdff 1909 start_networkd()
9bacf431
DS
1910 self.wait_operstate('test1', 'off', '')
1911 check_output('ip link set dev test1 up carrier off')
1912
1913 copy_unit_to_networkd_unit_path('25-test1.network.d/configure-without-carrier.conf', dropins=False)
1914 restart_networkd()
1915 self.wait_online(['test1:no-carrier'])
1916
1917 carrier_map = {'on': '1', 'off': '0'}
1918 routable_map = {'on': 'routable', 'off': 'no-carrier'}
1919 for carrier in ['off', 'on', 'off']:
1920 with self.subTest(carrier=carrier):
1921 if carrier_map[carrier] != read_link_attr('test1', 'carrier'):
1922 check_output(f'ip link set dev test1 carrier {carrier}')
1923 self.wait_online([f'test1:{routable_map[carrier]}'])
1924
1925 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'test1', env=env)
1926 print(output)
1927 self.assertRegex(output, '192.168.0.15')
1928 self.assertRegex(output, '192.168.0.1')
1929 self.assertRegex(output, routable_map[carrier])
e40a58b5 1930
9bacf431
DS
1931 def test_configure_without_carrier_yes_ignore_carrier_loss_no(self):
1932 copy_unit_to_networkd_unit_path('11-dummy.netdev')
1933 start_networkd()
1934 self.wait_operstate('test1', 'off', '')
1935 check_output('ip link set dev test1 up carrier off')
1936
1937 copy_unit_to_networkd_unit_path('25-test1.network')
1938 restart_networkd()
1939 self.wait_online(['test1:no-carrier'])
1940
1941 carrier_map = {'on': '1', 'off': '0'}
1942 routable_map = {'on': 'routable', 'off': 'no-carrier'}
1943 for (carrier, have_config) in [('off', True), ('on', True), ('off', False)]:
1944 with self.subTest(carrier=carrier, have_config=have_config):
1945 if carrier_map[carrier] != read_link_attr('test1', 'carrier'):
1946 check_output(f'ip link set dev test1 carrier {carrier}')
1947 self.wait_online([f'test1:{routable_map[carrier]}'])
1948
1949 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'test1', env=env)
1950 print(output)
1951 if have_config:
1952 self.assertRegex(output, '192.168.0.15')
1953 self.assertRegex(output, '192.168.0.1')
1954 else:
1955 self.assertNotRegex(output, '192.168.0.15')
1956 self.assertNotRegex(output, '192.168.0.1')
1957 self.assertRegex(output, routable_map[carrier])
1f0e3109 1958
1f0e3109 1959 def test_routing_policy_rule(self):
ec38833c 1960 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
2cf6fdff 1961 start_networkd()
e2aea43f 1962 self.wait_online(['test1:degraded'])
e40a58b5 1963
65c24cd0 1964 output = check_output('ip rule list iif test1 priority 111')
1f0e3109 1965 print(output)
65c24cd0 1966 self.assertRegex(output, '111:')
1f0e3109 1967 self.assertRegex(output, 'from 192.168.100.18')
426654d7 1968 self.assertRegex(output, r'tos (0x08|throughput)\s')
1f0e3109
SS
1969 self.assertRegex(output, 'iif test1')
1970 self.assertRegex(output, 'oif test1')
1971 self.assertRegex(output, 'lookup 7')
1972
65c24cd0
YW
1973 output = check_output('ip rule list iif test1 priority 101')
1974 print(output)
1975 self.assertRegex(output, '101:')
1976 self.assertRegex(output, 'from all')
1977 self.assertRegex(output, 'iif test1')
1978 self.assertRegex(output, 'lookup 9')
1979
1980 output = check_output('ip -6 rule list iif test1 priority 100')
1981 print(output)
1982 self.assertRegex(output, '100:')
1983 self.assertRegex(output, 'from all')
1984 self.assertRegex(output, 'iif test1')
1985 self.assertRegex(output, 'lookup 8')
1986
b677774d 1987 def test_routing_policy_rule_issue_11280(self):
ec38833c
ZJS
1988 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1989 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
b677774d 1990
b677774d
YW
1991 for trial in range(3):
1992 # Remove state files only first time
e2aea43f
YW
1993 start_networkd(3)
1994 self.wait_online(['test1:degraded', 'dummy98:degraded'])
df7f9afa 1995 time.sleep(1)
b677774d 1996
371810d1 1997 output = check_output('ip rule list table 7')
b677774d 1998 print(output)
426654d7 1999 self.assertRegex(output, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
b677774d 2000
371810d1 2001 output = check_output('ip rule list table 8')
b677774d 2002 print(output)
426654d7 2003 self.assertRegex(output, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
b677774d 2004
aaae5713
YW
2005 stop_networkd(remove_state_files=False)
2006
87adeabf
YW
2007 def test_routing_policy_rule_reconfigure(self):
2008 copy_unit_to_networkd_unit_path('routing-policy-rule-reconfigure.network', '11-dummy.netdev')
2009 start_networkd()
2010 self.wait_online(['test1:degraded'])
2011
2012 output = check_output('ip rule list table 1011')
2013 print(output)
2014 self.assertRegex(output, '10111: from all fwmark 0x3f3 lookup 1011')
2015 self.assertRegex(output, '10112: from all oif test1 lookup 1011')
2016 self.assertRegex(output, '10113: from all iif test1 lookup 1011')
2017 self.assertRegex(output, '10114: from 192.168.8.254 lookup 1011')
2018
2019 run('ip rule delete priority 10111')
2020 run('ip rule delete priority 10112')
2021 run('ip rule delete priority 10113')
2022 run('ip rule delete priority 10114')
2023 run('ip rule delete priority 10115')
2024
2025 output = check_output('ip rule list table 1011')
2026 print(output)
2027 self.assertEqual(output, '')
2028
2029 run(*networkctl_cmd, 'reconfigure', 'test1', env=env)
2030
2031 self.wait_online(['test1:degraded'])
2032
2033 output = check_output('ip rule list table 1011')
2034 print(output)
2035 self.assertRegex(output, '10111: from all fwmark 0x3f3 lookup 1011')
2036 self.assertRegex(output, '10112: from all oif test1 lookup 1011')
2037 self.assertRegex(output, '10113: from all iif test1 lookup 1011')
2038 self.assertRegex(output, '10114: from 192.168.8.254 lookup 1011')
2039
d586a2c3 2040 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
926062f0 2041 def test_routing_policy_rule_port_range(self):
ec38833c 2042 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
2cf6fdff 2043 start_networkd()
e2aea43f 2044 self.wait_online(['test1:degraded'])
e40a58b5 2045
371810d1 2046 output = check_output('ip rule')
926062f0
SS
2047 print(output)
2048 self.assertRegex(output, '111')
2049 self.assertRegex(output, 'from 192.168.100.18')
2050 self.assertRegex(output, '1123-1150')
2051 self.assertRegex(output, '3224-3290')
2052 self.assertRegex(output, 'tcp')
2053 self.assertRegex(output, 'lookup 7')
1f0e3109 2054
d586a2c3 2055 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
efecf9cd 2056 def test_routing_policy_rule_invert(self):
ec38833c 2057 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
2cf6fdff 2058 start_networkd()
e2aea43f 2059 self.wait_online(['test1:degraded'])
e40a58b5 2060
371810d1 2061 output = check_output('ip rule')
efecf9cd 2062 print(output)
efecf9cd
SS
2063 self.assertRegex(output, '111')
2064 self.assertRegex(output, 'not.*?from.*?192.168.100.18')
2065 self.assertRegex(output, 'tcp')
2066 self.assertRegex(output, 'lookup 7')
2067
6be8e78e
YW
2068 @expectedFailureIfRoutingPolicyUIDRangeIsNotAvailable()
2069 def test_routing_policy_rule_uidrange(self):
2070 copy_unit_to_networkd_unit_path('25-fibrule-uidrange.network', '11-dummy.netdev')
2071 start_networkd()
2072 self.wait_online(['test1:degraded'])
2073
2074 output = check_output('ip rule')
2075 print(output)
2076 self.assertRegex(output, '111')
2077 self.assertRegex(output, 'from 192.168.100.18')
2078 self.assertRegex(output, 'lookup 7')
2079 self.assertRegex(output, 'uidrange 100-200')
2080
0ef830cf 2081 def test_route_static(self):
ec38833c 2082 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
2cf6fdff 2083 start_networkd()
e2aea43f
YW
2084 self.wait_online(['dummy98:routable'])
2085
fc79e6ff 2086 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98', env=env)
e2aea43f 2087 print(output)
0d34228f 2088
6d60f9db 2089 print('### ip -6 route show dev dummy98')
371810d1 2090 output = check_output('ip -6 route show dev dummy98')
0d34228f 2091 print(output)
0ef830cf
YW
2092 self.assertRegex(output, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
2093 self.assertRegex(output, '2001:1234:5:8f63::1 proto kernel')
1f0e3109 2094
6d60f9db 2095 print('### ip -6 route show dev dummy98 default')
371810d1 2096 output = check_output('ip -6 route show dev dummy98 default')
6d60f9db 2097 print(output)
0ef830cf 2098 self.assertRegex(output, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1f0e3109 2099
6d60f9db 2100 print('### ip -4 route show dev dummy98')
371810d1 2101 output = check_output('ip -4 route show dev dummy98')
1f0e3109 2102 print(output)
0ef830cf
YW
2103 self.assertRegex(output, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
2104 self.assertRegex(output, '149.10.124.64 proto static scope link')
2b00dff8 2105 self.assertRegex(output, '169.254.0.0/16 proto static scope link metric 2048')
0ef830cf
YW
2106 self.assertRegex(output, '192.168.1.1 proto static initcwnd 20')
2107 self.assertRegex(output, '192.168.1.2 proto static initrwnd 30')
6d60f9db 2108 self.assertRegex(output, 'multicast 149.10.123.4 proto static')
1f0e3109 2109
6d60f9db 2110 print('### ip -4 route show dev dummy98 default')
371810d1 2111 output = check_output('ip -4 route show dev dummy98 default')
6d60f9db 2112 print(output)
0ef830cf
YW
2113 self.assertRegex(output, 'default via 149.10.125.65 proto static onlink')
2114 self.assertRegex(output, 'default via 149.10.124.64 proto static')
6543b7fd 2115 self.assertRegex(output, 'default proto static')
1f0e3109 2116
6d60f9db
YW
2117 print('### ip -4 route show table local dev dummy98')
2118 output = check_output('ip -4 route show table local dev dummy98')
2119 print(output)
2120 self.assertRegex(output, 'local 149.10.123.1 proto static scope host')
2121 self.assertRegex(output, 'anycast 149.10.123.2 proto static scope link')
2122 self.assertRegex(output, 'broadcast 149.10.123.3 proto static scope link')
2123
2124 print('### ip route show type blackhole')
371810d1 2125 output = check_output('ip route show type blackhole')
1f0e3109 2126 print(output)
0ef830cf 2127 self.assertRegex(output, 'blackhole 202.54.1.2 proto static')
f5050e48 2128
6d60f9db 2129 print('### ip route show type unreachable')
371810d1 2130 output = check_output('ip route show type unreachable')
f5050e48 2131 print(output)
0ef830cf 2132 self.assertRegex(output, 'unreachable 202.54.1.3 proto static')
f5050e48 2133
6d60f9db 2134 print('### ip route show type prohibit')
371810d1 2135 output = check_output('ip route show type prohibit')
f5050e48 2136 print(output)
0ef830cf 2137 self.assertRegex(output, 'prohibit 202.54.1.4 proto static')
f5050e48 2138
a0ce990e
YW
2139 print('### ip route show 192.168.10.1')
2140 output = check_output('ip route show 192.168.10.1')
2141 print(output)
2142 self.assertRegex(output, '192.168.10.1 proto static')
2143 self.assertRegex(output, 'nexthop via 149.10.124.59 dev dummy98 weight 10')
2144 self.assertRegex(output, 'nexthop via 149.10.124.60 dev dummy98 weight 5')
2145
2146 print('### ip route show 192.168.10.2')
2147 output = check_output('ip route show 192.168.10.2')
2148 print(output)
2149 # old ip command does not show IPv6 gateways...
2150 self.assertRegex(output, '192.168.10.2 proto static')
2151 self.assertRegex(output, 'nexthop')
2152 self.assertRegex(output, 'dev dummy98 weight 10')
2153 self.assertRegex(output, 'dev dummy98 weight 5')
2154
2155 print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2156 output = check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
2157 print(output)
2158 # old ip command does not show 'nexthop' keyword and weight...
2159 self.assertRegex(output, '2001:1234:5:7fff:ff:ff:ff:ff')
2160 self.assertRegex(output, 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98')
2161 self.assertRegex(output, 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98')
2162
40afe491
YW
2163 @expectedFailureIfModuleIsNotAvailable('vrf')
2164 def test_route_vrf(self):
2165 copy_unit_to_networkd_unit_path('25-route-vrf.network', '12-dummy.netdev',
2166 '25-vrf.netdev', '25-vrf.network')
2167 start_networkd()
2168 self.wait_online(['dummy98:routable', 'vrf99:carrier'])
2169
2170 output = check_output('ip route show vrf vrf99')
2171 print(output)
2172 self.assertRegex(output, 'default via 192.168.100.1')
2173
2174 output = check_output('ip route show')
2175 print(output)
2176 self.assertNotRegex(output, 'default via 192.168.100.1')
2177
0b1cd3e2
WKI
2178 def test_gateway_reconfigure(self):
2179 copy_unit_to_networkd_unit_path('25-gateway-static.network', '12-dummy.netdev')
2180 start_networkd()
2181 self.wait_online(['dummy98:routable'])
2182 print('### ip -4 route show dev dummy98 default')
2183 output = check_output('ip -4 route show dev dummy98 default')
2184 print(output)
2185 self.assertRegex(output, 'default via 149.10.124.59 proto static')
2186 self.assertNotRegex(output, '149.10.124.60')
2187
2188 remove_unit_from_networkd_path(['25-gateway-static.network'])
2189 copy_unit_to_networkd_unit_path('25-gateway-next-static.network')
2190 restart_networkd(3)
2191 self.wait_online(['dummy98:routable'])
2192 print('### ip -4 route show dev dummy98 default')
2193 output = check_output('ip -4 route show dev dummy98 default')
2194 print(output)
2195 self.assertNotRegex(output, '149.10.124.59')
2196 self.assertRegex(output, 'default via 149.10.124.60 proto static')
2197
20ca06a6
DA
2198 def test_ip_route_ipv6_src_route(self):
2199 # a dummy device does not make the addresses go through tentative state, so we
2200 # reuse a bond from an earlier test, which does make the addresses go through
2201 # tentative state, and do our test on that
ec38833c 2202 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2cf6fdff 2203 start_networkd()
e2aea43f 2204 self.wait_online(['dummy98:enslaved', 'bond199:routable'])
20ca06a6 2205
371810d1 2206 output = check_output('ip -6 route list dev bond199')
20ca06a6
DA
2207 print(output)
2208 self.assertRegex(output, 'abcd::/16')
2209 self.assertRegex(output, 'src')
2210 self.assertRegex(output, '2001:1234:56:8f63::2')
2211
1f0e3109 2212 def test_ip_link_mac_address(self):
ec38833c 2213 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
2cf6fdff 2214 start_networkd()
e2aea43f 2215 self.wait_online(['dummy98:degraded'])
1f0e3109 2216
371810d1 2217 output = check_output('ip link show dummy98')
1f0e3109
SS
2218 print(output)
2219 self.assertRegex(output, '00:01:02:aa:bb:cc')
2220
2221 def test_ip_link_unmanaged(self):
ec38833c 2222 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
df7f9afa 2223 start_networkd(5)
1f0e3109 2224
e39cc445 2225 self.check_link_exists('dummy98')
1f0e3109 2226
19cf3143 2227 self.wait_operstate('dummy98', 'off', setup_state='unmanaged')
1f0e3109
SS
2228
2229 def test_ipv6_address_label(self):
ec38833c 2230 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
2cf6fdff 2231 start_networkd()
e2aea43f 2232 self.wait_online(['dummy98:degraded'])
1f0e3109 2233
371810d1 2234 output = check_output('ip addrlabel list')
1f0e3109
SS
2235 print(output)
2236 self.assertRegex(output, '2004:da8:1::/64')
2237
d86f5c19 2238 def test_neighbor_section(self):
ec38833c 2239 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2cf6fdff 2240 start_networkd()
e2aea43f 2241 self.wait_online(['dummy98:degraded'], timeout='40s')
e4a71bf3 2242
d1bdafd2 2243 print('### ip neigh list dev dummy98')
df7f9afa 2244 output = check_output('ip neigh list dev dummy98')
e4a71bf3
WKI
2245 print(output)
2246 self.assertRegex(output, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
094b5479 2247 self.assertRegex(output, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
e4a71bf3 2248
d1bdafd2
WKI
2249 def test_neighbor_reconfigure(self):
2250 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
2251 start_networkd()
2252 self.wait_online(['dummy98:degraded'], timeout='40s')
2253
2254 print('### ip neigh list dev dummy98')
2255 output = check_output('ip neigh list dev dummy98')
2256 print(output)
2257 self.assertRegex(output, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2258 self.assertRegex(output, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
2259
2260 remove_unit_from_networkd_path(['25-neighbor-section.network'])
2261 copy_unit_to_networkd_unit_path('25-neighbor-next.network')
2262 restart_networkd(3)
2263 self.wait_online(['dummy98:degraded'], timeout='40s')
2264 print('### ip neigh list dev dummy98')
2265 output = check_output('ip neigh list dev dummy98')
2266 print(output)
2267 self.assertNotRegex(output, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
2268 self.assertRegex(output, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT')
2269 self.assertNotRegex(output, '2004:da8:1::1.*PERMANENT')
2270
74761cf3 2271 def test_neighbor_gre(self):
fb2ba330
YW
2272 copy_unit_to_networkd_unit_path('25-neighbor-ip.network', '25-neighbor-ipv6.network', '25-neighbor-ip-dummy.network',
2273 '12-dummy.netdev', '25-gre-tunnel-remote-any.netdev', '25-ip6gre-tunnel-remote-any.netdev')
74761cf3 2274 start_networkd()
fb2ba330 2275 self.wait_online(['dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable'], timeout='40s')
74761cf3
YW
2276
2277 output = check_output('ip neigh list dev gretun97')
2278 print(output)
2279 self.assertRegex(output, '10.0.0.22 lladdr 10.65.223.239 PERMANENT')
fb2ba330
YW
2280
2281 output = check_output('ip neigh list dev ip6gretun97')
2282 print(output)
2283 self.assertRegex(output, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
74761cf3 2284
05514ae1 2285 def test_link_local_addressing(self):
ec38833c
ZJS
2286 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
2287 '25-link-local-addressing-no.network', '12-dummy.netdev')
2cf6fdff 2288 start_networkd()
e2aea43f 2289 self.wait_online(['test1:degraded', 'dummy98:carrier'])
05514ae1 2290
371810d1 2291 output = check_output('ip address show dev test1')
05514ae1
YW
2292 print(output)
2293 self.assertRegex(output, 'inet .* scope link')
2294 self.assertRegex(output, 'inet6 .* scope link')
2295
371810d1 2296 output = check_output('ip address show dev dummy98')
05514ae1
YW
2297 print(output)
2298 self.assertNotRegex(output, 'inet6* .* scope link')
2299
05514ae1
YW
2300 '''
2301 Documentation/networking/ip-sysctl.txt
2302
2303 addr_gen_mode - INTEGER
2304 Defines how link-local and autoconf addresses are generated.
2305
2306 0: generate address based on EUI64 (default)
2307 1: do no generate a link-local address, use EUI64 for addresses generated
2308 from autoconf
2309 2: generate stable privacy addresses, using the secret from
2310 stable_secret (RFC7217)
2311 3: generate stable privacy addresses, using a random secret if unset
2312 '''
2313
2314 test1_addr_gen_mode = ''
2315 if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'stable_secret')):
2316 with open(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'stable_secret')) as f:
2317 try:
2318 f.readline()
2319 except IOError:
2320 # if stable_secret is unset, then EIO is returned
2321 test1_addr_gen_mode = '0'
2322 else:
2323 test1_addr_gen_mode = '2'
2324 else:
2325 test1_addr_gen_mode = '0'
2326
2327 if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'addr_gen_mode')):
ec38833c 2328 self.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode)
05514ae1
YW
2329
2330 if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'dummy98'), 'addr_gen_mode')):
ec38833c 2331 self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
05514ae1 2332
7b3770a7
YW
2333 def test_link_local_addressing_remove_ipv6ll(self):
2334 copy_unit_to_networkd_unit_path('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
2335 start_networkd()
2336 self.wait_online(['dummy98:degraded'])
2337
2338 output = check_output('ip address show dev dummy98')
2339 print(output)
2340 self.assertRegex(output, 'inet6 .* scope link')
2341
2342 copy_unit_to_networkd_unit_path('25-link-local-addressing-no.network')
2343 restart_networkd(1)
2344 self.wait_online(['dummy98:carrier'])
2345
2346 output = check_output('ip address show dev dummy98')
2347 print(output)
2348 self.assertNotRegex(output, 'inet6* .* scope link')
2349
1f0e3109 2350 def test_sysctl(self):
ec38833c 2351 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
2cf6fdff 2352 start_networkd()
e2aea43f 2353 self.wait_online(['dummy98:degraded'])
ec38833c
ZJS
2354
2355 self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
2356 self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
2357 self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
2358 self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
2359 self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
2360 self.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
2361 self.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
29f69c57 2362 self.assertEqual(read_ipv4_sysctl_attr('dummy98', 'accept_local'), '1')
1f0e3109 2363
4da33154 2364 def test_sysctl_disable_ipv6(self):
ec38833c 2365 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
4da33154
YW
2366
2367 print('## Disable ipv6')
cefd6b3d
ZJS
2368 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
2369 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
4da33154 2370
2cf6fdff 2371 start_networkd()
e2aea43f 2372 self.wait_online(['dummy98:routable'])
4da33154 2373
371810d1 2374 output = check_output('ip -4 address show dummy98')
4da33154
YW
2375 print(output)
2376 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
371810d1 2377 output = check_output('ip -6 address show dummy98')
4da33154 2378 print(output)
57ad7607
ZJS
2379 self.assertRegex(output, 'inet6 2607:5300:203:3906::/64 scope global')
2380 self.assertRegex(output, 'inet6 .* scope link')
4933b97d
YW
2381 output = check_output('ip -4 route show dev dummy98')
2382 print(output)
3d2c2692 2383 self.assertRegex(output, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
4933b97d
YW
2384 output = check_output('ip -6 route show dev dummy98')
2385 print(output)
57ad7607 2386 self.assertRegex(output, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
4da33154 2387
cefd6b3d 2388 check_output('ip link del dummy98')
4da33154
YW
2389
2390 print('## Enable ipv6')
cefd6b3d
ZJS
2391 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
2392 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
4da33154 2393
e2aea43f
YW
2394 restart_networkd(3)
2395 self.wait_online(['dummy98:routable'])
4da33154 2396
371810d1 2397 output = check_output('ip -4 address show dummy98')
4da33154
YW
2398 print(output)
2399 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
371810d1 2400 output = check_output('ip -6 address show dummy98')
4da33154 2401 print(output)
4933b97d 2402 self.assertRegex(output, 'inet6 2607:5300:203:3906::/64 scope global')
4da33154 2403 self.assertRegex(output, 'inet6 .* scope link')
4933b97d
YW
2404 output = check_output('ip -4 route show dev dummy98')
2405 print(output)
3d2c2692 2406 self.assertRegex(output, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
4933b97d
YW
2407 output = check_output('ip -6 route show dev dummy98')
2408 print(output)
2409 self.assertRegex(output, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
4da33154 2410
cd65d067 2411 def test_bind_carrier(self):
bc942f69
YW
2412 check_output('ip link add dummy98 type dummy')
2413 check_output('ip link set dummy98 up')
2414 time.sleep(2)
2415
ec38833c 2416 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
2cf6fdff 2417 start_networkd()
e2aea43f 2418 self.wait_online(['test1:routable'])
cd65d067 2419
371810d1 2420 output = check_output('ip address show test1')
cd65d067
YW
2421 print(output)
2422 self.assertRegex(output, 'UP,LOWER_UP')
2423 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
19cf3143 2424 self.wait_operstate('test1', 'routable')
cd65d067 2425
cefd6b3d
ZJS
2426 check_output('ip link add dummy99 type dummy')
2427 check_output('ip link set dummy99 up')
b117044c 2428 time.sleep(2)
371810d1 2429 output = check_output('ip address show test1')
cd65d067
YW
2430 print(output)
2431 self.assertRegex(output, 'UP,LOWER_UP')
2432 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
19cf3143 2433 self.wait_operstate('test1', 'routable')
cd65d067 2434
cefd6b3d 2435 check_output('ip link del dummy98')
b117044c 2436 time.sleep(2)
371810d1 2437 output = check_output('ip address show test1')
cd65d067
YW
2438 print(output)
2439 self.assertRegex(output, 'UP,LOWER_UP')
2440 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
19cf3143 2441 self.wait_operstate('test1', 'routable')
cd65d067 2442
bc942f69 2443 check_output('ip link set dummy99 down')
b117044c 2444 time.sleep(2)
371810d1 2445 output = check_output('ip address show test1')
cd65d067
YW
2446 print(output)
2447 self.assertNotRegex(output, 'UP,LOWER_UP')
2448 self.assertRegex(output, 'DOWN')
2449 self.assertNotRegex(output, '192.168.10')
19cf3143 2450 self.wait_operstate('test1', 'off')
cd65d067 2451
bc942f69 2452 check_output('ip link set dummy99 up')
b117044c 2453 time.sleep(2)
371810d1 2454 output = check_output('ip address show test1')
cd65d067
YW
2455 print(output)
2456 self.assertRegex(output, 'UP,LOWER_UP')
2457 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
19cf3143 2458 self.wait_operstate('test1', 'routable')
cd65d067 2459
fdcd1ec5 2460 def test_domain(self):
ec38833c 2461 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
2cf6fdff 2462 start_networkd()
e2aea43f 2463 self.wait_online(['dummy98:routable'])
fdcd1ec5 2464
fc79e6ff 2465 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'dummy98', env=env)
fdcd1ec5
YW
2466 print(output)
2467 self.assertRegex(output, 'Address: 192.168.42.100')
2468 self.assertRegex(output, 'DNS: 192.168.42.1')
2469 self.assertRegex(output, 'Search Domains: one')
2470
1e498853 2471 def test_keep_configuration_static(self):
3aa645f0
MB
2472 check_output('systemctl stop systemd-networkd.socket')
2473 check_output('systemctl stop systemd-networkd.service')
1e498853
YW
2474
2475 check_output('ip link add name dummy98 type dummy')
2476 check_output('ip address add 10.1.2.3/16 dev dummy98')
2477 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
2478 output = check_output('ip address show dummy98')
2479 print(output)
2480 self.assertRegex(output, 'inet 10.1.2.3/16 scope global dummy98')
2481 self.assertRegex(output, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2482 output = check_output('ip route show dev dummy98')
2483 print(output)
2484
2485 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
2cf6fdff 2486 start_networkd()
e2aea43f 2487 self.wait_online(['dummy98:routable'])
1e498853
YW
2488
2489 output = check_output('ip address show dummy98')
2490 print(output)
2491 self.assertRegex(output, 'inet 10.1.2.3/16 scope global dummy98')
2492 self.assertNotRegex(output, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2493
086bcf5d
YW
2494 @expectedFailureIfNexthopIsNotAvailable()
2495 def test_nexthop(self):
2496 copy_unit_to_networkd_unit_path('25-nexthop.network', '25-veth.netdev', '25-veth-peer.network')
2497 start_networkd()
2498 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2499
2500 output = check_output('ip nexthop list dev veth99')
2501 print(output)
2502 self.assertRegex(output, '192.168.5.1')
2503
ef3c8a92 2504 def test_qdisc(self):
f1de1eb3
YW
2505 copy_unit_to_networkd_unit_path('25-qdisc-clsact-and-htb.network', '12-dummy.netdev',
2506 '25-qdisc-ingress-netem-compat.network', '11-dummy.netdev')
2507 check_output('modprobe sch_teql max_equalizers=2')
ef3c8a92
YW
2508 start_networkd()
2509
1b628c4f 2510 self.wait_online(['dummy98:routable', 'test1:routable'])
ef3c8a92 2511
f1de1eb3
YW
2512 output = check_output('tc qdisc show dev test1')
2513 print(output)
2514 self.assertRegex(output, 'qdisc netem')
7887e580 2515 self.assertRegex(output, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
f1de1eb3
YW
2516 self.assertRegex(output, 'qdisc ingress')
2517
ef3c8a92
YW
2518 output = check_output('tc qdisc show dev dummy98')
2519 print(output)
f1de1eb3
YW
2520 self.assertRegex(output, 'qdisc clsact')
2521
2522 self.assertRegex(output, 'qdisc htb 2: root')
2523 self.assertRegex(output, r'default (0x30|30)')
2524
2525 self.assertRegex(output, 'qdisc netem 30: parent 2:30')
7887e580 2526 self.assertRegex(output, 'limit 100 delay 50(.0)?ms 10(.0)?ms loss 20%')
40821c2a 2527 self.assertRegex(output, 'qdisc fq_codel')
7887e580 2528 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')
ef3c8a92 2529
f1de1eb3 2530 self.assertRegex(output, 'qdisc teql1 31: parent 2:31')
0baddbd5 2531
f1de1eb3 2532 self.assertRegex(output, 'qdisc fq 32: parent 2:32')
a05a6e8b
YW
2533 self.assertRegex(output, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
2534 self.assertRegex(output, 'quantum 1500')
2535 self.assertRegex(output, 'initial_quantum 13000')
2536 self.assertRegex(output, 'maxrate 1Mbit')
ab9dc1db 2537
f1de1eb3 2538 self.assertRegex(output, 'qdisc codel 33: parent 2:33')
7887e580 2539 self.assertRegex(output, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn')
ab9dc1db 2540
f1de1eb3 2541 self.assertRegex(output, 'qdisc fq_codel 34: parent 2:34')
7887e580 2542 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')
ab9dc1db 2543
f1de1eb3 2544 self.assertRegex(output, 'qdisc tbf 35: parent 2:35')
7887e580 2545 self.assertRegex(output, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms')
ab9dc1db 2546
f1de1eb3
YW
2547 self.assertRegex(output, 'qdisc sfq 36: parent 2:36')
2548 self.assertRegex(output, 'perturb 5sec')
3d55b5a9 2549
bc0769c9
YW
2550 self.assertRegex(output, 'qdisc pfifo 37: parent 2:37')
2551 self.assertRegex(output, 'limit 100000p')
2552
95edcf3f
YW
2553 self.assertRegex(output, 'qdisc gred 38: parent 2:38')
2554 self.assertRegex(output, 'vqs 12 default 10 grio')
2555
f2c5c129
YW
2556 self.assertRegex(output, 'qdisc sfb 39: parent 2:39')
2557 self.assertRegex(output, 'limit 200000')
2558
7b1a31a3
YW
2559 self.assertRegex(output, 'qdisc bfifo 3a: parent 2:3a')
2560 self.assertRegex(output, 'limit 1000000')
2561
73136507
YW
2562 self.assertRegex(output, 'qdisc pfifo_head_drop 3b: parent 2:3b')
2563 self.assertRegex(output, 'limit 1023p')
2564
41bb371b
YW
2565 self.assertRegex(output, 'qdisc pfifo_fast 3c: parent 2:3c')
2566
2ee7e54b 2567 output = check_output('tc -d class show dev dummy98')
ab9dc1db 2568 print(output)
f1de1eb3
YW
2569 self.assertRegex(output, 'class htb 2:30 root leaf 30:')
2570 self.assertRegex(output, 'class htb 2:31 root leaf 31:')
2571 self.assertRegex(output, 'class htb 2:32 root leaf 32:')
2572 self.assertRegex(output, 'class htb 2:33 root leaf 33:')
2573 self.assertRegex(output, 'class htb 2:34 root leaf 34:')
2574 self.assertRegex(output, 'class htb 2:35 root leaf 35:')
2575 self.assertRegex(output, 'class htb 2:36 root leaf 36:')
bc0769c9 2576 self.assertRegex(output, 'class htb 2:37 root leaf 37:')
95edcf3f 2577 self.assertRegex(output, 'class htb 2:38 root leaf 38:')
f2c5c129 2578 self.assertRegex(output, 'class htb 2:39 root leaf 39:')
7b1a31a3 2579 self.assertRegex(output, 'class htb 2:3a root leaf 3a:')
73136507 2580 self.assertRegex(output, 'class htb 2:3b root leaf 3b:')
41bb371b 2581 self.assertRegex(output, 'class htb 2:3c root leaf 3c:')
2ee7e54b
YW
2582 self.assertRegex(output, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit')
2583 self.assertRegex(output, 'burst 123456')
2584 self.assertRegex(output, 'cburst 123457')
0baddbd5 2585
557fa421 2586 def test_qdisc2(self):
891ff963
YW
2587 copy_unit_to_networkd_unit_path('25-qdisc-drr.network', '12-dummy.netdev',
2588 '25-qdisc-qfq.network', '11-dummy.netdev')
557fa421
YW
2589 start_networkd()
2590
891ff963 2591 self.wait_online(['dummy98:routable', 'test1:routable'])
557fa421
YW
2592
2593 output = check_output('tc qdisc show dev dummy98')
2594 print(output)
2595 self.assertRegex(output, 'qdisc drr 2: root')
2596 output = check_output('tc class show dev dummy98')
2597 print(output)
2598 self.assertRegex(output, 'class drr 2:30 root quantum 2000b')
2599
891ff963
YW
2600 output = check_output('tc qdisc show dev test1')
2601 print(output)
2602 self.assertRegex(output, 'qdisc qfq 2: root')
2603 output = check_output('tc class show dev test1')
2604 print(output)
2605 self.assertRegex(output, 'class qfq 2:30 root weight 2 maxpkt 16000')
2606 self.assertRegex(output, 'class qfq 2:31 root weight 10 maxpkt 8000')
2607
f6c6af38
YW
2608 @expectedFailureIfCAKEIsNotAvailable()
2609 def test_qdisc_cake(self):
2610 copy_unit_to_networkd_unit_path('25-qdisc-cake.network', '12-dummy.netdev')
3d55b5a9 2611 start_networkd()
3d55b5a9
YW
2612 self.wait_online(['dummy98:routable'])
2613
2614 output = check_output('tc qdisc show dev dummy98')
2615 print(output)
f6c6af38
YW
2616 self.assertRegex(output, 'qdisc cake 3a: root')
2617 self.assertRegex(output, 'bandwidth 500Mbit')
2618 self.assertRegex(output, 'overhead 128')
3d55b5a9 2619
be94e591
YW
2620 @expectedFailureIfPIEIsNotAvailable()
2621 def test_qdisc_pie(self):
2622 copy_unit_to_networkd_unit_path('25-qdisc-pie.network', '12-dummy.netdev')
2623 start_networkd()
2624 self.wait_online(['dummy98:routable'])
2625
2626 output = check_output('tc qdisc show dev dummy98')
2627 print(output)
2628 self.assertRegex(output, 'qdisc pie 3a: root')
2629 self.assertRegex(output, 'limit 200000')
2630
970ab1fc
YW
2631 @expectedFailureIfHHFIsNotAvailable()
2632 def test_qdisc_hhf(self):
2633 copy_unit_to_networkd_unit_path('25-qdisc-hhf.network', '12-dummy.netdev')
2634 start_networkd()
2635 self.wait_online(['dummy98:routable'])
2636
2637 output = check_output('tc qdisc show dev dummy98')
2638 print(output)
2639 self.assertRegex(output, 'qdisc hhf 3a: root')
2640 self.assertRegex(output, 'limit 1022p')
2641
b753e835
YW
2642 @expectedFailureIfETSIsNotAvailable()
2643 def test_qdisc_ets(self):
2644 copy_unit_to_networkd_unit_path('25-qdisc-ets.network', '12-dummy.netdev')
2645 start_networkd()
2646 self.wait_online(['dummy98:routable'])
2647
2648 output = check_output('tc qdisc show dev dummy98')
2649 print(output)
2650 self.assertRegex(output, 'qdisc ets 3a: root')
2651 self.assertRegex(output, 'bands 10 strict 3')
2652 self.assertRegex(output, 'quanta 1 2 3 4 5')
2653 self.assertRegex(output, 'priomap 3 4 5 6 7')
2654
3d2c2692
YW
2655 @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable()
2656 def test_sriov(self):
2657 call('rmmod netdevsim', stderr=subprocess.DEVNULL)
2658 call('modprobe netdevsim', stderr=subprocess.DEVNULL)
2659 with open('/sys/bus/netdevsim/new_device', mode='w') as f:
2660 f.write('99 1')
2661
2662 call('udevadm settle')
2663 call('udevadm info -w10s /sys/devices/netdevsim99/net/eni99np1', stderr=subprocess.DEVNULL)
2664 with open('/sys/class/net/eni99np1/device/sriov_numvfs', mode='w') as f:
2665 f.write('3')
2666
2667 copy_unit_to_networkd_unit_path('25-sriov.network')
2668 start_networkd()
2669 self.wait_online(['eni99np1:routable'])
2670
2671 output = check_output('ip link show dev eni99np1')
2672 print(output)
2673 self.assertRegex(output,
2674 '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 *'
2675 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
2676 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
2677 )
2678
2679 call('rmmod netdevsim', stderr=subprocess.DEVNULL)
2680
336d18f0
YW
2681class NetworkdStateFileTests(unittest.TestCase, Utilities):
2682 links = [
2683 'dummy98',
2684 ]
2685
2686 units = [
2687 '12-dummy.netdev',
2688 'state-file-tests.network',
2689 ]
2690
2691 def setUp(self):
2692 remove_links(self.links)
2693 stop_networkd(show_logs=False)
2694
2695 def tearDown(self):
2696 remove_links(self.links)
2697 remove_unit_from_networkd_path(self.units)
2698 stop_networkd(show_logs=True)
2699
2700 def test_state_file(self):
2701 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'state-file-tests.network')
2702 start_networkd()
2703 self.wait_online(['dummy98:routable'])
2704
2705 output = check_output(*networkctl_cmd, '--no-legend', 'list', 'dummy98', env=env)
2706 print(output)
2707 ifindex = output.split()[0]
2708
2709 path = os.path.join('/run/systemd/netif/links/', ifindex)
2710 self.assertTrue(os.path.exists(path))
f91b2340
YW
2711
2712 # make link state file updated
2713 check_output(*resolvectl_cmd, 'revert', 'dummy98', env=env)
336d18f0
YW
2714
2715 with open(path) as f:
2716 data = f.read()
2717 self.assertRegex(data, r'ADMIN_STATE=configured')
2718 self.assertRegex(data, r'OPER_STATE=routable')
2719 self.assertRegex(data, r'REQUIRED_FOR_ONLINE=yes')
2720 self.assertRegex(data, r'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
2721 self.assertRegex(data, r'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
66479677 2722 self.assertRegex(data, r'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
336d18f0
YW
2723 self.assertRegex(data, r'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2724 self.assertRegex(data, r'DOMAINS=hogehoge')
2725 self.assertRegex(data, r'ROUTE_DOMAINS=foofoo')
2726 self.assertRegex(data, r'LLMNR=no')
2727 self.assertRegex(data, r'MDNS=yes')
2728 self.assertRegex(data, r'DNSSEC=no')
426654d7 2729 self.assertRegex(data, r'ADDRESSES=192.168.(10.10|12.12)/24 192.168.(12.12|10.10)/24')
336d18f0 2730
66479677 2731 check_output(*resolvectl_cmd, 'dns', 'dummy98', '10.10.10.12#ccc.com', '10.10.10.13', '1111:2222::3333', env=env)
336d18f0
YW
2732 check_output(*resolvectl_cmd, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env=env)
2733 check_output(*resolvectl_cmd, 'llmnr', 'dummy98', 'yes', env=env)
2734 check_output(*resolvectl_cmd, 'mdns', 'dummy98', 'no', env=env)
2735 check_output(*resolvectl_cmd, 'dnssec', 'dummy98', 'yes', env=env)
2736 check_output(*timedatectl_cmd, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env=env)
336d18f0
YW
2737
2738 with open(path) as f:
2739 data = f.read()
66479677 2740 self.assertRegex(data, r'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333')
336d18f0
YW
2741 self.assertRegex(data, r'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org')
2742 self.assertRegex(data, r'DOMAINS=hogehogehoge')
2743 self.assertRegex(data, r'ROUTE_DOMAINS=foofoofoo')
2744 self.assertRegex(data, r'LLMNR=yes')
2745 self.assertRegex(data, r'MDNS=no')
2746 self.assertRegex(data, r'DNSSEC=yes')
2747
2748 check_output(*timedatectl_cmd, 'revert', 'dummy98', env=env)
336d18f0
YW
2749
2750 with open(path) as f:
2751 data = f.read()
66479677 2752 self.assertRegex(data, r'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333')
336d18f0
YW
2753 self.assertRegex(data, r'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2754 self.assertRegex(data, r'DOMAINS=hogehogehoge')
2755 self.assertRegex(data, r'ROUTE_DOMAINS=foofoofoo')
2756 self.assertRegex(data, r'LLMNR=yes')
2757 self.assertRegex(data, r'MDNS=no')
2758 self.assertRegex(data, r'DNSSEC=yes')
2759
2760 check_output(*resolvectl_cmd, 'revert', 'dummy98', env=env)
336d18f0
YW
2761
2762 with open(path) as f:
2763 data = f.read()
66479677 2764 self.assertRegex(data, r'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
336d18f0
YW
2765 self.assertRegex(data, r'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2766 self.assertRegex(data, r'DOMAINS=hogehoge')
2767 self.assertRegex(data, r'ROUTE_DOMAINS=foofoo')
2768 self.assertRegex(data, r'LLMNR=no')
2769 self.assertRegex(data, r'MDNS=yes')
2770 self.assertRegex(data, r'DNSSEC=no')
2771
be68c2c9 2772class NetworkdBondTests(unittest.TestCase, Utilities):
c3a8853f 2773 links = [
c2990ec3 2774 'bond199',
c3a8853f 2775 'bond99',
cc3e488c
YW
2776 'dummy98',
2777 'test1']
c3a8853f
YW
2778
2779 units = [
cc3e488c
YW
2780 '11-dummy.netdev',
2781 '12-dummy.netdev',
c2990ec3
YW
2782 '23-active-slave.network',
2783 '23-bond199.network',
2784 '23-primary-slave.network',
c2990ec3 2785 '25-bond-active-backup-slave.netdev',
c3a8853f 2786 '25-bond.netdev',
c3a8853f 2787 'bond99.network',
cc3e488c 2788 'bond-slave.network']
c3a8853f
YW
2789
2790 def setUp(self):
ec38833c 2791 remove_links(self.links)
aaae5713 2792 stop_networkd(show_logs=False)
c3a8853f
YW
2793
2794 def tearDown(self):
ec38833c
ZJS
2795 remove_links(self.links)
2796 remove_unit_from_networkd_path(self.units)
aaae5713 2797 stop_networkd(show_logs=True)
c3a8853f 2798
c2990ec3 2799 def test_bond_active_slave(self):
ec38833c 2800 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2cf6fdff 2801 start_networkd()
e2aea43f 2802 self.wait_online(['dummy98:enslaved', 'bond199:degraded'])
c2990ec3 2803
371810d1 2804 output = check_output('ip -d link show bond199')
c2990ec3
YW
2805 print(output)
2806 self.assertRegex(output, 'active_slave dummy98')
2807
2808 def test_bond_primary_slave(self):
35a78c51 2809 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2cf6fdff 2810 start_networkd()
e2aea43f 2811 self.wait_online(['dummy98:enslaved', 'bond199:degraded'])
c2990ec3 2812
371810d1 2813 output = check_output('ip -d link show bond199')
c2990ec3 2814 print(output)
35a78c51 2815 self.assertRegex(output, 'primary dummy98')
c2990ec3 2816
cc3e488c 2817 def test_bond_operstate(self):
ec38833c
ZJS
2818 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
2819 'bond99.network','bond-slave.network')
2cf6fdff 2820 start_networkd()
e2aea43f 2821 self.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
c3a8853f 2822
371810d1 2823 output = check_output('ip -d link show dummy98')
c3a8853f 2824 print(output)
cc3e488c 2825 self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
c3a8853f 2826
371810d1 2827 output = check_output('ip -d link show test1')
c3a8853f
YW
2828 print(output)
2829 self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
2830
371810d1 2831 output = check_output('ip -d link show bond99')
c3a8853f
YW
2832 print(output)
2833 self.assertRegex(output, 'MASTER,UP,LOWER_UP')
2834
19cf3143
DS
2835 self.wait_operstate('dummy98', 'enslaved')
2836 self.wait_operstate('test1', 'enslaved')
2837 self.wait_operstate('bond99', 'routable')
c3a8853f 2838
cefd6b3d 2839 check_output('ip link set dummy98 down')
c3a8853f 2840
19cf3143
DS
2841 self.wait_operstate('dummy98', 'off')
2842 self.wait_operstate('test1', 'enslaved')
2843 self.wait_operstate('bond99', 'degraded-carrier')
c3a8853f 2844
cefd6b3d 2845 check_output('ip link set dummy98 up')
c3a8853f 2846
19cf3143
DS
2847 self.wait_operstate('dummy98', 'enslaved')
2848 self.wait_operstate('test1', 'enslaved')
2849 self.wait_operstate('bond99', 'routable')
c3a8853f 2850
cefd6b3d
ZJS
2851 check_output('ip link set dummy98 down')
2852 check_output('ip link set test1 down')
cc3e488c 2853
19cf3143
DS
2854 self.wait_operstate('dummy98', 'off')
2855 self.wait_operstate('test1', 'off')
2700d2c7 2856
a4632dc7 2857 if not self.wait_operstate('bond99', 'no-carrier', setup_timeout=30, fail_assert=False):
2700d2c7
YW
2858 # Huh? Kernel does not recognize that all slave interfaces are down?
2859 # Let's confirm that networkd's operstate is consistent with ip's result.
2860 self.assertNotRegex(output, 'NO-CARRIER')
cc3e488c 2861
be68c2c9 2862class NetworkdBridgeTests(unittest.TestCase, Utilities):
09ea6724
YW
2863 links = [
2864 'bridge99',
2865 'dummy98',
2866 'test1']
2867
2868 units = [
2869 '11-dummy.netdev',
2870 '12-dummy.netdev',
2871 '26-bridge.netdev',
0fc0d85f 2872 '26-bridge-configure-without-carrier.network',
cc0276cc
YW
2873 '26-bridge-mdb-master.network',
2874 '26-bridge-mdb-slave.network',
09ea6724
YW
2875 '26-bridge-slave-interface-1.network',
2876 '26-bridge-slave-interface-2.network',
6f943798
YW
2877 '26-bridge-vlan-master.network',
2878 '26-bridge-vlan-slave.network',
804b6cd2 2879 'bridge99-ignore-carrier-loss.network',
09ea6724 2880 'bridge99.network']
1f0e3109 2881
8d17c386
YW
2882 routing_policy_rule_tables = ['100']
2883
1f0e3109 2884 def setUp(self):
8d17c386 2885 remove_routing_policy_rule_tables(self.routing_policy_rule_tables)
ec38833c 2886 remove_links(self.links)
aaae5713 2887 stop_networkd(show_logs=False)
1f0e3109
SS
2888
2889 def tearDown(self):
8d17c386 2890 remove_routing_policy_rule_tables(self.routing_policy_rule_tables)
ec38833c
ZJS
2891 remove_links(self.links)
2892 remove_unit_from_networkd_path(self.units)
aaae5713 2893 stop_networkd(show_logs=True)
1f0e3109 2894
6f943798
YW
2895 def test_bridge_vlan(self):
2896 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
2897 '26-bridge.netdev', '26-bridge-vlan-master.network')
2898 start_networkd()
e2aea43f 2899 self.wait_online(['test1:enslaved', 'bridge99:degraded'])
6f943798
YW
2900
2901 output = check_output('bridge vlan show dev test1')
2902 print(output)
2903 self.assertNotRegex(output, '4063')
2904 for i in range(4064, 4095):
2905 self.assertRegex(output, f'{i}')
2906 self.assertNotRegex(output, '4095')
2907
2908 output = check_output('bridge vlan show dev bridge99')
2909 print(output)
2910 self.assertNotRegex(output, '4059')
2911 for i in range(4060, 4095):
2912 self.assertRegex(output, f'{i}')
2913 self.assertNotRegex(output, '4095')
2914
cc0276cc
YW
2915 def test_bridge_mdb(self):
2916 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-mdb-slave.network',
2917 '26-bridge.netdev', '26-bridge-mdb-master.network')
2918 start_networkd()
2919 self.wait_online(['test1:enslaved', 'bridge99:degraded'])
2920
2921 output = check_output('bridge mdb show dev bridge99')
2922 print(output)
2923 self.assertRegex(output, 'dev bridge99 port test1 grp ff02:aaaa:fee5::1:3 permanent *vid 4064')
2924 self.assertRegex(output, 'dev bridge99 port test1 grp 224.0.1.1 permanent *vid 4065')
2925
1f0e3109 2926 def test_bridge_property(self):
ec38833c
ZJS
2927 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2928 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2929 'bridge99.network')
2cf6fdff 2930 start_networkd()
e2aea43f 2931 self.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
1f0e3109 2932
371810d1 2933 output = check_output('ip -d link show test1')
1f0e3109
SS
2934 print(output)
2935 self.assertRegex(output, 'master')
2936 self.assertRegex(output, 'bridge')
2937
371810d1 2938 output = check_output('ip -d link show dummy98')
1f0e3109
SS
2939 print(output)
2940 self.assertRegex(output, 'master')
2941 self.assertRegex(output, 'bridge')
2942
371810d1 2943 output = check_output('ip addr show bridge99')
1f0e3109 2944 print(output)
2be6c5d2 2945 self.assertRegex(output, '192.168.0.15/24')
1f0e3109 2946
371810d1 2947 output = check_output('bridge -d link show dummy98')
1f0e3109 2948 print(output)
ec38833c 2949 self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
5424fd95
YW
2950 self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
2951 self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
ec38833c
ZJS
2952 self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
2953 self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
5424fd95
YW
2954 # CONFIG_BRIDGE_IGMP_SNOOPING=y
2955 if (os.path.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
2956 self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
7f15b714 2957 if (os.path.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
ec38833c
ZJS
2958 self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
2959 self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
5424fd95
YW
2960 self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'priority'), '23')
2961 self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard'), '1')
2962 self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'root_block'), '1')
4d7ed14f 2963
5424fd95
YW
2964 output = check_output('bridge -d link show test1')
2965 print(output)
2966 self.assertEqual(read_bridge_port_attr('bridge99', 'test1', 'priority'), '0')
1f0e3109 2967
371810d1 2968 check_output('ip address add 192.168.0.16/24 dev bridge99')
804b6cd2
YW
2969 time.sleep(1)
2970
371810d1 2971 output = check_output('ip addr show bridge99')
2be6c5d2
YW
2972 print(output)
2973 self.assertRegex(output, '192.168.0.16/24')
2974
e3cbaeab
YW
2975 # for issue #6088
2976 print('### ip -6 route list table all dev bridge99')
2977 output = check_output('ip -6 route list table all dev bridge99')
2978 print(output)
2979 self.assertRegex(output, 'ff00::/8 table local metric 256 pref medium')
2980
371810d1 2981 self.assertEqual(call('ip link del test1'), 0)
2be6c5d2 2982
19cf3143 2983 self.wait_operstate('bridge99', 'degraded-carrier')
2be6c5d2 2984
cefd6b3d 2985 check_output('ip link del dummy98')
804b6cd2 2986
19cf3143 2987 self.wait_operstate('bridge99', 'no-carrier')
2be6c5d2 2988
371810d1 2989 output = check_output('ip address show bridge99')
804b6cd2
YW
2990 print(output)
2991 self.assertRegex(output, 'NO-CARRIER')
2992 self.assertNotRegex(output, '192.168.0.15/24')
2993 self.assertNotRegex(output, '192.168.0.16/24')
2994
e3cbaeab
YW
2995 print('### ip -6 route list table all dev bridge99')
2996 output = check_output('ip -6 route list table all dev bridge99')
2997 print(output)
426654d7 2998 self.assertRegex(output, 'ff00::/8 table local metric 256 (linkdown )?pref medium')
e3cbaeab 2999
0fc0d85f
DS
3000 def test_bridge_configure_without_carrier(self):
3001 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-configure-without-carrier.network',
3002 '11-dummy.netdev')
3003 start_networkd()
3004
3005 # With ConfigureWithoutCarrier=yes, the bridge should remain configured for all these situations
3006 for test in ['no-slave', 'add-slave', 'slave-up', 'slave-no-carrier', 'slave-carrier', 'slave-down']:
3007 with self.subTest(test=test):
3008 if test == 'no-slave':
3009 # bridge has no slaves; it's up but *might* not have carrier
001c07cf 3010 self.wait_operstate('bridge99', operstate=r'(no-carrier|routable)', setup_state=None, setup_timeout=30)
0fc0d85f
DS
3011 # due to a bug in the kernel, newly-created bridges are brought up
3012 # *with* carrier, unless they have had any setting changed; e.g.
3013 # their mac set, priority set, etc. Then, they will lose carrier
3014 # as soon as a (down) slave interface is added, and regain carrier
3015 # again once the slave interface is brought up.
3016 #self.check_link_attr('bridge99', 'carrier', '0')
3017 elif test == 'add-slave':
3018 # add slave to bridge, but leave it down; bridge is definitely no-carrier
3019 self.check_link_attr('test1', 'operstate', 'down')
3020 check_output('ip link set dev test1 master bridge99')
001c07cf 3021 self.wait_operstate('bridge99', operstate='no-carrier', setup_state=None)
0fc0d85f
DS
3022 self.check_link_attr('bridge99', 'carrier', '0')
3023 elif test == 'slave-up':
3024 # bring up slave, which will have carrier; bridge gains carrier
3025 check_output('ip link set dev test1 up')
3026 self.wait_online(['bridge99:routable'])
3027 self.check_link_attr('bridge99', 'carrier', '1')
3028 elif test == 'slave-no-carrier':
3029 # drop slave carrier; bridge loses carrier
3030 check_output('ip link set dev test1 carrier off')
3031 self.wait_online(['bridge99:no-carrier:no-carrier'])
3032 self.check_link_attr('bridge99', 'carrier', '0')
3033 elif test == 'slave-carrier':
3034 # restore slave carrier; bridge gains carrier
3035 check_output('ip link set dev test1 carrier on')
3036 self.wait_online(['bridge99:routable'])
3037 self.check_link_attr('bridge99', 'carrier', '1')
3038 elif test == 'slave-down':
3039 # bring down slave; bridge loses carrier
3040 check_output('ip link set dev test1 down')
3041 self.wait_online(['bridge99:no-carrier:no-carrier'])
3042 self.check_link_attr('bridge99', 'carrier', '0')
3043
3044 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'bridge99', env=env)
0fc0d85f
DS
3045 self.assertRegex(output, '10.1.2.3')
3046 self.assertRegex(output, '10.1.2.1')
3047
804b6cd2 3048 def test_bridge_ignore_carrier_loss(self):
ec38833c
ZJS
3049 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
3050 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
3051 'bridge99-ignore-carrier-loss.network')
2cf6fdff 3052 start_networkd()
e2aea43f 3053 self.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
804b6cd2 3054
371810d1 3055 check_output('ip address add 192.168.0.16/24 dev bridge99')
804b6cd2
YW
3056 time.sleep(1)
3057
371810d1
ZJS
3058 check_output('ip link del test1')
3059 check_output('ip link del dummy98')
804b6cd2
YW
3060 time.sleep(3)
3061
371810d1 3062 output = check_output('ip address show bridge99')
804b6cd2
YW
3063 print(output)
3064 self.assertRegex(output, 'NO-CARRIER')
3065 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
3066 self.assertRegex(output, 'inet 192.168.0.16/24 scope global secondary bridge99')
3067
6609924c 3068 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self):
ec38833c
ZJS
3069 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
3070 'bridge99-ignore-carrier-loss.network')
2cf6fdff 3071 start_networkd()
e2aea43f 3072 self.wait_online(['bridge99:no-carrier'])
6609924c 3073
90e3bcbd
YW
3074 for trial in range(4):
3075 check_output('ip link add dummy98 type dummy')
3076 check_output('ip link set dummy98 up')
3077 if trial < 3:
3078 check_output('ip link del dummy98')
6609924c 3079
e2aea43f 3080 self.wait_online(['bridge99:routable', 'dummy98:enslaved'])
6609924c 3081
371810d1 3082 output = check_output('ip address show bridge99')
6609924c
YW
3083 print(output)
3084 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
3085
371810d1 3086 output = check_output('ip rule list table 100')
6609924c
YW
3087 print(output)
3088 self.assertEqual(output, '0: from all to 8.8.8.8 lookup 100')
3089
be68c2c9 3090class NetworkdLLDPTests(unittest.TestCase, Utilities):
1f0e3109
SS
3091 links = ['veth99']
3092
09ea6724
YW
3093 units = [
3094 '23-emit-lldp.network',
3095 '24-lldp.network',
3096 '25-veth.netdev']
1f0e3109
SS
3097
3098 def setUp(self):
ec38833c 3099 remove_links(self.links)
aaae5713 3100 stop_networkd(show_logs=False)
1f0e3109
SS
3101
3102 def tearDown(self):
ec38833c
ZJS
3103 remove_links(self.links)
3104 remove_unit_from_networkd_path(self.units)
aaae5713 3105 stop_networkd(show_logs=True)
1f0e3109
SS
3106
3107 def test_lldp(self):
ec38833c 3108 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
2cf6fdff 3109 start_networkd()
e2aea43f 3110 self.wait_online(['veth99:degraded', 'veth-peer:degraded'])
1f0e3109 3111
371810d1 3112 output = check_output(*networkctl_cmd, 'lldp', env=env)
1f0e3109
SS
3113 print(output)
3114 self.assertRegex(output, 'veth-peer')
3115 self.assertRegex(output, 'veth99')
3116
be68c2c9 3117class NetworkdRATests(unittest.TestCase, Utilities):
1f0e3109
SS
3118 links = ['veth99']
3119
09ea6724
YW
3120 units = [
3121 '25-veth.netdev',
3122 'ipv6-prefix.network',
87bbebea 3123 'ipv6-prefix-veth.network',
e2c4070e 3124 'ipv6-prefix-veth-token-static.network',
68248f43
YW
3125 'ipv6-prefix-veth-token-prefixstable.network',
3126 'ipv6-prefix-veth-token-prefixstable-without-address.network']
1f0e3109
SS
3127
3128 def setUp(self):
ec38833c 3129 remove_links(self.links)
aaae5713 3130 stop_networkd(show_logs=False)
1f0e3109
SS
3131
3132 def tearDown(self):
ec38833c
ZJS
3133 remove_links(self.links)
3134 remove_unit_from_networkd_path(self.units)
aaae5713 3135 stop_networkd(show_logs=True)
1f0e3109
SS
3136
3137 def test_ipv6_prefix_delegation(self):
ec38833c 3138 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
2cf6fdff 3139 start_networkd()
e2aea43f 3140 self.wait_online(['veth99:routable', 'veth-peer:degraded'])
1f0e3109 3141
41fd8fe7
YW
3142 output = check_output(*resolvectl_cmd, 'dns', 'veth99', env=env)
3143 print(output)
3144 self.assertRegex(output, 'fe80::')
3145 self.assertRegex(output, '2002:da8:1::1')
3146
fc79e6ff 3147 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
1f0e3109
SS
3148 print(output)
3149 self.assertRegex(output, '2002:da8:1:0')
3150
e2c4070e
YW
3151 def test_ipv6_token_static(self):
3152 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-static.network')
87bbebea 3153 start_networkd()
b241fa00
KF
3154 self.wait_online(['veth99:routable', 'veth-peer:degraded'])
3155
3156 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
3157 print(output)
3158 self.assertRegex(output, '2002:da8:1:0:1a:2b:3c:4d')
68248f43
YW
3159 self.assertRegex(output, '2002:da8:1:0:fa:de:ca:fe')
3160 self.assertRegex(output, '2002:da8:2:0:1a:2b:3c:4d')
3161 self.assertRegex(output, '2002:da8:2:0:fa:de:ca:fe')
b241fa00 3162
68248f43
YW
3163 def test_ipv6_token_prefixstable(self):
3164 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable.network')
c24c83dc
KF
3165 start_networkd()
3166 self.wait_online(['veth99:routable', 'veth-peer:degraded'])
3167
3168 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
3169 print(output)
68248f43
YW
3170 self.assertRegex(output, '2002:da8:1:0')
3171 self.assertRegex(output, '2002:da8:2:0.*78:9abc') # EUI
c24c83dc 3172
68248f43
YW
3173 def test_ipv6_token_prefixstable_without_address(self):
3174 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth-token-prefixstable-without-address.network')
87bbebea
YW
3175 start_networkd()
3176 self.wait_online(['veth99:routable', 'veth-peer:degraded'])
3177
3178 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
3179 print(output)
3180 self.assertRegex(output, '2002:da8:1:0')
68248f43 3181 self.assertRegex(output, '2002:da8:2:0')
87bbebea 3182
be68c2c9 3183class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
fdcd1ec5 3184 links = ['veth99']
09ea6724
YW
3185
3186 units = [
09ea6724
YW
3187 '25-veth.netdev',
3188 'dhcp-client.network',
3189 'dhcp-client-timezone-router.network',
3190 'dhcp-server.network',
3191 'dhcp-server-timezone-router.network']
1f0e3109
SS
3192
3193 def setUp(self):
ec38833c 3194 remove_links(self.links)
aaae5713 3195 stop_networkd(show_logs=False)
1f0e3109
SS
3196
3197 def tearDown(self):
ec38833c
ZJS
3198 remove_links(self.links)
3199 remove_unit_from_networkd_path(self.units)
aaae5713 3200 stop_networkd(show_logs=True)
1f0e3109
SS
3201
3202 def test_dhcp_server(self):
ec38833c 3203 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
2cf6fdff 3204 start_networkd()
e2aea43f 3205 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1f0e3109 3206
fc79e6ff 3207 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
1f0e3109
SS
3208 print(output)
3209 self.assertRegex(output, '192.168.5.*')
3210 self.assertRegex(output, 'Gateway: 192.168.5.1')
3211 self.assertRegex(output, 'DNS: 192.168.5.1')
3212 self.assertRegex(output, 'NTP: 192.168.5.1')
3213
1f0e3109 3214 def test_emit_router_timezone(self):
ec38833c 3215 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
2cf6fdff 3216 start_networkd()
e2aea43f 3217 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1f0e3109 3218
fc79e6ff 3219 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
1f0e3109
SS
3220 print(output)
3221 self.assertRegex(output, 'Gateway: 192.168.5.*')
3222 self.assertRegex(output, '192.168.5.*')
3223 self.assertRegex(output, 'Europe/Berlin')
3224
be68c2c9 3225class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
09ea6724 3226 links = [
18c613dc
YW
3227 'veth99',
3228 'vrf99']
09ea6724
YW
3229
3230 units = [
3231 '25-veth.netdev',
18c613dc
YW
3232 '25-vrf.netdev',
3233 '25-vrf.network',
09ea6724 3234 'dhcp-client-anonymize.network',
0fd8b718 3235 'dhcp-client-decline.network',
214c5bae
YW
3236 'dhcp-client-gateway-ipv4.network',
3237 'dhcp-client-gateway-ipv6.network',
af3b1498 3238 'dhcp-client-gateway-onlink-implicit.network',
09ea6724
YW
3239 'dhcp-client-ipv4-dhcp-settings.network',
3240 'dhcp-client-ipv4-only-ipv6-disabled.network',
3241 'dhcp-client-ipv4-only.network',
7c0d36ff 3242 'dhcp-client-ipv4-use-routes-use-gateway.network',
09ea6724
YW
3243 'dhcp-client-ipv6-only.network',
3244 'dhcp-client-ipv6-rapid-commit.network',
1e498853
YW
3245 'dhcp-client-keep-configuration-dhcp-on-stop.network',
3246 'dhcp-client-keep-configuration-dhcp.network',
09ea6724 3247 'dhcp-client-listen-port.network',
c1b01a62
YW
3248 'dhcp-client-reassign-static-routes-ipv4.network',
3249 'dhcp-client-reassign-static-routes-ipv6.network',
09ea6724
YW
3250 'dhcp-client-route-metric.network',
3251 'dhcp-client-route-table.network',
e2d5aab3
YW
3252 'dhcp-client-use-dns-ipv4-and-ra.network',
3253 'dhcp-client-use-dns-ipv4.network',
3254 'dhcp-client-use-dns-no.network',
3255 'dhcp-client-use-dns-yes.network',
e0c1341d 3256 'dhcp-client-use-domains.network',
18c613dc 3257 'dhcp-client-vrf.network',
117a55c7
YW
3258 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
3259 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
4c882c16 3260 'dhcp-client-with-static-address.network',
3e9d5552 3261 'dhcp-client.network',
0fd8b718 3262 'dhcp-server-decline.network',
09ea6724 3263 'dhcp-server-veth-peer.network',
30d3b54e
YW
3264 'dhcp-v4-server-veth-peer.network',
3265 'static.network']
1f0e3109
SS
3266
3267 def setUp(self):
ec38833c
ZJS
3268 stop_dnsmasq(dnsmasq_pid_file)
3269 remove_links(self.links)
aaae5713 3270 stop_networkd(show_logs=False)
1f0e3109
SS
3271
3272 def tearDown(self):
ec38833c
ZJS
3273 stop_dnsmasq(dnsmasq_pid_file)
3274 remove_lease_file()
3275 remove_log_file()
3276 remove_links(self.links)
3277 remove_unit_from_networkd_path(self.units)
aaae5713 3278 stop_networkd(show_logs=True)
1f0e3109
SS
3279
3280 def test_dhcp_client_ipv6_only(self):
ec38833c 3281 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
1f0e3109 3282
2cf6fdff 3283 start_networkd()
e2aea43f 3284 self.wait_online(['veth-peer:carrier'])
ec38833c 3285 start_dnsmasq()
e2aea43f 3286 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1f0e3109 3287
fc79e6ff 3288 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
1f0e3109
SS
3289 print(output)
3290 self.assertRegex(output, '2600::')
3291 self.assertNotRegex(output, '192.168.5')
3292
c5fcd8a7
YW
3293 output = check_output('ip addr show dev veth99')
3294 print(output)
3295 self.assertRegex(output, '2600::')
3296 self.assertNotRegex(output, '192.168.5')
3297 self.assertNotRegex(output, 'tentative')
3298
3a956d38 3299 # Confirm that ipv6 token is not set in the kernel
371810d1 3300 output = check_output('ip token show dev veth99')
3a956d38
YW
3301 print(output)
3302 self.assertRegex(output, 'token :: dev veth99')
3303
1f0e3109 3304 def test_dhcp_client_ipv4_only(self):
ec38833c 3305 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
1f0e3109 3306
2cf6fdff 3307 start_networkd()
e2aea43f 3308 self.wait_online(['veth-peer:carrier'])
195a18c1 3309 start_dnsmasq(additional_options='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time='2m')
e2aea43f 3310 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1f0e3109 3311
fc79e6ff 3312 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
1f0e3109
SS
3313 print(output)
3314 self.assertNotRegex(output, '2600::')
3315 self.assertRegex(output, '192.168.5')
195a18c1
YW
3316 self.assertRegex(output, '192.168.5.6')
3317 self.assertRegex(output, '192.168.5.7')
3318
3319 # checking routes to DNS servers
3320 output = check_output('ip route show dev veth99')
3321 print(output)
3322 self.assertRegex(output, r'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3323 self.assertRegex(output, r'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3324 self.assertRegex(output, r'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3325
3326 stop_dnsmasq(dnsmasq_pid_file)
3327 start_dnsmasq(additional_options='--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8', lease_time='2m')
3328
3329 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3330 print('Wait for the dynamic address to be renewed')
3331 time.sleep(125)
3332
3333 self.wait_online(['veth99:routable', 'veth-peer:routable'])
3334
fc79e6ff 3335 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
195a18c1
YW
3336 print(output)
3337 self.assertNotRegex(output, '2600::')
3338 self.assertRegex(output, '192.168.5')
3339 self.assertNotRegex(output, '192.168.5.6')
3340 self.assertRegex(output, '192.168.5.7')
3341 self.assertRegex(output, '192.168.5.8')
3342
3343 # checking routes to DNS servers
3344 output = check_output('ip route show dev veth99')
3345 print(output)
3346 self.assertNotRegex(output, r'192.168.5.6')
3347 self.assertRegex(output, r'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
3348 self.assertRegex(output, r'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3349 self.assertRegex(output, r'192.168.5.8 proto dhcp scope link src 192.168.5.181 metric 1024')
1f0e3109 3350
7c0d36ff 3351 def test_dhcp_client_ipv4_use_routes_gateway(self):
06c2b0c7 3352 for (routes, gateway, dnsroutes) in itertools.product([True, False, None], repeat=3):
7c0d36ff 3353 self.setUp()
06c2b0c7
DS
3354 with self.subTest(routes=routes, gateway=gateway, dnsroutes=dnsroutes):
3355 self._test_dhcp_client_ipv4_use_routes_gateway(routes, gateway, dnsroutes)
7c0d36ff
DS
3356 self.tearDown()
3357
06c2b0c7 3358 def _test_dhcp_client_ipv4_use_routes_gateway(self, routes, gateway, dnsroutes):
7c0d36ff
DS
3359 testunit = 'dhcp-client-ipv4-use-routes-use-gateway.network'
3360 testunits = ['25-veth.netdev', 'dhcp-server-veth-peer.network', testunit]
3361 if routes != None:
3362 testunits.append(f'{testunit}.d/use-routes-{routes}.conf');
3363 if gateway != None:
3364 testunits.append(f'{testunit}.d/use-gateway-{gateway}.conf');
06c2b0c7
DS
3365 if dnsroutes != None:
3366 testunits.append(f'{testunit}.d/use-dns-routes-{dnsroutes}.conf');
7c0d36ff 3367 copy_unit_to_networkd_unit_path(*testunits, dropins=False)
4c2e1833
YW
3368
3369 start_networkd()
3370 self.wait_online(['veth-peer:carrier'])
3371 start_dnsmasq(additional_options='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time='2m')
3372 self.wait_online(['veth99:routable', 'veth-peer:routable'])
3373
3374 output = check_output('ip route show dev veth99')
3375 print(output)
4c2e1833 3376
7c0d36ff
DS
3377 # UseRoutes= defaults to true
3378 useroutes = routes in [True, None]
3379 # UseGateway= defaults to useroutes
3380 usegateway = useroutes if gateway == None else gateway
0d7bd445 3381
7c0d36ff
DS
3382 # Check UseRoutes=
3383 if useroutes:
3384 self.assertRegex(output, r'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.181 metric 1024')
3385 else:
3386 self.assertNotRegex(output, r'192.168.5.5')
0d7bd445 3387
7c0d36ff
DS
3388 # Check UseGateway=
3389 if usegateway:
3390 self.assertRegex(output, r'default via 192.168.5.1 proto dhcp src 192.168.5.181 metric 1024')
3391 else:
3392 self.assertNotRegex(output, r'default via 192.168.5.1')
3393
06c2b0c7
DS
3394 # Check RoutesToDNS=, which defaults to false
3395 if dnsroutes:
7c0d36ff
DS
3396 self.assertRegex(output, r'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
3397 self.assertRegex(output, r'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
3398 else:
3399 self.assertNotRegex(output, r'192.168.5.6')
3400 self.assertNotRegex(output, r'192.168.5.7')
0d7bd445 3401
1f0e3109 3402 def test_dhcp_client_ipv4_ipv6(self):
ec38833c
ZJS
3403 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
3404 'dhcp-client-ipv4-only.network')
2cf6fdff 3405 start_networkd()
e2aea43f 3406 self.wait_online(['veth-peer:carrier'])
ec38833c 3407 start_dnsmasq()
e2aea43f 3408 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2629df47
YW
3409
3410 # link become 'routable' when at least one protocol provide an valid address.
e16ffe79 3411 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4')
426654d7 3412 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
1f0e3109 3413
fc79e6ff 3414 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
1f0e3109
SS
3415 print(output)
3416 self.assertRegex(output, '2600::')
3417 self.assertRegex(output, '192.168.5')
3418
3419 def test_dhcp_client_settings(self):
ec38833c 3420 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
1f0e3109 3421
2cf6fdff 3422 start_networkd()
e2aea43f 3423 self.wait_online(['veth-peer:carrier'])
ec38833c 3424 start_dnsmasq()
e2aea43f 3425 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1f0e3109 3426
0ae7a66d 3427 print('## ip address show dev veth99')
371810d1 3428 output = check_output('ip address show dev veth99')
1f0e3109
SS
3429 print(output)
3430 self.assertRegex(output, '12:34:56:78:9a:bc')
3431 self.assertRegex(output, '192.168.5')
3432 self.assertRegex(output, '1492')
3433
0ae7a66d 3434 print('## ip route show table main dev veth99')
371810d1 3435 output = check_output('ip route show table main dev veth99')
1f0e3109 3436 print(output)
156ddf8d 3437 # See issue #8726
dd9b10c8
YW
3438 main_table_is_empty = output == ''
3439 if not main_table_is_empty:
3440 self.assertNotRegex(output, 'proto dhcp')
1f0e3109 3441
0ae7a66d 3442 print('## ip route show table 211 dev veth99')
371810d1 3443 output = check_output('ip route show table 211 dev veth99')
0ae7a66d
YW
3444 print(output)
3445 self.assertRegex(output, 'default via 192.168.5.1 proto dhcp')
dd9b10c8
YW
3446 if main_table_is_empty:
3447 self.assertRegex(output, '192.168.5.0/24 proto dhcp')
0ae7a66d
YW
3448 self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
3449 self.assertRegex(output, '192.168.5.1 proto dhcp scope link')
3450
3451 print('## dnsmasq log')
ec38833c
ZJS
3452 self.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
3453 self.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
3454 self.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
3455 self.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
1f0e3109
SS
3456
3457 def test_dhcp6_client_settings_rapidcommit_true(self):
ec38833c 3458 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2cf6fdff 3459 start_networkd()
e2aea43f 3460 self.wait_online(['veth-peer:carrier'])
ec38833c 3461 start_dnsmasq()
e2aea43f 3462 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1f0e3109 3463
371810d1 3464 output = check_output('ip address show dev veth99')
1f0e3109
SS
3465 print(output)
3466 self.assertRegex(output, '12:34:56:78:9a:bc')
ec38833c 3467 self.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
1f0e3109
SS
3468
3469 def test_dhcp6_client_settings_rapidcommit_false(self):
ec38833c 3470 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
2cf6fdff 3471 start_networkd()
e2aea43f 3472 self.wait_online(['veth-peer:carrier'])
ec38833c 3473 start_dnsmasq()
e2aea43f 3474 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1f0e3109 3475
371810d1 3476 output = check_output('ip address show dev veth99')
1f0e3109
SS
3477 print(output)
3478 self.assertRegex(output, '12:34:56:78:9a:bc')
ec38833c 3479 self.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
1f0e3109
SS
3480
3481 def test_dhcp_client_settings_anonymize(self):
ec38833c 3482 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
2cf6fdff 3483 start_networkd()
e2aea43f 3484 self.wait_online(['veth-peer:carrier'])
ec38833c 3485 start_dnsmasq()
e2aea43f 3486 self.wait_online(['veth99:routable', 'veth-peer:routable'])
e40a58b5 3487
ec38833c
ZJS
3488 self.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
3489 self.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
3490 self.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
1f0e3109
SS
3491
3492 def test_dhcp_client_listen_port(self):
ec38833c 3493 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
2cf6fdff 3494 start_networkd()
e2aea43f 3495 self.wait_online(['veth-peer:carrier'])
ec38833c 3496 start_dnsmasq('--dhcp-alternate-port=67,5555')
e2aea43f 3497 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2629df47 3498
371810d1 3499 output = check_output('ip -4 address show dev veth99')
b412fce8
YW
3500 print(output)
3501 self.assertRegex(output, '192.168.5.* dynamic')
1f0e3109 3502
4c882c16
YW
3503 def test_dhcp_client_with_static_address(self):
3504 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
3505 'dhcp-client-with-static-address.network')
3506 start_networkd()
e2aea43f 3507 self.wait_online(['veth-peer:carrier'])
4c882c16 3508 start_dnsmasq()
e2aea43f 3509 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4c882c16
YW
3510
3511 output = check_output('ip address show dev veth99 scope global')
3512 print(output)
3513 self.assertRegex(output, r'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
3514 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
3515
3516 output = check_output('ip route show dev veth99')
3517 print(output)
3518 self.assertRegex(output, r'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
3519 self.assertRegex(output, r'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
3520 self.assertRegex(output, r'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
3521 self.assertRegex(output, r'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
3522
1f0e3109 3523 def test_dhcp_route_table_id(self):
ec38833c 3524 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
2cf6fdff 3525 start_networkd()
e2aea43f 3526 self.wait_online(['veth-peer:carrier'])
ec38833c 3527 start_dnsmasq()
e2aea43f 3528 self.wait_online(['veth99:routable', 'veth-peer:routable'])
e40a58b5 3529
371810d1 3530 output = check_output('ip route show table 12')
1f0e3109 3531 print(output)
1f0e3109
SS
3532 self.assertRegex(output, 'veth99 proto dhcp')
3533 self.assertRegex(output, '192.168.5.1')
3534
3535 def test_dhcp_route_metric(self):
ec38833c 3536 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
2cf6fdff 3537 start_networkd()
e2aea43f 3538 self.wait_online(['veth-peer:carrier'])
ec38833c 3539 start_dnsmasq()
e2aea43f 3540 self.wait_online(['veth99:routable', 'veth-peer:routable'])
e40a58b5 3541
371810d1 3542 output = check_output('ip route show dev veth99')
1f0e3109 3543 print(output)
1f0e3109
SS
3544 self.assertRegex(output, 'metric 24')
3545
c1b01a62 3546 def test_dhcp_client_reassign_static_routes_ipv4(self):
c38d2d4d 3547 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
c1b01a62 3548 'dhcp-client-reassign-static-routes-ipv4.network')
c38d2d4d 3549 start_networkd()
e2aea43f 3550 self.wait_online(['veth-peer:carrier'])
c38d2d4d 3551 start_dnsmasq(lease_time='2m')
e2aea43f 3552 self.wait_online(['veth99:routable', 'veth-peer:routable'])
c38d2d4d
YW
3553
3554 output = check_output('ip address show dev veth99 scope global')
3555 print(output)
3556 self.assertRegex(output, r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3557
3558 output = check_output('ip route show dev veth99')
3559 print(output)
3560 self.assertRegex(output, r'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3561 self.assertRegex(output, r'192.168.5.0/24 proto static')
3562 self.assertRegex(output, r'192.168.6.0/24 proto static')
3563 self.assertRegex(output, r'192.168.7.0/24 proto static')
3564
c1b01a62
YW
3565 stop_dnsmasq(dnsmasq_pid_file)
3566 start_dnsmasq(ipv4_range='192.168.5.210,192.168.5.220', lease_time='2m')
3567
c38d2d4d
YW
3568 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3569 print('Wait for the dynamic address to be renewed')
3570 time.sleep(125)
3571
e2aea43f 3572 self.wait_online(['veth99:routable'])
c38d2d4d
YW
3573
3574 output = check_output('ip route show dev veth99')
3575 print(output)
3576 self.assertRegex(output, r'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
3577 self.assertRegex(output, r'192.168.5.0/24 proto static')
3578 self.assertRegex(output, r'192.168.6.0/24 proto static')
3579 self.assertRegex(output, r'192.168.7.0/24 proto static')
3580
c1b01a62
YW
3581 def test_dhcp_client_reassign_static_routes_ipv6(self):
3582 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3583 'dhcp-client-reassign-static-routes-ipv6.network')
3584 start_networkd()
e2aea43f 3585 self.wait_online(['veth-peer:carrier'])
c1b01a62 3586 start_dnsmasq(lease_time='2m')
e2aea43f 3587 self.wait_online(['veth99:routable', 'veth-peer:routable'])
c1b01a62
YW
3588
3589 output = check_output('ip address show dev veth99 scope global')
3590 print(output)
426654d7 3591 self.assertRegex(output, r'inet6 2600::[0-9a-f]*/128 scope global (noprefixroute dynamic|dynamic noprefixroute)')
c1b01a62
YW
3592
3593 output = check_output('ip -6 route show dev veth99')
3594 print(output)
3595 self.assertRegex(output, r'2600::/64 proto ra metric 1024')
3596 self.assertRegex(output, r'2600:0:0:1::/64 proto static metric 1024 pref medium')
3597
3598 stop_dnsmasq(dnsmasq_pid_file)
3599 start_dnsmasq(ipv6_range='2600::30,2600::40', lease_time='2m')
3600
3601 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
3602 print('Wait for the dynamic address to be renewed')
3603 time.sleep(125)
3604
e2aea43f 3605 self.wait_online(['veth99:routable'])
c1b01a62
YW
3606
3607 output = check_output('ip -6 route show dev veth99')
3608 print(output)
3609 self.assertRegex(output, r'2600::/64 proto ra metric 1024')
3610 self.assertRegex(output, r'2600:0:0:1::/64 proto static metric 1024 pref medium')
3611
1e498853
YW
3612 def test_dhcp_keep_configuration_dhcp(self):
3613 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
2cf6fdff 3614 start_networkd()
e2aea43f 3615 self.wait_online(['veth-peer:carrier'])
1e498853 3616 start_dnsmasq(lease_time='2m')
e2aea43f 3617 self.wait_online(['veth99:routable', 'veth-peer:routable'])
e40a58b5 3618
1e498853
YW
3619 output = check_output('ip address show dev veth99 scope global')
3620 print(output)
3621 self.assertRegex(output, r'192.168.5.*')
3622
fc79e6ff 3623 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
1f0e3109 3624 print(output)
1e498853 3625 self.assertRegex(output, r'192.168.5.*')
e40a58b5 3626
5238e957 3627 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
ec38833c 3628 stop_dnsmasq(dnsmasq_pid_file)
1f0e3109
SS
3629
3630 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
1e498853 3631 print('Wait for the dynamic address to be expired')
1f0e3109
SS
3632 time.sleep(125)
3633
1e498853
YW
3634 print('The lease address should be kept after lease expired')
3635 output = check_output('ip address show dev veth99 scope global')
3636 print(output)
3637 self.assertRegex(output, r'192.168.5.*')
3638
fc79e6ff 3639 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
1f0e3109 3640 print(output)
1e498853
YW
3641 self.assertRegex(output, r'192.168.5.*')
3642
3aa645f0
MB
3643 check_output('systemctl stop systemd-networkd.socket')
3644 check_output('systemctl stop systemd-networkd.service')
1e498853
YW
3645
3646 print('The lease address should be kept after networkd stopped')
3647 output = check_output('ip address show dev veth99 scope global')
3648 print(output)
3649 self.assertRegex(output, r'192.168.5.*')
3650
fc79e6ff 3651 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
1e498853
YW
3652 print(output)
3653 self.assertRegex(output, r'192.168.5.*')
3654
e2aea43f
YW
3655 start_networkd(3)
3656 self.wait_online(['veth-peer:routable'])
1e498853
YW
3657
3658 print('Still the lease address should be kept after networkd restarted')
3659 output = check_output('ip address show dev veth99 scope global')
3660 print(output)
3661 self.assertRegex(output, r'192.168.5.*')
3662
fc79e6ff 3663 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
1e498853
YW
3664 print(output)
3665 self.assertRegex(output, r'192.168.5.*')
3666
3667 def test_dhcp_keep_configuration_dhcp_on_stop(self):
3668 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
2cf6fdff 3669 start_networkd()
e2aea43f 3670 self.wait_online(['veth-peer:carrier'])
1e498853 3671 start_dnsmasq(lease_time='2m')
e2aea43f 3672 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1e498853
YW
3673
3674 output = check_output('ip address show dev veth99 scope global')
3675 print(output)
3676 self.assertRegex(output, r'192.168.5.*')
3677
3678 stop_dnsmasq(dnsmasq_pid_file)
3aa645f0
MB
3679 check_output('systemctl stop systemd-networkd.socket')
3680 check_output('systemctl stop systemd-networkd.service')
1e498853
YW
3681
3682 output = check_output('ip address show dev veth99 scope global')
3683 print(output)
3684 self.assertRegex(output, r'192.168.5.*')
3685
e2aea43f
YW
3686 restart_networkd(3)
3687 self.wait_online(['veth-peer:routable'])
1e498853
YW
3688
3689 output = check_output('ip address show dev veth99 scope global')
3690 print(output)
3691 self.assertNotRegex(output, r'192.168.5.*')
1f0e3109 3692
30d3b54e 3693 def test_dhcp_client_reuse_address_as_static(self):
ec38833c 3694 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
2cf6fdff 3695 start_networkd()
e2aea43f 3696 self.wait_online(['veth-peer:carrier'])
ec38833c 3697 start_dnsmasq()
e2aea43f 3698 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2629df47
YW
3699
3700 # link become 'routable' when at least one protocol provide an valid address.
e16ffe79 3701 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4')
426654d7 3702 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
30d3b54e 3703
371810d1 3704 output = check_output('ip address show dev veth99 scope global')
30d3b54e
YW
3705 print(output)
3706 self.assertRegex(output, '192.168.5')
3707 self.assertRegex(output, '2600::')
3708
2629df47
YW
3709 ipv4_address = re.search(r'192.168.5.[0-9]*/24', output)
3710 ipv6_address = re.search(r'2600::[0-9a-f:]*/128', output)
30d3b54e
YW
3711 static_network = '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address.group(), 'Address=' + ipv6_address.group()])
3712 print(static_network)
3713
ec38833c 3714 remove_unit_from_networkd_path(['dhcp-client.network'])
30d3b54e
YW
3715
3716 with open(os.path.join(network_unit_file_path, 'static.network'), mode='w') as f:
3717 f.write(static_network)
3718
2629df47
YW
3719 # When networkd started, the links are already configured, so let's wait for 5 seconds
3720 # the links to be re-configured.
aaae5713 3721 restart_networkd(5)
e2aea43f 3722 self.wait_online(['veth99:routable', 'veth-peer:routable'])
30d3b54e 3723
371810d1 3724 output = check_output('ip -4 address show dev veth99 scope global')
30d3b54e
YW
3725 print(output)
3726 self.assertRegex(output, '192.168.5')
3727 self.assertRegex(output, 'valid_lft forever preferred_lft forever')
3728
371810d1 3729 output = check_output('ip -6 address show dev veth99 scope global')
30d3b54e
YW
3730 print(output)
3731 self.assertRegex(output, '2600::')
3732 self.assertRegex(output, 'valid_lft forever preferred_lft forever')
3733
18c613dc
YW
3734 @expectedFailureIfModuleIsNotAvailable('vrf')
3735 def test_dhcp_client_vrf(self):
ec38833c
ZJS
3736 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
3737 '25-vrf.netdev', '25-vrf.network')
2cf6fdff 3738 start_networkd()
e2aea43f 3739 self.wait_online(['veth-peer:carrier'])
ec38833c 3740 start_dnsmasq()
e2aea43f 3741 self.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
2629df47
YW
3742
3743 # link become 'routable' when at least one protocol provide an valid address.
e16ffe79 3744 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4')
426654d7 3745 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
18c613dc
YW
3746
3747 print('## ip -d link show dev vrf99')
371810d1 3748 output = check_output('ip -d link show dev vrf99')
18c613dc
YW
3749 print(output)
3750 self.assertRegex(output, 'vrf table 42')
3751
3752 print('## ip address show vrf vrf99')
371810d1 3753 output = check_output('ip address show vrf vrf99')
d90f4f7d
YW
3754 print(output)
3755 self.assertRegex(output, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3756 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
426654d7 3757 self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
d90f4f7d 3758 self.assertRegex(output, 'inet6 .* scope link')
18c613dc
YW
3759
3760 print('## ip address show dev veth99')
371810d1 3761 output = check_output('ip address show dev veth99')
18c613dc 3762 print(output)
18c613dc
YW
3763 self.assertRegex(output, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3764 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
426654d7 3765 self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
18c613dc
YW
3766 self.assertRegex(output, 'inet6 .* scope link')
3767
3768 print('## ip route show vrf vrf99')
371810d1 3769 output = check_output('ip route show vrf vrf99')
18c613dc
YW
3770 print(output)
3771 self.assertRegex(output, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
18c613dc
YW
3772 self.assertRegex(output, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
3773 self.assertRegex(output, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
3774 self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
3775 self.assertRegex(output, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
3776
3777 print('## ip route show table main dev veth99')
371810d1 3778 output = check_output('ip route show table main dev veth99')
18c613dc
YW
3779 print(output)
3780 self.assertEqual(output, '')
3781
214c5bae
YW
3782 def test_dhcp_client_gateway_ipv4(self):
3783 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3784 'dhcp-client-gateway-ipv4.network')
3785 start_networkd()
3786 self.wait_online(['veth-peer:carrier'])
3787 start_dnsmasq()
3788 self.wait_online(['veth99:routable', 'veth-peer:routable'])
3789
3790 output = check_output('ip route list dev veth99 10.0.0.0/8')
3791 print(output)
3792 self.assertRegex(output, '10.0.0.0/8 via 192.168.5.1 proto static')
3793
3794 def test_dhcp_client_gateway_ipv6(self):
3795 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3796 'dhcp-client-gateway-ipv6.network')
3797 start_networkd()
3798 self.wait_online(['veth-peer:carrier'])
3799 start_dnsmasq()
3800 self.wait_online(['veth99:routable', 'veth-peer:routable'])
3801
3802 output = check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff')
3803 print(output)
3804 self.assertRegex(output, 'via fe80::1034:56ff:fe78:9abd')
3805
af3b1498 3806 def test_dhcp_client_gateway_onlink_implicit(self):
ec38833c
ZJS
3807 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3808 'dhcp-client-gateway-onlink-implicit.network')
2cf6fdff 3809 start_networkd()
e2aea43f 3810 self.wait_online(['veth-peer:carrier'])
ec38833c 3811 start_dnsmasq()
e2aea43f 3812 self.wait_online(['veth99:routable', 'veth-peer:routable'])
af3b1498 3813
fc79e6ff 3814 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
af3b1498
YW
3815 print(output)
3816 self.assertRegex(output, '192.168.5')
3817
371810d1 3818 output = check_output('ip route list dev veth99 10.0.0.0/8')
af3b1498
YW
3819 print(output)
3820 self.assertRegex(output, 'onlink')
371810d1 3821 output = check_output('ip route list dev veth99 192.168.100.0/24')
af3b1498
YW
3822 print(output)
3823 self.assertRegex(output, 'onlink')
3824
117a55c7 3825 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self):
ec38833c
ZJS
3826 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3827 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
2cf6fdff 3828 start_networkd()
e2aea43f 3829 self.wait_online(['veth-peer:carrier'])
ec38833c 3830 start_dnsmasq(lease_time='2m')
e2aea43f 3831 self.wait_online(['veth99:routable', 'veth-peer:routable'])
63c598ed 3832
371810d1 3833 output = check_output('ip address show dev veth99')
63c598ed
YW
3834 print(output)
3835
371810d1 3836 output = check_output('ip -6 address show dev veth99 scope global dynamic')
63c598ed 3837 self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
371810d1 3838 output = check_output('ip -6 address show dev veth99 scope link')
63c598ed 3839 self.assertRegex(output, 'inet6 .* scope link')
371810d1 3840 output = check_output('ip -4 address show dev veth99 scope global dynamic')
63c598ed 3841 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
371810d1 3842 output = check_output('ip -4 address show dev veth99 scope link')
63c598ed
YW
3843 self.assertNotRegex(output, 'inet .* scope link')
3844
3845 print('Wait for the dynamic address to be expired')
3846 time.sleep(130)
3847
371810d1 3848 output = check_output('ip address show dev veth99')
63c598ed
YW
3849 print(output)
3850
371810d1 3851 output = check_output('ip -6 address show dev veth99 scope global dynamic')
63c598ed 3852 self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
371810d1 3853 output = check_output('ip -6 address show dev veth99 scope link')
63c598ed 3854 self.assertRegex(output, 'inet6 .* scope link')
371810d1 3855 output = check_output('ip -4 address show dev veth99 scope global dynamic')
63c598ed 3856 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
371810d1 3857 output = check_output('ip -4 address show dev veth99 scope link')
63c598ed
YW
3858 self.assertNotRegex(output, 'inet .* scope link')
3859
ec38833c 3860 search_words_in_dnsmasq_log('DHCPOFFER', show_all=True)
63c598ed 3861
117a55c7 3862 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self):
ec38833c
ZJS
3863 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3864 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
2cf6fdff 3865 start_networkd()
e2aea43f 3866 self.wait_online(['veth99:degraded', 'veth-peer:routable'])
117a55c7 3867
371810d1 3868 output = check_output('ip address show dev veth99')
117a55c7
YW
3869 print(output)
3870
371810d1 3871 output = check_output('ip -6 address show dev veth99 scope global dynamic')
117a55c7 3872 self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
371810d1 3873 output = check_output('ip -6 address show dev veth99 scope link')
117a55c7 3874 self.assertRegex(output, 'inet6 .* scope link')
371810d1 3875 output = check_output('ip -4 address show dev veth99 scope global dynamic')
117a55c7 3876 self.assertNotRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
371810d1 3877 output = check_output('ip -4 address show dev veth99 scope link')
117a55c7
YW
3878 self.assertRegex(output, 'inet .* scope link')
3879
b6efd661 3880 def test_dhcp_client_route_remove_on_renew(self):
ec38833c
ZJS
3881 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3882 'dhcp-client-ipv4-only-ipv6-disabled.network')
2cf6fdff 3883 start_networkd()
e2aea43f 3884 self.wait_online(['veth-peer:carrier'])
ec38833c 3885 start_dnsmasq(ipv4_range='192.168.5.100,192.168.5.199', lease_time='2m')
e2aea43f 3886 self.wait_online(['veth99:routable', 'veth-peer:routable'])
b6efd661
YW
3887
3888 # test for issue #12490
3889
371810d1 3890 output = check_output('ip -4 address show dev veth99 scope global dynamic')
b6efd661
YW
3891 print(output)
3892 self.assertRegex(output, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3893 address1=None
3894 for line in output.splitlines():
3895 if 'brd 192.168.5.255 scope global dynamic veth99' in line:
3896 address1 = line.split()[1].split('/')[0]
3897 break
3898
371810d1 3899 output = check_output('ip -4 route show dev veth99')
b6efd661
YW
3900 print(output)
3901 self.assertRegex(output, f'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3902 self.assertRegex(output, f'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3903
ec38833c
ZJS
3904 stop_dnsmasq(dnsmasq_pid_file)
3905 start_dnsmasq(ipv4_range='192.168.5.200,192.168.5.250', lease_time='2m')
b6efd661
YW
3906
3907 print('Wait for the dynamic address to be expired')
3908 time.sleep(130)
3909
371810d1 3910 output = check_output('ip -4 address show dev veth99 scope global dynamic')
b6efd661
YW
3911 print(output)
3912 self.assertRegex(output, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3913 address2=None
3914 for line in output.splitlines():
3915 if 'brd 192.168.5.255 scope global dynamic veth99' in line:
3916 address2 = line.split()[1].split('/')[0]
3917 break
3918
3919 self.assertNotEqual(address1, address2)
3920
371810d1 3921 output = check_output('ip -4 route show dev veth99')
b6efd661
YW
3922 print(output)
3923 self.assertNotRegex(output, f'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3924 self.assertNotRegex(output, f'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3925 self.assertRegex(output, f'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
3926 self.assertRegex(output, f'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
3927
e2d5aab3
YW
3928 def test_dhcp_client_use_dns_yes(self):
3929 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-yes.network')
3930
3931 start_networkd()
e2aea43f 3932 self.wait_online(['veth-peer:carrier'])
e2d5aab3 3933 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
e2aea43f 3934 self.wait_online(['veth99:routable', 'veth-peer:routable'])
e2d5aab3
YW
3935
3936 # link become 'routable' when at least one protocol provide an valid address.
3937 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4')
426654d7 3938 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
e2d5aab3 3939
693283cd 3940 time.sleep(3)
e2d5aab3
YW
3941 output = check_output(*resolvectl_cmd, 'dns', 'veth99', env=env)
3942 print(output)
3943 self.assertRegex(output, '192.168.5.1')
3944 self.assertRegex(output, '2600::1')
3945
3946 def test_dhcp_client_use_dns_no(self):
3947 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-no.network')
3948
3949 start_networkd()
e2aea43f 3950 self.wait_online(['veth-peer:carrier'])
e2d5aab3 3951 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
e2aea43f 3952 self.wait_online(['veth99:routable', 'veth-peer:routable'])
e2d5aab3
YW
3953
3954 # link become 'routable' when at least one protocol provide an valid address.
3955 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4')
426654d7 3956 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
e2d5aab3 3957
693283cd 3958 time.sleep(3)
e2d5aab3
YW
3959 output = check_output(*resolvectl_cmd, 'dns', 'veth99', env=env)
3960 print(output)
3961 self.assertNotRegex(output, '192.168.5.1')
3962 self.assertNotRegex(output, '2600::1')
3963
3964 def test_dhcp_client_use_dns_ipv4(self):
3965 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4.network')
3966
3967 start_networkd()
e2aea43f 3968 self.wait_online(['veth-peer:carrier'])
e2d5aab3 3969 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
e2aea43f 3970 self.wait_online(['veth99:routable', 'veth-peer:routable'])
e2d5aab3
YW
3971
3972 # link become 'routable' when at least one protocol provide an valid address.
3973 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4')
426654d7 3974 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
e2d5aab3 3975
693283cd 3976 time.sleep(3)
e2d5aab3
YW
3977 output = check_output(*resolvectl_cmd, 'dns', 'veth99', env=env)
3978 print(output)
3979 self.assertRegex(output, '192.168.5.1')
3980 self.assertNotRegex(output, '2600::1')
3981
3982 def test_dhcp_client_use_dns_ipv4_and_ra(self):
3983 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4-and-ra.network')
3984
3985 start_networkd()
e2aea43f 3986 self.wait_online(['veth-peer:carrier'])
e2d5aab3 3987 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
e2aea43f 3988 self.wait_online(['veth99:routable', 'veth-peer:routable'])
e2d5aab3
YW
3989
3990 # link become 'routable' when at least one protocol provide an valid address.
3991 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4')
426654d7 3992 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
e2d5aab3 3993
693283cd 3994 time.sleep(3)
e2d5aab3
YW
3995 output = check_output(*resolvectl_cmd, 'dns', 'veth99', env=env)
3996 print(output)
3997 self.assertRegex(output, '192.168.5.1')
3998 self.assertRegex(output, '2600::1')
3999
e0c1341d
YW
4000 def test_dhcp_client_use_domains(self):
4001 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-domains.network')
4002
4003 start_networkd()
e2aea43f 4004 self.wait_online(['veth-peer:carrier'])
e0c1341d 4005 start_dnsmasq('--dhcp-option=option:domain-search,example.com')
e2aea43f 4006 self.wait_online(['veth99:routable', 'veth-peer:routable'])
e0c1341d 4007
fc79e6ff 4008 output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
e0c1341d
YW
4009 print(output)
4010 self.assertRegex(output, 'Search Domains: example.com')
4011
4012 time.sleep(3)
4013 output = check_output(*resolvectl_cmd, 'domain', 'veth99', env=env)
4014 print(output)
4015 self.assertRegex(output, 'example.com')
4016
0fd8b718
YW
4017 def test_dhcp_client_decline(self):
4018 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-decline.network', 'dhcp-client-decline.network')
4019
4020 start_networkd()
4021 self.wait_online(['veth-peer:carrier'])
4022 rc = call(*wait_online_cmd, '--timeout=10s', '--interface=veth99:routable', env=env)
4023 self.assertTrue(rc == 1)
4024
9633f977
SS
4025class NetworkdIPv6PrefixTests(unittest.TestCase, Utilities):
4026 links = ['veth99']
4027
4028 units = [
4029 '25-veth.netdev',
4030 'ipv6ra-prefix-client.network',
4031 'ipv6ra-prefix.network'
4032 ]
4033
4034 def setUp(self):
4035 remove_links(self.links)
4036 stop_networkd(show_logs=False)
4037
4038 def tearDown(self):
4039 remove_log_file()
4040 remove_links(self.links)
4041 remove_unit_from_networkd_path(self.units)
4042 stop_networkd(show_logs=True)
4043
4044 def test_ipv6_route_prefix(self):
4045 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client.network', 'ipv6ra-prefix.network')
4046
4047 start_networkd()
9633f977
SS
4048 self.wait_online(['veth99:routable', 'veth-peer:routable'])
4049
3c874fd7 4050 output = check_output('ip -6 route show dev veth-peer')
9633f977
SS
4051 print(output)
4052 self.assertRegex(output, '2001:db8:0:1::/64 proto ra')
4053
3c874fd7
YW
4054 output = check_output('ip addr show dev veth99')
4055 print(output)
4056 self.assertNotRegex(output, '2001:db8:0:1')
4057 self.assertRegex(output, '2001:db8:0:2')
4058
7db05447
DS
4059class NetworkdMTUTests(unittest.TestCase, Utilities):
4060 links = ['dummy98']
4061
4062 units = [
4063 '12-dummy.netdev',
4064 '12-dummy-mtu.netdev',
4065 '12-dummy-mtu.link',
4066 '12-dummy.network',
4067 ]
4068
4069 def setUp(self):
4070 remove_links(self.links)
4071 stop_networkd(show_logs=False)
4072
4073 def tearDown(self):
4074 remove_log_file()
4075 remove_links(self.links)
4076 remove_unit_from_networkd_path(self.units)
4077 stop_networkd(show_logs=True)
4078
4079 def check_mtu(self, mtu, ipv6_mtu=None, reset=True):
4080 if not ipv6_mtu:
4081 ipv6_mtu = mtu
4082
4083 # test normal start
4084 start_networkd()
4085 self.wait_online(['dummy98:routable'])
4086 self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu)
4087 self.assertEqual(read_link_attr('dummy98', 'mtu'), mtu)
4088
4089 # test normal restart
4090 restart_networkd()
4091 self.wait_online(['dummy98:routable'])
4092 self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu)
4093 self.assertEqual(read_link_attr('dummy98', 'mtu'), mtu)
4094
4095 if reset:
4096 self.reset_check_mtu(mtu, ipv6_mtu)
4097
4098 def reset_check_mtu(self, mtu, ipv6_mtu=None):
4099 ''' test setting mtu/ipv6_mtu with interface already up '''
4100 stop_networkd()
4101
4102 # note - changing the device mtu resets the ipv6 mtu
4103 run('ip link set up mtu 1501 dev dummy98')
4104 run('ip link set up mtu 1500 dev dummy98')
4105 self.assertEqual(read_link_attr('dummy98', 'mtu'), '1500')
4106 self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), '1500')
4107
4108 self.check_mtu(mtu, ipv6_mtu, reset=False)
4109
4110 def test_mtu_network(self):
4111 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
4112 self.check_mtu('1600')
4113
4114 def test_mtu_netdev(self):
4115 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network', dropins=False)
4116 # note - MTU set by .netdev happens ONLY at device creation!
4117 self.check_mtu('1600', reset=False)
4118
4119 def test_mtu_link(self):
4120 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', dropins=False)
4121 # must reload udev because it only picks up new files after 3 second delay
4122 call('udevadm control --reload')
4123 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
4124 self.check_mtu('1600', reset=False)
4125
4126 def test_ipv6_mtu(self):
4127 ''' set ipv6 mtu without setting device mtu '''
4128 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
4129 self.check_mtu('1500', '1400')
4130
4131 def test_ipv6_mtu_toolarge(self):
4132 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
4133 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
4134 self.check_mtu('1500', '1500')
4135
4136 def test_mtu_network_ipv6_mtu(self):
4137 ''' set ipv6 mtu and set device mtu via network file '''
4138 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
4139 self.check_mtu('1600', '1550')
4140
4141 def test_mtu_netdev_ipv6_mtu(self):
4142 ''' set ipv6 mtu and set device mtu via netdev file '''
4143 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
4144 self.check_mtu('1600', '1550', reset=False)
4145
4146 def test_mtu_link_ipv6_mtu(self):
4147 ''' set ipv6 mtu and set device mtu via link file '''
4148 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
4149 # must reload udev because it only picks up new files after 3 second delay
4150 call('udevadm control --reload')
4151 self.check_mtu('1600', '1550', reset=False)
4152
4153
1f0e3109 4154if __name__ == '__main__':
9c1ae484
YW
4155 parser = argparse.ArgumentParser()
4156 parser.add_argument('--build-dir', help='Path to build dir', dest='build_dir')
4157 parser.add_argument('--networkd', help='Path to systemd-networkd', dest='networkd_bin')
b6d587d1 4158 parser.add_argument('--resolved', help='Path to systemd-resolved', dest='resolved_bin')
641aa412 4159 parser.add_argument('--udevd', help='Path to systemd-udevd', dest='udevd_bin')
9c1ae484
YW
4160 parser.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest='wait_online_bin')
4161 parser.add_argument('--networkctl', help='Path to networkctl', dest='networkctl_bin')
b6d587d1
YW
4162 parser.add_argument('--resolvectl', help='Path to resolvectl', dest='resolvectl_bin')
4163 parser.add_argument('--timedatectl', help='Path to timedatectl', dest='timedatectl_bin')
9c1ae484
YW
4164 parser.add_argument('--valgrind', help='Enable valgrind', dest='use_valgrind', type=bool, nargs='?', const=True, default=use_valgrind)
4165 parser.add_argument('--debug', help='Generate debugging logs', dest='enable_debug', type=bool, nargs='?', const=True, default=enable_debug)
94c03122 4166 parser.add_argument('--asan-options', help='ASAN options', dest='asan_options')
fa4c6095 4167 parser.add_argument('--lsan-options', help='LSAN options', dest='lsan_options')
94c03122 4168 parser.add_argument('--ubsan-options', help='UBSAN options', dest='ubsan_options')
9c1ae484
YW
4169 ns, args = parser.parse_known_args(namespace=unittest)
4170
4171 if ns.build_dir:
641aa412 4172 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:
b6d587d1 4173 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
9c1ae484 4174 networkd_bin = os.path.join(ns.build_dir, 'systemd-networkd')
b6d587d1 4175 resolved_bin = os.path.join(ns.build_dir, 'systemd-resolved')
641aa412 4176 udevd_bin = os.path.join(ns.build_dir, 'systemd-udevd')
9c1ae484
YW
4177 wait_online_bin = os.path.join(ns.build_dir, 'systemd-networkd-wait-online')
4178 networkctl_bin = os.path.join(ns.build_dir, 'networkctl')
b6d587d1
YW
4179 resolvectl_bin = os.path.join(ns.build_dir, 'resolvectl')
4180 timedatectl_bin = os.path.join(ns.build_dir, 'timedatectl')
9c1ae484
YW
4181 else:
4182 if ns.networkd_bin:
4183 networkd_bin = ns.networkd_bin
b6d587d1
YW
4184 if ns.resolved_bin:
4185 resolved_bin = ns.resolved_bin
641aa412
YW
4186 if ns.udevd_bin:
4187 udevd_bin = ns.udevd_bin
9c1ae484
YW
4188 if ns.wait_online_bin:
4189 wait_online_bin = ns.wait_online_bin
4190 if ns.networkctl_bin:
4191 networkctl_bin = ns.networkctl_bin
b6d587d1
YW
4192 if ns.resolvectl_bin:
4193 resolvectl_bin = ns.resolvectl_bin
4194 if ns.timedatectl_bin:
4195 timedatectl_bin = ns.timedatectl_bin
9c1ae484
YW
4196
4197 use_valgrind = ns.use_valgrind
4198 enable_debug = ns.enable_debug
94c03122 4199 asan_options = ns.asan_options
fa4c6095 4200 lsan_options = ns.lsan_options
94c03122 4201 ubsan_options = ns.ubsan_options
9c1ae484
YW
4202
4203 if use_valgrind:
4204 networkctl_cmd = ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin]
b6d587d1
YW
4205 resolvectl_cmd = ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin]
4206 timedatectl_cmd = ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin]
9c1ae484
YW
4207 wait_online_cmd = ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin]
4208 else:
4209 networkctl_cmd = [networkctl_bin]
b6d587d1
YW
4210 resolvectl_cmd = [resolvectl_bin]
4211 timedatectl_cmd = [timedatectl_bin]
9c1ae484
YW
4212 wait_online_cmd = [wait_online_bin]
4213
4214 if enable_debug:
4215 env.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
94c03122
YW
4216 if asan_options:
4217 env.update({ 'ASAN_OPTIONS' : asan_options })
fa4c6095
YW
4218 if lsan_options:
4219 env.update({ 'LSAN_OPTIONS' : lsan_options })
94c03122
YW
4220 if ubsan_options:
4221 env.update({ 'UBSAN_OPTIONS' : ubsan_options })
9c1ae484
YW
4222
4223 sys.argv[1:] = args
1f0e3109
SS
4224 unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout,
4225 verbosity=3))