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