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