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