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