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