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