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