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