]> git.ipfire.org Git - thirdparty/systemd.git/blame - test/test-network/systemd-networkd-tests.py
login: add a missing error check for session_set_leader()
[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
1f0e3109
SS
279 def test_bridge(self):
280 self.copy_unit_to_networkd_unit_path('25-bridge.netdev')
281 self.start_networkd()
282
283 self.assertTrue(self.link_exits('bridge99'))
284
285 self.assertEqual('900', self.read_link_attr('bridge99', 'bridge', 'hello_time'))
286 self.assertEqual('900', self.read_link_attr('bridge99', 'bridge', 'max_age'))
287 self.assertEqual('900', self.read_link_attr('bridge99', 'bridge','forward_delay'))
288 self.assertEqual('900', self.read_link_attr('bridge99', 'bridge','ageing_time'))
289 self.assertEqual('9', self.read_link_attr('bridge99', 'bridge','priority'))
290 self.assertEqual('1', self.read_link_attr('bridge99', 'bridge','multicast_querier'))
291 self.assertEqual('1', self.read_link_attr('bridge99', 'bridge','multicast_snooping'))
292 self.assertEqual('1', self.read_link_attr('bridge99', 'bridge','stp_state'))
293
294 def test_bond(self):
295 self.copy_unit_to_networkd_unit_path('25-bond.netdev')
296 self.start_networkd()
297
298 self.assertTrue(self.link_exits('bond99'))
299
99f68ef0
TJ
300 self.assertEqual('802.3ad 4', self.read_link_attr('bond99', 'bonding', 'mode'))
301 self.assertEqual('layer3+4 1', self.read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
302 self.assertEqual('1000', self.read_link_attr('bond99', 'bonding', 'miimon'))
303 self.assertEqual('fast 1', self.read_link_attr('bond99', 'bonding', 'lacp_rate'))
304 self.assertEqual('2000', self.read_link_attr('bond99', 'bonding', 'updelay'))
305 self.assertEqual('2000', self.read_link_attr('bond99', 'bonding', 'downdelay'))
306 self.assertEqual('4', self.read_link_attr('bond99', 'bonding', 'resend_igmp'))
307 self.assertEqual('1', self.read_link_attr('bond99', 'bonding', 'min_links'))
308 self.assertEqual('1218', self.read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
309 self.assertEqual('811', self.read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
310 self.assertEqual('00:11:22:33:44:55', self.read_link_attr('bond99', 'bonding', 'ad_actor_system'))
1f0e3109 311
fde60a42
SS
312 def test_bond_balanced_tlb(self):
313 self.copy_unit_to_networkd_unit_path('25-bond-balanced-tlb.netdev')
314 self.start_networkd()
315
316 self.assertTrue(self.link_exits('bond99'))
317
318 self.assertEqual('balance-tlb 5', self.read_link_attr('bond99', 'bonding', 'mode'))
319 self.assertEqual('1', self.read_link_attr('bond99', 'bonding', 'tlb_dynamic_lb'))
320
1f0e3109
SS
321 def test_vlan(self):
322 self.copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev', '21-vlan.network')
1f0e3109
SS
323 self.start_networkd()
324
325 self.assertTrue(self.link_exits('vlan99'))
326
327 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vlan99']).rstrip().decode('utf-8')
14ecd604 328 print(output)
1f0e3109
SS
329 self.assertTrue(output, 'REORDER_HDR')
330 self.assertTrue(output, 'LOOSE_BINDING')
331 self.assertTrue(output, 'GVRP')
332 self.assertTrue(output, 'MVRP')
333 self.assertTrue(output, '99')
334
335 def test_macvtap(self):
336 self.copy_unit_to_networkd_unit_path('21-macvtap.netdev', '11-dummy.netdev', 'macvtap.network')
1f0e3109
SS
337 self.start_networkd()
338
339 self.assertTrue(self.link_exits('macvtap99'))
340
341 def test_macvlan(self):
342 self.copy_unit_to_networkd_unit_path('21-macvlan.netdev', '11-dummy.netdev', 'macvlan.network')
1f0e3109
SS
343 self.start_networkd()
344
345 self.assertTrue(self.link_exits('macvlan99'))
346
7a0a37b2 347 @expectedFailureIfModuleIsNotAvailable('ipvlan')
1f0e3109
SS
348 def test_ipvlan(self):
349 self.copy_unit_to_networkd_unit_path('25-ipvlan.netdev', '11-dummy.netdev', 'ipvlan.network')
1f0e3109
SS
350 self.start_networkd()
351
352 self.assertTrue(self.link_exits('ipvlan99'))
353
354 def test_veth(self):
355 self.copy_unit_to_networkd_unit_path('25-veth.netdev')
1f0e3109
SS
356 self.start_networkd()
357
358 self.assertTrue(self.link_exits('veth99'))
359
360 def test_dummy(self):
361 self.copy_unit_to_networkd_unit_path('11-dummy.netdev')
1f0e3109
SS
362 self.start_networkd()
363
364 self.assertTrue(self.link_exits('test1'))
365
366 def test_tun(self):
367 self.copy_unit_to_networkd_unit_path('25-tun.netdev')
1f0e3109
SS
368 self.start_networkd()
369
370 self.assertTrue(self.link_exits('tun99'))
371
372 def test_tap(self):
373 self.copy_unit_to_networkd_unit_path('25-tap.netdev')
1f0e3109
SS
374 self.start_networkd()
375
376 self.assertTrue(self.link_exits('tap99'))
377
7a0a37b2 378 @expectedFailureIfModuleIsNotAvailable('vrf')
1f0e3109
SS
379 def test_vrf(self):
380 self.copy_unit_to_networkd_unit_path('25-vrf.netdev')
1f0e3109
SS
381 self.start_networkd()
382
383 self.assertTrue(self.link_exits('vrf99'))
384
7a0a37b2 385 @expectedFailureIfModuleIsNotAvailable('vcan')
1f0e3109
SS
386 def test_vcan(self):
387 self.copy_unit_to_networkd_unit_path('25-vcan.netdev')
1f0e3109
SS
388 self.start_networkd()
389
390 self.assertTrue(self.link_exits('vcan99'))
391
7a3bc5a8
EV
392 @expectedFailureIfModuleIsNotAvailable('wireguard')
393 def test_wireguard(self):
394 self.copy_unit_to_networkd_unit_path('25-wireguard.netdev')
7a3bc5a8
EV
395 self.start_networkd()
396
397 if shutil.which('wg'):
398 subprocess.call('wg')
16ab043b
YW
399 output = subprocess.check_output(['wg', 'show', 'wg99', 'listen-port']).rstrip().decode('utf-8')
400 self.assertTrue(output, '51820')
401 output = subprocess.check_output(['wg', 'show', 'wg99', 'fwmark']).rstrip().decode('utf-8')
402 self.assertTrue(output, '0x4d2')
403 output = subprocess.check_output(['wg', 'show', 'wg99', 'allowed-ips']).rstrip().decode('utf-8')
404 self.assertTrue(output, 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
405 output = subprocess.check_output(['wg', 'show', 'wg99', 'persistent-keepalive']).rstrip().decode('utf-8')
406 self.assertTrue(output, 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t20')
407 output = subprocess.check_output(['wg', 'show', 'wg99', 'endpoints']).rstrip().decode('utf-8')
408 self.assertTrue(output, 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t192.168.27.3:51820')
7a3bc5a8
EV
409
410 self.assertTrue(self.link_exits('wg99'))
411
da44fb8a
YW
412 @expectedFailureIfModuleIsNotAvailable('wireguard')
413 def test_wireguard_23_peers(self):
414 self.copy_unit_to_networkd_unit_path('25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network')
415 self.start_networkd()
416
417 if shutil.which('wg'):
418 subprocess.call('wg')
419
420 self.assertTrue(self.link_exits('wg98'))
421
1f0e3109
SS
422 def test_geneve(self):
423 self.copy_unit_to_networkd_unit_path('25-geneve.netdev')
1f0e3109
SS
424 self.start_networkd()
425
426 self.assertTrue(self.link_exits('geneve99'))
427
428 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'geneve99']).rstrip().decode('utf-8')
14ecd604 429 print(output)
1f0e3109
SS
430 self.assertTrue(output, '192.168.22.1')
431 self.assertTrue(output, '6082')
432 self.assertTrue(output, 'udpcsum')
433 self.assertTrue(output, 'udp6zerocsumrx')
434
435 def test_ipip_tunnel(self):
436 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-ipip-tunnel.netdev', 'ipip.network')
437 self.start_networkd()
438
439 self.assertTrue(self.link_exits('dummy98'))
440 self.assertTrue(self.link_exits('ipiptun99'))
441
442 def test_gre_tunnel(self):
443 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-gre-tunnel.netdev', 'gretun.network')
444 self.start_networkd()
445
446 self.assertTrue(self.link_exits('dummy98'))
447 self.assertTrue(self.link_exits('gretun99'))
448
449 def test_gretap_tunnel(self):
450 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-gretap-tunnel.netdev', 'gretap.network')
451 self.start_networkd()
452
453 self.assertTrue(self.link_exits('dummy98'))
454 self.assertTrue(self.link_exits('gretap99'))
455
456 def test_ip6gretap_tunnel(self):
457 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-ip6gre-tunnel.netdev', 'ip6gretap.network')
458 self.start_networkd()
459
460 self.assertTrue(self.link_exits('dummy98'))
461 self.assertTrue(self.link_exits('ip6gretap99'))
462
463 def test_vti_tunnel(self):
464 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-vti-tunnel.netdev', 'vti.network')
465 self.start_networkd()
466
467 self.assertTrue(self.link_exits('dummy98'))
468 self.assertTrue(self.link_exits('vtitun99'))
469
470 def test_vti6_tunnel(self):
471 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-vti6-tunnel.netdev', 'vti6.network')
472 self.start_networkd()
473
474 self.assertTrue(self.link_exits('dummy98'))
475 self.assertTrue(self.link_exits('vti6tun99'))
476
477 def test_ip6tnl_tunnel(self):
478 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-ip6tnl-tunnel.netdev', 'ip6tnl.network')
479 self.start_networkd()
480
481 self.assertTrue(self.link_exits('dummy98'))
482 self.assertTrue(self.link_exits('ip6tnl99'))
483
484 def test_sit_tunnel(self):
485 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-sit-tunnel.netdev', 'sit.network')
486 self.start_networkd()
487
488 self.assertTrue(self.link_exits('dummy98'))
489 self.assertTrue(self.link_exits('sittun99'))
490
d0e728b6
SS
491 def test_isatap_tunnel(self):
492 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-isatap-tunnel.netdev', 'isatap.network')
493 self.start_networkd()
494
495 self.assertTrue(self.link_exits('dummy98'))
496 self.assertTrue(self.link_exits('isataptun99'))
e40a58b5 497
d0e728b6 498 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'isataptun99']).rstrip().decode('utf-8')
14ecd604 499 print(output)
d0e728b6
SS
500 self.assertRegex(output, "isatap ")
501
d29dc4f1
DA
502 def test_6rd_tunnel(self):
503 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-6rd-tunnel.netdev', '6rd.network')
504 self.start_networkd()
505
506 self.assertTrue(self.link_exits('dummy98'))
507 self.assertTrue(self.link_exits('sittun99'))
508
7bea7f9b 509 @expectedFailureIfERSPANModuleIsNotAvailable()
2266864b
SS
510 def test_erspan_tunnel(self):
511 self.copy_unit_to_networkd_unit_path('25-erspan-tunnel.netdev')
512 self.start_networkd()
513
514 self.assertTrue(self.link_exits('erspan-test'))
515
516 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'erspan-test']).rstrip().decode('utf-8')
517 print(output)
518 self.assertTrue(output, '172.16.1.200')
519 self.assertTrue(output, '172.16.1.100')
520 self.assertTrue(output, '101')
521
1f0e3109
SS
522 def test_tunnel_independent(self):
523 self.copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev')
1f0e3109 524 self.start_networkd()
e40a58b5 525
1f0e3109
SS
526 self.assertTrue(self.link_exits('ipiptun99'))
527
528 def test_vxlan(self):
529 self.copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network','11-dummy.netdev')
1f0e3109
SS
530 self.start_networkd()
531
532 self.assertTrue(self.link_exits('vxlan99'))
533
534 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vxlan99']).rstrip().decode('utf-8')
14ecd604 535 print(output)
1f0e3109
SS
536 self.assertRegex(output, "999")
537 self.assertRegex(output, '5555')
538 self.assertRegex(output, 'l2miss')
539 self.assertRegex(output, 'l3miss')
540 self.assertRegex(output, 'udpcsum')
541 self.assertRegex(output, 'udp6zerocsumtx')
542 self.assertRegex(output, 'udp6zerocsumrx')
543 self.assertRegex(output, 'remcsumtx')
544 self.assertRegex(output, 'remcsumrx')
545 self.assertRegex(output, 'gbp')
546
547class NetworkdNetWorkTests(unittest.TestCase, Utilities):
09ea6724
YW
548 links = [
549 'bond199',
550 'dummy98',
551 'test1']
552
553 units = [
554 '11-dummy.netdev',
555 '12-dummy.netdev',
556 '23-active-slave.network',
557 '23-bond199.network',
558 '23-primary-slave.network',
559 '23-test1-bond199.network',
560 '25-address-link-section.network',
561 '25-address-section-miscellaneous.network',
562 '25-address-section.network',
563 '25-bond-active-backup-slave.netdev',
564 '25-fibrule-invert.network',
565 '25-fibrule-port-range.network',
566 '25-ipv6-address-label-section.network',
e4a71bf3 567 '25-neighbor-section.network',
05514ae1
YW
568 '25-link-local-addressing-no.network',
569 '25-link-local-addressing-yes.network',
09ea6724
YW
570 '25-link-section-unmanaged.network',
571 '25-route-gateway.network',
572 '25-route-gateway-on-link.network',
20ca06a6 573 '25-route-ipv6-src.network',
09ea6724
YW
574 '25-route-reverse-order.network',
575 '25-route-section.network',
576 '25-route-tcp-window-settings.network',
577 '25-route-type.network',
578 '25-sysctl.network',
579 'configure-without-carrier.network',
580 'routing-policy-rule.network',
581 'test-static.network']
1f0e3109
SS
582
583 def setUp(self):
584 self.link_remove(self.links)
585
586 def tearDown(self):
587 self.link_remove(self.links)
588 self.remove_unit_from_networkd_path(self.units)
589
590 def test_static_address(self):
591 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'test-static.network')
592 self.start_networkd()
593
594 self.assertTrue(self.link_exits('dummy98'))
e40a58b5 595
1f0e3109
SS
596 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
597 print(output)
598 self.assertRegex(output, '192.168.0.15')
599 self.assertRegex(output, '192.168.0.1')
600 self.assertRegex(output, 'routable')
601
602 def test_configure_without_carrier(self):
603 self.copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
604 self.start_networkd()
605
606 self.assertTrue(self.link_exits('test1'))
e40a58b5 607
1f0e3109
SS
608 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
609 print(output)
610 self.assertRegex(output, '192.168.0.15')
611 self.assertRegex(output, '192.168.0.1')
612 self.assertRegex(output, 'routable')
613
614 def test_bond_active_slave(self):
615 self.copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
616 self.start_networkd()
617
618 self.assertTrue(self.link_exits('dummy98'))
619 self.assertTrue(self.link_exits('bond199'))
e40a58b5 620
1f0e3109
SS
621 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond199']).rstrip().decode('utf-8')
622 print(output)
623 self.assertRegex(output, 'active_slave dummy98')
624
625 def test_bond_primary_slave(self):
626 self.copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-test1-bond199.network', '25-bond-active-backup-slave.netdev', '11-dummy.netdev')
627 self.start_networkd()
628
629 self.assertTrue(self.link_exits('test1'))
630 self.assertTrue(self.link_exits('bond199'))
e40a58b5 631
1f0e3109
SS
632 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond199']).rstrip().decode('utf-8')
633 print(output)
634 self.assertRegex(output, 'primary test1')
635
636 def test_routing_policy_rule(self):
637 self.copy_unit_to_networkd_unit_path('routing-policy-rule.network', '11-dummy.netdev')
638 self.start_networkd()
639
640 self.assertTrue(self.link_exits('test1'))
e40a58b5 641
1f0e3109
SS
642 output = subprocess.check_output(['ip', 'rule']).rstrip().decode('utf-8')
643 print(output)
644 self.assertRegex(output, '111')
645 self.assertRegex(output, 'from 192.168.100.18')
f7bdd562 646 self.assertRegex(output, r'tos (?:0x08|throughput)\s')
1f0e3109
SS
647 self.assertRegex(output, 'iif test1')
648 self.assertRegex(output, 'oif test1')
649 self.assertRegex(output, 'lookup 7')
650
e4eacdb0
YW
651 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
652
d586a2c3 653 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
926062f0
SS
654 def test_routing_policy_rule_port_range(self):
655 self.copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
656 self.start_networkd()
657
658 self.assertTrue(self.link_exits('test1'))
e40a58b5 659
926062f0
SS
660 output = subprocess.check_output(['ip', 'rule']).rstrip().decode('utf-8')
661 print(output)
662 self.assertRegex(output, '111')
663 self.assertRegex(output, 'from 192.168.100.18')
664 self.assertRegex(output, '1123-1150')
665 self.assertRegex(output, '3224-3290')
666 self.assertRegex(output, 'tcp')
667 self.assertRegex(output, 'lookup 7')
1f0e3109 668
e4eacdb0
YW
669 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
670
d586a2c3 671 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
efecf9cd
SS
672 def test_routing_policy_rule_invert(self):
673 self.copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
674 self.start_networkd()
675
676 self.assertTrue(self.link_exits('test1'))
e40a58b5 677
efecf9cd
SS
678 output = subprocess.check_output(['ip', 'rule']).rstrip().decode('utf-8')
679 print(output)
efecf9cd
SS
680 self.assertRegex(output, '111')
681 self.assertRegex(output, 'not.*?from.*?192.168.100.18')
682 self.assertRegex(output, 'tcp')
683 self.assertRegex(output, 'lookup 7')
684
e4eacdb0
YW
685 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
686
ac60877f
YW
687 def test_address_peer(self):
688 self.copy_unit_to_networkd_unit_path('25-address-section.network', '12-dummy.netdev')
689 self.start_networkd()
690
691 self.assertTrue(self.link_exits('dummy98'))
692
693 output = subprocess.check_output(['ip', 'address', 'show', 'dummy98']).rstrip().decode('utf-8')
694 print(output)
695 self.assertRegex(output, 'inet 10.2.3.4 peer 10.2.3.5/16 scope global 32')
696 self.assertRegex(output, 'inet 10.6.7.8/16 brd 10.6.255.255 scope global 33')
7e663619 697 self.assertRegex(output, 'inet6 2001:db8::20 peer 2001:db8::10/128 scope global')
ac60877f
YW
698
699 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
700 print(output)
701 self.assertRegex(output, 'State: routable \(configured\)')
702
1f0e3109
SS
703 def test_address_preferred_lifetime_zero_ipv6(self):
704 self.copy_unit_to_networkd_unit_path('25-address-section-miscellaneous.network', '12-dummy.netdev')
705 self.start_networkd()
706
707 self.assertTrue(self.link_exits('dummy98'))
708
709 output = subprocess.check_output(['ip', 'address', 'show', 'dummy98']).rstrip().decode('utf-8')
710 print(output)
711 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
712 self.assertRegex(output, 'inet6 2001:db8:0:f101::1/64 scope global')
713
714 def test_ip_route(self):
715 self.copy_unit_to_networkd_unit_path('25-route-section.network', '12-dummy.netdev')
716 self.start_networkd()
717
718 self.assertTrue(self.link_exits('dummy98'))
719
720 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98']).rstrip().decode('utf-8')
721 print(output)
722 self.assertRegex(output, '192.168.0.1')
723 self.assertRegex(output, 'static')
724 self.assertRegex(output, '192.168.0.0/24')
725
0d34228f
SS
726 def test_ip_route_reverse(self):
727 self.copy_unit_to_networkd_unit_path('25-route-reverse-order.network', '12-dummy.netdev')
728 self.start_networkd()
729
730 self.assertTrue(self.link_exits('dummy98'))
731
732 output = subprocess.check_output(['ip', '-6', 'route', 'show', 'dev', 'dummy98']).rstrip().decode('utf-8')
733 print(output)
734 self.assertRegex(output, '2001:1234:5:8fff:ff:ff:ff:ff')
735 self.assertRegex(output, '2001:1234:5:8f63::1')
736
1f0e3109
SS
737 def test_ip_route_blackhole_unreachable_prohibit(self):
738 self.copy_unit_to_networkd_unit_path('25-route-type.network', '12-dummy.netdev')
739 self.start_networkd()
740
741 self.assertTrue(self.link_exits('dummy98'))
742
743 output = subprocess.check_output(['ip', 'route', 'list']).rstrip().decode('utf-8')
744 print(output)
745 self.assertRegex(output, 'blackhole')
746 self.assertRegex(output, 'unreachable')
747 self.assertRegex(output, 'prohibit')
748
749 subprocess.call(['ip', 'route', 'del', 'blackhole', '202.54.1.2'])
750 subprocess.call(['ip', 'route', 'del', 'unreachable', '202.54.1.3'])
751 subprocess.call(['ip', 'route', 'del', 'prohibit', '202.54.1.4'])
752
753 def test_ip_route_tcp_window(self):
754 self.copy_unit_to_networkd_unit_path('25-route-tcp-window-settings.network', '11-dummy.netdev')
755 self.start_networkd()
756
757 self.assertTrue(self.link_exits('test1'))
758
759 output = subprocess.check_output(['ip', 'route', 'list']).rstrip().decode('utf-8')
760 print(output)
761 self.assertRegex(output, 'initcwnd 20')
762 self.assertRegex(output, 'initrwnd 30')
763
f5050e48
YW
764 def test_ip_route_gateway(self):
765 self.copy_unit_to_networkd_unit_path('25-route-gateway.network', '12-dummy.netdev')
766 self.start_networkd()
767
768 self.assertTrue(self.link_exits('dummy98'))
769
770 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98', 'default']).rstrip().decode('utf-8')
771 print(output)
772 self.assertRegex(output, 'default')
773 self.assertRegex(output, 'via')
774 self.assertRegex(output, '149.10.124.64')
775 self.assertRegex(output, 'proto')
776 self.assertRegex(output, 'static')
777
778 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98', 'src', '149.10.124.58']).rstrip().decode('utf-8')
779 print(output)
780 self.assertRegex(output, '149.10.124.48/28')
781 self.assertRegex(output, 'proto')
782 self.assertRegex(output, 'kernel')
783 self.assertRegex(output, 'scope')
784 self.assertRegex(output, 'link')
785
786 def test_ip_route_gateway_on_link(self):
787 self.copy_unit_to_networkd_unit_path('25-route-gateway-on-link.network', '12-dummy.netdev')
788 self.start_networkd()
789
790 self.assertTrue(self.link_exits('dummy98'))
791
792 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98', 'default']).rstrip().decode('utf-8')
793 print(output)
794 self.assertRegex(output, 'default')
795 self.assertRegex(output, 'via')
796 self.assertRegex(output, '149.10.125.65')
797 self.assertRegex(output, 'proto')
798 self.assertRegex(output, 'static')
799 self.assertRegex(output, 'onlink')
800
801 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98', 'src', '149.10.124.58']).rstrip().decode('utf-8')
802 print(output)
803 self.assertRegex(output, '149.10.124.48/28')
804 self.assertRegex(output, 'proto')
805 self.assertRegex(output, 'kernel')
806 self.assertRegex(output, 'scope')
807 self.assertRegex(output, 'link')
808
20ca06a6
DA
809 def test_ip_route_ipv6_src_route(self):
810 # a dummy device does not make the addresses go through tentative state, so we
811 # reuse a bond from an earlier test, which does make the addresses go through
812 # tentative state, and do our test on that
813 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')
814 self.start_networkd()
815
816 self.assertTrue(self.link_exits('dummy98'))
817 self.assertTrue(self.link_exits('bond199'))
818
819 output = subprocess.check_output(['ip', '-6', 'route', 'list', 'dev', 'bond199']).rstrip().decode('utf-8')
820 print(output)
821 self.assertRegex(output, 'abcd::/16')
822 self.assertRegex(output, 'src')
823 self.assertRegex(output, '2001:1234:56:8f63::2')
824
1f0e3109
SS
825 def test_ip_link_mac_address(self):
826 self.copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
827 self.start_networkd()
828
829 self.assertTrue(self.link_exits('dummy98'))
830
831 output = subprocess.check_output(['ip', 'link', 'show', 'dummy98']).rstrip().decode('utf-8')
832 print(output)
833 self.assertRegex(output, '00:01:02:aa:bb:cc')
834
835 def test_ip_link_unmanaged(self):
836 self.copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
837 self.start_networkd()
838
839 self.assertTrue(self.link_exits('dummy98'))
840
841 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
842 print(output)
843 self.assertRegex(output, 'unmanaged')
844
845 def test_ipv6_address_label(self):
846 self.copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
847 self.start_networkd()
848
849 self.assertTrue(self.link_exits('dummy98'))
850
851 output = subprocess.check_output(['ip', 'addrlabel', 'list']).rstrip().decode('utf-8')
852 print(output)
853 self.assertRegex(output, '2004:da8:1::/64')
854
e4a71bf3
WKI
855 def test_ipv6_neighbor(self):
856 self.copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
857 self.start_networkd()
858
859 self.assertTrue(self.link_exits('dummy98'))
860
861 output = subprocess.check_output(['ip', 'neigh', 'list']).rstrip().decode('utf-8')
862 print(output)
863 self.assertRegex(output, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
094b5479 864 self.assertRegex(output, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
e4a71bf3 865
05514ae1
YW
866 def test_link_local_addressing(self):
867 self.copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
868 '25-link-local-addressing-no.network', '12-dummy.netdev')
869 self.start_networkd()
870
871 self.assertTrue(self.link_exits('test1'))
872 self.assertTrue(self.link_exits('dummy98'))
873
874 time.sleep(10)
875
876 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'test1']).rstrip().decode('utf-8')
877 print(output)
878 self.assertRegex(output, 'inet .* scope link')
879 self.assertRegex(output, 'inet6 .* scope link')
880
881 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'dummy98']).rstrip().decode('utf-8')
882 print(output)
883 self.assertNotRegex(output, 'inet6* .* scope link')
884
885 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
886 print(output)
887 self.assertRegex(output, 'State: degraded \(configured\)')
888
889 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
890 print(output)
891 self.assertRegex(output, 'State: carrier \(configured\)')
892
893 '''
894 Documentation/networking/ip-sysctl.txt
895
896 addr_gen_mode - INTEGER
897 Defines how link-local and autoconf addresses are generated.
898
899 0: generate address based on EUI64 (default)
900 1: do no generate a link-local address, use EUI64 for addresses generated
901 from autoconf
902 2: generate stable privacy addresses, using the secret from
903 stable_secret (RFC7217)
904 3: generate stable privacy addresses, using a random secret if unset
905 '''
906
907 test1_addr_gen_mode = ''
908 if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'stable_secret')):
909 with open(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'stable_secret')) as f:
910 try:
911 f.readline()
912 except IOError:
913 # if stable_secret is unset, then EIO is returned
914 test1_addr_gen_mode = '0'
915 else:
916 test1_addr_gen_mode = '2'
917 else:
918 test1_addr_gen_mode = '0'
919
920 if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'addr_gen_mode')):
921 self.assertEqual(self.read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), '0')
922
923 if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'dummy98'), 'addr_gen_mode')):
924 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
925
1f0e3109
SS
926 def test_sysctl(self):
927 self.copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
928 self.start_networkd()
929
930 self.assertTrue(self.link_exits('dummy98'))
931
932 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
933 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
934 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
935 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
936 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
937 self.assertEqual(self.read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
938 self.assertEqual(self.read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
939
14dc0335 940class NetworkdNetWorkBridgeTests(unittest.TestCase, Utilities):
09ea6724
YW
941 links = [
942 'bridge99',
943 'dummy98',
944 'test1']
945
946 units = [
947 '11-dummy.netdev',
948 '12-dummy.netdev',
949 '26-bridge.netdev',
950 '26-bridge-slave-interface-1.network',
951 '26-bridge-slave-interface-2.network',
952 'bridge99.network']
1f0e3109
SS
953
954 def setUp(self):
955 self.link_remove(self.links)
956
957 def tearDown(self):
958 self.link_remove(self.links)
959 self.remove_unit_from_networkd_path(self.units)
960
961 def test_bridge_property(self):
962 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
963 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
964 'bridge99.network')
965 self.start_networkd()
966
967 self.assertTrue(self.link_exits('dummy98'))
968 self.assertTrue(self.link_exits('test1'))
969 self.assertTrue(self.link_exits('bridge99'))
970
971 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1']).rstrip().decode('utf-8')
972 print(output)
973 self.assertRegex(output, 'master')
974 self.assertRegex(output, 'bridge')
975
976 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'dummy98']).rstrip().decode('utf-8')
977 print(output)
978 self.assertRegex(output, 'master')
979 self.assertRegex(output, 'bridge')
980
981 output = subprocess.check_output(['ip', 'addr', 'show', 'bridge99']).rstrip().decode('utf-8')
982 print(output)
983 self.assertRegex(output, '192.168.0.15')
984 self.assertRegex(output, '192.168.0.1')
985
986 output = subprocess.check_output(['bridge', '-d', 'link', 'show', 'dummy98']).rstrip().decode('utf-8')
987 print(output)
4d7ed14f
SS
988 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
989 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
990 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
991 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
992
993 # CONFIG_BRIDGE_IGMP_SNOOPING=y
994 if (os.path.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
995 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
1f0e3109
SS
996
997class NetworkdNetWorkLLDPTests(unittest.TestCase, Utilities):
998 links = ['veth99']
999
09ea6724
YW
1000 units = [
1001 '23-emit-lldp.network',
1002 '24-lldp.network',
1003 '25-veth.netdev']
1f0e3109
SS
1004
1005 def setUp(self):
1006 self.link_remove(self.links)
1007
1008 def tearDown(self):
1009 self.link_remove(self.links)
1010 self.remove_unit_from_networkd_path(self.units)
1011
1012 def test_lldp(self):
1013 self.copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
1014 self.start_networkd()
1015
1016 self.assertTrue(self.link_exits('veth99'))
1017
1018 output = subprocess.check_output(['networkctl', 'lldp']).rstrip().decode('utf-8')
1019 print(output)
1020 self.assertRegex(output, 'veth-peer')
1021 self.assertRegex(output, 'veth99')
1022
1023class NetworkdNetworkRATests(unittest.TestCase, Utilities):
1024 links = ['veth99']
1025
09ea6724
YW
1026 units = [
1027 '25-veth.netdev',
1028 'ipv6-prefix.network',
1029 'ipv6-prefix-veth.network']
1f0e3109
SS
1030
1031 def setUp(self):
1032 self.link_remove(self.links)
1033
1034 def tearDown(self):
1035 self.link_remove(self.links)
1036 self.remove_unit_from_networkd_path(self.units)
1037
1038 def test_ipv6_prefix_delegation(self):
1039 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
1040 self.start_networkd()
1041
1042 self.assertTrue(self.link_exits('veth99'))
1043
1044 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1045 print(output)
1046 self.assertRegex(output, '2002:da8:1:0')
1047
1048class NetworkdNetworkDHCPServerTests(unittest.TestCase, Utilities):
09ea6724
YW
1049 links = [
1050 'dummy98',
1051 'veth99']
1052
1053 units = [
1054 '12-dummy.netdev',
1055 '24-search-domain.network',
1056 '25-veth.netdev',
1057 'dhcp-client.network',
1058 'dhcp-client-timezone-router.network',
1059 'dhcp-server.network',
1060 'dhcp-server-timezone-router.network']
1f0e3109
SS
1061
1062 def setUp(self):
1063 self.link_remove(self.links)
1064
1065 def tearDown(self):
1066 self.link_remove(self.links)
1067 self.remove_unit_from_networkd_path(self.units)
1068
1069 def test_dhcp_server(self):
1070 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
1071 self.start_networkd()
1072
1073 self.assertTrue(self.link_exits('veth99'))
1074
1f0e3109
SS
1075 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1076 print(output)
1077 self.assertRegex(output, '192.168.5.*')
1078 self.assertRegex(output, 'Gateway: 192.168.5.1')
1079 self.assertRegex(output, 'DNS: 192.168.5.1')
1080 self.assertRegex(output, 'NTP: 192.168.5.1')
1081
1082 def test_domain(self):
f5d191a9 1083 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
1f0e3109
SS
1084 self.start_networkd()
1085
1086 self.assertTrue(self.link_exits('dummy98'))
1087
1088 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
1089 print(output)
1090 self.assertRegex(output, 'Address: 192.168.42.100')
1091 self.assertRegex(output, 'DNS: 192.168.42.1')
1092 self.assertRegex(output, 'Search Domains: one')
1093
1094 def test_emit_router_timezone(self):
1095 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
1096 self.start_networkd()
1097
1098 self.assertTrue(self.link_exits('veth99'))
1099
1100 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1101 print(output)
1102 self.assertRegex(output, 'Gateway: 192.168.5.*')
1103 self.assertRegex(output, '192.168.5.*')
1104 self.assertRegex(output, 'Europe/Berlin')
1105
1106class NetworkdNetworkDHCPClientTests(unittest.TestCase, Utilities):
09ea6724
YW
1107 links = [
1108 'dummy98',
1109 'veth99']
1110
1111 units = [
1112 '25-veth.netdev',
1113 'dhcp-client-anonymize.network',
1114 'dhcp-client-critical-connection.network',
1115 'dhcp-client-ipv4-dhcp-settings.network',
1116 'dhcp-client-ipv4-only-ipv6-disabled.network',
1117 'dhcp-client-ipv4-only.network',
1118 'dhcp-client-ipv6-only.network',
1119 'dhcp-client-ipv6-rapid-commit.network',
1120 'dhcp-client-listen-port.network',
1121 'dhcp-client-route-metric.network',
1122 'dhcp-client-route-table.network',
3e9d5552 1123 'dhcp-client.network',
09ea6724 1124 'dhcp-server-veth-peer.network',
30d3b54e
YW
1125 'dhcp-v4-server-veth-peer.network',
1126 'static.network']
1f0e3109
SS
1127
1128 def setUp(self):
1129 self.link_remove(self.links)
1130 self.stop_dnsmasq(dnsmasq_pid_file)
1131
1132 def tearDown(self):
1133 self.link_remove(self.links)
1134 self.remove_unit_from_networkd_path(self.units)
1135 self.stop_dnsmasq(dnsmasq_pid_file)
1136 self.remove_lease_file()
1137 self.remove_log_file()
1138
1139 def test_dhcp_client_ipv6_only(self):
f5d191a9 1140 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
1f0e3109
SS
1141 self.start_networkd()
1142
1143 self.assertTrue(self.link_exits('veth99'))
1144
1145 self.start_dnsmasq()
1146
1147 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1148 print(output)
1149 self.assertRegex(output, '2600::')
1150 self.assertNotRegex(output, '192.168.5')
1151
1152 def test_dhcp_client_ipv4_only(self):
f5d191a9 1153 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
1f0e3109
SS
1154 self.start_networkd()
1155
1156 self.assertTrue(self.link_exits('veth99'))
1157
1158 self.start_dnsmasq()
1159
1160 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1161 print(output)
1162 self.assertNotRegex(output, '2600::')
1163 self.assertRegex(output, '192.168.5')
1164
1165 def test_dhcp_client_ipv4_ipv6(self):
1166 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
1167 'dhcp-client-ipv4-only.network')
1168 self.start_networkd()
1169
1170 self.assertTrue(self.link_exits('veth99'))
1171
1172 self.start_dnsmasq()
1173
1174 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1175 print(output)
1176 self.assertRegex(output, '2600::')
1177 self.assertRegex(output, '192.168.5')
1178
1179 def test_dhcp_client_settings(self):
1180 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
1181 self.start_networkd()
1182
1183 self.assertTrue(self.link_exits('veth99'))
1184
1185 self.start_dnsmasq()
1186
1187 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
1188 print(output)
1189 self.assertRegex(output, '12:34:56:78:9a:bc')
1190 self.assertRegex(output, '192.168.5')
1191 self.assertRegex(output, '1492')
1192
1193 output = subprocess.check_output(['ip', 'route']).rstrip().decode('utf-8')
1194 print(output)
1195 self.assertRegex(output, 'default.*dev veth99 proto dhcp')
1196
131717cb
YW
1197 self.assertTrue(self.search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
1198 self.assertTrue(self.search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
1199 self.assertTrue(self.search_words_in_dnsmasq_log('client provides name: test-hostname'))
1200 self.assertTrue(self.search_words_in_dnsmasq_log('26:mtu'))
1f0e3109
SS
1201
1202 def test_dhcp6_client_settings_rapidcommit_true(self):
1203 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
1204 self.start_networkd()
1205
1206 self.assertTrue(self.link_exits('veth99'))
1207
1208 self.start_dnsmasq()
1209
1210 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
1211 print(output)
1212 self.assertRegex(output, '12:34:56:78:9a:bc')
131717cb 1213 self.assertTrue(self.search_words_in_dnsmasq_log('14:rapid-commit', True))
1f0e3109
SS
1214
1215 def test_dhcp6_client_settings_rapidcommit_false(self):
1216 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
1217 self.start_networkd()
1218
1219 self.assertTrue(self.link_exits('veth99'))
1220
1221 self.start_dnsmasq()
1222
1223 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
1224 print(output)
1225 self.assertRegex(output, '12:34:56:78:9a:bc')
131717cb 1226 self.assertFalse(self.search_words_in_dnsmasq_log('14:rapid-commit', True))
1f0e3109
SS
1227
1228 def test_dhcp_client_settings_anonymize(self):
1229 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
1230 self.start_networkd()
1231
1232 self.assertTrue(self.link_exits('veth99'))
1233
1234 self.start_dnsmasq()
e40a58b5 1235
131717cb
YW
1236 self.assertFalse(self.search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
1237 self.assertFalse(self.search_words_in_dnsmasq_log('test-hostname'))
1238 self.assertFalse(self.search_words_in_dnsmasq_log('26:mtu'))
1f0e3109
SS
1239
1240 def test_dhcp_client_listen_port(self):
1241 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
1f0e3109
SS
1242 self.start_networkd()
1243
1244 self.assertTrue(self.link_exits('veth99'))
1245
b412fce8 1246 self.start_dnsmasq('--dhcp-alternate-port=67,5555')
1f0e3109 1247
b412fce8
YW
1248 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
1249 print(output)
1250 self.assertRegex(output, '192.168.5.* dynamic')
1f0e3109
SS
1251
1252 def test_dhcp_route_table_id(self):
1253 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
1254 self.start_networkd()
1f0e3109
SS
1255
1256 self.assertTrue(self.link_exits('veth99'))
1257
e40a58b5
YW
1258 self.start_dnsmasq()
1259
1f0e3109
SS
1260 output = subprocess.check_output(['ip', 'route', 'show', 'table', '12']).rstrip().decode('utf-8')
1261 print(output)
1f0e3109
SS
1262 self.assertRegex(output, 'veth99 proto dhcp')
1263 self.assertRegex(output, '192.168.5.1')
1264
1265 def test_dhcp_route_metric(self):
1266 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
1267 self.start_networkd()
1f0e3109
SS
1268
1269 self.assertTrue(self.link_exits('veth99'))
1270
e40a58b5
YW
1271 self.start_dnsmasq()
1272
1f0e3109
SS
1273 output = subprocess.check_output(['ip', 'route', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
1274 print(output)
1f0e3109
SS
1275 self.assertRegex(output, 'metric 24')
1276
1277 def test_dhcp_route_criticalconnection_true(self):
1278 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-critical-connection.network')
1279 self.start_networkd()
1f0e3109
SS
1280
1281 self.assertTrue(self.link_exits('veth99'))
1282
e40a58b5
YW
1283 self.start_dnsmasq()
1284
1f0e3109
SS
1285 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1286 print(output)
1f0e3109 1287 self.assertRegex(output, '192.168.5.*')
e40a58b5 1288
1f0e3109
SS
1289 # Stoping dnsmasq as networkd won't be allowed to renew the DHCP lease.
1290 self.stop_dnsmasq(dnsmasq_pid_file)
1291
1292 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
1293 time.sleep(125)
1294
1295 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1296 print(output)
1297 self.assertRegex(output, '192.168.5.*')
1298
30d3b54e
YW
1299 def test_dhcp_client_reuse_address_as_static(self):
1300 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
1301 self.start_networkd()
1302
1303 self.assertTrue(self.link_exits('veth99'))
1304
1305 self.start_dnsmasq()
1306
1307 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99', 'scope', 'global']).rstrip().decode('utf-8')
1308 print(output)
1309 self.assertRegex(output, '192.168.5')
1310 self.assertRegex(output, '2600::')
1311
1312 ipv4_address = re.search('192\.168\.5\.[0-9]*/24', output)
1313 ipv6_address = re.search('2600::[0-9a-f:]*/128', output)
1314 static_network = '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address.group(), 'Address=' + ipv6_address.group()])
1315 print(static_network)
1316
1317 self.remove_unit_from_networkd_path(['dhcp-client.network'])
1318
1319 with open(os.path.join(network_unit_file_path, 'static.network'), mode='w') as f:
1320 f.write(static_network)
1321
1322 self.start_networkd()
1323
1324 self.assertTrue(self.link_exits('veth99'))
1325
1326 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global']).rstrip().decode('utf-8')
1327 print(output)
1328 self.assertRegex(output, '192.168.5')
1329 self.assertRegex(output, 'valid_lft forever preferred_lft forever')
1330
1331 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global']).rstrip().decode('utf-8')
1332 print(output)
1333 self.assertRegex(output, '2600::')
1334 self.assertRegex(output, 'valid_lft forever preferred_lft forever')
1335
1f0e3109
SS
1336if __name__ == '__main__':
1337 unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout,
1338 verbosity=3))