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