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