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