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