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