]> git.ipfire.org Git - thirdparty/systemd.git/blame - test/test-network/systemd-networkd-tests.py
man: mention quoting in description of Parameters=
[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
1f0e3109 6import os
201bf07f 7import re
1f0e3109
SS
8import shutil
9import signal
10import socket
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
9c1ae484 26networkd_bin='/usr/lib/systemd/systemd-networkd'
5aa58329 27wait_online_bin='/usr/lib/systemd/systemd-networkd-wait-online'
9c1ae484
YW
28networkctl_bin='/usr/bin/networkctl'
29use_valgrind=False
30enable_debug=False
31env = {}
94c03122 32asan_options=None
fa4c6095 33lsan_options=None
94c03122 34ubsan_options=None
5aa58329 35
7a0a37b2 36def is_module_available(module_name):
201bf07f
EV
37 lsmod_output = subprocess.check_output('lsmod', universal_newlines=True)
38 module_re = re.compile(r'^{0}\b'.format(re.escape(module_name)), re.MULTILINE)
39 return module_re.search(lsmod_output) or not subprocess.call(["modprobe", module_name])
7a0a37b2
EV
40
41def expectedFailureIfModuleIsNotAvailable(module_name):
42 def f(func):
43 if not is_module_available(module_name):
44 return unittest.expectedFailure(func)
45 return func
46
47 return f
48
7bea7f9b
SS
49def expectedFailureIfERSPANModuleIsNotAvailable():
50 def f(func):
51 rc = subprocess.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'])
52 if rc == 0:
53 subprocess.call(['ip', 'link', 'del', 'erspan99'])
54 return func
55 else:
56 return unittest.expectedFailure(func)
57
58 return f
59
d586a2c3
YW
60def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable():
61 def f(func):
62 rc = subprocess.call(['ip', 'rule', 'add', 'from', '192.168.100.19', 'sport', '1123-1150', 'dport', '3224-3290', 'table', '7'])
63 if rc == 0:
64 subprocess.call(['ip', 'rule', 'del', 'from', '192.168.100.19', 'sport', '1123-1150', 'dport', '3224-3290', 'table', '7'])
65 return func
66 else:
67 return unittest.expectedFailure(func)
68
69 return f
70
71def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
72 def f(func):
73 rc = subprocess.call(['ip', 'rule', 'add', 'not', 'from', '192.168.100.19', 'ipproto', 'tcp', 'table', '7'])
74 if rc == 0:
75 subprocess.call(['ip', 'rule', 'del', 'not', 'from', '192.168.100.19', 'ipproto', 'tcp', 'table', '7'])
76 return func
77 else:
78 return unittest.expectedFailure(func)
79
80 return f
81
1ca44d7d
YW
82def expectedFailureIfEthtoolDoesNotSupportDriver():
83 def f(func):
84 support = False
85 rc = subprocess.call(['ip', 'link', 'add', 'name', 'dummy99', 'type', 'dummy'])
86 if rc == 0:
87 ret = subprocess.run(['udevadm', 'info', '-w10s', '/sys/class/net/dummy99'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)
88 if ret.returncode == 0 and 'E: ID_NET_DRIVER=dummy' in ret.stdout.rstrip():
89 support = True
90 subprocess.call(['ip', 'link', 'del', 'dummy99'])
91
92 if support:
93 return func
94 else:
95 return unittest.expectedFailure(func)
96
97 return f
98
1f0e3109 99def setUpModule():
1f0e3109
SS
100 os.makedirs(network_unit_file_path, exist_ok=True)
101 os.makedirs(networkd_ci_path, exist_ok=True)
102
103 shutil.rmtree(networkd_ci_path)
6aea9276 104 copytree(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'conf'), networkd_ci_path)
1f0e3109 105
c0bf6733 106 subprocess.check_call('systemctl stop systemd-networkd.socket', shell=True)
d4fda2a5 107 subprocess.check_call('systemctl stop systemd-networkd.service', shell=True)
c0bf6733 108
9c1ae484
YW
109 drop_in = [
110 '[Service]',
111 'Restart=no',
112 'ExecStart=',
113 ]
114 if use_valgrind:
115 drop_in += [
116 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin,
94c03122 117 'PrivateTmp=yes'
9c1ae484
YW
118 ]
119 else:
120 drop_in += ['ExecStart=!!' + networkd_bin]
121 if enable_debug:
122 drop_in += ['Environment=SYSTEMD_LOG_LEVEL=debug']
94c03122
YW
123 if asan_options:
124 drop_in += ['Environment=ASAN_OPTIONS="' + asan_options + '"']
fa4c6095
YW
125 if lsan_options:
126 drop_in += ['Environment=LSAN_OPTIONS="' + lsan_options + '"']
94c03122
YW
127 if ubsan_options:
128 drop_in += ['Environment=UBSAN_OPTIONS="' + ubsan_options + '"']
78690bb5
YW
129 if asan_options or lsan_options or ubsan_options:
130 drop_in += ['SystemCallFilter=']
fa4c6095 131 if use_valgrind or asan_options or lsan_options or ubsan_options:
94c03122 132 drop_in += ['MemoryDenyWriteExecute=no']
9c1ae484 133
9c1ae484
YW
134 os.makedirs('/run/systemd/system/systemd-networkd.service.d', exist_ok=True)
135 with open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode='w') as f:
72917fcc 136 f.write('\n'.join(drop_in))
9c1ae484
YW
137
138 subprocess.check_call('systemctl daemon-reload', shell=True)
72917fcc
YW
139 output = subprocess.check_output(['systemctl', 'cat', 'systemd-networkd.service'], universal_newlines=True).rstrip()
140 print(output)
9c1ae484 141
1f0e3109
SS
142def tearDownModule():
143 shutil.rmtree(networkd_ci_path)
d4fda2a5
YW
144
145 subprocess.check_call('systemctl stop systemd-networkd.service', shell=True)
146
9c1ae484
YW
147 shutil.rmtree('/run/systemd/system/systemd-networkd.service.d')
148 subprocess.check_call('systemctl daemon-reload', shell=True)
1f0e3109 149
c0bf6733
YW
150 subprocess.check_call('systemctl start systemd-networkd.socket', shell=True)
151 subprocess.check_call('systemctl start systemd-networkd.service', shell=True)
152
1f0e3109 153class Utilities():
1f0e3109
SS
154 def read_link_attr(self, link, dev, attribute):
155 with open(os.path.join(os.path.join(os.path.join('/sys/class/net/', link), dev), attribute)) as f:
156 return f.readline().strip()
157
4d7ed14f
SS
158 def read_bridge_port_attr(self, bridge, link, attribute):
159
160 path_bridge = os.path.join('/sys/devices/virtual/net', bridge)
161 path_port = 'lower_' + link + '/brport'
162 path = os.path.join(path_bridge, path_port)
163
164 with open(os.path.join(path, attribute)) as f:
165 return f.readline().strip()
166
e39cc445 167 def link_exists(self, link):
1f0e3109
SS
168 return os.path.exists(os.path.join('/sys/class/net', link))
169
e39cc445
YW
170 def check_link_exists(self, link):
171 self.assertTrue(self.link_exists(link))
172
350e05d2 173 def remove_links(self, links):
1f0e3109 174 for link in links:
e39cc445 175 if self.link_exists(link):
1f0e3109 176 subprocess.call(['ip', 'link', 'del', 'dev', link])
9a4720a9 177 time.sleep(1)
1f0e3109 178
def9fc0d
YW
179 def remove_fou_ports(self, ports):
180 for port in ports:
181 subprocess.call(['ip', 'fou', 'del', 'port', port])
182
95c74b0a
YW
183 def remove_routing_policy_rule_tables(self, tables):
184 for table in tables:
185 subprocess.call(['ip', 'rule', 'del', 'table', table])
186
5f68a6a4
YW
187 def remove_routes(self, routes):
188 for route_type, addr in routes:
189 subprocess.call(['ip', 'route', 'del', route_type, addr])
190
cff83db9 191 def l2tp_tunnel_remove(self, tunnel_ids):
ce87a190 192 output = subprocess.check_output(['ip', 'l2tp', 'show', 'tunnel'], universal_newlines=True).rstrip()
cff83db9
YW
193 for tid in tunnel_ids:
194 words='Tunnel ' + tid + ', encap'
195 if words in output:
196 subprocess.call(['ip', 'l2tp', 'del', 'tunnel', 'tid', tid])
197 time.sleep(1)
198
1f0e3109
SS
199 def read_ipv6_sysctl_attr(self, link, attribute):
200 with open(os.path.join(os.path.join(network_sysctl_ipv6_path, link), attribute)) as f:
201 return f.readline().strip()
202
203 def read_ipv4_sysctl_attr(self, link, attribute):
204 with open(os.path.join(os.path.join(network_sysctl_ipv4_path, link), attribute)) as f:
205 return f.readline().strip()
206
207 def copy_unit_to_networkd_unit_path(self, *units):
ecdd0392 208 print()
1f0e3109
SS
209 for unit in units:
210 shutil.copy(os.path.join(networkd_ci_path, unit), network_unit_file_path)
013c8dc9
YW
211 if (os.path.exists(os.path.join(networkd_ci_path, unit + '.d'))):
212 copytree(os.path.join(networkd_ci_path, unit + '.d'), os.path.join(network_unit_file_path, unit + '.d'))
1f0e3109
SS
213
214 def remove_unit_from_networkd_path(self, units):
215 for unit in units:
216 if (os.path.exists(os.path.join(network_unit_file_path, unit))):
217 os.remove(os.path.join(network_unit_file_path, unit))
013c8dc9
YW
218 if (os.path.exists(os.path.join(network_unit_file_path, unit + '.d'))):
219 shutil.rmtree(os.path.join(network_unit_file_path, unit + '.d'))
1f0e3109 220
1836bedf
YW
221 def warn_about_firewalld(self):
222 rc = subprocess.call(['systemctl', '-q', 'is-active', 'firewalld.service'])
223 if rc == 0:
224 print('\nWARNING: firewalld.service is active. The test may fail.')
225
b6efd661 226 def start_dnsmasq(self, additional_options='', ipv4_range='192.168.5.10,192.168.5.200', ipv6_range='2600::10,2600::20', lease_time='1h'):
1836bedf 227 self.warn_about_firewalld()
b6efd661 228 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
b412fce8 229 subprocess.check_call(dnsmasq_command, shell=True)
1f0e3109 230
1f0e3109
SS
231 def stop_dnsmasq(self, pid_file):
232 if os.path.exists(pid_file):
233 with open(pid_file, 'r') as f:
234 pid = f.read().rstrip(' \t\r\n\0')
235 os.kill(int(pid), signal.SIGTERM)
236
237 os.remove(pid_file)
238
131717cb 239 def search_words_in_dnsmasq_log(self, words, show_all=False):
1f0e3109
SS
240 if os.path.exists(dnsmasq_log_file):
241 with open (dnsmasq_log_file) as in_file:
242 contents = in_file.read()
131717cb
YW
243 if show_all:
244 print(contents)
881b1f35 245 for line in contents.splitlines():
131717cb 246 if words in line:
1f0e3109 247 in_file.close()
131717cb 248 print("%s, %s" % (words, line))
1f0e3109
SS
249 return True
250 return False
251
252 def remove_lease_file(self):
253 if os.path.exists(os.path.join(networkd_ci_path, 'lease')):
254 os.remove(os.path.join(networkd_ci_path, 'lease'))
255
256 def remove_log_file(self):
257 if os.path.exists(dnsmasq_log_file):
258 os.remove(dnsmasq_log_file)
259
5aa58329 260 def start_networkd(self, sleep_sec=5, remove_state_files=True):
b677774d
YW
261 if (remove_state_files and
262 os.path.exists(os.path.join(networkd_runtime_directory, 'state'))):
bad4969b
YW
263 subprocess.check_call('systemctl stop systemd-networkd', shell=True)
264 os.remove(os.path.join(networkd_runtime_directory, 'state'))
265 subprocess.check_call('systemctl start systemd-networkd', shell=True)
266 else:
267 subprocess.check_call('systemctl restart systemd-networkd', shell=True)
5aa58329
YW
268 if sleep_sec > 0:
269 time.sleep(sleep_sec)
270
03db80b2 271 def wait_online(self, links_with_operstate, timeout='20s', bool_any=False):
9c1ae484 272 args = wait_online_cmd + [f'--timeout={timeout}'] + [f'--interface={link}' for link in links_with_operstate]
03db80b2
YW
273 if bool_any:
274 args += ['--any']
8d7f0987 275 try:
9c1ae484 276 subprocess.check_call(args, env=env)
8d7f0987
YW
277 except subprocess.CalledProcessError:
278 for link in links_with_operstate:
9c1ae484 279 output = subprocess.check_output(networkctl_cmd + ['status', link.split(':')[0]], universal_newlines=True, env=env).rstrip()
8d7f0987
YW
280 print(output)
281 raise
1f0e3109 282
2be0b6fc 283 def get_operstate(self, link, show_status=True, setup_state='configured'):
9c1ae484 284 output = subprocess.check_output(networkctl_cmd + ['status', link], universal_newlines=True, env=env).rstrip()
2be0b6fc
YW
285 if show_status:
286 print(output)
287 for line in output.splitlines():
288 if 'State:' in line and (not setup_state or setup_state in line):
289 return line.split()[1]
290 return None
291
292 def check_operstate(self, link, expected, show_status=True, setup_state='configured'):
293 self.assertRegex(self.get_operstate(link, show_status, setup_state), expected)
294
53c32c2b 295 def wait_address(self, link, address_regex, scope='global', ipv='', timeout_sec=100):
2629df47
YW
296 for i in range(timeout_sec):
297 if i > 0:
298 time.sleep(1)
299 output = subprocess.check_output(['ip', ipv, 'address', 'show', 'dev', link, 'scope', scope], universal_newlines=True).rstrip()
300 if re.search(address_regex, output):
301 break
302 else:
303 self.assertRegex(output, address_regex)
304
1ca44d7d
YW
305class NetworkctlTests(unittest.TestCase, Utilities):
306
307 links = [
308 'test1',
309 'veth99',
310 ]
311
312 units = [
313 '11-dummy.netdev',
6d5b4efe 314 '11-dummy-mtu.netdev',
1ca44d7d
YW
315 '11-dummy.network',
316 '25-veth.netdev',
317 'netdev-link-local-addressing-yes.network',
318 ]
319
320 def setUp(self):
321 self.remove_links(self.links)
322
323 def tearDown(self):
324 self.remove_links(self.links)
325 self.remove_unit_from_networkd_path(self.units)
326
327 def test_glob(self):
328 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
329 self.start_networkd(0)
330
331 self.wait_online(['test1:degraded'])
332
333 output = subprocess.check_output(networkctl_cmd + ['list'], universal_newlines=True, env=env).rstrip()
334 self.assertRegex(output, '1 lo ')
335 self.assertRegex(output, 'test1')
336
337 output = subprocess.check_output(networkctl_cmd + ['list', 'test1'], universal_newlines=True, env=env).rstrip()
338 self.assertNotRegex(output, '1 lo ')
339 self.assertRegex(output, 'test1')
340
341 output = subprocess.check_output(networkctl_cmd + ['list', 'te*'], universal_newlines=True, env=env).rstrip()
342 self.assertNotRegex(output, '1 lo ')
343 self.assertRegex(output, 'test1')
344
345 output = subprocess.check_output(networkctl_cmd + ['status', 'te*'], universal_newlines=True, env=env).rstrip()
346 self.assertNotRegex(output, '1: lo ')
347 self.assertRegex(output, 'test1')
348
349 output = subprocess.check_output(networkctl_cmd + ['status', 'tes[a-z][0-9]'], universal_newlines=True, env=env).rstrip()
350 self.assertNotRegex(output, '1: lo ')
351 self.assertRegex(output, 'test1')
352
6d5b4efe
YW
353 def test_mtu(self):
354 self.copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
355 self.start_networkd(0)
356
357 self.wait_online(['test1:degraded'])
358
359 output = subprocess.check_output(networkctl_cmd + ['status', 'test1'], universal_newlines=True, env=env).rstrip()
360 self.assertRegex(output, 'MTU: 1600')
361
1ca44d7d
YW
362 @expectedFailureIfEthtoolDoesNotSupportDriver()
363 def test_udev_driver(self):
364 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
365 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
366 self.start_networkd(0)
367
368 self.wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
369
370 output = subprocess.check_output(networkctl_cmd + ['status', 'test1'], universal_newlines=True, env=env).rstrip()
371 self.assertRegex(output, 'Driver: dummy')
372
373 output = subprocess.check_output(networkctl_cmd + ['status', 'veth99'], universal_newlines=True, env=env).rstrip()
374 self.assertRegex(output, 'Driver: veth')
375
376 output = subprocess.check_output(networkctl_cmd + ['status', 'veth-peer'], universal_newlines=True, env=env).rstrip()
377 self.assertRegex(output, 'Driver: veth')
2be0b6fc 378
bee692fd
YW
379 def test_delete_links(self):
380 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
381 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
382 self.start_networkd(0)
383
384 self.wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
385
386 subprocess.check_call(networkctl_cmd + ['delete', 'test1', 'veth99'])
387 self.assertFalse(self.link_exists('test1'))
388 self.assertFalse(self.link_exists('veth99'))
389 self.assertFalse(self.link_exists('veth-peer'))
390
1f0e3109
SS
391class NetworkdNetDevTests(unittest.TestCase, Utilities):
392
09ea6724
YW
393 links =[
394 '6rdtun99',
395 'bond99',
396 'bridge99',
397 'dropin-test',
398 'dummy98',
6a97a864
YW
399 'erspan98',
400 'erspan99',
09ea6724 401 'geneve99',
4b6a6d1e 402 'gretap96',
6a97a864 403 'gretap98',
09ea6724 404 'gretap99',
4b6a6d1e 405 'gretun96',
6a97a864
YW
406 'gretun97',
407 'gretun98',
09ea6724 408 'gretun99',
6a97a864 409 'ip6gretap98',
09ea6724 410 'ip6gretap99',
6a97a864
YW
411 'ip6gretun97',
412 'ip6gretun98',
413 'ip6gretun99',
414 'ip6tnl97',
415 'ip6tnl98',
09ea6724 416 'ip6tnl99',
4b6a6d1e 417 'ipiptun96',
6a97a864
YW
418 'ipiptun97',
419 'ipiptun98',
09ea6724
YW
420 'ipiptun99',
421 'ipvlan99',
956c8fec 422 'ipvtap99',
09ea6724
YW
423 'isataptun99',
424 'macvlan99',
425 'macvtap99',
811f33d0 426 'nlmon99',
4b6a6d1e 427 'sittun96',
6a97a864
YW
428 'sittun97',
429 'sittun98',
09ea6724
YW
430 'sittun99',
431 'tap99',
432 'test1',
433 'tun99',
434 'vcan99',
435 'veth99',
436 'vlan99',
437 'vrf99',
6a97a864
YW
438 'vti6tun97',
439 'vti6tun98',
09ea6724 440 'vti6tun99',
6a97a864
YW
441 'vtitun97',
442 'vtitun98',
09ea6724 443 'vtitun99',
f63b14d3 444 'vxcan99',
09ea6724 445 'vxlan99',
da44fb8a 446 'wg98',
09ea6724
YW
447 'wg99']
448
449 units = [
450 '10-dropin-test.netdev',
451 '11-dummy.netdev',
03db80b2 452 '11-dummy.network',
09ea6724 453 '12-dummy.netdev',
753e0a24 454 '15-name-conflict-test.netdev',
09ea6724
YW
455 '21-macvlan.netdev',
456 '21-macvtap.netdev',
7f45d738 457 '21-vlan-test1.network',
09ea6724
YW
458 '21-vlan.netdev',
459 '21-vlan.network',
460 '25-6rd-tunnel.netdev',
461 '25-bond.netdev',
fde60a42 462 '25-bond-balanced-tlb.netdev',
09ea6724 463 '25-bridge.netdev',
03db80b2 464 '25-bridge.network',
6a97a864 465 '25-erspan-tunnel-local-any.netdev',
09ea6724 466 '25-erspan-tunnel.netdev',
4b6a6d1e
YW
467 '25-fou-gretap.netdev',
468 '25-fou-gre.netdev',
469 '25-fou-ipip.netdev',
470 '25-fou-ipproto-gre.netdev',
471 '25-fou-ipproto-ipip.netdev',
472 '25-fou-sit.netdev',
09ea6724 473 '25-geneve.netdev',
6a97a864 474 '25-gretap-tunnel-local-any.netdev',
09ea6724 475 '25-gretap-tunnel.netdev',
6a97a864
YW
476 '25-gre-tunnel-local-any.netdev',
477 '25-gre-tunnel-remote-any.netdev',
09ea6724 478 '25-gre-tunnel.netdev',
6a97a864
YW
479 '25-ip6gretap-tunnel-local-any.netdev',
480 '25-ip6gretap-tunnel.netdev',
481 '25-ip6gre-tunnel-local-any.netdev',
482 '25-ip6gre-tunnel-remote-any.netdev',
09ea6724 483 '25-ip6gre-tunnel.netdev',
6a97a864
YW
484 '25-ip6tnl-tunnel-remote-any.netdev',
485 '25-ip6tnl-tunnel-local-any.netdev',
09ea6724
YW
486 '25-ip6tnl-tunnel.netdev',
487 '25-ipip-tunnel-independent.netdev',
6a97a864
YW
488 '25-ipip-tunnel-local-any.netdev',
489 '25-ipip-tunnel-remote-any.netdev',
09ea6724
YW
490 '25-ipip-tunnel.netdev',
491 '25-ipvlan.netdev',
956c8fec 492 '25-ipvtap.netdev',
09ea6724 493 '25-isatap-tunnel.netdev',
02849d8b
YW
494 '25-macsec.key',
495 '25-macsec.netdev',
496 '25-macsec.network',
811f33d0 497 '25-nlmon.netdev',
6a97a864
YW
498 '25-sit-tunnel-local-any.netdev',
499 '25-sit-tunnel-remote-any.netdev',
09ea6724
YW
500 '25-sit-tunnel.netdev',
501 '25-tap.netdev',
502 '25-tun.netdev',
11309591
YW
503 '25-tunnel-local-any.network',
504 '25-tunnel-remote-any.network',
505 '25-tunnel.network',
09ea6724
YW
506 '25-vcan.netdev',
507 '25-veth.netdev',
508 '25-vrf.netdev',
6a97a864
YW
509 '25-vti6-tunnel-local-any.netdev',
510 '25-vti6-tunnel-remote-any.netdev',
09ea6724 511 '25-vti6-tunnel.netdev',
6a97a864
YW
512 '25-vti-tunnel-local-any.netdev',
513 '25-vti-tunnel-remote-any.netdev',
09ea6724 514 '25-vti-tunnel.netdev',
f63b14d3 515 '25-vxcan.netdev',
09ea6724 516 '25-vxlan.netdev',
da44fb8a
YW
517 '25-wireguard-23-peers.netdev',
518 '25-wireguard-23-peers.network',
9e5d79e7 519 '25-wireguard-preshared-key.txt',
39bcff3b 520 '25-wireguard-private-key.txt',
09ea6724 521 '25-wireguard.netdev',
5a0bd90b 522 '25-wireguard.network',
09ea6724 523 '6rd.network',
6730a1f3 524 'erspan.network',
09ea6724
YW
525 'gre.network',
526 'gretap.network',
527 'gretun.network',
528 'ip6gretap.network',
6a97a864 529 'ip6gretun.network',
09ea6724
YW
530 'ip6tnl.network',
531 'ipip.network',
532 'ipvlan.network',
956c8fec 533 'ipvtap.network',
09ea6724 534 'isatap.network',
02849d8b 535 'macsec.network',
09ea6724
YW
536 'macvlan.network',
537 'macvtap.network',
077f9abc 538 'netdev-link-local-addressing-yes.network',
09ea6724
YW
539 'sit.network',
540 'vti6.network',
541 'vti.network',
1c862fe0 542 'vxlan-test1.network',
09ea6724 543 'vxlan.network']
1f0e3109 544
def9fc0d
YW
545 fou_ports = [
546 '55555',
547 '55556']
548
1f0e3109 549 def setUp(self):
def9fc0d 550 self.remove_fou_ports(self.fou_ports)
350e05d2 551 self.remove_links(self.links)
1f0e3109
SS
552
553 def tearDown(self):
def9fc0d 554 self.remove_fou_ports(self.fou_ports)
350e05d2 555 self.remove_links(self.links)
1f0e3109
SS
556 self.remove_unit_from_networkd_path(self.units)
557
1ca44d7d 558 def test_dropin_and_name_conflict(self):
753e0a24 559 self.copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
c815f33e 560 self.start_networkd(0)
d80734f7 561
c815f33e 562 self.wait_online(['dropin-test:off'])
d80734f7 563
ce87a190 564 output = subprocess.check_output(['ip', 'link', 'show', 'dropin-test'], universal_newlines=True).rstrip()
d80734f7
YW
565 print(output)
566 self.assertRegex(output, '00:50:56:c0:00:28')
567
03db80b2
YW
568 def test_wait_online_any(self):
569 self.copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
570 self.start_networkd(0)
571
572 self.wait_online(['bridge99', 'test1:degraded'], bool_any=True)
03db80b2 573
791c1140
YW
574 self.check_operstate('bridge99', '(?:off|no-carrier)', setup_state='configuring')
575 self.check_operstate('test1', 'degraded')
03db80b2 576
1f0e3109
SS
577 def test_bridge(self):
578 self.copy_unit_to_networkd_unit_path('25-bridge.netdev')
c815f33e 579 self.start_networkd(0)
1f0e3109 580
c815f33e 581 self.wait_online(['bridge99:off'])
1f0e3109 582
3d165124
YW
583 tick = os.sysconf('SC_CLK_TCK')
584 self.assertEqual(9, round(float(self.read_link_attr('bridge99', 'bridge', 'hello_time')) / tick))
585 self.assertEqual(9, round(float(self.read_link_attr('bridge99', 'bridge', 'max_age')) / tick))
586 self.assertEqual(9, round(float(self.read_link_attr('bridge99', 'bridge','forward_delay')) / tick))
587 self.assertEqual(9, round(float(self.read_link_attr('bridge99', 'bridge','ageing_time')) / tick))
588 self.assertEqual(9, int(self.read_link_attr('bridge99', 'bridge','priority')))
589 self.assertEqual(1, int(self.read_link_attr('bridge99', 'bridge','multicast_querier')))
590 self.assertEqual(1, int(self.read_link_attr('bridge99', 'bridge','multicast_snooping')))
591 self.assertEqual(1, int(self.read_link_attr('bridge99', 'bridge','stp_state')))
1f0e3109
SS
592
593 def test_bond(self):
c815f33e
YW
594 self.copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
595 self.start_networkd(0)
1f0e3109 596
c815f33e 597 self.wait_online(['bond99:off', 'bond98:off'])
1f0e3109 598
99f68ef0
TJ
599 self.assertEqual('802.3ad 4', self.read_link_attr('bond99', 'bonding', 'mode'))
600 self.assertEqual('layer3+4 1', self.read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
601 self.assertEqual('1000', self.read_link_attr('bond99', 'bonding', 'miimon'))
602 self.assertEqual('fast 1', self.read_link_attr('bond99', 'bonding', 'lacp_rate'))
603 self.assertEqual('2000', self.read_link_attr('bond99', 'bonding', 'updelay'))
604 self.assertEqual('2000', self.read_link_attr('bond99', 'bonding', 'downdelay'))
605 self.assertEqual('4', self.read_link_attr('bond99', 'bonding', 'resend_igmp'))
606 self.assertEqual('1', self.read_link_attr('bond99', 'bonding', 'min_links'))
607 self.assertEqual('1218', self.read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
608 self.assertEqual('811', self.read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
609 self.assertEqual('00:11:22:33:44:55', self.read_link_attr('bond99', 'bonding', 'ad_actor_system'))
1f0e3109 610
c815f33e
YW
611 self.assertEqual('balance-tlb 5', self.read_link_attr('bond98', 'bonding', 'mode'))
612 self.assertEqual('1', self.read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
fde60a42 613
1f0e3109 614 def test_vlan(self):
7f45d738
YW
615 self.copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
616 '21-vlan.network', '21-vlan-test1.network')
c815f33e 617 self.start_networkd(0)
1f0e3109 618
0aefa227 619 self.wait_online(['test1:degraded', 'vlan99:routable'])
1f0e3109 620
ce87a190 621 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1'], universal_newlines=True).rstrip()
72b7f1b9 622 print(output)
7d7be1b9 623 self.assertRegex(output, ' mtu 2000 ')
72b7f1b9 624
ce87a190 625 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vlan99'], universal_newlines=True).rstrip()
14ecd604 626 print(output)
06895a1d
YW
627 self.assertRegex(output, ' mtu 2000 ')
628 self.assertRegex(output, 'REORDER_HDR')
629 self.assertRegex(output, 'LOOSE_BINDING')
630 self.assertRegex(output, 'GVRP')
631 self.assertRegex(output, 'MVRP')
632 self.assertRegex(output, ' id 99 ')
1f0e3109 633
ce87a190 634 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'test1'], universal_newlines=True).rstrip()
7f45d738
YW
635 print(output)
636 self.assertRegex(output, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
637 self.assertRegex(output, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
638
ce87a190 639 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'vlan99'], universal_newlines=True).rstrip()
7f45d738
YW
640 print(output)
641 self.assertRegex(output, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
642
1f0e3109 643 def test_macvtap(self):
460feb61
YW
644 for mode in ['private', 'vepa', 'bridge', 'passthru']:
645 with self.subTest(mode=mode):
646 if mode != 'private':
647 self.tearDown()
077f9abc
YW
648 self.copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
649 '11-dummy.netdev', 'macvtap.network')
460feb61
YW
650 with open(os.path.join(network_unit_file_path, '21-macvtap.netdev'), mode='a') as f:
651 f.write('[MACVTAP]\nMode=' + mode)
652 self.start_networkd(0)
1f0e3109 653
077f9abc 654 self.wait_online(['macvtap99:degraded', 'test1:degraded'])
460feb61
YW
655
656 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'macvtap99'], universal_newlines=True).rstrip()
657 print(output)
658 self.assertRegex(output, 'macvtap mode ' + mode + ' ')
1f0e3109
SS
659
660 def test_macvlan(self):
dff9792b
YW
661 for mode in ['private', 'vepa', 'bridge', 'passthru']:
662 with self.subTest(mode=mode):
663 if mode != 'private':
664 self.tearDown()
077f9abc
YW
665 self.copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
666 '11-dummy.netdev', 'macvlan.network')
dff9792b
YW
667 with open(os.path.join(network_unit_file_path, '21-macvlan.netdev'), mode='a') as f:
668 f.write('[MACVLAN]\nMode=' + mode)
669 self.start_networkd(0)
670
077f9abc 671 self.wait_online(['macvlan99:degraded', 'test1:degraded'])
dff9792b
YW
672
673 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1'], universal_newlines=True).rstrip()
674 print(output)
675 self.assertRegex(output, ' mtu 2000 ')
72b7f1b9 676
dff9792b
YW
677 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'macvlan99'], universal_newlines=True).rstrip()
678 print(output)
679 self.assertRegex(output, ' mtu 2000 ')
680 self.assertRegex(output, 'macvlan mode ' + mode + ' ')
72b7f1b9 681
7a0a37b2 682 @expectedFailureIfModuleIsNotAvailable('ipvlan')
1f0e3109 683 def test_ipvlan(self):
bc6dff6e
YW
684 for mode, flag in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
685 with self.subTest(mode=mode, flag=flag):
686 if mode != 'L2':
687 self.tearDown()
077f9abc
YW
688 self.copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
689 '11-dummy.netdev', 'ipvlan.network')
bc6dff6e
YW
690 with open(os.path.join(network_unit_file_path, '25-ipvlan.netdev'), mode='a') as f:
691 f.write('[IPVLAN]\nMode=' + mode + '\nFlags=' + flag)
1f0e3109 692
bc6dff6e 693 self.start_networkd(0)
077f9abc 694 self.wait_online(['ipvlan99:degraded', 'test1:degraded'])
bc6dff6e
YW
695
696 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ipvlan99'], universal_newlines=True).rstrip()
697 print(output)
698 self.assertRegex(output, 'ipvlan *mode ' + mode.lower() + ' ' + flag)
1f0e3109 699
956c8fec
YW
700 @expectedFailureIfModuleIsNotAvailable('ipvtap')
701 def test_ipvtap(self):
40921f08
YW
702 for mode, flag in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
703 with self.subTest(mode=mode, flag=flag):
704 if mode != 'L2':
705 self.tearDown()
077f9abc
YW
706 self.copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
707 '11-dummy.netdev', 'ipvtap.network')
40921f08
YW
708 with open(os.path.join(network_unit_file_path, '25-ipvtap.netdev'), mode='a') as f:
709 f.write('[IPVTAP]\nMode=' + mode + '\nFlags=' + flag)
710
711 self.start_networkd(0)
077f9abc 712 self.wait_online(['ipvtap99:degraded', 'test1:degraded'])
956c8fec 713
40921f08
YW
714 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ipvtap99'], universal_newlines=True).rstrip()
715 print(output)
716 self.assertRegex(output, 'ipvtap *mode ' + mode.lower() + ' ' + flag)
956c8fec 717
1f0e3109 718 def test_veth(self):
671dacdf 719 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
c815f33e 720 self.start_networkd(0)
1f0e3109 721
671dacdf
YW
722 self.wait_online(['veth99:degraded', 'veth-peer:degraded'])
723
724 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'veth99'], universal_newlines=True).rstrip()
725 print(output)
726 self.assertRegex(output, 'link/ether 12:34:56:78:9a:bc')
727 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'veth-peer'], universal_newlines=True).rstrip()
728 print(output)
729 self.assertRegex(output, 'link/ether 12:34:56:78:9a:bd')
1f0e3109 730
1f0e3109
SS
731 def test_tun(self):
732 self.copy_unit_to_networkd_unit_path('25-tun.netdev')
c815f33e 733 self.start_networkd(0)
1f0e3109 734
c815f33e 735 self.wait_online(['tun99:off'])
1f0e3109 736
2746d307
YW
737 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'tun99'], universal_newlines=True).rstrip()
738 print(output)
739 # Old ip command does not support IFF_ flags
740 self.assertRegex(output, 'tun (?:type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
741
1f0e3109
SS
742 def test_tap(self):
743 self.copy_unit_to_networkd_unit_path('25-tap.netdev')
c815f33e 744 self.start_networkd(0)
1f0e3109 745
c815f33e 746 self.wait_online(['tap99:off'])
1f0e3109 747
2746d307
YW
748 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'tap99'], universal_newlines=True).rstrip()
749 print(output)
750 # Old ip command does not support IFF_ flags
751 self.assertRegex(output, 'tun (?:type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
752
7a0a37b2 753 @expectedFailureIfModuleIsNotAvailable('vrf')
1f0e3109 754 def test_vrf(self):
0aefa227 755 self.copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
c815f33e 756 self.start_networkd(0)
1f0e3109 757
0aefa227 758 self.wait_online(['vrf99:carrier'])
1f0e3109 759
7a0a37b2 760 @expectedFailureIfModuleIsNotAvailable('vcan')
1f0e3109 761 def test_vcan(self):
a1b35590 762 self.copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
c815f33e 763 self.start_networkd(0)
1f0e3109 764
a1b35590 765 self.wait_online(['vcan99:carrier'])
1f0e3109 766
f63b14d3
YW
767 @expectedFailureIfModuleIsNotAvailable('vxcan')
768 def test_vxcan(self):
769 self.copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
770 self.start_networkd(0)
771
772 self.wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
773
7a3bc5a8
EV
774 @expectedFailureIfModuleIsNotAvailable('wireguard')
775 def test_wireguard(self):
5a0bd90b
YW
776 self.copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
777 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
9e5d79e7 778 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt')
5a0bd90b
YW
779 self.start_networkd(0)
780 self.wait_online(['wg99:carrier', 'wg98:routable'])
781
7a3bc5a8
EV
782 if shutil.which('wg'):
783 subprocess.call('wg')
5a0bd90b 784
ce87a190 785 output = subprocess.check_output(['wg', 'show', 'wg99', 'listen-port'], universal_newlines=True).rstrip()
06895a1d 786 self.assertRegex(output, '51820')
ce87a190 787 output = subprocess.check_output(['wg', 'show', 'wg99', 'fwmark'], universal_newlines=True).rstrip()
06895a1d 788 self.assertRegex(output, '0x4d2')
ce87a190 789 output = subprocess.check_output(['wg', 'show', 'wg99', 'allowed-ips'], universal_newlines=True).rstrip()
06895a1d
YW
790 self.assertRegex(output, 'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
791 self.assertRegex(output, 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
ce87a190 792 output = subprocess.check_output(['wg', 'show', 'wg99', 'persistent-keepalive'], universal_newlines=True).rstrip()
06895a1d 793 self.assertRegex(output, 'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
ce87a190 794 output = subprocess.check_output(['wg', 'show', 'wg99', 'endpoints'], universal_newlines=True).rstrip()
06895a1d 795 self.assertRegex(output, 'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
ce87a190 796 output = subprocess.check_output(['wg', 'show', 'wg99', 'private-key'], universal_newlines=True).rstrip()
06895a1d 797 self.assertRegex(output, 'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
ce87a190 798 output = subprocess.check_output(['wg', 'show', 'wg99', 'preshared-keys'], universal_newlines=True).rstrip()
06895a1d
YW
799 self.assertRegex(output, 'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
800 self.assertRegex(output, 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
7a3bc5a8 801
ce87a190 802 output = subprocess.check_output(['wg', 'show', 'wg98', 'private-key'], universal_newlines=True).rstrip()
06895a1d 803 self.assertRegex(output, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
da44fb8a 804
1f0e3109 805 def test_geneve(self):
0aefa227 806 self.copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
c815f33e 807 self.start_networkd(0)
1f0e3109 808
0aefa227 809 self.wait_online(['geneve99:degraded'])
1f0e3109 810
ce87a190 811 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'geneve99'], universal_newlines=True).rstrip()
14ecd604 812 print(output)
06895a1d
YW
813 self.assertRegex(output, '192.168.22.1')
814 self.assertRegex(output, '6082')
815 self.assertRegex(output, 'udpcsum')
816 self.assertRegex(output, 'udp6zerocsumrx')
1f0e3109
SS
817
818 def test_ipip_tunnel(self):
11309591
YW
819 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
820 '25-ipip-tunnel.netdev', '25-tunnel.network',
821 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
822 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
823 self.start_networkd(0)
824 self.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'dummy98:degraded'])
6a97a864 825
ce87a190 826 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ipiptun99'], universal_newlines=True).rstrip()
6a97a864
YW
827 print(output)
828 self.assertRegex(output, 'ipip (?:ipip |)remote 192.169.224.239 local 192.168.223.238 dev dummy98')
ce87a190 829 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ipiptun98'], universal_newlines=True).rstrip()
6a97a864
YW
830 print(output)
831 self.assertRegex(output, 'ipip (?:ipip |)remote 192.169.224.239 local any dev dummy98')
ce87a190 832 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ipiptun97'], universal_newlines=True).rstrip()
6a97a864
YW
833 print(output)
834 self.assertRegex(output, 'ipip (?:ipip |)remote any local 192.168.223.238 dev dummy98')
1f0e3109
SS
835
836 def test_gre_tunnel(self):
11309591
YW
837 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
838 '25-gre-tunnel.netdev', '25-tunnel.network',
839 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
840 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
841 self.start_networkd(0)
842 self.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'dummy98:degraded'])
6a97a864 843
ce87a190 844 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretun99'], universal_newlines=True).rstrip()
6a97a864
YW
845 print(output)
846 self.assertRegex(output, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
38f4bb44
YW
847 self.assertRegex(output, 'ikey 1.2.3.103')
848 self.assertRegex(output, 'okey 1.2.4.103')
849 self.assertRegex(output, 'iseq')
850 self.assertRegex(output, 'oseq')
ce87a190 851 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretun98'], universal_newlines=True).rstrip()
6a97a864
YW
852 print(output)
853 self.assertRegex(output, 'gre remote 10.65.223.239 local any dev dummy98')
38f4bb44
YW
854 self.assertRegex(output, 'ikey 0.0.0.104')
855 self.assertRegex(output, 'okey 0.0.0.104')
856 self.assertNotRegex(output, 'iseq')
857 self.assertNotRegex(output, 'oseq')
ce87a190 858 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretun97'], universal_newlines=True).rstrip()
6a97a864
YW
859 print(output)
860 self.assertRegex(output, 'gre remote any local 10.65.223.238 dev dummy98')
38f4bb44
YW
861 self.assertRegex(output, 'ikey 0.0.0.105')
862 self.assertRegex(output, 'okey 0.0.0.105')
863 self.assertNotRegex(output, 'iseq')
864 self.assertNotRegex(output, 'oseq')
6a97a864
YW
865
866 def test_ip6gre_tunnel(self):
11309591
YW
867 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
868 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
869 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
870 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
6a97a864
YW
871 self.start_networkd()
872
17bcf0a0
YW
873 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
874
e39cc445
YW
875 self.check_link_exists('dummy98')
876 self.check_link_exists('ip6gretun99')
877 self.check_link_exists('ip6gretun98')
878 self.check_link_exists('ip6gretun97')
6a97a864 879
ce87a190 880 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6gretun99'], universal_newlines=True).rstrip()
6a97a864
YW
881 print(output)
882 self.assertRegex(output, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
ce87a190 883 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6gretun98'], universal_newlines=True).rstrip()
6a97a864
YW
884 print(output)
885 self.assertRegex(output, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
ce87a190 886 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6gretun97'], universal_newlines=True).rstrip()
6a97a864
YW
887 print(output)
888 self.assertRegex(output, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
1f0e3109 889
11309591
YW
890 def test_gretap_tunnel(self):
891 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
892 '25-gretap-tunnel.netdev', '25-tunnel.network',
893 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
894 self.start_networkd(0)
895 self.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
6a97a864 896
ce87a190 897 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretap99'], universal_newlines=True).rstrip()
6a97a864
YW
898 print(output)
899 self.assertRegex(output, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
38f4bb44
YW
900 self.assertRegex(output, 'ikey 0.0.0.106')
901 self.assertRegex(output, 'okey 0.0.0.106')
902 self.assertRegex(output, 'iseq')
903 self.assertRegex(output, 'oseq')
ce87a190 904 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretap98'], universal_newlines=True).rstrip()
6a97a864
YW
905 print(output)
906 self.assertRegex(output, 'gretap remote 10.65.223.239 local any dev dummy98')
38f4bb44
YW
907 self.assertRegex(output, 'ikey 0.0.0.107')
908 self.assertRegex(output, 'okey 0.0.0.107')
909 self.assertRegex(output, 'iseq')
910 self.assertRegex(output, 'oseq')
1f0e3109
SS
911
912 def test_ip6gretap_tunnel(self):
11309591
YW
913 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
914 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
915 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
916 self.start_networkd(0)
917 self.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
6a97a864 918
ce87a190 919 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6gretap99'], universal_newlines=True).rstrip()
6a97a864
YW
920 print(output)
921 self.assertRegex(output, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
ce87a190 922 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6gretap98'], universal_newlines=True).rstrip()
6a97a864
YW
923 print(output)
924 self.assertRegex(output, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1f0e3109
SS
925
926 def test_vti_tunnel(self):
11309591
YW
927 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
928 '25-vti-tunnel.netdev', '25-tunnel.network',
929 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
930 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
931 self.start_networkd(0)
932 self.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'dummy98:degraded'])
6a97a864 933
ce87a190 934 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vtitun99'], universal_newlines=True).rstrip()
6a97a864
YW
935 print(output)
936 self.assertRegex(output, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
ce87a190 937 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vtitun98'], universal_newlines=True).rstrip()
6a97a864
YW
938 print(output)
939 self.assertRegex(output, 'vti remote 10.65.223.239 local any dev dummy98')
ce87a190 940 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vtitun97'], universal_newlines=True).rstrip()
6a97a864
YW
941 print(output)
942 self.assertRegex(output, 'vti remote any local 10.65.223.238 dev dummy98')
1f0e3109
SS
943
944 def test_vti6_tunnel(self):
11309591
YW
945 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
946 '25-vti6-tunnel.netdev', '25-tunnel.network',
947 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
948 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
949 self.start_networkd(0)
950 self.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
6a97a864 951
ce87a190 952 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vti6tun99'], universal_newlines=True).rstrip()
6a97a864
YW
953 print(output)
954 self.assertRegex(output, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
ce87a190 955 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vti6tun98'], universal_newlines=True).rstrip()
6a97a864
YW
956 print(output)
957 self.assertRegex(output, 'vti6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
ce87a190 958 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vti6tun97'], universal_newlines=True).rstrip()
6a97a864
YW
959 print(output)
960 self.assertRegex(output, 'vti6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1f0e3109
SS
961
962 def test_ip6tnl_tunnel(self):
11309591
YW
963 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
964 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
965 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
966 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
967 self.start_networkd(0)
968 self.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
6a97a864 969
ce87a190 970 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6tnl99'], universal_newlines=True).rstrip()
6a97a864
YW
971 print(output)
972 self.assertRegex(output, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
ce87a190 973 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6tnl98'], universal_newlines=True).rstrip()
6a97a864
YW
974 print(output)
975 self.assertRegex(output, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
ce87a190 976 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6tnl97'], universal_newlines=True).rstrip()
6a97a864
YW
977 print(output)
978 self.assertRegex(output, 'ip6tnl ip6ip6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1f0e3109
SS
979
980 def test_sit_tunnel(self):
11309591
YW
981 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
982 '25-sit-tunnel.netdev', '25-tunnel.network',
983 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
984 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
985 self.start_networkd(0)
986 self.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'dummy98:degraded'])
6a97a864 987
ce87a190 988 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'sittun99'], universal_newlines=True).rstrip()
6a97a864
YW
989 print(output)
990 self.assertRegex(output, "sit (?:ip6ip |)remote 10.65.223.239 local 10.65.223.238 dev dummy98")
ce87a190 991 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'sittun98'], universal_newlines=True).rstrip()
6a97a864
YW
992 print(output)
993 self.assertRegex(output, "sit (?:ip6ip |)remote 10.65.223.239 local any dev dummy98")
ce87a190 994 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'sittun97'], universal_newlines=True).rstrip()
6a97a864
YW
995 print(output)
996 self.assertRegex(output, "sit (?:ip6ip |)remote any local 10.65.223.238 dev dummy98")
1f0e3109 997
d0e728b6 998 def test_isatap_tunnel(self):
11309591
YW
999 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1000 '25-isatap-tunnel.netdev', '25-tunnel.network')
1001 self.start_networkd(0)
1002 self.wait_online(['isataptun99:routable', 'dummy98:degraded'])
d0e728b6 1003
ce87a190 1004 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'isataptun99'], universal_newlines=True).rstrip()
14ecd604 1005 print(output)
d0e728b6
SS
1006 self.assertRegex(output, "isatap ")
1007
d29dc4f1 1008 def test_6rd_tunnel(self):
11309591
YW
1009 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1010 '25-6rd-tunnel.netdev', '25-tunnel.network')
1011 self.start_networkd(0)
1012 self.wait_online(['sittun99:routable', 'dummy98:degraded'])
d29dc4f1 1013
ce87a190 1014 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'sittun99'], universal_newlines=True).rstrip()
6a97a864
YW
1015 print(output)
1016 self.assertRegex(output, '6rd-prefix 2602::/24')
1017
7bea7f9b 1018 @expectedFailureIfERSPANModuleIsNotAvailable()
2266864b 1019 def test_erspan_tunnel(self):
6730a1f3 1020 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
11309591
YW
1021 '25-erspan-tunnel.netdev', '25-tunnel.network',
1022 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1023 self.start_networkd(0)
1024 self.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
2266864b 1025
ce87a190 1026 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'erspan99'], universal_newlines=True).rstrip()
6a97a864
YW
1027 print(output)
1028 self.assertRegex(output, 'erspan remote 172.16.1.100 local 172.16.1.200')
38f4bb44
YW
1029 self.assertRegex(output, 'ikey 0.0.0.101')
1030 self.assertRegex(output, 'okey 0.0.0.101')
1031 self.assertRegex(output, 'iseq')
1032 self.assertRegex(output, 'oseq')
ce87a190 1033 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'erspan98'], universal_newlines=True).rstrip()
2266864b 1034 print(output)
6a97a864
YW
1035 self.assertRegex(output, 'erspan remote 172.16.1.100 local any')
1036 self.assertRegex(output, '102')
38f4bb44
YW
1037 self.assertRegex(output, 'ikey 0.0.0.102')
1038 self.assertRegex(output, 'okey 0.0.0.102')
1039 self.assertRegex(output, 'iseq')
1040 self.assertRegex(output, 'oseq')
2266864b 1041
1f0e3109 1042 def test_tunnel_independent(self):
0aefa227 1043 self.copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
c815f33e 1044 self.start_networkd(0)
e40a58b5 1045
0aefa227 1046 self.wait_online(['ipiptun99:carrier'])
1f0e3109 1047
4b6a6d1e
YW
1048 @expectedFailureIfModuleIsNotAvailable('fou')
1049 def test_fou(self):
1050 # The following redundant check is necessary for CentOS CI.
1051 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1052 self.assertTrue(is_module_available('fou'))
1053
1054 self.copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1055 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1056 '25-fou-gre.netdev', '25-fou-gretap.netdev')
c815f33e 1057 self.start_networkd(0)
4b6a6d1e 1058
c815f33e 1059 self.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'])
4b6a6d1e 1060
ce87a190 1061 output = subprocess.check_output(['ip', 'fou', 'show'], universal_newlines=True).rstrip()
4b6a6d1e
YW
1062 print(output)
1063 self.assertRegex(output, 'port 55555 ipproto 4')
1064 self.assertRegex(output, 'port 55556 ipproto 47')
1065
ce87a190 1066 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ipiptun96'], universal_newlines=True).rstrip()
4b6a6d1e
YW
1067 print(output)
1068 self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55555')
ce87a190 1069 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'sittun96'], universal_newlines=True).rstrip()
4b6a6d1e
YW
1070 print(output)
1071 self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55555')
ce87a190 1072 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretun96'], universal_newlines=True).rstrip()
4b6a6d1e
YW
1073 print(output)
1074 self.assertRegex(output, 'encap fou encap-sport 1001 encap-dport 55556')
ce87a190 1075 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretap96'], universal_newlines=True).rstrip()
4b6a6d1e
YW
1076 print(output)
1077 self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55556')
1078
1f0e3109 1079 def test_vxlan(self):
1c862fe0
YW
1080 self.copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1081 '11-dummy.netdev', 'vxlan-test1.network')
1082 self.start_networkd(0)
1f0e3109 1083
1c862fe0 1084 self.wait_online(['test1:degraded', 'vxlan99:degraded'])
1f0e3109 1085
ce87a190 1086 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vxlan99'], universal_newlines=True).rstrip()
14ecd604 1087 print(output)
1c862fe0 1088 self.assertRegex(output, '999')
1f0e3109
SS
1089 self.assertRegex(output, '5555')
1090 self.assertRegex(output, 'l2miss')
1091 self.assertRegex(output, 'l3miss')
1092 self.assertRegex(output, 'udpcsum')
1093 self.assertRegex(output, 'udp6zerocsumtx')
1094 self.assertRegex(output, 'udp6zerocsumrx')
1095 self.assertRegex(output, 'remcsumtx')
1096 self.assertRegex(output, 'remcsumrx')
1097 self.assertRegex(output, 'gbp')
1098
ce87a190 1099 output = subprocess.check_output(['bridge', 'fdb', 'show', 'dev', 'vxlan99'], universal_newlines=True).rstrip()
1c862fe0
YW
1100 print(output)
1101 self.assertRegex(output, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1102 self.assertRegex(output, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1103 self.assertRegex(output, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1104
02849d8b
YW
1105 def test_macsec(self):
1106 self.copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1107 'macsec.network', '12-dummy.netdev')
1108 self.start_networkd(0)
1109
1110 self.wait_online(['dummy98:degraded', 'macsec99:routable'])
1111
ce87a190 1112 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'macsec99'], universal_newlines=True).rstrip()
02849d8b
YW
1113 print(output)
1114 self.assertRegex(output, 'macsec99@dummy98')
1115 self.assertRegex(output, 'macsec sci [0-9a-f]*000b')
1116 self.assertRegex(output, 'encrypt on')
1117
ce87a190 1118 output = subprocess.check_output(['ip', 'macsec', 'show', 'macsec99'], universal_newlines=True).rstrip()
02849d8b
YW
1119 print(output)
1120 self.assertRegex(output, 'encrypt on')
1121 self.assertRegex(output, 'TXSC: [0-9a-f]*000b on SA 1')
1122 self.assertRegex(output, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1123 self.assertRegex(output, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1124 self.assertRegex(output, 'RXSC: c619528fe6a00100, state on')
1125 self.assertRegex(output, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1126 self.assertRegex(output, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1127 self.assertRegex(output, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1128 self.assertRegex(output, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1129 self.assertNotRegex(output, 'key 02030405067080900000000000000000')
1130 self.assertRegex(output, 'RXSC: 8c16456c83a90002, state on')
1131 self.assertRegex(output, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1132
811f33d0 1133 def test_nlmon(self):
931d1105 1134 self.copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
811f33d0
YW
1135 self.start_networkd()
1136
1137 self.wait_online(['nlmon99:carrier'])
02849d8b 1138
cff83db9
YW
1139class NetworkdL2TPTests(unittest.TestCase, Utilities):
1140
1141 links =[
1142 'l2tp-ses1',
1143 'l2tp-ses2',
1144 'l2tp-ses3',
1145 'l2tp-ses4',
1146 'test1']
1147
1148 units = [
1149 '11-dummy.netdev',
1150 '25-l2tp-dummy.network',
1151 '25-l2tp-ip.netdev',
1152 '25-l2tp-udp.netdev']
1153
1154 l2tp_tunnel_ids = [ '10' ]
1155
1156 def setUp(self):
1157 self.l2tp_tunnel_remove(self.l2tp_tunnel_ids)
350e05d2 1158 self.remove_links(self.links)
cff83db9
YW
1159
1160 def tearDown(self):
1161 self.l2tp_tunnel_remove(self.l2tp_tunnel_ids)
350e05d2 1162 self.remove_links(self.links)
cff83db9
YW
1163 self.remove_unit_from_networkd_path(self.units)
1164
1165 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1166 def test_l2tp_udp(self):
1167 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-udp.netdev')
a9a2ee6a 1168 self.start_networkd(0)
cff83db9 1169
a9a2ee6a 1170 self.wait_online(['test1:routable', 'l2tp-ses1:off', 'l2tp-ses2:off'])
cff83db9 1171
ce87a190 1172 output = subprocess.check_output(['ip', 'l2tp', 'show', 'tunnel', 'tunnel_id', '10'], universal_newlines=True).rstrip()
cff83db9
YW
1173 print(output)
1174 self.assertRegex(output, "Tunnel 10, encap UDP")
1175 self.assertRegex(output, "From 192.168.30.100 to 192.168.30.101")
1176 self.assertRegex(output, "Peer tunnel 11")
1177 self.assertRegex(output, "UDP source / dest ports: 3000/4000")
1178 self.assertRegex(output, "UDP checksum: enabled")
1179
ce87a190 1180 output = subprocess.check_output(['ip', 'l2tp', 'show', 'session', 'tid', '10', 'session_id', '15'], universal_newlines=True).rstrip()
cff83db9
YW
1181 print(output)
1182 self.assertRegex(output, "Session 15 in tunnel 10")
1183 self.assertRegex(output, "Peer session 16, tunnel 11")
1184 self.assertRegex(output, "interface name: l2tp-ses1")
1185
ce87a190 1186 output = subprocess.check_output(['ip', 'l2tp', 'show', 'session', 'tid', '10', 'session_id', '17'], universal_newlines=True).rstrip()
cff83db9
YW
1187 print(output)
1188 self.assertRegex(output, "Session 17 in tunnel 10")
1189 self.assertRegex(output, "Peer session 18, tunnel 11")
1190 self.assertRegex(output, "interface name: l2tp-ses2")
1191
1192 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1193 def test_l2tp_ip(self):
1194 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-ip.netdev')
a9a2ee6a 1195 self.start_networkd(0)
cff83db9 1196
a9a2ee6a 1197 self.wait_online(['test1:routable', 'l2tp-ses3:off', 'l2tp-ses4:off'])
cff83db9 1198
ce87a190 1199 output = subprocess.check_output(['ip', 'l2tp', 'show', 'tunnel', 'tunnel_id', '10'], universal_newlines=True).rstrip()
cff83db9
YW
1200 print(output)
1201 self.assertRegex(output, "Tunnel 10, encap IP")
1202 self.assertRegex(output, "From 192.168.30.100 to 192.168.30.101")
1203 self.assertRegex(output, "Peer tunnel 12")
1204
ce87a190 1205 output = subprocess.check_output(['ip', 'l2tp', 'show', 'session', 'tid', '10', 'session_id', '25'], universal_newlines=True).rstrip()
cff83db9
YW
1206 print(output)
1207 self.assertRegex(output, "Session 25 in tunnel 10")
1208 self.assertRegex(output, "Peer session 26, tunnel 12")
1209 self.assertRegex(output, "interface name: l2tp-ses3")
1210
ce87a190 1211 output = subprocess.check_output(['ip', 'l2tp', 'show', 'session', 'tid', '10', 'session_id', '27'], universal_newlines=True).rstrip()
cff83db9
YW
1212 print(output)
1213 self.assertRegex(output, "Session 27 in tunnel 10")
1214 self.assertRegex(output, "Peer session 28, tunnel 12")
1215 self.assertRegex(output, "interface name: l2tp-ses4")
1216
be68c2c9 1217class NetworkdNetworkTests(unittest.TestCase, Utilities):
09ea6724
YW
1218 links = [
1219 'bond199',
1220 'dummy98',
cd65d067 1221 'dummy99',
09ea6724
YW
1222 'test1']
1223
1224 units = [
1225 '11-dummy.netdev',
1226 '12-dummy.netdev',
1227 '23-active-slave.network',
fdcd1ec5 1228 '24-search-domain.network',
09ea6724 1229 '25-address-link-section.network',
b8102725
YW
1230 '25-address-preferred-lifetime-zero-ipv6.network',
1231 '25-address-static.network',
cd65d067 1232 '25-bind-carrier.network',
09ea6724
YW
1233 '25-bond-active-backup-slave.netdev',
1234 '25-fibrule-invert.network',
1235 '25-fibrule-port-range.network',
1236 '25-ipv6-address-label-section.network',
e4a71bf3 1237 '25-neighbor-section.network',
05514ae1
YW
1238 '25-link-local-addressing-no.network',
1239 '25-link-local-addressing-yes.network',
09ea6724 1240 '25-link-section-unmanaged.network',
20ca06a6 1241 '25-route-ipv6-src.network',
0ef830cf 1242 '25-route-static.network',
4da33154 1243 '25-sysctl-disable-ipv6.network',
09ea6724
YW
1244 '25-sysctl.network',
1245 'configure-without-carrier.network',
b677774d 1246 'routing-policy-rule-dummy98.network',
b8102725 1247 'routing-policy-rule-test1.network']
1f0e3109 1248
95c74b0a 1249 routing_policy_rule_tables = ['7', '8']
5f68a6a4 1250 routes = [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
95c74b0a 1251
1f0e3109 1252 def setUp(self):
95c74b0a 1253 self.remove_routing_policy_rule_tables(self.routing_policy_rule_tables)
5f68a6a4 1254 self.remove_routes(self.routes)
350e05d2 1255 self.remove_links(self.links)
1f0e3109
SS
1256
1257 def tearDown(self):
95c74b0a 1258 self.remove_routing_policy_rule_tables(self.routing_policy_rule_tables)
5f68a6a4 1259 self.remove_routes(self.routes)
350e05d2 1260 self.remove_links(self.links)
1f0e3109
SS
1261 self.remove_unit_from_networkd_path(self.units)
1262
b8102725
YW
1263 def test_address_static(self):
1264 self.copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1265 self.start_networkd(0)
1266
1267 self.wait_online(['dummy98:routable'])
1268
ce87a190 1269 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98'], universal_newlines=True).rstrip()
b8102725
YW
1270 print(output)
1271 self.assertRegex(output, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1272 self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1273 self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1274
1275 # invalid sections
1276 self.assertNotRegex(output, '10.10.0.1/16')
1277 self.assertNotRegex(output, '10.10.0.2/16')
1278
ce87a190 1279 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98', 'label', '32'], universal_newlines=True).rstrip()
b8102725
YW
1280 self.assertRegex(output, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1281
ce87a190 1282 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98', 'label', '33'], universal_newlines=True).rstrip()
b8102725
YW
1283 self.assertRegex(output, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1284
ce87a190 1285 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98', 'label', '34'], universal_newlines=True).rstrip()
b8102725
YW
1286 self.assertRegex(output, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1287
ce87a190 1288 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98', 'label', '35'], universal_newlines=True).rstrip()
b8102725
YW
1289 self.assertRegex(output, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1290
ce87a190 1291 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'dummy98'], universal_newlines=True).rstrip()
b8102725
YW
1292 print(output)
1293 self.assertRegex(output, 'inet6 2001:db8:0:f101::15/64 scope global')
1294 self.assertRegex(output, 'inet6 2001:db8:0:f101::16/64 scope global')
1295 self.assertRegex(output, 'inet6 2001:db8:0:f102::15/64 scope global')
1296 self.assertRegex(output, 'inet6 2001:db8:0:f102::16/64 scope global')
1297 self.assertRegex(output, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1298 self.assertRegex(output, 'inet6 fd[0-9a-f:]*1/64 scope global')
1299
1300 def test_address_preferred_lifetime_zero_ipv6(self):
1301 self.copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero-ipv6.network', '12-dummy.netdev')
1f0e3109
SS
1302 self.start_networkd()
1303
e39cc445 1304 self.check_link_exists('dummy98')
e40a58b5 1305
791c1140 1306 self.check_operstate('dummy98', 'routable', setup_state='configuring')
b8102725 1307
ce87a190 1308 output = subprocess.check_output(['ip', 'address', 'show', 'dummy98'], universal_newlines=True).rstrip()
b8102725
YW
1309 print(output)
1310 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1311 self.assertRegex(output, 'inet6 2001:db8:0:f101::1/64 scope global')
1f0e3109
SS
1312
1313 def test_configure_without_carrier(self):
1314 self.copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
1315 self.start_networkd()
1316
e39cc445 1317 self.check_link_exists('test1')
e40a58b5 1318
9c1ae484 1319 output = subprocess.check_output(networkctl_cmd + ['status', 'test1'], universal_newlines=True, env=env).rstrip()
1f0e3109
SS
1320 print(output)
1321 self.assertRegex(output, '192.168.0.15')
1322 self.assertRegex(output, '192.168.0.1')
1323 self.assertRegex(output, 'routable')
1324
1f0e3109 1325 def test_routing_policy_rule(self):
b677774d 1326 self.copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
703bc7a2 1327
1f0e3109
SS
1328 self.start_networkd()
1329
e39cc445 1330 self.check_link_exists('test1')
e40a58b5 1331
ce87a190 1332 output = subprocess.check_output(['ip', 'rule'], universal_newlines=True).rstrip()
1f0e3109
SS
1333 print(output)
1334 self.assertRegex(output, '111')
1335 self.assertRegex(output, 'from 192.168.100.18')
f7bdd562 1336 self.assertRegex(output, r'tos (?:0x08|throughput)\s')
1f0e3109
SS
1337 self.assertRegex(output, 'iif test1')
1338 self.assertRegex(output, 'oif test1')
1339 self.assertRegex(output, 'lookup 7')
1340
b677774d
YW
1341 def test_routing_policy_rule_issue_11280(self):
1342 self.copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1343 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1344
b677774d
YW
1345 for trial in range(3):
1346 # Remove state files only first time
5aa58329 1347 self.start_networkd(remove_state_files=(trial == 0))
b677774d 1348
e39cc445
YW
1349 self.check_link_exists('test1')
1350 self.check_link_exists('dummy98')
b677774d 1351
ce87a190 1352 output = subprocess.check_output(['ip', 'rule', 'list', 'table', '7'], universal_newlines=True).rstrip()
b677774d
YW
1353 print(output)
1354 self.assertRegex(output, '111: from 192.168.100.18 tos (?:0x08|throughput) iif test1 oif test1 lookup 7')
1355
ce87a190 1356 output = subprocess.check_output(['ip', 'rule', 'list', 'table', '8'], universal_newlines=True).rstrip()
b677774d
YW
1357 print(output)
1358 self.assertRegex(output, '112: from 192.168.101.18 tos (?:0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1359
d586a2c3 1360 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
926062f0
SS
1361 def test_routing_policy_rule_port_range(self):
1362 self.copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
703bc7a2 1363
926062f0
SS
1364 self.start_networkd()
1365
e39cc445 1366 self.check_link_exists('test1')
e40a58b5 1367
ce87a190 1368 output = subprocess.check_output(['ip', 'rule'], universal_newlines=True).rstrip()
926062f0
SS
1369 print(output)
1370 self.assertRegex(output, '111')
1371 self.assertRegex(output, 'from 192.168.100.18')
1372 self.assertRegex(output, '1123-1150')
1373 self.assertRegex(output, '3224-3290')
1374 self.assertRegex(output, 'tcp')
1375 self.assertRegex(output, 'lookup 7')
1f0e3109 1376
d586a2c3 1377 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
efecf9cd
SS
1378 def test_routing_policy_rule_invert(self):
1379 self.copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
703bc7a2 1380
efecf9cd
SS
1381 self.start_networkd()
1382
e39cc445 1383 self.check_link_exists('test1')
e40a58b5 1384
ce87a190 1385 output = subprocess.check_output(['ip', 'rule'], universal_newlines=True).rstrip()
efecf9cd 1386 print(output)
efecf9cd
SS
1387 self.assertRegex(output, '111')
1388 self.assertRegex(output, 'not.*?from.*?192.168.100.18')
1389 self.assertRegex(output, 'tcp')
1390 self.assertRegex(output, 'lookup 7')
1391
0ef830cf
YW
1392 def test_route_static(self):
1393 self.copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1394 self.start_networkd(0)
0d34228f 1395
0ef830cf 1396 self.wait_online(['dummy98:routable'])
0d34228f 1397
ce87a190 1398 output = subprocess.check_output(['ip', '-6', 'route', 'show', 'dev', 'dummy98'], universal_newlines=True).rstrip()
0d34228f 1399 print(output)
0ef830cf
YW
1400 self.assertRegex(output, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1401 self.assertRegex(output, '2001:1234:5:8f63::1 proto kernel')
1f0e3109 1402
ce87a190 1403 output = subprocess.check_output(['ip', '-6', 'route', 'show', 'dev', 'dummy98', 'default'], universal_newlines=True).rstrip()
0ef830cf 1404 self.assertRegex(output, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1f0e3109 1405
ce87a190 1406 output = subprocess.check_output(['ip', '-4', 'route', 'show', 'dev', 'dummy98'], universal_newlines=True).rstrip()
1f0e3109 1407 print(output)
0ef830cf
YW
1408 self.assertRegex(output, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1409 self.assertRegex(output, '149.10.124.64 proto static scope link')
2b00dff8 1410 self.assertRegex(output, '169.254.0.0/16 proto static scope link metric 2048')
0ef830cf
YW
1411 self.assertRegex(output, '192.168.1.1 proto static initcwnd 20')
1412 self.assertRegex(output, '192.168.1.2 proto static initrwnd 30')
1f0e3109 1413
ce87a190 1414 output = subprocess.check_output(['ip', '-4', 'route', 'show', 'dev', 'dummy98', 'default'], universal_newlines=True).rstrip()
0ef830cf
YW
1415 self.assertRegex(output, 'default via 149.10.125.65 proto static onlink')
1416 self.assertRegex(output, 'default via 149.10.124.64 proto static')
6543b7fd 1417 self.assertRegex(output, 'default proto static')
1f0e3109 1418
ce87a190 1419 output = subprocess.check_output(['ip', 'route', 'show', 'type', 'blackhole'], universal_newlines=True).rstrip()
1f0e3109 1420 print(output)
0ef830cf 1421 self.assertRegex(output, 'blackhole 202.54.1.2 proto static')
f5050e48 1422
ce87a190 1423 output = subprocess.check_output(['ip', 'route', 'show', 'type', 'unreachable'], universal_newlines=True).rstrip()
f5050e48 1424 print(output)
0ef830cf 1425 self.assertRegex(output, 'unreachable 202.54.1.3 proto static')
f5050e48 1426
ce87a190 1427 output = subprocess.check_output(['ip', 'route', 'show', 'type', 'prohibit'], universal_newlines=True).rstrip()
f5050e48 1428 print(output)
0ef830cf 1429 self.assertRegex(output, 'prohibit 202.54.1.4 proto static')
f5050e48 1430
20ca06a6
DA
1431 def test_ip_route_ipv6_src_route(self):
1432 # a dummy device does not make the addresses go through tentative state, so we
1433 # reuse a bond from an earlier test, which does make the addresses go through
1434 # tentative state, and do our test on that
1435 self.copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1436 self.start_networkd()
1437
e39cc445
YW
1438 self.check_link_exists('dummy98')
1439 self.check_link_exists('bond199')
20ca06a6 1440
ce87a190 1441 output = subprocess.check_output(['ip', '-6', 'route', 'list', 'dev', 'bond199'], universal_newlines=True).rstrip()
20ca06a6
DA
1442 print(output)
1443 self.assertRegex(output, 'abcd::/16')
1444 self.assertRegex(output, 'src')
1445 self.assertRegex(output, '2001:1234:56:8f63::2')
1446
1f0e3109
SS
1447 def test_ip_link_mac_address(self):
1448 self.copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
1449 self.start_networkd()
1450
e39cc445 1451 self.check_link_exists('dummy98')
1f0e3109 1452
ce87a190 1453 output = subprocess.check_output(['ip', 'link', 'show', 'dummy98'], universal_newlines=True).rstrip()
1f0e3109
SS
1454 print(output)
1455 self.assertRegex(output, '00:01:02:aa:bb:cc')
1456
1457 def test_ip_link_unmanaged(self):
1458 self.copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
1459 self.start_networkd()
1460
e39cc445 1461 self.check_link_exists('dummy98')
1f0e3109 1462
9c1ae484 1463 output = subprocess.check_output(networkctl_cmd + ['status', 'dummy98'], universal_newlines=True, env=env).rstrip()
1f0e3109
SS
1464 print(output)
1465 self.assertRegex(output, 'unmanaged')
1466
1467 def test_ipv6_address_label(self):
1468 self.copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
1469 self.start_networkd()
1470
e39cc445 1471 self.check_link_exists('dummy98')
1f0e3109 1472
ce87a190 1473 output = subprocess.check_output(['ip', 'addrlabel', 'list'], universal_newlines=True).rstrip()
1f0e3109
SS
1474 print(output)
1475 self.assertRegex(output, '2004:da8:1::/64')
1476
e4a71bf3
WKI
1477 def test_ipv6_neighbor(self):
1478 self.copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
1479 self.start_networkd()
1480
e39cc445 1481 self.check_link_exists('dummy98')
e4a71bf3 1482
ce87a190 1483 output = subprocess.check_output(['ip', 'neigh', 'list'], universal_newlines=True).rstrip()
e4a71bf3
WKI
1484 print(output)
1485 self.assertRegex(output, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
094b5479 1486 self.assertRegex(output, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
e4a71bf3 1487
05514ae1
YW
1488 def test_link_local_addressing(self):
1489 self.copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
1490 '25-link-local-addressing-no.network', '12-dummy.netdev')
2dcfcc08
YW
1491 self.start_networkd(0)
1492 self.wait_online(['test1:degraded', 'dummy98:carrier'])
05514ae1 1493
e39cc445
YW
1494 self.check_link_exists('test1')
1495 self.check_link_exists('dummy98')
05514ae1 1496
ce87a190 1497 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'test1'], universal_newlines=True).rstrip()
05514ae1
YW
1498 print(output)
1499 self.assertRegex(output, 'inet .* scope link')
1500 self.assertRegex(output, 'inet6 .* scope link')
1501
ce87a190 1502 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'dummy98'], universal_newlines=True).rstrip()
05514ae1
YW
1503 print(output)
1504 self.assertNotRegex(output, 'inet6* .* scope link')
1505
791c1140
YW
1506 self.check_operstate('test1', 'degraded')
1507 self.check_operstate('dummy98', 'carrier')
05514ae1
YW
1508
1509 '''
1510 Documentation/networking/ip-sysctl.txt
1511
1512 addr_gen_mode - INTEGER
1513 Defines how link-local and autoconf addresses are generated.
1514
1515 0: generate address based on EUI64 (default)
1516 1: do no generate a link-local address, use EUI64 for addresses generated
1517 from autoconf
1518 2: generate stable privacy addresses, using the secret from
1519 stable_secret (RFC7217)
1520 3: generate stable privacy addresses, using a random secret if unset
1521 '''
1522
1523 test1_addr_gen_mode = ''
1524 if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'stable_secret')):
1525 with open(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'stable_secret')) as f:
1526 try:
1527 f.readline()
1528 except IOError:
1529 # if stable_secret is unset, then EIO is returned
1530 test1_addr_gen_mode = '0'
1531 else:
1532 test1_addr_gen_mode = '2'
1533 else:
1534 test1_addr_gen_mode = '0'
1535
1536 if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'addr_gen_mode')):
d06f30fc 1537 self.assertEqual(self.read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode)
05514ae1
YW
1538
1539 if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'dummy98'), 'addr_gen_mode')):
1540 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
1541
1f0e3109
SS
1542 def test_sysctl(self):
1543 self.copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
ba1e0d06
YW
1544 self.start_networkd(0)
1545 self.wait_online(['dummy98:degraded'])
1f0e3109 1546
1f0e3109
SS
1547 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
1548 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
1549 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
1550 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
1551 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
1552 self.assertEqual(self.read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
1553 self.assertEqual(self.read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
1554
4da33154
YW
1555 def test_sysctl_disable_ipv6(self):
1556 self.copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
1557
1558 print('## Disable ipv6')
1559 self.assertEqual(subprocess.call(['sysctl', 'net.ipv6.conf.all.disable_ipv6=1']), 0)
1560 self.assertEqual(subprocess.call(['sysctl', 'net.ipv6.conf.default.disable_ipv6=1']), 0)
1561
a15ff207
YW
1562 self.start_networkd(0)
1563 self.wait_online(['dummy98:routable'])
4da33154 1564
ce87a190 1565 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dummy98'], universal_newlines=True).rstrip()
4da33154
YW
1566 print(output)
1567 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
ce87a190 1568 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dummy98'], universal_newlines=True).rstrip()
4da33154
YW
1569 print(output)
1570 self.assertEqual(output, '')
791c1140 1571 self.check_operstate('dummy98', 'routable')
4da33154
YW
1572
1573 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1574
1575 print('## Enable ipv6')
1576 self.assertEqual(subprocess.call(['sysctl', 'net.ipv6.conf.all.disable_ipv6=0']), 0)
1577 self.assertEqual(subprocess.call(['sysctl', 'net.ipv6.conf.default.disable_ipv6=0']), 0)
1578
a15ff207
YW
1579 self.start_networkd(0)
1580 self.wait_online(['dummy98:routable'])
4da33154 1581
ce87a190 1582 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dummy98'], universal_newlines=True).rstrip()
4da33154
YW
1583 print(output)
1584 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
ce87a190 1585 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dummy98'], universal_newlines=True).rstrip()
4da33154
YW
1586 print(output)
1587 self.assertRegex(output, 'inet6 .* scope link')
791c1140 1588 self.check_operstate('dummy98', 'routable')
4da33154 1589
cd65d067
YW
1590 def test_bind_carrier(self):
1591 self.copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
1592 self.start_networkd()
1593
e39cc445 1594 self.check_link_exists('test1')
cd65d067 1595
cd65d067
YW
1596 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1597 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
b117044c 1598 time.sleep(2)
ce87a190 1599 output = subprocess.check_output(['ip', 'address', 'show', 'test1'], universal_newlines=True).rstrip()
cd65d067
YW
1600 print(output)
1601 self.assertRegex(output, 'UP,LOWER_UP')
1602 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
791c1140 1603 self.check_operstate('test1', 'routable')
cd65d067
YW
1604
1605 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy99', 'type', 'dummy']), 0)
1606 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy99', 'up']), 0)
b117044c 1607 time.sleep(2)
ce87a190 1608 output = subprocess.check_output(['ip', 'address', 'show', 'test1'], universal_newlines=True).rstrip()
cd65d067
YW
1609 print(output)
1610 self.assertRegex(output, 'UP,LOWER_UP')
1611 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
791c1140 1612 self.check_operstate('test1', 'routable')
cd65d067
YW
1613
1614 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
b117044c 1615 time.sleep(2)
ce87a190 1616 output = subprocess.check_output(['ip', 'address', 'show', 'test1'], universal_newlines=True).rstrip()
cd65d067
YW
1617 print(output)
1618 self.assertRegex(output, 'UP,LOWER_UP')
1619 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
791c1140 1620 self.check_operstate('test1', 'routable')
cd65d067
YW
1621
1622 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy99']), 0)
b117044c 1623 time.sleep(2)
ce87a190 1624 output = subprocess.check_output(['ip', 'address', 'show', 'test1'], universal_newlines=True).rstrip()
cd65d067
YW
1625 print(output)
1626 self.assertNotRegex(output, 'UP,LOWER_UP')
1627 self.assertRegex(output, 'DOWN')
1628 self.assertNotRegex(output, '192.168.10')
791c1140 1629 self.check_operstate('test1', 'off')
cd65d067
YW
1630
1631 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1632 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
b117044c 1633 time.sleep(2)
ce87a190 1634 output = subprocess.check_output(['ip', 'address', 'show', 'test1'], universal_newlines=True).rstrip()
cd65d067
YW
1635 print(output)
1636 self.assertRegex(output, 'UP,LOWER_UP')
1637 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
791c1140 1638 self.check_operstate('test1', 'routable')
cd65d067 1639
fdcd1ec5
YW
1640 def test_domain(self):
1641 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
1642 self.start_networkd(0)
1643 self.wait_online(['dummy98:routable'])
1644
9c1ae484 1645 output = subprocess.check_output(networkctl_cmd + ['status', 'dummy98'], universal_newlines=True, env=env).rstrip()
fdcd1ec5
YW
1646 print(output)
1647 self.assertRegex(output, 'Address: 192.168.42.100')
1648 self.assertRegex(output, 'DNS: 192.168.42.1')
1649 self.assertRegex(output, 'Search Domains: one')
1650
be68c2c9 1651class NetworkdBondTests(unittest.TestCase, Utilities):
c3a8853f 1652 links = [
c2990ec3 1653 'bond199',
c3a8853f 1654 'bond99',
cc3e488c
YW
1655 'dummy98',
1656 'test1']
c3a8853f
YW
1657
1658 units = [
cc3e488c
YW
1659 '11-dummy.netdev',
1660 '12-dummy.netdev',
c2990ec3
YW
1661 '23-active-slave.network',
1662 '23-bond199.network',
1663 '23-primary-slave.network',
1664 '23-test1-bond199.network',
1665 '25-bond-active-backup-slave.netdev',
c3a8853f 1666 '25-bond.netdev',
c3a8853f 1667 'bond99.network',
cc3e488c 1668 'bond-slave.network']
c3a8853f
YW
1669
1670 def setUp(self):
350e05d2 1671 self.remove_links(self.links)
c3a8853f
YW
1672
1673 def tearDown(self):
350e05d2 1674 self.remove_links(self.links)
c3a8853f
YW
1675 self.remove_unit_from_networkd_path(self.units)
1676
c2990ec3
YW
1677 def test_bond_active_slave(self):
1678 self.copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1679 self.start_networkd()
1680
e39cc445
YW
1681 self.check_link_exists('dummy98')
1682 self.check_link_exists('bond199')
c2990ec3 1683
ce87a190 1684 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond199'], universal_newlines=True).rstrip()
c2990ec3
YW
1685 print(output)
1686 self.assertRegex(output, 'active_slave dummy98')
1687
1688 def test_bond_primary_slave(self):
1689 self.copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-test1-bond199.network', '25-bond-active-backup-slave.netdev', '11-dummy.netdev')
1690 self.start_networkd()
1691
e39cc445
YW
1692 self.check_link_exists('test1')
1693 self.check_link_exists('bond199')
c2990ec3 1694
ce87a190 1695 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond199'], universal_newlines=True).rstrip()
c2990ec3
YW
1696 print(output)
1697 self.assertRegex(output, 'primary test1')
1698
cc3e488c
YW
1699 def test_bond_operstate(self):
1700 self.copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
1701 'bond99.network','bond-slave.network')
c3a8853f
YW
1702 self.start_networkd()
1703
e39cc445
YW
1704 self.check_link_exists('bond99')
1705 self.check_link_exists('dummy98')
1706 self.check_link_exists('test1')
c3a8853f 1707
ce87a190 1708 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'dummy98'], universal_newlines=True).rstrip()
c3a8853f 1709 print(output)
cc3e488c 1710 self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
c3a8853f 1711
ce87a190 1712 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1'], universal_newlines=True).rstrip()
c3a8853f
YW
1713 print(output)
1714 self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
1715
ce87a190 1716 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond99'], universal_newlines=True).rstrip()
c3a8853f
YW
1717 print(output)
1718 self.assertRegex(output, 'MASTER,UP,LOWER_UP')
1719
791c1140
YW
1720 self.check_operstate('dummy98', 'enslaved')
1721 self.check_operstate('test1', 'enslaved')
1722 self.check_operstate('bond99', 'routable')
c3a8853f 1723
cc3e488c 1724 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'down']), 0)
c3a8853f
YW
1725 time.sleep(2)
1726
791c1140
YW
1727 self.check_operstate('dummy98', 'off')
1728 self.check_operstate('test1', 'enslaved')
1729 self.check_operstate('bond99', 'degraded-carrier')
c3a8853f 1730
cc3e488c 1731 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
c3a8853f
YW
1732 time.sleep(2)
1733
791c1140
YW
1734 self.check_operstate('dummy98', 'enslaved')
1735 self.check_operstate('test1', 'enslaved')
1736 self.check_operstate('bond99', 'routable')
c3a8853f 1737
cc3e488c
YW
1738 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'down']), 0)
1739 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'test1', 'down']), 0)
2700d2c7 1740 time.sleep(2)
cc3e488c 1741
791c1140
YW
1742 self.check_operstate('dummy98', 'off')
1743 self.check_operstate('test1', 'off')
2700d2c7 1744
2700d2c7
YW
1745 for trial in range(30):
1746 if trial > 0:
1747 time.sleep(1)
1748 output = subprocess.check_output(['ip', 'address', 'show', 'bond99'], universal_newlines=True).rstrip()
1749 print(output)
1750 if self.get_operstate('bond99') == 'no-carrier':
1751 break
1752 else:
1753 # Huh? Kernel does not recognize that all slave interfaces are down?
1754 # Let's confirm that networkd's operstate is consistent with ip's result.
1755 self.assertNotRegex(output, 'NO-CARRIER')
cc3e488c 1756
be68c2c9 1757class NetworkdBridgeTests(unittest.TestCase, Utilities):
09ea6724
YW
1758 links = [
1759 'bridge99',
1760 'dummy98',
1761 'test1']
1762
1763 units = [
1764 '11-dummy.netdev',
1765 '12-dummy.netdev',
1766 '26-bridge.netdev',
1767 '26-bridge-slave-interface-1.network',
1768 '26-bridge-slave-interface-2.network',
804b6cd2 1769 'bridge99-ignore-carrier-loss.network',
09ea6724 1770 'bridge99.network']
1f0e3109
SS
1771
1772 def setUp(self):
350e05d2 1773 self.remove_links(self.links)
1f0e3109
SS
1774
1775 def tearDown(self):
350e05d2 1776 self.remove_links(self.links)
1f0e3109
SS
1777 self.remove_unit_from_networkd_path(self.units)
1778
1779 def test_bridge_property(self):
1780 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1781 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1782 'bridge99.network')
1783 self.start_networkd()
1784
e39cc445
YW
1785 self.check_link_exists('dummy98')
1786 self.check_link_exists('test1')
1787 self.check_link_exists('bridge99')
1f0e3109 1788
ce87a190 1789 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1'], universal_newlines=True).rstrip()
1f0e3109
SS
1790 print(output)
1791 self.assertRegex(output, 'master')
1792 self.assertRegex(output, 'bridge')
1793
ce87a190 1794 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'dummy98'], universal_newlines=True).rstrip()
1f0e3109
SS
1795 print(output)
1796 self.assertRegex(output, 'master')
1797 self.assertRegex(output, 'bridge')
1798
ce87a190 1799 output = subprocess.check_output(['ip', 'addr', 'show', 'bridge99'], universal_newlines=True).rstrip()
1f0e3109 1800 print(output)
2be6c5d2 1801 self.assertRegex(output, '192.168.0.15/24')
1f0e3109 1802
ce87a190 1803 output = subprocess.check_output(['bridge', '-d', 'link', 'show', 'dummy98'], universal_newlines=True).rstrip()
1f0e3109 1804 print(output)
4d7ed14f
SS
1805 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
1806 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
1807 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
7f15b714 1808 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
4d7ed14f 1809 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
7f15b714
TJ
1810 if (os.path.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
1811 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
1812 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
4d7ed14f
SS
1813
1814 # CONFIG_BRIDGE_IGMP_SNOOPING=y
1815 if (os.path.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
1816 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
1f0e3109 1817
791c1140
YW
1818 self.check_operstate('test1', 'enslaved')
1819 self.check_operstate('dummy98', 'enslaved')
1820 self.check_operstate('bridge99', 'routable')
2be6c5d2 1821
804b6cd2
YW
1822 self.assertEqual(subprocess.call(['ip', 'address', 'add', '192.168.0.16/24', 'dev', 'bridge99']), 0)
1823 time.sleep(1)
1824
ce87a190 1825 output = subprocess.check_output(['ip', 'addr', 'show', 'bridge99'], universal_newlines=True).rstrip()
2be6c5d2
YW
1826 print(output)
1827 self.assertRegex(output, '192.168.0.16/24')
1828
791c1140 1829 self.check_operstate('bridge99', 'routable')
2be6c5d2 1830
804b6cd2 1831 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'test1']), 0)
2be6c5d2
YW
1832 time.sleep(3)
1833
791c1140 1834 self.check_operstate('bridge99', 'degraded-carrier')
2be6c5d2 1835
804b6cd2
YW
1836 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1837 time.sleep(3)
1838
791c1140 1839 self.check_operstate('bridge99', 'no-carrier')
2be6c5d2 1840
ce87a190 1841 output = subprocess.check_output(['ip', 'address', 'show', 'bridge99'], universal_newlines=True).rstrip()
804b6cd2
YW
1842 print(output)
1843 self.assertRegex(output, 'NO-CARRIER')
1844 self.assertNotRegex(output, '192.168.0.15/24')
1845 self.assertNotRegex(output, '192.168.0.16/24')
1846
1847 def test_bridge_ignore_carrier_loss(self):
1848 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1849 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1850 'bridge99-ignore-carrier-loss.network')
703bc7a2
YW
1851
1852 subprocess.call(['ip', 'rule', 'del', 'table', '100'])
1853
804b6cd2
YW
1854 self.start_networkd()
1855
e39cc445
YW
1856 self.check_link_exists('dummy98')
1857 self.check_link_exists('test1')
1858 self.check_link_exists('bridge99')
804b6cd2
YW
1859
1860 self.assertEqual(subprocess.call(['ip', 'address', 'add', '192.168.0.16/24', 'dev', 'bridge99']), 0)
1861 time.sleep(1)
1862
1863 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'test1']), 0)
1864 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1865 time.sleep(3)
1866
ce87a190 1867 output = subprocess.check_output(['ip', 'address', 'show', 'bridge99'], universal_newlines=True).rstrip()
804b6cd2
YW
1868 print(output)
1869 self.assertRegex(output, 'NO-CARRIER')
1870 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1871 self.assertRegex(output, 'inet 192.168.0.16/24 scope global secondary bridge99')
1872
6609924c
YW
1873 subprocess.call(['ip', 'rule', 'del', 'table', '100'])
1874
1875 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self):
1876 self.copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
1877 'bridge99-ignore-carrier-loss.network')
703bc7a2
YW
1878
1879 subprocess.call(['ip', 'rule', 'del', 'table', '100'])
1880
6609924c
YW
1881 self.start_networkd()
1882
e39cc445 1883 self.check_link_exists('bridge99')
6609924c
YW
1884
1885 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1886 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1887 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1888
1889 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1890 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1891 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1892
1893 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1894 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1895 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1896
1897 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1898 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1899
be0e1ef9
YW
1900 for trial in range(30):
1901 if trial > 0:
1902 time.sleep(1)
1903 if self.get_operstate('bridge99') == 'routable' and self.get_operstate('dummy98') == 'enslaved':
1904 break
1905 else:
1906 self.assertTrue(False)
6609924c 1907
ce87a190 1908 output = subprocess.check_output(['ip', 'address', 'show', 'bridge99'], universal_newlines=True).rstrip()
6609924c
YW
1909 print(output)
1910 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1911
ce87a190 1912 output = subprocess.check_output(['ip', 'rule', 'list', 'table', '100'], universal_newlines=True).rstrip()
6609924c
YW
1913 print(output)
1914 self.assertEqual(output, '0: from all to 8.8.8.8 lookup 100')
1915
1916 subprocess.call(['ip', 'rule', 'del', 'table', '100'])
1917
be68c2c9 1918class NetworkdLLDPTests(unittest.TestCase, Utilities):
1f0e3109
SS
1919 links = ['veth99']
1920
09ea6724
YW
1921 units = [
1922 '23-emit-lldp.network',
1923 '24-lldp.network',
1924 '25-veth.netdev']
1f0e3109
SS
1925
1926 def setUp(self):
350e05d2 1927 self.remove_links(self.links)
1f0e3109
SS
1928
1929 def tearDown(self):
350e05d2 1930 self.remove_links(self.links)
1f0e3109
SS
1931 self.remove_unit_from_networkd_path(self.units)
1932
1933 def test_lldp(self):
1934 self.copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
8ad82924
YW
1935 self.start_networkd(0)
1936 self.wait_online(['veth99:degraded', 'veth-peer:degraded'])
1f0e3109 1937
9c1ae484 1938 output = subprocess.check_output(networkctl_cmd + ['lldp'], universal_newlines=True, env=env).rstrip()
1f0e3109
SS
1939 print(output)
1940 self.assertRegex(output, 'veth-peer')
1941 self.assertRegex(output, 'veth99')
1942
be68c2c9 1943class NetworkdRATests(unittest.TestCase, Utilities):
1f0e3109
SS
1944 links = ['veth99']
1945
09ea6724
YW
1946 units = [
1947 '25-veth.netdev',
1948 'ipv6-prefix.network',
1949 'ipv6-prefix-veth.network']
1f0e3109
SS
1950
1951 def setUp(self):
350e05d2 1952 self.remove_links(self.links)
1f0e3109
SS
1953
1954 def tearDown(self):
350e05d2 1955 self.remove_links(self.links)
1f0e3109
SS
1956 self.remove_unit_from_networkd_path(self.units)
1957
1958 def test_ipv6_prefix_delegation(self):
1836bedf 1959 self.warn_about_firewalld()
1f0e3109 1960 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
8ad82924
YW
1961 self.start_networkd(0)
1962 self.wait_online(['veth99:routable', 'veth-peer:degraded'])
1f0e3109 1963
9c1ae484 1964 output = subprocess.check_output(networkctl_cmd + ['status', 'veth99'], universal_newlines=True, env=env).rstrip()
1f0e3109
SS
1965 print(output)
1966 self.assertRegex(output, '2002:da8:1:0')
1967
be68c2c9 1968class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
fdcd1ec5 1969 links = ['veth99']
09ea6724
YW
1970
1971 units = [
09ea6724
YW
1972 '25-veth.netdev',
1973 'dhcp-client.network',
1974 'dhcp-client-timezone-router.network',
1975 'dhcp-server.network',
1976 'dhcp-server-timezone-router.network']
1f0e3109
SS
1977
1978 def setUp(self):
350e05d2 1979 self.remove_links(self.links)
1f0e3109
SS
1980
1981 def tearDown(self):
350e05d2 1982 self.remove_links(self.links)
1f0e3109
SS
1983 self.remove_unit_from_networkd_path(self.units)
1984
1985 def test_dhcp_server(self):
1836bedf 1986 self.warn_about_firewalld()
1f0e3109 1987 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
8ad82924
YW
1988 self.start_networkd(0)
1989 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1f0e3109 1990
9c1ae484 1991 output = subprocess.check_output(networkctl_cmd + ['status', 'veth99'], universal_newlines=True, env=env).rstrip()
1f0e3109
SS
1992 print(output)
1993 self.assertRegex(output, '192.168.5.*')
1994 self.assertRegex(output, 'Gateway: 192.168.5.1')
1995 self.assertRegex(output, 'DNS: 192.168.5.1')
1996 self.assertRegex(output, 'NTP: 192.168.5.1')
1997
1f0e3109 1998 def test_emit_router_timezone(self):
1836bedf 1999 self.warn_about_firewalld()
1f0e3109 2000 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
8ad82924
YW
2001 self.start_networkd(0)
2002 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1f0e3109 2003
9c1ae484 2004 output = subprocess.check_output(networkctl_cmd + ['status', 'veth99'], universal_newlines=True, env=env).rstrip()
1f0e3109
SS
2005 print(output)
2006 self.assertRegex(output, 'Gateway: 192.168.5.*')
2007 self.assertRegex(output, '192.168.5.*')
2008 self.assertRegex(output, 'Europe/Berlin')
2009
be68c2c9 2010class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
09ea6724 2011 links = [
18c613dc
YW
2012 'veth99',
2013 'vrf99']
09ea6724
YW
2014
2015 units = [
2016 '25-veth.netdev',
18c613dc
YW
2017 '25-vrf.netdev',
2018 '25-vrf.network',
09ea6724
YW
2019 'dhcp-client-anonymize.network',
2020 'dhcp-client-critical-connection.network',
af3b1498 2021 'dhcp-client-gateway-onlink-implicit.network',
09ea6724
YW
2022 'dhcp-client-ipv4-dhcp-settings.network',
2023 'dhcp-client-ipv4-only-ipv6-disabled.network',
2024 'dhcp-client-ipv4-only.network',
2025 'dhcp-client-ipv6-only.network',
2026 'dhcp-client-ipv6-rapid-commit.network',
2027 'dhcp-client-listen-port.network',
2028 'dhcp-client-route-metric.network',
2029 'dhcp-client-route-table.network',
18c613dc 2030 'dhcp-client-vrf.network',
117a55c7
YW
2031 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
2032 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
3e9d5552 2033 'dhcp-client.network',
09ea6724 2034 'dhcp-server-veth-peer.network',
30d3b54e
YW
2035 'dhcp-v4-server-veth-peer.network',
2036 'static.network']
1f0e3109
SS
2037
2038 def setUp(self):
1f0e3109 2039 self.stop_dnsmasq(dnsmasq_pid_file)
350e05d2 2040 self.remove_links(self.links)
1f0e3109
SS
2041
2042 def tearDown(self):
1f0e3109
SS
2043 self.stop_dnsmasq(dnsmasq_pid_file)
2044 self.remove_lease_file()
2045 self.remove_log_file()
350e05d2 2046 self.remove_links(self.links)
9f10126f 2047 self.remove_unit_from_networkd_path(self.units)
1f0e3109
SS
2048
2049 def test_dhcp_client_ipv6_only(self):
f5d191a9 2050 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
1f0e3109 2051
3a956d38
YW
2052 self.start_networkd(0)
2053 self.wait_online(['veth-peer:carrier'])
1f0e3109 2054 self.start_dnsmasq()
3a956d38 2055 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1f0e3109 2056
9c1ae484 2057 output = subprocess.check_output(networkctl_cmd + ['status', 'veth99'], universal_newlines=True, env=env).rstrip()
1f0e3109
SS
2058 print(output)
2059 self.assertRegex(output, '2600::')
2060 self.assertNotRegex(output, '192.168.5')
2061
3a956d38 2062 # Confirm that ipv6 token is not set in the kernel
ce87a190 2063 output = subprocess.check_output(['ip', 'token', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
3a956d38
YW
2064 print(output)
2065 self.assertRegex(output, 'token :: dev veth99')
2066
1f0e3109 2067 def test_dhcp_client_ipv4_only(self):
f5d191a9 2068 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
1f0e3109 2069
2629df47
YW
2070 self.start_networkd(0)
2071 self.wait_online(['veth-peer:carrier'])
1f0e3109 2072 self.start_dnsmasq()
2629df47 2073 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1f0e3109 2074
9c1ae484 2075 output = subprocess.check_output(networkctl_cmd + ['status', 'veth99'], universal_newlines=True, env=env).rstrip()
1f0e3109
SS
2076 print(output)
2077 self.assertNotRegex(output, '2600::')
2078 self.assertRegex(output, '192.168.5')
2079
2080 def test_dhcp_client_ipv4_ipv6(self):
2081 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
2082 'dhcp-client-ipv4-only.network')
2629df47
YW
2083 self.start_networkd(0)
2084 self.wait_online(['veth-peer:carrier'])
1f0e3109 2085 self.start_dnsmasq()
2629df47
YW
2086 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2087
2088 # link become 'routable' when at least one protocol provide an valid address.
2089 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255', ipv='-4')
2090 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128', ipv='-6')
1f0e3109 2091
9c1ae484 2092 output = subprocess.check_output(networkctl_cmd + ['status', 'veth99'], universal_newlines=True, env=env).rstrip()
1f0e3109
SS
2093 print(output)
2094 self.assertRegex(output, '2600::')
2095 self.assertRegex(output, '192.168.5')
2096
2097 def test_dhcp_client_settings(self):
2098 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
1f0e3109 2099
2629df47
YW
2100 self.start_networkd(0)
2101 self.wait_online(['veth-peer:carrier'])
1f0e3109 2102 self.start_dnsmasq()
2629df47 2103 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1f0e3109 2104
0ae7a66d 2105 print('## ip address show dev veth99')
ce87a190 2106 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
1f0e3109
SS
2107 print(output)
2108 self.assertRegex(output, '12:34:56:78:9a:bc')
2109 self.assertRegex(output, '192.168.5')
2110 self.assertRegex(output, '1492')
2111
0ae7a66d
YW
2112 # issue #8726
2113 print('## ip route show table main dev veth99')
ce87a190 2114 output = subprocess.check_output(['ip', 'route', 'show', 'table', 'main', 'dev', 'veth99'], universal_newlines=True).rstrip()
1f0e3109 2115 print(output)
0ae7a66d 2116 self.assertNotRegex(output, 'proto dhcp')
1f0e3109 2117
0ae7a66d 2118 print('## ip route show table 211 dev veth99')
ce87a190 2119 output = subprocess.check_output(['ip', 'route', 'show', 'table', '211', 'dev', 'veth99'], universal_newlines=True).rstrip()
0ae7a66d
YW
2120 print(output)
2121 self.assertRegex(output, 'default via 192.168.5.1 proto dhcp')
2122 self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
2123 self.assertRegex(output, '192.168.5.1 proto dhcp scope link')
2124
2125 print('## dnsmasq log')
131717cb
YW
2126 self.assertTrue(self.search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
2127 self.assertTrue(self.search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
2128 self.assertTrue(self.search_words_in_dnsmasq_log('client provides name: test-hostname'))
2129 self.assertTrue(self.search_words_in_dnsmasq_log('26:mtu'))
1f0e3109
SS
2130
2131 def test_dhcp6_client_settings_rapidcommit_true(self):
2132 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2629df47
YW
2133 self.start_networkd(0)
2134 self.wait_online(['veth-peer:carrier'])
1f0e3109 2135 self.start_dnsmasq()
2629df47 2136 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1f0e3109 2137
ce87a190 2138 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
1f0e3109
SS
2139 print(output)
2140 self.assertRegex(output, '12:34:56:78:9a:bc')
131717cb 2141 self.assertTrue(self.search_words_in_dnsmasq_log('14:rapid-commit', True))
1f0e3109
SS
2142
2143 def test_dhcp6_client_settings_rapidcommit_false(self):
2144 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
2629df47
YW
2145 self.start_networkd(0)
2146 self.wait_online(['veth-peer:carrier'])
1f0e3109 2147 self.start_dnsmasq()
2629df47 2148 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1f0e3109 2149
ce87a190 2150 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
1f0e3109
SS
2151 print(output)
2152 self.assertRegex(output, '12:34:56:78:9a:bc')
131717cb 2153 self.assertFalse(self.search_words_in_dnsmasq_log('14:rapid-commit', True))
1f0e3109
SS
2154
2155 def test_dhcp_client_settings_anonymize(self):
2156 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
2629df47
YW
2157 self.start_networkd(0)
2158 self.wait_online(['veth-peer:carrier'])
1f0e3109 2159 self.start_dnsmasq()
2629df47 2160 self.wait_online(['veth99:routable', 'veth-peer:routable'])
e40a58b5 2161
131717cb
YW
2162 self.assertFalse(self.search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
2163 self.assertFalse(self.search_words_in_dnsmasq_log('test-hostname'))
2164 self.assertFalse(self.search_words_in_dnsmasq_log('26:mtu'))
1f0e3109
SS
2165
2166 def test_dhcp_client_listen_port(self):
2167 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
2629df47
YW
2168 self.start_networkd(0)
2169 self.wait_online(['veth-peer:carrier'])
b412fce8 2170 self.start_dnsmasq('--dhcp-alternate-port=67,5555')
2629df47
YW
2171 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2172
2173 # link become 'routable' when at least one protocol provide an valid address.
2174 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255', ipv='-4')
2175 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128', ipv='-6')
1f0e3109 2176
ce87a190 2177 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
b412fce8
YW
2178 print(output)
2179 self.assertRegex(output, '192.168.5.* dynamic')
1f0e3109
SS
2180
2181 def test_dhcp_route_table_id(self):
2182 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
2629df47
YW
2183 self.start_networkd(0)
2184 self.wait_online(['veth-peer:carrier'])
e40a58b5 2185 self.start_dnsmasq()
2629df47 2186 self.wait_online(['veth99:routable', 'veth-peer:routable'])
e40a58b5 2187
ce87a190 2188 output = subprocess.check_output(['ip', 'route', 'show', 'table', '12'], universal_newlines=True).rstrip()
1f0e3109 2189 print(output)
1f0e3109
SS
2190 self.assertRegex(output, 'veth99 proto dhcp')
2191 self.assertRegex(output, '192.168.5.1')
2192
2193 def test_dhcp_route_metric(self):
2194 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
2629df47
YW
2195 self.start_networkd(0)
2196 self.wait_online(['veth-peer:carrier'])
e40a58b5 2197 self.start_dnsmasq()
2629df47 2198 self.wait_online(['veth99:routable', 'veth-peer:routable'])
e40a58b5 2199
ce87a190 2200 output = subprocess.check_output(['ip', 'route', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
1f0e3109 2201 print(output)
1f0e3109
SS
2202 self.assertRegex(output, 'metric 24')
2203
2204 def test_dhcp_route_criticalconnection_true(self):
2205 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-critical-connection.network')
2629df47
YW
2206 self.start_networkd(0)
2207 self.wait_online(['veth-peer:carrier'])
e40a58b5 2208 self.start_dnsmasq()
2629df47 2209 self.wait_online(['veth99:routable', 'veth-peer:routable'])
e40a58b5 2210
9c1ae484 2211 output = subprocess.check_output(networkctl_cmd + ['status', 'veth99'], universal_newlines=True, env=env).rstrip()
1f0e3109 2212 print(output)
1f0e3109 2213 self.assertRegex(output, '192.168.5.*')
e40a58b5 2214
5238e957 2215 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
1f0e3109
SS
2216 self.stop_dnsmasq(dnsmasq_pid_file)
2217
2218 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2219 time.sleep(125)
2220
9c1ae484 2221 output = subprocess.check_output(networkctl_cmd + ['status', 'veth99'], universal_newlines=True, env=env).rstrip()
1f0e3109
SS
2222 print(output)
2223 self.assertRegex(output, '192.168.5.*')
2224
30d3b54e
YW
2225 def test_dhcp_client_reuse_address_as_static(self):
2226 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
2629df47
YW
2227 self.start_networkd(0)
2228 self.wait_online(['veth-peer:carrier'])
30d3b54e 2229 self.start_dnsmasq()
2629df47
YW
2230 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2231
2232 # link become 'routable' when at least one protocol provide an valid address.
2233 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255', ipv='-4')
2234 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128', ipv='-6')
30d3b54e 2235
ce87a190 2236 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99', 'scope', 'global'], universal_newlines=True).rstrip()
30d3b54e
YW
2237 print(output)
2238 self.assertRegex(output, '192.168.5')
2239 self.assertRegex(output, '2600::')
2240
2629df47
YW
2241 ipv4_address = re.search(r'192.168.5.[0-9]*/24', output)
2242 ipv6_address = re.search(r'2600::[0-9a-f:]*/128', output)
30d3b54e
YW
2243 static_network = '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address.group(), 'Address=' + ipv6_address.group()])
2244 print(static_network)
2245
2246 self.remove_unit_from_networkd_path(['dhcp-client.network'])
2247
2248 with open(os.path.join(network_unit_file_path, 'static.network'), mode='w') as f:
2249 f.write(static_network)
2250
2629df47
YW
2251 # When networkd started, the links are already configured, so let's wait for 5 seconds
2252 # the links to be re-configured.
2253 self.start_networkd(5)
2254 self.wait_online(['veth99:routable', 'veth-peer:routable'])
30d3b54e 2255
ce87a190 2256 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global'], universal_newlines=True).rstrip()
30d3b54e
YW
2257 print(output)
2258 self.assertRegex(output, '192.168.5')
2259 self.assertRegex(output, 'valid_lft forever preferred_lft forever')
2260
ce87a190 2261 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global'], universal_newlines=True).rstrip()
30d3b54e
YW
2262 print(output)
2263 self.assertRegex(output, '2600::')
2264 self.assertRegex(output, 'valid_lft forever preferred_lft forever')
2265
18c613dc
YW
2266 @expectedFailureIfModuleIsNotAvailable('vrf')
2267 def test_dhcp_client_vrf(self):
2268 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
2269 '25-vrf.netdev', '25-vrf.network')
2629df47
YW
2270 self.start_networkd(0)
2271 self.wait_online(['veth-peer:carrier'])
18c613dc 2272 self.start_dnsmasq()
2629df47
YW
2273 self.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
2274
2275 # link become 'routable' when at least one protocol provide an valid address.
2276 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255', ipv='-4')
2277 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128', ipv='-6')
18c613dc
YW
2278
2279 print('## ip -d link show dev vrf99')
ce87a190 2280 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'dev', 'vrf99'], universal_newlines=True).rstrip()
18c613dc
YW
2281 print(output)
2282 self.assertRegex(output, 'vrf table 42')
2283
2284 print('## ip address show vrf vrf99')
ce87a190 2285 output_ip_vrf = subprocess.check_output(['ip', 'address', 'show', 'vrf', 'vrf99'], universal_newlines=True).rstrip()
18c613dc
YW
2286 print(output_ip_vrf)
2287
2288 print('## ip address show dev veth99')
ce87a190 2289 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
18c613dc
YW
2290 print(output)
2291 self.assertEqual(output, output_ip_vrf)
2292 self.assertRegex(output, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2293 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2294 self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic noprefixroute')
2295 self.assertRegex(output, 'inet6 .* scope link')
2296
2297 print('## ip route show vrf vrf99')
ce87a190 2298 output = subprocess.check_output(['ip', 'route', 'show', 'vrf', 'vrf99'], universal_newlines=True).rstrip()
18c613dc
YW
2299 print(output)
2300 self.assertRegex(output, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
2301 self.assertRegex(output, 'default dev veth99 proto static scope link')
2302 self.assertRegex(output, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
2303 self.assertRegex(output, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
2304 self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
2305 self.assertRegex(output, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
2306
2307 print('## ip route show table main dev veth99')
ce87a190 2308 output = subprocess.check_output(['ip', 'route', 'show', 'table', 'main', 'dev', 'veth99'], universal_newlines=True).rstrip()
18c613dc
YW
2309 print(output)
2310 self.assertEqual(output, '')
2311
791c1140
YW
2312 self.check_operstate('vrf99', 'carrier')
2313 self.check_operstate('veth99', 'routable')
18c613dc 2314
af3b1498
YW
2315 def test_dhcp_client_gateway_onlink_implicit(self):
2316 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2317 'dhcp-client-gateway-onlink-implicit.network')
2629df47
YW
2318 self.start_networkd(0)
2319 self.wait_online(['veth-peer:carrier'])
af3b1498 2320 self.start_dnsmasq()
2629df47 2321 self.wait_online(['veth99:routable', 'veth-peer:routable'])
af3b1498 2322
9c1ae484 2323 output = subprocess.check_output(networkctl_cmd + ['status', 'veth99'], universal_newlines=True, env=env).rstrip()
af3b1498
YW
2324 print(output)
2325 self.assertRegex(output, '192.168.5')
2326
ce87a190 2327 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'veth99', '10.0.0.0/8'], universal_newlines=True).rstrip()
af3b1498
YW
2328 print(output)
2329 self.assertRegex(output, 'onlink')
ce87a190 2330 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'veth99', '192.168.100.0/24'], universal_newlines=True).rstrip()
af3b1498
YW
2331 print(output)
2332 self.assertRegex(output, 'onlink')
2333
117a55c7 2334 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self):
63c598ed 2335 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
117a55c7 2336 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
63c598ed 2337 self.start_networkd(0)
117a55c7 2338 self.wait_online(['veth-peer:carrier'])
63c598ed
YW
2339 self.start_dnsmasq(lease_time='2m')
2340 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2341
ce87a190 2342 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
63c598ed
YW
2343 print(output)
2344
ce87a190 2345 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
63c598ed 2346 self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
ce87a190 2347 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
63c598ed 2348 self.assertRegex(output, 'inet6 .* scope link')
ce87a190 2349 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
63c598ed 2350 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
ce87a190 2351 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
63c598ed
YW
2352 self.assertNotRegex(output, 'inet .* scope link')
2353
2354 print('Wait for the dynamic address to be expired')
2355 time.sleep(130)
2356
ce87a190 2357 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
63c598ed
YW
2358 print(output)
2359
ce87a190 2360 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
63c598ed 2361 self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
ce87a190 2362 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
63c598ed 2363 self.assertRegex(output, 'inet6 .* scope link')
ce87a190 2364 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
63c598ed 2365 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
ce87a190 2366 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
63c598ed
YW
2367 self.assertNotRegex(output, 'inet .* scope link')
2368
2369 self.search_words_in_dnsmasq_log('DHCPOFFER', show_all=True)
2370
117a55c7
YW
2371 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self):
2372 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2373 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
2374 self.start_networkd(0)
2375 self.wait_online(['veth99:degraded', 'veth-peer:routable'])
2376
ce87a190 2377 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
117a55c7
YW
2378 print(output)
2379
ce87a190 2380 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
117a55c7 2381 self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
ce87a190 2382 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
117a55c7 2383 self.assertRegex(output, 'inet6 .* scope link')
ce87a190 2384 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
117a55c7 2385 self.assertNotRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
ce87a190 2386 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
117a55c7
YW
2387 self.assertRegex(output, 'inet .* scope link')
2388
b6efd661
YW
2389 def test_dhcp_client_route_remove_on_renew(self):
2390 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2391 'dhcp-client-ipv4-only-ipv6-disabled.network')
2392 self.start_networkd(0)
2393 self.wait_online(['veth-peer:carrier'])
2394 self.start_dnsmasq(ipv4_range='192.168.5.100,192.168.5.199', lease_time='2m')
2395 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2396
2397 # test for issue #12490
2398
2399 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
2400 print(output)
2401 self.assertRegex(output, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2402 address1=None
2403 for line in output.splitlines():
2404 if 'brd 192.168.5.255 scope global dynamic veth99' in line:
2405 address1 = line.split()[1].split('/')[0]
2406 break
2407
2408 output = subprocess.check_output(['ip', '-4', 'route', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2409 print(output)
2410 self.assertRegex(output, f'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2411 self.assertRegex(output, f'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2412
2413 self.stop_dnsmasq(dnsmasq_pid_file)
2414 self.start_dnsmasq(ipv4_range='192.168.5.200,192.168.5.250', lease_time='2m')
2415
2416 print('Wait for the dynamic address to be expired')
2417 time.sleep(130)
2418
2419 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
2420 print(output)
2421 self.assertRegex(output, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2422 address2=None
2423 for line in output.splitlines():
2424 if 'brd 192.168.5.255 scope global dynamic veth99' in line:
2425 address2 = line.split()[1].split('/')[0]
2426 break
2427
2428 self.assertNotEqual(address1, address2)
2429
2430 output = subprocess.check_output(['ip', '-4', 'route', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2431 print(output)
2432 self.assertNotRegex(output, f'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2433 self.assertNotRegex(output, f'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2434 self.assertRegex(output, f'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
2435 self.assertRegex(output, f'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
2436
1f0e3109 2437if __name__ == '__main__':
9c1ae484
YW
2438 parser = argparse.ArgumentParser()
2439 parser.add_argument('--build-dir', help='Path to build dir', dest='build_dir')
2440 parser.add_argument('--networkd', help='Path to systemd-networkd', dest='networkd_bin')
2441 parser.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest='wait_online_bin')
2442 parser.add_argument('--networkctl', help='Path to networkctl', dest='networkctl_bin')
2443 parser.add_argument('--valgrind', help='Enable valgrind', dest='use_valgrind', type=bool, nargs='?', const=True, default=use_valgrind)
2444 parser.add_argument('--debug', help='Generate debugging logs', dest='enable_debug', type=bool, nargs='?', const=True, default=enable_debug)
94c03122 2445 parser.add_argument('--asan-options', help='ASAN options', dest='asan_options')
fa4c6095 2446 parser.add_argument('--lsan-options', help='LSAN options', dest='lsan_options')
94c03122 2447 parser.add_argument('--ubsan-options', help='UBSAN options', dest='ubsan_options')
9c1ae484
YW
2448 ns, args = parser.parse_known_args(namespace=unittest)
2449
2450 if ns.build_dir:
2451 if ns.networkd_bin or ns.wait_online_bin or ns.networkctl_bin:
2452 print('WARNING: --networkd, --wait-online, or --networkctl options are ignored when --build-dir is specified.')
2453 networkd_bin = os.path.join(ns.build_dir, 'systemd-networkd')
2454 wait_online_bin = os.path.join(ns.build_dir, 'systemd-networkd-wait-online')
2455 networkctl_bin = os.path.join(ns.build_dir, 'networkctl')
2456 else:
2457 if ns.networkd_bin:
2458 networkd_bin = ns.networkd_bin
2459 if ns.wait_online_bin:
2460 wait_online_bin = ns.wait_online_bin
2461 if ns.networkctl_bin:
2462 networkctl_bin = ns.networkctl_bin
2463
2464 use_valgrind = ns.use_valgrind
2465 enable_debug = ns.enable_debug
94c03122 2466 asan_options = ns.asan_options
fa4c6095 2467 lsan_options = ns.lsan_options
94c03122 2468 ubsan_options = ns.ubsan_options
9c1ae484
YW
2469
2470 if use_valgrind:
2471 networkctl_cmd = ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin]
2472 wait_online_cmd = ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin]
2473 else:
2474 networkctl_cmd = [networkctl_bin]
2475 wait_online_cmd = [wait_online_bin]
2476
2477 if enable_debug:
2478 env.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
94c03122
YW
2479 if asan_options:
2480 env.update({ 'ASAN_OPTIONS' : asan_options })
fa4c6095
YW
2481 if lsan_options:
2482 env.update({ 'LSAN_OPTIONS' : lsan_options })
94c03122
YW
2483 if ubsan_options:
2484 env.update({ 'UBSAN_OPTIONS' : ubsan_options })
9c1ae484
YW
2485
2486 sys.argv[1:] = args
1f0e3109
SS
2487 unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout,
2488 verbosity=3))