]> git.ipfire.org Git - thirdparty/systemd.git/blame - test/test-network/systemd-networkd-tests.py
Add 6rd directive to the netdev fuzzing corpus.
[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
6import sys
7import unittest
8import subprocess
9import time
201bf07f 10import re
1f0e3109
SS
11import shutil
12import signal
13import socket
14import threading
15from shutil import copytree
16
17network_unit_file_path='/var/run/systemd/network'
18networkd_ci_path='/var/run/networkd-ci'
19network_sysctl_ipv6_path='/proc/sys/net/ipv6/conf'
20network_sysctl_ipv4_path='/proc/sys/net/ipv4/conf'
21
22dnsmasq_config_file='/var/run/networkd-ci/test-dnsmasq.conf'
23dnsmasq_pid_file='/var/run/networkd-ci/test-test-dnsmasq.pid'
24dnsmasq_log_file='/var/run/networkd-ci/test-dnsmasq-log-file'
25
7a0a37b2 26def is_module_available(module_name):
201bf07f
EV
27 lsmod_output = subprocess.check_output('lsmod', universal_newlines=True)
28 module_re = re.compile(r'^{0}\b'.format(re.escape(module_name)), re.MULTILINE)
29 return module_re.search(lsmod_output) or not subprocess.call(["modprobe", module_name])
7a0a37b2
EV
30
31def expectedFailureIfModuleIsNotAvailable(module_name):
32 def f(func):
33 if not is_module_available(module_name):
34 return unittest.expectedFailure(func)
35 return func
36
37 return f
38
1f0e3109
SS
39def setUpModule():
40
41 os.makedirs(network_unit_file_path, exist_ok=True)
42 os.makedirs(networkd_ci_path, exist_ok=True)
43
44 shutil.rmtree(networkd_ci_path)
6aea9276 45 copytree(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'conf'), networkd_ci_path)
1f0e3109
SS
46
47def tearDownModule():
48 shutil.rmtree(networkd_ci_path)
49
50class Utilities():
51 dhcp_server_data = []
52
53 def read_link_attr(self, link, dev, attribute):
54 with open(os.path.join(os.path.join(os.path.join('/sys/class/net/', link), dev), attribute)) as f:
55 return f.readline().strip()
56
57 def link_exits(self, link):
58 return os.path.exists(os.path.join('/sys/class/net', link))
59
60 def link_remove(self, links):
61 for link in links:
62 if os.path.exists(os.path.join('/sys/class/net', link)):
63 subprocess.call(['ip', 'link', 'del', 'dev', link])
9a4720a9 64 time.sleep(1)
1f0e3109
SS
65
66 def read_ipv6_sysctl_attr(self, link, attribute):
67 with open(os.path.join(os.path.join(network_sysctl_ipv6_path, link), attribute)) as f:
68 return f.readline().strip()
69
70 def read_ipv4_sysctl_attr(self, link, attribute):
71 with open(os.path.join(os.path.join(network_sysctl_ipv4_path, link), attribute)) as f:
72 return f.readline().strip()
73
74 def copy_unit_to_networkd_unit_path(self, *units):
75 for unit in units:
76 shutil.copy(os.path.join(networkd_ci_path, unit), network_unit_file_path)
77
78 def remove_unit_from_networkd_path(self, units):
79 for unit in units:
80 if (os.path.exists(os.path.join(network_unit_file_path, unit))):
81 os.remove(os.path.join(network_unit_file_path, unit))
82
83 def start_dnsmasq(self):
84 subprocess.check_call('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', shell=True)
85
86 time.sleep(10)
87
88 def stop_dnsmasq(self, pid_file):
89 if os.path.exists(pid_file):
90 with open(pid_file, 'r') as f:
91 pid = f.read().rstrip(' \t\r\n\0')
92 os.kill(int(pid), signal.SIGTERM)
93
94 os.remove(pid_file)
95
96 def search_words_in_file(self, word):
97 if os.path.exists(dnsmasq_log_file):
98 with open (dnsmasq_log_file) as in_file:
99 contents = in_file.read()
100 print(contents)
101 for part in contents.split():
102 if word in part:
103 in_file.close()
104 print("%s, %s" % (word, part))
105 return True
106 return False
107
108 def remove_lease_file(self):
109 if os.path.exists(os.path.join(networkd_ci_path, 'lease')):
110 os.remove(os.path.join(networkd_ci_path, 'lease'))
111
112 def remove_log_file(self):
113 if os.path.exists(dnsmasq_log_file):
114 os.remove(dnsmasq_log_file)
115
116 def start_networkd(self):
ec6a4704 117 subprocess.check_call('systemctl restart systemd-networkd', shell=True)
1f0e3109
SS
118 time.sleep(5)
119
120global ip
121global port
122
123class DHCPServer(threading.Thread):
124 def __init__(self, name):
125 threading.Thread.__init__(self)
126 self.name = name
127
128 def run(self):
129 self.start_dhcp_server()
130
131 def start_dhcp_server(self):
132 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
133
134 server_address = ('0.0.0.0', 67)
135 sock.bind(server_address)
136
137 print('Starting DHCP Server ...\n')
138 data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
139
140 global ip
141 ip = addr[0]
142
143 global port
144 port = addr[1]
145 sock.close()
146
147class NetworkdNetDevTests(unittest.TestCase, Utilities):
148
149 links =['bridge99', 'bond99', 'bond99', 'vlan99', 'test1', 'macvtap99',
150 'macvlan99', 'ipvlan99', 'vxlan99', 'veth99', 'vrf99', 'tun99',
151 'tap99', 'vcan99', 'geneve99', 'dummy98', 'ipiptun99', 'sittun99',
7a3bc5a8 152 'gretap99', 'vtitun99', 'vti6tun99','ip6tnl99', 'gretun99', 'ip6gretap99', 'wg99']
1f0e3109
SS
153
154 units = ['25-bridge.netdev', '25-bond.netdev', '21-vlan.netdev', '11-dummy.netdev', '21-vlan.network',
155 '21-macvtap.netdev', 'macvtap.network', '21-macvlan.netdev', 'macvlan.network', 'vxlan.network',
156 '25-vxlan.netdev', '25-ipvlan.netdev', 'ipvlan.network', '25-veth.netdev', '25-vrf.netdev',
157 '25-tun.netdev', '25-tun.netdev', '25-vcan.netdev', '25-geneve.netdev', '25-ipip-tunnel.netdev',
158 '25-ip6tnl-tunnel.netdev', '25-ip6gre-tunnel.netdev','25-sit-tunnel.netdev', '25-gre-tunnel.netdev',
159 '25-gretap-tunnel.netdev', '25-vti-tunnel.netdev', '25-vti6-tunnel.netdev', '12-dummy.netdev',
160 'gre.network', 'ipip.network', 'ip6gretap.network', 'gretun.network', 'ip6tnl.network', '25-tap.netdev',
7a3bc5a8
EV
161 'vti6.network', 'vti.network', 'gretap.network', 'sit.network', '25-ipip-tunnel-independent.netdev',
162 '25-wireguard.netdev']
1f0e3109
SS
163
164 def setUp(self):
165 self.link_remove(self.links)
166
167 def tearDown(self):
168 self.link_remove(self.links)
169 self.remove_unit_from_networkd_path(self.units)
170
171 def test_bridge(self):
172 self.copy_unit_to_networkd_unit_path('25-bridge.netdev')
173 self.start_networkd()
174
175 self.assertTrue(self.link_exits('bridge99'))
176
177 self.assertEqual('900', self.read_link_attr('bridge99', 'bridge', 'hello_time'))
178 self.assertEqual('900', self.read_link_attr('bridge99', 'bridge', 'max_age'))
179 self.assertEqual('900', self.read_link_attr('bridge99', 'bridge','forward_delay'))
180 self.assertEqual('900', self.read_link_attr('bridge99', 'bridge','ageing_time'))
181 self.assertEqual('9', self.read_link_attr('bridge99', 'bridge','priority'))
182 self.assertEqual('1', self.read_link_attr('bridge99', 'bridge','multicast_querier'))
183 self.assertEqual('1', self.read_link_attr('bridge99', 'bridge','multicast_snooping'))
184 self.assertEqual('1', self.read_link_attr('bridge99', 'bridge','stp_state'))
185
186 def test_bond(self):
187 self.copy_unit_to_networkd_unit_path('25-bond.netdev')
188 self.start_networkd()
189
190 self.assertTrue(self.link_exits('bond99'))
191
99f68ef0
TJ
192 self.assertEqual('802.3ad 4', self.read_link_attr('bond99', 'bonding', 'mode'))
193 self.assertEqual('layer3+4 1', self.read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
194 self.assertEqual('1000', self.read_link_attr('bond99', 'bonding', 'miimon'))
195 self.assertEqual('fast 1', self.read_link_attr('bond99', 'bonding', 'lacp_rate'))
196 self.assertEqual('2000', self.read_link_attr('bond99', 'bonding', 'updelay'))
197 self.assertEqual('2000', self.read_link_attr('bond99', 'bonding', 'downdelay'))
198 self.assertEqual('4', self.read_link_attr('bond99', 'bonding', 'resend_igmp'))
199 self.assertEqual('1', self.read_link_attr('bond99', 'bonding', 'min_links'))
200 self.assertEqual('1218', self.read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
201 self.assertEqual('811', self.read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
202 self.assertEqual('00:11:22:33:44:55', self.read_link_attr('bond99', 'bonding', 'ad_actor_system'))
1f0e3109
SS
203
204 def test_vlan(self):
205 self.copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev', '21-vlan.network')
206
207 self.start_networkd()
208
209 self.assertTrue(self.link_exits('vlan99'))
210
211 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vlan99']).rstrip().decode('utf-8')
212 self.assertTrue(output, 'REORDER_HDR')
213 self.assertTrue(output, 'LOOSE_BINDING')
214 self.assertTrue(output, 'GVRP')
215 self.assertTrue(output, 'MVRP')
216 self.assertTrue(output, '99')
217
218 def test_macvtap(self):
219 self.copy_unit_to_networkd_unit_path('21-macvtap.netdev', '11-dummy.netdev', 'macvtap.network')
220
221 self.start_networkd()
222
223 self.assertTrue(self.link_exits('macvtap99'))
224
225 def test_macvlan(self):
226 self.copy_unit_to_networkd_unit_path('21-macvlan.netdev', '11-dummy.netdev', 'macvlan.network')
227
228 self.start_networkd()
229
230 self.assertTrue(self.link_exits('macvlan99'))
231
7a0a37b2 232 @expectedFailureIfModuleIsNotAvailable('ipvlan')
1f0e3109
SS
233 def test_ipvlan(self):
234 self.copy_unit_to_networkd_unit_path('25-ipvlan.netdev', '11-dummy.netdev', 'ipvlan.network')
235
236 self.start_networkd()
237
238 self.assertTrue(self.link_exits('ipvlan99'))
239
240 def test_veth(self):
241 self.copy_unit_to_networkd_unit_path('25-veth.netdev')
242
243 self.start_networkd()
244
245 self.assertTrue(self.link_exits('veth99'))
246
247 def test_dummy(self):
248 self.copy_unit_to_networkd_unit_path('11-dummy.netdev')
249
250 self.start_networkd()
251
252 self.assertTrue(self.link_exits('test1'))
253
254 def test_tun(self):
255 self.copy_unit_to_networkd_unit_path('25-tun.netdev')
256
257 self.start_networkd()
258
259 self.assertTrue(self.link_exits('tun99'))
260
261 def test_tap(self):
262 self.copy_unit_to_networkd_unit_path('25-tap.netdev')
263
264 self.start_networkd()
265
266 self.assertTrue(self.link_exits('tap99'))
267
7a0a37b2 268 @expectedFailureIfModuleIsNotAvailable('vrf')
1f0e3109
SS
269 def test_vrf(self):
270 self.copy_unit_to_networkd_unit_path('25-vrf.netdev')
271
272 self.start_networkd()
273
274 self.assertTrue(self.link_exits('vrf99'))
275
7a0a37b2 276 @expectedFailureIfModuleIsNotAvailable('vcan')
1f0e3109
SS
277 def test_vcan(self):
278 self.copy_unit_to_networkd_unit_path('25-vcan.netdev')
279
280 self.start_networkd()
281
282 self.assertTrue(self.link_exits('vcan99'))
283
7a3bc5a8
EV
284 @expectedFailureIfModuleIsNotAvailable('wireguard')
285 def test_wireguard(self):
286 self.copy_unit_to_networkd_unit_path('25-wireguard.netdev')
287
288 self.start_networkd()
289
290 if shutil.which('wg'):
291 subprocess.call('wg')
292
293 self.assertTrue(self.link_exits('wg99'))
294
1f0e3109
SS
295 def test_geneve(self):
296 self.copy_unit_to_networkd_unit_path('25-geneve.netdev')
297
298 self.start_networkd()
299
300 self.assertTrue(self.link_exits('geneve99'))
301
302 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'geneve99']).rstrip().decode('utf-8')
303 self.assertTrue(output, '192.168.22.1')
304 self.assertTrue(output, '6082')
305 self.assertTrue(output, 'udpcsum')
306 self.assertTrue(output, 'udp6zerocsumrx')
307
308 def test_ipip_tunnel(self):
309 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-ipip-tunnel.netdev', 'ipip.network')
310 self.start_networkd()
311
312 self.assertTrue(self.link_exits('dummy98'))
313 self.assertTrue(self.link_exits('ipiptun99'))
314
315 def test_gre_tunnel(self):
316 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-gre-tunnel.netdev', 'gretun.network')
317 self.start_networkd()
318
319 self.assertTrue(self.link_exits('dummy98'))
320 self.assertTrue(self.link_exits('gretun99'))
321
322 def test_gretap_tunnel(self):
323 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-gretap-tunnel.netdev', 'gretap.network')
324 self.start_networkd()
325
326 self.assertTrue(self.link_exits('dummy98'))
327 self.assertTrue(self.link_exits('gretap99'))
328
329 def test_ip6gretap_tunnel(self):
330 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-ip6gre-tunnel.netdev', 'ip6gretap.network')
331 self.start_networkd()
332
333 self.assertTrue(self.link_exits('dummy98'))
334 self.assertTrue(self.link_exits('ip6gretap99'))
335
336 def test_vti_tunnel(self):
337 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-vti-tunnel.netdev', 'vti.network')
338 self.start_networkd()
339
340 self.assertTrue(self.link_exits('dummy98'))
341 self.assertTrue(self.link_exits('vtitun99'))
342
343 def test_vti6_tunnel(self):
344 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-vti6-tunnel.netdev', 'vti6.network')
345 self.start_networkd()
346
347 self.assertTrue(self.link_exits('dummy98'))
348 self.assertTrue(self.link_exits('vti6tun99'))
349
350 def test_ip6tnl_tunnel(self):
351 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-ip6tnl-tunnel.netdev', 'ip6tnl.network')
352 self.start_networkd()
353
354 self.assertTrue(self.link_exits('dummy98'))
355 self.assertTrue(self.link_exits('ip6tnl99'))
356
357 def test_sit_tunnel(self):
358 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-sit-tunnel.netdev', 'sit.network')
359 self.start_networkd()
360
361 self.assertTrue(self.link_exits('dummy98'))
362 self.assertTrue(self.link_exits('sittun99'))
363
364 def test_tunnel_independent(self):
365 self.copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev')
366
367 self.start_networkd()
368 self.assertTrue(self.link_exits('ipiptun99'))
369
370 def test_vxlan(self):
371 self.copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network','11-dummy.netdev')
372
373 self.start_networkd()
374
375 self.assertTrue(self.link_exits('vxlan99'))
376
377 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vxlan99']).rstrip().decode('utf-8')
378 self.assertRegex(output, "999")
379 self.assertRegex(output, '5555')
380 self.assertRegex(output, 'l2miss')
381 self.assertRegex(output, 'l3miss')
382 self.assertRegex(output, 'udpcsum')
383 self.assertRegex(output, 'udp6zerocsumtx')
384 self.assertRegex(output, 'udp6zerocsumrx')
385 self.assertRegex(output, 'remcsumtx')
386 self.assertRegex(output, 'remcsumrx')
387 self.assertRegex(output, 'gbp')
388
389class NetworkdNetWorkTests(unittest.TestCase, Utilities):
390 links = ['dummy98', 'test1', 'bond199']
391
392 units = ['12-dummy.netdev', 'test-static.network', 'configure-without-carrier.network', '11-dummy.netdev',
393 '23-primary-slave.network', '23-test1-bond199.network', '11-dummy.netdev', '23-bond199.network',
394 '25-bond-active-backup-slave.netdev', '12-dummy.netdev', '23-active-slave.network',
395 'routing-policy-rule.network', '25-address-section.network', '25-address-section-miscellaneous.network',
396 '25-route-section.network', '25-route-type.network', '25-route-tcp-window-settings.network',
397 '25-address-link-section.network', '25-ipv6-address-label-section.network', '25-link-section-unmanaged.network',
398 '25-sysctl.network']
399
400 def setUp(self):
401 self.link_remove(self.links)
402
403 def tearDown(self):
404 self.link_remove(self.links)
405 self.remove_unit_from_networkd_path(self.units)
406
407 def test_static_address(self):
408 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'test-static.network')
409 self.start_networkd()
410
411 self.assertTrue(self.link_exits('dummy98'))
412 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
413 print(output)
414 self.assertRegex(output, '192.168.0.15')
415 self.assertRegex(output, '192.168.0.1')
416 self.assertRegex(output, 'routable')
417
418 def test_configure_without_carrier(self):
419 self.copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
420 self.start_networkd()
421
422 self.assertTrue(self.link_exits('test1'))
423 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
424 print(output)
425 self.assertRegex(output, '192.168.0.15')
426 self.assertRegex(output, '192.168.0.1')
427 self.assertRegex(output, 'routable')
428
429 def test_bond_active_slave(self):
430 self.copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
431 self.start_networkd()
432
433 self.assertTrue(self.link_exits('dummy98'))
434 self.assertTrue(self.link_exits('bond199'))
435 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond199']).rstrip().decode('utf-8')
436 print(output)
437 self.assertRegex(output, 'active_slave dummy98')
438
439 def test_bond_primary_slave(self):
440 self.copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-test1-bond199.network', '25-bond-active-backup-slave.netdev', '11-dummy.netdev')
441 self.start_networkd()
442
443 self.assertTrue(self.link_exits('test1'))
444 self.assertTrue(self.link_exits('bond199'))
445 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond199']).rstrip().decode('utf-8')
446 print(output)
447 self.assertRegex(output, 'primary test1')
448
449 def test_routing_policy_rule(self):
450 self.copy_unit_to_networkd_unit_path('routing-policy-rule.network', '11-dummy.netdev')
451 self.start_networkd()
452
453 self.assertTrue(self.link_exits('test1'))
454 output = subprocess.check_output(['ip', 'rule']).rstrip().decode('utf-8')
455 print(output)
456 self.assertRegex(output, '111')
457 self.assertRegex(output, 'from 192.168.100.18')
f7bdd562 458 self.assertRegex(output, r'tos (?:0x08|throughput)\s')
1f0e3109
SS
459 self.assertRegex(output, 'iif test1')
460 self.assertRegex(output, 'oif test1')
461 self.assertRegex(output, 'lookup 7')
462
463 def test_address_preferred_lifetime_zero_ipv6(self):
464 self.copy_unit_to_networkd_unit_path('25-address-section-miscellaneous.network', '12-dummy.netdev')
465 self.start_networkd()
466
467 self.assertTrue(self.link_exits('dummy98'))
468
469 output = subprocess.check_output(['ip', 'address', 'show', 'dummy98']).rstrip().decode('utf-8')
470 print(output)
471 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
472 self.assertRegex(output, 'inet6 2001:db8:0:f101::1/64 scope global')
473
474 def test_ip_route(self):
475 self.copy_unit_to_networkd_unit_path('25-route-section.network', '12-dummy.netdev')
476 self.start_networkd()
477
478 self.assertTrue(self.link_exits('dummy98'))
479
480 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98']).rstrip().decode('utf-8')
481 print(output)
482 self.assertRegex(output, '192.168.0.1')
483 self.assertRegex(output, 'static')
484 self.assertRegex(output, '192.168.0.0/24')
485
486 def test_ip_route_blackhole_unreachable_prohibit(self):
487 self.copy_unit_to_networkd_unit_path('25-route-type.network', '12-dummy.netdev')
488 self.start_networkd()
489
490 self.assertTrue(self.link_exits('dummy98'))
491
492 output = subprocess.check_output(['ip', 'route', 'list']).rstrip().decode('utf-8')
493 print(output)
494 self.assertRegex(output, 'blackhole')
495 self.assertRegex(output, 'unreachable')
496 self.assertRegex(output, 'prohibit')
497
498 subprocess.call(['ip', 'route', 'del', 'blackhole', '202.54.1.2'])
499 subprocess.call(['ip', 'route', 'del', 'unreachable', '202.54.1.3'])
500 subprocess.call(['ip', 'route', 'del', 'prohibit', '202.54.1.4'])
501
502 def test_ip_route_tcp_window(self):
503 self.copy_unit_to_networkd_unit_path('25-route-tcp-window-settings.network', '11-dummy.netdev')
504 self.start_networkd()
505
506 self.assertTrue(self.link_exits('test1'))
507
508 output = subprocess.check_output(['ip', 'route', 'list']).rstrip().decode('utf-8')
509 print(output)
510 self.assertRegex(output, 'initcwnd 20')
511 self.assertRegex(output, 'initrwnd 30')
512
513 def test_ip_link_mac_address(self):
514 self.copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
515 self.start_networkd()
516
517 self.assertTrue(self.link_exits('dummy98'))
518
519 output = subprocess.check_output(['ip', 'link', 'show', 'dummy98']).rstrip().decode('utf-8')
520 print(output)
521 self.assertRegex(output, '00:01:02:aa:bb:cc')
522
523 def test_ip_link_unmanaged(self):
524 self.copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
525 self.start_networkd()
526
527 self.assertTrue(self.link_exits('dummy98'))
528
529 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
530 print(output)
531 self.assertRegex(output, 'unmanaged')
532
533 def test_ipv6_address_label(self):
534 self.copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
535 self.start_networkd()
536
537 self.assertTrue(self.link_exits('dummy98'))
538
539 output = subprocess.check_output(['ip', 'addrlabel', 'list']).rstrip().decode('utf-8')
540 print(output)
541 self.assertRegex(output, '2004:da8:1::/64')
542
543 def test_sysctl(self):
544 self.copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
545 self.start_networkd()
546
547 self.assertTrue(self.link_exits('dummy98'))
548
549 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
550 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
551 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
552 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
553 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
554 self.assertEqual(self.read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
555 self.assertEqual(self.read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
556
557class NetworkdNetWorkBrideTests(unittest.TestCase, Utilities):
558 links = ['dummy98', 'test1', 'bridge99']
559
560 units = ['11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev', '26-bridge-slave-interface-1.network',
561 '26-bridge-slave-interface-2.network', 'bridge99.network']
562
563 def setUp(self):
564 self.link_remove(self.links)
565
566 def tearDown(self):
567 self.link_remove(self.links)
568 self.remove_unit_from_networkd_path(self.units)
569
570 def test_bridge_property(self):
571 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
572 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
573 'bridge99.network')
574 self.start_networkd()
575
576 self.assertTrue(self.link_exits('dummy98'))
577 self.assertTrue(self.link_exits('test1'))
578 self.assertTrue(self.link_exits('bridge99'))
579
580 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1']).rstrip().decode('utf-8')
581 print(output)
582 self.assertRegex(output, 'master')
583 self.assertRegex(output, 'bridge')
584
585 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'dummy98']).rstrip().decode('utf-8')
586 print(output)
587 self.assertRegex(output, 'master')
588 self.assertRegex(output, 'bridge')
589
590 output = subprocess.check_output(['ip', 'addr', 'show', 'bridge99']).rstrip().decode('utf-8')
591 print(output)
592 self.assertRegex(output, '192.168.0.15')
593 self.assertRegex(output, '192.168.0.1')
594
595 output = subprocess.check_output(['bridge', '-d', 'link', 'show', 'dummy98']).rstrip().decode('utf-8')
596 print(output)
597 self.assertRegex(output, 'cost 400')
598 self.assertRegex(output, 'hairpin on')
599 self.assertRegex(output, 'flood on')
600 self.assertRegex(output, 'fastleave on')
601
602class NetworkdNetWorkLLDPTests(unittest.TestCase, Utilities):
603 links = ['veth99']
604
605 units = ['23-emit-lldp.network', '24-lldp.network', '25-veth.netdev']
606
607 def setUp(self):
608 self.link_remove(self.links)
609
610 def tearDown(self):
611 self.link_remove(self.links)
612 self.remove_unit_from_networkd_path(self.units)
613
614 def test_lldp(self):
615 self.copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
616 self.start_networkd()
617
618 self.assertTrue(self.link_exits('veth99'))
619
620 output = subprocess.check_output(['networkctl', 'lldp']).rstrip().decode('utf-8')
621 print(output)
622 self.assertRegex(output, 'veth-peer')
623 self.assertRegex(output, 'veth99')
624
625class NetworkdNetworkRATests(unittest.TestCase, Utilities):
626 links = ['veth99']
627
628 units = ['25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network']
629
630 def setUp(self):
631 self.link_remove(self.links)
632
633 def tearDown(self):
634 self.link_remove(self.links)
635 self.remove_unit_from_networkd_path(self.units)
636
637 def test_ipv6_prefix_delegation(self):
638 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
639 self.start_networkd()
640
641 self.assertTrue(self.link_exits('veth99'))
642
643 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
644 print(output)
645 self.assertRegex(output, '2002:da8:1:0')
646
647class NetworkdNetworkDHCPServerTests(unittest.TestCase, Utilities):
648 links = ['veth99', 'dummy98']
649
650 units = ['25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network', '12-dummy.netdev', '24-search-domain.network',
651 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network']
652
653 def setUp(self):
654 self.link_remove(self.links)
655
656 def tearDown(self):
657 self.link_remove(self.links)
658 self.remove_unit_from_networkd_path(self.units)
659
660 def test_dhcp_server(self):
661 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
662 self.start_networkd()
663
664 self.assertTrue(self.link_exits('veth99'))
665
666 time.sleep(5)
667
668 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
669 print(output)
670 self.assertRegex(output, '192.168.5.*')
671 self.assertRegex(output, 'Gateway: 192.168.5.1')
672 self.assertRegex(output, 'DNS: 192.168.5.1')
673 self.assertRegex(output, 'NTP: 192.168.5.1')
674
675 def test_domain(self):
676 self.copy_unit_to_networkd_unit_path( '12-dummy.netdev', '24-search-domain.network')
677 self.start_networkd()
678
679 self.assertTrue(self.link_exits('dummy98'))
680
681 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
682 print(output)
683 self.assertRegex(output, 'Address: 192.168.42.100')
684 self.assertRegex(output, 'DNS: 192.168.42.1')
685 self.assertRegex(output, 'Search Domains: one')
686
687 def test_emit_router_timezone(self):
688 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
689 self.start_networkd()
690
691 self.assertTrue(self.link_exits('veth99'))
692
693 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
694 print(output)
695 self.assertRegex(output, 'Gateway: 192.168.5.*')
696 self.assertRegex(output, '192.168.5.*')
697 self.assertRegex(output, 'Europe/Berlin')
698
699class NetworkdNetworkDHCPClientTests(unittest.TestCase, Utilities):
700 links = ['veth99', 'dummy98']
701
702 units = ['25-veth.netdev', 'dhcp-server-veth-peer.network','dhcp-client-ipv6-only.network',
703 'dhcp-client-ipv4-only-ipv6-disabled.network', 'dhcp-client-ipv4-only.network',
704 'dhcp-client-ipv4-dhcp-settings.network', 'dhcp-client-anonymize.network',
705 'dhcp-client-ipv6-rapid-commit.network', 'dhcp-client-route-table.network',
706 'dhcp-v4-server-veth-peer.network', 'dhcp-client-listen-port.network',
707 'dhcp-client-route-metric.network', 'dhcp-client-critical-connection.network']
708
709 def setUp(self):
710 self.link_remove(self.links)
711 self.stop_dnsmasq(dnsmasq_pid_file)
712
713 def tearDown(self):
714 self.link_remove(self.links)
715 self.remove_unit_from_networkd_path(self.units)
716 self.stop_dnsmasq(dnsmasq_pid_file)
717 self.remove_lease_file()
718 self.remove_log_file()
719
720 def test_dhcp_client_ipv6_only(self):
721 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network','dhcp-client-ipv6-only.network')
722 self.start_networkd()
723
724 self.assertTrue(self.link_exits('veth99'))
725
726 self.start_dnsmasq()
727
728 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
729 print(output)
730 self.assertRegex(output, '2600::')
731 self.assertNotRegex(output, '192.168.5')
732
733 def test_dhcp_client_ipv4_only(self):
734 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network','dhcp-client-ipv4-only-ipv6-disabled.network')
735 self.start_networkd()
736
737 self.assertTrue(self.link_exits('veth99'))
738
739 self.start_dnsmasq()
740
741 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
742 print(output)
743 self.assertNotRegex(output, '2600::')
744 self.assertRegex(output, '192.168.5')
745
746 def test_dhcp_client_ipv4_ipv6(self):
747 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
748 'dhcp-client-ipv4-only.network')
749 self.start_networkd()
750
751 self.assertTrue(self.link_exits('veth99'))
752
753 self.start_dnsmasq()
754
755 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
756 print(output)
757 self.assertRegex(output, '2600::')
758 self.assertRegex(output, '192.168.5')
759
760 def test_dhcp_client_settings(self):
761 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
762 self.start_networkd()
763
764 self.assertTrue(self.link_exits('veth99'))
765
766 self.start_dnsmasq()
767
768 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
769 print(output)
770 self.assertRegex(output, '12:34:56:78:9a:bc')
771 self.assertRegex(output, '192.168.5')
772 self.assertRegex(output, '1492')
773
774 output = subprocess.check_output(['ip', 'route']).rstrip().decode('utf-8')
775 print(output)
776 self.assertRegex(output, 'default.*dev veth99 proto dhcp')
777
778 self.search_words_in_file('vendor class: SusantVendorTest')
779 self.search_words_in_file('client MAC address: 12:34:56:78:9a:bc')
780 self.search_words_in_file('client provides name: test-hostname')
781 self.search_words_in_file('26:mtu')
782
783 def test_dhcp6_client_settings_rapidcommit_true(self):
784 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
785 self.start_networkd()
786
787 self.assertTrue(self.link_exits('veth99'))
788
789 self.start_dnsmasq()
790
791 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
792 print(output)
793 self.assertRegex(output, '12:34:56:78:9a:bc')
794
795 self.assertTrue(self.search_words_in_file('14:rapid-commit'))
796
797 def test_dhcp6_client_settings_rapidcommit_false(self):
798 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
799 self.start_networkd()
800
801 self.assertTrue(self.link_exits('veth99'))
802
803 self.start_dnsmasq()
804
805 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
806 print(output)
807 self.assertRegex(output, '12:34:56:78:9a:bc')
808
809 self.assertFalse(self.search_words_in_file('14:rapid-commit'))
810
811 def test_dhcp_client_settings_anonymize(self):
812 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
813 self.start_networkd()
814
815 self.assertTrue(self.link_exits('veth99'))
816
817 self.start_dnsmasq()
818 self.assertFalse(self.search_words_in_file('VendorClassIdentifier=SusantVendorTest'))
819 self.assertFalse(self.search_words_in_file('test-hostname'))
820 self.assertFalse(self.search_words_in_file('26:mtu'))
821
822 def test_dhcp_client_listen_port(self):
823 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
824 dh_server = DHCPServer("dhcp_server")
825 dh_server.start()
826
827 self.start_networkd()
828
829 self.assertTrue(self.link_exits('veth99'))
830
831 global port
832 global ip
833
834 self.assertRegex(str(port), '5555')
835 self.assertRegex(str(ip), '0.0.0.0')
836
837 dh_server.join()
838
839 def test_dhcp_route_table_id(self):
840 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
841 self.start_networkd()
842 self.start_dnsmasq()
843
844 self.assertTrue(self.link_exits('veth99'))
845
846 output = subprocess.check_output(['ip', 'route', 'show', 'table', '12']).rstrip().decode('utf-8')
847 print(output)
848
849 self.assertRegex(output, 'veth99 proto dhcp')
850 self.assertRegex(output, '192.168.5.1')
851
852 def test_dhcp_route_metric(self):
853 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
854 self.start_networkd()
855 self.start_dnsmasq()
856
857 self.assertTrue(self.link_exits('veth99'))
858
859 output = subprocess.check_output(['ip', 'route', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
860 print(output)
861
862 self.assertRegex(output, 'metric 24')
863
864 def test_dhcp_route_criticalconnection_true(self):
865 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-critical-connection.network')
866 self.start_networkd()
867 self.start_dnsmasq()
868
869 self.assertTrue(self.link_exits('veth99'))
870
871 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
872 print(output)
873
874 self.assertRegex(output, '192.168.5.*')
875 # Stoping dnsmasq as networkd won't be allowed to renew the DHCP lease.
876 self.stop_dnsmasq(dnsmasq_pid_file)
877
878 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
879 time.sleep(125)
880
881 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
882 print(output)
883 self.assertRegex(output, '192.168.5.*')
884
885if __name__ == '__main__':
886 unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout,
887 verbosity=3))