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