]> git.ipfire.org Git - thirdparty/systemd.git/blame - test/test-network/systemd-networkd-tests.py
test-network: add test that vcan device can be configured state
[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
YW
1624
1625 bond_has_no_carrier=False
1626 for trial in range(30):
1627 if trial > 0:
1628 time.sleep(1)
1629 output = subprocess.check_output(['ip', 'address', 'show', 'bond99'], universal_newlines=True).rstrip()
1630 print(output)
1631 if self.get_operstate('bond99') == 'no-carrier':
1632 break
1633 else:
1634 # Huh? Kernel does not recognize that all slave interfaces are down?
1635 # Let's confirm that networkd's operstate is consistent with ip's result.
1636 self.assertNotRegex(output, 'NO-CARRIER')
cc3e488c 1637
14dc0335 1638class NetworkdNetWorkBridgeTests(unittest.TestCase, Utilities):
09ea6724
YW
1639 links = [
1640 'bridge99',
1641 'dummy98',
1642 'test1']
1643
1644 units = [
1645 '11-dummy.netdev',
1646 '12-dummy.netdev',
1647 '26-bridge.netdev',
1648 '26-bridge-slave-interface-1.network',
1649 '26-bridge-slave-interface-2.network',
804b6cd2 1650 'bridge99-ignore-carrier-loss.network',
09ea6724 1651 'bridge99.network']
1f0e3109
SS
1652
1653 def setUp(self):
1654 self.link_remove(self.links)
1655
1656 def tearDown(self):
1657 self.link_remove(self.links)
1658 self.remove_unit_from_networkd_path(self.units)
1659
1660 def test_bridge_property(self):
1661 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1662 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1663 'bridge99.network')
1664 self.start_networkd()
1665
e39cc445
YW
1666 self.check_link_exists('dummy98')
1667 self.check_link_exists('test1')
1668 self.check_link_exists('bridge99')
1f0e3109 1669
ce87a190 1670 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1'], universal_newlines=True).rstrip()
1f0e3109
SS
1671 print(output)
1672 self.assertRegex(output, 'master')
1673 self.assertRegex(output, 'bridge')
1674
ce87a190 1675 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'dummy98'], universal_newlines=True).rstrip()
1f0e3109
SS
1676 print(output)
1677 self.assertRegex(output, 'master')
1678 self.assertRegex(output, 'bridge')
1679
ce87a190 1680 output = subprocess.check_output(['ip', 'addr', 'show', 'bridge99'], universal_newlines=True).rstrip()
1f0e3109 1681 print(output)
2be6c5d2 1682 self.assertRegex(output, '192.168.0.15/24')
1f0e3109 1683
ce87a190 1684 output = subprocess.check_output(['bridge', '-d', 'link', 'show', 'dummy98'], universal_newlines=True).rstrip()
1f0e3109 1685 print(output)
4d7ed14f
SS
1686 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
1687 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
1688 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
7f15b714 1689 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
4d7ed14f 1690 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
7f15b714
TJ
1691 if (os.path.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
1692 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
1693 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
4d7ed14f
SS
1694
1695 # CONFIG_BRIDGE_IGMP_SNOOPING=y
1696 if (os.path.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
1697 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
1f0e3109 1698
791c1140
YW
1699 self.check_operstate('test1', 'enslaved')
1700 self.check_operstate('dummy98', 'enslaved')
1701 self.check_operstate('bridge99', 'routable')
2be6c5d2 1702
804b6cd2
YW
1703 self.assertEqual(subprocess.call(['ip', 'address', 'add', '192.168.0.16/24', 'dev', 'bridge99']), 0)
1704 time.sleep(1)
1705
ce87a190 1706 output = subprocess.check_output(['ip', 'addr', 'show', 'bridge99'], universal_newlines=True).rstrip()
2be6c5d2
YW
1707 print(output)
1708 self.assertRegex(output, '192.168.0.16/24')
1709
791c1140 1710 self.check_operstate('bridge99', 'routable')
2be6c5d2 1711
804b6cd2 1712 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'test1']), 0)
2be6c5d2
YW
1713 time.sleep(3)
1714
791c1140 1715 self.check_operstate('bridge99', 'degraded-carrier')
2be6c5d2 1716
804b6cd2
YW
1717 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1718 time.sleep(3)
1719
791c1140 1720 self.check_operstate('bridge99', 'no-carrier')
2be6c5d2 1721
ce87a190 1722 output = subprocess.check_output(['ip', 'address', 'show', 'bridge99'], universal_newlines=True).rstrip()
804b6cd2
YW
1723 print(output)
1724 self.assertRegex(output, 'NO-CARRIER')
1725 self.assertNotRegex(output, '192.168.0.15/24')
1726 self.assertNotRegex(output, '192.168.0.16/24')
1727
1728 def test_bridge_ignore_carrier_loss(self):
1729 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1730 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1731 'bridge99-ignore-carrier-loss.network')
703bc7a2
YW
1732
1733 subprocess.call(['ip', 'rule', 'del', 'table', '100'])
1734
804b6cd2
YW
1735 self.start_networkd()
1736
e39cc445
YW
1737 self.check_link_exists('dummy98')
1738 self.check_link_exists('test1')
1739 self.check_link_exists('bridge99')
804b6cd2
YW
1740
1741 self.assertEqual(subprocess.call(['ip', 'address', 'add', '192.168.0.16/24', 'dev', 'bridge99']), 0)
1742 time.sleep(1)
1743
1744 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'test1']), 0)
1745 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1746 time.sleep(3)
1747
ce87a190 1748 output = subprocess.check_output(['ip', 'address', 'show', 'bridge99'], universal_newlines=True).rstrip()
804b6cd2
YW
1749 print(output)
1750 self.assertRegex(output, 'NO-CARRIER')
1751 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1752 self.assertRegex(output, 'inet 192.168.0.16/24 scope global secondary bridge99')
1753
6609924c
YW
1754 subprocess.call(['ip', 'rule', 'del', 'table', '100'])
1755
1756 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self):
1757 self.copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
1758 'bridge99-ignore-carrier-loss.network')
703bc7a2
YW
1759
1760 subprocess.call(['ip', 'rule', 'del', 'table', '100'])
1761
6609924c
YW
1762 self.start_networkd()
1763
e39cc445 1764 self.check_link_exists('bridge99')
6609924c
YW
1765
1766 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1767 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1768 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1769
1770 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1771 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1772 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1773
1774 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1775 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1776 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1777
1778 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1779 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1780
1781 time.sleep(3)
1782
ce87a190 1783 output = subprocess.check_output(['ip', 'address', 'show', 'bridge99'], universal_newlines=True).rstrip()
6609924c
YW
1784 print(output)
1785 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1786
791c1140
YW
1787 self.check_operstate('bridge99', 'routable')
1788 self.check_operstate('dummy98', 'enslaved')
6609924c 1789
ce87a190 1790 output = subprocess.check_output(['ip', 'rule', 'list', 'table', '100'], universal_newlines=True).rstrip()
6609924c
YW
1791 print(output)
1792 self.assertEqual(output, '0: from all to 8.8.8.8 lookup 100')
1793
1794 subprocess.call(['ip', 'rule', 'del', 'table', '100'])
1795
1f0e3109
SS
1796class NetworkdNetWorkLLDPTests(unittest.TestCase, Utilities):
1797 links = ['veth99']
1798
09ea6724
YW
1799 units = [
1800 '23-emit-lldp.network',
1801 '24-lldp.network',
1802 '25-veth.netdev']
1f0e3109
SS
1803
1804 def setUp(self):
1805 self.link_remove(self.links)
1806
1807 def tearDown(self):
1808 self.link_remove(self.links)
1809 self.remove_unit_from_networkd_path(self.units)
1810
1811 def test_lldp(self):
1812 self.copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
1813 self.start_networkd()
1814
e39cc445 1815 self.check_link_exists('veth99')
1f0e3109 1816
ce87a190 1817 output = subprocess.check_output(['networkctl', 'lldp'], universal_newlines=True).rstrip()
1f0e3109
SS
1818 print(output)
1819 self.assertRegex(output, 'veth-peer')
1820 self.assertRegex(output, 'veth99')
1821
1822class NetworkdNetworkRATests(unittest.TestCase, Utilities):
1823 links = ['veth99']
1824
09ea6724
YW
1825 units = [
1826 '25-veth.netdev',
1827 'ipv6-prefix.network',
1828 'ipv6-prefix-veth.network']
1f0e3109
SS
1829
1830 def setUp(self):
1831 self.link_remove(self.links)
1832
1833 def tearDown(self):
1834 self.link_remove(self.links)
1835 self.remove_unit_from_networkd_path(self.units)
1836
1837 def test_ipv6_prefix_delegation(self):
1838 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
1839 self.start_networkd()
1840
e39cc445 1841 self.check_link_exists('veth99')
1f0e3109 1842
ce87a190 1843 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1f0e3109
SS
1844 print(output)
1845 self.assertRegex(output, '2002:da8:1:0')
1846
1847class NetworkdNetworkDHCPServerTests(unittest.TestCase, Utilities):
09ea6724
YW
1848 links = [
1849 'dummy98',
1850 'veth99']
1851
1852 units = [
1853 '12-dummy.netdev',
1854 '24-search-domain.network',
1855 '25-veth.netdev',
1856 'dhcp-client.network',
1857 'dhcp-client-timezone-router.network',
1858 'dhcp-server.network',
1859 'dhcp-server-timezone-router.network']
1f0e3109
SS
1860
1861 def setUp(self):
1862 self.link_remove(self.links)
1863
1864 def tearDown(self):
1865 self.link_remove(self.links)
1866 self.remove_unit_from_networkd_path(self.units)
1867
1868 def test_dhcp_server(self):
1869 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
1870 self.start_networkd()
1871
e39cc445 1872 self.check_link_exists('veth99')
1f0e3109 1873
ce87a190 1874 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1f0e3109
SS
1875 print(output)
1876 self.assertRegex(output, '192.168.5.*')
1877 self.assertRegex(output, 'Gateway: 192.168.5.1')
1878 self.assertRegex(output, 'DNS: 192.168.5.1')
1879 self.assertRegex(output, 'NTP: 192.168.5.1')
1880
1881 def test_domain(self):
f5d191a9 1882 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
1f0e3109
SS
1883 self.start_networkd()
1884
e39cc445 1885 self.check_link_exists('dummy98')
1f0e3109 1886
ce87a190 1887 output = subprocess.check_output(['networkctl', 'status', 'dummy98'], universal_newlines=True).rstrip()
1f0e3109
SS
1888 print(output)
1889 self.assertRegex(output, 'Address: 192.168.42.100')
1890 self.assertRegex(output, 'DNS: 192.168.42.1')
1891 self.assertRegex(output, 'Search Domains: one')
1892
1893 def test_emit_router_timezone(self):
1894 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
1895 self.start_networkd()
1896
e39cc445 1897 self.check_link_exists('veth99')
1f0e3109 1898
ce87a190 1899 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1f0e3109
SS
1900 print(output)
1901 self.assertRegex(output, 'Gateway: 192.168.5.*')
1902 self.assertRegex(output, '192.168.5.*')
1903 self.assertRegex(output, 'Europe/Berlin')
1904
1905class NetworkdNetworkDHCPClientTests(unittest.TestCase, Utilities):
09ea6724
YW
1906 links = [
1907 'dummy98',
18c613dc
YW
1908 'veth99',
1909 'vrf99']
09ea6724
YW
1910
1911 units = [
1912 '25-veth.netdev',
18c613dc
YW
1913 '25-vrf.netdev',
1914 '25-vrf.network',
09ea6724
YW
1915 'dhcp-client-anonymize.network',
1916 'dhcp-client-critical-connection.network',
af3b1498 1917 'dhcp-client-gateway-onlink-implicit.network',
09ea6724
YW
1918 'dhcp-client-ipv4-dhcp-settings.network',
1919 'dhcp-client-ipv4-only-ipv6-disabled.network',
1920 'dhcp-client-ipv4-only.network',
1921 'dhcp-client-ipv6-only.network',
1922 'dhcp-client-ipv6-rapid-commit.network',
1923 'dhcp-client-listen-port.network',
1924 'dhcp-client-route-metric.network',
1925 'dhcp-client-route-table.network',
18c613dc 1926 'dhcp-client-vrf.network',
117a55c7
YW
1927 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
1928 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
3e9d5552 1929 'dhcp-client.network',
09ea6724 1930 'dhcp-server-veth-peer.network',
30d3b54e
YW
1931 'dhcp-v4-server-veth-peer.network',
1932 'static.network']
1f0e3109
SS
1933
1934 def setUp(self):
1935 self.link_remove(self.links)
1936 self.stop_dnsmasq(dnsmasq_pid_file)
1937
1938 def tearDown(self):
1939 self.link_remove(self.links)
1940 self.remove_unit_from_networkd_path(self.units)
1941 self.stop_dnsmasq(dnsmasq_pid_file)
1942 self.remove_lease_file()
1943 self.remove_log_file()
1944
1945 def test_dhcp_client_ipv6_only(self):
f5d191a9 1946 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
1f0e3109 1947
3a956d38
YW
1948 self.start_networkd(0)
1949 self.wait_online(['veth-peer:carrier'])
1f0e3109 1950 self.start_dnsmasq()
3a956d38 1951 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1f0e3109 1952
ce87a190 1953 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1f0e3109
SS
1954 print(output)
1955 self.assertRegex(output, '2600::')
1956 self.assertNotRegex(output, '192.168.5')
1957
3a956d38 1958 # Confirm that ipv6 token is not set in the kernel
ce87a190 1959 output = subprocess.check_output(['ip', 'token', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
3a956d38
YW
1960 print(output)
1961 self.assertRegex(output, 'token :: dev veth99')
1962
1f0e3109 1963 def test_dhcp_client_ipv4_only(self):
f5d191a9 1964 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
1f0e3109
SS
1965 self.start_networkd()
1966
e39cc445 1967 self.check_link_exists('veth99')
1f0e3109
SS
1968
1969 self.start_dnsmasq()
1970
ce87a190 1971 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1f0e3109
SS
1972 print(output)
1973 self.assertNotRegex(output, '2600::')
1974 self.assertRegex(output, '192.168.5')
1975
1976 def test_dhcp_client_ipv4_ipv6(self):
1977 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
1978 'dhcp-client-ipv4-only.network')
1979 self.start_networkd()
1980
e39cc445 1981 self.check_link_exists('veth99')
1f0e3109
SS
1982
1983 self.start_dnsmasq()
1984
ce87a190 1985 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1f0e3109
SS
1986 print(output)
1987 self.assertRegex(output, '2600::')
1988 self.assertRegex(output, '192.168.5')
1989
1990 def test_dhcp_client_settings(self):
1991 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
1992 self.start_networkd()
1993
e39cc445 1994 self.check_link_exists('veth99')
1f0e3109
SS
1995
1996 self.start_dnsmasq()
1997
0ae7a66d 1998 print('## ip address show dev veth99')
ce87a190 1999 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
1f0e3109
SS
2000 print(output)
2001 self.assertRegex(output, '12:34:56:78:9a:bc')
2002 self.assertRegex(output, '192.168.5')
2003 self.assertRegex(output, '1492')
2004
0ae7a66d
YW
2005 # issue #8726
2006 print('## ip route show table main dev veth99')
ce87a190 2007 output = subprocess.check_output(['ip', 'route', 'show', 'table', 'main', 'dev', 'veth99'], universal_newlines=True).rstrip()
1f0e3109 2008 print(output)
0ae7a66d 2009 self.assertNotRegex(output, 'proto dhcp')
1f0e3109 2010
0ae7a66d 2011 print('## ip route show table 211 dev veth99')
ce87a190 2012 output = subprocess.check_output(['ip', 'route', 'show', 'table', '211', 'dev', 'veth99'], universal_newlines=True).rstrip()
0ae7a66d
YW
2013 print(output)
2014 self.assertRegex(output, 'default via 192.168.5.1 proto dhcp')
2015 self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
2016 self.assertRegex(output, '192.168.5.1 proto dhcp scope link')
2017
2018 print('## dnsmasq log')
131717cb
YW
2019 self.assertTrue(self.search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
2020 self.assertTrue(self.search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
2021 self.assertTrue(self.search_words_in_dnsmasq_log('client provides name: test-hostname'))
2022 self.assertTrue(self.search_words_in_dnsmasq_log('26:mtu'))
1f0e3109
SS
2023
2024 def test_dhcp6_client_settings_rapidcommit_true(self):
2025 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2026 self.start_networkd()
2027
e39cc445 2028 self.check_link_exists('veth99')
1f0e3109
SS
2029
2030 self.start_dnsmasq()
2031
ce87a190 2032 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
1f0e3109
SS
2033 print(output)
2034 self.assertRegex(output, '12:34:56:78:9a:bc')
131717cb 2035 self.assertTrue(self.search_words_in_dnsmasq_log('14:rapid-commit', True))
1f0e3109
SS
2036
2037 def test_dhcp6_client_settings_rapidcommit_false(self):
2038 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
2039 self.start_networkd()
2040
e39cc445 2041 self.check_link_exists('veth99')
1f0e3109
SS
2042
2043 self.start_dnsmasq()
2044
ce87a190 2045 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
1f0e3109
SS
2046 print(output)
2047 self.assertRegex(output, '12:34:56:78:9a:bc')
131717cb 2048 self.assertFalse(self.search_words_in_dnsmasq_log('14:rapid-commit', True))
1f0e3109
SS
2049
2050 def test_dhcp_client_settings_anonymize(self):
2051 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
2052 self.start_networkd()
2053
e39cc445 2054 self.check_link_exists('veth99')
1f0e3109
SS
2055
2056 self.start_dnsmasq()
e40a58b5 2057
131717cb
YW
2058 self.assertFalse(self.search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
2059 self.assertFalse(self.search_words_in_dnsmasq_log('test-hostname'))
2060 self.assertFalse(self.search_words_in_dnsmasq_log('26:mtu'))
1f0e3109
SS
2061
2062 def test_dhcp_client_listen_port(self):
2063 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
1f0e3109
SS
2064 self.start_networkd()
2065
e39cc445 2066 self.check_link_exists('veth99')
1f0e3109 2067
b412fce8 2068 self.start_dnsmasq('--dhcp-alternate-port=67,5555')
1f0e3109 2069
ce87a190 2070 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
b412fce8
YW
2071 print(output)
2072 self.assertRegex(output, '192.168.5.* dynamic')
1f0e3109
SS
2073
2074 def test_dhcp_route_table_id(self):
2075 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
2076 self.start_networkd()
1f0e3109 2077
e39cc445 2078 self.check_link_exists('veth99')
1f0e3109 2079
e40a58b5
YW
2080 self.start_dnsmasq()
2081
ce87a190 2082 output = subprocess.check_output(['ip', 'route', 'show', 'table', '12'], universal_newlines=True).rstrip()
1f0e3109 2083 print(output)
1f0e3109
SS
2084 self.assertRegex(output, 'veth99 proto dhcp')
2085 self.assertRegex(output, '192.168.5.1')
2086
2087 def test_dhcp_route_metric(self):
2088 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
2089 self.start_networkd()
1f0e3109 2090
e39cc445 2091 self.check_link_exists('veth99')
1f0e3109 2092
e40a58b5
YW
2093 self.start_dnsmasq()
2094
ce87a190 2095 output = subprocess.check_output(['ip', 'route', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
1f0e3109 2096 print(output)
1f0e3109
SS
2097 self.assertRegex(output, 'metric 24')
2098
2099 def test_dhcp_route_criticalconnection_true(self):
2100 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-critical-connection.network')
2101 self.start_networkd()
1f0e3109 2102
e39cc445 2103 self.check_link_exists('veth99')
1f0e3109 2104
e40a58b5
YW
2105 self.start_dnsmasq()
2106
ce87a190 2107 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1f0e3109 2108 print(output)
1f0e3109 2109 self.assertRegex(output, '192.168.5.*')
e40a58b5 2110
5238e957 2111 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
1f0e3109
SS
2112 self.stop_dnsmasq(dnsmasq_pid_file)
2113
2114 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2115 time.sleep(125)
2116
ce87a190 2117 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1f0e3109
SS
2118 print(output)
2119 self.assertRegex(output, '192.168.5.*')
2120
30d3b54e
YW
2121 def test_dhcp_client_reuse_address_as_static(self):
2122 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
2123 self.start_networkd()
2124
e39cc445 2125 self.check_link_exists('veth99')
30d3b54e
YW
2126
2127 self.start_dnsmasq()
2128
ce87a190 2129 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99', 'scope', 'global'], universal_newlines=True).rstrip()
30d3b54e
YW
2130 print(output)
2131 self.assertRegex(output, '192.168.5')
2132 self.assertRegex(output, '2600::')
2133
2134 ipv4_address = re.search('192\.168\.5\.[0-9]*/24', output)
2135 ipv6_address = re.search('2600::[0-9a-f:]*/128', output)
2136 static_network = '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address.group(), 'Address=' + ipv6_address.group()])
2137 print(static_network)
2138
2139 self.remove_unit_from_networkd_path(['dhcp-client.network'])
2140
2141 with open(os.path.join(network_unit_file_path, 'static.network'), mode='w') as f:
2142 f.write(static_network)
2143
2144 self.start_networkd()
2145
e39cc445 2146 self.check_link_exists('veth99')
30d3b54e 2147
ce87a190 2148 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global'], universal_newlines=True).rstrip()
30d3b54e
YW
2149 print(output)
2150 self.assertRegex(output, '192.168.5')
2151 self.assertRegex(output, 'valid_lft forever preferred_lft forever')
2152
ce87a190 2153 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global'], universal_newlines=True).rstrip()
30d3b54e
YW
2154 print(output)
2155 self.assertRegex(output, '2600::')
2156 self.assertRegex(output, 'valid_lft forever preferred_lft forever')
2157
18c613dc
YW
2158 @expectedFailureIfModuleIsNotAvailable('vrf')
2159 def test_dhcp_client_vrf(self):
2160 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
2161 '25-vrf.netdev', '25-vrf.network')
2162 self.start_networkd()
2163
e39cc445
YW
2164 self.check_link_exists('veth99')
2165 self.check_link_exists('vrf99')
18c613dc
YW
2166
2167 self.start_dnsmasq()
2168
2169 print('## ip -d link show dev vrf99')
ce87a190 2170 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'dev', 'vrf99'], universal_newlines=True).rstrip()
18c613dc
YW
2171 print(output)
2172 self.assertRegex(output, 'vrf table 42')
2173
2174 print('## ip address show vrf vrf99')
ce87a190 2175 output_ip_vrf = subprocess.check_output(['ip', 'address', 'show', 'vrf', 'vrf99'], universal_newlines=True).rstrip()
18c613dc
YW
2176 print(output_ip_vrf)
2177
2178 print('## ip address show dev veth99')
ce87a190 2179 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
18c613dc
YW
2180 print(output)
2181 self.assertEqual(output, output_ip_vrf)
2182 self.assertRegex(output, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2183 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2184 self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic noprefixroute')
2185 self.assertRegex(output, 'inet6 .* scope link')
2186
2187 print('## ip route show vrf vrf99')
ce87a190 2188 output = subprocess.check_output(['ip', 'route', 'show', 'vrf', 'vrf99'], universal_newlines=True).rstrip()
18c613dc
YW
2189 print(output)
2190 self.assertRegex(output, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
2191 self.assertRegex(output, 'default dev veth99 proto static scope link')
2192 self.assertRegex(output, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
2193 self.assertRegex(output, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
2194 self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
2195 self.assertRegex(output, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
2196
2197 print('## ip route show table main dev veth99')
ce87a190 2198 output = subprocess.check_output(['ip', 'route', 'show', 'table', 'main', 'dev', 'veth99'], universal_newlines=True).rstrip()
18c613dc
YW
2199 print(output)
2200 self.assertEqual(output, '')
2201
791c1140
YW
2202 self.check_operstate('vrf99', 'carrier')
2203 self.check_operstate('veth99', 'routable')
18c613dc 2204
af3b1498
YW
2205 def test_dhcp_client_gateway_onlink_implicit(self):
2206 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2207 'dhcp-client-gateway-onlink-implicit.network')
2208 self.start_networkd()
2209
e39cc445 2210 self.check_link_exists('veth99')
af3b1498
YW
2211
2212 self.start_dnsmasq()
2213
ce87a190 2214 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
af3b1498
YW
2215 print(output)
2216 self.assertRegex(output, '192.168.5')
2217
ce87a190 2218 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'veth99', '10.0.0.0/8'], universal_newlines=True).rstrip()
af3b1498
YW
2219 print(output)
2220 self.assertRegex(output, 'onlink')
ce87a190 2221 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'veth99', '192.168.100.0/24'], universal_newlines=True).rstrip()
af3b1498
YW
2222 print(output)
2223 self.assertRegex(output, 'onlink')
2224
117a55c7 2225 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self):
63c598ed 2226 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
117a55c7 2227 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
63c598ed 2228 self.start_networkd(0)
117a55c7 2229 self.wait_online(['veth-peer:carrier'])
63c598ed
YW
2230 self.start_dnsmasq(lease_time='2m')
2231 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2232
ce87a190 2233 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
63c598ed
YW
2234 print(output)
2235
ce87a190 2236 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
63c598ed 2237 self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
ce87a190 2238 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
63c598ed 2239 self.assertRegex(output, 'inet6 .* scope link')
ce87a190 2240 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
63c598ed 2241 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
ce87a190 2242 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
63c598ed
YW
2243 self.assertNotRegex(output, 'inet .* scope link')
2244
2245 print('Wait for the dynamic address to be expired')
2246 time.sleep(130)
2247
ce87a190 2248 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
63c598ed
YW
2249 print(output)
2250
ce87a190 2251 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
63c598ed 2252 self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
ce87a190 2253 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
63c598ed 2254 self.assertRegex(output, 'inet6 .* scope link')
ce87a190 2255 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
63c598ed 2256 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
ce87a190 2257 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
63c598ed
YW
2258 self.assertNotRegex(output, 'inet .* scope link')
2259
2260 self.search_words_in_dnsmasq_log('DHCPOFFER', show_all=True)
2261
117a55c7
YW
2262 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self):
2263 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2264 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
2265 self.start_networkd(0)
2266 self.wait_online(['veth99:degraded', 'veth-peer:routable'])
2267
ce87a190 2268 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
117a55c7
YW
2269 print(output)
2270
ce87a190 2271 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
117a55c7 2272 self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
ce87a190 2273 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
117a55c7 2274 self.assertRegex(output, 'inet6 .* scope link')
ce87a190 2275 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
117a55c7 2276 self.assertNotRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
ce87a190 2277 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
117a55c7
YW
2278 self.assertRegex(output, 'inet .* scope link')
2279
1f0e3109
SS
2280if __name__ == '__main__':
2281 unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout,
2282 verbosity=3))