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