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