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