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