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