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