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