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