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