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