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