]> git.ipfire.org Git - thirdparty/systemd.git/blob - test/test-network/systemd-networkd-tests.py
test-network: wait for bridge slave to be enslaved in test_bridge_ignore_carrier_loss...
[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 for trial in range(30):
1626 if trial > 0:
1627 time.sleep(1)
1628 output = subprocess.check_output(['ip', 'address', 'show', 'bond99'], universal_newlines=True).rstrip()
1629 print(output)
1630 if self.get_operstate('bond99') == 'no-carrier':
1631 break
1632 else:
1633 # Huh? Kernel does not recognize that all slave interfaces are down?
1634 # Let's confirm that networkd's operstate is consistent with ip's result.
1635 self.assertNotRegex(output, 'NO-CARRIER')
1636
1637 class NetworkdNetWorkBridgeTests(unittest.TestCase, Utilities):
1638 links = [
1639 'bridge99',
1640 'dummy98',
1641 'test1']
1642
1643 units = [
1644 '11-dummy.netdev',
1645 '12-dummy.netdev',
1646 '26-bridge.netdev',
1647 '26-bridge-slave-interface-1.network',
1648 '26-bridge-slave-interface-2.network',
1649 'bridge99-ignore-carrier-loss.network',
1650 'bridge99.network']
1651
1652 def setUp(self):
1653 self.link_remove(self.links)
1654
1655 def tearDown(self):
1656 self.link_remove(self.links)
1657 self.remove_unit_from_networkd_path(self.units)
1658
1659 def test_bridge_property(self):
1660 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1661 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1662 'bridge99.network')
1663 self.start_networkd()
1664
1665 self.check_link_exists('dummy98')
1666 self.check_link_exists('test1')
1667 self.check_link_exists('bridge99')
1668
1669 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1'], universal_newlines=True).rstrip()
1670 print(output)
1671 self.assertRegex(output, 'master')
1672 self.assertRegex(output, 'bridge')
1673
1674 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'dummy98'], universal_newlines=True).rstrip()
1675 print(output)
1676 self.assertRegex(output, 'master')
1677 self.assertRegex(output, 'bridge')
1678
1679 output = subprocess.check_output(['ip', 'addr', 'show', 'bridge99'], universal_newlines=True).rstrip()
1680 print(output)
1681 self.assertRegex(output, '192.168.0.15/24')
1682
1683 output = subprocess.check_output(['bridge', '-d', 'link', 'show', 'dummy98'], universal_newlines=True).rstrip()
1684 print(output)
1685 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
1686 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
1687 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
1688 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
1689 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
1690 if (os.path.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
1691 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
1692 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
1693
1694 # CONFIG_BRIDGE_IGMP_SNOOPING=y
1695 if (os.path.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
1696 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
1697
1698 self.check_operstate('test1', 'enslaved')
1699 self.check_operstate('dummy98', 'enslaved')
1700 self.check_operstate('bridge99', 'routable')
1701
1702 self.assertEqual(subprocess.call(['ip', 'address', 'add', '192.168.0.16/24', 'dev', 'bridge99']), 0)
1703 time.sleep(1)
1704
1705 output = subprocess.check_output(['ip', 'addr', 'show', 'bridge99'], universal_newlines=True).rstrip()
1706 print(output)
1707 self.assertRegex(output, '192.168.0.16/24')
1708
1709 self.check_operstate('bridge99', 'routable')
1710
1711 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'test1']), 0)
1712 time.sleep(3)
1713
1714 self.check_operstate('bridge99', 'degraded-carrier')
1715
1716 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1717 time.sleep(3)
1718
1719 self.check_operstate('bridge99', 'no-carrier')
1720
1721 output = subprocess.check_output(['ip', 'address', 'show', 'bridge99'], universal_newlines=True).rstrip()
1722 print(output)
1723 self.assertRegex(output, 'NO-CARRIER')
1724 self.assertNotRegex(output, '192.168.0.15/24')
1725 self.assertNotRegex(output, '192.168.0.16/24')
1726
1727 def test_bridge_ignore_carrier_loss(self):
1728 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1729 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1730 'bridge99-ignore-carrier-loss.network')
1731
1732 subprocess.call(['ip', 'rule', 'del', 'table', '100'])
1733
1734 self.start_networkd()
1735
1736 self.check_link_exists('dummy98')
1737 self.check_link_exists('test1')
1738 self.check_link_exists('bridge99')
1739
1740 self.assertEqual(subprocess.call(['ip', 'address', 'add', '192.168.0.16/24', 'dev', 'bridge99']), 0)
1741 time.sleep(1)
1742
1743 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'test1']), 0)
1744 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1745 time.sleep(3)
1746
1747 output = subprocess.check_output(['ip', 'address', 'show', 'bridge99'], universal_newlines=True).rstrip()
1748 print(output)
1749 self.assertRegex(output, 'NO-CARRIER')
1750 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1751 self.assertRegex(output, 'inet 192.168.0.16/24 scope global secondary bridge99')
1752
1753 subprocess.call(['ip', 'rule', 'del', 'table', '100'])
1754
1755 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self):
1756 self.copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
1757 'bridge99-ignore-carrier-loss.network')
1758
1759 subprocess.call(['ip', 'rule', 'del', 'table', '100'])
1760
1761 self.start_networkd()
1762
1763 self.check_link_exists('bridge99')
1764
1765 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1766 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1767 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1768
1769 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1770 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1771 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1772
1773 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1774 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1775 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1776
1777 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1778 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1779
1780 for trial in range(30):
1781 if trial > 0:
1782 time.sleep(1)
1783 if self.get_operstate('bridge99') == 'routable' and self.get_operstate('dummy98') == 'enslaved':
1784 break
1785 else:
1786 self.assertTrue(False)
1787
1788 output = subprocess.check_output(['ip', 'address', 'show', 'bridge99'], universal_newlines=True).rstrip()
1789 print(output)
1790 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1791
1792 output = subprocess.check_output(['ip', 'rule', 'list', 'table', '100'], universal_newlines=True).rstrip()
1793 print(output)
1794 self.assertEqual(output, '0: from all to 8.8.8.8 lookup 100')
1795
1796 subprocess.call(['ip', 'rule', 'del', 'table', '100'])
1797
1798 class NetworkdNetWorkLLDPTests(unittest.TestCase, Utilities):
1799 links = ['veth99']
1800
1801 units = [
1802 '23-emit-lldp.network',
1803 '24-lldp.network',
1804 '25-veth.netdev']
1805
1806 def setUp(self):
1807 self.link_remove(self.links)
1808
1809 def tearDown(self):
1810 self.link_remove(self.links)
1811 self.remove_unit_from_networkd_path(self.units)
1812
1813 def test_lldp(self):
1814 self.copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
1815 self.start_networkd()
1816
1817 self.check_link_exists('veth99')
1818
1819 output = subprocess.check_output(['networkctl', 'lldp'], universal_newlines=True).rstrip()
1820 print(output)
1821 self.assertRegex(output, 'veth-peer')
1822 self.assertRegex(output, 'veth99')
1823
1824 class NetworkdNetworkRATests(unittest.TestCase, Utilities):
1825 links = ['veth99']
1826
1827 units = [
1828 '25-veth.netdev',
1829 'ipv6-prefix.network',
1830 'ipv6-prefix-veth.network']
1831
1832 def setUp(self):
1833 self.link_remove(self.links)
1834
1835 def tearDown(self):
1836 self.link_remove(self.links)
1837 self.remove_unit_from_networkd_path(self.units)
1838
1839 def test_ipv6_prefix_delegation(self):
1840 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
1841 self.start_networkd()
1842
1843 self.check_link_exists('veth99')
1844
1845 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1846 print(output)
1847 self.assertRegex(output, '2002:da8:1:0')
1848
1849 class NetworkdNetworkDHCPServerTests(unittest.TestCase, Utilities):
1850 links = [
1851 'dummy98',
1852 'veth99']
1853
1854 units = [
1855 '12-dummy.netdev',
1856 '24-search-domain.network',
1857 '25-veth.netdev',
1858 'dhcp-client.network',
1859 'dhcp-client-timezone-router.network',
1860 'dhcp-server.network',
1861 'dhcp-server-timezone-router.network']
1862
1863 def setUp(self):
1864 self.link_remove(self.links)
1865
1866 def tearDown(self):
1867 self.link_remove(self.links)
1868 self.remove_unit_from_networkd_path(self.units)
1869
1870 def test_dhcp_server(self):
1871 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
1872 self.start_networkd()
1873
1874 self.check_link_exists('veth99')
1875
1876 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1877 print(output)
1878 self.assertRegex(output, '192.168.5.*')
1879 self.assertRegex(output, 'Gateway: 192.168.5.1')
1880 self.assertRegex(output, 'DNS: 192.168.5.1')
1881 self.assertRegex(output, 'NTP: 192.168.5.1')
1882
1883 def test_domain(self):
1884 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
1885 self.start_networkd()
1886
1887 self.check_link_exists('dummy98')
1888
1889 output = subprocess.check_output(['networkctl', 'status', 'dummy98'], universal_newlines=True).rstrip()
1890 print(output)
1891 self.assertRegex(output, 'Address: 192.168.42.100')
1892 self.assertRegex(output, 'DNS: 192.168.42.1')
1893 self.assertRegex(output, 'Search Domains: one')
1894
1895 def test_emit_router_timezone(self):
1896 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
1897 self.start_networkd()
1898
1899 self.check_link_exists('veth99')
1900
1901 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1902 print(output)
1903 self.assertRegex(output, 'Gateway: 192.168.5.*')
1904 self.assertRegex(output, '192.168.5.*')
1905 self.assertRegex(output, 'Europe/Berlin')
1906
1907 class NetworkdNetworkDHCPClientTests(unittest.TestCase, Utilities):
1908 links = [
1909 'dummy98',
1910 'veth99',
1911 'vrf99']
1912
1913 units = [
1914 '25-veth.netdev',
1915 '25-vrf.netdev',
1916 '25-vrf.network',
1917 'dhcp-client-anonymize.network',
1918 'dhcp-client-critical-connection.network',
1919 'dhcp-client-gateway-onlink-implicit.network',
1920 'dhcp-client-ipv4-dhcp-settings.network',
1921 'dhcp-client-ipv4-only-ipv6-disabled.network',
1922 'dhcp-client-ipv4-only.network',
1923 'dhcp-client-ipv6-only.network',
1924 'dhcp-client-ipv6-rapid-commit.network',
1925 'dhcp-client-listen-port.network',
1926 'dhcp-client-route-metric.network',
1927 'dhcp-client-route-table.network',
1928 'dhcp-client-vrf.network',
1929 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
1930 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
1931 'dhcp-client.network',
1932 'dhcp-server-veth-peer.network',
1933 'dhcp-v4-server-veth-peer.network',
1934 'static.network']
1935
1936 def setUp(self):
1937 self.link_remove(self.links)
1938 self.stop_dnsmasq(dnsmasq_pid_file)
1939
1940 def tearDown(self):
1941 self.link_remove(self.links)
1942 self.remove_unit_from_networkd_path(self.units)
1943 self.stop_dnsmasq(dnsmasq_pid_file)
1944 self.remove_lease_file()
1945 self.remove_log_file()
1946
1947 def test_dhcp_client_ipv6_only(self):
1948 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
1949
1950 self.start_networkd(0)
1951 self.wait_online(['veth-peer:carrier'])
1952 self.start_dnsmasq()
1953 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1954
1955 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1956 print(output)
1957 self.assertRegex(output, '2600::')
1958 self.assertNotRegex(output, '192.168.5')
1959
1960 # Confirm that ipv6 token is not set in the kernel
1961 output = subprocess.check_output(['ip', 'token', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
1962 print(output)
1963 self.assertRegex(output, 'token :: dev veth99')
1964
1965 def test_dhcp_client_ipv4_only(self):
1966 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
1967 self.start_networkd()
1968
1969 self.check_link_exists('veth99')
1970
1971 self.start_dnsmasq()
1972
1973 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1974 print(output)
1975 self.assertNotRegex(output, '2600::')
1976 self.assertRegex(output, '192.168.5')
1977
1978 def test_dhcp_client_ipv4_ipv6(self):
1979 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
1980 'dhcp-client-ipv4-only.network')
1981 self.start_networkd()
1982
1983 self.check_link_exists('veth99')
1984
1985 self.start_dnsmasq()
1986
1987 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1988 print(output)
1989 self.assertRegex(output, '2600::')
1990 self.assertRegex(output, '192.168.5')
1991
1992 def test_dhcp_client_settings(self):
1993 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
1994 self.start_networkd()
1995
1996 self.check_link_exists('veth99')
1997
1998 self.start_dnsmasq()
1999
2000 print('## ip address show dev veth99')
2001 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2002 print(output)
2003 self.assertRegex(output, '12:34:56:78:9a:bc')
2004 self.assertRegex(output, '192.168.5')
2005 self.assertRegex(output, '1492')
2006
2007 # issue #8726
2008 print('## ip route show table main dev veth99')
2009 output = subprocess.check_output(['ip', 'route', 'show', 'table', 'main', 'dev', 'veth99'], universal_newlines=True).rstrip()
2010 print(output)
2011 self.assertNotRegex(output, 'proto dhcp')
2012
2013 print('## ip route show table 211 dev veth99')
2014 output = subprocess.check_output(['ip', 'route', 'show', 'table', '211', 'dev', 'veth99'], universal_newlines=True).rstrip()
2015 print(output)
2016 self.assertRegex(output, 'default via 192.168.5.1 proto dhcp')
2017 self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
2018 self.assertRegex(output, '192.168.5.1 proto dhcp scope link')
2019
2020 print('## dnsmasq log')
2021 self.assertTrue(self.search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
2022 self.assertTrue(self.search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
2023 self.assertTrue(self.search_words_in_dnsmasq_log('client provides name: test-hostname'))
2024 self.assertTrue(self.search_words_in_dnsmasq_log('26:mtu'))
2025
2026 def test_dhcp6_client_settings_rapidcommit_true(self):
2027 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2028 self.start_networkd()
2029
2030 self.check_link_exists('veth99')
2031
2032 self.start_dnsmasq()
2033
2034 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2035 print(output)
2036 self.assertRegex(output, '12:34:56:78:9a:bc')
2037 self.assertTrue(self.search_words_in_dnsmasq_log('14:rapid-commit', True))
2038
2039 def test_dhcp6_client_settings_rapidcommit_false(self):
2040 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
2041 self.start_networkd()
2042
2043 self.check_link_exists('veth99')
2044
2045 self.start_dnsmasq()
2046
2047 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2048 print(output)
2049 self.assertRegex(output, '12:34:56:78:9a:bc')
2050 self.assertFalse(self.search_words_in_dnsmasq_log('14:rapid-commit', True))
2051
2052 def test_dhcp_client_settings_anonymize(self):
2053 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
2054 self.start_networkd()
2055
2056 self.check_link_exists('veth99')
2057
2058 self.start_dnsmasq()
2059
2060 self.assertFalse(self.search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
2061 self.assertFalse(self.search_words_in_dnsmasq_log('test-hostname'))
2062 self.assertFalse(self.search_words_in_dnsmasq_log('26:mtu'))
2063
2064 def test_dhcp_client_listen_port(self):
2065 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
2066 self.start_networkd()
2067
2068 self.check_link_exists('veth99')
2069
2070 self.start_dnsmasq('--dhcp-alternate-port=67,5555')
2071
2072 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2073 print(output)
2074 self.assertRegex(output, '192.168.5.* dynamic')
2075
2076 def test_dhcp_route_table_id(self):
2077 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
2078 self.start_networkd()
2079
2080 self.check_link_exists('veth99')
2081
2082 self.start_dnsmasq()
2083
2084 output = subprocess.check_output(['ip', 'route', 'show', 'table', '12'], universal_newlines=True).rstrip()
2085 print(output)
2086 self.assertRegex(output, 'veth99 proto dhcp')
2087 self.assertRegex(output, '192.168.5.1')
2088
2089 def test_dhcp_route_metric(self):
2090 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
2091 self.start_networkd()
2092
2093 self.check_link_exists('veth99')
2094
2095 self.start_dnsmasq()
2096
2097 output = subprocess.check_output(['ip', 'route', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2098 print(output)
2099 self.assertRegex(output, 'metric 24')
2100
2101 def test_dhcp_route_criticalconnection_true(self):
2102 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-critical-connection.network')
2103 self.start_networkd()
2104
2105 self.check_link_exists('veth99')
2106
2107 self.start_dnsmasq()
2108
2109 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
2110 print(output)
2111 self.assertRegex(output, '192.168.5.*')
2112
2113 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
2114 self.stop_dnsmasq(dnsmasq_pid_file)
2115
2116 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2117 time.sleep(125)
2118
2119 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
2120 print(output)
2121 self.assertRegex(output, '192.168.5.*')
2122
2123 def test_dhcp_client_reuse_address_as_static(self):
2124 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
2125 self.start_networkd()
2126
2127 self.check_link_exists('veth99')
2128
2129 self.start_dnsmasq()
2130
2131 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99', 'scope', 'global'], universal_newlines=True).rstrip()
2132 print(output)
2133 self.assertRegex(output, '192.168.5')
2134 self.assertRegex(output, '2600::')
2135
2136 ipv4_address = re.search('192\.168\.5\.[0-9]*/24', output)
2137 ipv6_address = re.search('2600::[0-9a-f:]*/128', output)
2138 static_network = '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address.group(), 'Address=' + ipv6_address.group()])
2139 print(static_network)
2140
2141 self.remove_unit_from_networkd_path(['dhcp-client.network'])
2142
2143 with open(os.path.join(network_unit_file_path, 'static.network'), mode='w') as f:
2144 f.write(static_network)
2145
2146 self.start_networkd()
2147
2148 self.check_link_exists('veth99')
2149
2150 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global'], universal_newlines=True).rstrip()
2151 print(output)
2152 self.assertRegex(output, '192.168.5')
2153 self.assertRegex(output, 'valid_lft forever preferred_lft forever')
2154
2155 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global'], universal_newlines=True).rstrip()
2156 print(output)
2157 self.assertRegex(output, '2600::')
2158 self.assertRegex(output, 'valid_lft forever preferred_lft forever')
2159
2160 @expectedFailureIfModuleIsNotAvailable('vrf')
2161 def test_dhcp_client_vrf(self):
2162 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
2163 '25-vrf.netdev', '25-vrf.network')
2164 self.start_networkd()
2165
2166 self.check_link_exists('veth99')
2167 self.check_link_exists('vrf99')
2168
2169 self.start_dnsmasq()
2170
2171 print('## ip -d link show dev vrf99')
2172 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'dev', 'vrf99'], universal_newlines=True).rstrip()
2173 print(output)
2174 self.assertRegex(output, 'vrf table 42')
2175
2176 print('## ip address show vrf vrf99')
2177 output_ip_vrf = subprocess.check_output(['ip', 'address', 'show', 'vrf', 'vrf99'], universal_newlines=True).rstrip()
2178 print(output_ip_vrf)
2179
2180 print('## ip address show dev veth99')
2181 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2182 print(output)
2183 self.assertEqual(output, output_ip_vrf)
2184 self.assertRegex(output, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2185 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2186 self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic noprefixroute')
2187 self.assertRegex(output, 'inet6 .* scope link')
2188
2189 print('## ip route show vrf vrf99')
2190 output = subprocess.check_output(['ip', 'route', 'show', 'vrf', 'vrf99'], universal_newlines=True).rstrip()
2191 print(output)
2192 self.assertRegex(output, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
2193 self.assertRegex(output, 'default dev veth99 proto static scope link')
2194 self.assertRegex(output, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
2195 self.assertRegex(output, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
2196 self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
2197 self.assertRegex(output, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
2198
2199 print('## ip route show table main dev veth99')
2200 output = subprocess.check_output(['ip', 'route', 'show', 'table', 'main', 'dev', 'veth99'], universal_newlines=True).rstrip()
2201 print(output)
2202 self.assertEqual(output, '')
2203
2204 self.check_operstate('vrf99', 'carrier')
2205 self.check_operstate('veth99', 'routable')
2206
2207 def test_dhcp_client_gateway_onlink_implicit(self):
2208 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2209 'dhcp-client-gateway-onlink-implicit.network')
2210 self.start_networkd()
2211
2212 self.check_link_exists('veth99')
2213
2214 self.start_dnsmasq()
2215
2216 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
2217 print(output)
2218 self.assertRegex(output, '192.168.5')
2219
2220 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'veth99', '10.0.0.0/8'], universal_newlines=True).rstrip()
2221 print(output)
2222 self.assertRegex(output, 'onlink')
2223 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'veth99', '192.168.100.0/24'], universal_newlines=True).rstrip()
2224 print(output)
2225 self.assertRegex(output, 'onlink')
2226
2227 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self):
2228 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2229 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
2230 self.start_networkd(0)
2231 self.wait_online(['veth-peer:carrier'])
2232 self.start_dnsmasq(lease_time='2m')
2233 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2234
2235 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2236 print(output)
2237
2238 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
2239 self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2240 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
2241 self.assertRegex(output, 'inet6 .* scope link')
2242 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
2243 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2244 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
2245 self.assertNotRegex(output, 'inet .* scope link')
2246
2247 print('Wait for the dynamic address to be expired')
2248 time.sleep(130)
2249
2250 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2251 print(output)
2252
2253 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
2254 self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2255 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
2256 self.assertRegex(output, 'inet6 .* scope link')
2257 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
2258 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2259 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
2260 self.assertNotRegex(output, 'inet .* scope link')
2261
2262 self.search_words_in_dnsmasq_log('DHCPOFFER', show_all=True)
2263
2264 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self):
2265 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2266 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
2267 self.start_networkd(0)
2268 self.wait_online(['veth99:degraded', 'veth-peer:routable'])
2269
2270 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2271 print(output)
2272
2273 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
2274 self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2275 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
2276 self.assertRegex(output, 'inet6 .* scope link')
2277 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
2278 self.assertNotRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2279 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
2280 self.assertRegex(output, 'inet .* scope link')
2281
2282 if __name__ == '__main__':
2283 unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout,
2284 verbosity=3))