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