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