blob: 5a8d676058659675937df93eb7a821b704026f72 [file] [log] [blame]
Jane546d3b2016-12-08 13:10:03 +01001#!/usr/bin/env python
2"""IP4 VRF Multi-instance Test Case HLD:
3
4**NOTES:**
5 - higher number of pg-ip4 interfaces causes problems => only 15 pg-ip4 \
6 interfaces in 5 VRFs are tested
7 - jumbo packets in configuration with 15 pg-ip4 interfaces leads to \
8 problems too
9 - Reset of FIB table / VRF does not remove routes from IP FIB (see Jira \
10 ticket https://jira.fd.io/browse/VPP-560) so checks of reset VRF tables \
11 are skipped in tests 2, 3 and 4
12
13**config 1**
14 - add 15 pg-ip4 interfaces
15 - configure 5 hosts per pg-ip4 interface
16 - configure 4 VRFs
17 - add 3 pg-ip4 interfaces per VRF
18
19**test 1**
20 - send IP4 packets between all pg-ip4 interfaces in all VRF groups
21
22**verify 1**
23 - check VRF data by parsing output of ip_fib_dump API command
24 - all packets received correctly in case of pg-ip4 interfaces in VRF
25 - no packet received in case of pg-ip4 interfaces not in VRF
26
27**config 2**
28 - delete 2 VRFs
29
30**test 2**
31 - send IP4 packets between all pg-ip4 interfaces in all VRF groups
32
33**verify 2**
34 - check VRF data by parsing output of ip_fib_dump API command
35 - all packets received correctly in case of pg-ip4 interfaces in VRF
36 - no packet received in case of pg-ip4 interfaces not in VRF
37
38**config 3**
39 - add 1 of deleted VRFs and 1 new VRF
40
41**test 3**
42 - send IP4 packets between all pg-ip4 interfaces in all VRF groups
43
44**verify 3**
45 - check VRF data by parsing output of ip_fib_dump API command
46 - all packets received correctly in case of pg-ip4 interfaces in VRF
47 - no packet received in case of pg-ip4 interfaces not in VRF
48
49**config 4**
50 - delete all VRFs (i.e. no VRF except VRF=0 created)
51
52**test 4**
53 - send IP4 packets between all pg-ip4 interfaces in all VRF groups
54
55**verify 4**
56 - check VRF data by parsing output of ip_fib_dump API command
57 - all packets received correctly in case of pg-ip4 interfaces in VRF
58 - no packet received in case of pg-ip4 interfaces not in VRF
59"""
60
61import unittest
62import random
63
64from scapy.packet import Raw
65from scapy.layers.l2 import Ether
66from scapy.layers.inet import IP, UDP, ARP
67
68from framework import VppTestCase, VppTestRunner
69from util import ppp
70
71
72def is_ipv4_misc(p):
73 """ Is packet one of uninteresting IPv4 broadcasts? """
74 if p.haslayer(ARP):
75 return True
76 return False
77
78
79class TestIp4VrfMultiInst(VppTestCase):
80 """ IP4 VRF Multi-instance Test Case """
81
82 @classmethod
83 def setUpClass(cls):
84 """
85 Perform standard class setup (defined by class method setUpClass in
86 class VppTestCase) before running the test case, set test case related
87 variables and configure VPP.
88 """
89 super(TestIp4VrfMultiInst, cls).setUpClass()
90
91 # Test variables
92 cls.hosts_per_pg = 5
93 cls.nr_of_vrfs = 5
94 cls.pg_ifs_per_vrf = 3
95
96 try:
97 # Create pg interfaces
Klement Sekerada505f62017-01-04 12:58:53 +010098 cls.create_pg_interfaces(
99 range(cls.nr_of_vrfs * cls.pg_ifs_per_vrf))
Jane546d3b2016-12-08 13:10:03 +0100100
101 # Packet flows mapping pg0 -> pg1, pg2 etc.
102 cls.flows = dict()
103 for i in range(len(cls.pg_interfaces)):
104 multiplicand = i / cls.pg_ifs_per_vrf
105 pg_list = [
106 cls.pg_interfaces[multiplicand * cls.pg_ifs_per_vrf + j]
107 for j in range(cls.pg_ifs_per_vrf)
108 if (multiplicand * cls.pg_ifs_per_vrf + j) != i]
109 cls.flows[cls.pg_interfaces[i]] = pg_list
110
111 # Packet sizes - jumbo packet (9018 bytes) skipped
112 cls.pg_if_packet_sizes = [64, 512, 1518]
113
114 # Set up all interfaces
115 for pg_if in cls.pg_interfaces:
116 pg_if.admin_up()
117 pg_if.generate_remote_hosts(cls.hosts_per_pg)
118
119 # Create list of VRFs
120 cls.vrf_list = list()
121
122 # Create list of deleted VRFs
123 cls.vrf_deleted_list = list()
124
125 # Create list of pg_interfaces in VRFs
126 cls.pg_in_vrf = list()
127
128 # Create list of pg_interfaces not in BDs
129 cls.pg_not_in_vrf = [pg_if for pg_if in cls.pg_interfaces]
130
131 # Create mapping of pg_interfaces to VRF IDs
132 cls.pg_if_by_vrf_id = dict()
133 for i in range(cls.nr_of_vrfs):
134 vrf_id = i + 1
135 pg_list = [
136 cls.pg_interfaces[i * cls.pg_ifs_per_vrf + j]
137 for j in range(cls.pg_ifs_per_vrf)]
138 cls.pg_if_by_vrf_id[vrf_id] = pg_list
139
140 except Exception:
141 super(TestIp4VrfMultiInst, cls).tearDownClass()
142 raise
143
144 def setUp(self):
Jan Gelety3900fe52017-01-26 15:46:19 +0100145 """
Jane546d3b2016-12-08 13:10:03 +0100146 Clear trace and packet infos before running each test.
147 """
148 super(TestIp4VrfMultiInst, self).setUp()
149 self.reset_packet_infos()
150
151 def tearDown(self):
152 """
153 Show various debug prints after each test.
154 """
155 super(TestIp4VrfMultiInst, self).tearDown()
156 if not self.vpp_dead:
157 self.logger.info(self.vapi.ppcli("show ip fib"))
158 self.logger.info(self.vapi.ppcli("show ip arp"))
159
160 def create_vrf_and_assign_interfaces(self, count, start=1):
Jan Gelety3900fe52017-01-26 15:46:19 +0100161 """
Jane546d3b2016-12-08 13:10:03 +0100162 Create required number of FIB tables / VRFs, put 3 l2-pg interfaces
163 to every FIB table / VRF.
164
165 :param int count: Number of FIB tables / VRFs to be created.
166 :param int start: Starting number of the FIB table / VRF ID. \
167 (Default value = 1)
168 """
169
170 for i in range(count):
171 vrf_id = i + start
172 pg_if = self.pg_if_by_vrf_id[vrf_id][0]
173 dest_addr = pg_if.remote_hosts[0].ip4n
174 dest_addr_len = 24
Neale Ranns15002542017-09-10 04:39:11 -0700175 self.vapi.ip_table_add_del(vrf_id, is_add=1)
Jane546d3b2016-12-08 13:10:03 +0100176 self.vapi.ip_add_del_route(
177 dest_addr, dest_addr_len, pg_if.local_ip4n,
Neale Ranns15002542017-09-10 04:39:11 -0700178 table_id=vrf_id, is_multipath=1)
Jane546d3b2016-12-08 13:10:03 +0100179 self.logger.info("IPv4 VRF ID %d created" % vrf_id)
180 if vrf_id not in self.vrf_list:
181 self.vrf_list.append(vrf_id)
182 if vrf_id in self.vrf_deleted_list:
183 self.vrf_deleted_list.remove(vrf_id)
184 for j in range(self.pg_ifs_per_vrf):
185 pg_if = self.pg_if_by_vrf_id[vrf_id][j]
186 pg_if.set_table_ip4(vrf_id)
187 self.logger.info("pg-interface %s added to IPv4 VRF ID %d"
188 % (pg_if.name, vrf_id))
189 if pg_if not in self.pg_in_vrf:
190 self.pg_in_vrf.append(pg_if)
191 if pg_if in self.pg_not_in_vrf:
192 self.pg_not_in_vrf.remove(pg_if)
193 pg_if.config_ip4()
Neale Rannsbaf2e902017-02-25 04:20:00 -0800194 pg_if.configure_ipv4_neighbors()
Jane546d3b2016-12-08 13:10:03 +0100195 self.logger.debug(self.vapi.ppcli("show ip fib"))
196 self.logger.debug(self.vapi.ppcli("show ip arp"))
197
198 def delete_vrf(self, vrf_id):
Jan Gelety3900fe52017-01-26 15:46:19 +0100199 """
Jane546d3b2016-12-08 13:10:03 +0100200 Delete required FIB table / VRF.
201
202 :param int vrf_id: The FIB table / VRF ID to be deleted.
203 """
204 # self.vapi.reset_vrf(vrf_id, is_ipv6=0)
205 self.vapi.reset_fib(vrf_id, is_ipv6=0)
206 if vrf_id in self.vrf_list:
207 self.vrf_list.remove(vrf_id)
208 if vrf_id not in self.vrf_deleted_list:
209 self.vrf_deleted_list.append(vrf_id)
210 for j in range(self.pg_ifs_per_vrf):
211 pg_if = self.pg_if_by_vrf_id[vrf_id][j]
Neale Ranns4008ac92017-02-13 23:20:04 -0800212 pg_if.unconfig_ip4()
Jane546d3b2016-12-08 13:10:03 +0100213 if pg_if in self.pg_in_vrf:
214 self.pg_in_vrf.remove(pg_if)
215 if pg_if not in self.pg_not_in_vrf:
216 self.pg_not_in_vrf.append(pg_if)
217 self.logger.info("IPv4 VRF ID %d reset" % vrf_id)
218 self.logger.debug(self.vapi.ppcli("show ip fib"))
219 self.logger.debug(self.vapi.ppcli("show ip arp"))
Neale Ranns15002542017-09-10 04:39:11 -0700220 self.vapi.ip_table_add_del(vrf_id, is_add=0)
Jane546d3b2016-12-08 13:10:03 +0100221
222 def create_stream(self, src_if, packet_sizes):
223 """
224 Create input packet stream for defined interface using hosts list.
225
226 :param object src_if: Interface to create packet stream for.
227 :param list packet_sizes: List of required packet sizes.
228 :return: Stream of packets.
229 """
230 pkts = []
231 src_hosts = src_if.remote_hosts
232 for dst_if in self.flows[src_if]:
233 for dst_host in dst_if.remote_hosts:
234 src_host = random.choice(src_hosts)
235 pkt_info = self.create_packet_info(src_if, dst_if)
236 payload = self.info_to_payload(pkt_info)
237 p = (Ether(dst=src_if.local_mac, src=src_host.mac) /
238 IP(src=src_host.ip4, dst=dst_host.ip4) /
239 UDP(sport=1234, dport=1234) /
240 Raw(payload))
241 pkt_info.data = p.copy()
242 size = random.choice(packet_sizes)
243 self.extend_packet(p, size)
244 pkts.append(p)
245 self.logger.debug("Input stream created for port %s. Length: %u pkt(s)"
246 % (src_if.name, len(pkts)))
247 return pkts
248
249 def verify_capture(self, pg_if, capture):
250 """
251 Verify captured input packet stream for defined interface.
252
253 :param object pg_if: Interface to verify captured packet stream for.
254 :param list capture: Captured packet stream.
255 """
256 last_info = dict()
257 for i in self.pg_interfaces:
258 last_info[i.sw_if_index] = None
259 dst_sw_if_index = pg_if.sw_if_index
260 for packet in capture:
261 try:
262 ip = packet[IP]
263 udp = packet[UDP]
264 payload_info = self.payload_to_info(str(packet[Raw]))
265 packet_index = payload_info.index
266 self.assertEqual(payload_info.dst, dst_sw_if_index)
267 self.logger.debug("Got packet on port %s: src=%u (id=%u)" %
268 (pg_if.name, payload_info.src, packet_index))
269 next_info = self.get_next_packet_info_for_interface2(
270 payload_info.src, dst_sw_if_index,
271 last_info[payload_info.src])
272 last_info[payload_info.src] = next_info
273 self.assertIsNotNone(next_info)
274 self.assertEqual(packet_index, next_info.index)
275 saved_packet = next_info.data
276 # Check standard fields
277 self.assertEqual(ip.src, saved_packet[IP].src)
278 self.assertEqual(ip.dst, saved_packet[IP].dst)
279 self.assertEqual(udp.sport, saved_packet[UDP].sport)
280 self.assertEqual(udp.dport, saved_packet[UDP].dport)
281 except:
282 self.logger.error(ppp("Unexpected or invalid packet:", packet))
283 raise
284 for i in self.pg_interfaces:
285 remaining_packet = self.get_next_packet_info_for_interface2(
286 i, dst_sw_if_index, last_info[i.sw_if_index])
287 self.assertIsNone(
288 remaining_packet,
289 "Port %u: Packet expected from source %u didn't arrive" %
290 (dst_sw_if_index, i.sw_if_index))
291
292 def verify_vrf(self, vrf_id):
293 """
294 Check if the FIB table / VRF ID is configured.
295
296 :param int vrf_id: The FIB table / VRF ID to be verified.
297 :return: 1 if the FIB table / VRF ID is configured, otherwise return 0.
298 """
299 ip_fib_dump = self.vapi.ip_fib_dump()
300 vrf_count = 0
301 for ip_fib_details in ip_fib_dump:
302 if ip_fib_details[2] == vrf_id:
303 vrf_count += 1
304 if vrf_count == 0:
305 self.logger.info("IPv4 VRF ID %d is not configured" % vrf_id)
306 return 0
307 else:
308 self.logger.info("IPv4 VRF ID %d is configured" % vrf_id)
309 return 1
310
311 def run_verify_test(self):
312 """
Jan Gelety3900fe52017-01-26 15:46:19 +0100313 Create packet streams for all configured l2-pg interfaces, send all \
Jane546d3b2016-12-08 13:10:03 +0100314 prepared packet streams and verify that:
Klement Sekerada505f62017-01-04 12:58:53 +0100315 - all packets received correctly on all pg-l2 interfaces assigned
Jan Gelety3900fe52017-01-26 15:46:19 +0100316 to bridge domains
Jane546d3b2016-12-08 13:10:03 +0100317 - no packet received on all pg-l2 interfaces not assigned to bridge
Jan Gelety3900fe52017-01-26 15:46:19 +0100318 domains
Jane546d3b2016-12-08 13:10:03 +0100319
320 :raise RuntimeError: If no packet captured on l2-pg interface assigned
Klement Sekerada505f62017-01-04 12:58:53 +0100321 to the bridge domain or if any packet is captured on l2-pg
322 interface not assigned to the bridge domain.
Jane546d3b2016-12-08 13:10:03 +0100323 """
324 # Test
325 # Create incoming packet streams for packet-generator interfaces
326 for pg_if in self.pg_interfaces:
327 pkts = self.create_stream(pg_if, self.pg_if_packet_sizes)
328 pg_if.add_stream(pkts)
329
330 # Enable packet capture and start packet sending
331 self.pg_enable_capture(self.pg_interfaces)
332 self.pg_start()
333
334 # Verify
335 # Verify outgoing packet streams per packet-generator interface
336 for pg_if in self.pg_interfaces:
337 if pg_if in self.pg_in_vrf:
338 capture = pg_if.get_capture(remark="interface is in VRF")
339 self.verify_capture(pg_if, capture)
340 elif pg_if in self.pg_not_in_vrf:
341 pg_if.assert_nothing_captured(remark="interface is not in VRF",
342 filter_out_fn=is_ipv4_misc)
343 self.logger.debug("No capture for interface %s" % pg_if.name)
344 else:
345 raise Exception("Unknown interface: %s" % pg_if.name)
346
347 def test_ip4_vrf_01(self):
348 """ IP4 VRF Multi-instance test 1 - create 5 BDs
349 """
350 # Config 1
351 # Create 4 VRFs
352 self.create_vrf_and_assign_interfaces(4)
353
354 # Verify 1
355 for vrf_id in self.vrf_list:
356 self.assertEqual(self.verify_vrf(vrf_id), 1)
357
358 # Test 1
359 self.run_verify_test()
360
361 def test_ip4_vrf_02(self):
362 """ IP4 VRF Multi-instance test 2 - delete 2 VRFs
363 """
364 # Config 2
365 # Delete 2 VRFs
366 self.delete_vrf(1)
367 self.delete_vrf(2)
368
369 # Verify 2
370 # for vrf_id in self.vrf_deleted_list:
371 # self.assertEqual(self.verify_vrf(vrf_id), 0)
372 for vrf_id in self.vrf_list:
373 self.assertEqual(self.verify_vrf(vrf_id), 1)
374
375 # Test 2
376 self.run_verify_test()
377
378 def test_ip4_vrf_03(self):
379 """ IP4 VRF Multi-instance 3 - add 2 VRFs
380 """
381 # Config 3
382 # Add 1 of deleted VRFs and 1 new VRF
383 self.create_vrf_and_assign_interfaces(1)
384 self.create_vrf_and_assign_interfaces(1, start=5)
385
386 # Verify 3
387 # for vrf_id in self.vrf_deleted_list:
388 # self.assertEqual(self.verify_vrf(vrf_id), 0)
389 for vrf_id in self.vrf_list:
390 self.assertEqual(self.verify_vrf(vrf_id), 1)
391
392 # Test 3
393 self.run_verify_test()
394
395 def test_ip4_vrf_04(self):
396 """ IP4 VRF Multi-instance test 4 - delete 4 VRFs
397 """
398 # Config 4
399 # Delete all VRFs (i.e. no VRF except VRF=0 created)
400 for i in range(len(self.vrf_list)):
401 self.delete_vrf(self.vrf_list[0])
402
403 # Verify 4
404 # for vrf_id in self.vrf_deleted_list:
405 # self.assertEqual(self.verify_vrf(vrf_id), 0)
406 for vrf_id in self.vrf_list:
407 self.assertEqual(self.verify_vrf(vrf_id), 1)
408
409 # Test 4
410 self.run_verify_test()
411
412
413if __name__ == '__main__':
414 unittest.main(testRunner=VppTestRunner)