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