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