]> git.ipfire.org Git - thirdparty/systemd.git/blame - test/test-network/systemd-networkd-tests.py
network: always drop configs when corresponding network file does not exist
[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
7a0a37b2 25def is_module_available(module_name):
201bf07f
EV
26 lsmod_output = subprocess.check_output('lsmod', universal_newlines=True)
27 module_re = re.compile(r'^{0}\b'.format(re.escape(module_name)), re.MULTILINE)
28 return module_re.search(lsmod_output) or not subprocess.call(["modprobe", module_name])
7a0a37b2
EV
29
30def expectedFailureIfModuleIsNotAvailable(module_name):
31 def f(func):
32 if not is_module_available(module_name):
33 return unittest.expectedFailure(func)
34 return func
35
36 return f
37
7bea7f9b
SS
38def expectedFailureIfERSPANModuleIsNotAvailable():
39 def f(func):
40 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'])
41 if rc == 0:
42 subprocess.call(['ip', 'link', 'del', 'erspan99'])
43 return func
44 else:
45 return unittest.expectedFailure(func)
46
47 return f
48
d586a2c3
YW
49def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable():
50 def f(func):
51 rc = subprocess.call(['ip', 'rule', 'add', 'from', '192.168.100.19', 'sport', '1123-1150', 'dport', '3224-3290', 'table', '7'])
52 if rc == 0:
53 subprocess.call(['ip', 'rule', 'del', 'from', '192.168.100.19', 'sport', '1123-1150', 'dport', '3224-3290', 'table', '7'])
54 return func
55 else:
56 return unittest.expectedFailure(func)
57
58 return f
59
60def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
61 def f(func):
62 rc = subprocess.call(['ip', 'rule', 'add', 'not', 'from', '192.168.100.19', 'ipproto', 'tcp', 'table', '7'])
63 if rc == 0:
64 subprocess.call(['ip', 'rule', 'del', 'not', 'from', '192.168.100.19', 'ipproto', 'tcp', 'table', '7'])
65 return func
66 else:
67 return unittest.expectedFailure(func)
68
69 return f
70
1f0e3109
SS
71def setUpModule():
72
73 os.makedirs(network_unit_file_path, exist_ok=True)
74 os.makedirs(networkd_ci_path, exist_ok=True)
75
76 shutil.rmtree(networkd_ci_path)
6aea9276 77 copytree(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'conf'), networkd_ci_path)
1f0e3109 78
c0bf6733
YW
79 subprocess.check_call('systemctl stop systemd-networkd.socket', shell=True)
80
1f0e3109
SS
81def tearDownModule():
82 shutil.rmtree(networkd_ci_path)
83
c0bf6733
YW
84 subprocess.check_call('systemctl stop systemd-networkd.service', shell=True)
85 subprocess.check_call('systemctl start systemd-networkd.socket', shell=True)
86 subprocess.check_call('systemctl start systemd-networkd.service', shell=True)
87
1f0e3109
SS
88class Utilities():
89 dhcp_server_data = []
90
91 def read_link_attr(self, link, dev, attribute):
92 with open(os.path.join(os.path.join(os.path.join('/sys/class/net/', link), dev), attribute)) as f:
93 return f.readline().strip()
94
4d7ed14f
SS
95 def read_bridge_port_attr(self, bridge, link, attribute):
96
97 path_bridge = os.path.join('/sys/devices/virtual/net', bridge)
98 path_port = 'lower_' + link + '/brport'
99 path = os.path.join(path_bridge, path_port)
100
101 with open(os.path.join(path, attribute)) as f:
102 return f.readline().strip()
103
1f0e3109
SS
104 def link_exits(self, link):
105 return os.path.exists(os.path.join('/sys/class/net', link))
106
107 def link_remove(self, links):
108 for link in links:
109 if os.path.exists(os.path.join('/sys/class/net', link)):
110 subprocess.call(['ip', 'link', 'del', 'dev', link])
9a4720a9 111 time.sleep(1)
1f0e3109
SS
112
113 def read_ipv6_sysctl_attr(self, link, attribute):
114 with open(os.path.join(os.path.join(network_sysctl_ipv6_path, link), attribute)) as f:
115 return f.readline().strip()
116
117 def read_ipv4_sysctl_attr(self, link, attribute):
118 with open(os.path.join(os.path.join(network_sysctl_ipv4_path, link), attribute)) as f:
119 return f.readline().strip()
120
121 def copy_unit_to_networkd_unit_path(self, *units):
122 for unit in units:
123 shutil.copy(os.path.join(networkd_ci_path, unit), network_unit_file_path)
013c8dc9
YW
124 if (os.path.exists(os.path.join(networkd_ci_path, unit + '.d'))):
125 copytree(os.path.join(networkd_ci_path, unit + '.d'), os.path.join(network_unit_file_path, unit + '.d'))
1f0e3109
SS
126
127 def remove_unit_from_networkd_path(self, units):
128 for unit in units:
129 if (os.path.exists(os.path.join(network_unit_file_path, unit))):
130 os.remove(os.path.join(network_unit_file_path, unit))
013c8dc9
YW
131 if (os.path.exists(os.path.join(network_unit_file_path, unit + '.d'))):
132 shutil.rmtree(os.path.join(network_unit_file_path, unit + '.d'))
1f0e3109 133
b412fce8
YW
134 def start_dnsmasq(self, additional_options=''):
135 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
136 subprocess.check_call(dnsmasq_command, shell=True)
1f0e3109
SS
137
138 time.sleep(10)
139
140 def stop_dnsmasq(self, pid_file):
141 if os.path.exists(pid_file):
142 with open(pid_file, 'r') as f:
143 pid = f.read().rstrip(' \t\r\n\0')
144 os.kill(int(pid), signal.SIGTERM)
145
146 os.remove(pid_file)
147
131717cb 148 def search_words_in_dnsmasq_log(self, words, show_all=False):
1f0e3109
SS
149 if os.path.exists(dnsmasq_log_file):
150 with open (dnsmasq_log_file) as in_file:
151 contents = in_file.read()
131717cb
YW
152 if show_all:
153 print(contents)
154 for line in contents.split('\n'):
155 if words in line:
1f0e3109 156 in_file.close()
131717cb 157 print("%s, %s" % (words, line))
1f0e3109
SS
158 return True
159 return False
160
161 def remove_lease_file(self):
162 if os.path.exists(os.path.join(networkd_ci_path, 'lease')):
163 os.remove(os.path.join(networkd_ci_path, 'lease'))
164
165 def remove_log_file(self):
166 if os.path.exists(dnsmasq_log_file):
167 os.remove(dnsmasq_log_file)
168
169 def start_networkd(self):
bad4969b
YW
170 if (os.path.exists(os.path.join(networkd_runtime_directory, 'state'))):
171 subprocess.check_call('systemctl stop systemd-networkd', shell=True)
172 os.remove(os.path.join(networkd_runtime_directory, 'state'))
173 subprocess.check_call('systemctl start systemd-networkd', shell=True)
174 else:
175 subprocess.check_call('systemctl restart systemd-networkd', shell=True)
1f0e3109 176 time.sleep(5)
fa7cd602 177 print()
1f0e3109 178
1f0e3109
SS
179class NetworkdNetDevTests(unittest.TestCase, Utilities):
180
09ea6724
YW
181 links =[
182 '6rdtun99',
183 'bond99',
184 'bridge99',
185 'dropin-test',
186 'dummy98',
187 'erspan-test',
188 'geneve99',
189 'gretap99',
190 'gretun99',
191 'ip6gretap99',
192 'ip6tnl99',
193 'ipiptun99',
194 'ipvlan99',
195 'isataptun99',
196 'macvlan99',
197 'macvtap99',
198 'sittun99',
199 'tap99',
200 'test1',
201 'tun99',
202 'vcan99',
203 'veth99',
204 'vlan99',
205 'vrf99',
206 'vti6tun99',
207 'vtitun99',
208 'vxlan99',
da44fb8a 209 'wg98',
09ea6724
YW
210 'wg99']
211
212 units = [
213 '10-dropin-test.netdev',
214 '11-dummy.netdev',
215 '12-dummy.netdev',
216 '21-macvlan.netdev',
217 '21-macvtap.netdev',
218 '21-vlan.netdev',
219 '21-vlan.network',
220 '25-6rd-tunnel.netdev',
221 '25-bond.netdev',
fde60a42 222 '25-bond-balanced-tlb.netdev',
09ea6724
YW
223 '25-bridge.netdev',
224 '25-erspan-tunnel.netdev',
225 '25-geneve.netdev',
226 '25-gretap-tunnel.netdev',
227 '25-gre-tunnel.netdev',
228 '25-ip6gre-tunnel.netdev',
229 '25-ip6tnl-tunnel.netdev',
230 '25-ipip-tunnel-independent.netdev',
231 '25-ipip-tunnel.netdev',
232 '25-ipvlan.netdev',
233 '25-isatap-tunnel.netdev',
234 '25-sit-tunnel.netdev',
235 '25-tap.netdev',
236 '25-tun.netdev',
237 '25-vcan.netdev',
238 '25-veth.netdev',
239 '25-vrf.netdev',
240 '25-vti6-tunnel.netdev',
241 '25-vti-tunnel.netdev',
242 '25-vxlan.netdev',
da44fb8a
YW
243 '25-wireguard-23-peers.netdev',
244 '25-wireguard-23-peers.network',
09ea6724
YW
245 '25-wireguard.netdev',
246 '6rd.network',
247 'gre.network',
248 'gretap.network',
249 'gretun.network',
250 'ip6gretap.network',
251 'ip6tnl.network',
252 'ipip.network',
253 'ipvlan.network',
254 'isatap.network',
255 'macvlan.network',
256 'macvtap.network',
257 'sit.network',
258 'vti6.network',
259 'vti.network',
260 'vxlan.network']
1f0e3109
SS
261
262 def setUp(self):
263 self.link_remove(self.links)
264
265 def tearDown(self):
266 self.link_remove(self.links)
267 self.remove_unit_from_networkd_path(self.units)
268
d80734f7
YW
269 def test_dropin(self):
270 self.copy_unit_to_networkd_unit_path('10-dropin-test.netdev')
d80734f7
YW
271 self.start_networkd()
272
273 self.assertTrue(self.link_exits('dropin-test'))
274
275 output = subprocess.check_output(['ip', 'link', 'show', 'dropin-test']).rstrip().decode('utf-8')
276 print(output)
277 self.assertRegex(output, '00:50:56:c0:00:28')
278
308ae89c
YW
279 output = subprocess.check_output(['networkctl', 'list']).rstrip().decode('utf-8')
280 self.assertRegex(output, '1 lo ')
281 self.assertRegex(output, 'dropin-test')
282
283 output = subprocess.check_output(['networkctl', 'list', 'dropin-test']).rstrip().decode('utf-8')
284 self.assertNotRegex(output, '1 lo ')
285 self.assertRegex(output, 'dropin-test')
286
287 output = subprocess.check_output(['networkctl', 'list', 'dropin-*']).rstrip().decode('utf-8')
288 self.assertNotRegex(output, '1 lo ')
289 self.assertRegex(output, 'dropin-test')
290
1f0e3109
SS
291 def test_bridge(self):
292 self.copy_unit_to_networkd_unit_path('25-bridge.netdev')
293 self.start_networkd()
294
295 self.assertTrue(self.link_exits('bridge99'))
296
297 self.assertEqual('900', self.read_link_attr('bridge99', 'bridge', 'hello_time'))
298 self.assertEqual('900', self.read_link_attr('bridge99', 'bridge', 'max_age'))
299 self.assertEqual('900', self.read_link_attr('bridge99', 'bridge','forward_delay'))
300 self.assertEqual('900', self.read_link_attr('bridge99', 'bridge','ageing_time'))
301 self.assertEqual('9', self.read_link_attr('bridge99', 'bridge','priority'))
302 self.assertEqual('1', self.read_link_attr('bridge99', 'bridge','multicast_querier'))
303 self.assertEqual('1', self.read_link_attr('bridge99', 'bridge','multicast_snooping'))
304 self.assertEqual('1', self.read_link_attr('bridge99', 'bridge','stp_state'))
305
306 def test_bond(self):
307 self.copy_unit_to_networkd_unit_path('25-bond.netdev')
308 self.start_networkd()
309
310 self.assertTrue(self.link_exits('bond99'))
311
99f68ef0
TJ
312 self.assertEqual('802.3ad 4', self.read_link_attr('bond99', 'bonding', 'mode'))
313 self.assertEqual('layer3+4 1', self.read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
314 self.assertEqual('1000', self.read_link_attr('bond99', 'bonding', 'miimon'))
315 self.assertEqual('fast 1', self.read_link_attr('bond99', 'bonding', 'lacp_rate'))
316 self.assertEqual('2000', self.read_link_attr('bond99', 'bonding', 'updelay'))
317 self.assertEqual('2000', self.read_link_attr('bond99', 'bonding', 'downdelay'))
318 self.assertEqual('4', self.read_link_attr('bond99', 'bonding', 'resend_igmp'))
319 self.assertEqual('1', self.read_link_attr('bond99', 'bonding', 'min_links'))
320 self.assertEqual('1218', self.read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
321 self.assertEqual('811', self.read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
322 self.assertEqual('00:11:22:33:44:55', self.read_link_attr('bond99', 'bonding', 'ad_actor_system'))
1f0e3109 323
fde60a42
SS
324 def test_bond_balanced_tlb(self):
325 self.copy_unit_to_networkd_unit_path('25-bond-balanced-tlb.netdev')
326 self.start_networkd()
327
328 self.assertTrue(self.link_exits('bond99'))
329
330 self.assertEqual('balance-tlb 5', self.read_link_attr('bond99', 'bonding', 'mode'))
331 self.assertEqual('1', self.read_link_attr('bond99', 'bonding', 'tlb_dynamic_lb'))
332
1f0e3109
SS
333 def test_vlan(self):
334 self.copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev', '21-vlan.network')
1f0e3109
SS
335 self.start_networkd()
336
337 self.assertTrue(self.link_exits('vlan99'))
338
339 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vlan99']).rstrip().decode('utf-8')
14ecd604 340 print(output)
1f0e3109
SS
341 self.assertTrue(output, 'REORDER_HDR')
342 self.assertTrue(output, 'LOOSE_BINDING')
343 self.assertTrue(output, 'GVRP')
344 self.assertTrue(output, 'MVRP')
345 self.assertTrue(output, '99')
346
347 def test_macvtap(self):
348 self.copy_unit_to_networkd_unit_path('21-macvtap.netdev', '11-dummy.netdev', 'macvtap.network')
1f0e3109
SS
349 self.start_networkd()
350
351 self.assertTrue(self.link_exits('macvtap99'))
352
353 def test_macvlan(self):
354 self.copy_unit_to_networkd_unit_path('21-macvlan.netdev', '11-dummy.netdev', 'macvlan.network')
1f0e3109
SS
355 self.start_networkd()
356
357 self.assertTrue(self.link_exits('macvlan99'))
358
7a0a37b2 359 @expectedFailureIfModuleIsNotAvailable('ipvlan')
1f0e3109
SS
360 def test_ipvlan(self):
361 self.copy_unit_to_networkd_unit_path('25-ipvlan.netdev', '11-dummy.netdev', 'ipvlan.network')
1f0e3109
SS
362 self.start_networkd()
363
364 self.assertTrue(self.link_exits('ipvlan99'))
365
366 def test_veth(self):
367 self.copy_unit_to_networkd_unit_path('25-veth.netdev')
1f0e3109
SS
368 self.start_networkd()
369
370 self.assertTrue(self.link_exits('veth99'))
371
372 def test_dummy(self):
373 self.copy_unit_to_networkd_unit_path('11-dummy.netdev')
1f0e3109
SS
374 self.start_networkd()
375
376 self.assertTrue(self.link_exits('test1'))
377
378 def test_tun(self):
379 self.copy_unit_to_networkd_unit_path('25-tun.netdev')
1f0e3109
SS
380 self.start_networkd()
381
382 self.assertTrue(self.link_exits('tun99'))
383
384 def test_tap(self):
385 self.copy_unit_to_networkd_unit_path('25-tap.netdev')
1f0e3109
SS
386 self.start_networkd()
387
388 self.assertTrue(self.link_exits('tap99'))
389
7a0a37b2 390 @expectedFailureIfModuleIsNotAvailable('vrf')
1f0e3109
SS
391 def test_vrf(self):
392 self.copy_unit_to_networkd_unit_path('25-vrf.netdev')
1f0e3109
SS
393 self.start_networkd()
394
395 self.assertTrue(self.link_exits('vrf99'))
396
7a0a37b2 397 @expectedFailureIfModuleIsNotAvailable('vcan')
1f0e3109
SS
398 def test_vcan(self):
399 self.copy_unit_to_networkd_unit_path('25-vcan.netdev')
1f0e3109
SS
400 self.start_networkd()
401
402 self.assertTrue(self.link_exits('vcan99'))
403
7a3bc5a8
EV
404 @expectedFailureIfModuleIsNotAvailable('wireguard')
405 def test_wireguard(self):
406 self.copy_unit_to_networkd_unit_path('25-wireguard.netdev')
7a3bc5a8
EV
407 self.start_networkd()
408
409 if shutil.which('wg'):
410 subprocess.call('wg')
16ab043b
YW
411 output = subprocess.check_output(['wg', 'show', 'wg99', 'listen-port']).rstrip().decode('utf-8')
412 self.assertTrue(output, '51820')
413 output = subprocess.check_output(['wg', 'show', 'wg99', 'fwmark']).rstrip().decode('utf-8')
414 self.assertTrue(output, '0x4d2')
415 output = subprocess.check_output(['wg', 'show', 'wg99', 'allowed-ips']).rstrip().decode('utf-8')
416 self.assertTrue(output, 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
417 output = subprocess.check_output(['wg', 'show', 'wg99', 'persistent-keepalive']).rstrip().decode('utf-8')
418 self.assertTrue(output, 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t20')
419 output = subprocess.check_output(['wg', 'show', 'wg99', 'endpoints']).rstrip().decode('utf-8')
420 self.assertTrue(output, 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t192.168.27.3:51820')
7a3bc5a8
EV
421
422 self.assertTrue(self.link_exits('wg99'))
423
da44fb8a
YW
424 @expectedFailureIfModuleIsNotAvailable('wireguard')
425 def test_wireguard_23_peers(self):
426 self.copy_unit_to_networkd_unit_path('25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network')
427 self.start_networkd()
428
429 if shutil.which('wg'):
430 subprocess.call('wg')
431
432 self.assertTrue(self.link_exits('wg98'))
433
1f0e3109
SS
434 def test_geneve(self):
435 self.copy_unit_to_networkd_unit_path('25-geneve.netdev')
1f0e3109
SS
436 self.start_networkd()
437
438 self.assertTrue(self.link_exits('geneve99'))
439
440 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'geneve99']).rstrip().decode('utf-8')
14ecd604 441 print(output)
1f0e3109
SS
442 self.assertTrue(output, '192.168.22.1')
443 self.assertTrue(output, '6082')
444 self.assertTrue(output, 'udpcsum')
445 self.assertTrue(output, 'udp6zerocsumrx')
446
447 def test_ipip_tunnel(self):
448 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-ipip-tunnel.netdev', 'ipip.network')
449 self.start_networkd()
450
451 self.assertTrue(self.link_exits('dummy98'))
452 self.assertTrue(self.link_exits('ipiptun99'))
453
454 def test_gre_tunnel(self):
455 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-gre-tunnel.netdev', 'gretun.network')
456 self.start_networkd()
457
458 self.assertTrue(self.link_exits('dummy98'))
459 self.assertTrue(self.link_exits('gretun99'))
460
461 def test_gretap_tunnel(self):
462 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-gretap-tunnel.netdev', 'gretap.network')
463 self.start_networkd()
464
465 self.assertTrue(self.link_exits('dummy98'))
466 self.assertTrue(self.link_exits('gretap99'))
467
468 def test_ip6gretap_tunnel(self):
469 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-ip6gre-tunnel.netdev', 'ip6gretap.network')
470 self.start_networkd()
471
472 self.assertTrue(self.link_exits('dummy98'))
473 self.assertTrue(self.link_exits('ip6gretap99'))
474
475 def test_vti_tunnel(self):
476 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-vti-tunnel.netdev', 'vti.network')
477 self.start_networkd()
478
479 self.assertTrue(self.link_exits('dummy98'))
480 self.assertTrue(self.link_exits('vtitun99'))
481
482 def test_vti6_tunnel(self):
483 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-vti6-tunnel.netdev', 'vti6.network')
484 self.start_networkd()
485
486 self.assertTrue(self.link_exits('dummy98'))
487 self.assertTrue(self.link_exits('vti6tun99'))
488
489 def test_ip6tnl_tunnel(self):
490 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-ip6tnl-tunnel.netdev', 'ip6tnl.network')
491 self.start_networkd()
492
493 self.assertTrue(self.link_exits('dummy98'))
494 self.assertTrue(self.link_exits('ip6tnl99'))
495
496 def test_sit_tunnel(self):
497 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-sit-tunnel.netdev', 'sit.network')
498 self.start_networkd()
499
500 self.assertTrue(self.link_exits('dummy98'))
501 self.assertTrue(self.link_exits('sittun99'))
502
d0e728b6
SS
503 def test_isatap_tunnel(self):
504 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-isatap-tunnel.netdev', 'isatap.network')
505 self.start_networkd()
506
507 self.assertTrue(self.link_exits('dummy98'))
508 self.assertTrue(self.link_exits('isataptun99'))
e40a58b5 509
d0e728b6 510 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'isataptun99']).rstrip().decode('utf-8')
14ecd604 511 print(output)
d0e728b6
SS
512 self.assertRegex(output, "isatap ")
513
d29dc4f1
DA
514 def test_6rd_tunnel(self):
515 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-6rd-tunnel.netdev', '6rd.network')
516 self.start_networkd()
517
518 self.assertTrue(self.link_exits('dummy98'))
519 self.assertTrue(self.link_exits('sittun99'))
520
7bea7f9b 521 @expectedFailureIfERSPANModuleIsNotAvailable()
2266864b
SS
522 def test_erspan_tunnel(self):
523 self.copy_unit_to_networkd_unit_path('25-erspan-tunnel.netdev')
524 self.start_networkd()
525
526 self.assertTrue(self.link_exits('erspan-test'))
527
528 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'erspan-test']).rstrip().decode('utf-8')
529 print(output)
530 self.assertTrue(output, '172.16.1.200')
531 self.assertTrue(output, '172.16.1.100')
532 self.assertTrue(output, '101')
533
1f0e3109
SS
534 def test_tunnel_independent(self):
535 self.copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev')
1f0e3109 536 self.start_networkd()
e40a58b5 537
1f0e3109
SS
538 self.assertTrue(self.link_exits('ipiptun99'))
539
540 def test_vxlan(self):
541 self.copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network','11-dummy.netdev')
1f0e3109
SS
542 self.start_networkd()
543
544 self.assertTrue(self.link_exits('vxlan99'))
545
546 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vxlan99']).rstrip().decode('utf-8')
14ecd604 547 print(output)
1f0e3109
SS
548 self.assertRegex(output, "999")
549 self.assertRegex(output, '5555')
550 self.assertRegex(output, 'l2miss')
551 self.assertRegex(output, 'l3miss')
552 self.assertRegex(output, 'udpcsum')
553 self.assertRegex(output, 'udp6zerocsumtx')
554 self.assertRegex(output, 'udp6zerocsumrx')
555 self.assertRegex(output, 'remcsumtx')
556 self.assertRegex(output, 'remcsumrx')
557 self.assertRegex(output, 'gbp')
558
559class NetworkdNetWorkTests(unittest.TestCase, Utilities):
09ea6724
YW
560 links = [
561 'bond199',
562 'dummy98',
cd65d067 563 'dummy99',
09ea6724
YW
564 'test1']
565
566 units = [
567 '11-dummy.netdev',
568 '12-dummy.netdev',
569 '23-active-slave.network',
570 '23-bond199.network',
571 '23-primary-slave.network',
572 '23-test1-bond199.network',
573 '25-address-link-section.network',
574 '25-address-section-miscellaneous.network',
575 '25-address-section.network',
cd65d067 576 '25-bind-carrier.network',
09ea6724
YW
577 '25-bond-active-backup-slave.netdev',
578 '25-fibrule-invert.network',
579 '25-fibrule-port-range.network',
580 '25-ipv6-address-label-section.network',
e4a71bf3 581 '25-neighbor-section.network',
05514ae1
YW
582 '25-link-local-addressing-no.network',
583 '25-link-local-addressing-yes.network',
09ea6724
YW
584 '25-link-section-unmanaged.network',
585 '25-route-gateway.network',
586 '25-route-gateway-on-link.network',
20ca06a6 587 '25-route-ipv6-src.network',
09ea6724
YW
588 '25-route-reverse-order.network',
589 '25-route-section.network',
590 '25-route-tcp-window-settings.network',
591 '25-route-type.network',
592 '25-sysctl.network',
593 'configure-without-carrier.network',
594 'routing-policy-rule.network',
595 'test-static.network']
1f0e3109
SS
596
597 def setUp(self):
598 self.link_remove(self.links)
599
600 def tearDown(self):
601 self.link_remove(self.links)
602 self.remove_unit_from_networkd_path(self.units)
603
604 def test_static_address(self):
605 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'test-static.network')
606 self.start_networkd()
607
608 self.assertTrue(self.link_exits('dummy98'))
e40a58b5 609
1f0e3109
SS
610 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
611 print(output)
612 self.assertRegex(output, '192.168.0.15')
613 self.assertRegex(output, '192.168.0.1')
614 self.assertRegex(output, 'routable')
615
616 def test_configure_without_carrier(self):
617 self.copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
618 self.start_networkd()
619
620 self.assertTrue(self.link_exits('test1'))
e40a58b5 621
1f0e3109
SS
622 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
623 print(output)
624 self.assertRegex(output, '192.168.0.15')
625 self.assertRegex(output, '192.168.0.1')
626 self.assertRegex(output, 'routable')
627
628 def test_bond_active_slave(self):
629 self.copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
630 self.start_networkd()
631
632 self.assertTrue(self.link_exits('dummy98'))
633 self.assertTrue(self.link_exits('bond199'))
e40a58b5 634
1f0e3109
SS
635 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond199']).rstrip().decode('utf-8')
636 print(output)
637 self.assertRegex(output, 'active_slave dummy98')
638
639 def test_bond_primary_slave(self):
640 self.copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-test1-bond199.network', '25-bond-active-backup-slave.netdev', '11-dummy.netdev')
641 self.start_networkd()
642
643 self.assertTrue(self.link_exits('test1'))
644 self.assertTrue(self.link_exits('bond199'))
e40a58b5 645
1f0e3109
SS
646 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond199']).rstrip().decode('utf-8')
647 print(output)
648 self.assertRegex(output, 'primary test1')
649
650 def test_routing_policy_rule(self):
651 self.copy_unit_to_networkd_unit_path('routing-policy-rule.network', '11-dummy.netdev')
652 self.start_networkd()
653
654 self.assertTrue(self.link_exits('test1'))
e40a58b5 655
1f0e3109
SS
656 output = subprocess.check_output(['ip', 'rule']).rstrip().decode('utf-8')
657 print(output)
658 self.assertRegex(output, '111')
659 self.assertRegex(output, 'from 192.168.100.18')
f7bdd562 660 self.assertRegex(output, r'tos (?:0x08|throughput)\s')
1f0e3109
SS
661 self.assertRegex(output, 'iif test1')
662 self.assertRegex(output, 'oif test1')
663 self.assertRegex(output, 'lookup 7')
664
e4eacdb0
YW
665 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
666
d586a2c3 667 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
926062f0
SS
668 def test_routing_policy_rule_port_range(self):
669 self.copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
670 self.start_networkd()
671
672 self.assertTrue(self.link_exits('test1'))
e40a58b5 673
926062f0
SS
674 output = subprocess.check_output(['ip', 'rule']).rstrip().decode('utf-8')
675 print(output)
676 self.assertRegex(output, '111')
677 self.assertRegex(output, 'from 192.168.100.18')
678 self.assertRegex(output, '1123-1150')
679 self.assertRegex(output, '3224-3290')
680 self.assertRegex(output, 'tcp')
681 self.assertRegex(output, 'lookup 7')
1f0e3109 682
e4eacdb0
YW
683 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
684
d586a2c3 685 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
efecf9cd
SS
686 def test_routing_policy_rule_invert(self):
687 self.copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
688 self.start_networkd()
689
690 self.assertTrue(self.link_exits('test1'))
e40a58b5 691
efecf9cd
SS
692 output = subprocess.check_output(['ip', 'rule']).rstrip().decode('utf-8')
693 print(output)
efecf9cd
SS
694 self.assertRegex(output, '111')
695 self.assertRegex(output, 'not.*?from.*?192.168.100.18')
696 self.assertRegex(output, 'tcp')
697 self.assertRegex(output, 'lookup 7')
698
e4eacdb0
YW
699 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
700
ac60877f
YW
701 def test_address_peer(self):
702 self.copy_unit_to_networkd_unit_path('25-address-section.network', '12-dummy.netdev')
703 self.start_networkd()
704
705 self.assertTrue(self.link_exits('dummy98'))
706
707 output = subprocess.check_output(['ip', 'address', 'show', 'dummy98']).rstrip().decode('utf-8')
708 print(output)
709 self.assertRegex(output, 'inet 10.2.3.4 peer 10.2.3.5/16 scope global 32')
710 self.assertRegex(output, 'inet 10.6.7.8/16 brd 10.6.255.255 scope global 33')
7e663619 711 self.assertRegex(output, 'inet6 2001:db8::20 peer 2001:db8::10/128 scope global')
ac60877f
YW
712
713 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
714 print(output)
715 self.assertRegex(output, 'State: routable \(configured\)')
716
1f0e3109
SS
717 def test_address_preferred_lifetime_zero_ipv6(self):
718 self.copy_unit_to_networkd_unit_path('25-address-section-miscellaneous.network', '12-dummy.netdev')
719 self.start_networkd()
720
721 self.assertTrue(self.link_exits('dummy98'))
722
723 output = subprocess.check_output(['ip', 'address', 'show', 'dummy98']).rstrip().decode('utf-8')
724 print(output)
725 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
726 self.assertRegex(output, 'inet6 2001:db8:0:f101::1/64 scope global')
727
728 def test_ip_route(self):
729 self.copy_unit_to_networkd_unit_path('25-route-section.network', '12-dummy.netdev')
730 self.start_networkd()
731
732 self.assertTrue(self.link_exits('dummy98'))
733
734 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98']).rstrip().decode('utf-8')
735 print(output)
736 self.assertRegex(output, '192.168.0.1')
737 self.assertRegex(output, 'static')
738 self.assertRegex(output, '192.168.0.0/24')
739
0d34228f
SS
740 def test_ip_route_reverse(self):
741 self.copy_unit_to_networkd_unit_path('25-route-reverse-order.network', '12-dummy.netdev')
742 self.start_networkd()
743
744 self.assertTrue(self.link_exits('dummy98'))
745
746 output = subprocess.check_output(['ip', '-6', 'route', 'show', 'dev', 'dummy98']).rstrip().decode('utf-8')
747 print(output)
748 self.assertRegex(output, '2001:1234:5:8fff:ff:ff:ff:ff')
749 self.assertRegex(output, '2001:1234:5:8f63::1')
750
1f0e3109
SS
751 def test_ip_route_blackhole_unreachable_prohibit(self):
752 self.copy_unit_to_networkd_unit_path('25-route-type.network', '12-dummy.netdev')
753 self.start_networkd()
754
755 self.assertTrue(self.link_exits('dummy98'))
756
757 output = subprocess.check_output(['ip', 'route', 'list']).rstrip().decode('utf-8')
758 print(output)
759 self.assertRegex(output, 'blackhole')
760 self.assertRegex(output, 'unreachable')
761 self.assertRegex(output, 'prohibit')
762
763 subprocess.call(['ip', 'route', 'del', 'blackhole', '202.54.1.2'])
764 subprocess.call(['ip', 'route', 'del', 'unreachable', '202.54.1.3'])
765 subprocess.call(['ip', 'route', 'del', 'prohibit', '202.54.1.4'])
766
767 def test_ip_route_tcp_window(self):
768 self.copy_unit_to_networkd_unit_path('25-route-tcp-window-settings.network', '11-dummy.netdev')
769 self.start_networkd()
770
771 self.assertTrue(self.link_exits('test1'))
772
773 output = subprocess.check_output(['ip', 'route', 'list']).rstrip().decode('utf-8')
774 print(output)
775 self.assertRegex(output, 'initcwnd 20')
776 self.assertRegex(output, 'initrwnd 30')
777
f5050e48
YW
778 def test_ip_route_gateway(self):
779 self.copy_unit_to_networkd_unit_path('25-route-gateway.network', '12-dummy.netdev')
780 self.start_networkd()
781
782 self.assertTrue(self.link_exits('dummy98'))
783
784 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98', 'default']).rstrip().decode('utf-8')
785 print(output)
786 self.assertRegex(output, 'default')
787 self.assertRegex(output, 'via')
788 self.assertRegex(output, '149.10.124.64')
789 self.assertRegex(output, 'proto')
790 self.assertRegex(output, 'static')
791
792 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98', 'src', '149.10.124.58']).rstrip().decode('utf-8')
793 print(output)
794 self.assertRegex(output, '149.10.124.48/28')
795 self.assertRegex(output, 'proto')
796 self.assertRegex(output, 'kernel')
797 self.assertRegex(output, 'scope')
798 self.assertRegex(output, 'link')
799
800 def test_ip_route_gateway_on_link(self):
801 self.copy_unit_to_networkd_unit_path('25-route-gateway-on-link.network', '12-dummy.netdev')
802 self.start_networkd()
803
804 self.assertTrue(self.link_exits('dummy98'))
805
806 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98', 'default']).rstrip().decode('utf-8')
807 print(output)
808 self.assertRegex(output, 'default')
809 self.assertRegex(output, 'via')
810 self.assertRegex(output, '149.10.125.65')
811 self.assertRegex(output, 'proto')
812 self.assertRegex(output, 'static')
813 self.assertRegex(output, 'onlink')
814
815 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98', 'src', '149.10.124.58']).rstrip().decode('utf-8')
816 print(output)
817 self.assertRegex(output, '149.10.124.48/28')
818 self.assertRegex(output, 'proto')
819 self.assertRegex(output, 'kernel')
820 self.assertRegex(output, 'scope')
821 self.assertRegex(output, 'link')
822
20ca06a6
DA
823 def test_ip_route_ipv6_src_route(self):
824 # a dummy device does not make the addresses go through tentative state, so we
825 # reuse a bond from an earlier test, which does make the addresses go through
826 # tentative state, and do our test on that
827 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')
828 self.start_networkd()
829
830 self.assertTrue(self.link_exits('dummy98'))
831 self.assertTrue(self.link_exits('bond199'))
832
833 output = subprocess.check_output(['ip', '-6', 'route', 'list', 'dev', 'bond199']).rstrip().decode('utf-8')
834 print(output)
835 self.assertRegex(output, 'abcd::/16')
836 self.assertRegex(output, 'src')
837 self.assertRegex(output, '2001:1234:56:8f63::2')
838
1f0e3109
SS
839 def test_ip_link_mac_address(self):
840 self.copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
841 self.start_networkd()
842
843 self.assertTrue(self.link_exits('dummy98'))
844
845 output = subprocess.check_output(['ip', 'link', 'show', 'dummy98']).rstrip().decode('utf-8')
846 print(output)
847 self.assertRegex(output, '00:01:02:aa:bb:cc')
848
849 def test_ip_link_unmanaged(self):
850 self.copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
851 self.start_networkd()
852
853 self.assertTrue(self.link_exits('dummy98'))
854
855 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
856 print(output)
857 self.assertRegex(output, 'unmanaged')
858
859 def test_ipv6_address_label(self):
860 self.copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
861 self.start_networkd()
862
863 self.assertTrue(self.link_exits('dummy98'))
864
865 output = subprocess.check_output(['ip', 'addrlabel', 'list']).rstrip().decode('utf-8')
866 print(output)
867 self.assertRegex(output, '2004:da8:1::/64')
868
e4a71bf3
WKI
869 def test_ipv6_neighbor(self):
870 self.copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
871 self.start_networkd()
872
873 self.assertTrue(self.link_exits('dummy98'))
874
875 output = subprocess.check_output(['ip', 'neigh', 'list']).rstrip().decode('utf-8')
876 print(output)
877 self.assertRegex(output, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
094b5479 878 self.assertRegex(output, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
e4a71bf3 879
05514ae1
YW
880 def test_link_local_addressing(self):
881 self.copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
882 '25-link-local-addressing-no.network', '12-dummy.netdev')
883 self.start_networkd()
884
885 self.assertTrue(self.link_exits('test1'))
886 self.assertTrue(self.link_exits('dummy98'))
887
888 time.sleep(10)
889
890 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'test1']).rstrip().decode('utf-8')
891 print(output)
892 self.assertRegex(output, 'inet .* scope link')
893 self.assertRegex(output, 'inet6 .* scope link')
894
895 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'dummy98']).rstrip().decode('utf-8')
896 print(output)
897 self.assertNotRegex(output, 'inet6* .* scope link')
898
899 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
900 print(output)
901 self.assertRegex(output, 'State: degraded \(configured\)')
902
903 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
904 print(output)
905 self.assertRegex(output, 'State: carrier \(configured\)')
906
907 '''
908 Documentation/networking/ip-sysctl.txt
909
910 addr_gen_mode - INTEGER
911 Defines how link-local and autoconf addresses are generated.
912
913 0: generate address based on EUI64 (default)
914 1: do no generate a link-local address, use EUI64 for addresses generated
915 from autoconf
916 2: generate stable privacy addresses, using the secret from
917 stable_secret (RFC7217)
918 3: generate stable privacy addresses, using a random secret if unset
919 '''
920
921 test1_addr_gen_mode = ''
922 if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'stable_secret')):
923 with open(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'stable_secret')) as f:
924 try:
925 f.readline()
926 except IOError:
927 # if stable_secret is unset, then EIO is returned
928 test1_addr_gen_mode = '0'
929 else:
930 test1_addr_gen_mode = '2'
931 else:
932 test1_addr_gen_mode = '0'
933
934 if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'addr_gen_mode')):
935 self.assertEqual(self.read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), '0')
936
937 if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'dummy98'), 'addr_gen_mode')):
938 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
939
1f0e3109
SS
940 def test_sysctl(self):
941 self.copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
942 self.start_networkd()
943
944 self.assertTrue(self.link_exits('dummy98'))
945
946 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
947 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
948 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
949 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
950 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
951 self.assertEqual(self.read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
952 self.assertEqual(self.read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
953
cd65d067
YW
954 def test_bind_carrier(self):
955 self.copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
956 self.start_networkd()
957
958 self.assertTrue(self.link_exits('test1'))
959
cd65d067
YW
960 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
961 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
63eb0956 962 time.sleep(4)
cd65d067
YW
963 output = subprocess.check_output(['ip', 'address', 'show', 'test1']).rstrip().decode('utf-8')
964 print(output)
965 self.assertRegex(output, 'UP,LOWER_UP')
966 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
967 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
968 self.assertRegex(output, 'State: routable \(configured\)')
969
970 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy99', 'type', 'dummy']), 0)
971 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy99', 'up']), 0)
63eb0956 972 time.sleep(4)
cd65d067
YW
973 output = subprocess.check_output(['ip', 'address', 'show', 'test1']).rstrip().decode('utf-8')
974 print(output)
975 self.assertRegex(output, 'UP,LOWER_UP')
976 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
977 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
978 self.assertRegex(output, 'State: routable \(configured\)')
979
980 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
63eb0956 981 time.sleep(4)
cd65d067
YW
982 output = subprocess.check_output(['ip', 'address', 'show', 'test1']).rstrip().decode('utf-8')
983 print(output)
984 self.assertRegex(output, 'UP,LOWER_UP')
985 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
986 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
987 self.assertRegex(output, 'State: routable \(configured\)')
988
989 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy99']), 0)
63eb0956 990 time.sleep(4)
cd65d067
YW
991 output = subprocess.check_output(['ip', 'address', 'show', 'test1']).rstrip().decode('utf-8')
992 print(output)
993 self.assertNotRegex(output, 'UP,LOWER_UP')
994 self.assertRegex(output, 'DOWN')
995 self.assertNotRegex(output, '192.168.10')
996 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
997 self.assertRegex(output, 'State: off \(configured\)')
998
999 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1000 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
63eb0956 1001 time.sleep(4)
cd65d067
YW
1002 output = subprocess.check_output(['ip', 'address', 'show', 'test1']).rstrip().decode('utf-8')
1003 print(output)
1004 self.assertRegex(output, 'UP,LOWER_UP')
1005 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1006 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
1007 self.assertRegex(output, 'State: routable \(configured\)')
1008
14dc0335 1009class NetworkdNetWorkBridgeTests(unittest.TestCase, Utilities):
09ea6724
YW
1010 links = [
1011 'bridge99',
1012 'dummy98',
1013 'test1']
1014
1015 units = [
1016 '11-dummy.netdev',
1017 '12-dummy.netdev',
1018 '26-bridge.netdev',
1019 '26-bridge-slave-interface-1.network',
1020 '26-bridge-slave-interface-2.network',
804b6cd2 1021 'bridge99-ignore-carrier-loss.network',
09ea6724 1022 'bridge99.network']
1f0e3109
SS
1023
1024 def setUp(self):
1025 self.link_remove(self.links)
1026
1027 def tearDown(self):
1028 self.link_remove(self.links)
1029 self.remove_unit_from_networkd_path(self.units)
1030
1031 def test_bridge_property(self):
1032 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1033 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1034 'bridge99.network')
1035 self.start_networkd()
1036
1037 self.assertTrue(self.link_exits('dummy98'))
1038 self.assertTrue(self.link_exits('test1'))
1039 self.assertTrue(self.link_exits('bridge99'))
1040
1041 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1']).rstrip().decode('utf-8')
1042 print(output)
1043 self.assertRegex(output, 'master')
1044 self.assertRegex(output, 'bridge')
1045
1046 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'dummy98']).rstrip().decode('utf-8')
1047 print(output)
1048 self.assertRegex(output, 'master')
1049 self.assertRegex(output, 'bridge')
1050
1051 output = subprocess.check_output(['ip', 'addr', 'show', 'bridge99']).rstrip().decode('utf-8')
1052 print(output)
1053 self.assertRegex(output, '192.168.0.15')
1054 self.assertRegex(output, '192.168.0.1')
1055
1056 output = subprocess.check_output(['bridge', '-d', 'link', 'show', 'dummy98']).rstrip().decode('utf-8')
1057 print(output)
4d7ed14f
SS
1058 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
1059 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
1060 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
1061 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
1062
1063 # CONFIG_BRIDGE_IGMP_SNOOPING=y
1064 if (os.path.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
1065 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
1f0e3109 1066
804b6cd2
YW
1067 self.assertEqual(subprocess.call(['ip', 'address', 'add', '192.168.0.16/24', 'dev', 'bridge99']), 0)
1068 time.sleep(1)
1069
1070 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'test1']), 0)
1071 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1072 time.sleep(3)
1073
1074 output = subprocess.check_output(['ip', 'address', 'show', 'bridge99']).rstrip().decode('utf-8')
1075 print(output)
1076 self.assertRegex(output, 'NO-CARRIER')
1077 self.assertNotRegex(output, '192.168.0.15/24')
1078 self.assertNotRegex(output, '192.168.0.16/24')
1079
1080 def test_bridge_ignore_carrier_loss(self):
1081 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1082 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1083 'bridge99-ignore-carrier-loss.network')
1084 self.start_networkd()
1085
1086 self.assertTrue(self.link_exits('dummy98'))
1087 self.assertTrue(self.link_exits('test1'))
1088 self.assertTrue(self.link_exits('bridge99'))
1089
1090 self.assertEqual(subprocess.call(['ip', 'address', 'add', '192.168.0.16/24', 'dev', 'bridge99']), 0)
1091 time.sleep(1)
1092
1093 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'test1']), 0)
1094 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1095 time.sleep(3)
1096
1097 output = subprocess.check_output(['ip', 'address', 'show', 'bridge99']).rstrip().decode('utf-8')
1098 print(output)
1099 self.assertRegex(output, 'NO-CARRIER')
1100 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1101 self.assertRegex(output, 'inet 192.168.0.16/24 scope global secondary bridge99')
1102
1f0e3109
SS
1103class NetworkdNetWorkLLDPTests(unittest.TestCase, Utilities):
1104 links = ['veth99']
1105
09ea6724
YW
1106 units = [
1107 '23-emit-lldp.network',
1108 '24-lldp.network',
1109 '25-veth.netdev']
1f0e3109
SS
1110
1111 def setUp(self):
1112 self.link_remove(self.links)
1113
1114 def tearDown(self):
1115 self.link_remove(self.links)
1116 self.remove_unit_from_networkd_path(self.units)
1117
1118 def test_lldp(self):
1119 self.copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
1120 self.start_networkd()
1121
1122 self.assertTrue(self.link_exits('veth99'))
1123
1124 output = subprocess.check_output(['networkctl', 'lldp']).rstrip().decode('utf-8')
1125 print(output)
1126 self.assertRegex(output, 'veth-peer')
1127 self.assertRegex(output, 'veth99')
1128
1129class NetworkdNetworkRATests(unittest.TestCase, Utilities):
1130 links = ['veth99']
1131
09ea6724
YW
1132 units = [
1133 '25-veth.netdev',
1134 'ipv6-prefix.network',
1135 'ipv6-prefix-veth.network']
1f0e3109
SS
1136
1137 def setUp(self):
1138 self.link_remove(self.links)
1139
1140 def tearDown(self):
1141 self.link_remove(self.links)
1142 self.remove_unit_from_networkd_path(self.units)
1143
1144 def test_ipv6_prefix_delegation(self):
1145 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
1146 self.start_networkd()
1147
1148 self.assertTrue(self.link_exits('veth99'))
1149
1150 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1151 print(output)
1152 self.assertRegex(output, '2002:da8:1:0')
1153
1154class NetworkdNetworkDHCPServerTests(unittest.TestCase, Utilities):
09ea6724
YW
1155 links = [
1156 'dummy98',
1157 'veth99']
1158
1159 units = [
1160 '12-dummy.netdev',
1161 '24-search-domain.network',
1162 '25-veth.netdev',
1163 'dhcp-client.network',
1164 'dhcp-client-timezone-router.network',
1165 'dhcp-server.network',
1166 'dhcp-server-timezone-router.network']
1f0e3109
SS
1167
1168 def setUp(self):
1169 self.link_remove(self.links)
1170
1171 def tearDown(self):
1172 self.link_remove(self.links)
1173 self.remove_unit_from_networkd_path(self.units)
1174
1175 def test_dhcp_server(self):
1176 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
1177 self.start_networkd()
1178
1179 self.assertTrue(self.link_exits('veth99'))
1180
1f0e3109
SS
1181 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1182 print(output)
1183 self.assertRegex(output, '192.168.5.*')
1184 self.assertRegex(output, 'Gateway: 192.168.5.1')
1185 self.assertRegex(output, 'DNS: 192.168.5.1')
1186 self.assertRegex(output, 'NTP: 192.168.5.1')
1187
1188 def test_domain(self):
f5d191a9 1189 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
1f0e3109
SS
1190 self.start_networkd()
1191
1192 self.assertTrue(self.link_exits('dummy98'))
1193
1194 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
1195 print(output)
1196 self.assertRegex(output, 'Address: 192.168.42.100')
1197 self.assertRegex(output, 'DNS: 192.168.42.1')
1198 self.assertRegex(output, 'Search Domains: one')
1199
1200 def test_emit_router_timezone(self):
1201 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
1202 self.start_networkd()
1203
1204 self.assertTrue(self.link_exits('veth99'))
1205
1206 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1207 print(output)
1208 self.assertRegex(output, 'Gateway: 192.168.5.*')
1209 self.assertRegex(output, '192.168.5.*')
1210 self.assertRegex(output, 'Europe/Berlin')
1211
1212class NetworkdNetworkDHCPClientTests(unittest.TestCase, Utilities):
09ea6724
YW
1213 links = [
1214 'dummy98',
1215 'veth99']
1216
1217 units = [
1218 '25-veth.netdev',
1219 'dhcp-client-anonymize.network',
1220 'dhcp-client-critical-connection.network',
1221 'dhcp-client-ipv4-dhcp-settings.network',
1222 'dhcp-client-ipv4-only-ipv6-disabled.network',
1223 'dhcp-client-ipv4-only.network',
1224 'dhcp-client-ipv6-only.network',
1225 'dhcp-client-ipv6-rapid-commit.network',
1226 'dhcp-client-listen-port.network',
1227 'dhcp-client-route-metric.network',
1228 'dhcp-client-route-table.network',
3e9d5552 1229 'dhcp-client.network',
09ea6724 1230 'dhcp-server-veth-peer.network',
30d3b54e
YW
1231 'dhcp-v4-server-veth-peer.network',
1232 'static.network']
1f0e3109
SS
1233
1234 def setUp(self):
1235 self.link_remove(self.links)
1236 self.stop_dnsmasq(dnsmasq_pid_file)
1237
1238 def tearDown(self):
1239 self.link_remove(self.links)
1240 self.remove_unit_from_networkd_path(self.units)
1241 self.stop_dnsmasq(dnsmasq_pid_file)
1242 self.remove_lease_file()
1243 self.remove_log_file()
1244
1245 def test_dhcp_client_ipv6_only(self):
f5d191a9 1246 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
1f0e3109
SS
1247 self.start_networkd()
1248
1249 self.assertTrue(self.link_exits('veth99'))
1250
1251 self.start_dnsmasq()
1252
1253 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1254 print(output)
1255 self.assertRegex(output, '2600::')
1256 self.assertNotRegex(output, '192.168.5')
1257
1258 def test_dhcp_client_ipv4_only(self):
f5d191a9 1259 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
1f0e3109
SS
1260 self.start_networkd()
1261
1262 self.assertTrue(self.link_exits('veth99'))
1263
1264 self.start_dnsmasq()
1265
1266 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1267 print(output)
1268 self.assertNotRegex(output, '2600::')
1269 self.assertRegex(output, '192.168.5')
1270
1271 def test_dhcp_client_ipv4_ipv6(self):
1272 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
1273 'dhcp-client-ipv4-only.network')
1274 self.start_networkd()
1275
1276 self.assertTrue(self.link_exits('veth99'))
1277
1278 self.start_dnsmasq()
1279
1280 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1281 print(output)
1282 self.assertRegex(output, '2600::')
1283 self.assertRegex(output, '192.168.5')
1284
1285 def test_dhcp_client_settings(self):
1286 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
1287 self.start_networkd()
1288
1289 self.assertTrue(self.link_exits('veth99'))
1290
1291 self.start_dnsmasq()
1292
1293 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
1294 print(output)
1295 self.assertRegex(output, '12:34:56:78:9a:bc')
1296 self.assertRegex(output, '192.168.5')
1297 self.assertRegex(output, '1492')
1298
1299 output = subprocess.check_output(['ip', 'route']).rstrip().decode('utf-8')
1300 print(output)
1301 self.assertRegex(output, 'default.*dev veth99 proto dhcp')
1302
131717cb
YW
1303 self.assertTrue(self.search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
1304 self.assertTrue(self.search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
1305 self.assertTrue(self.search_words_in_dnsmasq_log('client provides name: test-hostname'))
1306 self.assertTrue(self.search_words_in_dnsmasq_log('26:mtu'))
1f0e3109
SS
1307
1308 def test_dhcp6_client_settings_rapidcommit_true(self):
1309 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
1310 self.start_networkd()
1311
1312 self.assertTrue(self.link_exits('veth99'))
1313
1314 self.start_dnsmasq()
1315
1316 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
1317 print(output)
1318 self.assertRegex(output, '12:34:56:78:9a:bc')
131717cb 1319 self.assertTrue(self.search_words_in_dnsmasq_log('14:rapid-commit', True))
1f0e3109
SS
1320
1321 def test_dhcp6_client_settings_rapidcommit_false(self):
1322 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
1323 self.start_networkd()
1324
1325 self.assertTrue(self.link_exits('veth99'))
1326
1327 self.start_dnsmasq()
1328
1329 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
1330 print(output)
1331 self.assertRegex(output, '12:34:56:78:9a:bc')
131717cb 1332 self.assertFalse(self.search_words_in_dnsmasq_log('14:rapid-commit', True))
1f0e3109
SS
1333
1334 def test_dhcp_client_settings_anonymize(self):
1335 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
1336 self.start_networkd()
1337
1338 self.assertTrue(self.link_exits('veth99'))
1339
1340 self.start_dnsmasq()
e40a58b5 1341
131717cb
YW
1342 self.assertFalse(self.search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
1343 self.assertFalse(self.search_words_in_dnsmasq_log('test-hostname'))
1344 self.assertFalse(self.search_words_in_dnsmasq_log('26:mtu'))
1f0e3109
SS
1345
1346 def test_dhcp_client_listen_port(self):
1347 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
1f0e3109
SS
1348 self.start_networkd()
1349
1350 self.assertTrue(self.link_exits('veth99'))
1351
b412fce8 1352 self.start_dnsmasq('--dhcp-alternate-port=67,5555')
1f0e3109 1353
b412fce8
YW
1354 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
1355 print(output)
1356 self.assertRegex(output, '192.168.5.* dynamic')
1f0e3109
SS
1357
1358 def test_dhcp_route_table_id(self):
1359 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
1360 self.start_networkd()
1f0e3109
SS
1361
1362 self.assertTrue(self.link_exits('veth99'))
1363
e40a58b5
YW
1364 self.start_dnsmasq()
1365
1f0e3109
SS
1366 output = subprocess.check_output(['ip', 'route', 'show', 'table', '12']).rstrip().decode('utf-8')
1367 print(output)
1f0e3109
SS
1368 self.assertRegex(output, 'veth99 proto dhcp')
1369 self.assertRegex(output, '192.168.5.1')
1370
1371 def test_dhcp_route_metric(self):
1372 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
1373 self.start_networkd()
1f0e3109
SS
1374
1375 self.assertTrue(self.link_exits('veth99'))
1376
e40a58b5
YW
1377 self.start_dnsmasq()
1378
1f0e3109
SS
1379 output = subprocess.check_output(['ip', 'route', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
1380 print(output)
1f0e3109
SS
1381 self.assertRegex(output, 'metric 24')
1382
1383 def test_dhcp_route_criticalconnection_true(self):
1384 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-critical-connection.network')
1385 self.start_networkd()
1f0e3109
SS
1386
1387 self.assertTrue(self.link_exits('veth99'))
1388
e40a58b5
YW
1389 self.start_dnsmasq()
1390
1f0e3109
SS
1391 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1392 print(output)
1f0e3109 1393 self.assertRegex(output, '192.168.5.*')
e40a58b5 1394
1f0e3109
SS
1395 # Stoping dnsmasq as networkd won't be allowed to renew the DHCP lease.
1396 self.stop_dnsmasq(dnsmasq_pid_file)
1397
1398 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
1399 time.sleep(125)
1400
1401 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1402 print(output)
1403 self.assertRegex(output, '192.168.5.*')
1404
30d3b54e
YW
1405 def test_dhcp_client_reuse_address_as_static(self):
1406 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
1407 self.start_networkd()
1408
1409 self.assertTrue(self.link_exits('veth99'))
1410
1411 self.start_dnsmasq()
1412
1413 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99', 'scope', 'global']).rstrip().decode('utf-8')
1414 print(output)
1415 self.assertRegex(output, '192.168.5')
1416 self.assertRegex(output, '2600::')
1417
1418 ipv4_address = re.search('192\.168\.5\.[0-9]*/24', output)
1419 ipv6_address = re.search('2600::[0-9a-f:]*/128', output)
1420 static_network = '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address.group(), 'Address=' + ipv6_address.group()])
1421 print(static_network)
1422
1423 self.remove_unit_from_networkd_path(['dhcp-client.network'])
1424
1425 with open(os.path.join(network_unit_file_path, 'static.network'), mode='w') as f:
1426 f.write(static_network)
1427
1428 self.start_networkd()
1429
1430 self.assertTrue(self.link_exits('veth99'))
1431
1432 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global']).rstrip().decode('utf-8')
1433 print(output)
1434 self.assertRegex(output, '192.168.5')
1435 self.assertRegex(output, 'valid_lft forever preferred_lft forever')
1436
1437 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global']).rstrip().decode('utf-8')
1438 print(output)
1439 self.assertRegex(output, '2600::')
1440 self.assertRegex(output, 'valid_lft forever preferred_lft forever')
1441
1f0e3109
SS
1442if __name__ == '__main__':
1443 unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout,
1444 verbosity=3))