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