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