blob: 05de0fb229ba0d523c2b73bbe6bc2dbf481bb856 [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
Jane546d3b2016-12-08 13:10:03 +01009
10**config 1**
11 - add 15 pg-ip4 interfaces
12 - configure 5 hosts per pg-ip4 interface
13 - configure 4 VRFs
14 - add 3 pg-ip4 interfaces per VRF
15
16**test 1**
17 - send IP4 packets between all pg-ip4 interfaces in all VRF groups
18
19**verify 1**
20 - check VRF data by parsing output of ip_fib_dump API command
21 - all packets received correctly in case of pg-ip4 interfaces in VRF
22 - no packet received in case of pg-ip4 interfaces not in VRF
23
24**config 2**
Jan Gelety95c87b52017-02-27 10:46:14 +010025 - reset 2 VRFs
Jane546d3b2016-12-08 13:10:03 +010026
27**test 2**
28 - send IP4 packets between all pg-ip4 interfaces in all VRF groups
29
30**verify 2**
31 - check VRF data by parsing output of ip_fib_dump API command
32 - all packets received correctly in case of pg-ip4 interfaces in VRF
33 - no packet received in case of pg-ip4 interfaces not in VRF
34
35**config 3**
Jan Gelety95c87b52017-02-27 10:46:14 +010036 - add 1 of reset VRFs and 1 new VRF
Jane546d3b2016-12-08 13:10:03 +010037
38**test 3**
39 - send IP4 packets between all pg-ip4 interfaces in all VRF groups
40
41**verify 3**
42 - check VRF data by parsing output of ip_fib_dump API command
43 - all packets received correctly in case of pg-ip4 interfaces in VRF
44 - no packet received in case of pg-ip4 interfaces not in VRF
45
46**config 4**
Jan Gelety95c87b52017-02-27 10:46:14 +010047 - reset all created VRFs
Jane546d3b2016-12-08 13:10:03 +010048
49**test 4**
50 - send IP4 packets between all pg-ip4 interfaces in all VRF groups
51
52**verify 4**
53 - check VRF data by parsing output of ip_fib_dump API command
54 - all packets received correctly in case of pg-ip4 interfaces in VRF
55 - no packet received in case of pg-ip4 interfaces not in VRF
56"""
57
58import unittest
59import random
Jan Gelety95c87b52017-02-27 10:46:14 +010060import socket
Jane546d3b2016-12-08 13:10:03 +010061
62from scapy.packet import Raw
63from scapy.layers.l2 import Ether
64from scapy.layers.inet import IP, UDP, ARP
65
66from framework import VppTestCase, VppTestRunner
67from util import ppp
Jan Gelety95c87b52017-02-27 10:46:14 +010068from vrf import VRFState
Jane546d3b2016-12-08 13:10:03 +010069
70
71def is_ipv4_misc(p):
72 """ Is packet one of uninteresting IPv4 broadcasts? """
73 if p.haslayer(ARP):
74 return True
75 return False
76
77
78class TestIp4VrfMultiInst(VppTestCase):
79 """ IP4 VRF Multi-instance Test Case """
80
81 @classmethod
82 def setUpClass(cls):
83 """
84 Perform standard class setup (defined by class method setUpClass in
85 class VppTestCase) before running the test case, set test case related
86 variables and configure VPP.
87 """
88 super(TestIp4VrfMultiInst, cls).setUpClass()
89
90 # Test variables
91 cls.hosts_per_pg = 5
92 cls.nr_of_vrfs = 5
93 cls.pg_ifs_per_vrf = 3
94
95 try:
96 # Create pg interfaces
Klement Sekerada505f62017-01-04 12:58:53 +010097 cls.create_pg_interfaces(
98 range(cls.nr_of_vrfs * cls.pg_ifs_per_vrf))
Jane546d3b2016-12-08 13:10:03 +010099
100 # Packet flows mapping pg0 -> pg1, pg2 etc.
101 cls.flows = dict()
102 for i in range(len(cls.pg_interfaces)):
103 multiplicand = i / cls.pg_ifs_per_vrf
104 pg_list = [
105 cls.pg_interfaces[multiplicand * cls.pg_ifs_per_vrf + j]
106 for j in range(cls.pg_ifs_per_vrf)
107 if (multiplicand * cls.pg_ifs_per_vrf + j) != i]
108 cls.flows[cls.pg_interfaces[i]] = pg_list
109
110 # Packet sizes - jumbo packet (9018 bytes) skipped
111 cls.pg_if_packet_sizes = [64, 512, 1518]
112
113 # Set up all interfaces
114 for pg_if in cls.pg_interfaces:
115 pg_if.admin_up()
116 pg_if.generate_remote_hosts(cls.hosts_per_pg)
117
118 # Create list of VRFs
119 cls.vrf_list = list()
120
Jan Gelety95c87b52017-02-27 10:46:14 +0100121 # Create list of reset VRFs
122 cls.vrf_reset_list = list()
Jane546d3b2016-12-08 13:10:03 +0100123
124 # Create list of pg_interfaces in VRFs
125 cls.pg_in_vrf = list()
126
127 # Create list of pg_interfaces not in BDs
128 cls.pg_not_in_vrf = [pg_if for pg_if in cls.pg_interfaces]
129
130 # Create mapping of pg_interfaces to VRF IDs
131 cls.pg_if_by_vrf_id = dict()
132 for i in range(cls.nr_of_vrfs):
133 vrf_id = i + 1
134 pg_list = [
135 cls.pg_interfaces[i * cls.pg_ifs_per_vrf + j]
136 for j in range(cls.pg_ifs_per_vrf)]
137 cls.pg_if_by_vrf_id[vrf_id] = pg_list
138
139 except Exception:
140 super(TestIp4VrfMultiInst, cls).tearDownClass()
141 raise
142
143 def setUp(self):
Jan Gelety3900fe52017-01-26 15:46:19 +0100144 """
Jane546d3b2016-12-08 13:10:03 +0100145 Clear trace and packet infos before running each test.
146 """
147 super(TestIp4VrfMultiInst, self).setUp()
148 self.reset_packet_infos()
149
150 def tearDown(self):
151 """
152 Show various debug prints after each test.
153 """
154 super(TestIp4VrfMultiInst, self).tearDown()
155 if not self.vpp_dead:
156 self.logger.info(self.vapi.ppcli("show ip fib"))
157 self.logger.info(self.vapi.ppcli("show ip arp"))
158
159 def create_vrf_and_assign_interfaces(self, count, start=1):
Jan Gelety3900fe52017-01-26 15:46:19 +0100160 """
Jane546d3b2016-12-08 13:10:03 +0100161 Create required number of FIB tables / VRFs, put 3 l2-pg interfaces
162 to every FIB table / VRF.
163
164 :param int count: Number of FIB tables / VRFs to be created.
165 :param int start: Starting number of the FIB table / VRF ID. \
166 (Default value = 1)
167 """
168
169 for i in range(count):
170 vrf_id = i + start
171 pg_if = self.pg_if_by_vrf_id[vrf_id][0]
Jan Gelety95c87b52017-02-27 10:46:14 +0100172 dest_addr = pg_if.local_ip4n
Jane546d3b2016-12-08 13:10:03 +0100173 dest_addr_len = 24
Neale Ranns15002542017-09-10 04:39:11 -0700174 self.vapi.ip_table_add_del(vrf_id, is_add=1)
Jane546d3b2016-12-08 13:10:03 +0100175 self.vapi.ip_add_del_route(
176 dest_addr, dest_addr_len, pg_if.local_ip4n,
Neale Ranns15002542017-09-10 04:39:11 -0700177 table_id=vrf_id, is_multipath=1)
Jane546d3b2016-12-08 13:10:03 +0100178 self.logger.info("IPv4 VRF ID %d created" % vrf_id)
179 if vrf_id not in self.vrf_list:
180 self.vrf_list.append(vrf_id)
Jan Gelety95c87b52017-02-27 10:46:14 +0100181 if vrf_id in self.vrf_reset_list:
182 self.vrf_reset_list.remove(vrf_id)
Jane546d3b2016-12-08 13:10:03 +0100183 for j in range(self.pg_ifs_per_vrf):
184 pg_if = self.pg_if_by_vrf_id[vrf_id][j]
185 pg_if.set_table_ip4(vrf_id)
186 self.logger.info("pg-interface %s added to IPv4 VRF ID %d"
187 % (pg_if.name, vrf_id))
188 if pg_if not in self.pg_in_vrf:
189 self.pg_in_vrf.append(pg_if)
190 if pg_if in self.pg_not_in_vrf:
191 self.pg_not_in_vrf.remove(pg_if)
192 pg_if.config_ip4()
Neale Rannsbaf2e902017-02-25 04:20:00 -0800193 pg_if.configure_ipv4_neighbors()
Jane546d3b2016-12-08 13:10:03 +0100194 self.logger.debug(self.vapi.ppcli("show ip fib"))
195 self.logger.debug(self.vapi.ppcli("show ip arp"))
196
Jan Gelety95c87b52017-02-27 10:46:14 +0100197 def reset_vrf_and_remove_from_vrf_list(self, vrf_id):
Jan Gelety3900fe52017-01-26 15:46:19 +0100198 """
Jan Gelety95c87b52017-02-27 10:46:14 +0100199 Reset required FIB table / VRF and remove it from VRF list.
Jane546d3b2016-12-08 13:10:03 +0100200
Jan Gelety95c87b52017-02-27 10:46:14 +0100201 :param int vrf_id: The FIB table / VRF ID to be reset.
Jane546d3b2016-12-08 13:10:03 +0100202 """
203 # self.vapi.reset_vrf(vrf_id, is_ipv6=0)
204 self.vapi.reset_fib(vrf_id, is_ipv6=0)
205 if vrf_id in self.vrf_list:
206 self.vrf_list.remove(vrf_id)
Jan Gelety95c87b52017-02-27 10:46:14 +0100207 if vrf_id not in self.vrf_reset_list:
208 self.vrf_reset_list.append(vrf_id)
Jane546d3b2016-12-08 13:10:03 +0100209 for j in range(self.pg_ifs_per_vrf):
210 pg_if = self.pg_if_by_vrf_id[vrf_id][j]
Neale Ranns4008ac92017-02-13 23:20:04 -0800211 pg_if.unconfig_ip4()
Jane546d3b2016-12-08 13:10:03 +0100212 if pg_if in self.pg_in_vrf:
213 self.pg_in_vrf.remove(pg_if)
214 if pg_if not in self.pg_not_in_vrf:
215 self.pg_not_in_vrf.append(pg_if)
Jan Gelety95c87b52017-02-27 10:46:14 +0100216 self.logger.info("IPv4 VRF ID %d reset finished" % vrf_id)
Jane546d3b2016-12-08 13:10:03 +0100217 self.logger.debug(self.vapi.ppcli("show ip fib"))
218 self.logger.debug(self.vapi.ppcli("show ip arp"))
Neale Ranns15002542017-09-10 04:39:11 -0700219 self.vapi.ip_table_add_del(vrf_id, is_add=0)
Jane546d3b2016-12-08 13:10:03 +0100220
221 def create_stream(self, src_if, packet_sizes):
222 """
223 Create input packet stream for defined interface using hosts list.
224
225 :param object src_if: Interface to create packet stream for.
226 :param list packet_sizes: List of required packet sizes.
227 :return: Stream of packets.
228 """
229 pkts = []
230 src_hosts = src_if.remote_hosts
231 for dst_if in self.flows[src_if]:
232 for dst_host in dst_if.remote_hosts:
233 src_host = random.choice(src_hosts)
234 pkt_info = self.create_packet_info(src_if, dst_if)
235 payload = self.info_to_payload(pkt_info)
236 p = (Ether(dst=src_if.local_mac, src=src_host.mac) /
237 IP(src=src_host.ip4, dst=dst_host.ip4) /
238 UDP(sport=1234, dport=1234) /
239 Raw(payload))
240 pkt_info.data = p.copy()
241 size = random.choice(packet_sizes)
242 self.extend_packet(p, size)
243 pkts.append(p)
244 self.logger.debug("Input stream created for port %s. Length: %u pkt(s)"
245 % (src_if.name, len(pkts)))
246 return pkts
247
248 def verify_capture(self, pg_if, capture):
249 """
250 Verify captured input packet stream for defined interface.
251
252 :param object pg_if: Interface to verify captured packet stream for.
253 :param list capture: Captured packet stream.
254 """
255 last_info = dict()
256 for i in self.pg_interfaces:
257 last_info[i.sw_if_index] = None
258 dst_sw_if_index = pg_if.sw_if_index
259 for packet in capture:
260 try:
261 ip = packet[IP]
262 udp = packet[UDP]
263 payload_info = self.payload_to_info(str(packet[Raw]))
264 packet_index = payload_info.index
265 self.assertEqual(payload_info.dst, dst_sw_if_index)
266 self.logger.debug("Got packet on port %s: src=%u (id=%u)" %
267 (pg_if.name, payload_info.src, packet_index))
268 next_info = self.get_next_packet_info_for_interface2(
269 payload_info.src, dst_sw_if_index,
270 last_info[payload_info.src])
271 last_info[payload_info.src] = next_info
272 self.assertIsNotNone(next_info)
273 self.assertEqual(packet_index, next_info.index)
274 saved_packet = next_info.data
275 # Check standard fields
276 self.assertEqual(ip.src, saved_packet[IP].src)
277 self.assertEqual(ip.dst, saved_packet[IP].dst)
278 self.assertEqual(udp.sport, saved_packet[UDP].sport)
279 self.assertEqual(udp.dport, saved_packet[UDP].dport)
280 except:
281 self.logger.error(ppp("Unexpected or invalid packet:", packet))
282 raise
283 for i in self.pg_interfaces:
284 remaining_packet = self.get_next_packet_info_for_interface2(
285 i, dst_sw_if_index, last_info[i.sw_if_index])
286 self.assertIsNone(
287 remaining_packet,
288 "Port %u: Packet expected from source %u didn't arrive" %
289 (dst_sw_if_index, i.sw_if_index))
290
291 def verify_vrf(self, vrf_id):
292 """
293 Check if the FIB table / VRF ID is configured.
294
295 :param int vrf_id: The FIB table / VRF ID to be verified.
296 :return: 1 if the FIB table / VRF ID is configured, otherwise return 0.
297 """
298 ip_fib_dump = self.vapi.ip_fib_dump()
Jan Gelety95c87b52017-02-27 10:46:14 +0100299 vrf_exist = False
Jane546d3b2016-12-08 13:10:03 +0100300 vrf_count = 0
301 for ip_fib_details in ip_fib_dump:
Jan Gelety95c87b52017-02-27 10:46:14 +0100302 if ip_fib_details.table_id == vrf_id:
303 if not vrf_exist:
304 vrf_exist = True
305 addr = socket.inet_ntoa(ip_fib_details.address)
306 found = False
307 for pg_if in self.pg_if_by_vrf_id[vrf_id]:
308 if found:
309 break
310 for host in pg_if.remote_hosts:
311 if str(addr) == str(host.ip4):
312 vrf_count += 1
313 found = True
314 break
315 if not vrf_exist and vrf_count == 0:
Jane546d3b2016-12-08 13:10:03 +0100316 self.logger.info("IPv4 VRF ID %d is not configured" % vrf_id)
Jan Gelety95c87b52017-02-27 10:46:14 +0100317 return VRFState.not_configured
318 elif vrf_exist and vrf_count == 0:
319 self.logger.info("IPv4 VRF ID %d has been reset" % vrf_id)
320 return VRFState.reset
Jane546d3b2016-12-08 13:10:03 +0100321 else:
322 self.logger.info("IPv4 VRF ID %d is configured" % vrf_id)
Jan Gelety95c87b52017-02-27 10:46:14 +0100323 return VRFState.configured
Jane546d3b2016-12-08 13:10:03 +0100324
325 def run_verify_test(self):
326 """
Jan Gelety3900fe52017-01-26 15:46:19 +0100327 Create packet streams for all configured l2-pg interfaces, send all \
Jane546d3b2016-12-08 13:10:03 +0100328 prepared packet streams and verify that:
Klement Sekerada505f62017-01-04 12:58:53 +0100329 - all packets received correctly on all pg-l2 interfaces assigned
Jan Gelety3900fe52017-01-26 15:46:19 +0100330 to bridge domains
Jane546d3b2016-12-08 13:10:03 +0100331 - no packet received on all pg-l2 interfaces not assigned to bridge
Jan Gelety3900fe52017-01-26 15:46:19 +0100332 domains
Jane546d3b2016-12-08 13:10:03 +0100333
334 :raise RuntimeError: If no packet captured on l2-pg interface assigned
Klement Sekerada505f62017-01-04 12:58:53 +0100335 to the bridge domain or if any packet is captured on l2-pg
336 interface not assigned to the bridge domain.
Jane546d3b2016-12-08 13:10:03 +0100337 """
338 # Test
339 # Create incoming packet streams for packet-generator interfaces
340 for pg_if in self.pg_interfaces:
341 pkts = self.create_stream(pg_if, self.pg_if_packet_sizes)
342 pg_if.add_stream(pkts)
343
344 # Enable packet capture and start packet sending
345 self.pg_enable_capture(self.pg_interfaces)
346 self.pg_start()
347
348 # Verify
349 # Verify outgoing packet streams per packet-generator interface
350 for pg_if in self.pg_interfaces:
351 if pg_if in self.pg_in_vrf:
352 capture = pg_if.get_capture(remark="interface is in VRF")
353 self.verify_capture(pg_if, capture)
354 elif pg_if in self.pg_not_in_vrf:
355 pg_if.assert_nothing_captured(remark="interface is not in VRF",
356 filter_out_fn=is_ipv4_misc)
357 self.logger.debug("No capture for interface %s" % pg_if.name)
358 else:
359 raise Exception("Unknown interface: %s" % pg_if.name)
360
361 def test_ip4_vrf_01(self):
Jan Gelety95c87b52017-02-27 10:46:14 +0100362 """ IP4 VRF Multi-instance test 1 - create 4 VRFs
Jane546d3b2016-12-08 13:10:03 +0100363 """
364 # Config 1
365 # Create 4 VRFs
366 self.create_vrf_and_assign_interfaces(4)
367
368 # Verify 1
369 for vrf_id in self.vrf_list:
Jan Gelety95c87b52017-02-27 10:46:14 +0100370 self.assert_equal(self.verify_vrf(vrf_id),
371 VRFState.configured, VRFState)
Jane546d3b2016-12-08 13:10:03 +0100372
373 # Test 1
374 self.run_verify_test()
375
376 def test_ip4_vrf_02(self):
Jan Gelety95c87b52017-02-27 10:46:14 +0100377 """ IP4 VRF Multi-instance test 2 - reset 2 VRFs
Jane546d3b2016-12-08 13:10:03 +0100378 """
379 # Config 2
Jan Gelety95c87b52017-02-27 10:46:14 +0100380 # Reset 2 VRFs
381 self.reset_vrf_and_remove_from_vrf_list(1)
382 self.reset_vrf_and_remove_from_vrf_list(2)
Jane546d3b2016-12-08 13:10:03 +0100383
384 # Verify 2
Jan Gelety95c87b52017-02-27 10:46:14 +0100385 for vrf_id in self.vrf_reset_list:
386 self.assert_equal(self.verify_vrf(vrf_id),
387 VRFState.reset, VRFState)
Jane546d3b2016-12-08 13:10:03 +0100388 for vrf_id in self.vrf_list:
Jan Gelety95c87b52017-02-27 10:46:14 +0100389 self.assert_equal(self.verify_vrf(vrf_id),
390 VRFState.configured, VRFState)
Jane546d3b2016-12-08 13:10:03 +0100391
392 # Test 2
393 self.run_verify_test()
394
395 def test_ip4_vrf_03(self):
396 """ IP4 VRF Multi-instance 3 - add 2 VRFs
397 """
398 # Config 3
Jan Gelety95c87b52017-02-27 10:46:14 +0100399 # Add 1 of reset VRFs and 1 new VRF
Jane546d3b2016-12-08 13:10:03 +0100400 self.create_vrf_and_assign_interfaces(1)
401 self.create_vrf_and_assign_interfaces(1, start=5)
402
403 # Verify 3
Jan Gelety95c87b52017-02-27 10:46:14 +0100404 for vrf_id in self.vrf_reset_list:
405 self.assert_equal(self.verify_vrf(vrf_id),
406 VRFState.reset, VRFState)
Jane546d3b2016-12-08 13:10:03 +0100407 for vrf_id in self.vrf_list:
Jan Gelety95c87b52017-02-27 10:46:14 +0100408 self.assert_equal(self.verify_vrf(vrf_id),
409 VRFState.configured, VRFState)
Jane546d3b2016-12-08 13:10:03 +0100410
411 # Test 3
412 self.run_verify_test()
413
414 def test_ip4_vrf_04(self):
Jan Gelety95c87b52017-02-27 10:46:14 +0100415 """ IP4 VRF Multi-instance test 4 - reset 4 VRFs
Jane546d3b2016-12-08 13:10:03 +0100416 """
417 # Config 4
Jan Gelety95c87b52017-02-27 10:46:14 +0100418 # Reset all VRFs (i.e. no VRF except VRF=0 configured)
Jane546d3b2016-12-08 13:10:03 +0100419 for i in range(len(self.vrf_list)):
Jan Gelety95c87b52017-02-27 10:46:14 +0100420 self.reset_vrf_and_remove_from_vrf_list(self.vrf_list[0])
Jane546d3b2016-12-08 13:10:03 +0100421
422 # Verify 4
Jan Gelety95c87b52017-02-27 10:46:14 +0100423 for vrf_id in self.vrf_reset_list:
424 self.assert_equal(self.verify_vrf(vrf_id),
425 VRFState.reset, VRFState)
426 vrf_list_length = len(self.vrf_list)
427 self.assertEqual(
428 vrf_list_length, 0,
429 "List of configured VRFs is not empty: %s != 0" % vrf_list_length)
Jane546d3b2016-12-08 13:10:03 +0100430
431 # Test 4
432 self.run_verify_test()
433
434
435if __name__ == '__main__':
436 unittest.main(testRunner=VppTestRunner)