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