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