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