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