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