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