]> git.ipfire.org Git - thirdparty/systemd.git/blob - test/test-network/systemd-networkd-tests.py
test-network: remove routes even on failure
[thirdparty/systemd.git] / test / test-network / systemd-networkd-tests.py
1 #!/usr/bin/env python3
2 # SPDX-License-Identifier: LGPL-2.1+
3 # systemd-networkd tests
4
5 import os
6 import re
7 import shutil
8 import signal
9 import socket
10 import subprocess
11 import sys
12 import time
13 import unittest
14 from shutil import copytree
15
16 network_unit_file_path='/run/systemd/network'
17 networkd_runtime_directory='/run/systemd/netif'
18 networkd_ci_path='/run/networkd-ci'
19 network_sysctl_ipv6_path='/proc/sys/net/ipv6/conf'
20 network_sysctl_ipv4_path='/proc/sys/net/ipv4/conf'
21
22 dnsmasq_pid_file='/run/networkd-ci/test-test-dnsmasq.pid'
23 dnsmasq_log_file='/run/networkd-ci/test-dnsmasq-log-file'
24
25 wait_online_bin='/usr/lib/systemd/systemd-networkd-wait-online'
26
27 def is_module_available(module_name):
28 lsmod_output = subprocess.check_output('lsmod', universal_newlines=True)
29 module_re = re.compile(r'^{0}\b'.format(re.escape(module_name)), re.MULTILINE)
30 return module_re.search(lsmod_output) or not subprocess.call(["modprobe", module_name])
31
32 def expectedFailureIfModuleIsNotAvailable(module_name):
33 def f(func):
34 if not is_module_available(module_name):
35 return unittest.expectedFailure(func)
36 return func
37
38 return f
39
40 def expectedFailureIfERSPANModuleIsNotAvailable():
41 def f(func):
42 rc = subprocess.call(['ip', 'link', 'add', 'dev', 'erspan99', 'type', 'erspan', 'seq', 'key', '30', 'local', '192.168.1.4', 'remote', '192.168.1.1', 'erspan_ver', '1', 'erspan', '123'])
43 if rc == 0:
44 subprocess.call(['ip', 'link', 'del', 'erspan99'])
45 return func
46 else:
47 return unittest.expectedFailure(func)
48
49 return f
50
51 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable():
52 def f(func):
53 rc = subprocess.call(['ip', 'rule', 'add', 'from', '192.168.100.19', 'sport', '1123-1150', 'dport', '3224-3290', 'table', '7'])
54 if rc == 0:
55 subprocess.call(['ip', 'rule', 'del', 'from', '192.168.100.19', 'sport', '1123-1150', 'dport', '3224-3290', 'table', '7'])
56 return func
57 else:
58 return unittest.expectedFailure(func)
59
60 return f
61
62 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
63 def f(func):
64 rc = subprocess.call(['ip', 'rule', 'add', 'not', 'from', '192.168.100.19', 'ipproto', 'tcp', 'table', '7'])
65 if rc == 0:
66 subprocess.call(['ip', 'rule', 'del', 'not', 'from', '192.168.100.19', 'ipproto', 'tcp', 'table', '7'])
67 return func
68 else:
69 return unittest.expectedFailure(func)
70
71 return f
72
73 def setUpModule():
74 os.makedirs(network_unit_file_path, exist_ok=True)
75 os.makedirs(networkd_ci_path, exist_ok=True)
76
77 shutil.rmtree(networkd_ci_path)
78 copytree(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'conf'), networkd_ci_path)
79
80 subprocess.check_call('systemctl stop systemd-networkd.socket', shell=True)
81
82 def tearDownModule():
83 shutil.rmtree(networkd_ci_path)
84
85 subprocess.check_call('systemctl stop systemd-networkd.service', shell=True)
86 subprocess.check_call('systemctl start systemd-networkd.socket', shell=True)
87 subprocess.check_call('systemctl start systemd-networkd.service', shell=True)
88
89 class Utilities():
90 def read_link_attr(self, link, dev, attribute):
91 with open(os.path.join(os.path.join(os.path.join('/sys/class/net/', link), dev), attribute)) as f:
92 return f.readline().strip()
93
94 def read_bridge_port_attr(self, bridge, link, attribute):
95
96 path_bridge = os.path.join('/sys/devices/virtual/net', bridge)
97 path_port = 'lower_' + link + '/brport'
98 path = os.path.join(path_bridge, path_port)
99
100 with open(os.path.join(path, attribute)) as f:
101 return f.readline().strip()
102
103 def link_exists(self, link):
104 return os.path.exists(os.path.join('/sys/class/net', link))
105
106 def check_link_exists(self, link):
107 self.assertTrue(self.link_exists(link))
108
109 def link_remove(self, links):
110 for link in links:
111 if self.link_exists(link):
112 subprocess.call(['ip', 'link', 'del', 'dev', link])
113 time.sleep(1)
114
115 def remove_fou_ports(self, ports):
116 for port in ports:
117 subprocess.call(['ip', 'fou', 'del', 'port', port])
118
119 def remove_routing_policy_rule_tables(self, tables):
120 for table in tables:
121 subprocess.call(['ip', 'rule', 'del', 'table', table])
122
123 def remove_routes(self, routes):
124 for route_type, addr in routes:
125 subprocess.call(['ip', 'route', 'del', route_type, addr])
126
127 def l2tp_tunnel_remove(self, tunnel_ids):
128 output = subprocess.check_output(['ip', 'l2tp', 'show', 'tunnel'], universal_newlines=True).rstrip()
129 for tid in tunnel_ids:
130 words='Tunnel ' + tid + ', encap'
131 if words in output:
132 subprocess.call(['ip', 'l2tp', 'del', 'tunnel', 'tid', tid])
133 time.sleep(1)
134
135 def read_ipv6_sysctl_attr(self, link, attribute):
136 with open(os.path.join(os.path.join(network_sysctl_ipv6_path, link), attribute)) as f:
137 return f.readline().strip()
138
139 def read_ipv4_sysctl_attr(self, link, attribute):
140 with open(os.path.join(os.path.join(network_sysctl_ipv4_path, link), attribute)) as f:
141 return f.readline().strip()
142
143 def copy_unit_to_networkd_unit_path(self, *units):
144 print()
145 for unit in units:
146 shutil.copy(os.path.join(networkd_ci_path, unit), network_unit_file_path)
147 if (os.path.exists(os.path.join(networkd_ci_path, unit + '.d'))):
148 copytree(os.path.join(networkd_ci_path, unit + '.d'), os.path.join(network_unit_file_path, unit + '.d'))
149
150 def remove_unit_from_networkd_path(self, units):
151 for unit in units:
152 if (os.path.exists(os.path.join(network_unit_file_path, unit))):
153 os.remove(os.path.join(network_unit_file_path, unit))
154 if (os.path.exists(os.path.join(network_unit_file_path, unit + '.d'))):
155 shutil.rmtree(os.path.join(network_unit_file_path, unit + '.d'))
156
157 def warn_about_firewalld(self):
158 rc = subprocess.call(['systemctl', '-q', 'is-active', 'firewalld.service'])
159 if rc == 0:
160 print('\nWARNING: firewalld.service is active. The test may fail.')
161
162 def start_dnsmasq(self, additional_options='', ipv4_range='192.168.5.10,192.168.5.200', ipv6_range='2600::10,2600::20', lease_time='1h'):
163 self.warn_about_firewalld()
164 dnsmasq_command = f'dnsmasq -8 /var/run/networkd-ci/test-dnsmasq-log-file --log-queries=extra --log-dhcp --pid-file=/var/run/networkd-ci/test-test-dnsmasq.pid --conf-file=/dev/null --interface=veth-peer --enable-ra --dhcp-range={ipv6_range},{lease_time} --dhcp-range={ipv4_range},{lease_time} -R --dhcp-leasefile=/var/run/networkd-ci/lease --dhcp-option=26,1492 --dhcp-option=option:router,192.168.5.1 --dhcp-option=33,192.168.5.4,192.168.5.5 --port=0 ' + additional_options
165 subprocess.check_call(dnsmasq_command, shell=True)
166
167 time.sleep(10)
168
169 def stop_dnsmasq(self, pid_file):
170 if os.path.exists(pid_file):
171 with open(pid_file, 'r') as f:
172 pid = f.read().rstrip(' \t\r\n\0')
173 os.kill(int(pid), signal.SIGTERM)
174
175 os.remove(pid_file)
176
177 def search_words_in_dnsmasq_log(self, words, show_all=False):
178 if os.path.exists(dnsmasq_log_file):
179 with open (dnsmasq_log_file) as in_file:
180 contents = in_file.read()
181 if show_all:
182 print(contents)
183 for line in contents.splitlines():
184 if words in line:
185 in_file.close()
186 print("%s, %s" % (words, line))
187 return True
188 return False
189
190 def remove_lease_file(self):
191 if os.path.exists(os.path.join(networkd_ci_path, 'lease')):
192 os.remove(os.path.join(networkd_ci_path, 'lease'))
193
194 def remove_log_file(self):
195 if os.path.exists(dnsmasq_log_file):
196 os.remove(dnsmasq_log_file)
197
198 def start_networkd(self, sleep_sec=5, remove_state_files=True):
199 if (remove_state_files and
200 os.path.exists(os.path.join(networkd_runtime_directory, 'state'))):
201 subprocess.check_call('systemctl stop systemd-networkd', shell=True)
202 os.remove(os.path.join(networkd_runtime_directory, 'state'))
203 subprocess.check_call('systemctl start systemd-networkd', shell=True)
204 else:
205 subprocess.check_call('systemctl restart systemd-networkd', shell=True)
206 if sleep_sec > 0:
207 time.sleep(sleep_sec)
208
209 def wait_online(self, links_with_operstate, timeout='20s', bool_any=False):
210 args = [wait_online_bin, f'--timeout={timeout}'] + [f'--interface={link}' for link in links_with_operstate]
211 if bool_any:
212 args += ['--any']
213 try:
214 subprocess.check_call(args)
215 except subprocess.CalledProcessError:
216 for link in links_with_operstate:
217 output = subprocess.check_output(['networkctl', 'status', link.split(':')[0]], universal_newlines=True).rstrip()
218 print(output)
219 raise
220
221 def get_operstate(self, link, show_status=True, setup_state='configured'):
222 output = subprocess.check_output(['networkctl', 'status', link], universal_newlines=True).rstrip()
223 if show_status:
224 print(output)
225 for line in output.splitlines():
226 if 'State:' in line and (not setup_state or setup_state in line):
227 return line.split()[1]
228 return None
229
230 def check_operstate(self, link, expected, show_status=True, setup_state='configured'):
231 self.assertRegex(self.get_operstate(link, show_status, setup_state), expected)
232
233
234 class NetworkdNetDevTests(unittest.TestCase, Utilities):
235
236 links =[
237 '6rdtun99',
238 'bond99',
239 'bridge99',
240 'dropin-test',
241 'dummy98',
242 'erspan98',
243 'erspan99',
244 'geneve99',
245 'gretap96',
246 'gretap98',
247 'gretap99',
248 'gretun96',
249 'gretun97',
250 'gretun98',
251 'gretun99',
252 'ip6gretap98',
253 'ip6gretap99',
254 'ip6gretun97',
255 'ip6gretun98',
256 'ip6gretun99',
257 'ip6tnl97',
258 'ip6tnl98',
259 'ip6tnl99',
260 'ipiptun96',
261 'ipiptun97',
262 'ipiptun98',
263 'ipiptun99',
264 'ipvlan99',
265 'ipvtap99',
266 'isataptun99',
267 'macvlan99',
268 'macvtap99',
269 'sittun96',
270 'sittun97',
271 'sittun98',
272 'sittun99',
273 'tap99',
274 'test1',
275 'tun99',
276 'vcan99',
277 'veth99',
278 'vlan99',
279 'vrf99',
280 'vti6tun97',
281 'vti6tun98',
282 'vti6tun99',
283 'vtitun97',
284 'vtitun98',
285 'vtitun99',
286 'vxcan99',
287 'vxlan99',
288 'wg98',
289 'wg99']
290
291 units = [
292 '10-dropin-test.netdev',
293 '11-dummy.netdev',
294 '11-dummy.network',
295 '12-dummy.netdev',
296 '15-name-conflict-test.netdev',
297 '21-macvlan.netdev',
298 '21-macvtap.netdev',
299 '21-vlan-test1.network',
300 '21-vlan.netdev',
301 '21-vlan.network',
302 '25-6rd-tunnel.netdev',
303 '25-bond.netdev',
304 '25-bond-balanced-tlb.netdev',
305 '25-bridge.netdev',
306 '25-bridge.network',
307 '25-erspan-tunnel-local-any.netdev',
308 '25-erspan-tunnel.netdev',
309 '25-fou-gretap.netdev',
310 '25-fou-gre.netdev',
311 '25-fou-ipip.netdev',
312 '25-fou-ipproto-gre.netdev',
313 '25-fou-ipproto-ipip.netdev',
314 '25-fou-sit.netdev',
315 '25-geneve.netdev',
316 '25-gretap-tunnel-local-any.netdev',
317 '25-gretap-tunnel.netdev',
318 '25-gre-tunnel-local-any.netdev',
319 '25-gre-tunnel-remote-any.netdev',
320 '25-gre-tunnel.netdev',
321 '25-ip6gretap-tunnel-local-any.netdev',
322 '25-ip6gretap-tunnel.netdev',
323 '25-ip6gre-tunnel-local-any.netdev',
324 '25-ip6gre-tunnel-remote-any.netdev',
325 '25-ip6gre-tunnel.netdev',
326 '25-ip6tnl-tunnel-remote-any.netdev',
327 '25-ip6tnl-tunnel-local-any.netdev',
328 '25-ip6tnl-tunnel.netdev',
329 '25-ipip-tunnel-independent.netdev',
330 '25-ipip-tunnel-local-any.netdev',
331 '25-ipip-tunnel-remote-any.netdev',
332 '25-ipip-tunnel.netdev',
333 '25-ipvlan.netdev',
334 '25-ipvtap.netdev',
335 '25-isatap-tunnel.netdev',
336 '25-macsec.key',
337 '25-macsec.netdev',
338 '25-macsec.network',
339 '25-sit-tunnel-local-any.netdev',
340 '25-sit-tunnel-remote-any.netdev',
341 '25-sit-tunnel.netdev',
342 '25-tap.netdev',
343 '25-tun.netdev',
344 '25-tunnel-local-any.network',
345 '25-tunnel-remote-any.network',
346 '25-tunnel.network',
347 '25-vcan.netdev',
348 '25-veth.netdev',
349 '25-vrf.netdev',
350 '25-vti6-tunnel-local-any.netdev',
351 '25-vti6-tunnel-remote-any.netdev',
352 '25-vti6-tunnel.netdev',
353 '25-vti-tunnel-local-any.netdev',
354 '25-vti-tunnel-remote-any.netdev',
355 '25-vti-tunnel.netdev',
356 '25-vxcan.netdev',
357 '25-vxlan.netdev',
358 '25-wireguard-23-peers.netdev',
359 '25-wireguard-23-peers.network',
360 '25-wireguard-preshared-key.txt',
361 '25-wireguard-private-key.txt',
362 '25-wireguard.netdev',
363 '25-wireguard.network',
364 '6rd.network',
365 'erspan.network',
366 'gre.network',
367 'gretap.network',
368 'gretun.network',
369 'ip6gretap.network',
370 'ip6gretun.network',
371 'ip6tnl.network',
372 'ipip.network',
373 'ipvlan.network',
374 'ipvtap.network',
375 'isatap.network',
376 'macsec.network',
377 'macvlan.network',
378 'macvtap.network',
379 'netdev-link-local-addressing-yes.network',
380 'sit.network',
381 'vti6.network',
382 'vti.network',
383 'vxlan-test1.network',
384 'vxlan.network']
385
386 fou_ports = [
387 '55555',
388 '55556']
389
390 def setUp(self):
391 self.remove_fou_ports(self.fou_ports)
392 self.link_remove(self.links)
393
394 def tearDown(self):
395 self.remove_fou_ports(self.fou_ports)
396 self.link_remove(self.links)
397 self.remove_unit_from_networkd_path(self.units)
398
399 def test_dropin_and_networkctl_glob(self):
400 self.copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
401 self.start_networkd(0)
402
403 self.wait_online(['dropin-test:off'])
404
405 # This also tests NetDev.Name= conflict and basic networkctl functionalities
406
407 output = subprocess.check_output(['ip', 'link', 'show', 'dropin-test'], universal_newlines=True).rstrip()
408 print(output)
409 self.assertRegex(output, '00:50:56:c0:00:28')
410
411 output = subprocess.check_output(['networkctl', 'list'], universal_newlines=True).rstrip()
412 self.assertRegex(output, '1 lo ')
413 self.assertRegex(output, 'dropin-test')
414
415 output = subprocess.check_output(['networkctl', 'list', 'dropin-test'], universal_newlines=True).rstrip()
416 self.assertNotRegex(output, '1 lo ')
417 self.assertRegex(output, 'dropin-test')
418
419 output = subprocess.check_output(['networkctl', 'list', 'dropin-*'], universal_newlines=True).rstrip()
420 self.assertNotRegex(output, '1 lo ')
421 self.assertRegex(output, 'dropin-test')
422
423 output = subprocess.check_output(['networkctl', 'status', 'dropin-*'], universal_newlines=True).rstrip()
424 self.assertNotRegex(output, '1: lo ')
425 self.assertRegex(output, 'dropin-test')
426
427 ret = subprocess.run(['ethtool', '--driver', 'dropin-test'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)
428 print(ret.stdout.rstrip())
429 if ret.returncode == 0 and re.search('driver: dummy', ret.stdout.rstrip()) != None:
430 self.assertRegex(output, 'Driver: dummy')
431 else:
432 print('ethtool does not support driver field at least for dummy interfaces, skipping test for Driver field of networkctl.')
433
434 def test_wait_online_any(self):
435 self.copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
436 self.start_networkd(0)
437
438 self.wait_online(['bridge99', 'test1:degraded'], bool_any=True)
439
440 self.check_operstate('bridge99', '(?:off|no-carrier)', setup_state='configuring')
441 self.check_operstate('test1', 'degraded')
442
443 def test_bridge(self):
444 self.copy_unit_to_networkd_unit_path('25-bridge.netdev')
445 self.start_networkd(0)
446
447 self.wait_online(['bridge99:off'])
448
449 tick = os.sysconf('SC_CLK_TCK')
450 self.assertEqual(9, round(float(self.read_link_attr('bridge99', 'bridge', 'hello_time')) / tick))
451 self.assertEqual(9, round(float(self.read_link_attr('bridge99', 'bridge', 'max_age')) / tick))
452 self.assertEqual(9, round(float(self.read_link_attr('bridge99', 'bridge','forward_delay')) / tick))
453 self.assertEqual(9, round(float(self.read_link_attr('bridge99', 'bridge','ageing_time')) / tick))
454 self.assertEqual(9, int(self.read_link_attr('bridge99', 'bridge','priority')))
455 self.assertEqual(1, int(self.read_link_attr('bridge99', 'bridge','multicast_querier')))
456 self.assertEqual(1, int(self.read_link_attr('bridge99', 'bridge','multicast_snooping')))
457 self.assertEqual(1, int(self.read_link_attr('bridge99', 'bridge','stp_state')))
458
459 def test_bond(self):
460 self.copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
461 self.start_networkd(0)
462
463 self.wait_online(['bond99:off', 'bond98:off'])
464
465 self.assertEqual('802.3ad 4', self.read_link_attr('bond99', 'bonding', 'mode'))
466 self.assertEqual('layer3+4 1', self.read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
467 self.assertEqual('1000', self.read_link_attr('bond99', 'bonding', 'miimon'))
468 self.assertEqual('fast 1', self.read_link_attr('bond99', 'bonding', 'lacp_rate'))
469 self.assertEqual('2000', self.read_link_attr('bond99', 'bonding', 'updelay'))
470 self.assertEqual('2000', self.read_link_attr('bond99', 'bonding', 'downdelay'))
471 self.assertEqual('4', self.read_link_attr('bond99', 'bonding', 'resend_igmp'))
472 self.assertEqual('1', self.read_link_attr('bond99', 'bonding', 'min_links'))
473 self.assertEqual('1218', self.read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
474 self.assertEqual('811', self.read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
475 self.assertEqual('00:11:22:33:44:55', self.read_link_attr('bond99', 'bonding', 'ad_actor_system'))
476
477 self.assertEqual('balance-tlb 5', self.read_link_attr('bond98', 'bonding', 'mode'))
478 self.assertEqual('1', self.read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
479
480 def test_vlan(self):
481 self.copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
482 '21-vlan.network', '21-vlan-test1.network')
483 self.start_networkd(0)
484
485 self.wait_online(['test1:degraded', 'vlan99:routable'])
486
487 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1'], universal_newlines=True).rstrip()
488 print(output)
489 self.assertRegex(output, ' mtu 2000 ')
490
491 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vlan99'], universal_newlines=True).rstrip()
492 print(output)
493 self.assertRegex(output, ' mtu 2000 ')
494 self.assertRegex(output, 'REORDER_HDR')
495 self.assertRegex(output, 'LOOSE_BINDING')
496 self.assertRegex(output, 'GVRP')
497 self.assertRegex(output, 'MVRP')
498 self.assertRegex(output, ' id 99 ')
499
500 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'test1'], universal_newlines=True).rstrip()
501 print(output)
502 self.assertRegex(output, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
503 self.assertRegex(output, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
504
505 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'vlan99'], universal_newlines=True).rstrip()
506 print(output)
507 self.assertRegex(output, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
508
509 def test_macvtap(self):
510 for mode in ['private', 'vepa', 'bridge', 'passthru']:
511 with self.subTest(mode=mode):
512 if mode != 'private':
513 self.tearDown()
514 self.copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
515 '11-dummy.netdev', 'macvtap.network')
516 with open(os.path.join(network_unit_file_path, '21-macvtap.netdev'), mode='a') as f:
517 f.write('[MACVTAP]\nMode=' + mode)
518 self.start_networkd(0)
519
520 self.wait_online(['macvtap99:degraded', 'test1:degraded'])
521
522 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'macvtap99'], universal_newlines=True).rstrip()
523 print(output)
524 self.assertRegex(output, 'macvtap mode ' + mode + ' ')
525
526 def test_macvlan(self):
527 for mode in ['private', 'vepa', 'bridge', 'passthru']:
528 with self.subTest(mode=mode):
529 if mode != 'private':
530 self.tearDown()
531 self.copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
532 '11-dummy.netdev', 'macvlan.network')
533 with open(os.path.join(network_unit_file_path, '21-macvlan.netdev'), mode='a') as f:
534 f.write('[MACVLAN]\nMode=' + mode)
535 self.start_networkd(0)
536
537 self.wait_online(['macvlan99:degraded', 'test1:degraded'])
538
539 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1'], universal_newlines=True).rstrip()
540 print(output)
541 self.assertRegex(output, ' mtu 2000 ')
542
543 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'macvlan99'], universal_newlines=True).rstrip()
544 print(output)
545 self.assertRegex(output, ' mtu 2000 ')
546 self.assertRegex(output, 'macvlan mode ' + mode + ' ')
547
548 @expectedFailureIfModuleIsNotAvailable('ipvlan')
549 def test_ipvlan(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-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
555 '11-dummy.netdev', 'ipvlan.network')
556 with open(os.path.join(network_unit_file_path, '25-ipvlan.netdev'), mode='a') as f:
557 f.write('[IPVLAN]\nMode=' + mode + '\nFlags=' + flag)
558
559 self.start_networkd(0)
560 self.wait_online(['ipvlan99:degraded', 'test1:degraded'])
561
562 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ipvlan99'], universal_newlines=True).rstrip()
563 print(output)
564 self.assertRegex(output, 'ipvlan *mode ' + mode.lower() + ' ' + flag)
565
566 @expectedFailureIfModuleIsNotAvailable('ipvtap')
567 def test_ipvtap(self):
568 for mode, flag in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
569 with self.subTest(mode=mode, flag=flag):
570 if mode != 'L2':
571 self.tearDown()
572 self.copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
573 '11-dummy.netdev', 'ipvtap.network')
574 with open(os.path.join(network_unit_file_path, '25-ipvtap.netdev'), mode='a') as f:
575 f.write('[IPVTAP]\nMode=' + mode + '\nFlags=' + flag)
576
577 self.start_networkd(0)
578 self.wait_online(['ipvtap99:degraded', 'test1:degraded'])
579
580 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ipvtap99'], universal_newlines=True).rstrip()
581 print(output)
582 self.assertRegex(output, 'ipvtap *mode ' + mode.lower() + ' ' + flag)
583
584 def test_veth(self):
585 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
586 self.start_networkd(0)
587
588 self.wait_online(['veth99:degraded', 'veth-peer:degraded'])
589
590 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'veth99'], universal_newlines=True).rstrip()
591 print(output)
592 self.assertRegex(output, 'link/ether 12:34:56:78:9a:bc')
593 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'veth-peer'], universal_newlines=True).rstrip()
594 print(output)
595 self.assertRegex(output, 'link/ether 12:34:56:78:9a:bd')
596
597 def test_tun(self):
598 self.copy_unit_to_networkd_unit_path('25-tun.netdev')
599 self.start_networkd(0)
600
601 self.wait_online(['tun99:off'])
602
603 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'tun99'], universal_newlines=True).rstrip()
604 print(output)
605 # Old ip command does not support IFF_ flags
606 self.assertRegex(output, 'tun (?:type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
607
608 def test_tap(self):
609 self.copy_unit_to_networkd_unit_path('25-tap.netdev')
610 self.start_networkd(0)
611
612 self.wait_online(['tap99:off'])
613
614 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'tap99'], universal_newlines=True).rstrip()
615 print(output)
616 # Old ip command does not support IFF_ flags
617 self.assertRegex(output, 'tun (?:type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
618
619 @expectedFailureIfModuleIsNotAvailable('vrf')
620 def test_vrf(self):
621 self.copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
622 self.start_networkd(0)
623
624 self.wait_online(['vrf99:carrier'])
625
626 @expectedFailureIfModuleIsNotAvailable('vcan')
627 def test_vcan(self):
628 self.copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
629 self.start_networkd(0)
630
631 self.wait_online(['vcan99:carrier'])
632
633 @expectedFailureIfModuleIsNotAvailable('vxcan')
634 def test_vxcan(self):
635 self.copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
636 self.start_networkd(0)
637
638 self.wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
639
640 @expectedFailureIfModuleIsNotAvailable('wireguard')
641 def test_wireguard(self):
642 self.copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
643 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
644 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt')
645 self.start_networkd(0)
646 self.wait_online(['wg99:carrier', 'wg98:routable'])
647
648 if shutil.which('wg'):
649 subprocess.call('wg')
650
651 output = subprocess.check_output(['wg', 'show', 'wg99', 'listen-port'], universal_newlines=True).rstrip()
652 self.assertRegex(output, '51820')
653 output = subprocess.check_output(['wg', 'show', 'wg99', 'fwmark'], universal_newlines=True).rstrip()
654 self.assertRegex(output, '0x4d2')
655 output = subprocess.check_output(['wg', 'show', 'wg99', 'allowed-ips'], universal_newlines=True).rstrip()
656 self.assertRegex(output, 'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
657 self.assertRegex(output, 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
658 output = subprocess.check_output(['wg', 'show', 'wg99', 'persistent-keepalive'], universal_newlines=True).rstrip()
659 self.assertRegex(output, 'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
660 output = subprocess.check_output(['wg', 'show', 'wg99', 'endpoints'], universal_newlines=True).rstrip()
661 self.assertRegex(output, 'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
662 output = subprocess.check_output(['wg', 'show', 'wg99', 'private-key'], universal_newlines=True).rstrip()
663 self.assertRegex(output, 'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
664 output = subprocess.check_output(['wg', 'show', 'wg99', 'preshared-keys'], universal_newlines=True).rstrip()
665 self.assertRegex(output, 'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
666 self.assertRegex(output, 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
667
668 output = subprocess.check_output(['wg', 'show', 'wg98', 'private-key'], universal_newlines=True).rstrip()
669 self.assertRegex(output, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
670
671 def test_geneve(self):
672 self.copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
673 self.start_networkd(0)
674
675 self.wait_online(['geneve99:degraded'])
676
677 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'geneve99'], universal_newlines=True).rstrip()
678 print(output)
679 self.assertRegex(output, '192.168.22.1')
680 self.assertRegex(output, '6082')
681 self.assertRegex(output, 'udpcsum')
682 self.assertRegex(output, 'udp6zerocsumrx')
683
684 def test_ipip_tunnel(self):
685 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
686 '25-ipip-tunnel.netdev', '25-tunnel.network',
687 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
688 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
689 self.start_networkd(0)
690 self.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'dummy98:degraded'])
691
692 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ipiptun99'], universal_newlines=True).rstrip()
693 print(output)
694 self.assertRegex(output, 'ipip (?:ipip |)remote 192.169.224.239 local 192.168.223.238 dev dummy98')
695 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ipiptun98'], universal_newlines=True).rstrip()
696 print(output)
697 self.assertRegex(output, 'ipip (?:ipip |)remote 192.169.224.239 local any dev dummy98')
698 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ipiptun97'], universal_newlines=True).rstrip()
699 print(output)
700 self.assertRegex(output, 'ipip (?:ipip |)remote any local 192.168.223.238 dev dummy98')
701
702 def test_gre_tunnel(self):
703 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
704 '25-gre-tunnel.netdev', '25-tunnel.network',
705 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
706 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
707 self.start_networkd(0)
708 self.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'dummy98:degraded'])
709
710 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretun99'], universal_newlines=True).rstrip()
711 print(output)
712 self.assertRegex(output, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
713 self.assertRegex(output, 'ikey 1.2.3.103')
714 self.assertRegex(output, 'okey 1.2.4.103')
715 self.assertRegex(output, 'iseq')
716 self.assertRegex(output, 'oseq')
717 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretun98'], universal_newlines=True).rstrip()
718 print(output)
719 self.assertRegex(output, 'gre remote 10.65.223.239 local any dev dummy98')
720 self.assertRegex(output, 'ikey 0.0.0.104')
721 self.assertRegex(output, 'okey 0.0.0.104')
722 self.assertNotRegex(output, 'iseq')
723 self.assertNotRegex(output, 'oseq')
724 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretun97'], universal_newlines=True).rstrip()
725 print(output)
726 self.assertRegex(output, 'gre remote any local 10.65.223.238 dev dummy98')
727 self.assertRegex(output, 'ikey 0.0.0.105')
728 self.assertRegex(output, 'okey 0.0.0.105')
729 self.assertNotRegex(output, 'iseq')
730 self.assertNotRegex(output, 'oseq')
731
732 def test_ip6gre_tunnel(self):
733 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
734 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
735 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
736 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
737 self.start_networkd()
738
739 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
740
741 self.check_link_exists('dummy98')
742 self.check_link_exists('ip6gretun99')
743 self.check_link_exists('ip6gretun98')
744 self.check_link_exists('ip6gretun97')
745
746 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6gretun99'], universal_newlines=True).rstrip()
747 print(output)
748 self.assertRegex(output, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
749 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6gretun98'], universal_newlines=True).rstrip()
750 print(output)
751 self.assertRegex(output, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
752 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6gretun97'], universal_newlines=True).rstrip()
753 print(output)
754 self.assertRegex(output, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
755
756 def test_gretap_tunnel(self):
757 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
758 '25-gretap-tunnel.netdev', '25-tunnel.network',
759 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
760 self.start_networkd(0)
761 self.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
762
763 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretap99'], universal_newlines=True).rstrip()
764 print(output)
765 self.assertRegex(output, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
766 self.assertRegex(output, 'ikey 0.0.0.106')
767 self.assertRegex(output, 'okey 0.0.0.106')
768 self.assertRegex(output, 'iseq')
769 self.assertRegex(output, 'oseq')
770 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretap98'], universal_newlines=True).rstrip()
771 print(output)
772 self.assertRegex(output, 'gretap remote 10.65.223.239 local any dev dummy98')
773 self.assertRegex(output, 'ikey 0.0.0.107')
774 self.assertRegex(output, 'okey 0.0.0.107')
775 self.assertRegex(output, 'iseq')
776 self.assertRegex(output, 'oseq')
777
778 def test_ip6gretap_tunnel(self):
779 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
780 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
781 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
782 self.start_networkd(0)
783 self.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
784
785 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6gretap99'], universal_newlines=True).rstrip()
786 print(output)
787 self.assertRegex(output, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
788 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6gretap98'], universal_newlines=True).rstrip()
789 print(output)
790 self.assertRegex(output, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
791
792 def test_vti_tunnel(self):
793 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
794 '25-vti-tunnel.netdev', '25-tunnel.network',
795 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
796 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
797 self.start_networkd(0)
798 self.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'dummy98:degraded'])
799
800 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vtitun99'], universal_newlines=True).rstrip()
801 print(output)
802 self.assertRegex(output, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
803 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vtitun98'], universal_newlines=True).rstrip()
804 print(output)
805 self.assertRegex(output, 'vti remote 10.65.223.239 local any dev dummy98')
806 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vtitun97'], universal_newlines=True).rstrip()
807 print(output)
808 self.assertRegex(output, 'vti remote any local 10.65.223.238 dev dummy98')
809
810 def test_vti6_tunnel(self):
811 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
812 '25-vti6-tunnel.netdev', '25-tunnel.network',
813 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
814 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
815 self.start_networkd(0)
816 self.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
817
818 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vti6tun99'], universal_newlines=True).rstrip()
819 print(output)
820 self.assertRegex(output, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
821 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vti6tun98'], universal_newlines=True).rstrip()
822 print(output)
823 self.assertRegex(output, 'vti6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
824 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vti6tun97'], universal_newlines=True).rstrip()
825 print(output)
826 self.assertRegex(output, 'vti6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
827
828 def test_ip6tnl_tunnel(self):
829 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
830 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
831 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
832 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
833 self.start_networkd(0)
834 self.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
835
836 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6tnl99'], universal_newlines=True).rstrip()
837 print(output)
838 self.assertRegex(output, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
839 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6tnl98'], universal_newlines=True).rstrip()
840 print(output)
841 self.assertRegex(output, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
842 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6tnl97'], universal_newlines=True).rstrip()
843 print(output)
844 self.assertRegex(output, 'ip6tnl ip6ip6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
845
846 def test_sit_tunnel(self):
847 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
848 '25-sit-tunnel.netdev', '25-tunnel.network',
849 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
850 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
851 self.start_networkd(0)
852 self.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'dummy98:degraded'])
853
854 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'sittun99'], universal_newlines=True).rstrip()
855 print(output)
856 self.assertRegex(output, "sit (?:ip6ip |)remote 10.65.223.239 local 10.65.223.238 dev dummy98")
857 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'sittun98'], universal_newlines=True).rstrip()
858 print(output)
859 self.assertRegex(output, "sit (?:ip6ip |)remote 10.65.223.239 local any dev dummy98")
860 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'sittun97'], universal_newlines=True).rstrip()
861 print(output)
862 self.assertRegex(output, "sit (?:ip6ip |)remote any local 10.65.223.238 dev dummy98")
863
864 def test_isatap_tunnel(self):
865 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
866 '25-isatap-tunnel.netdev', '25-tunnel.network')
867 self.start_networkd(0)
868 self.wait_online(['isataptun99:routable', 'dummy98:degraded'])
869
870 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'isataptun99'], universal_newlines=True).rstrip()
871 print(output)
872 self.assertRegex(output, "isatap ")
873
874 def test_6rd_tunnel(self):
875 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
876 '25-6rd-tunnel.netdev', '25-tunnel.network')
877 self.start_networkd(0)
878 self.wait_online(['sittun99:routable', 'dummy98:degraded'])
879
880 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'sittun99'], universal_newlines=True).rstrip()
881 print(output)
882 self.assertRegex(output, '6rd-prefix 2602::/24')
883
884 @expectedFailureIfERSPANModuleIsNotAvailable()
885 def test_erspan_tunnel(self):
886 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
887 '25-erspan-tunnel.netdev', '25-tunnel.network',
888 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
889 self.start_networkd(0)
890 self.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
891
892 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'erspan99'], universal_newlines=True).rstrip()
893 print(output)
894 self.assertRegex(output, 'erspan remote 172.16.1.100 local 172.16.1.200')
895 self.assertRegex(output, 'ikey 0.0.0.101')
896 self.assertRegex(output, 'okey 0.0.0.101')
897 self.assertRegex(output, 'iseq')
898 self.assertRegex(output, 'oseq')
899 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'erspan98'], universal_newlines=True).rstrip()
900 print(output)
901 self.assertRegex(output, 'erspan remote 172.16.1.100 local any')
902 self.assertRegex(output, '102')
903 self.assertRegex(output, 'ikey 0.0.0.102')
904 self.assertRegex(output, 'okey 0.0.0.102')
905 self.assertRegex(output, 'iseq')
906 self.assertRegex(output, 'oseq')
907
908 def test_tunnel_independent(self):
909 self.copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
910 self.start_networkd(0)
911
912 self.wait_online(['ipiptun99:carrier'])
913
914 @expectedFailureIfModuleIsNotAvailable('fou')
915 def test_fou(self):
916 # The following redundant check is necessary for CentOS CI.
917 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
918 self.assertTrue(is_module_available('fou'))
919
920 self.copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
921 '25-fou-ipip.netdev', '25-fou-sit.netdev',
922 '25-fou-gre.netdev', '25-fou-gretap.netdev')
923 self.start_networkd(0)
924
925 self.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'])
926
927 output = subprocess.check_output(['ip', 'fou', 'show'], universal_newlines=True).rstrip()
928 print(output)
929 self.assertRegex(output, 'port 55555 ipproto 4')
930 self.assertRegex(output, 'port 55556 ipproto 47')
931
932 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ipiptun96'], universal_newlines=True).rstrip()
933 print(output)
934 self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55555')
935 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'sittun96'], universal_newlines=True).rstrip()
936 print(output)
937 self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55555')
938 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretun96'], universal_newlines=True).rstrip()
939 print(output)
940 self.assertRegex(output, 'encap fou encap-sport 1001 encap-dport 55556')
941 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretap96'], universal_newlines=True).rstrip()
942 print(output)
943 self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55556')
944
945 def test_vxlan(self):
946 self.copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
947 '11-dummy.netdev', 'vxlan-test1.network')
948 self.start_networkd(0)
949
950 self.wait_online(['test1:degraded', 'vxlan99:degraded'])
951
952 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vxlan99'], universal_newlines=True).rstrip()
953 print(output)
954 self.assertRegex(output, '999')
955 self.assertRegex(output, '5555')
956 self.assertRegex(output, 'l2miss')
957 self.assertRegex(output, 'l3miss')
958 self.assertRegex(output, 'udpcsum')
959 self.assertRegex(output, 'udp6zerocsumtx')
960 self.assertRegex(output, 'udp6zerocsumrx')
961 self.assertRegex(output, 'remcsumtx')
962 self.assertRegex(output, 'remcsumrx')
963 self.assertRegex(output, 'gbp')
964
965 output = subprocess.check_output(['bridge', 'fdb', 'show', 'dev', 'vxlan99'], universal_newlines=True).rstrip()
966 print(output)
967 self.assertRegex(output, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
968 self.assertRegex(output, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
969 self.assertRegex(output, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
970
971 def test_macsec(self):
972 self.copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
973 'macsec.network', '12-dummy.netdev')
974 self.start_networkd(0)
975
976 self.wait_online(['dummy98:degraded', 'macsec99:routable'])
977
978 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'macsec99'], universal_newlines=True).rstrip()
979 print(output)
980 self.assertRegex(output, 'macsec99@dummy98')
981 self.assertRegex(output, 'macsec sci [0-9a-f]*000b')
982 self.assertRegex(output, 'encrypt on')
983
984 output = subprocess.check_output(['ip', 'macsec', 'show', 'macsec99'], universal_newlines=True).rstrip()
985 print(output)
986 self.assertRegex(output, 'encrypt on')
987 self.assertRegex(output, 'TXSC: [0-9a-f]*000b on SA 1')
988 self.assertRegex(output, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
989 self.assertRegex(output, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
990 self.assertRegex(output, 'RXSC: c619528fe6a00100, state on')
991 self.assertRegex(output, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
992 self.assertRegex(output, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
993 self.assertRegex(output, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
994 self.assertRegex(output, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
995 self.assertNotRegex(output, 'key 02030405067080900000000000000000')
996 self.assertRegex(output, 'RXSC: 8c16456c83a90002, state on')
997 self.assertRegex(output, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
998
999
1000 class NetworkdL2TPTests(unittest.TestCase, Utilities):
1001
1002 links =[
1003 'l2tp-ses1',
1004 'l2tp-ses2',
1005 'l2tp-ses3',
1006 'l2tp-ses4',
1007 'test1']
1008
1009 units = [
1010 '11-dummy.netdev',
1011 '25-l2tp-dummy.network',
1012 '25-l2tp-ip.netdev',
1013 '25-l2tp-udp.netdev']
1014
1015 l2tp_tunnel_ids = [ '10' ]
1016
1017 def setUp(self):
1018 self.l2tp_tunnel_remove(self.l2tp_tunnel_ids)
1019 self.link_remove(self.links)
1020
1021 def tearDown(self):
1022 self.l2tp_tunnel_remove(self.l2tp_tunnel_ids)
1023 self.link_remove(self.links)
1024 self.remove_unit_from_networkd_path(self.units)
1025
1026 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1027 def test_l2tp_udp(self):
1028 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-udp.netdev')
1029 self.start_networkd(0)
1030
1031 self.wait_online(['test1:routable', 'l2tp-ses1:off', 'l2tp-ses2:off'])
1032
1033 output = subprocess.check_output(['ip', 'l2tp', 'show', 'tunnel', 'tunnel_id', '10'], universal_newlines=True).rstrip()
1034 print(output)
1035 self.assertRegex(output, "Tunnel 10, encap UDP")
1036 self.assertRegex(output, "From 192.168.30.100 to 192.168.30.101")
1037 self.assertRegex(output, "Peer tunnel 11")
1038 self.assertRegex(output, "UDP source / dest ports: 3000/4000")
1039 self.assertRegex(output, "UDP checksum: enabled")
1040
1041 output = subprocess.check_output(['ip', 'l2tp', 'show', 'session', 'tid', '10', 'session_id', '15'], universal_newlines=True).rstrip()
1042 print(output)
1043 self.assertRegex(output, "Session 15 in tunnel 10")
1044 self.assertRegex(output, "Peer session 16, tunnel 11")
1045 self.assertRegex(output, "interface name: l2tp-ses1")
1046
1047 output = subprocess.check_output(['ip', 'l2tp', 'show', 'session', 'tid', '10', 'session_id', '17'], universal_newlines=True).rstrip()
1048 print(output)
1049 self.assertRegex(output, "Session 17 in tunnel 10")
1050 self.assertRegex(output, "Peer session 18, tunnel 11")
1051 self.assertRegex(output, "interface name: l2tp-ses2")
1052
1053 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1054 def test_l2tp_ip(self):
1055 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-ip.netdev')
1056 self.start_networkd(0)
1057
1058 self.wait_online(['test1:routable', 'l2tp-ses3:off', 'l2tp-ses4:off'])
1059
1060 output = subprocess.check_output(['ip', 'l2tp', 'show', 'tunnel', 'tunnel_id', '10'], universal_newlines=True).rstrip()
1061 print(output)
1062 self.assertRegex(output, "Tunnel 10, encap IP")
1063 self.assertRegex(output, "From 192.168.30.100 to 192.168.30.101")
1064 self.assertRegex(output, "Peer tunnel 12")
1065
1066 output = subprocess.check_output(['ip', 'l2tp', 'show', 'session', 'tid', '10', 'session_id', '25'], universal_newlines=True).rstrip()
1067 print(output)
1068 self.assertRegex(output, "Session 25 in tunnel 10")
1069 self.assertRegex(output, "Peer session 26, tunnel 12")
1070 self.assertRegex(output, "interface name: l2tp-ses3")
1071
1072 output = subprocess.check_output(['ip', 'l2tp', 'show', 'session', 'tid', '10', 'session_id', '27'], universal_newlines=True).rstrip()
1073 print(output)
1074 self.assertRegex(output, "Session 27 in tunnel 10")
1075 self.assertRegex(output, "Peer session 28, tunnel 12")
1076 self.assertRegex(output, "interface name: l2tp-ses4")
1077
1078 class NetworkdNetWorkTests(unittest.TestCase, Utilities):
1079 links = [
1080 'bond199',
1081 'dummy98',
1082 'dummy99',
1083 'test1']
1084
1085 units = [
1086 '11-dummy.netdev',
1087 '12-dummy.netdev',
1088 '23-active-slave.network',
1089 '25-address-link-section.network',
1090 '25-address-preferred-lifetime-zero-ipv6.network',
1091 '25-address-static.network',
1092 '25-bind-carrier.network',
1093 '25-bond-active-backup-slave.netdev',
1094 '25-fibrule-invert.network',
1095 '25-fibrule-port-range.network',
1096 '25-ipv6-address-label-section.network',
1097 '25-neighbor-section.network',
1098 '25-link-local-addressing-no.network',
1099 '25-link-local-addressing-yes.network',
1100 '25-link-section-unmanaged.network',
1101 '25-route-ipv6-src.network',
1102 '25-route-static.network',
1103 '25-sysctl-disable-ipv6.network',
1104 '25-sysctl.network',
1105 'configure-without-carrier.network',
1106 'routing-policy-rule-dummy98.network',
1107 'routing-policy-rule-test1.network']
1108
1109 routing_policy_rule_tables = ['7', '8']
1110 routes = [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1111
1112 def setUp(self):
1113 self.remove_routing_policy_rule_tables(self.routing_policy_rule_tables)
1114 self.remove_routes(self.routes)
1115 self.link_remove(self.links)
1116
1117 def tearDown(self):
1118 self.remove_routing_policy_rule_tables(self.routing_policy_rule_tables)
1119 self.remove_routes(self.routes)
1120 self.link_remove(self.links)
1121 self.remove_unit_from_networkd_path(self.units)
1122
1123 def test_address_static(self):
1124 self.copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1125 self.start_networkd(0)
1126
1127 self.wait_online(['dummy98:routable'])
1128
1129 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98'], universal_newlines=True).rstrip()
1130 print(output)
1131 self.assertRegex(output, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1132 self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1133 self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1134
1135 # invalid sections
1136 self.assertNotRegex(output, '10.10.0.1/16')
1137 self.assertNotRegex(output, '10.10.0.2/16')
1138
1139 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98', 'label', '32'], universal_newlines=True).rstrip()
1140 self.assertRegex(output, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1141
1142 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98', 'label', '33'], universal_newlines=True).rstrip()
1143 self.assertRegex(output, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1144
1145 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98', 'label', '34'], universal_newlines=True).rstrip()
1146 self.assertRegex(output, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1147
1148 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98', 'label', '35'], universal_newlines=True).rstrip()
1149 self.assertRegex(output, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1150
1151 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'dummy98'], universal_newlines=True).rstrip()
1152 print(output)
1153 self.assertRegex(output, 'inet6 2001:db8:0:f101::15/64 scope global')
1154 self.assertRegex(output, 'inet6 2001:db8:0:f101::16/64 scope global')
1155 self.assertRegex(output, 'inet6 2001:db8:0:f102::15/64 scope global')
1156 self.assertRegex(output, 'inet6 2001:db8:0:f102::16/64 scope global')
1157 self.assertRegex(output, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1158 self.assertRegex(output, 'inet6 fd[0-9a-f:]*1/64 scope global')
1159
1160 def test_address_preferred_lifetime_zero_ipv6(self):
1161 self.copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero-ipv6.network', '12-dummy.netdev')
1162 self.start_networkd()
1163
1164 self.check_link_exists('dummy98')
1165
1166 self.check_operstate('dummy98', 'routable', setup_state='configuring')
1167
1168 output = subprocess.check_output(['ip', 'address', 'show', 'dummy98'], universal_newlines=True).rstrip()
1169 print(output)
1170 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1171 self.assertRegex(output, 'inet6 2001:db8:0:f101::1/64 scope global')
1172
1173 def test_configure_without_carrier(self):
1174 self.copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
1175 self.start_networkd()
1176
1177 self.check_link_exists('test1')
1178
1179 output = subprocess.check_output(['networkctl', 'status', 'test1'], universal_newlines=True).rstrip()
1180 print(output)
1181 self.assertRegex(output, '192.168.0.15')
1182 self.assertRegex(output, '192.168.0.1')
1183 self.assertRegex(output, 'routable')
1184
1185 def test_routing_policy_rule(self):
1186 self.copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1187
1188 self.start_networkd()
1189
1190 self.check_link_exists('test1')
1191
1192 output = subprocess.check_output(['ip', 'rule'], universal_newlines=True).rstrip()
1193 print(output)
1194 self.assertRegex(output, '111')
1195 self.assertRegex(output, 'from 192.168.100.18')
1196 self.assertRegex(output, r'tos (?:0x08|throughput)\s')
1197 self.assertRegex(output, 'iif test1')
1198 self.assertRegex(output, 'oif test1')
1199 self.assertRegex(output, 'lookup 7')
1200
1201 def test_routing_policy_rule_issue_11280(self):
1202 self.copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1203 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1204
1205 for trial in range(3):
1206 # Remove state files only first time
1207 self.start_networkd(remove_state_files=(trial == 0))
1208
1209 self.check_link_exists('test1')
1210 self.check_link_exists('dummy98')
1211
1212 output = subprocess.check_output(['ip', 'rule', 'list', 'table', '7'], universal_newlines=True).rstrip()
1213 print(output)
1214 self.assertRegex(output, '111: from 192.168.100.18 tos (?:0x08|throughput) iif test1 oif test1 lookup 7')
1215
1216 output = subprocess.check_output(['ip', 'rule', 'list', 'table', '8'], universal_newlines=True).rstrip()
1217 print(output)
1218 self.assertRegex(output, '112: from 192.168.101.18 tos (?:0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1219
1220 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1221 def test_routing_policy_rule_port_range(self):
1222 self.copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1223
1224 self.start_networkd()
1225
1226 self.check_link_exists('test1')
1227
1228 output = subprocess.check_output(['ip', 'rule'], universal_newlines=True).rstrip()
1229 print(output)
1230 self.assertRegex(output, '111')
1231 self.assertRegex(output, 'from 192.168.100.18')
1232 self.assertRegex(output, '1123-1150')
1233 self.assertRegex(output, '3224-3290')
1234 self.assertRegex(output, 'tcp')
1235 self.assertRegex(output, 'lookup 7')
1236
1237 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1238 def test_routing_policy_rule_invert(self):
1239 self.copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1240
1241 self.start_networkd()
1242
1243 self.check_link_exists('test1')
1244
1245 output = subprocess.check_output(['ip', 'rule'], universal_newlines=True).rstrip()
1246 print(output)
1247 self.assertRegex(output, '111')
1248 self.assertRegex(output, 'not.*?from.*?192.168.100.18')
1249 self.assertRegex(output, 'tcp')
1250 self.assertRegex(output, 'lookup 7')
1251
1252 def test_route_static(self):
1253 self.copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1254 self.start_networkd(0)
1255
1256 self.wait_online(['dummy98:routable'])
1257
1258 output = subprocess.check_output(['ip', '-6', 'route', 'show', 'dev', 'dummy98'], universal_newlines=True).rstrip()
1259 print(output)
1260 self.assertRegex(output, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1261 self.assertRegex(output, '2001:1234:5:8f63::1 proto kernel')
1262
1263 output = subprocess.check_output(['ip', '-6', 'route', 'show', 'dev', 'dummy98', 'default'], universal_newlines=True).rstrip()
1264 self.assertRegex(output, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1265
1266 output = subprocess.check_output(['ip', '-4', 'route', 'show', 'dev', 'dummy98'], universal_newlines=True).rstrip()
1267 print(output)
1268 self.assertRegex(output, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1269 self.assertRegex(output, '149.10.124.64 proto static scope link')
1270 self.assertRegex(output, '169.254.0.0/16 proto static scope link metric 2048')
1271 self.assertRegex(output, '192.168.1.1 proto static initcwnd 20')
1272 self.assertRegex(output, '192.168.1.2 proto static initrwnd 30')
1273
1274 output = subprocess.check_output(['ip', '-4', 'route', 'show', 'dev', 'dummy98', 'default'], universal_newlines=True).rstrip()
1275 self.assertRegex(output, 'default via 149.10.125.65 proto static onlink')
1276 self.assertRegex(output, 'default via 149.10.124.64 proto static')
1277 self.assertRegex(output, 'default proto static')
1278
1279 output = subprocess.check_output(['ip', 'route', 'show', 'type', 'blackhole'], universal_newlines=True).rstrip()
1280 print(output)
1281 self.assertRegex(output, 'blackhole 202.54.1.2 proto static')
1282
1283 output = subprocess.check_output(['ip', 'route', 'show', 'type', 'unreachable'], universal_newlines=True).rstrip()
1284 print(output)
1285 self.assertRegex(output, 'unreachable 202.54.1.3 proto static')
1286
1287 output = subprocess.check_output(['ip', 'route', 'show', 'type', 'prohibit'], universal_newlines=True).rstrip()
1288 print(output)
1289 self.assertRegex(output, 'prohibit 202.54.1.4 proto static')
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))