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