]> git.ipfire.org Git - thirdparty/systemd.git/blame - test/test-network/systemd-networkd-tests.py
test-network: use wait_online() in test_sysctl_disable_ipv6()
[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',
09ea6724 871 '25-address-link-section.network',
b8102725
YW
872 '25-address-preferred-lifetime-zero-ipv6.network',
873 '25-address-static.network',
cd65d067 874 '25-bind-carrier.network',
09ea6724
YW
875 '25-bond-active-backup-slave.netdev',
876 '25-fibrule-invert.network',
877 '25-fibrule-port-range.network',
878 '25-ipv6-address-label-section.network',
e4a71bf3 879 '25-neighbor-section.network',
05514ae1
YW
880 '25-link-local-addressing-no.network',
881 '25-link-local-addressing-yes.network',
09ea6724
YW
882 '25-link-section-unmanaged.network',
883 '25-route-gateway.network',
884 '25-route-gateway-on-link.network',
20ca06a6 885 '25-route-ipv6-src.network',
09ea6724
YW
886 '25-route-reverse-order.network',
887 '25-route-section.network',
888 '25-route-tcp-window-settings.network',
889 '25-route-type.network',
4da33154 890 '25-sysctl-disable-ipv6.network',
09ea6724
YW
891 '25-sysctl.network',
892 'configure-without-carrier.network',
b677774d 893 'routing-policy-rule-dummy98.network',
b8102725 894 'routing-policy-rule-test1.network']
1f0e3109
SS
895
896 def setUp(self):
897 self.link_remove(self.links)
898
899 def tearDown(self):
900 self.link_remove(self.links)
901 self.remove_unit_from_networkd_path(self.units)
902
b8102725
YW
903 def test_address_static(self):
904 self.copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
905 self.start_networkd(0)
906
907 self.wait_online(['dummy98:routable'])
908
909 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98']).rstrip().decode('utf-8')
910 print(output)
911 self.assertRegex(output, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
912 self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
913 self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
914
915 # invalid sections
916 self.assertNotRegex(output, '10.10.0.1/16')
917 self.assertNotRegex(output, '10.10.0.2/16')
918
919 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98', 'label', '32']).rstrip().decode('utf-8')
920 self.assertRegex(output, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
921
922 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98', 'label', '33']).rstrip().decode('utf-8')
923 self.assertRegex(output, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
924
925 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98', 'label', '34']).rstrip().decode('utf-8')
926 self.assertRegex(output, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
927
928 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98', 'label', '35']).rstrip().decode('utf-8')
929 self.assertRegex(output, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
930
931 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'dummy98']).rstrip().decode('utf-8')
932 print(output)
933 self.assertRegex(output, 'inet6 2001:db8:0:f101::15/64 scope global')
934 self.assertRegex(output, 'inet6 2001:db8:0:f101::16/64 scope global')
935 self.assertRegex(output, 'inet6 2001:db8:0:f102::15/64 scope global')
936 self.assertRegex(output, 'inet6 2001:db8:0:f102::16/64 scope global')
937 self.assertRegex(output, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
938 self.assertRegex(output, 'inet6 fd[0-9a-f:]*1/64 scope global')
939
940 def test_address_preferred_lifetime_zero_ipv6(self):
941 self.copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero-ipv6.network', '12-dummy.netdev')
1f0e3109
SS
942 self.start_networkd()
943
944 self.assertTrue(self.link_exits('dummy98'))
e40a58b5 945
1f0e3109
SS
946 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
947 print(output)
b8102725
YW
948 self.assertRegex(output, 'State: routable \(configuring\)')
949
950 output = subprocess.check_output(['ip', 'address', 'show', 'dummy98']).rstrip().decode('utf-8')
951 print(output)
952 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
953 self.assertRegex(output, 'inet6 2001:db8:0:f101::1/64 scope global')
1f0e3109
SS
954
955 def test_configure_without_carrier(self):
956 self.copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
957 self.start_networkd()
958
959 self.assertTrue(self.link_exits('test1'))
e40a58b5 960
1f0e3109
SS
961 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
962 print(output)
963 self.assertRegex(output, '192.168.0.15')
964 self.assertRegex(output, '192.168.0.1')
965 self.assertRegex(output, 'routable')
966
1f0e3109 967 def test_routing_policy_rule(self):
b677774d 968 self.copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
703bc7a2
YW
969
970 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
971
1f0e3109
SS
972 self.start_networkd()
973
974 self.assertTrue(self.link_exits('test1'))
e40a58b5 975
1f0e3109
SS
976 output = subprocess.check_output(['ip', 'rule']).rstrip().decode('utf-8')
977 print(output)
978 self.assertRegex(output, '111')
979 self.assertRegex(output, 'from 192.168.100.18')
f7bdd562 980 self.assertRegex(output, r'tos (?:0x08|throughput)\s')
1f0e3109
SS
981 self.assertRegex(output, 'iif test1')
982 self.assertRegex(output, 'oif test1')
983 self.assertRegex(output, 'lookup 7')
984
e4eacdb0
YW
985 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
986
b677774d
YW
987 def test_routing_policy_rule_issue_11280(self):
988 self.copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
989 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
990
991 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
992 subprocess.call(['ip', 'rule', 'del', 'table', '8'])
993
994 for trial in range(3):
995 # Remove state files only first time
5aa58329 996 self.start_networkd(remove_state_files=(trial == 0))
b677774d
YW
997
998 self.assertTrue(self.link_exits('test1'))
999 self.assertTrue(self.link_exits('dummy98'))
1000
1001 output = subprocess.check_output(['ip', 'rule', 'list', 'table', '7']).rstrip().decode('utf-8')
1002 print(output)
1003 self.assertRegex(output, '111: from 192.168.100.18 tos (?:0x08|throughput) iif test1 oif test1 lookup 7')
1004
1005 output = subprocess.check_output(['ip', 'rule', 'list', 'table', '8']).rstrip().decode('utf-8')
1006 print(output)
1007 self.assertRegex(output, '112: from 192.168.101.18 tos (?:0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1008
1009 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
1010 subprocess.call(['ip', 'rule', 'del', 'table', '8'])
1011
d586a2c3 1012 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
926062f0
SS
1013 def test_routing_policy_rule_port_range(self):
1014 self.copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
703bc7a2
YW
1015
1016 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
1017
926062f0
SS
1018 self.start_networkd()
1019
1020 self.assertTrue(self.link_exits('test1'))
e40a58b5 1021
926062f0
SS
1022 output = subprocess.check_output(['ip', 'rule']).rstrip().decode('utf-8')
1023 print(output)
1024 self.assertRegex(output, '111')
1025 self.assertRegex(output, 'from 192.168.100.18')
1026 self.assertRegex(output, '1123-1150')
1027 self.assertRegex(output, '3224-3290')
1028 self.assertRegex(output, 'tcp')
1029 self.assertRegex(output, 'lookup 7')
1f0e3109 1030
e4eacdb0
YW
1031 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
1032
d586a2c3 1033 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
efecf9cd
SS
1034 def test_routing_policy_rule_invert(self):
1035 self.copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
703bc7a2
YW
1036
1037 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
1038
efecf9cd
SS
1039 self.start_networkd()
1040
1041 self.assertTrue(self.link_exits('test1'))
e40a58b5 1042
efecf9cd
SS
1043 output = subprocess.check_output(['ip', 'rule']).rstrip().decode('utf-8')
1044 print(output)
efecf9cd
SS
1045 self.assertRegex(output, '111')
1046 self.assertRegex(output, 'not.*?from.*?192.168.100.18')
1047 self.assertRegex(output, 'tcp')
1048 self.assertRegex(output, 'lookup 7')
1049
e4eacdb0
YW
1050 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
1051
1f0e3109
SS
1052 def test_ip_route(self):
1053 self.copy_unit_to_networkd_unit_path('25-route-section.network', '12-dummy.netdev')
1054 self.start_networkd()
1055
1056 self.assertTrue(self.link_exits('dummy98'))
1057
1058 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98']).rstrip().decode('utf-8')
1059 print(output)
1060 self.assertRegex(output, '192.168.0.1')
1061 self.assertRegex(output, 'static')
1062 self.assertRegex(output, '192.168.0.0/24')
1063
0d34228f
SS
1064 def test_ip_route_reverse(self):
1065 self.copy_unit_to_networkd_unit_path('25-route-reverse-order.network', '12-dummy.netdev')
1066 self.start_networkd()
1067
1068 self.assertTrue(self.link_exits('dummy98'))
1069
1070 output = subprocess.check_output(['ip', '-6', 'route', 'show', 'dev', 'dummy98']).rstrip().decode('utf-8')
1071 print(output)
1072 self.assertRegex(output, '2001:1234:5:8fff:ff:ff:ff:ff')
1073 self.assertRegex(output, '2001:1234:5:8f63::1')
1074
1f0e3109
SS
1075 def test_ip_route_blackhole_unreachable_prohibit(self):
1076 self.copy_unit_to_networkd_unit_path('25-route-type.network', '12-dummy.netdev')
1077 self.start_networkd()
1078
1079 self.assertTrue(self.link_exits('dummy98'))
1080
1081 output = subprocess.check_output(['ip', 'route', 'list']).rstrip().decode('utf-8')
1082 print(output)
1083 self.assertRegex(output, 'blackhole')
1084 self.assertRegex(output, 'unreachable')
1085 self.assertRegex(output, 'prohibit')
1086
1087 subprocess.call(['ip', 'route', 'del', 'blackhole', '202.54.1.2'])
1088 subprocess.call(['ip', 'route', 'del', 'unreachable', '202.54.1.3'])
1089 subprocess.call(['ip', 'route', 'del', 'prohibit', '202.54.1.4'])
1090
1091 def test_ip_route_tcp_window(self):
1092 self.copy_unit_to_networkd_unit_path('25-route-tcp-window-settings.network', '11-dummy.netdev')
1093 self.start_networkd()
1094
1095 self.assertTrue(self.link_exits('test1'))
1096
1097 output = subprocess.check_output(['ip', 'route', 'list']).rstrip().decode('utf-8')
1098 print(output)
1099 self.assertRegex(output, 'initcwnd 20')
1100 self.assertRegex(output, 'initrwnd 30')
1101
f5050e48
YW
1102 def test_ip_route_gateway(self):
1103 self.copy_unit_to_networkd_unit_path('25-route-gateway.network', '12-dummy.netdev')
1104 self.start_networkd()
1105
1106 self.assertTrue(self.link_exits('dummy98'))
1107
1108 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98', 'default']).rstrip().decode('utf-8')
1109 print(output)
1110 self.assertRegex(output, 'default')
1111 self.assertRegex(output, 'via')
1112 self.assertRegex(output, '149.10.124.64')
1113 self.assertRegex(output, 'proto')
1114 self.assertRegex(output, 'static')
1115
1116 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98', 'src', '149.10.124.58']).rstrip().decode('utf-8')
1117 print(output)
1118 self.assertRegex(output, '149.10.124.48/28')
1119 self.assertRegex(output, 'proto')
1120 self.assertRegex(output, 'kernel')
1121 self.assertRegex(output, 'scope')
1122 self.assertRegex(output, 'link')
1123
1124 def test_ip_route_gateway_on_link(self):
1125 self.copy_unit_to_networkd_unit_path('25-route-gateway-on-link.network', '12-dummy.netdev')
1126 self.start_networkd()
1127
1128 self.assertTrue(self.link_exits('dummy98'))
1129
1130 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98', 'default']).rstrip().decode('utf-8')
1131 print(output)
1132 self.assertRegex(output, 'default')
1133 self.assertRegex(output, 'via')
1134 self.assertRegex(output, '149.10.125.65')
1135 self.assertRegex(output, 'proto')
1136 self.assertRegex(output, 'static')
1137 self.assertRegex(output, 'onlink')
1138
1139 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98', 'src', '149.10.124.58']).rstrip().decode('utf-8')
1140 print(output)
1141 self.assertRegex(output, '149.10.124.48/28')
1142 self.assertRegex(output, 'proto')
1143 self.assertRegex(output, 'kernel')
1144 self.assertRegex(output, 'scope')
1145 self.assertRegex(output, 'link')
1146
20ca06a6
DA
1147 def test_ip_route_ipv6_src_route(self):
1148 # a dummy device does not make the addresses go through tentative state, so we
1149 # reuse a bond from an earlier test, which does make the addresses go through
1150 # tentative state, and do our test on that
1151 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')
1152 self.start_networkd()
1153
1154 self.assertTrue(self.link_exits('dummy98'))
1155 self.assertTrue(self.link_exits('bond199'))
1156
1157 output = subprocess.check_output(['ip', '-6', 'route', 'list', 'dev', 'bond199']).rstrip().decode('utf-8')
1158 print(output)
1159 self.assertRegex(output, 'abcd::/16')
1160 self.assertRegex(output, 'src')
1161 self.assertRegex(output, '2001:1234:56:8f63::2')
1162
1f0e3109
SS
1163 def test_ip_link_mac_address(self):
1164 self.copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
1165 self.start_networkd()
1166
1167 self.assertTrue(self.link_exits('dummy98'))
1168
1169 output = subprocess.check_output(['ip', 'link', 'show', 'dummy98']).rstrip().decode('utf-8')
1170 print(output)
1171 self.assertRegex(output, '00:01:02:aa:bb:cc')
1172
1173 def test_ip_link_unmanaged(self):
1174 self.copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
1175 self.start_networkd()
1176
1177 self.assertTrue(self.link_exits('dummy98'))
1178
1179 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
1180 print(output)
1181 self.assertRegex(output, 'unmanaged')
1182
1183 def test_ipv6_address_label(self):
1184 self.copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
1185 self.start_networkd()
1186
1187 self.assertTrue(self.link_exits('dummy98'))
1188
1189 output = subprocess.check_output(['ip', 'addrlabel', 'list']).rstrip().decode('utf-8')
1190 print(output)
1191 self.assertRegex(output, '2004:da8:1::/64')
1192
e4a71bf3
WKI
1193 def test_ipv6_neighbor(self):
1194 self.copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
1195 self.start_networkd()
1196
1197 self.assertTrue(self.link_exits('dummy98'))
1198
1199 output = subprocess.check_output(['ip', 'neigh', 'list']).rstrip().decode('utf-8')
1200 print(output)
1201 self.assertRegex(output, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
094b5479 1202 self.assertRegex(output, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
e4a71bf3 1203
05514ae1
YW
1204 def test_link_local_addressing(self):
1205 self.copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
1206 '25-link-local-addressing-no.network', '12-dummy.netdev')
2dcfcc08
YW
1207 self.start_networkd(0)
1208 self.wait_online(['test1:degraded', 'dummy98:carrier'])
05514ae1
YW
1209
1210 self.assertTrue(self.link_exits('test1'))
1211 self.assertTrue(self.link_exits('dummy98'))
1212
05514ae1
YW
1213 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'test1']).rstrip().decode('utf-8')
1214 print(output)
1215 self.assertRegex(output, 'inet .* scope link')
1216 self.assertRegex(output, 'inet6 .* scope link')
1217
1218 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'dummy98']).rstrip().decode('utf-8')
1219 print(output)
1220 self.assertNotRegex(output, 'inet6* .* scope link')
1221
1222 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
1223 print(output)
1224 self.assertRegex(output, 'State: degraded \(configured\)')
1225
1226 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
1227 print(output)
1228 self.assertRegex(output, 'State: carrier \(configured\)')
1229
1230 '''
1231 Documentation/networking/ip-sysctl.txt
1232
1233 addr_gen_mode - INTEGER
1234 Defines how link-local and autoconf addresses are generated.
1235
1236 0: generate address based on EUI64 (default)
1237 1: do no generate a link-local address, use EUI64 for addresses generated
1238 from autoconf
1239 2: generate stable privacy addresses, using the secret from
1240 stable_secret (RFC7217)
1241 3: generate stable privacy addresses, using a random secret if unset
1242 '''
1243
1244 test1_addr_gen_mode = ''
1245 if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'stable_secret')):
1246 with open(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'stable_secret')) as f:
1247 try:
1248 f.readline()
1249 except IOError:
1250 # if stable_secret is unset, then EIO is returned
1251 test1_addr_gen_mode = '0'
1252 else:
1253 test1_addr_gen_mode = '2'
1254 else:
1255 test1_addr_gen_mode = '0'
1256
1257 if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'addr_gen_mode')):
d06f30fc 1258 self.assertEqual(self.read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode)
05514ae1
YW
1259
1260 if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'dummy98'), 'addr_gen_mode')):
1261 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
1262
1f0e3109
SS
1263 def test_sysctl(self):
1264 self.copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
ba1e0d06
YW
1265 self.start_networkd(0)
1266 self.wait_online(['dummy98:degraded'])
1f0e3109
SS
1267
1268 self.assertTrue(self.link_exits('dummy98'))
1269
1270 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
1271 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
1272 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
1273 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
1274 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
1275 self.assertEqual(self.read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
1276 self.assertEqual(self.read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
1277
4da33154
YW
1278 def test_sysctl_disable_ipv6(self):
1279 self.copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
1280
1281 print('## Disable ipv6')
1282 self.assertEqual(subprocess.call(['sysctl', 'net.ipv6.conf.all.disable_ipv6=1']), 0)
1283 self.assertEqual(subprocess.call(['sysctl', 'net.ipv6.conf.default.disable_ipv6=1']), 0)
1284
a15ff207
YW
1285 self.start_networkd(0)
1286 self.wait_online(['dummy98:routable'])
4da33154
YW
1287
1288 self.assertTrue(self.link_exits('dummy98'))
1289
1290 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dummy98']).rstrip().decode('utf-8')
1291 print(output)
1292 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1293 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dummy98']).rstrip().decode('utf-8')
1294 print(output)
1295 self.assertEqual(output, '')
1296 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
1297 self.assertRegex(output, 'State: routable \(configured\)')
1298
1299 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1300
1301 print('## Enable ipv6')
1302 self.assertEqual(subprocess.call(['sysctl', 'net.ipv6.conf.all.disable_ipv6=0']), 0)
1303 self.assertEqual(subprocess.call(['sysctl', 'net.ipv6.conf.default.disable_ipv6=0']), 0)
1304
a15ff207
YW
1305 self.start_networkd(0)
1306 self.wait_online(['dummy98:routable'])
4da33154
YW
1307
1308 self.assertTrue(self.link_exits('dummy98'))
1309
1310 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dummy98']).rstrip().decode('utf-8')
1311 print(output)
1312 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1313 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dummy98']).rstrip().decode('utf-8')
1314 print(output)
1315 self.assertRegex(output, 'inet6 .* scope link')
1316 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
1317 self.assertRegex(output, 'State: routable \(configured\)')
1318
cd65d067
YW
1319 def test_bind_carrier(self):
1320 self.copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
1321 self.start_networkd()
1322
1323 self.assertTrue(self.link_exits('test1'))
1324
cd65d067
YW
1325 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1326 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
b117044c 1327 time.sleep(2)
cd65d067
YW
1328 output = subprocess.check_output(['ip', 'address', 'show', 'test1']).rstrip().decode('utf-8')
1329 print(output)
1330 self.assertRegex(output, 'UP,LOWER_UP')
1331 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1332 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
1333 self.assertRegex(output, 'State: routable \(configured\)')
1334
1335 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy99', 'type', 'dummy']), 0)
1336 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy99', 'up']), 0)
b117044c 1337 time.sleep(2)
cd65d067
YW
1338 output = subprocess.check_output(['ip', 'address', 'show', 'test1']).rstrip().decode('utf-8')
1339 print(output)
1340 self.assertRegex(output, 'UP,LOWER_UP')
1341 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1342 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
1343 self.assertRegex(output, 'State: routable \(configured\)')
1344
1345 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
b117044c 1346 time.sleep(2)
cd65d067
YW
1347 output = subprocess.check_output(['ip', 'address', 'show', 'test1']).rstrip().decode('utf-8')
1348 print(output)
1349 self.assertRegex(output, 'UP,LOWER_UP')
1350 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1351 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
1352 self.assertRegex(output, 'State: routable \(configured\)')
1353
1354 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy99']), 0)
b117044c 1355 time.sleep(2)
cd65d067
YW
1356 output = subprocess.check_output(['ip', 'address', 'show', 'test1']).rstrip().decode('utf-8')
1357 print(output)
1358 self.assertNotRegex(output, 'UP,LOWER_UP')
1359 self.assertRegex(output, 'DOWN')
1360 self.assertNotRegex(output, '192.168.10')
1361 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
1362 self.assertRegex(output, 'State: off \(configured\)')
1363
1364 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1365 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
b117044c 1366 time.sleep(2)
cd65d067
YW
1367 output = subprocess.check_output(['ip', 'address', 'show', 'test1']).rstrip().decode('utf-8')
1368 print(output)
1369 self.assertRegex(output, 'UP,LOWER_UP')
1370 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1371 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
1372 self.assertRegex(output, 'State: routable \(configured\)')
1373
c3a8853f
YW
1374class NetworkdNetWorkBondTests(unittest.TestCase, Utilities):
1375 links = [
c2990ec3 1376 'bond199',
c3a8853f 1377 'bond99',
cc3e488c
YW
1378 'dummy98',
1379 'test1']
c3a8853f
YW
1380
1381 units = [
cc3e488c
YW
1382 '11-dummy.netdev',
1383 '12-dummy.netdev',
c2990ec3
YW
1384 '23-active-slave.network',
1385 '23-bond199.network',
1386 '23-primary-slave.network',
1387 '23-test1-bond199.network',
1388 '25-bond-active-backup-slave.netdev',
c3a8853f 1389 '25-bond.netdev',
c3a8853f 1390 'bond99.network',
cc3e488c 1391 'bond-slave.network']
c3a8853f
YW
1392
1393 def setUp(self):
1394 self.link_remove(self.links)
1395
1396 def tearDown(self):
1397 self.link_remove(self.links)
1398 self.remove_unit_from_networkd_path(self.units)
1399
c2990ec3
YW
1400 def test_bond_active_slave(self):
1401 self.copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1402 self.start_networkd()
1403
1404 self.assertTrue(self.link_exits('dummy98'))
1405 self.assertTrue(self.link_exits('bond199'))
1406
1407 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond199']).rstrip().decode('utf-8')
1408 print(output)
1409 self.assertRegex(output, 'active_slave dummy98')
1410
1411 def test_bond_primary_slave(self):
1412 self.copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-test1-bond199.network', '25-bond-active-backup-slave.netdev', '11-dummy.netdev')
1413 self.start_networkd()
1414
1415 self.assertTrue(self.link_exits('test1'))
1416 self.assertTrue(self.link_exits('bond199'))
1417
1418 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond199']).rstrip().decode('utf-8')
1419 print(output)
1420 self.assertRegex(output, 'primary test1')
1421
cc3e488c
YW
1422 def test_bond_operstate(self):
1423 self.copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
1424 'bond99.network','bond-slave.network')
c3a8853f
YW
1425 self.start_networkd()
1426
1427 self.assertTrue(self.link_exits('bond99'))
cc3e488c
YW
1428 self.assertTrue(self.link_exits('dummy98'))
1429 self.assertTrue(self.link_exits('test1'))
c3a8853f 1430
cc3e488c 1431 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'dummy98']).rstrip().decode('utf-8')
c3a8853f 1432 print(output)
cc3e488c 1433 self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
c3a8853f 1434
cc3e488c 1435 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1']).rstrip().decode('utf-8')
c3a8853f
YW
1436 print(output)
1437 self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
1438
1439 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond99']).rstrip().decode('utf-8')
1440 print(output)
1441 self.assertRegex(output, 'MASTER,UP,LOWER_UP')
1442
cc3e488c 1443 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
c3a8853f 1444 print(output)
cc3e488c 1445 self.assertRegex(output, 'State: enslaved \(configured\)')
c3a8853f 1446
cc3e488c 1447 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
c3a8853f
YW
1448 print(output)
1449 self.assertRegex(output, 'State: enslaved \(configured\)')
1450
1451 output = subprocess.check_output(['networkctl', 'status', 'bond99']).rstrip().decode('utf-8')
1452 print(output)
1453 self.assertRegex(output, 'State: routable \(configured\)')
1454
cc3e488c 1455 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'down']), 0)
c3a8853f
YW
1456 time.sleep(2)
1457
cc3e488c 1458 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
c3a8853f
YW
1459 print(output)
1460 self.assertRegex(output, 'State: off \(configured\)')
1461
cc3e488c
YW
1462 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
1463 print(output)
1464 self.assertRegex(output, 'State: enslaved \(configured\)')
1465
c3a8853f
YW
1466 output = subprocess.check_output(['networkctl', 'status', 'bond99']).rstrip().decode('utf-8')
1467 print(output)
c9cc0383 1468 self.assertRegex(output, 'State: degraded-carrier \(configured\)')
c3a8853f 1469
cc3e488c 1470 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
c3a8853f
YW
1471 time.sleep(2)
1472
cc3e488c
YW
1473 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
1474 print(output)
1475 self.assertRegex(output, 'State: enslaved \(configured\)')
1476
1477 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
c3a8853f
YW
1478 print(output)
1479 self.assertRegex(output, 'State: enslaved \(configured\)')
1480
1481 output = subprocess.check_output(['networkctl', 'status', 'bond99']).rstrip().decode('utf-8')
1482 print(output)
1483 self.assertRegex(output, 'State: routable \(configured\)')
1484
cc3e488c
YW
1485 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'down']), 0)
1486 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'test1', 'down']), 0)
4ddbf08c 1487 time.sleep(5)
cc3e488c
YW
1488
1489 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
1490 print(output)
1491 self.assertRegex(output, 'State: off \(configured\)')
1492
1493 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
1494 print(output)
1495 self.assertRegex(output, 'State: off \(configured\)')
1496
1497 output = subprocess.check_output(['networkctl', 'status', 'bond99']).rstrip().decode('utf-8')
1498 print(output)
4ddbf08c 1499 self.assertRegex(output, 'State: no-carrier \(configured\)')
cc3e488c 1500
14dc0335 1501class NetworkdNetWorkBridgeTests(unittest.TestCase, Utilities):
09ea6724
YW
1502 links = [
1503 'bridge99',
1504 'dummy98',
1505 'test1']
1506
1507 units = [
1508 '11-dummy.netdev',
1509 '12-dummy.netdev',
1510 '26-bridge.netdev',
1511 '26-bridge-slave-interface-1.network',
1512 '26-bridge-slave-interface-2.network',
804b6cd2 1513 'bridge99-ignore-carrier-loss.network',
09ea6724 1514 'bridge99.network']
1f0e3109
SS
1515
1516 def setUp(self):
1517 self.link_remove(self.links)
1518
1519 def tearDown(self):
1520 self.link_remove(self.links)
1521 self.remove_unit_from_networkd_path(self.units)
1522
1523 def test_bridge_property(self):
1524 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1525 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1526 'bridge99.network')
1527 self.start_networkd()
1528
1529 self.assertTrue(self.link_exits('dummy98'))
1530 self.assertTrue(self.link_exits('test1'))
1531 self.assertTrue(self.link_exits('bridge99'))
1532
1533 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1']).rstrip().decode('utf-8')
1534 print(output)
1535 self.assertRegex(output, 'master')
1536 self.assertRegex(output, 'bridge')
1537
1538 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'dummy98']).rstrip().decode('utf-8')
1539 print(output)
1540 self.assertRegex(output, 'master')
1541 self.assertRegex(output, 'bridge')
1542
1543 output = subprocess.check_output(['ip', 'addr', 'show', 'bridge99']).rstrip().decode('utf-8')
1544 print(output)
2be6c5d2 1545 self.assertRegex(output, '192.168.0.15/24')
1f0e3109
SS
1546
1547 output = subprocess.check_output(['bridge', '-d', 'link', 'show', 'dummy98']).rstrip().decode('utf-8')
1548 print(output)
4d7ed14f
SS
1549 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
1550 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
1551 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
7f15b714 1552 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
4d7ed14f 1553 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
7f15b714
TJ
1554 if (os.path.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
1555 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
1556 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
4d7ed14f
SS
1557
1558 # CONFIG_BRIDGE_IGMP_SNOOPING=y
1559 if (os.path.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
1560 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
1f0e3109 1561
2be6c5d2
YW
1562 output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
1563 self.assertRegex(output, 'State: enslaved \(configured\)')
1564
1565 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
1566 self.assertRegex(output, 'State: enslaved \(configured\)')
1567
1568 output = subprocess.check_output(['networkctl', 'status', 'bridge99']).rstrip().decode('utf-8')
1569 self.assertRegex(output, 'State: routable \(configured\)')
1570
804b6cd2
YW
1571 self.assertEqual(subprocess.call(['ip', 'address', 'add', '192.168.0.16/24', 'dev', 'bridge99']), 0)
1572 time.sleep(1)
1573
2be6c5d2
YW
1574 output = subprocess.check_output(['ip', 'addr', 'show', 'bridge99']).rstrip().decode('utf-8')
1575 print(output)
1576 self.assertRegex(output, '192.168.0.16/24')
1577
1578 output = subprocess.check_output(['networkctl', 'status', 'bridge99']).rstrip().decode('utf-8')
1579 self.assertRegex(output, 'State: routable \(configured\)')
1580
804b6cd2 1581 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'test1']), 0)
2be6c5d2
YW
1582 time.sleep(3)
1583
1584 output = subprocess.check_output(['networkctl', 'status', 'bridge99']).rstrip().decode('utf-8')
c9cc0383 1585 self.assertRegex(output, 'State: degraded-carrier \(configured\)')
2be6c5d2 1586
804b6cd2
YW
1587 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1588 time.sleep(3)
1589
2be6c5d2
YW
1590 output = subprocess.check_output(['networkctl', 'status', 'bridge99']).rstrip().decode('utf-8')
1591 self.assertRegex(output, 'State: no-carrier \(configured\)')
1592
804b6cd2
YW
1593 output = subprocess.check_output(['ip', 'address', 'show', 'bridge99']).rstrip().decode('utf-8')
1594 print(output)
1595 self.assertRegex(output, 'NO-CARRIER')
1596 self.assertNotRegex(output, '192.168.0.15/24')
1597 self.assertNotRegex(output, '192.168.0.16/24')
1598
1599 def test_bridge_ignore_carrier_loss(self):
1600 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1601 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1602 'bridge99-ignore-carrier-loss.network')
703bc7a2
YW
1603
1604 subprocess.call(['ip', 'rule', 'del', 'table', '100'])
1605
804b6cd2
YW
1606 self.start_networkd()
1607
1608 self.assertTrue(self.link_exits('dummy98'))
1609 self.assertTrue(self.link_exits('test1'))
1610 self.assertTrue(self.link_exits('bridge99'))
1611
1612 self.assertEqual(subprocess.call(['ip', 'address', 'add', '192.168.0.16/24', 'dev', 'bridge99']), 0)
1613 time.sleep(1)
1614
1615 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'test1']), 0)
1616 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1617 time.sleep(3)
1618
1619 output = subprocess.check_output(['ip', 'address', 'show', 'bridge99']).rstrip().decode('utf-8')
1620 print(output)
1621 self.assertRegex(output, 'NO-CARRIER')
1622 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1623 self.assertRegex(output, 'inet 192.168.0.16/24 scope global secondary bridge99')
1624
6609924c
YW
1625 subprocess.call(['ip', 'rule', 'del', 'table', '100'])
1626
1627 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self):
1628 self.copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
1629 'bridge99-ignore-carrier-loss.network')
703bc7a2
YW
1630
1631 subprocess.call(['ip', 'rule', 'del', 'table', '100'])
1632
6609924c
YW
1633 self.start_networkd()
1634
1635 self.assertTrue(self.link_exits('bridge99'))
1636
1637 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1638 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1639 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1640
1641 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1642 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1643 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1644
1645 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1646 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1647 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1648
1649 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1650 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1651
1652 time.sleep(3)
1653
1654 output = subprocess.check_output(['ip', 'address', 'show', 'bridge99']).rstrip().decode('utf-8')
1655 print(output)
1656 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1657
1658 output = subprocess.check_output(['networkctl', 'status', 'bridge99']).rstrip().decode('utf-8')
1659 self.assertRegex(output, 'State: routable \(configured\)')
1660
1661 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
1662 self.assertRegex(output, 'State: enslaved \(configured\)')
1663
1664 output = subprocess.check_output(['ip', 'rule', 'list', 'table', '100']).rstrip().decode('utf-8')
1665 print(output)
1666 self.assertEqual(output, '0: from all to 8.8.8.8 lookup 100')
1667
1668 subprocess.call(['ip', 'rule', 'del', 'table', '100'])
1669
1f0e3109
SS
1670class NetworkdNetWorkLLDPTests(unittest.TestCase, Utilities):
1671 links = ['veth99']
1672
09ea6724
YW
1673 units = [
1674 '23-emit-lldp.network',
1675 '24-lldp.network',
1676 '25-veth.netdev']
1f0e3109
SS
1677
1678 def setUp(self):
1679 self.link_remove(self.links)
1680
1681 def tearDown(self):
1682 self.link_remove(self.links)
1683 self.remove_unit_from_networkd_path(self.units)
1684
1685 def test_lldp(self):
1686 self.copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
1687 self.start_networkd()
1688
1689 self.assertTrue(self.link_exits('veth99'))
1690
1691 output = subprocess.check_output(['networkctl', 'lldp']).rstrip().decode('utf-8')
1692 print(output)
1693 self.assertRegex(output, 'veth-peer')
1694 self.assertRegex(output, 'veth99')
1695
1696class NetworkdNetworkRATests(unittest.TestCase, Utilities):
1697 links = ['veth99']
1698
09ea6724
YW
1699 units = [
1700 '25-veth.netdev',
1701 'ipv6-prefix.network',
1702 'ipv6-prefix-veth.network']
1f0e3109
SS
1703
1704 def setUp(self):
1705 self.link_remove(self.links)
1706
1707 def tearDown(self):
1708 self.link_remove(self.links)
1709 self.remove_unit_from_networkd_path(self.units)
1710
1711 def test_ipv6_prefix_delegation(self):
1712 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
1713 self.start_networkd()
1714
1715 self.assertTrue(self.link_exits('veth99'))
1716
1717 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1718 print(output)
1719 self.assertRegex(output, '2002:da8:1:0')
1720
1721class NetworkdNetworkDHCPServerTests(unittest.TestCase, Utilities):
09ea6724
YW
1722 links = [
1723 'dummy98',
1724 'veth99']
1725
1726 units = [
1727 '12-dummy.netdev',
1728 '24-search-domain.network',
1729 '25-veth.netdev',
1730 'dhcp-client.network',
1731 'dhcp-client-timezone-router.network',
1732 'dhcp-server.network',
1733 'dhcp-server-timezone-router.network']
1f0e3109
SS
1734
1735 def setUp(self):
1736 self.link_remove(self.links)
1737
1738 def tearDown(self):
1739 self.link_remove(self.links)
1740 self.remove_unit_from_networkd_path(self.units)
1741
1742 def test_dhcp_server(self):
1743 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
1744 self.start_networkd()
1745
1746 self.assertTrue(self.link_exits('veth99'))
1747
1f0e3109
SS
1748 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1749 print(output)
1750 self.assertRegex(output, '192.168.5.*')
1751 self.assertRegex(output, 'Gateway: 192.168.5.1')
1752 self.assertRegex(output, 'DNS: 192.168.5.1')
1753 self.assertRegex(output, 'NTP: 192.168.5.1')
1754
1755 def test_domain(self):
f5d191a9 1756 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
1f0e3109
SS
1757 self.start_networkd()
1758
1759 self.assertTrue(self.link_exits('dummy98'))
1760
1761 output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
1762 print(output)
1763 self.assertRegex(output, 'Address: 192.168.42.100')
1764 self.assertRegex(output, 'DNS: 192.168.42.1')
1765 self.assertRegex(output, 'Search Domains: one')
1766
1767 def test_emit_router_timezone(self):
1768 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
1769 self.start_networkd()
1770
1771 self.assertTrue(self.link_exits('veth99'))
1772
1773 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1774 print(output)
1775 self.assertRegex(output, 'Gateway: 192.168.5.*')
1776 self.assertRegex(output, '192.168.5.*')
1777 self.assertRegex(output, 'Europe/Berlin')
1778
1779class NetworkdNetworkDHCPClientTests(unittest.TestCase, Utilities):
09ea6724
YW
1780 links = [
1781 'dummy98',
18c613dc
YW
1782 'veth99',
1783 'vrf99']
09ea6724
YW
1784
1785 units = [
1786 '25-veth.netdev',
18c613dc
YW
1787 '25-vrf.netdev',
1788 '25-vrf.network',
09ea6724
YW
1789 'dhcp-client-anonymize.network',
1790 'dhcp-client-critical-connection.network',
af3b1498 1791 'dhcp-client-gateway-onlink-implicit.network',
09ea6724
YW
1792 'dhcp-client-ipv4-dhcp-settings.network',
1793 'dhcp-client-ipv4-only-ipv6-disabled.network',
1794 'dhcp-client-ipv4-only.network',
1795 'dhcp-client-ipv6-only.network',
1796 'dhcp-client-ipv6-rapid-commit.network',
1797 'dhcp-client-listen-port.network',
1798 'dhcp-client-route-metric.network',
1799 'dhcp-client-route-table.network',
18c613dc 1800 'dhcp-client-vrf.network',
3e9d5552 1801 'dhcp-client.network',
09ea6724 1802 'dhcp-server-veth-peer.network',
30d3b54e
YW
1803 'dhcp-v4-server-veth-peer.network',
1804 'static.network']
1f0e3109
SS
1805
1806 def setUp(self):
1807 self.link_remove(self.links)
1808 self.stop_dnsmasq(dnsmasq_pid_file)
1809
1810 def tearDown(self):
1811 self.link_remove(self.links)
1812 self.remove_unit_from_networkd_path(self.units)
1813 self.stop_dnsmasq(dnsmasq_pid_file)
1814 self.remove_lease_file()
1815 self.remove_log_file()
1816
1817 def test_dhcp_client_ipv6_only(self):
f5d191a9 1818 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
1f0e3109
SS
1819 self.start_networkd()
1820
1821 self.assertTrue(self.link_exits('veth99'))
1822
1823 self.start_dnsmasq()
1824
1825 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1826 print(output)
1827 self.assertRegex(output, '2600::')
1828 self.assertNotRegex(output, '192.168.5')
1829
1830 def test_dhcp_client_ipv4_only(self):
f5d191a9 1831 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
1f0e3109
SS
1832 self.start_networkd()
1833
1834 self.assertTrue(self.link_exits('veth99'))
1835
1836 self.start_dnsmasq()
1837
1838 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1839 print(output)
1840 self.assertNotRegex(output, '2600::')
1841 self.assertRegex(output, '192.168.5')
1842
1843 def test_dhcp_client_ipv4_ipv6(self):
1844 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
1845 'dhcp-client-ipv4-only.network')
1846 self.start_networkd()
1847
1848 self.assertTrue(self.link_exits('veth99'))
1849
1850 self.start_dnsmasq()
1851
1852 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1853 print(output)
1854 self.assertRegex(output, '2600::')
1855 self.assertRegex(output, '192.168.5')
1856
1857 def test_dhcp_client_settings(self):
1858 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
1859 self.start_networkd()
1860
1861 self.assertTrue(self.link_exits('veth99'))
1862
1863 self.start_dnsmasq()
1864
0ae7a66d 1865 print('## ip address show dev veth99')
1f0e3109
SS
1866 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
1867 print(output)
1868 self.assertRegex(output, '12:34:56:78:9a:bc')
1869 self.assertRegex(output, '192.168.5')
1870 self.assertRegex(output, '1492')
1871
0ae7a66d
YW
1872 # issue #8726
1873 print('## ip route show table main dev veth99')
1874 output = subprocess.check_output(['ip', 'route', 'show', 'table', 'main', 'dev', 'veth99']).rstrip().decode('utf-8')
1f0e3109 1875 print(output)
0ae7a66d 1876 self.assertNotRegex(output, 'proto dhcp')
1f0e3109 1877
0ae7a66d
YW
1878 print('## ip route show table 211 dev veth99')
1879 output = subprocess.check_output(['ip', 'route', 'show', 'table', '211', 'dev', 'veth99']).rstrip().decode('utf-8')
1880 print(output)
1881 self.assertRegex(output, 'default via 192.168.5.1 proto dhcp')
1882 self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
1883 self.assertRegex(output, '192.168.5.1 proto dhcp scope link')
1884
1885 print('## dnsmasq log')
131717cb
YW
1886 self.assertTrue(self.search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
1887 self.assertTrue(self.search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
1888 self.assertTrue(self.search_words_in_dnsmasq_log('client provides name: test-hostname'))
1889 self.assertTrue(self.search_words_in_dnsmasq_log('26:mtu'))
1f0e3109
SS
1890
1891 def test_dhcp6_client_settings_rapidcommit_true(self):
1892 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
1893 self.start_networkd()
1894
1895 self.assertTrue(self.link_exits('veth99'))
1896
1897 self.start_dnsmasq()
1898
1899 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
1900 print(output)
1901 self.assertRegex(output, '12:34:56:78:9a:bc')
131717cb 1902 self.assertTrue(self.search_words_in_dnsmasq_log('14:rapid-commit', True))
1f0e3109
SS
1903
1904 def test_dhcp6_client_settings_rapidcommit_false(self):
1905 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
1906 self.start_networkd()
1907
1908 self.assertTrue(self.link_exits('veth99'))
1909
1910 self.start_dnsmasq()
1911
1912 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
1913 print(output)
1914 self.assertRegex(output, '12:34:56:78:9a:bc')
131717cb 1915 self.assertFalse(self.search_words_in_dnsmasq_log('14:rapid-commit', True))
1f0e3109
SS
1916
1917 def test_dhcp_client_settings_anonymize(self):
1918 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
1919 self.start_networkd()
1920
1921 self.assertTrue(self.link_exits('veth99'))
1922
1923 self.start_dnsmasq()
e40a58b5 1924
131717cb
YW
1925 self.assertFalse(self.search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
1926 self.assertFalse(self.search_words_in_dnsmasq_log('test-hostname'))
1927 self.assertFalse(self.search_words_in_dnsmasq_log('26:mtu'))
1f0e3109
SS
1928
1929 def test_dhcp_client_listen_port(self):
1930 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
1f0e3109
SS
1931 self.start_networkd()
1932
1933 self.assertTrue(self.link_exits('veth99'))
1934
b412fce8 1935 self.start_dnsmasq('--dhcp-alternate-port=67,5555')
1f0e3109 1936
b412fce8
YW
1937 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
1938 print(output)
1939 self.assertRegex(output, '192.168.5.* dynamic')
1f0e3109
SS
1940
1941 def test_dhcp_route_table_id(self):
1942 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
1943 self.start_networkd()
1f0e3109
SS
1944
1945 self.assertTrue(self.link_exits('veth99'))
1946
e40a58b5
YW
1947 self.start_dnsmasq()
1948
1f0e3109
SS
1949 output = subprocess.check_output(['ip', 'route', 'show', 'table', '12']).rstrip().decode('utf-8')
1950 print(output)
1f0e3109
SS
1951 self.assertRegex(output, 'veth99 proto dhcp')
1952 self.assertRegex(output, '192.168.5.1')
1953
1954 def test_dhcp_route_metric(self):
1955 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
1956 self.start_networkd()
1f0e3109
SS
1957
1958 self.assertTrue(self.link_exits('veth99'))
1959
e40a58b5
YW
1960 self.start_dnsmasq()
1961
1f0e3109
SS
1962 output = subprocess.check_output(['ip', 'route', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
1963 print(output)
1f0e3109
SS
1964 self.assertRegex(output, 'metric 24')
1965
1966 def test_dhcp_route_criticalconnection_true(self):
1967 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-critical-connection.network')
1968 self.start_networkd()
1f0e3109
SS
1969
1970 self.assertTrue(self.link_exits('veth99'))
1971
e40a58b5
YW
1972 self.start_dnsmasq()
1973
1f0e3109
SS
1974 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1975 print(output)
1f0e3109 1976 self.assertRegex(output, '192.168.5.*')
e40a58b5 1977
1f0e3109
SS
1978 # Stoping dnsmasq as networkd won't be allowed to renew the DHCP lease.
1979 self.stop_dnsmasq(dnsmasq_pid_file)
1980
1981 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
1982 time.sleep(125)
1983
1984 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
1985 print(output)
1986 self.assertRegex(output, '192.168.5.*')
1987
30d3b54e
YW
1988 def test_dhcp_client_reuse_address_as_static(self):
1989 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
1990 self.start_networkd()
1991
1992 self.assertTrue(self.link_exits('veth99'))
1993
1994 self.start_dnsmasq()
1995
1996 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99', 'scope', 'global']).rstrip().decode('utf-8')
1997 print(output)
1998 self.assertRegex(output, '192.168.5')
1999 self.assertRegex(output, '2600::')
2000
2001 ipv4_address = re.search('192\.168\.5\.[0-9]*/24', output)
2002 ipv6_address = re.search('2600::[0-9a-f:]*/128', output)
2003 static_network = '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address.group(), 'Address=' + ipv6_address.group()])
2004 print(static_network)
2005
2006 self.remove_unit_from_networkd_path(['dhcp-client.network'])
2007
2008 with open(os.path.join(network_unit_file_path, 'static.network'), mode='w') as f:
2009 f.write(static_network)
2010
2011 self.start_networkd()
2012
2013 self.assertTrue(self.link_exits('veth99'))
2014
2015 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global']).rstrip().decode('utf-8')
2016 print(output)
2017 self.assertRegex(output, '192.168.5')
2018 self.assertRegex(output, 'valid_lft forever preferred_lft forever')
2019
2020 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global']).rstrip().decode('utf-8')
2021 print(output)
2022 self.assertRegex(output, '2600::')
2023 self.assertRegex(output, 'valid_lft forever preferred_lft forever')
2024
18c613dc
YW
2025 @expectedFailureIfModuleIsNotAvailable('vrf')
2026 def test_dhcp_client_vrf(self):
2027 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
2028 '25-vrf.netdev', '25-vrf.network')
2029 self.start_networkd()
2030
2031 self.assertTrue(self.link_exits('veth99'))
2032 self.assertTrue(self.link_exits('vrf99'))
2033
2034 self.start_dnsmasq()
2035
2036 print('## ip -d link show dev vrf99')
2037 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'dev', 'vrf99']).rstrip().decode('utf-8')
2038 print(output)
2039 self.assertRegex(output, 'vrf table 42')
2040
2041 print('## ip address show vrf vrf99')
2042 output_ip_vrf = subprocess.check_output(['ip', 'address', 'show', 'vrf', 'vrf99']).rstrip().decode('utf-8')
2043 print(output_ip_vrf)
2044
2045 print('## ip address show dev veth99')
2046 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
2047 print(output)
2048 self.assertEqual(output, output_ip_vrf)
2049 self.assertRegex(output, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2050 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2051 self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic noprefixroute')
2052 self.assertRegex(output, 'inet6 .* scope link')
2053
2054 print('## ip route show vrf vrf99')
2055 output = subprocess.check_output(['ip', 'route', 'show', 'vrf', 'vrf99']).rstrip().decode('utf-8')
2056 print(output)
2057 self.assertRegex(output, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
2058 self.assertRegex(output, 'default dev veth99 proto static scope link')
2059 self.assertRegex(output, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
2060 self.assertRegex(output, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
2061 self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
2062 self.assertRegex(output, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
2063
2064 print('## ip route show table main dev veth99')
2065 output = subprocess.check_output(['ip', 'route', 'show', 'table', 'main', 'dev', 'veth99']).rstrip().decode('utf-8')
2066 print(output)
2067 self.assertEqual(output, '')
2068
2069 output = subprocess.check_output(['networkctl', 'status', 'vrf99']).rstrip().decode('utf-8')
2070 print(output)
2071 self.assertRegex(output, 'State: carrier \(configured\)')
2072
2073 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
2074 print(output)
2075 self.assertRegex(output, 'State: routable \(configured\)')
2076
af3b1498
YW
2077 def test_dhcp_client_gateway_onlink_implicit(self):
2078 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2079 'dhcp-client-gateway-onlink-implicit.network')
2080 self.start_networkd()
2081
2082 self.assertTrue(self.link_exits('veth99'))
2083
2084 self.start_dnsmasq()
2085
2086 output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
2087 print(output)
2088 self.assertRegex(output, '192.168.5')
2089
2090 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'veth99', '10.0.0.0/8']).rstrip().decode('utf-8')
2091 print(output)
2092 self.assertRegex(output, 'onlink')
2093 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'veth99', '192.168.100.0/24']).rstrip().decode('utf-8')
2094 print(output)
2095 self.assertRegex(output, 'onlink')
2096
1f0e3109
SS
2097if __name__ == '__main__':
2098 unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout,
2099 verbosity=3))