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