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