]> git.ipfire.org Git - thirdparty/systemd.git/blob - test/test-network/systemd-networkd-tests.py
test-network: add tests for flags of tun or tap devices
[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')
589 self.start_networkd(0)
590
591 self.wait_online(['veth99:off', 'veth-peer:off'])
592
593 def test_dummy(self):
594 self.copy_unit_to_networkd_unit_path('11-dummy.netdev')
595 self.start_networkd(0)
596
597 self.wait_online(['test1:off'])
598
599 def test_tun(self):
600 self.copy_unit_to_networkd_unit_path('25-tun.netdev')
601 self.start_networkd(0)
602
603 self.wait_online(['tun99:off'])
604
605 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'tun99'], universal_newlines=True).rstrip()
606 print(output)
607 # Old ip command does not support IFF_ flags
608 self.assertRegex(output, 'tun (?:type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
609
610 def test_tap(self):
611 self.copy_unit_to_networkd_unit_path('25-tap.netdev')
612 self.start_networkd(0)
613
614 self.wait_online(['tap99:off'])
615
616 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'tap99'], universal_newlines=True).rstrip()
617 print(output)
618 # Old ip command does not support IFF_ flags
619 self.assertRegex(output, 'tun (?:type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
620
621 @expectedFailureIfModuleIsNotAvailable('vrf')
622 def test_vrf(self):
623 self.copy_unit_to_networkd_unit_path('25-vrf.netdev')
624 self.start_networkd(0)
625
626 self.wait_online(['vrf99:off'])
627
628 @expectedFailureIfModuleIsNotAvailable('vcan')
629 def test_vcan(self):
630 self.copy_unit_to_networkd_unit_path('25-vcan.netdev')
631 self.start_networkd(0)
632
633 self.wait_online(['vcan99:off'])
634
635 @expectedFailureIfModuleIsNotAvailable('wireguard')
636 def test_wireguard(self):
637 self.copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
638 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
639 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt')
640 self.start_networkd(0)
641 self.wait_online(['wg99:carrier', 'wg98:routable'])
642
643 if shutil.which('wg'):
644 subprocess.call('wg')
645
646 output = subprocess.check_output(['wg', 'show', 'wg99', 'listen-port'], universal_newlines=True).rstrip()
647 self.assertRegex(output, '51820')
648 output = subprocess.check_output(['wg', 'show', 'wg99', 'fwmark'], universal_newlines=True).rstrip()
649 self.assertRegex(output, '0x4d2')
650 output = subprocess.check_output(['wg', 'show', 'wg99', 'allowed-ips'], universal_newlines=True).rstrip()
651 self.assertRegex(output, 'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
652 self.assertRegex(output, 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
653 output = subprocess.check_output(['wg', 'show', 'wg99', 'persistent-keepalive'], universal_newlines=True).rstrip()
654 self.assertRegex(output, 'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
655 output = subprocess.check_output(['wg', 'show', 'wg99', 'endpoints'], universal_newlines=True).rstrip()
656 self.assertRegex(output, 'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
657 output = subprocess.check_output(['wg', 'show', 'wg99', 'private-key'], universal_newlines=True).rstrip()
658 self.assertRegex(output, 'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
659 output = subprocess.check_output(['wg', 'show', 'wg99', 'preshared-keys'], universal_newlines=True).rstrip()
660 self.assertRegex(output, 'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
661 self.assertRegex(output, 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
662
663 output = subprocess.check_output(['wg', 'show', 'wg98', 'private-key'], universal_newlines=True).rstrip()
664 self.assertRegex(output, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
665
666 def test_geneve(self):
667 self.copy_unit_to_networkd_unit_path('25-geneve.netdev')
668 self.start_networkd(0)
669
670 self.wait_online(['geneve99:off'])
671
672 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'geneve99'], universal_newlines=True).rstrip()
673 print(output)
674 self.assertRegex(output, '192.168.22.1')
675 self.assertRegex(output, '6082')
676 self.assertRegex(output, 'udpcsum')
677 self.assertRegex(output, 'udp6zerocsumrx')
678
679 def test_ipip_tunnel(self):
680 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
681 '25-ipip-tunnel.netdev', '25-tunnel.network',
682 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
683 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
684 self.start_networkd(0)
685 self.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'dummy98:degraded'])
686
687 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ipiptun99'], universal_newlines=True).rstrip()
688 print(output)
689 self.assertRegex(output, 'ipip (?:ipip |)remote 192.169.224.239 local 192.168.223.238 dev dummy98')
690 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ipiptun98'], universal_newlines=True).rstrip()
691 print(output)
692 self.assertRegex(output, 'ipip (?:ipip |)remote 192.169.224.239 local any dev dummy98')
693 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ipiptun97'], universal_newlines=True).rstrip()
694 print(output)
695 self.assertRegex(output, 'ipip (?:ipip |)remote any local 192.168.223.238 dev dummy98')
696
697 def test_gre_tunnel(self):
698 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
699 '25-gre-tunnel.netdev', '25-tunnel.network',
700 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
701 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
702 self.start_networkd(0)
703 self.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'dummy98:degraded'])
704
705 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretun99'], universal_newlines=True).rstrip()
706 print(output)
707 self.assertRegex(output, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
708 self.assertRegex(output, 'ikey 1.2.3.103')
709 self.assertRegex(output, 'okey 1.2.4.103')
710 self.assertRegex(output, 'iseq')
711 self.assertRegex(output, 'oseq')
712 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretun98'], universal_newlines=True).rstrip()
713 print(output)
714 self.assertRegex(output, 'gre remote 10.65.223.239 local any dev dummy98')
715 self.assertRegex(output, 'ikey 0.0.0.104')
716 self.assertRegex(output, 'okey 0.0.0.104')
717 self.assertNotRegex(output, 'iseq')
718 self.assertNotRegex(output, 'oseq')
719 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretun97'], universal_newlines=True).rstrip()
720 print(output)
721 self.assertRegex(output, 'gre remote any local 10.65.223.238 dev dummy98')
722 self.assertRegex(output, 'ikey 0.0.0.105')
723 self.assertRegex(output, 'okey 0.0.0.105')
724 self.assertNotRegex(output, 'iseq')
725 self.assertNotRegex(output, 'oseq')
726
727 @expectedFailureIf_ip6gre_do_not_support_ipv6ll()
728 def test_ip6gre_tunnel(self):
729 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
730 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
731 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
732 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
733 self.start_networkd()
734
735 self.check_link_exists('dummy98')
736 self.check_link_exists('ip6gretun99')
737 self.check_link_exists('ip6gretun98')
738 self.check_link_exists('ip6gretun97')
739
740 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6gretun99'], universal_newlines=True).rstrip()
741 print(output)
742 self.assertRegex(output, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
743 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6gretun98'], universal_newlines=True).rstrip()
744 print(output)
745 self.assertRegex(output, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
746 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6gretun97'], universal_newlines=True).rstrip()
747 print(output)
748 self.assertRegex(output, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
749
750 # Old kernels may not support IPv6LL address on ip6gre tunnel, and the following test may fails.
751 self.wait_online(['ip6gretun99:routable', 'ip6gretun98:routable', 'ip6gretun97:routable', 'dummy98:degraded'])
752
753 def test_gretap_tunnel(self):
754 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
755 '25-gretap-tunnel.netdev', '25-tunnel.network',
756 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
757 self.start_networkd(0)
758 self.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
759
760 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretap99'], universal_newlines=True).rstrip()
761 print(output)
762 self.assertRegex(output, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
763 self.assertRegex(output, 'ikey 0.0.0.106')
764 self.assertRegex(output, 'okey 0.0.0.106')
765 self.assertRegex(output, 'iseq')
766 self.assertRegex(output, 'oseq')
767 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretap98'], universal_newlines=True).rstrip()
768 print(output)
769 self.assertRegex(output, 'gretap remote 10.65.223.239 local any dev dummy98')
770 self.assertRegex(output, 'ikey 0.0.0.107')
771 self.assertRegex(output, 'okey 0.0.0.107')
772 self.assertRegex(output, 'iseq')
773 self.assertRegex(output, 'oseq')
774
775 def test_ip6gretap_tunnel(self):
776 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
777 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
778 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
779 self.start_networkd(0)
780 self.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
781
782 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6gretap99'], universal_newlines=True).rstrip()
783 print(output)
784 self.assertRegex(output, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
785 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6gretap98'], universal_newlines=True).rstrip()
786 print(output)
787 self.assertRegex(output, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
788
789 def test_vti_tunnel(self):
790 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
791 '25-vti-tunnel.netdev', '25-tunnel.network',
792 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
793 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
794 self.start_networkd(0)
795 self.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'dummy98:degraded'])
796
797 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vtitun99'], universal_newlines=True).rstrip()
798 print(output)
799 self.assertRegex(output, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
800 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vtitun98'], universal_newlines=True).rstrip()
801 print(output)
802 self.assertRegex(output, 'vti remote 10.65.223.239 local any dev dummy98')
803 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vtitun97'], universal_newlines=True).rstrip()
804 print(output)
805 self.assertRegex(output, 'vti remote any local 10.65.223.238 dev dummy98')
806
807 def test_vti6_tunnel(self):
808 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
809 '25-vti6-tunnel.netdev', '25-tunnel.network',
810 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
811 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
812 self.start_networkd(0)
813 self.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
814
815 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vti6tun99'], universal_newlines=True).rstrip()
816 print(output)
817 self.assertRegex(output, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
818 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vti6tun98'], universal_newlines=True).rstrip()
819 print(output)
820 self.assertRegex(output, 'vti6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
821 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vti6tun97'], universal_newlines=True).rstrip()
822 print(output)
823 self.assertRegex(output, 'vti6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
824
825 def test_ip6tnl_tunnel(self):
826 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
827 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
828 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
829 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
830 self.start_networkd(0)
831 self.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
832
833 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6tnl99'], universal_newlines=True).rstrip()
834 print(output)
835 self.assertRegex(output, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
836 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6tnl98'], universal_newlines=True).rstrip()
837 print(output)
838 self.assertRegex(output, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
839 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6tnl97'], universal_newlines=True).rstrip()
840 print(output)
841 self.assertRegex(output, 'ip6tnl ip6ip6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
842
843 def test_sit_tunnel(self):
844 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
845 '25-sit-tunnel.netdev', '25-tunnel.network',
846 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
847 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
848 self.start_networkd(0)
849 self.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'dummy98:degraded'])
850
851 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'sittun99'], universal_newlines=True).rstrip()
852 print(output)
853 self.assertRegex(output, "sit (?:ip6ip |)remote 10.65.223.239 local 10.65.223.238 dev dummy98")
854 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'sittun98'], universal_newlines=True).rstrip()
855 print(output)
856 self.assertRegex(output, "sit (?:ip6ip |)remote 10.65.223.239 local any dev dummy98")
857 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'sittun97'], universal_newlines=True).rstrip()
858 print(output)
859 self.assertRegex(output, "sit (?:ip6ip |)remote any local 10.65.223.238 dev dummy98")
860
861 def test_isatap_tunnel(self):
862 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
863 '25-isatap-tunnel.netdev', '25-tunnel.network')
864 self.start_networkd(0)
865 self.wait_online(['isataptun99:routable', 'dummy98:degraded'])
866
867 self.check_link_exists('dummy98')
868 self.check_link_exists('isataptun99')
869
870 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'isataptun99'], universal_newlines=True).rstrip()
871 print(output)
872 self.assertRegex(output, "isatap ")
873
874 def test_6rd_tunnel(self):
875 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
876 '25-6rd-tunnel.netdev', '25-tunnel.network')
877 self.start_networkd(0)
878 self.wait_online(['sittun99:routable', 'dummy98:degraded'])
879
880 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'sittun99'], universal_newlines=True).rstrip()
881 print(output)
882 self.assertRegex(output, '6rd-prefix 2602::/24')
883
884 @expectedFailureIfERSPANModuleIsNotAvailable()
885 def test_erspan_tunnel(self):
886 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
887 '25-erspan-tunnel.netdev', '25-tunnel.network',
888 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
889 self.start_networkd(0)
890 self.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
891
892 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'erspan99'], universal_newlines=True).rstrip()
893 print(output)
894 self.assertRegex(output, 'erspan remote 172.16.1.100 local 172.16.1.200')
895 self.assertRegex(output, 'ikey 0.0.0.101')
896 self.assertRegex(output, 'okey 0.0.0.101')
897 self.assertRegex(output, 'iseq')
898 self.assertRegex(output, 'oseq')
899 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'erspan98'], universal_newlines=True).rstrip()
900 print(output)
901 self.assertRegex(output, 'erspan remote 172.16.1.100 local any')
902 self.assertRegex(output, '102')
903 self.assertRegex(output, 'ikey 0.0.0.102')
904 self.assertRegex(output, 'okey 0.0.0.102')
905 self.assertRegex(output, 'iseq')
906 self.assertRegex(output, 'oseq')
907
908 def test_tunnel_independent(self):
909 self.copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev')
910 self.start_networkd(0)
911
912 self.wait_online(['ipiptun99:off'])
913
914 @expectedFailureIfModuleIsNotAvailable('fou')
915 def test_fou(self):
916 # The following redundant check is necessary for CentOS CI.
917 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
918 self.assertTrue(is_module_available('fou'))
919
920 self.copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
921 '25-fou-ipip.netdev', '25-fou-sit.netdev',
922 '25-fou-gre.netdev', '25-fou-gretap.netdev')
923 self.start_networkd(0)
924
925 self.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'])
926
927 output = subprocess.check_output(['ip', 'fou', 'show'], universal_newlines=True).rstrip()
928 print(output)
929 self.assertRegex(output, 'port 55555 ipproto 4')
930 self.assertRegex(output, 'port 55556 ipproto 47')
931
932 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ipiptun96'], universal_newlines=True).rstrip()
933 print(output)
934 self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55555')
935 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'sittun96'], universal_newlines=True).rstrip()
936 print(output)
937 self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55555')
938 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretun96'], universal_newlines=True).rstrip()
939 print(output)
940 self.assertRegex(output, 'encap fou encap-sport 1001 encap-dport 55556')
941 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretap96'], universal_newlines=True).rstrip()
942 print(output)
943 self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55556')
944
945 subprocess.call(['ip', 'fou', 'del', 'port', '55555'])
946 subprocess.call(['ip', 'fou', 'del', 'port', '55556'])
947
948 def test_vxlan(self):
949 self.copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
950 '11-dummy.netdev', 'vxlan-test1.network')
951 self.start_networkd(0)
952
953 self.wait_online(['test1:degraded', 'vxlan99:degraded'])
954
955 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vxlan99'], universal_newlines=True).rstrip()
956 print(output)
957 self.assertRegex(output, '999')
958 self.assertRegex(output, '5555')
959 self.assertRegex(output, 'l2miss')
960 self.assertRegex(output, 'l3miss')
961 self.assertRegex(output, 'udpcsum')
962 self.assertRegex(output, 'udp6zerocsumtx')
963 self.assertRegex(output, 'udp6zerocsumrx')
964 self.assertRegex(output, 'remcsumtx')
965 self.assertRegex(output, 'remcsumrx')
966 self.assertRegex(output, 'gbp')
967
968 output = subprocess.check_output(['bridge', 'fdb', 'show', 'dev', 'vxlan99'], universal_newlines=True).rstrip()
969 print(output)
970 self.assertRegex(output, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
971 self.assertRegex(output, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
972 self.assertRegex(output, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
973
974 def test_macsec(self):
975 self.copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
976 'macsec.network', '12-dummy.netdev')
977 self.start_networkd(0)
978
979 self.wait_online(['dummy98:degraded', 'macsec99:routable'])
980
981 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'macsec99'], universal_newlines=True).rstrip()
982 print(output)
983 self.assertRegex(output, 'macsec99@dummy98')
984 self.assertRegex(output, 'macsec sci [0-9a-f]*000b')
985 self.assertRegex(output, 'encrypt on')
986
987 output = subprocess.check_output(['ip', 'macsec', 'show', 'macsec99'], universal_newlines=True).rstrip()
988 print(output)
989 self.assertRegex(output, 'encrypt on')
990 self.assertRegex(output, 'TXSC: [0-9a-f]*000b on SA 1')
991 self.assertRegex(output, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
992 self.assertRegex(output, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
993 self.assertRegex(output, 'RXSC: c619528fe6a00100, state on')
994 self.assertRegex(output, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
995 self.assertRegex(output, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
996 self.assertRegex(output, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
997 self.assertRegex(output, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
998 self.assertNotRegex(output, 'key 02030405067080900000000000000000')
999 self.assertRegex(output, 'RXSC: 8c16456c83a90002, state on')
1000 self.assertRegex(output, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1001
1002
1003 class NetworkdL2TPTests(unittest.TestCase, Utilities):
1004
1005 links =[
1006 'l2tp-ses1',
1007 'l2tp-ses2',
1008 'l2tp-ses3',
1009 'l2tp-ses4',
1010 'test1']
1011
1012 units = [
1013 '11-dummy.netdev',
1014 '25-l2tp-dummy.network',
1015 '25-l2tp-ip.netdev',
1016 '25-l2tp-udp.netdev']
1017
1018 l2tp_tunnel_ids = [ '10' ]
1019
1020 def setUp(self):
1021 self.l2tp_tunnel_remove(self.l2tp_tunnel_ids)
1022 self.link_remove(self.links)
1023
1024 def tearDown(self):
1025 self.l2tp_tunnel_remove(self.l2tp_tunnel_ids)
1026 self.link_remove(self.links)
1027 self.remove_unit_from_networkd_path(self.units)
1028
1029 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1030 def test_l2tp_udp(self):
1031 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-udp.netdev')
1032 self.start_networkd(0)
1033
1034 self.wait_online(['test1:routable', 'l2tp-ses1:off', 'l2tp-ses2:off'])
1035
1036 output = subprocess.check_output(['ip', 'l2tp', 'show', 'tunnel', 'tunnel_id', '10'], universal_newlines=True).rstrip()
1037 print(output)
1038 self.assertRegex(output, "Tunnel 10, encap UDP")
1039 self.assertRegex(output, "From 192.168.30.100 to 192.168.30.101")
1040 self.assertRegex(output, "Peer tunnel 11")
1041 self.assertRegex(output, "UDP source / dest ports: 3000/4000")
1042 self.assertRegex(output, "UDP checksum: enabled")
1043
1044 output = subprocess.check_output(['ip', 'l2tp', 'show', 'session', 'tid', '10', 'session_id', '15'], universal_newlines=True).rstrip()
1045 print(output)
1046 self.assertRegex(output, "Session 15 in tunnel 10")
1047 self.assertRegex(output, "Peer session 16, tunnel 11")
1048 self.assertRegex(output, "interface name: l2tp-ses1")
1049
1050 output = subprocess.check_output(['ip', 'l2tp', 'show', 'session', 'tid', '10', 'session_id', '17'], universal_newlines=True).rstrip()
1051 print(output)
1052 self.assertRegex(output, "Session 17 in tunnel 10")
1053 self.assertRegex(output, "Peer session 18, tunnel 11")
1054 self.assertRegex(output, "interface name: l2tp-ses2")
1055
1056 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1057 def test_l2tp_ip(self):
1058 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-ip.netdev')
1059 self.start_networkd(0)
1060
1061 self.wait_online(['test1:routable', 'l2tp-ses3:off', 'l2tp-ses4:off'])
1062
1063 output = subprocess.check_output(['ip', 'l2tp', 'show', 'tunnel', 'tunnel_id', '10'], universal_newlines=True).rstrip()
1064 print(output)
1065 self.assertRegex(output, "Tunnel 10, encap IP")
1066 self.assertRegex(output, "From 192.168.30.100 to 192.168.30.101")
1067 self.assertRegex(output, "Peer tunnel 12")
1068
1069 output = subprocess.check_output(['ip', 'l2tp', 'show', 'session', 'tid', '10', 'session_id', '25'], universal_newlines=True).rstrip()
1070 print(output)
1071 self.assertRegex(output, "Session 25 in tunnel 10")
1072 self.assertRegex(output, "Peer session 26, tunnel 12")
1073 self.assertRegex(output, "interface name: l2tp-ses3")
1074
1075 output = subprocess.check_output(['ip', 'l2tp', 'show', 'session', 'tid', '10', 'session_id', '27'], universal_newlines=True).rstrip()
1076 print(output)
1077 self.assertRegex(output, "Session 27 in tunnel 10")
1078 self.assertRegex(output, "Peer session 28, tunnel 12")
1079 self.assertRegex(output, "interface name: l2tp-ses4")
1080
1081 class NetworkdNetWorkTests(unittest.TestCase, Utilities):
1082 links = [
1083 'bond199',
1084 'dummy98',
1085 'dummy99',
1086 'test1']
1087
1088 units = [
1089 '11-dummy.netdev',
1090 '12-dummy.netdev',
1091 '23-active-slave.network',
1092 '25-address-link-section.network',
1093 '25-address-preferred-lifetime-zero-ipv6.network',
1094 '25-address-static.network',
1095 '25-bind-carrier.network',
1096 '25-bond-active-backup-slave.netdev',
1097 '25-fibrule-invert.network',
1098 '25-fibrule-port-range.network',
1099 '25-ipv6-address-label-section.network',
1100 '25-neighbor-section.network',
1101 '25-link-local-addressing-no.network',
1102 '25-link-local-addressing-yes.network',
1103 '25-link-section-unmanaged.network',
1104 '25-route-ipv6-src.network',
1105 '25-route-static.network',
1106 '25-sysctl-disable-ipv6.network',
1107 '25-sysctl.network',
1108 'configure-without-carrier.network',
1109 'routing-policy-rule-dummy98.network',
1110 'routing-policy-rule-test1.network']
1111
1112 def setUp(self):
1113 self.link_remove(self.links)
1114
1115 def tearDown(self):
1116 self.link_remove(self.links)
1117 self.remove_unit_from_networkd_path(self.units)
1118
1119 def test_address_static(self):
1120 self.copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1121 self.start_networkd(0)
1122
1123 self.wait_online(['dummy98:routable'])
1124
1125 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98'], universal_newlines=True).rstrip()
1126 print(output)
1127 self.assertRegex(output, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1128 self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1129 self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1130
1131 # invalid sections
1132 self.assertNotRegex(output, '10.10.0.1/16')
1133 self.assertNotRegex(output, '10.10.0.2/16')
1134
1135 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98', 'label', '32'], universal_newlines=True).rstrip()
1136 self.assertRegex(output, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1137
1138 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98', 'label', '33'], universal_newlines=True).rstrip()
1139 self.assertRegex(output, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1140
1141 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98', 'label', '34'], universal_newlines=True).rstrip()
1142 self.assertRegex(output, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1143
1144 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98', 'label', '35'], universal_newlines=True).rstrip()
1145 self.assertRegex(output, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1146
1147 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'dummy98'], universal_newlines=True).rstrip()
1148 print(output)
1149 self.assertRegex(output, 'inet6 2001:db8:0:f101::15/64 scope global')
1150 self.assertRegex(output, 'inet6 2001:db8:0:f101::16/64 scope global')
1151 self.assertRegex(output, 'inet6 2001:db8:0:f102::15/64 scope global')
1152 self.assertRegex(output, 'inet6 2001:db8:0:f102::16/64 scope global')
1153 self.assertRegex(output, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1154 self.assertRegex(output, 'inet6 fd[0-9a-f:]*1/64 scope global')
1155
1156 def test_address_preferred_lifetime_zero_ipv6(self):
1157 self.copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero-ipv6.network', '12-dummy.netdev')
1158 self.start_networkd()
1159
1160 self.check_link_exists('dummy98')
1161
1162 self.check_operstate('dummy98', 'routable', setup_state='configuring')
1163
1164 output = subprocess.check_output(['ip', 'address', 'show', 'dummy98'], universal_newlines=True).rstrip()
1165 print(output)
1166 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1167 self.assertRegex(output, 'inet6 2001:db8:0:f101::1/64 scope global')
1168
1169 def test_configure_without_carrier(self):
1170 self.copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
1171 self.start_networkd()
1172
1173 self.check_link_exists('test1')
1174
1175 output = subprocess.check_output(['networkctl', 'status', 'test1'], universal_newlines=True).rstrip()
1176 print(output)
1177 self.assertRegex(output, '192.168.0.15')
1178 self.assertRegex(output, '192.168.0.1')
1179 self.assertRegex(output, 'routable')
1180
1181 def test_routing_policy_rule(self):
1182 self.copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1183
1184 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
1185
1186 self.start_networkd()
1187
1188 self.check_link_exists('test1')
1189
1190 output = subprocess.check_output(['ip', 'rule'], universal_newlines=True).rstrip()
1191 print(output)
1192 self.assertRegex(output, '111')
1193 self.assertRegex(output, 'from 192.168.100.18')
1194 self.assertRegex(output, r'tos (?:0x08|throughput)\s')
1195 self.assertRegex(output, 'iif test1')
1196 self.assertRegex(output, 'oif test1')
1197 self.assertRegex(output, 'lookup 7')
1198
1199 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
1200
1201 def test_routing_policy_rule_issue_11280(self):
1202 self.copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1203 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1204
1205 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
1206 subprocess.call(['ip', 'rule', 'del', 'table', '8'])
1207
1208 for trial in range(3):
1209 # Remove state files only first time
1210 self.start_networkd(remove_state_files=(trial == 0))
1211
1212 self.check_link_exists('test1')
1213 self.check_link_exists('dummy98')
1214
1215 output = subprocess.check_output(['ip', 'rule', 'list', 'table', '7'], universal_newlines=True).rstrip()
1216 print(output)
1217 self.assertRegex(output, '111: from 192.168.100.18 tos (?:0x08|throughput) iif test1 oif test1 lookup 7')
1218
1219 output = subprocess.check_output(['ip', 'rule', 'list', 'table', '8'], universal_newlines=True).rstrip()
1220 print(output)
1221 self.assertRegex(output, '112: from 192.168.101.18 tos (?:0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1222
1223 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
1224 subprocess.call(['ip', 'rule', 'del', 'table', '8'])
1225
1226 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1227 def test_routing_policy_rule_port_range(self):
1228 self.copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1229
1230 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
1231
1232 self.start_networkd()
1233
1234 self.check_link_exists('test1')
1235
1236 output = subprocess.check_output(['ip', 'rule'], universal_newlines=True).rstrip()
1237 print(output)
1238 self.assertRegex(output, '111')
1239 self.assertRegex(output, 'from 192.168.100.18')
1240 self.assertRegex(output, '1123-1150')
1241 self.assertRegex(output, '3224-3290')
1242 self.assertRegex(output, 'tcp')
1243 self.assertRegex(output, 'lookup 7')
1244
1245 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
1246
1247 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1248 def test_routing_policy_rule_invert(self):
1249 self.copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1250
1251 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
1252
1253 self.start_networkd()
1254
1255 self.check_link_exists('test1')
1256
1257 output = subprocess.check_output(['ip', 'rule'], universal_newlines=True).rstrip()
1258 print(output)
1259 self.assertRegex(output, '111')
1260 self.assertRegex(output, 'not.*?from.*?192.168.100.18')
1261 self.assertRegex(output, 'tcp')
1262 self.assertRegex(output, 'lookup 7')
1263
1264 subprocess.call(['ip', 'rule', 'del', 'table', '7'])
1265
1266 def test_route_static(self):
1267 self.copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1268 self.start_networkd(0)
1269
1270 self.wait_online(['dummy98:routable'])
1271
1272 output = subprocess.check_output(['ip', '-6', 'route', 'show', 'dev', 'dummy98'], universal_newlines=True).rstrip()
1273 print(output)
1274 self.assertRegex(output, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1275 self.assertRegex(output, '2001:1234:5:8f63::1 proto kernel')
1276
1277 output = subprocess.check_output(['ip', '-6', 'route', 'show', 'dev', 'dummy98', 'default'], universal_newlines=True).rstrip()
1278 self.assertRegex(output, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1279
1280 output = subprocess.check_output(['ip', '-4', 'route', 'show', 'dev', 'dummy98'], universal_newlines=True).rstrip()
1281 print(output)
1282 self.assertRegex(output, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1283 self.assertRegex(output, '149.10.124.64 proto static scope link')
1284 self.assertRegex(output, '169.254.0.0/16 proto static scope link metric 2048')
1285 self.assertRegex(output, '192.168.1.1 proto static initcwnd 20')
1286 self.assertRegex(output, '192.168.1.2 proto static initrwnd 30')
1287
1288 output = subprocess.check_output(['ip', '-4', 'route', 'show', 'dev', 'dummy98', 'default'], universal_newlines=True).rstrip()
1289 self.assertRegex(output, 'default via 149.10.125.65 proto static onlink')
1290 self.assertRegex(output, 'default via 149.10.124.64 proto static')
1291 self.assertRegex(output, 'default proto static')
1292
1293 output = subprocess.check_output(['ip', 'route', 'show', 'type', 'blackhole'], universal_newlines=True).rstrip()
1294 print(output)
1295 self.assertRegex(output, 'blackhole 202.54.1.2 proto static')
1296
1297 output = subprocess.check_output(['ip', 'route', 'show', 'type', 'unreachable'], universal_newlines=True).rstrip()
1298 print(output)
1299 self.assertRegex(output, 'unreachable 202.54.1.3 proto static')
1300
1301 output = subprocess.check_output(['ip', 'route', 'show', 'type', 'prohibit'], universal_newlines=True).rstrip()
1302 print(output)
1303 self.assertRegex(output, 'prohibit 202.54.1.4 proto static')
1304
1305 subprocess.call(['ip', 'route', 'del', 'blackhole', '202.54.1.2'])
1306 subprocess.call(['ip', 'route', 'del', 'unreachable', '202.54.1.3'])
1307 subprocess.call(['ip', 'route', 'del', 'prohibit', '202.54.1.4'])
1308
1309 def test_ip_route_ipv6_src_route(self):
1310 # a dummy device does not make the addresses go through tentative state, so we
1311 # reuse a bond from an earlier test, which does make the addresses go through
1312 # tentative state, and do our test on that
1313 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')
1314 self.start_networkd()
1315
1316 self.check_link_exists('dummy98')
1317 self.check_link_exists('bond199')
1318
1319 output = subprocess.check_output(['ip', '-6', 'route', 'list', 'dev', 'bond199'], universal_newlines=True).rstrip()
1320 print(output)
1321 self.assertRegex(output, 'abcd::/16')
1322 self.assertRegex(output, 'src')
1323 self.assertRegex(output, '2001:1234:56:8f63::2')
1324
1325 def test_ip_link_mac_address(self):
1326 self.copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
1327 self.start_networkd()
1328
1329 self.check_link_exists('dummy98')
1330
1331 output = subprocess.check_output(['ip', 'link', 'show', 'dummy98'], universal_newlines=True).rstrip()
1332 print(output)
1333 self.assertRegex(output, '00:01:02:aa:bb:cc')
1334
1335 def test_ip_link_unmanaged(self):
1336 self.copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
1337 self.start_networkd()
1338
1339 self.check_link_exists('dummy98')
1340
1341 output = subprocess.check_output(['networkctl', 'status', 'dummy98'], universal_newlines=True).rstrip()
1342 print(output)
1343 self.assertRegex(output, 'unmanaged')
1344
1345 def test_ipv6_address_label(self):
1346 self.copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
1347 self.start_networkd()
1348
1349 self.check_link_exists('dummy98')
1350
1351 output = subprocess.check_output(['ip', 'addrlabel', 'list'], universal_newlines=True).rstrip()
1352 print(output)
1353 self.assertRegex(output, '2004:da8:1::/64')
1354
1355 def test_ipv6_neighbor(self):
1356 self.copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
1357 self.start_networkd()
1358
1359 self.check_link_exists('dummy98')
1360
1361 output = subprocess.check_output(['ip', 'neigh', 'list'], universal_newlines=True).rstrip()
1362 print(output)
1363 self.assertRegex(output, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
1364 self.assertRegex(output, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
1365
1366 def test_link_local_addressing(self):
1367 self.copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
1368 '25-link-local-addressing-no.network', '12-dummy.netdev')
1369 self.start_networkd(0)
1370 self.wait_online(['test1:degraded', 'dummy98:carrier'])
1371
1372 self.check_link_exists('test1')
1373 self.check_link_exists('dummy98')
1374
1375 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'test1'], universal_newlines=True).rstrip()
1376 print(output)
1377 self.assertRegex(output, 'inet .* scope link')
1378 self.assertRegex(output, 'inet6 .* scope link')
1379
1380 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'dummy98'], universal_newlines=True).rstrip()
1381 print(output)
1382 self.assertNotRegex(output, 'inet6* .* scope link')
1383
1384 self.check_operstate('test1', 'degraded')
1385 self.check_operstate('dummy98', 'carrier')
1386
1387 '''
1388 Documentation/networking/ip-sysctl.txt
1389
1390 addr_gen_mode - INTEGER
1391 Defines how link-local and autoconf addresses are generated.
1392
1393 0: generate address based on EUI64 (default)
1394 1: do no generate a link-local address, use EUI64 for addresses generated
1395 from autoconf
1396 2: generate stable privacy addresses, using the secret from
1397 stable_secret (RFC7217)
1398 3: generate stable privacy addresses, using a random secret if unset
1399 '''
1400
1401 test1_addr_gen_mode = ''
1402 if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'stable_secret')):
1403 with open(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'stable_secret')) as f:
1404 try:
1405 f.readline()
1406 except IOError:
1407 # if stable_secret is unset, then EIO is returned
1408 test1_addr_gen_mode = '0'
1409 else:
1410 test1_addr_gen_mode = '2'
1411 else:
1412 test1_addr_gen_mode = '0'
1413
1414 if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'addr_gen_mode')):
1415 self.assertEqual(self.read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode)
1416
1417 if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'dummy98'), 'addr_gen_mode')):
1418 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
1419
1420 def test_sysctl(self):
1421 self.copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
1422 self.start_networkd(0)
1423 self.wait_online(['dummy98:degraded'])
1424
1425 self.check_link_exists('dummy98')
1426
1427 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
1428 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
1429 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
1430 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
1431 self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
1432 self.assertEqual(self.read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
1433 self.assertEqual(self.read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
1434
1435 def test_sysctl_disable_ipv6(self):
1436 self.copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
1437
1438 print('## Disable ipv6')
1439 self.assertEqual(subprocess.call(['sysctl', 'net.ipv6.conf.all.disable_ipv6=1']), 0)
1440 self.assertEqual(subprocess.call(['sysctl', 'net.ipv6.conf.default.disable_ipv6=1']), 0)
1441
1442 self.start_networkd(0)
1443 self.wait_online(['dummy98:routable'])
1444
1445 self.check_link_exists('dummy98')
1446
1447 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dummy98'], universal_newlines=True).rstrip()
1448 print(output)
1449 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1450 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dummy98'], universal_newlines=True).rstrip()
1451 print(output)
1452 self.assertEqual(output, '')
1453 self.check_operstate('dummy98', 'routable')
1454
1455 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1456
1457 print('## Enable ipv6')
1458 self.assertEqual(subprocess.call(['sysctl', 'net.ipv6.conf.all.disable_ipv6=0']), 0)
1459 self.assertEqual(subprocess.call(['sysctl', 'net.ipv6.conf.default.disable_ipv6=0']), 0)
1460
1461 self.start_networkd(0)
1462 self.wait_online(['dummy98:routable'])
1463
1464 self.check_link_exists('dummy98')
1465
1466 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dummy98'], universal_newlines=True).rstrip()
1467 print(output)
1468 self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1469 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dummy98'], universal_newlines=True).rstrip()
1470 print(output)
1471 self.assertRegex(output, 'inet6 .* scope link')
1472 self.check_operstate('dummy98', 'routable')
1473
1474 def test_bind_carrier(self):
1475 self.copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
1476 self.start_networkd()
1477
1478 self.check_link_exists('test1')
1479
1480 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1481 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1482 time.sleep(2)
1483 output = subprocess.check_output(['ip', 'address', 'show', 'test1'], universal_newlines=True).rstrip()
1484 print(output)
1485 self.assertRegex(output, 'UP,LOWER_UP')
1486 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1487 self.check_operstate('test1', 'routable')
1488
1489 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy99', 'type', 'dummy']), 0)
1490 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy99', 'up']), 0)
1491 time.sleep(2)
1492 output = subprocess.check_output(['ip', 'address', 'show', 'test1'], universal_newlines=True).rstrip()
1493 print(output)
1494 self.assertRegex(output, 'UP,LOWER_UP')
1495 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1496 self.check_operstate('test1', 'routable')
1497
1498 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1499 time.sleep(2)
1500 output = subprocess.check_output(['ip', 'address', 'show', 'test1'], universal_newlines=True).rstrip()
1501 print(output)
1502 self.assertRegex(output, 'UP,LOWER_UP')
1503 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1504 self.check_operstate('test1', 'routable')
1505
1506 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy99']), 0)
1507 time.sleep(2)
1508 output = subprocess.check_output(['ip', 'address', 'show', 'test1'], universal_newlines=True).rstrip()
1509 print(output)
1510 self.assertNotRegex(output, 'UP,LOWER_UP')
1511 self.assertRegex(output, 'DOWN')
1512 self.assertNotRegex(output, '192.168.10')
1513 self.check_operstate('test1', 'off')
1514
1515 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1516 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1517 time.sleep(2)
1518 output = subprocess.check_output(['ip', 'address', 'show', 'test1'], universal_newlines=True).rstrip()
1519 print(output)
1520 self.assertRegex(output, 'UP,LOWER_UP')
1521 self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1522 self.check_operstate('test1', 'routable')
1523
1524 class NetworkdNetWorkBondTests(unittest.TestCase, Utilities):
1525 links = [
1526 'bond199',
1527 'bond99',
1528 'dummy98',
1529 'test1']
1530
1531 units = [
1532 '11-dummy.netdev',
1533 '12-dummy.netdev',
1534 '23-active-slave.network',
1535 '23-bond199.network',
1536 '23-primary-slave.network',
1537 '23-test1-bond199.network',
1538 '25-bond-active-backup-slave.netdev',
1539 '25-bond.netdev',
1540 'bond99.network',
1541 'bond-slave.network']
1542
1543 def setUp(self):
1544 self.link_remove(self.links)
1545
1546 def tearDown(self):
1547 self.link_remove(self.links)
1548 self.remove_unit_from_networkd_path(self.units)
1549
1550 def test_bond_active_slave(self):
1551 self.copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1552 self.start_networkd()
1553
1554 self.check_link_exists('dummy98')
1555 self.check_link_exists('bond199')
1556
1557 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond199'], universal_newlines=True).rstrip()
1558 print(output)
1559 self.assertRegex(output, 'active_slave dummy98')
1560
1561 def test_bond_primary_slave(self):
1562 self.copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-test1-bond199.network', '25-bond-active-backup-slave.netdev', '11-dummy.netdev')
1563 self.start_networkd()
1564
1565 self.check_link_exists('test1')
1566 self.check_link_exists('bond199')
1567
1568 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond199'], universal_newlines=True).rstrip()
1569 print(output)
1570 self.assertRegex(output, 'primary test1')
1571
1572 def test_bond_operstate(self):
1573 self.copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
1574 'bond99.network','bond-slave.network')
1575 self.start_networkd()
1576
1577 self.check_link_exists('bond99')
1578 self.check_link_exists('dummy98')
1579 self.check_link_exists('test1')
1580
1581 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'dummy98'], universal_newlines=True).rstrip()
1582 print(output)
1583 self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
1584
1585 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1'], universal_newlines=True).rstrip()
1586 print(output)
1587 self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
1588
1589 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond99'], universal_newlines=True).rstrip()
1590 print(output)
1591 self.assertRegex(output, 'MASTER,UP,LOWER_UP')
1592
1593 self.check_operstate('dummy98', 'enslaved')
1594 self.check_operstate('test1', 'enslaved')
1595 self.check_operstate('bond99', 'routable')
1596
1597 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'down']), 0)
1598 time.sleep(2)
1599
1600 self.check_operstate('dummy98', 'off')
1601 self.check_operstate('test1', 'enslaved')
1602 self.check_operstate('bond99', 'degraded-carrier')
1603
1604 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1605 time.sleep(2)
1606
1607 self.check_operstate('dummy98', 'enslaved')
1608 self.check_operstate('test1', 'enslaved')
1609 self.check_operstate('bond99', 'routable')
1610
1611 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'down']), 0)
1612 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'test1', 'down']), 0)
1613 time.sleep(2)
1614
1615 self.check_operstate('dummy98', 'off')
1616 self.check_operstate('test1', 'off')
1617
1618 bond_has_no_carrier=False
1619 for trial in range(30):
1620 if trial > 0:
1621 time.sleep(1)
1622 output = subprocess.check_output(['ip', 'address', 'show', 'bond99'], universal_newlines=True).rstrip()
1623 print(output)
1624 if self.get_operstate('bond99') == 'no-carrier':
1625 break
1626 else:
1627 # Huh? Kernel does not recognize that all slave interfaces are down?
1628 # Let's confirm that networkd's operstate is consistent with ip's result.
1629 self.assertNotRegex(output, 'NO-CARRIER')
1630
1631 class NetworkdNetWorkBridgeTests(unittest.TestCase, Utilities):
1632 links = [
1633 'bridge99',
1634 'dummy98',
1635 'test1']
1636
1637 units = [
1638 '11-dummy.netdev',
1639 '12-dummy.netdev',
1640 '26-bridge.netdev',
1641 '26-bridge-slave-interface-1.network',
1642 '26-bridge-slave-interface-2.network',
1643 'bridge99-ignore-carrier-loss.network',
1644 'bridge99.network']
1645
1646 def setUp(self):
1647 self.link_remove(self.links)
1648
1649 def tearDown(self):
1650 self.link_remove(self.links)
1651 self.remove_unit_from_networkd_path(self.units)
1652
1653 def test_bridge_property(self):
1654 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1655 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1656 'bridge99.network')
1657 self.start_networkd()
1658
1659 self.check_link_exists('dummy98')
1660 self.check_link_exists('test1')
1661 self.check_link_exists('bridge99')
1662
1663 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1'], universal_newlines=True).rstrip()
1664 print(output)
1665 self.assertRegex(output, 'master')
1666 self.assertRegex(output, 'bridge')
1667
1668 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'dummy98'], universal_newlines=True).rstrip()
1669 print(output)
1670 self.assertRegex(output, 'master')
1671 self.assertRegex(output, 'bridge')
1672
1673 output = subprocess.check_output(['ip', 'addr', 'show', 'bridge99'], universal_newlines=True).rstrip()
1674 print(output)
1675 self.assertRegex(output, '192.168.0.15/24')
1676
1677 output = subprocess.check_output(['bridge', '-d', 'link', 'show', 'dummy98'], universal_newlines=True).rstrip()
1678 print(output)
1679 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
1680 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
1681 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
1682 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
1683 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
1684 if (os.path.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
1685 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
1686 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
1687
1688 # CONFIG_BRIDGE_IGMP_SNOOPING=y
1689 if (os.path.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
1690 self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
1691
1692 self.check_operstate('test1', 'enslaved')
1693 self.check_operstate('dummy98', 'enslaved')
1694 self.check_operstate('bridge99', 'routable')
1695
1696 self.assertEqual(subprocess.call(['ip', 'address', 'add', '192.168.0.16/24', 'dev', 'bridge99']), 0)
1697 time.sleep(1)
1698
1699 output = subprocess.check_output(['ip', 'addr', 'show', 'bridge99'], universal_newlines=True).rstrip()
1700 print(output)
1701 self.assertRegex(output, '192.168.0.16/24')
1702
1703 self.check_operstate('bridge99', 'routable')
1704
1705 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'test1']), 0)
1706 time.sleep(3)
1707
1708 self.check_operstate('bridge99', 'degraded-carrier')
1709
1710 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1711 time.sleep(3)
1712
1713 self.check_operstate('bridge99', 'no-carrier')
1714
1715 output = subprocess.check_output(['ip', 'address', 'show', 'bridge99'], universal_newlines=True).rstrip()
1716 print(output)
1717 self.assertRegex(output, 'NO-CARRIER')
1718 self.assertNotRegex(output, '192.168.0.15/24')
1719 self.assertNotRegex(output, '192.168.0.16/24')
1720
1721 def test_bridge_ignore_carrier_loss(self):
1722 self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1723 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1724 'bridge99-ignore-carrier-loss.network')
1725
1726 subprocess.call(['ip', 'rule', 'del', 'table', '100'])
1727
1728 self.start_networkd()
1729
1730 self.check_link_exists('dummy98')
1731 self.check_link_exists('test1')
1732 self.check_link_exists('bridge99')
1733
1734 self.assertEqual(subprocess.call(['ip', 'address', 'add', '192.168.0.16/24', 'dev', 'bridge99']), 0)
1735 time.sleep(1)
1736
1737 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'test1']), 0)
1738 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1739 time.sleep(3)
1740
1741 output = subprocess.check_output(['ip', 'address', 'show', 'bridge99'], universal_newlines=True).rstrip()
1742 print(output)
1743 self.assertRegex(output, 'NO-CARRIER')
1744 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1745 self.assertRegex(output, 'inet 192.168.0.16/24 scope global secondary bridge99')
1746
1747 subprocess.call(['ip', 'rule', 'del', 'table', '100'])
1748
1749 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self):
1750 self.copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
1751 'bridge99-ignore-carrier-loss.network')
1752
1753 subprocess.call(['ip', 'rule', 'del', 'table', '100'])
1754
1755 self.start_networkd()
1756
1757 self.check_link_exists('bridge99')
1758
1759 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1760 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1761 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1762
1763 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1764 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1765 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1766
1767 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1768 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1769 self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
1770
1771 self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
1772 self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
1773
1774 time.sleep(3)
1775
1776 output = subprocess.check_output(['ip', 'address', 'show', 'bridge99'], universal_newlines=True).rstrip()
1777 print(output)
1778 self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1779
1780 self.check_operstate('bridge99', 'routable')
1781 self.check_operstate('dummy98', 'enslaved')
1782
1783 output = subprocess.check_output(['ip', 'rule', 'list', 'table', '100'], universal_newlines=True).rstrip()
1784 print(output)
1785 self.assertEqual(output, '0: from all to 8.8.8.8 lookup 100')
1786
1787 subprocess.call(['ip', 'rule', 'del', 'table', '100'])
1788
1789 class NetworkdNetWorkLLDPTests(unittest.TestCase, Utilities):
1790 links = ['veth99']
1791
1792 units = [
1793 '23-emit-lldp.network',
1794 '24-lldp.network',
1795 '25-veth.netdev']
1796
1797 def setUp(self):
1798 self.link_remove(self.links)
1799
1800 def tearDown(self):
1801 self.link_remove(self.links)
1802 self.remove_unit_from_networkd_path(self.units)
1803
1804 def test_lldp(self):
1805 self.copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
1806 self.start_networkd()
1807
1808 self.check_link_exists('veth99')
1809
1810 output = subprocess.check_output(['networkctl', 'lldp'], universal_newlines=True).rstrip()
1811 print(output)
1812 self.assertRegex(output, 'veth-peer')
1813 self.assertRegex(output, 'veth99')
1814
1815 class NetworkdNetworkRATests(unittest.TestCase, Utilities):
1816 links = ['veth99']
1817
1818 units = [
1819 '25-veth.netdev',
1820 'ipv6-prefix.network',
1821 'ipv6-prefix-veth.network']
1822
1823 def setUp(self):
1824 self.link_remove(self.links)
1825
1826 def tearDown(self):
1827 self.link_remove(self.links)
1828 self.remove_unit_from_networkd_path(self.units)
1829
1830 def test_ipv6_prefix_delegation(self):
1831 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
1832 self.start_networkd()
1833
1834 self.check_link_exists('veth99')
1835
1836 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1837 print(output)
1838 self.assertRegex(output, '2002:da8:1:0')
1839
1840 class NetworkdNetworkDHCPServerTests(unittest.TestCase, Utilities):
1841 links = [
1842 'dummy98',
1843 'veth99']
1844
1845 units = [
1846 '12-dummy.netdev',
1847 '24-search-domain.network',
1848 '25-veth.netdev',
1849 'dhcp-client.network',
1850 'dhcp-client-timezone-router.network',
1851 'dhcp-server.network',
1852 'dhcp-server-timezone-router.network']
1853
1854 def setUp(self):
1855 self.link_remove(self.links)
1856
1857 def tearDown(self):
1858 self.link_remove(self.links)
1859 self.remove_unit_from_networkd_path(self.units)
1860
1861 def test_dhcp_server(self):
1862 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
1863 self.start_networkd()
1864
1865 self.check_link_exists('veth99')
1866
1867 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1868 print(output)
1869 self.assertRegex(output, '192.168.5.*')
1870 self.assertRegex(output, 'Gateway: 192.168.5.1')
1871 self.assertRegex(output, 'DNS: 192.168.5.1')
1872 self.assertRegex(output, 'NTP: 192.168.5.1')
1873
1874 def test_domain(self):
1875 self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
1876 self.start_networkd()
1877
1878 self.check_link_exists('dummy98')
1879
1880 output = subprocess.check_output(['networkctl', 'status', 'dummy98'], universal_newlines=True).rstrip()
1881 print(output)
1882 self.assertRegex(output, 'Address: 192.168.42.100')
1883 self.assertRegex(output, 'DNS: 192.168.42.1')
1884 self.assertRegex(output, 'Search Domains: one')
1885
1886 def test_emit_router_timezone(self):
1887 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
1888 self.start_networkd()
1889
1890 self.check_link_exists('veth99')
1891
1892 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1893 print(output)
1894 self.assertRegex(output, 'Gateway: 192.168.5.*')
1895 self.assertRegex(output, '192.168.5.*')
1896 self.assertRegex(output, 'Europe/Berlin')
1897
1898 class NetworkdNetworkDHCPClientTests(unittest.TestCase, Utilities):
1899 links = [
1900 'dummy98',
1901 'veth99',
1902 'vrf99']
1903
1904 units = [
1905 '25-veth.netdev',
1906 '25-vrf.netdev',
1907 '25-vrf.network',
1908 'dhcp-client-anonymize.network',
1909 'dhcp-client-critical-connection.network',
1910 'dhcp-client-gateway-onlink-implicit.network',
1911 'dhcp-client-ipv4-dhcp-settings.network',
1912 'dhcp-client-ipv4-only-ipv6-disabled.network',
1913 'dhcp-client-ipv4-only.network',
1914 'dhcp-client-ipv6-only.network',
1915 'dhcp-client-ipv6-rapid-commit.network',
1916 'dhcp-client-listen-port.network',
1917 'dhcp-client-route-metric.network',
1918 'dhcp-client-route-table.network',
1919 'dhcp-client-vrf.network',
1920 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
1921 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
1922 'dhcp-client.network',
1923 'dhcp-server-veth-peer.network',
1924 'dhcp-v4-server-veth-peer.network',
1925 'static.network']
1926
1927 def setUp(self):
1928 self.link_remove(self.links)
1929 self.stop_dnsmasq(dnsmasq_pid_file)
1930
1931 def tearDown(self):
1932 self.link_remove(self.links)
1933 self.remove_unit_from_networkd_path(self.units)
1934 self.stop_dnsmasq(dnsmasq_pid_file)
1935 self.remove_lease_file()
1936 self.remove_log_file()
1937
1938 def test_dhcp_client_ipv6_only(self):
1939 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
1940
1941 self.start_networkd(0)
1942 self.wait_online(['veth-peer:carrier'])
1943 self.start_dnsmasq()
1944 self.wait_online(['veth99:routable', 'veth-peer:routable'])
1945
1946 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1947 print(output)
1948 self.assertRegex(output, '2600::')
1949 self.assertNotRegex(output, '192.168.5')
1950
1951 # Confirm that ipv6 token is not set in the kernel
1952 output = subprocess.check_output(['ip', 'token', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
1953 print(output)
1954 self.assertRegex(output, 'token :: dev veth99')
1955
1956 def test_dhcp_client_ipv4_only(self):
1957 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
1958 self.start_networkd()
1959
1960 self.check_link_exists('veth99')
1961
1962 self.start_dnsmasq()
1963
1964 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1965 print(output)
1966 self.assertNotRegex(output, '2600::')
1967 self.assertRegex(output, '192.168.5')
1968
1969 def test_dhcp_client_ipv4_ipv6(self):
1970 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
1971 'dhcp-client-ipv4-only.network')
1972 self.start_networkd()
1973
1974 self.check_link_exists('veth99')
1975
1976 self.start_dnsmasq()
1977
1978 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
1979 print(output)
1980 self.assertRegex(output, '2600::')
1981 self.assertRegex(output, '192.168.5')
1982
1983 def test_dhcp_client_settings(self):
1984 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
1985 self.start_networkd()
1986
1987 self.check_link_exists('veth99')
1988
1989 self.start_dnsmasq()
1990
1991 print('## ip address show dev veth99')
1992 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
1993 print(output)
1994 self.assertRegex(output, '12:34:56:78:9a:bc')
1995 self.assertRegex(output, '192.168.5')
1996 self.assertRegex(output, '1492')
1997
1998 # issue #8726
1999 print('## ip route show table main dev veth99')
2000 output = subprocess.check_output(['ip', 'route', 'show', 'table', 'main', 'dev', 'veth99'], universal_newlines=True).rstrip()
2001 print(output)
2002 self.assertNotRegex(output, 'proto dhcp')
2003
2004 print('## ip route show table 211 dev veth99')
2005 output = subprocess.check_output(['ip', 'route', 'show', 'table', '211', 'dev', 'veth99'], universal_newlines=True).rstrip()
2006 print(output)
2007 self.assertRegex(output, 'default via 192.168.5.1 proto dhcp')
2008 self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
2009 self.assertRegex(output, '192.168.5.1 proto dhcp scope link')
2010
2011 print('## dnsmasq log')
2012 self.assertTrue(self.search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
2013 self.assertTrue(self.search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
2014 self.assertTrue(self.search_words_in_dnsmasq_log('client provides name: test-hostname'))
2015 self.assertTrue(self.search_words_in_dnsmasq_log('26:mtu'))
2016
2017 def test_dhcp6_client_settings_rapidcommit_true(self):
2018 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2019 self.start_networkd()
2020
2021 self.check_link_exists('veth99')
2022
2023 self.start_dnsmasq()
2024
2025 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2026 print(output)
2027 self.assertRegex(output, '12:34:56:78:9a:bc')
2028 self.assertTrue(self.search_words_in_dnsmasq_log('14:rapid-commit', True))
2029
2030 def test_dhcp6_client_settings_rapidcommit_false(self):
2031 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
2032 self.start_networkd()
2033
2034 self.check_link_exists('veth99')
2035
2036 self.start_dnsmasq()
2037
2038 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2039 print(output)
2040 self.assertRegex(output, '12:34:56:78:9a:bc')
2041 self.assertFalse(self.search_words_in_dnsmasq_log('14:rapid-commit', True))
2042
2043 def test_dhcp_client_settings_anonymize(self):
2044 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
2045 self.start_networkd()
2046
2047 self.check_link_exists('veth99')
2048
2049 self.start_dnsmasq()
2050
2051 self.assertFalse(self.search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
2052 self.assertFalse(self.search_words_in_dnsmasq_log('test-hostname'))
2053 self.assertFalse(self.search_words_in_dnsmasq_log('26:mtu'))
2054
2055 def test_dhcp_client_listen_port(self):
2056 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
2057 self.start_networkd()
2058
2059 self.check_link_exists('veth99')
2060
2061 self.start_dnsmasq('--dhcp-alternate-port=67,5555')
2062
2063 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2064 print(output)
2065 self.assertRegex(output, '192.168.5.* dynamic')
2066
2067 def test_dhcp_route_table_id(self):
2068 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
2069 self.start_networkd()
2070
2071 self.check_link_exists('veth99')
2072
2073 self.start_dnsmasq()
2074
2075 output = subprocess.check_output(['ip', 'route', 'show', 'table', '12'], universal_newlines=True).rstrip()
2076 print(output)
2077 self.assertRegex(output, 'veth99 proto dhcp')
2078 self.assertRegex(output, '192.168.5.1')
2079
2080 def test_dhcp_route_metric(self):
2081 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
2082 self.start_networkd()
2083
2084 self.check_link_exists('veth99')
2085
2086 self.start_dnsmasq()
2087
2088 output = subprocess.check_output(['ip', 'route', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2089 print(output)
2090 self.assertRegex(output, 'metric 24')
2091
2092 def test_dhcp_route_criticalconnection_true(self):
2093 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-critical-connection.network')
2094 self.start_networkd()
2095
2096 self.check_link_exists('veth99')
2097
2098 self.start_dnsmasq()
2099
2100 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
2101 print(output)
2102 self.assertRegex(output, '192.168.5.*')
2103
2104 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
2105 self.stop_dnsmasq(dnsmasq_pid_file)
2106
2107 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2108 time.sleep(125)
2109
2110 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
2111 print(output)
2112 self.assertRegex(output, '192.168.5.*')
2113
2114 def test_dhcp_client_reuse_address_as_static(self):
2115 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
2116 self.start_networkd()
2117
2118 self.check_link_exists('veth99')
2119
2120 self.start_dnsmasq()
2121
2122 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99', 'scope', 'global'], universal_newlines=True).rstrip()
2123 print(output)
2124 self.assertRegex(output, '192.168.5')
2125 self.assertRegex(output, '2600::')
2126
2127 ipv4_address = re.search('192\.168\.5\.[0-9]*/24', output)
2128 ipv6_address = re.search('2600::[0-9a-f:]*/128', output)
2129 static_network = '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address.group(), 'Address=' + ipv6_address.group()])
2130 print(static_network)
2131
2132 self.remove_unit_from_networkd_path(['dhcp-client.network'])
2133
2134 with open(os.path.join(network_unit_file_path, 'static.network'), mode='w') as f:
2135 f.write(static_network)
2136
2137 self.start_networkd()
2138
2139 self.check_link_exists('veth99')
2140
2141 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global'], universal_newlines=True).rstrip()
2142 print(output)
2143 self.assertRegex(output, '192.168.5')
2144 self.assertRegex(output, 'valid_lft forever preferred_lft forever')
2145
2146 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global'], universal_newlines=True).rstrip()
2147 print(output)
2148 self.assertRegex(output, '2600::')
2149 self.assertRegex(output, 'valid_lft forever preferred_lft forever')
2150
2151 @expectedFailureIfModuleIsNotAvailable('vrf')
2152 def test_dhcp_client_vrf(self):
2153 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
2154 '25-vrf.netdev', '25-vrf.network')
2155 self.start_networkd()
2156
2157 self.check_link_exists('veth99')
2158 self.check_link_exists('vrf99')
2159
2160 self.start_dnsmasq()
2161
2162 print('## ip -d link show dev vrf99')
2163 output = subprocess.check_output(['ip', '-d', 'link', 'show', 'dev', 'vrf99'], universal_newlines=True).rstrip()
2164 print(output)
2165 self.assertRegex(output, 'vrf table 42')
2166
2167 print('## ip address show vrf vrf99')
2168 output_ip_vrf = subprocess.check_output(['ip', 'address', 'show', 'vrf', 'vrf99'], universal_newlines=True).rstrip()
2169 print(output_ip_vrf)
2170
2171 print('## ip address show dev veth99')
2172 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2173 print(output)
2174 self.assertEqual(output, output_ip_vrf)
2175 self.assertRegex(output, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2176 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2177 self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic noprefixroute')
2178 self.assertRegex(output, 'inet6 .* scope link')
2179
2180 print('## ip route show vrf vrf99')
2181 output = subprocess.check_output(['ip', 'route', 'show', 'vrf', 'vrf99'], universal_newlines=True).rstrip()
2182 print(output)
2183 self.assertRegex(output, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
2184 self.assertRegex(output, 'default dev veth99 proto static scope link')
2185 self.assertRegex(output, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
2186 self.assertRegex(output, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
2187 self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
2188 self.assertRegex(output, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
2189
2190 print('## ip route show table main dev veth99')
2191 output = subprocess.check_output(['ip', 'route', 'show', 'table', 'main', 'dev', 'veth99'], universal_newlines=True).rstrip()
2192 print(output)
2193 self.assertEqual(output, '')
2194
2195 self.check_operstate('vrf99', 'carrier')
2196 self.check_operstate('veth99', 'routable')
2197
2198 def test_dhcp_client_gateway_onlink_implicit(self):
2199 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2200 'dhcp-client-gateway-onlink-implicit.network')
2201 self.start_networkd()
2202
2203 self.check_link_exists('veth99')
2204
2205 self.start_dnsmasq()
2206
2207 output = subprocess.check_output(['networkctl', 'status', 'veth99'], universal_newlines=True).rstrip()
2208 print(output)
2209 self.assertRegex(output, '192.168.5')
2210
2211 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'veth99', '10.0.0.0/8'], universal_newlines=True).rstrip()
2212 print(output)
2213 self.assertRegex(output, 'onlink')
2214 output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'veth99', '192.168.100.0/24'], universal_newlines=True).rstrip()
2215 print(output)
2216 self.assertRegex(output, 'onlink')
2217
2218 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self):
2219 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2220 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
2221 self.start_networkd(0)
2222 self.wait_online(['veth-peer:carrier'])
2223 self.start_dnsmasq(lease_time='2m')
2224 self.wait_online(['veth99:routable', 'veth-peer:routable'])
2225
2226 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2227 print(output)
2228
2229 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
2230 self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2231 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
2232 self.assertRegex(output, 'inet6 .* scope link')
2233 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
2234 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2235 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
2236 self.assertNotRegex(output, 'inet .* scope link')
2237
2238 print('Wait for the dynamic address to be expired')
2239 time.sleep(130)
2240
2241 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2242 print(output)
2243
2244 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
2245 self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2246 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
2247 self.assertRegex(output, 'inet6 .* scope link')
2248 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
2249 self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2250 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
2251 self.assertNotRegex(output, 'inet .* scope link')
2252
2253 self.search_words_in_dnsmasq_log('DHCPOFFER', show_all=True)
2254
2255 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self):
2256 self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2257 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
2258 self.start_networkd(0)
2259 self.wait_online(['veth99:degraded', 'veth-peer:routable'])
2260
2261 output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99'], universal_newlines=True).rstrip()
2262 print(output)
2263
2264 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
2265 self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2266 output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
2267 self.assertRegex(output, 'inet6 .* scope link')
2268 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'global', 'dynamic'], universal_newlines=True).rstrip()
2269 self.assertNotRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2270 output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'veth99', 'scope', 'link'], universal_newlines=True).rstrip()
2271 self.assertRegex(output, 'inet .* scope link')
2272
2273 if __name__ == '__main__':
2274 unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout,
2275 verbosity=3))