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