]> git.ipfire.org Git - thirdparty/systemd.git/blob - test/test-network/systemd-networkd-tests.py
Merge pull request #12573 from yuwata/network-dhcp-issue-12490
[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 '24-search-domain.network',
1098 '25-address-link-section.network',
1099 '25-address-preferred-lifetime-zero-ipv6.network',
1100 '25-address-static.network',
1101 '25-bind-carrier.network',
1102 '25-bond-active-backup-slave.netdev',
1103 '25-fibrule-invert.network',
1104 '25-fibrule-port-range.network',
1105 '25-ipv6-address-label-section.network',
1106 '25-neighbor-section.network',
1107 '25-link-local-addressing-no.network',
1108 '25-link-local-addressing-yes.network',
1109 '25-link-section-unmanaged.network',
1110 '25-route-ipv6-src.network',
1111 '25-route-static.network',
1112 '25-sysctl-disable-ipv6.network',
1113 '25-sysctl.network',
1114 'configure-without-carrier.network',
1115 'routing-policy-rule-dummy98.network',
1116 'routing-policy-rule-test1.network']
1117
1118 routing_policy_rule_tables = ['7', '8']
1119 routes = [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1120
1121 def setUp(self):
1122 self.remove_routing_policy_rule_tables(self.routing_policy_rule_tables)
1123 self.remove_routes(self.routes)
1124 self.remove_links(self.links)
1125
1126 def tearDown(self):
1127 self.remove_routing_policy_rule_tables(self.routing_policy_rule_tables)
1128 self.remove_routes(self.routes)
1129 self.remove_links(self.links)
1130 self.remove_unit_from_networkd_path(self.units)
1131
1132 def test_address_static(self):
1133 self.copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1134 self.start_networkd(0)
1135
1136 self.wait_online(['dummy98:routable'])
1137
1138 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98'], universal_newlines=True).rstrip()
1139 print(output)
1140 self.assertRegex(output, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1141 self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1142 self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1143
1144 # invalid sections
1145 self.assertNotRegex(output, '10.10.0.1/16')
1146 self.assertNotRegex(output, '10.10.0.2/16')
1147
1148 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98', 'label', '32'], universal_newlines=True).rstrip()
1149 self.assertRegex(output, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1150
1151 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98', 'label', '33'], universal_newlines=True).rstrip()
1152 self.assertRegex(output, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1153
1154 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98', 'label', '34'], universal_newlines=True).rstrip()
1155 self.assertRegex(output, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1156
1157 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98', 'label', '35'], universal_newlines=True).rstrip()
1158 self.assertRegex(output, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1159
1160 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'dummy98'], universal_newlines=True).rstrip()
1161 print(output)
1162 self.assertRegex(output, 'inet6 2001:db8:0:f101::15/64 scope global')
1163 self.assertRegex(output, 'inet6 2001:db8:0:f101::16/64 scope global')
1164 self.assertRegex(output, 'inet6 2001:db8:0:f102::15/64 scope global')
1165 self.assertRegex(output, 'inet6 2001:db8:0:f102::16/64 scope global')
1166 self.assertRegex(output, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1167 self.assertRegex(output, 'inet6 fd[0-9a-f:]*1/64 scope global')
1168
1169 def test_address_preferred_lifetime_zero_ipv6(self):
1170 self.copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero-ipv6.network', '12-dummy.netdev')
1171 self.start_networkd()
1172
1173 self.check_link_exists('dummy98')
1174
1175 self.check_operstate('dummy98', 'routable', setup_state='configuring')
1176
1177 output = subprocess.check_output(['ip', 'address', 'show', 'dummy98'], universal_newlines=True).rstrip()
1178 print(output)
1179 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1180 self.assertRegex(output, 'inet6 2001:db8:0:f101::1/64 scope global')
1181
1182 def test_configure_without_carrier(self):
1183 self.copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
1184 self.start_networkd()
1185
1186 self.check_link_exists('test1')
1187
1188 output = subprocess.check_output(['networkctl', 'status', 'test1'], universal_newlines=True).rstrip()
1189 print(output)
1190 self.assertRegex(output, '192.168.0.15')
1191 self.assertRegex(output, '192.168.0.1')
1192 self.assertRegex(output, 'routable')
1193
1194 def test_routing_policy_rule(self):
1195 self.copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1196
1197 self.start_networkd()
1198
1199 self.check_link_exists('test1')
1200
1201 output = subprocess.check_output(['ip', 'rule'], universal_newlines=True).rstrip()
1202 print(output)
1203 self.assertRegex(output, '111')
1204 self.assertRegex(output, 'from 192.168.100.18')
1205 self.assertRegex(output, r'tos (?:0x08|throughput)\s')
1206 self.assertRegex(output, 'iif test1')
1207 self.assertRegex(output, 'oif test1')
1208 self.assertRegex(output, 'lookup 7')
1209
1210 def test_routing_policy_rule_issue_11280(self):
1211 self.copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1212 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1213
1214 for trial in range(3):
1215 # Remove state files only first time
1216 self.start_networkd(remove_state_files=(trial == 0))
1217
1218 self.check_link_exists('test1')
1219 self.check_link_exists('dummy98')
1220
1221 output = subprocess.check_output(['ip', 'rule', 'list', 'table', '7'], universal_newlines=True).rstrip()
1222 print(output)
1223 self.assertRegex(output, '111: from 192.168.100.18 tos (?:0x08|throughput) iif test1 oif test1 lookup 7')
1224
1225 output = subprocess.check_output(['ip', 'rule', 'list', 'table', '8'], universal_newlines=True).rstrip()
1226 print(output)
1227 self.assertRegex(output, '112: from 192.168.101.18 tos (?:0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1228
1229 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1230 def test_routing_policy_rule_port_range(self):
1231 self.copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1232
1233 self.start_networkd()
1234
1235 self.check_link_exists('test1')
1236
1237 output = subprocess.check_output(['ip', 'rule'], universal_newlines=True).rstrip()
1238 print(output)
1239 self.assertRegex(output, '111')
1240 self.assertRegex(output, 'from 192.168.100.18')
1241 self.assertRegex(output, '1123-1150')
1242 self.assertRegex(output, '3224-3290')
1243 self.assertRegex(output, 'tcp')
1244 self.assertRegex(output, 'lookup 7')
1245
1246 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1247 def test_routing_policy_rule_invert(self):
1248 self.copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1249
1250 self.start_networkd()
1251
1252 self.check_link_exists('test1')
1253
1254 output = subprocess.check_output(['ip', 'rule'], universal_newlines=True).rstrip()
1255 print(output)
1256 self.assertRegex(output, '111')
1257 self.assertRegex(output, 'not.*?from.*?192.168.100.18')
1258 self.assertRegex(output, 'tcp')
1259 self.assertRegex(output, 'lookup 7')
1260
1261 def test_route_static(self):
1262 self.copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1263 self.start_networkd(0)
1264
1265 self.wait_online(['dummy98:routable'])
1266
1267 output = subprocess.check_output(['ip', '-6', 'route', 'show', 'dev', 'dummy98'], universal_newlines=True).rstrip()
1268 print(output)
1269 self.assertRegex(output, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1270 self.assertRegex(output, '2001:1234:5:8f63::1 proto kernel')
1271
1272 output = subprocess.check_output(['ip', '-6', 'route', 'show', 'dev', 'dummy98', 'default'], universal_newlines=True).rstrip()
1273 self.assertRegex(output, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1274
1275 output = subprocess.check_output(['ip', '-4', 'route', 'show', 'dev', 'dummy98'], universal_newlines=True).rstrip()
1276 print(output)
1277 self.assertRegex(output, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1278 self.assertRegex(output, '149.10.124.64 proto static scope link')
1279 self.assertRegex(output, '169.254.0.0/16 proto static scope link metric 2048')
1280 self.assertRegex(output, '192.168.1.1 proto static initcwnd 20')
1281 self.assertRegex(output, '192.168.1.2 proto static initrwnd 30')
1282
1283 output = subprocess.check_output(['ip', '-4', 'route', 'show', 'dev', 'dummy98', 'default'], universal_newlines=True).rstrip()
1284 self.assertRegex(output, 'default via 149.10.125.65 proto static onlink')
1285 self.assertRegex(output, 'default via 149.10.124.64 proto static')
1286 self.assertRegex(output, 'default proto static')
1287
1288 output = subprocess.check_output(['ip', 'route', 'show', 'type', 'blackhole'], universal_newlines=True).rstrip()
1289 print(output)
1290 self.assertRegex(output, 'blackhole 202.54.1.2 proto static')
1291
1292 output = subprocess.check_output(['ip', 'route', 'show', 'type', 'unreachable'], universal_newlines=True).rstrip()
1293 print(output)
1294 self.assertRegex(output, 'unreachable 202.54.1.3 proto static')
1295
1296 output = subprocess.check_output(['ip', 'route', 'show', 'type', 'prohibit'], universal_newlines=True).rstrip()
1297 print(output)
1298 self.assertRegex(output, 'prohibit 202.54.1.4 proto static')
1299
1300 def test_ip_route_ipv6_src_route(self):
1301 # a dummy device does not make the addresses go through tentative state, so we
1302 # reuse a bond from an earlier test, which does make the addresses go through
1303 # tentative state, and do our test on that
1304 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')
1305 self.start_networkd()
1306
1307 self.check_link_exists('dummy98')
1308 self.check_link_exists('bond199')
1309
1310 output = subprocess.check_output(['ip', '-6', 'route', 'list', 'dev', 'bond199'], universal_newlines=True).rstrip()
1311 print(output)
1312 self.assertRegex(output, 'abcd::/16')
1313 self.assertRegex(output, 'src')
1314 self.assertRegex(output, '2001:1234:56:8f63::2')
1315
1316 def test_ip_link_mac_address(self):
1317 self.copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
1318 self.start_networkd()
1319
1320 self.check_link_exists('dummy98')
1321
1322 output = subprocess.check_output(['ip', 'link', 'show', 'dummy98'], universal_newlines=True).rstrip()
1323 print(output)
1324 self.assertRegex(output, '00:01:02:aa:bb:cc')
1325
1326 def test_ip_link_unmanaged(self):
1327 self.copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
1328 self.start_networkd()
1329
1330 self.check_link_exists('dummy98')
1331
1332 output = subprocess.check_output(['networkctl', 'status', 'dummy98'], universal_newlines=True).rstrip()
1333 print(output)
1334 self.assertRegex(output, 'unmanaged')
1335
1336 def test_ipv6_address_label(self):
1337 self.copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
1338 self.start_networkd()
1339
1340 self.check_link_exists('dummy98')
1341
1342 output = subprocess.check_output(['ip', 'addrlabel', 'list'], universal_newlines=True).rstrip()
1343 print(output)
1344 self.assertRegex(output, '2004:da8:1::/64')
1345
1346 def test_ipv6_neighbor(self):
1347 self.copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
1348 self.start_networkd()
1349
1350 self.check_link_exists('dummy98')
1351
1352 output = subprocess.check_output(['ip', 'neigh', 'list'], universal_newlines=True).rstrip()
1353 print(output)
1354 self.assertRegex(output, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
1355 self.assertRegex(output, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
1356
1357 def test_link_local_addressing(self):
1358 self.copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
1359 '25-link-local-addressing-no.network', '12-dummy.netdev')
1360 self.start_networkd(0)
1361 self.wait_online(['test1:degraded', 'dummy98:carrier'])
1362
1363 self.check_link_exists('test1')
1364 self.check_link_exists('dummy98')
1365
1366 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'test1'], universal_newlines=True).rstrip()
1367 print(output)
1368 self.assertRegex(output, 'inet .* scope link')
1369 self.assertRegex(output, 'inet6 .* scope link')
1370
1371 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'dummy98'], universal_newlines=True).rstrip()
1372 print(output)
1373 self.assertNotRegex(output, 'inet6* .* scope link')
1374
1375 self.check_operstate('test1', 'degraded')
1376 self.check_operstate('dummy98', 'carrier')
1377
1378 '''
1379 Documentation/networking/ip-sysctl.txt
1380
1381 addr_gen_mode - INTEGER
1382 Defines how link-local and autoconf addresses are generated.
1383
1384 0: generate address based on EUI64 (default)
1385 1: do no generate a link-local address, use EUI64 for addresses generated
1386 from autoconf
1387 2: generate stable privacy addresses, using the secret from
1388 stable_secret (RFC7217)
1389 3: generate stable privacy addresses, using a random secret if unset
1390 '''
1391
1392 test1_addr_gen_mode = ''
1393 if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'stable_secret')):
1394 with open(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'stable_secret')) as f:
1395 try:
1396 f.readline()
1397 except IOError:
1398 # if stable_secret is unset, then EIO is returned
1399 test1_addr_gen_mode = '0'
1400 else:
1401 test1_addr_gen_mode = '2'
1402 else:
1403 test1_addr_gen_mode = '0'
1404
1405 if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'addr_gen_mode')):
1406 self.assertEqual(self.read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode)
1407
1408 if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'dummy98'), 'addr_gen_mode')):
1409 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
1410
1411 def test_sysctl(self):
1412 self.copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
1413 self.start_networkd(0)
1414 self.wait_online(['dummy98:degraded'])
1415
1416 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
1417 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
1418 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
1419 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
1420 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
1421 self.assertEqual(self.read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
1422 self.assertEqual(self.read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
1423
1424 def test_sysctl_disable_ipv6(self):
1425 self.copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
1426
1427 print('## Disable ipv6')
1428 self.assertEqual(subprocess.call(['sysctl', 'net.ipv6.conf.all.disable_ipv6=1']), 0)
1429 self.assertEqual(subprocess.call(['sysctl', 'net.ipv6.conf.default.disable_ipv6=1']), 0)
1430
1431 self.start_networkd(0)
1432 self.wait_online(['dummy98:routable'])
1433
1434 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dummy98'], universal_newlines=True).rstrip()
1435 print(output)
1436 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1437 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dummy98'], universal_newlines=True).rstrip()
1438 print(output)
1439 self.assertEqual(output, '')
1440 self.check_operstate('dummy98', 'routable')
1441
1442 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1443
1444 print('## Enable ipv6')
1445 self.assertEqual(subprocess.call(['sysctl', 'net.ipv6.conf.all.disable_ipv6=0']), 0)
1446 self.assertEqual(subprocess.call(['sysctl', 'net.ipv6.conf.default.disable_ipv6=0']), 0)
1447
1448 self.start_networkd(0)
1449 self.wait_online(['dummy98:routable'])
1450
1451 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dummy98'], universal_newlines=True).rstrip()
1452 print(output)
1453 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1454 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dummy98'], universal_newlines=True).rstrip()
1455 print(output)
1456 self.assertRegex(output, 'inet6 .* scope link')
1457 self.check_operstate('dummy98', 'routable')
1458
1459 def test_bind_carrier(self):
1460 self.copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
1461 self.start_networkd()
1462
1463 self.check_link_exists('test1')
1464
1465 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1466 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1467 time.sleep(2)
1468 output = subprocess.check_output(['ip', 'address', 'show', 'test1'], universal_newlines=True).rstrip()
1469 print(output)
1470 self.assertRegex(output, 'UP,LOWER_UP')
1471 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1472 self.check_operstate('test1', 'routable')
1473
1474 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy99', 'type', 'dummy']), 0)
1475 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy99', 'up']), 0)
1476 time.sleep(2)
1477 output = subprocess.check_output(['ip', 'address', 'show', 'test1'], universal_newlines=True).rstrip()
1478 print(output)
1479 self.assertRegex(output, 'UP,LOWER_UP')
1480 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1481 self.check_operstate('test1', 'routable')
1482
1483 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1484 time.sleep(2)
1485 output = subprocess.check_output(['ip', 'address', 'show', 'test1'], universal_newlines=True).rstrip()
1486 print(output)
1487 self.assertRegex(output, 'UP,LOWER_UP')
1488 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1489 self.check_operstate('test1', 'routable')
1490
1491 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy99']), 0)
1492 time.sleep(2)
1493 output = subprocess.check_output(['ip', 'address', 'show', 'test1'], universal_newlines=True).rstrip()
1494 print(output)
1495 self.assertNotRegex(output, 'UP,LOWER_UP')
1496 self.assertRegex(output, 'DOWN')
1497 self.assertNotRegex(output, '192.168.10')
1498 self.check_operstate('test1', 'off')
1499
1500 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1501 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1502 time.sleep(2)
1503 output = subprocess.check_output(['ip', 'address', 'show', 'test1'], universal_newlines=True).rstrip()
1504 print(output)
1505 self.assertRegex(output, 'UP,LOWER_UP')
1506 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1507 self.check_operstate('test1', 'routable')
1508
1509 def test_domain(self):
1510 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
1511 self.start_networkd(0)
1512 self.wait_online(['dummy98:routable'])
1513
1514 output = subprocess.check_output(['networkctl', 'status', 'dummy98'], universal_newlines=True).rstrip()
1515 print(output)
1516 self.assertRegex(output, 'Address: 192.168.42.100')
1517 self.assertRegex(output, 'DNS: 192.168.42.1')
1518 self.assertRegex(output, 'Search Domains: one')
1519
1520 class NetworkdBondTests(unittest.TestCase, Utilities):
1521 links = [
1522 'bond199',
1523 'bond99',
1524 'dummy98',
1525 'test1']
1526
1527 units = [
1528 '11-dummy.netdev',
1529 '12-dummy.netdev',
1530 '23-active-slave.network',
1531 '23-bond199.network',
1532 '23-primary-slave.network',
1533 '23-test1-bond199.network',
1534 '25-bond-active-backup-slave.netdev',
1535 '25-bond.netdev',
1536 'bond99.network',
1537 'bond-slave.network']
1538
1539 def setUp(self):
1540 self.remove_links(self.links)
1541
1542 def tearDown(self):
1543 self.remove_links(self.links)
1544 self.remove_unit_from_networkd_path(self.units)
1545
1546 def test_bond_active_slave(self):
1547 self.copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1548 self.start_networkd()
1549
1550 self.check_link_exists('dummy98')
1551 self.check_link_exists('bond199')
1552
1553 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond199'], universal_newlines=True).rstrip()
1554 print(output)
1555 self.assertRegex(output, 'active_slave dummy98')
1556
1557 def test_bond_primary_slave(self):
1558 self.copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-test1-bond199.network', '25-bond-active-backup-slave.netdev', '11-dummy.netdev')
1559 self.start_networkd()
1560
1561 self.check_link_exists('test1')
1562 self.check_link_exists('bond199')
1563
1564 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond199'], universal_newlines=True).rstrip()
1565 print(output)
1566 self.assertRegex(output, 'primary test1')
1567
1568 def test_bond_operstate(self):
1569 self.copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
1570 'bond99.network','bond-slave.network')
1571 self.start_networkd()
1572
1573 self.check_link_exists('bond99')
1574 self.check_link_exists('dummy98')
1575 self.check_link_exists('test1')
1576
1577 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'dummy98'], universal_newlines=True).rstrip()
1578 print(output)
1579 self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
1580
1581 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1'], universal_newlines=True).rstrip()
1582 print(output)
1583 self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
1584
1585 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond99'], universal_newlines=True).rstrip()
1586 print(output)
1587 self.assertRegex(output, 'MASTER,UP,LOWER_UP')
1588
1589 self.check_operstate('dummy98', 'enslaved')
1590 self.check_operstate('test1', 'enslaved')
1591 self.check_operstate('bond99', 'routable')
1592
1593 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'down']), 0)
1594 time.sleep(2)
1595
1596 self.check_operstate('dummy98', 'off')
1597 self.check_operstate('test1', 'enslaved')
1598 self.check_operstate('bond99', 'degraded-carrier')
1599
1600 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1601 time.sleep(2)
1602
1603 self.check_operstate('dummy98', 'enslaved')
1604 self.check_operstate('test1', 'enslaved')
1605 self.check_operstate('bond99', 'routable')
1606
1607 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'down']), 0)
1608 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'test1', 'down']), 0)
1609 time.sleep(2)
1610
1611 self.check_operstate('dummy98', 'off')
1612 self.check_operstate('test1', 'off')
1613
1614 for trial in range(30):
1615 if trial > 0:
1616 time.sleep(1)
1617 output = subprocess.check_output(['ip', 'address', 'show', 'bond99'], universal_newlines=True).rstrip()
1618 print(output)
1619 if self.get_operstate('bond99') == 'no-carrier':
1620 break
1621 else:
1622 # Huh? Kernel does not recognize that all slave interfaces are down?
1623 # Let's confirm that networkd's operstate is consistent with ip's result.
1624 self.assertNotRegex(output, 'NO-CARRIER')
1625
1626 class NetworkdBridgeTests(unittest.TestCase, Utilities):
1627 links = [
1628 'bridge99',
1629 'dummy98',
1630 'test1']
1631
1632 units = [
1633 '11-dummy.netdev',
1634 '12-dummy.netdev',
1635 '26-bridge.netdev',
1636 '26-bridge-slave-interface-1.network',
1637 '26-bridge-slave-interface-2.network',
1638 'bridge99-ignore-carrier-loss.network',
1639 'bridge99.network']
1640
1641 def setUp(self):
1642 self.remove_links(self.links)
1643
1644 def tearDown(self):
1645 self.remove_links(self.links)
1646 self.remove_unit_from_networkd_path(self.units)
1647
1648 def test_bridge_property(self):
1649 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1650 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1651 'bridge99.network')
1652 self.start_networkd()
1653
1654 self.check_link_exists('dummy98')
1655 self.check_link_exists('test1')
1656 self.check_link_exists('bridge99')
1657
1658 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1'], universal_newlines=True).rstrip()
1659 print(output)
1660 self.assertRegex(output, 'master')
1661 self.assertRegex(output, 'bridge')
1662
1663 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'dummy98'], universal_newlines=True).rstrip()
1664 print(output)
1665 self.assertRegex(output, 'master')
1666 self.assertRegex(output, 'bridge')
1667
1668 output = subprocess.check_output(['ip', 'addr', 'show', 'bridge99'], universal_newlines=True).rstrip()
1669 print(output)
1670 self.assertRegex(output, '192.168.0.15/24')
1671
1672 output = subprocess.check_output(['bridge', '-d', 'link', 'show', 'dummy98'], universal_newlines=True).rstrip()
1673 print(output)
1674 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
1675 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
1676 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
1677 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
1678 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
1679 if (os.path.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
1680 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
1681 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
1682
1683 # CONFIG_BRIDGE_IGMP_SNOOPING=y
1684 if (os.path.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
1685 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
1686
1687 self.check_operstate('test1', 'enslaved')
1688 self.check_operstate('dummy98', 'enslaved')
1689 self.check_operstate('bridge99', 'routable')
1690
1691 self.assertEqual(subprocess.call(['ip', 'address', 'add', '192.168.0.16/24', 'dev', 'bridge99']), 0)
1692 time.sleep(1)
1693
1694 output = subprocess.check_output(['ip', 'addr', 'show', 'bridge99'], universal_newlines=True).rstrip()
1695 print(output)
1696 self.assertRegex(output, '192.168.0.16/24')
1697
1698 self.check_operstate('bridge99', 'routable')
1699
1700 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'test1']), 0)
1701 time.sleep(3)
1702
1703 self.check_operstate('bridge99', 'degraded-carrier')
1704
1705 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1706 time.sleep(3)
1707
1708 self.check_operstate('bridge99', 'no-carrier')
1709
1710 output = subprocess.check_output(['ip', 'address', 'show', 'bridge99'], universal_newlines=True).rstrip()
1711 print(output)
1712 self.assertRegex(output, 'NO-CARRIER')
1713 self.assertNotRegex(output, '192.168.0.15/24')
1714 self.assertNotRegex(output, '192.168.0.16/24')
1715
1716 def test_bridge_ignore_carrier_loss(self):
1717 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1718 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1719 'bridge99-ignore-carrier-loss.network')
1720
1721 subprocess.call(['ip', 'rule', 'del', 'table', '100'])
1722
1723 self.start_networkd()
1724
1725 self.check_link_exists('dummy98')
1726 self.check_link_exists('test1')
1727 self.check_link_exists('bridge99')
1728
1729 self.assertEqual(subprocess.call(['ip', 'address', 'add', '192.168.0.16/24', 'dev', 'bridge99']), 0)
1730 time.sleep(1)
1731
1732 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'test1']), 0)
1733 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1734 time.sleep(3)
1735
1736 output = subprocess.check_output(['ip', 'address', 'show', 'bridge99'], universal_newlines=True).rstrip()
1737 print(output)
1738 self.assertRegex(output, 'NO-CARRIER')
1739 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1740 self.assertRegex(output, 'inet 192.168.0.16/24 scope global secondary bridge99')
1741
1742 subprocess.call(['ip', 'rule', 'del', 'table', '100'])
1743
1744 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self):
1745 self.copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
1746 'bridge99-ignore-carrier-loss.network')
1747
1748 subprocess.call(['ip', 'rule', 'del', 'table', '100'])
1749
1750 self.start_networkd()
1751
1752 self.check_link_exists('bridge99')
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 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1757
1758 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1759 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1760 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1761
1762 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1763 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1764 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1765
1766 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1767 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1768
1769 for trial in range(30):
1770 if trial > 0:
1771 time.sleep(1)
1772 if self.get_operstate('bridge99') == 'routable' and self.get_operstate('dummy98') == 'enslaved':
1773 break
1774 else:
1775 self.assertTrue(False)
1776
1777 output = subprocess.check_output(['ip', 'address', 'show', 'bridge99'], universal_newlines=True).rstrip()
1778 print(output)
1779 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1780
1781 output = subprocess.check_output(['ip', 'rule', 'list', 'table', '100'], universal_newlines=True).rstrip()
1782 print(output)
1783 self.assertEqual(output, '0: from all to 8.8.8.8 lookup 100')
1784
1785 subprocess.call(['ip', 'rule', 'del', 'table', '100'])
1786
1787 class NetworkdLLDPTests(unittest.TestCase, Utilities):
1788 links = ['veth99']
1789
1790 units = [
1791 '23-emit-lldp.network',
1792 '24-lldp.network',
1793 '25-veth.netdev']
1794
1795 def setUp(self):
1796 self.remove_links(self.links)
1797
1798 def tearDown(self):
1799 self.remove_links(self.links)
1800 self.remove_unit_from_networkd_path(self.units)
1801
1802 def test_lldp(self):
1803 self.copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
1804 self.start_networkd(0)
1805 self.wait_online(['veth99:degraded', 'veth-peer:degraded'])
1806
1807 output = subprocess.check_output(['networkctl', 'lldp'], universal_newlines=True).rstrip()
1808 print(output)
1809 self.assertRegex(output, 'veth-peer')
1810 self.assertRegex(output, 'veth99')
1811
1812 class NetworkdRATests(unittest.TestCase, Utilities):
1813 links = ['veth99']
1814
1815 units = [
1816 '25-veth.netdev',
1817 'ipv6-prefix.network',
1818 'ipv6-prefix-veth.network']
1819
1820 def setUp(self):
1821 self.remove_links(self.links)
1822
1823 def tearDown(self):
1824 self.remove_links(self.links)
1825 self.remove_unit_from_networkd_path(self.units)
1826
1827 def test_ipv6_prefix_delegation(self):
1828 self.warn_about_firewalld()
1829 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
1830 self.start_networkd(0)
1831 self.wait_online(['veth99:routable', 'veth-peer:degraded'])
1832
1833 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1834 print(output)
1835 self.assertRegex(output, '2002:da8:1:0')
1836
1837 class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
1838 links = ['veth99']
1839
1840 units = [
1841 '25-veth.netdev',
1842 'dhcp-client.network',
1843 'dhcp-client-timezone-router.network',
1844 'dhcp-server.network',
1845 'dhcp-server-timezone-router.network']
1846
1847 def setUp(self):
1848 self.remove_links(self.links)
1849
1850 def tearDown(self):
1851 self.remove_links(self.links)
1852 self.remove_unit_from_networkd_path(self.units)
1853
1854 def test_dhcp_server(self):
1855 self.warn_about_firewalld()
1856 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
1857 self.start_networkd(0)
1858 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1859
1860 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1861 print(output)
1862 self.assertRegex(output, '192.168.5.*')
1863 self.assertRegex(output, 'Gateway: 192.168.5.1')
1864 self.assertRegex(output, 'DNS: 192.168.5.1')
1865 self.assertRegex(output, 'NTP: 192.168.5.1')
1866
1867 def test_emit_router_timezone(self):
1868 self.warn_about_firewalld()
1869 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
1870 self.start_networkd(0)
1871 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1872
1873 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1874 print(output)
1875 self.assertRegex(output, 'Gateway: 192.168.5.*')
1876 self.assertRegex(output, '192.168.5.*')
1877 self.assertRegex(output, 'Europe/Berlin')
1878
1879 class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
1880 links = [
1881 'veth99',
1882 'vrf99']
1883
1884 units = [
1885 '25-veth.netdev',
1886 '25-vrf.netdev',
1887 '25-vrf.network',
1888 'dhcp-client-anonymize.network',
1889 'dhcp-client-critical-connection.network',
1890 'dhcp-client-gateway-onlink-implicit.network',
1891 'dhcp-client-ipv4-dhcp-settings.network',
1892 'dhcp-client-ipv4-only-ipv6-disabled.network',
1893 'dhcp-client-ipv4-only.network',
1894 'dhcp-client-ipv6-only.network',
1895 'dhcp-client-ipv6-rapid-commit.network',
1896 'dhcp-client-listen-port.network',
1897 'dhcp-client-route-metric.network',
1898 'dhcp-client-route-table.network',
1899 'dhcp-client-vrf.network',
1900 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
1901 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
1902 'dhcp-client.network',
1903 'dhcp-server-veth-peer.network',
1904 'dhcp-v4-server-veth-peer.network',
1905 'static.network']
1906
1907 def setUp(self):
1908 self.stop_dnsmasq(dnsmasq_pid_file)
1909 self.remove_links(self.links)
1910
1911 def tearDown(self):
1912 self.stop_dnsmasq(dnsmasq_pid_file)
1913 self.remove_lease_file()
1914 self.remove_log_file()
1915 self.remove_links(self.links)
1916 self.remove_unit_from_networkd_path(self.units)
1917
1918 def test_dhcp_client_ipv6_only(self):
1919 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
1920
1921 self.start_networkd(0)
1922 self.wait_online(['veth-peer:carrier'])
1923 self.start_dnsmasq()
1924 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1925
1926 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1927 print(output)
1928 self.assertRegex(output, '2600::')
1929 self.assertNotRegex(output, '192.168.5')
1930
1931 # Confirm that ipv6 token is not set in the kernel
1932 output = subprocess.check_output(['ip', 'token', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
1933 print(output)
1934 self.assertRegex(output, 'token :: dev veth99')
1935
1936 def test_dhcp_client_ipv4_only(self):
1937 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
1938
1939 self.start_networkd(0)
1940 self.wait_online(['veth-peer:carrier'])
1941 self.start_dnsmasq()
1942 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1943
1944 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1945 print(output)
1946 self.assertNotRegex(output, '2600::')
1947 self.assertRegex(output, '192.168.5')
1948
1949 def test_dhcp_client_ipv4_ipv6(self):
1950 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
1951 'dhcp-client-ipv4-only.network')
1952 self.start_networkd(0)
1953 self.wait_online(['veth-peer:carrier'])
1954 self.start_dnsmasq()
1955 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1956
1957 # link become 'routable' when at least one protocol provide an valid address.
1958 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255', ipv='-4')
1959 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128', ipv='-6')
1960
1961 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1962 print(output)
1963 self.assertRegex(output, '2600::')
1964 self.assertRegex(output, '192.168.5')
1965
1966 def test_dhcp_client_settings(self):
1967 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
1968
1969 self.start_networkd(0)
1970 self.wait_online(['veth-peer:carrier'])
1971 self.start_dnsmasq()
1972 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1973
1974 print('## ip address show dev veth99')
1975 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
1976 print(output)
1977 self.assertRegex(output, '12:34:56:78:9a:bc')
1978 self.assertRegex(output, '192.168.5')
1979 self.assertRegex(output, '1492')
1980
1981 # issue #8726
1982 print('## ip route show table main dev veth99')
1983 output = subprocess.check_output(['ip', 'route', 'show', 'table', 'main', 'dev', 'veth99'], universal_newlines=True).rstrip()
1984 print(output)
1985 self.assertNotRegex(output, 'proto dhcp')
1986
1987 print('## ip route show table 211 dev veth99')
1988 output = subprocess.check_output(['ip', 'route', 'show', 'table', '211', 'dev', 'veth99'], universal_newlines=True).rstrip()
1989 print(output)
1990 self.assertRegex(output, 'default via 192.168.5.1 proto dhcp')
1991 self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
1992 self.assertRegex(output, '192.168.5.1 proto dhcp scope link')
1993
1994 print('## dnsmasq log')
1995 self.assertTrue(self.search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
1996 self.assertTrue(self.search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
1997 self.assertTrue(self.search_words_in_dnsmasq_log('client provides name: test-hostname'))
1998 self.assertTrue(self.search_words_in_dnsmasq_log('26:mtu'))
1999
2000 def test_dhcp6_client_settings_rapidcommit_true(self):
2001 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2002 self.start_networkd(0)
2003 self.wait_online(['veth-peer:carrier'])
2004 self.start_dnsmasq()
2005 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2006
2007 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2008 print(output)
2009 self.assertRegex(output, '12:34:56:78:9a:bc')
2010 self.assertTrue(self.search_words_in_dnsmasq_log('14:rapid-commit', True))
2011
2012 def test_dhcp6_client_settings_rapidcommit_false(self):
2013 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
2014 self.start_networkd(0)
2015 self.wait_online(['veth-peer:carrier'])
2016 self.start_dnsmasq()
2017 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2018
2019 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2020 print(output)
2021 self.assertRegex(output, '12:34:56:78:9a:bc')
2022 self.assertFalse(self.search_words_in_dnsmasq_log('14:rapid-commit', True))
2023
2024 def test_dhcp_client_settings_anonymize(self):
2025 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
2026 self.start_networkd(0)
2027 self.wait_online(['veth-peer:carrier'])
2028 self.start_dnsmasq()
2029 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2030
2031 self.assertFalse(self.search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
2032 self.assertFalse(self.search_words_in_dnsmasq_log('test-hostname'))
2033 self.assertFalse(self.search_words_in_dnsmasq_log('26:mtu'))
2034
2035 def test_dhcp_client_listen_port(self):
2036 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
2037 self.start_networkd(0)
2038 self.wait_online(['veth-peer:carrier'])
2039 self.start_dnsmasq('--dhcp-alternate-port=67,5555')
2040 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2041
2042 # link become 'routable' when at least one protocol provide an valid address.
2043 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255', ipv='-4')
2044 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128', ipv='-6')
2045
2046 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2047 print(output)
2048 self.assertRegex(output, '192.168.5.* dynamic')
2049
2050 def test_dhcp_route_table_id(self):
2051 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
2052 self.start_networkd(0)
2053 self.wait_online(['veth-peer:carrier'])
2054 self.start_dnsmasq()
2055 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2056
2057 output = subprocess.check_output(['ip', 'route', 'show', 'table', '12'], universal_newlines=True).rstrip()
2058 print(output)
2059 self.assertRegex(output, 'veth99 proto dhcp')
2060 self.assertRegex(output, '192.168.5.1')
2061
2062 def test_dhcp_route_metric(self):
2063 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
2064 self.start_networkd(0)
2065 self.wait_online(['veth-peer:carrier'])
2066 self.start_dnsmasq()
2067 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2068
2069 output = subprocess.check_output(['ip', 'route', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2070 print(output)
2071 self.assertRegex(output, 'metric 24')
2072
2073 def test_dhcp_route_criticalconnection_true(self):
2074 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-critical-connection.network')
2075 self.start_networkd(0)
2076 self.wait_online(['veth-peer:carrier'])
2077 self.start_dnsmasq()
2078 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2079
2080 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
2081 print(output)
2082 self.assertRegex(output, '192.168.5.*')
2083
2084 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
2085 self.stop_dnsmasq(dnsmasq_pid_file)
2086
2087 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2088 time.sleep(125)
2089
2090 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
2091 print(output)
2092 self.assertRegex(output, '192.168.5.*')
2093
2094 def test_dhcp_client_reuse_address_as_static(self):
2095 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
2096 self.start_networkd(0)
2097 self.wait_online(['veth-peer:carrier'])
2098 self.start_dnsmasq()
2099 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2100
2101 # link become 'routable' when at least one protocol provide an valid address.
2102 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255', ipv='-4')
2103 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128', ipv='-6')
2104
2105 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99', 'scope', 'global'], universal_newlines=True).rstrip()
2106 print(output)
2107 self.assertRegex(output, '192.168.5')
2108 self.assertRegex(output, '2600::')
2109
2110 ipv4_address = re.search(r'192.168.5.[0-9]*/24', output)
2111 ipv6_address = re.search(r'2600::[0-9a-f:]*/128', output)
2112 static_network = '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address.group(), 'Address=' + ipv6_address.group()])
2113 print(static_network)
2114
2115 self.remove_unit_from_networkd_path(['dhcp-client.network'])
2116
2117 with open(os.path.join(network_unit_file_path, 'static.network'), mode='w') as f:
2118 f.write(static_network)
2119
2120 # When networkd started, the links are already configured, so let's wait for 5 seconds
2121 # the links to be re-configured.
2122 self.start_networkd(5)
2123 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2124
2125 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global'], universal_newlines=True).rstrip()
2126 print(output)
2127 self.assertRegex(output, '192.168.5')
2128 self.assertRegex(output, 'valid_lft forever preferred_lft forever')
2129
2130 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global'], universal_newlines=True).rstrip()
2131 print(output)
2132 self.assertRegex(output, '2600::')
2133 self.assertRegex(output, 'valid_lft forever preferred_lft forever')
2134
2135 @expectedFailureIfModuleIsNotAvailable('vrf')
2136 def test_dhcp_client_vrf(self):
2137 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
2138 '25-vrf.netdev', '25-vrf.network')
2139 self.start_networkd(0)
2140 self.wait_online(['veth-peer:carrier'])
2141 self.start_dnsmasq()
2142 self.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
2143
2144 # link become 'routable' when at least one protocol provide an valid address.
2145 self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255', ipv='-4')
2146 self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128', ipv='-6')
2147
2148 print('## ip -d link show dev vrf99')
2149 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'dev', 'vrf99'], universal_newlines=True).rstrip()
2150 print(output)
2151 self.assertRegex(output, 'vrf table 42')
2152
2153 print('## ip address show vrf vrf99')
2154 output_ip_vrf = subprocess.check_output(['ip', 'address', 'show', 'vrf', 'vrf99'], universal_newlines=True).rstrip()
2155 print(output_ip_vrf)
2156
2157 print('## ip address show dev veth99')
2158 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2159 print(output)
2160 self.assertEqual(output, output_ip_vrf)
2161 self.assertRegex(output, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2162 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2163 self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic noprefixroute')
2164 self.assertRegex(output, 'inet6 .* scope link')
2165
2166 print('## ip route show vrf vrf99')
2167 output = subprocess.check_output(['ip', 'route', 'show', 'vrf', 'vrf99'], universal_newlines=True).rstrip()
2168 print(output)
2169 self.assertRegex(output, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
2170 self.assertRegex(output, 'default dev veth99 proto static scope link')
2171 self.assertRegex(output, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
2172 self.assertRegex(output, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
2173 self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
2174 self.assertRegex(output, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
2175
2176 print('## ip route show table main dev veth99')
2177 output = subprocess.check_output(['ip', 'route', 'show', 'table', 'main', 'dev', 'veth99'], universal_newlines=True).rstrip()
2178 print(output)
2179 self.assertEqual(output, '')
2180
2181 self.check_operstate('vrf99', 'carrier')
2182 self.check_operstate('veth99', 'routable')
2183
2184 def test_dhcp_client_gateway_onlink_implicit(self):
2185 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2186 'dhcp-client-gateway-onlink-implicit.network')
2187 self.start_networkd(0)
2188 self.wait_online(['veth-peer:carrier'])
2189 self.start_dnsmasq()
2190 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2191
2192 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
2193 print(output)
2194 self.assertRegex(output, '192.168.5')
2195
2196 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'veth99', '10.0.0.0/8'], universal_newlines=True).rstrip()
2197 print(output)
2198 self.assertRegex(output, 'onlink')
2199 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'veth99', '192.168.100.0/24'], universal_newlines=True).rstrip()
2200 print(output)
2201 self.assertRegex(output, 'onlink')
2202
2203 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self):
2204 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2205 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
2206 self.start_networkd(0)
2207 self.wait_online(['veth-peer:carrier'])
2208 self.start_dnsmasq(lease_time='2m')
2209 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2210
2211 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2212 print(output)
2213
2214 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
2215 self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2216 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
2217 self.assertRegex(output, 'inet6 .* scope link')
2218 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
2219 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2220 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
2221 self.assertNotRegex(output, 'inet .* scope link')
2222
2223 print('Wait for the dynamic address to be expired')
2224 time.sleep(130)
2225
2226 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2227 print(output)
2228
2229 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
2230 self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2231 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
2232 self.assertRegex(output, 'inet6 .* scope link')
2233 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
2234 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2235 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
2236 self.assertNotRegex(output, 'inet .* scope link')
2237
2238 self.search_words_in_dnsmasq_log('DHCPOFFER', show_all=True)
2239
2240 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self):
2241 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2242 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
2243 self.start_networkd(0)
2244 self.wait_online(['veth99:degraded', 'veth-peer:routable'])
2245
2246 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2247 print(output)
2248
2249 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
2250 self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2251 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
2252 self.assertRegex(output, 'inet6 .* scope link')
2253 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
2254 self.assertNotRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2255 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
2256 self.assertRegex(output, 'inet .* scope link')
2257
2258 def test_dhcp_client_route_remove_on_renew(self):
2259 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2260 'dhcp-client-ipv4-only-ipv6-disabled.network')
2261 self.start_networkd(0)
2262 self.wait_online(['veth-peer:carrier'])
2263 self.start_dnsmasq(ipv4_range='192.168.5.100,192.168.5.199', lease_time='2m')
2264 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2265
2266 # test for issue #12490
2267
2268 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
2269 print(output)
2270 self.assertRegex(output, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2271 address1=None
2272 for line in output.splitlines():
2273 if 'brd 192.168.5.255 scope global dynamic veth99' in line:
2274 address1 = line.split()[1].split('/')[0]
2275 break
2276
2277 output = subprocess.check_output(['ip', '-4', 'route', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2278 print(output)
2279 self.assertRegex(output, f'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2280 self.assertRegex(output, f'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2281
2282 self.stop_dnsmasq(dnsmasq_pid_file)
2283 self.start_dnsmasq(ipv4_range='192.168.5.200,192.168.5.250', lease_time='2m')
2284
2285 print('Wait for the dynamic address to be expired')
2286 time.sleep(130)
2287
2288 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
2289 print(output)
2290 self.assertRegex(output, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2291 address2=None
2292 for line in output.splitlines():
2293 if 'brd 192.168.5.255 scope global dynamic veth99' in line:
2294 address2 = line.split()[1].split('/')[0]
2295 break
2296
2297 self.assertNotEqual(address1, address2)
2298
2299 output = subprocess.check_output(['ip', '-4', 'route', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2300 print(output)
2301 self.assertNotRegex(output, f'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2302 self.assertNotRegex(output, f'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2303 self.assertRegex(output, f'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
2304 self.assertRegex(output, f'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
2305
2306 if __name__ == '__main__':
2307 unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout,
2308 verbosity=3))