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