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