]> git.ipfire.org Git - thirdparty/systemd.git/blame - test/test-network/systemd-networkd-tests.py
logind: don't print warning when user@.service template is masked
[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')
662 self.start_networkd()
663
664 self.assertTrue(self.link_exits('test1'))
e40a58b5 665
1f0e3109
SS
666 output = subprocess.check_output(['ip', 'rule']).rstrip().decode('utf-8')
667 print(output)
668 self.assertRegex(output, '111')
669 self.assertRegex(output, 'from 192.168.100.18')
f7bdd562 670 self.assertRegex(output, r'tos (?:0x08|throughput)\s')
1f0e3109
SS
671 self.assertRegex(output, 'iif test1')
672 self.assertRegex(output, 'oif test1')
673 self.assertRegex(output, 'lookup 7')
674
e4eacdb0
YW
675 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
676
d586a2c3 677 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
926062f0
SS
678 def test_routing_policy_rule_port_range(self):
679 self.copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
680 self.start_networkd()
681
682 self.assertTrue(self.link_exits('test1'))
e40a58b5 683
926062f0
SS
684 output = subprocess.check_output(['ip', 'rule']).rstrip().decode('utf-8')
685 print(output)
686 self.assertRegex(output, '111')
687 self.assertRegex(output, 'from 192.168.100.18')
688 self.assertRegex(output, '1123-1150')
689 self.assertRegex(output, '3224-3290')
690 self.assertRegex(output, 'tcp')
691 self.assertRegex(output, 'lookup 7')
1f0e3109 692
e4eacdb0
YW
693 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
694
d586a2c3 695 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
efecf9cd
SS
696 def test_routing_policy_rule_invert(self):
697 self.copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
698 self.start_networkd()
699
700 self.assertTrue(self.link_exits('test1'))
e40a58b5 701
efecf9cd
SS
702 output = subprocess.check_output(['ip', 'rule']).rstrip().decode('utf-8')
703 print(output)
efecf9cd
SS
704 self.assertRegex(output, '111')
705 self.assertRegex(output, 'not.*?from.*?192.168.100.18')
706 self.assertRegex(output, 'tcp')
707 self.assertRegex(output, 'lookup 7')
708
e4eacdb0
YW
709 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
710
ac60877f
YW
711 def test_address_peer(self):
712 self.copy_unit_to_networkd_unit_path('25-address-section.network', '12-dummy.netdev')
713 self.start_networkd()
714
715 self.assertTrue(self.link_exits('dummy98'))
716
717 output = subprocess.check_output(['ip', 'address', 'show', 'dummy98']).rstrip().decode('utf-8')
718 print(output)
719 self.assertRegex(output, 'inet 10.2.3.4 peer 10.2.3.5/16 scope global 32')
720 self.assertRegex(output, 'inet 10.6.7.8/16 brd 10.6.255.255 scope global 33')
7e663619 721 self.assertRegex(output, 'inet6 2001:db8::20 peer 2001:db8::10/128 scope global')
ac60877f
YW
722
723 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
724 print(output)
725 self.assertRegex(output, 'State: routable \(configured\)')
726
1f0e3109
SS
727 def test_address_preferred_lifetime_zero_ipv6(self):
728 self.copy_unit_to_networkd_unit_path('25-address-section-miscellaneous.network', '12-dummy.netdev')
729 self.start_networkd()
730
731 self.assertTrue(self.link_exits('dummy98'))
732
733 output = subprocess.check_output(['ip', 'address', 'show', 'dummy98']).rstrip().decode('utf-8')
734 print(output)
735 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
736 self.assertRegex(output, 'inet6 2001:db8:0:f101::1/64 scope global')
737
738 def test_ip_route(self):
739 self.copy_unit_to_networkd_unit_path('25-route-section.network', '12-dummy.netdev')
740 self.start_networkd()
741
742 self.assertTrue(self.link_exits('dummy98'))
743
744 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98']).rstrip().decode('utf-8')
745 print(output)
746 self.assertRegex(output, '192.168.0.1')
747 self.assertRegex(output, 'static')
748 self.assertRegex(output, '192.168.0.0/24')
749
0d34228f
SS
750 def test_ip_route_reverse(self):
751 self.copy_unit_to_networkd_unit_path('25-route-reverse-order.network', '12-dummy.netdev')
752 self.start_networkd()
753
754 self.assertTrue(self.link_exits('dummy98'))
755
756 output = subprocess.check_output(['ip', '-6', 'route', 'show', 'dev', 'dummy98']).rstrip().decode('utf-8')
757 print(output)
758 self.assertRegex(output, '2001:1234:5:8fff:ff:ff:ff:ff')
759 self.assertRegex(output, '2001:1234:5:8f63::1')
760
1f0e3109
SS
761 def test_ip_route_blackhole_unreachable_prohibit(self):
762 self.copy_unit_to_networkd_unit_path('25-route-type.network', '12-dummy.netdev')
763 self.start_networkd()
764
765 self.assertTrue(self.link_exits('dummy98'))
766
767 output = subprocess.check_output(['ip', 'route', 'list']).rstrip().decode('utf-8')
768 print(output)
769 self.assertRegex(output, 'blackhole')
770 self.assertRegex(output, 'unreachable')
771 self.assertRegex(output, 'prohibit')
772
773 subprocess.call(['ip', 'route', 'del', 'blackhole', '202.54.1.2'])
774 subprocess.call(['ip', 'route', 'del', 'unreachable', '202.54.1.3'])
775 subprocess.call(['ip', 'route', 'del', 'prohibit', '202.54.1.4'])
776
777 def test_ip_route_tcp_window(self):
778 self.copy_unit_to_networkd_unit_path('25-route-tcp-window-settings.network', '11-dummy.netdev')
779 self.start_networkd()
780
781 self.assertTrue(self.link_exits('test1'))
782
783 output = subprocess.check_output(['ip', 'route', 'list']).rstrip().decode('utf-8')
784 print(output)
785 self.assertRegex(output, 'initcwnd 20')
786 self.assertRegex(output, 'initrwnd 30')
787
f5050e48
YW
788 def test_ip_route_gateway(self):
789 self.copy_unit_to_networkd_unit_path('25-route-gateway.network', '12-dummy.netdev')
790 self.start_networkd()
791
792 self.assertTrue(self.link_exits('dummy98'))
793
794 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98', 'default']).rstrip().decode('utf-8')
795 print(output)
796 self.assertRegex(output, 'default')
797 self.assertRegex(output, 'via')
798 self.assertRegex(output, '149.10.124.64')
799 self.assertRegex(output, 'proto')
800 self.assertRegex(output, 'static')
801
802 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98', 'src', '149.10.124.58']).rstrip().decode('utf-8')
803 print(output)
804 self.assertRegex(output, '149.10.124.48/28')
805 self.assertRegex(output, 'proto')
806 self.assertRegex(output, 'kernel')
807 self.assertRegex(output, 'scope')
808 self.assertRegex(output, 'link')
809
810 def test_ip_route_gateway_on_link(self):
811 self.copy_unit_to_networkd_unit_path('25-route-gateway-on-link.network', '12-dummy.netdev')
812 self.start_networkd()
813
814 self.assertTrue(self.link_exits('dummy98'))
815
816 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98', 'default']).rstrip().decode('utf-8')
817 print(output)
818 self.assertRegex(output, 'default')
819 self.assertRegex(output, 'via')
820 self.assertRegex(output, '149.10.125.65')
821 self.assertRegex(output, 'proto')
822 self.assertRegex(output, 'static')
823 self.assertRegex(output, 'onlink')
824
825 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98', 'src', '149.10.124.58']).rstrip().decode('utf-8')
826 print(output)
827 self.assertRegex(output, '149.10.124.48/28')
828 self.assertRegex(output, 'proto')
829 self.assertRegex(output, 'kernel')
830 self.assertRegex(output, 'scope')
831 self.assertRegex(output, 'link')
832
20ca06a6
DA
833 def test_ip_route_ipv6_src_route(self):
834 # a dummy device does not make the addresses go through tentative state, so we
835 # reuse a bond from an earlier test, which does make the addresses go through
836 # tentative state, and do our test on that
837 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')
838 self.start_networkd()
839
840 self.assertTrue(self.link_exits('dummy98'))
841 self.assertTrue(self.link_exits('bond199'))
842
843 output = subprocess.check_output(['ip', '-6', 'route', 'list', 'dev', 'bond199']).rstrip().decode('utf-8')
844 print(output)
845 self.assertRegex(output, 'abcd::/16')
846 self.assertRegex(output, 'src')
847 self.assertRegex(output, '2001:1234:56:8f63::2')
848
1f0e3109
SS
849 def test_ip_link_mac_address(self):
850 self.copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
851 self.start_networkd()
852
853 self.assertTrue(self.link_exits('dummy98'))
854
855 output = subprocess.check_output(['ip', 'link', 'show', 'dummy98']).rstrip().decode('utf-8')
856 print(output)
857 self.assertRegex(output, '00:01:02:aa:bb:cc')
858
859 def test_ip_link_unmanaged(self):
860 self.copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
861 self.start_networkd()
862
863 self.assertTrue(self.link_exits('dummy98'))
864
865 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
866 print(output)
867 self.assertRegex(output, 'unmanaged')
868
869 def test_ipv6_address_label(self):
870 self.copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
871 self.start_networkd()
872
873 self.assertTrue(self.link_exits('dummy98'))
874
875 output = subprocess.check_output(['ip', 'addrlabel', 'list']).rstrip().decode('utf-8')
876 print(output)
877 self.assertRegex(output, '2004:da8:1::/64')
878
e4a71bf3
WKI
879 def test_ipv6_neighbor(self):
880 self.copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
881 self.start_networkd()
882
883 self.assertTrue(self.link_exits('dummy98'))
884
885 output = subprocess.check_output(['ip', 'neigh', 'list']).rstrip().decode('utf-8')
886 print(output)
887 self.assertRegex(output, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
094b5479 888 self.assertRegex(output, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
e4a71bf3 889
05514ae1
YW
890 def test_link_local_addressing(self):
891 self.copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
892 '25-link-local-addressing-no.network', '12-dummy.netdev')
893 self.start_networkd()
894
895 self.assertTrue(self.link_exits('test1'))
896 self.assertTrue(self.link_exits('dummy98'))
897
898 time.sleep(10)
899
900 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'test1']).rstrip().decode('utf-8')
901 print(output)
902 self.assertRegex(output, 'inet .* scope link')
903 self.assertRegex(output, 'inet6 .* scope link')
904
905 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'dummy98']).rstrip().decode('utf-8')
906 print(output)
907 self.assertNotRegex(output, 'inet6* .* scope link')
908
909 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
910 print(output)
911 self.assertRegex(output, 'State: degraded \(configured\)')
912
913 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
914 print(output)
915 self.assertRegex(output, 'State: carrier \(configured\)')
916
917 '''
918 Documentation/networking/ip-sysctl.txt
919
920 addr_gen_mode - INTEGER
921 Defines how link-local and autoconf addresses are generated.
922
923 0: generate address based on EUI64 (default)
924 1: do no generate a link-local address, use EUI64 for addresses generated
925 from autoconf
926 2: generate stable privacy addresses, using the secret from
927 stable_secret (RFC7217)
928 3: generate stable privacy addresses, using a random secret if unset
929 '''
930
931 test1_addr_gen_mode = ''
932 if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'stable_secret')):
933 with open(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'stable_secret')) as f:
934 try:
935 f.readline()
936 except IOError:
937 # if stable_secret is unset, then EIO is returned
938 test1_addr_gen_mode = '0'
939 else:
940 test1_addr_gen_mode = '2'
941 else:
942 test1_addr_gen_mode = '0'
943
944 if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'addr_gen_mode')):
945 self.assertEqual(self.read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), '0')
946
947 if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'dummy98'), 'addr_gen_mode')):
948 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
949
1f0e3109
SS
950 def test_sysctl(self):
951 self.copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
952 self.start_networkd()
953
954 self.assertTrue(self.link_exits('dummy98'))
955
956 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
957 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
958 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
959 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
960 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
961 self.assertEqual(self.read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
962 self.assertEqual(self.read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
963
4da33154
YW
964 def test_sysctl_disable_ipv6(self):
965 self.copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
966
967 print('## Disable ipv6')
968 self.assertEqual(subprocess.call(['sysctl', 'net.ipv6.conf.all.disable_ipv6=1']), 0)
969 self.assertEqual(subprocess.call(['sysctl', 'net.ipv6.conf.default.disable_ipv6=1']), 0)
970
971 self.start_networkd()
972
973 self.assertTrue(self.link_exits('dummy98'))
974
975 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dummy98']).rstrip().decode('utf-8')
976 print(output)
977 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
978 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dummy98']).rstrip().decode('utf-8')
979 print(output)
980 self.assertEqual(output, '')
981 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
982 self.assertRegex(output, 'State: routable \(configured\)')
983
984 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
985
986 print('## Enable ipv6')
987 self.assertEqual(subprocess.call(['sysctl', 'net.ipv6.conf.all.disable_ipv6=0']), 0)
988 self.assertEqual(subprocess.call(['sysctl', 'net.ipv6.conf.default.disable_ipv6=0']), 0)
989
990 self.start_networkd()
991
992 self.assertTrue(self.link_exits('dummy98'))
993
994 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dummy98']).rstrip().decode('utf-8')
995 print(output)
996 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
997 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dummy98']).rstrip().decode('utf-8')
998 print(output)
999 self.assertRegex(output, 'inet6 .* scope link')
1000 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
1001 self.assertRegex(output, 'State: routable \(configured\)')
1002
cd65d067
YW
1003 def test_bind_carrier(self):
1004 self.copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
1005 self.start_networkd()
1006
1007 self.assertTrue(self.link_exits('test1'))
1008
cd65d067
YW
1009 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1010 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
b117044c 1011 time.sleep(2)
cd65d067
YW
1012 output = subprocess.check_output(['ip', 'address', 'show', 'test1']).rstrip().decode('utf-8')
1013 print(output)
1014 self.assertRegex(output, 'UP,LOWER_UP')
1015 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1016 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
1017 self.assertRegex(output, 'State: routable \(configured\)')
1018
1019 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy99', 'type', 'dummy']), 0)
1020 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy99', 'up']), 0)
b117044c 1021 time.sleep(2)
cd65d067
YW
1022 output = subprocess.check_output(['ip', 'address', 'show', 'test1']).rstrip().decode('utf-8')
1023 print(output)
1024 self.assertRegex(output, 'UP,LOWER_UP')
1025 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1026 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
1027 self.assertRegex(output, 'State: routable \(configured\)')
1028
1029 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 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', 'dummy99']), 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.assertNotRegex(output, 'UP,LOWER_UP')
1043 self.assertRegex(output, 'DOWN')
1044 self.assertNotRegex(output, '192.168.10')
1045 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
1046 self.assertRegex(output, 'State: off \(configured\)')
1047
1048 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1049 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
b117044c 1050 time.sleep(2)
cd65d067
YW
1051 output = subprocess.check_output(['ip', 'address', 'show', 'test1']).rstrip().decode('utf-8')
1052 print(output)
1053 self.assertRegex(output, 'UP,LOWER_UP')
1054 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1055 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
1056 self.assertRegex(output, 'State: routable \(configured\)')
1057
c3a8853f
YW
1058class NetworkdNetWorkBondTests(unittest.TestCase, Utilities):
1059 links = [
1060 'bond99',
1061 'veth99']
1062
1063 units = [
1064 '25-bond.netdev',
1065 '25-veth.netdev',
1066 'bond99.network',
1067 'dhcp-server.network',
1068 'veth-bond.network']
1069
1070 def setUp(self):
1071 self.link_remove(self.links)
1072
1073 def tearDown(self):
1074 self.link_remove(self.links)
1075 self.remove_unit_from_networkd_path(self.units)
1076
1077 def test_bridge_property(self):
1078 self.copy_unit_to_networkd_unit_path('25-bond.netdev', '25-veth.netdev', 'bond99.network',
1079 'dhcp-server.network', 'veth-bond.network')
1080 self.start_networkd()
1081
1082 self.assertTrue(self.link_exits('bond99'))
1083 self.assertTrue(self.link_exits('veth99'))
1084 self.assertTrue(self.link_exits('veth-peer'))
1085
1086 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'veth-peer']).rstrip().decode('utf-8')
1087 print(output)
1088 self.assertRegex(output, 'UP,LOWER_UP')
1089
1090 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'veth99']).rstrip().decode('utf-8')
1091 print(output)
1092 self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
1093
1094 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond99']).rstrip().decode('utf-8')
1095 print(output)
1096 self.assertRegex(output, 'MASTER,UP,LOWER_UP')
1097
1098 output = subprocess.check_output(['networkctl', 'status', 'veth-peer']).rstrip().decode('utf-8')
1099 print(output)
1100 self.assertRegex(output, 'State: routable \(configured\)')
1101
1102 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1103 print(output)
1104 self.assertRegex(output, 'State: enslaved \(configured\)')
1105
1106 output = subprocess.check_output(['networkctl', 'status', 'bond99']).rstrip().decode('utf-8')
1107 print(output)
1108 self.assertRegex(output, 'State: routable \(configured\)')
1109
1110 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'veth99', 'down']), 0)
1111 time.sleep(2)
1112
1113 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1114 print(output)
1115 self.assertRegex(output, 'State: off \(configured\)')
1116
1117 output = subprocess.check_output(['networkctl', 'status', 'bond99']).rstrip().decode('utf-8')
1118 print(output)
1119 self.assertRegex(output, 'State: degraded \(configured\)')
1120
1121 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'veth99', 'up']), 0)
1122 time.sleep(2)
1123
1124 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1125 print(output)
1126 self.assertRegex(output, 'State: enslaved \(configured\)')
1127
1128 output = subprocess.check_output(['networkctl', 'status', 'bond99']).rstrip().decode('utf-8')
1129 print(output)
1130 self.assertRegex(output, 'State: routable \(configured\)')
1131
14dc0335 1132class NetworkdNetWorkBridgeTests(unittest.TestCase, Utilities):
09ea6724
YW
1133 links = [
1134 'bridge99',
1135 'dummy98',
1136 'test1']
1137
1138 units = [
1139 '11-dummy.netdev',
1140 '12-dummy.netdev',
1141 '26-bridge.netdev',
1142 '26-bridge-slave-interface-1.network',
1143 '26-bridge-slave-interface-2.network',
804b6cd2 1144 'bridge99-ignore-carrier-loss.network',
09ea6724 1145 'bridge99.network']
1f0e3109
SS
1146
1147 def setUp(self):
1148 self.link_remove(self.links)
1149
1150 def tearDown(self):
1151 self.link_remove(self.links)
1152 self.remove_unit_from_networkd_path(self.units)
1153
1154 def test_bridge_property(self):
1155 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1156 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1157 'bridge99.network')
1158 self.start_networkd()
1159
1160 self.assertTrue(self.link_exits('dummy98'))
1161 self.assertTrue(self.link_exits('test1'))
1162 self.assertTrue(self.link_exits('bridge99'))
1163
1164 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1']).rstrip().decode('utf-8')
1165 print(output)
1166 self.assertRegex(output, 'master')
1167 self.assertRegex(output, 'bridge')
1168
1169 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'dummy98']).rstrip().decode('utf-8')
1170 print(output)
1171 self.assertRegex(output, 'master')
1172 self.assertRegex(output, 'bridge')
1173
1174 output = subprocess.check_output(['ip', 'addr', 'show', 'bridge99']).rstrip().decode('utf-8')
1175 print(output)
1176 self.assertRegex(output, '192.168.0.15')
1177 self.assertRegex(output, '192.168.0.1')
1178
1179 output = subprocess.check_output(['bridge', '-d', 'link', 'show', 'dummy98']).rstrip().decode('utf-8')
1180 print(output)
4d7ed14f
SS
1181 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
1182 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
1183 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
1184 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
1185
1186 # CONFIG_BRIDGE_IGMP_SNOOPING=y
1187 if (os.path.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
1188 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
1f0e3109 1189
804b6cd2
YW
1190 self.assertEqual(subprocess.call(['ip', 'address', 'add', '192.168.0.16/24', 'dev', 'bridge99']), 0)
1191 time.sleep(1)
1192
1193 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'test1']), 0)
1194 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1195 time.sleep(3)
1196
1197 output = subprocess.check_output(['ip', 'address', 'show', 'bridge99']).rstrip().decode('utf-8')
1198 print(output)
1199 self.assertRegex(output, 'NO-CARRIER')
1200 self.assertNotRegex(output, '192.168.0.15/24')
1201 self.assertNotRegex(output, '192.168.0.16/24')
1202
1203 def test_bridge_ignore_carrier_loss(self):
1204 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1205 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1206 'bridge99-ignore-carrier-loss.network')
1207 self.start_networkd()
1208
1209 self.assertTrue(self.link_exits('dummy98'))
1210 self.assertTrue(self.link_exits('test1'))
1211 self.assertTrue(self.link_exits('bridge99'))
1212
1213 self.assertEqual(subprocess.call(['ip', 'address', 'add', '192.168.0.16/24', 'dev', 'bridge99']), 0)
1214 time.sleep(1)
1215
1216 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'test1']), 0)
1217 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1218 time.sleep(3)
1219
1220 output = subprocess.check_output(['ip', 'address', 'show', 'bridge99']).rstrip().decode('utf-8')
1221 print(output)
1222 self.assertRegex(output, 'NO-CARRIER')
1223 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1224 self.assertRegex(output, 'inet 192.168.0.16/24 scope global secondary bridge99')
1225
1f0e3109
SS
1226class NetworkdNetWorkLLDPTests(unittest.TestCase, Utilities):
1227 links = ['veth99']
1228
09ea6724
YW
1229 units = [
1230 '23-emit-lldp.network',
1231 '24-lldp.network',
1232 '25-veth.netdev']
1f0e3109
SS
1233
1234 def setUp(self):
1235 self.link_remove(self.links)
1236
1237 def tearDown(self):
1238 self.link_remove(self.links)
1239 self.remove_unit_from_networkd_path(self.units)
1240
1241 def test_lldp(self):
1242 self.copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
1243 self.start_networkd()
1244
1245 self.assertTrue(self.link_exits('veth99'))
1246
1247 output = subprocess.check_output(['networkctl', 'lldp']).rstrip().decode('utf-8')
1248 print(output)
1249 self.assertRegex(output, 'veth-peer')
1250 self.assertRegex(output, 'veth99')
1251
1252class NetworkdNetworkRATests(unittest.TestCase, Utilities):
1253 links = ['veth99']
1254
09ea6724
YW
1255 units = [
1256 '25-veth.netdev',
1257 'ipv6-prefix.network',
1258 'ipv6-prefix-veth.network']
1f0e3109
SS
1259
1260 def setUp(self):
1261 self.link_remove(self.links)
1262
1263 def tearDown(self):
1264 self.link_remove(self.links)
1265 self.remove_unit_from_networkd_path(self.units)
1266
1267 def test_ipv6_prefix_delegation(self):
1268 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
1269 self.start_networkd()
1270
1271 self.assertTrue(self.link_exits('veth99'))
1272
1273 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1274 print(output)
1275 self.assertRegex(output, '2002:da8:1:0')
1276
1277class NetworkdNetworkDHCPServerTests(unittest.TestCase, Utilities):
09ea6724
YW
1278 links = [
1279 'dummy98',
1280 'veth99']
1281
1282 units = [
1283 '12-dummy.netdev',
1284 '24-search-domain.network',
1285 '25-veth.netdev',
1286 'dhcp-client.network',
1287 'dhcp-client-timezone-router.network',
1288 'dhcp-server.network',
1289 'dhcp-server-timezone-router.network']
1f0e3109
SS
1290
1291 def setUp(self):
1292 self.link_remove(self.links)
1293
1294 def tearDown(self):
1295 self.link_remove(self.links)
1296 self.remove_unit_from_networkd_path(self.units)
1297
1298 def test_dhcp_server(self):
1299 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
1300 self.start_networkd()
1301
1302 self.assertTrue(self.link_exits('veth99'))
1303
1f0e3109
SS
1304 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1305 print(output)
1306 self.assertRegex(output, '192.168.5.*')
1307 self.assertRegex(output, 'Gateway: 192.168.5.1')
1308 self.assertRegex(output, 'DNS: 192.168.5.1')
1309 self.assertRegex(output, 'NTP: 192.168.5.1')
1310
1311 def test_domain(self):
f5d191a9 1312 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
1f0e3109
SS
1313 self.start_networkd()
1314
1315 self.assertTrue(self.link_exits('dummy98'))
1316
1317 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
1318 print(output)
1319 self.assertRegex(output, 'Address: 192.168.42.100')
1320 self.assertRegex(output, 'DNS: 192.168.42.1')
1321 self.assertRegex(output, 'Search Domains: one')
1322
1323 def test_emit_router_timezone(self):
1324 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
1325 self.start_networkd()
1326
1327 self.assertTrue(self.link_exits('veth99'))
1328
1329 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1330 print(output)
1331 self.assertRegex(output, 'Gateway: 192.168.5.*')
1332 self.assertRegex(output, '192.168.5.*')
1333 self.assertRegex(output, 'Europe/Berlin')
1334
1335class NetworkdNetworkDHCPClientTests(unittest.TestCase, Utilities):
09ea6724
YW
1336 links = [
1337 'dummy98',
18c613dc
YW
1338 'veth99',
1339 'vrf99']
09ea6724
YW
1340
1341 units = [
1342 '25-veth.netdev',
18c613dc
YW
1343 '25-vrf.netdev',
1344 '25-vrf.network',
09ea6724
YW
1345 'dhcp-client-anonymize.network',
1346 'dhcp-client-critical-connection.network',
1347 'dhcp-client-ipv4-dhcp-settings.network',
1348 'dhcp-client-ipv4-only-ipv6-disabled.network',
1349 'dhcp-client-ipv4-only.network',
1350 'dhcp-client-ipv6-only.network',
1351 'dhcp-client-ipv6-rapid-commit.network',
1352 'dhcp-client-listen-port.network',
1353 'dhcp-client-route-metric.network',
1354 'dhcp-client-route-table.network',
18c613dc 1355 'dhcp-client-vrf.network',
3e9d5552 1356 'dhcp-client.network',
09ea6724 1357 'dhcp-server-veth-peer.network',
30d3b54e
YW
1358 'dhcp-v4-server-veth-peer.network',
1359 'static.network']
1f0e3109
SS
1360
1361 def setUp(self):
1362 self.link_remove(self.links)
1363 self.stop_dnsmasq(dnsmasq_pid_file)
1364
1365 def tearDown(self):
1366 self.link_remove(self.links)
1367 self.remove_unit_from_networkd_path(self.units)
1368 self.stop_dnsmasq(dnsmasq_pid_file)
1369 self.remove_lease_file()
1370 self.remove_log_file()
1371
1372 def test_dhcp_client_ipv6_only(self):
f5d191a9 1373 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
1f0e3109
SS
1374 self.start_networkd()
1375
1376 self.assertTrue(self.link_exits('veth99'))
1377
1378 self.start_dnsmasq()
1379
1380 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1381 print(output)
1382 self.assertRegex(output, '2600::')
1383 self.assertNotRegex(output, '192.168.5')
1384
1385 def test_dhcp_client_ipv4_only(self):
f5d191a9 1386 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
1f0e3109
SS
1387 self.start_networkd()
1388
1389 self.assertTrue(self.link_exits('veth99'))
1390
1391 self.start_dnsmasq()
1392
1393 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1394 print(output)
1395 self.assertNotRegex(output, '2600::')
1396 self.assertRegex(output, '192.168.5')
1397
1398 def test_dhcp_client_ipv4_ipv6(self):
1399 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
1400 'dhcp-client-ipv4-only.network')
1401 self.start_networkd()
1402
1403 self.assertTrue(self.link_exits('veth99'))
1404
1405 self.start_dnsmasq()
1406
1407 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1408 print(output)
1409 self.assertRegex(output, '2600::')
1410 self.assertRegex(output, '192.168.5')
1411
1412 def test_dhcp_client_settings(self):
1413 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
1414 self.start_networkd()
1415
1416 self.assertTrue(self.link_exits('veth99'))
1417
1418 self.start_dnsmasq()
1419
0ae7a66d 1420 print('## ip address show dev veth99')
1f0e3109
SS
1421 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
1422 print(output)
1423 self.assertRegex(output, '12:34:56:78:9a:bc')
1424 self.assertRegex(output, '192.168.5')
1425 self.assertRegex(output, '1492')
1426
0ae7a66d
YW
1427 # issue #8726
1428 print('## ip route show table main dev veth99')
1429 output = subprocess.check_output(['ip', 'route', 'show', 'table', 'main', 'dev', 'veth99']).rstrip().decode('utf-8')
1f0e3109 1430 print(output)
0ae7a66d 1431 self.assertNotRegex(output, 'proto dhcp')
1f0e3109 1432
0ae7a66d
YW
1433 print('## ip route show table 211 dev veth99')
1434 output = subprocess.check_output(['ip', 'route', 'show', 'table', '211', 'dev', 'veth99']).rstrip().decode('utf-8')
1435 print(output)
1436 self.assertRegex(output, 'default via 192.168.5.1 proto dhcp')
1437 self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
1438 self.assertRegex(output, '192.168.5.1 proto dhcp scope link')
1439
1440 print('## dnsmasq log')
131717cb
YW
1441 self.assertTrue(self.search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
1442 self.assertTrue(self.search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
1443 self.assertTrue(self.search_words_in_dnsmasq_log('client provides name: test-hostname'))
1444 self.assertTrue(self.search_words_in_dnsmasq_log('26:mtu'))
1f0e3109
SS
1445
1446 def test_dhcp6_client_settings_rapidcommit_true(self):
1447 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
1448 self.start_networkd()
1449
1450 self.assertTrue(self.link_exits('veth99'))
1451
1452 self.start_dnsmasq()
1453
1454 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
1455 print(output)
1456 self.assertRegex(output, '12:34:56:78:9a:bc')
131717cb 1457 self.assertTrue(self.search_words_in_dnsmasq_log('14:rapid-commit', True))
1f0e3109
SS
1458
1459 def test_dhcp6_client_settings_rapidcommit_false(self):
1460 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
1461 self.start_networkd()
1462
1463 self.assertTrue(self.link_exits('veth99'))
1464
1465 self.start_dnsmasq()
1466
1467 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
1468 print(output)
1469 self.assertRegex(output, '12:34:56:78:9a:bc')
131717cb 1470 self.assertFalse(self.search_words_in_dnsmasq_log('14:rapid-commit', True))
1f0e3109
SS
1471
1472 def test_dhcp_client_settings_anonymize(self):
1473 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
1474 self.start_networkd()
1475
1476 self.assertTrue(self.link_exits('veth99'))
1477
1478 self.start_dnsmasq()
e40a58b5 1479
131717cb
YW
1480 self.assertFalse(self.search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
1481 self.assertFalse(self.search_words_in_dnsmasq_log('test-hostname'))
1482 self.assertFalse(self.search_words_in_dnsmasq_log('26:mtu'))
1f0e3109
SS
1483
1484 def test_dhcp_client_listen_port(self):
1485 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
1f0e3109
SS
1486 self.start_networkd()
1487
1488 self.assertTrue(self.link_exits('veth99'))
1489
b412fce8 1490 self.start_dnsmasq('--dhcp-alternate-port=67,5555')
1f0e3109 1491
b412fce8
YW
1492 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
1493 print(output)
1494 self.assertRegex(output, '192.168.5.* dynamic')
1f0e3109
SS
1495
1496 def test_dhcp_route_table_id(self):
1497 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
1498 self.start_networkd()
1f0e3109
SS
1499
1500 self.assertTrue(self.link_exits('veth99'))
1501
e40a58b5
YW
1502 self.start_dnsmasq()
1503
1f0e3109
SS
1504 output = subprocess.check_output(['ip', 'route', 'show', 'table', '12']).rstrip().decode('utf-8')
1505 print(output)
1f0e3109
SS
1506 self.assertRegex(output, 'veth99 proto dhcp')
1507 self.assertRegex(output, '192.168.5.1')
1508
1509 def test_dhcp_route_metric(self):
1510 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
1511 self.start_networkd()
1f0e3109
SS
1512
1513 self.assertTrue(self.link_exits('veth99'))
1514
e40a58b5
YW
1515 self.start_dnsmasq()
1516
1f0e3109
SS
1517 output = subprocess.check_output(['ip', 'route', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
1518 print(output)
1f0e3109
SS
1519 self.assertRegex(output, 'metric 24')
1520
1521 def test_dhcp_route_criticalconnection_true(self):
1522 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-critical-connection.network')
1523 self.start_networkd()
1f0e3109
SS
1524
1525 self.assertTrue(self.link_exits('veth99'))
1526
e40a58b5
YW
1527 self.start_dnsmasq()
1528
1f0e3109
SS
1529 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1530 print(output)
1f0e3109 1531 self.assertRegex(output, '192.168.5.*')
e40a58b5 1532
1f0e3109
SS
1533 # Stoping dnsmasq as networkd won't be allowed to renew the DHCP lease.
1534 self.stop_dnsmasq(dnsmasq_pid_file)
1535
1536 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
1537 time.sleep(125)
1538
1539 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1540 print(output)
1541 self.assertRegex(output, '192.168.5.*')
1542
30d3b54e
YW
1543 def test_dhcp_client_reuse_address_as_static(self):
1544 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
1545 self.start_networkd()
1546
1547 self.assertTrue(self.link_exits('veth99'))
1548
1549 self.start_dnsmasq()
1550
1551 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99', 'scope', 'global']).rstrip().decode('utf-8')
1552 print(output)
1553 self.assertRegex(output, '192.168.5')
1554 self.assertRegex(output, '2600::')
1555
1556 ipv4_address = re.search('192\.168\.5\.[0-9]*/24', output)
1557 ipv6_address = re.search('2600::[0-9a-f:]*/128', output)
1558 static_network = '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address.group(), 'Address=' + ipv6_address.group()])
1559 print(static_network)
1560
1561 self.remove_unit_from_networkd_path(['dhcp-client.network'])
1562
1563 with open(os.path.join(network_unit_file_path, 'static.network'), mode='w') as f:
1564 f.write(static_network)
1565
1566 self.start_networkd()
1567
1568 self.assertTrue(self.link_exits('veth99'))
1569
1570 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global']).rstrip().decode('utf-8')
1571 print(output)
1572 self.assertRegex(output, '192.168.5')
1573 self.assertRegex(output, 'valid_lft forever preferred_lft forever')
1574
1575 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global']).rstrip().decode('utf-8')
1576 print(output)
1577 self.assertRegex(output, '2600::')
1578 self.assertRegex(output, 'valid_lft forever preferred_lft forever')
1579
18c613dc
YW
1580 @expectedFailureIfModuleIsNotAvailable('vrf')
1581 def test_dhcp_client_vrf(self):
1582 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
1583 '25-vrf.netdev', '25-vrf.network')
1584 self.start_networkd()
1585
1586 self.assertTrue(self.link_exits('veth99'))
1587 self.assertTrue(self.link_exits('vrf99'))
1588
1589 self.start_dnsmasq()
1590
1591 print('## ip -d link show dev vrf99')
1592 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'dev', 'vrf99']).rstrip().decode('utf-8')
1593 print(output)
1594 self.assertRegex(output, 'vrf table 42')
1595
1596 print('## ip address show vrf vrf99')
1597 output_ip_vrf = subprocess.check_output(['ip', 'address', 'show', 'vrf', 'vrf99']).rstrip().decode('utf-8')
1598 print(output_ip_vrf)
1599
1600 print('## ip address show dev veth99')
1601 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
1602 print(output)
1603 self.assertEqual(output, output_ip_vrf)
1604 self.assertRegex(output, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
1605 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
1606 self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic noprefixroute')
1607 self.assertRegex(output, 'inet6 .* scope link')
1608
1609 print('## ip route show vrf vrf99')
1610 output = subprocess.check_output(['ip', 'route', 'show', 'vrf', 'vrf99']).rstrip().decode('utf-8')
1611 print(output)
1612 self.assertRegex(output, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
1613 self.assertRegex(output, 'default dev veth99 proto static scope link')
1614 self.assertRegex(output, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
1615 self.assertRegex(output, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
1616 self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
1617 self.assertRegex(output, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
1618
1619 print('## ip route show table main dev veth99')
1620 output = subprocess.check_output(['ip', 'route', 'show', 'table', 'main', 'dev', 'veth99']).rstrip().decode('utf-8')
1621 print(output)
1622 self.assertEqual(output, '')
1623
1624 output = subprocess.check_output(['networkctl', 'status', 'vrf99']).rstrip().decode('utf-8')
1625 print(output)
1626 self.assertRegex(output, 'State: carrier \(configured\)')
1627
1628 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1629 print(output)
1630 self.assertRegex(output, 'State: routable \(configured\)')
1631
1f0e3109
SS
1632if __name__ == '__main__':
1633 unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout,
1634 verbosity=3))