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