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