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