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