2 """IP4 VRF Multi-instance Test Case HLD:
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 \
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
14 - add 15 pg-ip4 interfaces
15 - configure 5 hosts per pg-ip4 interface
17 - add 3 pg-ip4 interfaces per VRF
20 - send IP4 packets between all pg-ip4 interfaces in all VRF groups
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
31 - send IP4 packets between all pg-ip4 interfaces in all VRF groups
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
39 - add 1 of deleted VRFs and 1 new VRF
42 - send IP4 packets between all pg-ip4 interfaces in all VRF groups
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
50 - delete all VRFs (i.e. no VRF except VRF=0 created)
53 - send IP4 packets between all pg-ip4 interfaces in all VRF groups
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
64 from scapy.packet import Raw
65 from scapy.layers.l2 import Ether
66 from scapy.layers.inet import IP, UDP, ARP
68 from framework import VppTestCase, VppTestRunner
73 """ Is packet one of uninteresting IPv4 broadcasts? """
79 class TestIp4VrfMultiInst(VppTestCase):
80 """ IP4 VRF Multi-instance Test Case """
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.
89 super(TestIp4VrfMultiInst, cls).setUpClass()
94 cls.pg_ifs_per_vrf = 3
97 # Create pg interfaces
98 cls.create_pg_interfaces(
99 range(cls.nr_of_vrfs * cls.pg_ifs_per_vrf))
101 # Packet flows mapping pg0 -> pg1, pg2 etc.
103 for i in range(len(cls.pg_interfaces)):
104 multiplicand = i / cls.pg_ifs_per_vrf
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
111 # Packet sizes - jumbo packet (9018 bytes) skipped
112 cls.pg_if_packet_sizes = [64, 512, 1518]
114 # Set up all interfaces
115 for pg_if in cls.pg_interfaces:
117 pg_if.generate_remote_hosts(cls.hosts_per_pg)
119 # Create list of VRFs
120 cls.vrf_list = list()
122 # Create list of deleted VRFs
123 cls.vrf_deleted_list = list()
125 # Create list of pg_interfaces in VRFs
126 cls.pg_in_vrf = list()
128 # Create list of pg_interfaces not in BDs
129 cls.pg_not_in_vrf = [pg_if for pg_if in cls.pg_interfaces]
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):
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
141 super(TestIp4VrfMultiInst, cls).tearDownClass()
146 Clear trace and packet infos before running each test.
148 super(TestIp4VrfMultiInst, self).setUp()
149 self.reset_packet_infos()
153 Show various debug prints after each test.
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"))
160 def create_vrf_and_assign_interfaces(self, count, start=1):
162 Create required number of FIB tables / VRFs, put 3 l2-pg interfaces
163 to every FIB table / VRF.
165 :param int count: Number of FIB tables / VRFs to be created.
166 :param int start: Starting number of the FIB table / VRF ID. \
170 for i in range(count):
172 pg_if = self.pg_if_by_vrf_id[vrf_id][0]
173 dest_addr = pg_if.remote_hosts[0].ip4n
175 self.vapi.ip_add_del_route(
176 dest_addr, dest_addr_len, pg_if.local_ip4n,
177 table_id=vrf_id, create_vrf_if_needed=1, is_multipath=1)
178 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)
181 if vrf_id in self.vrf_deleted_list:
182 self.vrf_deleted_list.remove(vrf_id)
183 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)
193 pg_if.configure_ipv4_neighbors(vrf_id)
194 self.logger.debug(self.vapi.ppcli("show ip fib"))
195 self.logger.debug(self.vapi.ppcli("show ip arp"))
197 def delete_vrf(self, vrf_id):
199 Delete required FIB table / VRF.
201 :param int vrf_id: The FIB table / VRF ID to be deleted.
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)
207 if vrf_id not in self.vrf_deleted_list:
208 self.vrf_deleted_list.append(vrf_id)
209 for j in range(self.pg_ifs_per_vrf):
210 pg_if = self.pg_if_by_vrf_id[vrf_id][j]
211 if pg_if in self.pg_in_vrf:
212 self.pg_in_vrf.remove(pg_if)
213 if pg_if not in self.pg_not_in_vrf:
214 self.pg_not_in_vrf.append(pg_if)
215 self.logger.info("IPv4 VRF ID %d reset" % vrf_id)
216 self.logger.debug(self.vapi.ppcli("show ip fib"))
217 self.logger.debug(self.vapi.ppcli("show ip arp"))
219 def create_stream(self, src_if, packet_sizes):
221 Create input packet stream for defined interface using hosts list.
223 :param object src_if: Interface to create packet stream for.
224 :param list packet_sizes: List of required packet sizes.
225 :return: Stream of packets.
228 src_hosts = src_if.remote_hosts
229 for dst_if in self.flows[src_if]:
230 for dst_host in dst_if.remote_hosts:
231 src_host = random.choice(src_hosts)
232 pkt_info = self.create_packet_info(src_if, dst_if)
233 payload = self.info_to_payload(pkt_info)
234 p = (Ether(dst=src_if.local_mac, src=src_host.mac) /
235 IP(src=src_host.ip4, dst=dst_host.ip4) /
236 UDP(sport=1234, dport=1234) /
238 pkt_info.data = p.copy()
239 size = random.choice(packet_sizes)
240 self.extend_packet(p, size)
242 self.logger.debug("Input stream created for port %s. Length: %u pkt(s)"
243 % (src_if.name, len(pkts)))
246 def verify_capture(self, pg_if, capture):
248 Verify captured input packet stream for defined interface.
250 :param object pg_if: Interface to verify captured packet stream for.
251 :param list capture: Captured packet stream.
254 for i in self.pg_interfaces:
255 last_info[i.sw_if_index] = None
256 dst_sw_if_index = pg_if.sw_if_index
257 for packet in capture:
261 payload_info = self.payload_to_info(str(packet[Raw]))
262 packet_index = payload_info.index
263 self.assertEqual(payload_info.dst, dst_sw_if_index)
264 self.logger.debug("Got packet on port %s: src=%u (id=%u)" %
265 (pg_if.name, payload_info.src, packet_index))
266 next_info = self.get_next_packet_info_for_interface2(
267 payload_info.src, dst_sw_if_index,
268 last_info[payload_info.src])
269 last_info[payload_info.src] = next_info
270 self.assertIsNotNone(next_info)
271 self.assertEqual(packet_index, next_info.index)
272 saved_packet = next_info.data
273 # Check standard fields
274 self.assertEqual(ip.src, saved_packet[IP].src)
275 self.assertEqual(ip.dst, saved_packet[IP].dst)
276 self.assertEqual(udp.sport, saved_packet[UDP].sport)
277 self.assertEqual(udp.dport, saved_packet[UDP].dport)
279 self.logger.error(ppp("Unexpected or invalid packet:", packet))
281 for i in self.pg_interfaces:
282 remaining_packet = self.get_next_packet_info_for_interface2(
283 i, dst_sw_if_index, last_info[i.sw_if_index])
286 "Port %u: Packet expected from source %u didn't arrive" %
287 (dst_sw_if_index, i.sw_if_index))
289 def verify_vrf(self, vrf_id):
291 Check if the FIB table / VRF ID is configured.
293 :param int vrf_id: The FIB table / VRF ID to be verified.
294 :return: 1 if the FIB table / VRF ID is configured, otherwise return 0.
296 ip_fib_dump = self.vapi.ip_fib_dump()
298 for ip_fib_details in ip_fib_dump:
299 if ip_fib_details[2] == vrf_id:
302 self.logger.info("IPv4 VRF ID %d is not configured" % vrf_id)
305 self.logger.info("IPv4 VRF ID %d is configured" % vrf_id)
308 def run_verify_test(self):
310 Create packet streams for all configured l2-pg interfaces, send all \
311 prepared packet streams and verify that:
312 - all packets received correctly on all pg-l2 interfaces assigned
314 - no packet received on all pg-l2 interfaces not assigned to bridge
317 :raise RuntimeError: If no packet captured on l2-pg interface assigned
318 to the bridge domain or if any packet is captured on l2-pg
319 interface not assigned to the bridge domain.
322 # Create incoming packet streams for packet-generator interfaces
323 for pg_if in self.pg_interfaces:
324 pkts = self.create_stream(pg_if, self.pg_if_packet_sizes)
325 pg_if.add_stream(pkts)
327 # Enable packet capture and start packet sending
328 self.pg_enable_capture(self.pg_interfaces)
332 # Verify outgoing packet streams per packet-generator interface
333 for pg_if in self.pg_interfaces:
334 if pg_if in self.pg_in_vrf:
335 capture = pg_if.get_capture(remark="interface is in VRF")
336 self.verify_capture(pg_if, capture)
337 elif pg_if in self.pg_not_in_vrf:
338 pg_if.assert_nothing_captured(remark="interface is not in VRF",
339 filter_out_fn=is_ipv4_misc)
340 self.logger.debug("No capture for interface %s" % pg_if.name)
342 raise Exception("Unknown interface: %s" % pg_if.name)
344 def test_ip4_vrf_01(self):
345 """ IP4 VRF Multi-instance test 1 - create 5 BDs
349 self.create_vrf_and_assign_interfaces(4)
352 for vrf_id in self.vrf_list:
353 self.assertEqual(self.verify_vrf(vrf_id), 1)
356 self.run_verify_test()
358 def test_ip4_vrf_02(self):
359 """ IP4 VRF Multi-instance test 2 - delete 2 VRFs
367 # for vrf_id in self.vrf_deleted_list:
368 # self.assertEqual(self.verify_vrf(vrf_id), 0)
369 for vrf_id in self.vrf_list:
370 self.assertEqual(self.verify_vrf(vrf_id), 1)
373 self.run_verify_test()
375 def test_ip4_vrf_03(self):
376 """ IP4 VRF Multi-instance 3 - add 2 VRFs
379 # Add 1 of deleted VRFs and 1 new VRF
380 self.create_vrf_and_assign_interfaces(1)
381 self.create_vrf_and_assign_interfaces(1, start=5)
384 # for vrf_id in self.vrf_deleted_list:
385 # self.assertEqual(self.verify_vrf(vrf_id), 0)
386 for vrf_id in self.vrf_list:
387 self.assertEqual(self.verify_vrf(vrf_id), 1)
390 self.run_verify_test()
392 def test_ip4_vrf_04(self):
393 """ IP4 VRF Multi-instance test 4 - delete 4 VRFs
396 # Delete all VRFs (i.e. no VRF except VRF=0 created)
397 for i in range(len(self.vrf_list)):
398 self.delete_vrf(self.vrf_list[0])
401 # for vrf_id in self.vrf_deleted_list:
402 # self.assertEqual(self.verify_vrf(vrf_id), 0)
403 for vrf_id in self.vrf_list:
404 self.assertEqual(self.verify_vrf(vrf_id), 1)
407 self.run_verify_test()
410 if __name__ == '__main__':
411 unittest.main(testRunner=VppTestRunner)