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 \
11 - add 15 pg-ip4 interfaces
12 - configure 5 hosts per pg-ip4 interface
14 - add 3 pg-ip4 interfaces per VRF
17 - send IP4 packets between all pg-ip4 interfaces in all VRF groups
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 the same
23 - no packet received in case of pg-ip4 interfaces not in VRF
24 - no packet received in case of pg-ip4 interfaces in different VRFs
30 - send IP4 packets between all pg-ip4 interfaces in all VRF groups
33 - all packets received correctly in case of pg-ip4 interfaces in the same
35 - no packet received in case of pg-ip4 interfaces not in VRF
36 - no packet received in case of pg-ip4 interfaces in different VRFs
39 - add 1 of reset 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 the same
48 - no packet received in case of pg-ip4 interfaces not in VRF
49 - no packet received in case of pg-ip4 interfaces in different VRFs
52 - reset all created VRFs
55 - send IP4 packets between all pg-ip4 interfaces in all VRF groups
58 - check VRF data by parsing output of ip_fib_dump API command
59 - all packets received correctly in case of pg-ip4 interfaces in the same
61 - no packet received in case of pg-ip4 interfaces not in VRF
62 - no packet received in case of pg-ip4 interfaces in different VRFs
69 from scapy.packet import Raw
70 from scapy.layers.l2 import Ether
71 from scapy.layers.inet import IP, UDP, ARP
73 from framework import VppTestCase, VppTestRunner
75 from vrf import VRFState
79 """ Is packet one of uninteresting IPv4 broadcasts? """
85 class TestIp4VrfMultiInst(VppTestCase):
86 """ IP4 VRF Multi-instance Test Case """
91 Perform standard class setup (defined by class method setUpClass in
92 class VppTestCase) before running the test case, set test case related
93 variables and configure VPP.
95 super(TestIp4VrfMultiInst, cls).setUpClass()
100 cls.pg_ifs_per_vrf = 3
103 # Create pg interfaces
104 cls.create_pg_interfaces(
105 range(cls.nr_of_vrfs * cls.pg_ifs_per_vrf))
107 # Packet flows mapping pg0 -> pg1, pg2 etc.
109 for i in range(len(cls.pg_interfaces)):
110 multiplicand = i / cls.pg_ifs_per_vrf
112 cls.pg_interfaces[multiplicand * cls.pg_ifs_per_vrf + j]
113 for j in range(cls.pg_ifs_per_vrf)
114 if (multiplicand * cls.pg_ifs_per_vrf + j) != i]
115 cls.flows[cls.pg_interfaces[i]] = pg_list
117 # Packet sizes - jumbo packet (9018 bytes) skipped
118 cls.pg_if_packet_sizes = [64, 512, 1518]
120 # Set up all interfaces
121 for pg_if in cls.pg_interfaces:
123 pg_if.generate_remote_hosts(cls.hosts_per_pg)
125 # Create list of VRFs
126 cls.vrf_list = list()
128 # Create list of reset VRFs
129 cls.vrf_reset_list = list()
131 # Create list of pg_interfaces in VRFs
132 cls.pg_in_vrf = list()
134 # Create list of pg_interfaces not in VRFs
135 cls.pg_not_in_vrf = [pg_if for pg_if in cls.pg_interfaces]
137 # Create mapping of pg_interfaces to VRF IDs
138 cls.pg_if_by_vrf_id = dict()
139 for i in range(cls.nr_of_vrfs):
142 cls.pg_interfaces[i * cls.pg_ifs_per_vrf + j]
143 for j in range(cls.pg_ifs_per_vrf)]
144 cls.pg_if_by_vrf_id[vrf_id] = pg_list
147 super(TestIp4VrfMultiInst, cls).tearDownClass()
152 Clear trace and packet infos before running each test.
154 super(TestIp4VrfMultiInst, self).setUp()
155 self.reset_packet_infos()
159 Show various debug prints after each test.
161 super(TestIp4VrfMultiInst, self).tearDown()
162 if not self.vpp_dead:
163 self.logger.info(self.vapi.ppcli("show ip fib"))
164 self.logger.info(self.vapi.ppcli("show ip arp"))
166 def create_vrf_and_assign_interfaces(self, count, start=1):
168 Create required number of FIB tables / VRFs, put 3 pg-ip4 interfaces
169 to every FIB table / VRF.
171 :param int count: Number of FIB tables / VRFs to be created.
172 :param int start: Starting number of the FIB table / VRF ID. \
176 for i in range(count):
178 pg_if = self.pg_if_by_vrf_id[vrf_id][0]
179 dest_addr = pg_if.local_ip4n
181 self.vapi.ip_table_add_del(vrf_id, is_add=1)
182 self.vapi.ip_add_del_route(
183 dest_addr, dest_addr_len, pg_if.local_ip4n,
184 table_id=vrf_id, is_multipath=1)
185 self.logger.info("IPv4 VRF ID %d created" % vrf_id)
186 if vrf_id not in self.vrf_list:
187 self.vrf_list.append(vrf_id)
188 if vrf_id in self.vrf_reset_list:
189 self.vrf_reset_list.remove(vrf_id)
190 for j in range(self.pg_ifs_per_vrf):
191 pg_if = self.pg_if_by_vrf_id[vrf_id][j]
192 pg_if.set_table_ip4(vrf_id)
193 self.logger.info("pg-interface %s added to IPv4 VRF ID %d"
194 % (pg_if.name, vrf_id))
195 if pg_if not in self.pg_in_vrf:
196 self.pg_in_vrf.append(pg_if)
197 if pg_if in self.pg_not_in_vrf:
198 self.pg_not_in_vrf.remove(pg_if)
200 pg_if.configure_ipv4_neighbors()
201 self.logger.debug(self.vapi.ppcli("show ip fib"))
202 self.logger.debug(self.vapi.ppcli("show ip arp"))
204 def reset_vrf_and_remove_from_vrf_list(self, vrf_id):
206 Reset required FIB table / VRF and remove it from VRF list.
208 :param int vrf_id: The FIB table / VRF ID to be reset.
210 # self.vapi.reset_vrf(vrf_id, is_ipv6=0)
211 self.vapi.reset_fib(vrf_id, is_ipv6=0)
212 if vrf_id in self.vrf_list:
213 self.vrf_list.remove(vrf_id)
214 if vrf_id not in self.vrf_reset_list:
215 self.vrf_reset_list.append(vrf_id)
216 for j in range(self.pg_ifs_per_vrf):
217 pg_if = self.pg_if_by_vrf_id[vrf_id][j]
219 if pg_if in self.pg_in_vrf:
220 self.pg_in_vrf.remove(pg_if)
221 if pg_if not in self.pg_not_in_vrf:
222 self.pg_not_in_vrf.append(pg_if)
223 self.logger.info("IPv4 VRF ID %d reset finished" % vrf_id)
224 self.logger.debug(self.vapi.ppcli("show ip fib"))
225 self.logger.debug(self.vapi.ppcli("show ip arp"))
226 self.vapi.ip_table_add_del(vrf_id, is_add=0)
228 def create_stream(self, src_if, packet_sizes):
230 Create input packet stream for defined interface using hosts list.
232 :param object src_if: Interface to create packet stream for.
233 :param list packet_sizes: List of required packet sizes.
234 :return: Stream of packets.
237 src_hosts = src_if.remote_hosts
238 for dst_if in self.flows[src_if]:
239 for dst_host in dst_if.remote_hosts:
240 src_host = random.choice(src_hosts)
241 pkt_info = self.create_packet_info(src_if, dst_if)
242 payload = self.info_to_payload(pkt_info)
243 p = (Ether(dst=src_if.local_mac, src=src_host.mac) /
244 IP(src=src_host.ip4, dst=dst_host.ip4) /
245 UDP(sport=1234, dport=1234) /
247 pkt_info.data = p.copy()
248 size = random.choice(packet_sizes)
249 self.extend_packet(p, size)
251 self.logger.debug("Input stream created for port %s. Length: %u pkt(s)"
252 % (src_if.name, len(pkts)))
255 def create_stream_crosswise_vrf(self, src_if, vrf_id, packet_sizes):
257 Create input packet stream for negative test for leaking across
258 different VRFs for defined interface using hosts list.
260 :param object src_if: Interface to create packet stream for.
261 :param int vrf_id: The FIB table / VRF ID where src_if is assigned.
262 :param list packet_sizes: List of required packet sizes.
263 :return: Stream of packets.
266 src_hosts = src_if.remote_hosts
267 vrf_lst = list(self.vrf_list)
268 vrf_lst.remove(vrf_id)
270 for dst_if in self.pg_if_by_vrf_id[vrf]:
271 for dst_host in dst_if.remote_hosts:
272 src_host = random.choice(src_hosts)
273 pkt_info = self.create_packet_info(src_if, dst_if)
274 payload = self.info_to_payload(pkt_info)
275 p = (Ether(dst=src_if.local_mac, src=src_host.mac) /
276 IP(src=src_host.ip4, dst=dst_host.ip4) /
277 UDP(sport=1234, dport=1234) /
279 pkt_info.data = p.copy()
280 size = random.choice(packet_sizes)
281 self.extend_packet(p, size)
283 self.logger.debug("Input stream created for port %s. Length: %u pkt(s)"
284 % (src_if.name, len(pkts)))
287 def verify_capture(self, pg_if, capture):
289 Verify captured input packet stream for defined interface.
291 :param object pg_if: Interface to verify captured packet stream for.
292 :param list capture: Captured packet stream.
295 for i in self.pg_interfaces:
296 last_info[i.sw_if_index] = None
297 dst_sw_if_index = pg_if.sw_if_index
298 for packet in capture:
302 payload_info = self.payload_to_info(str(packet[Raw]))
303 packet_index = payload_info.index
304 self.assertEqual(payload_info.dst, dst_sw_if_index)
305 self.logger.debug("Got packet on port %s: src=%u (id=%u)" %
306 (pg_if.name, payload_info.src, packet_index))
307 next_info = self.get_next_packet_info_for_interface2(
308 payload_info.src, dst_sw_if_index,
309 last_info[payload_info.src])
310 last_info[payload_info.src] = next_info
311 self.assertIsNotNone(next_info)
312 self.assertEqual(packet_index, next_info.index)
313 saved_packet = next_info.data
314 # Check standard fields
315 self.assertEqual(ip.src, saved_packet[IP].src)
316 self.assertEqual(ip.dst, saved_packet[IP].dst)
317 self.assertEqual(udp.sport, saved_packet[UDP].sport)
318 self.assertEqual(udp.dport, saved_packet[UDP].dport)
320 self.logger.error(ppp("Unexpected or invalid packet:", packet))
322 for i in self.pg_interfaces:
323 remaining_packet = self.get_next_packet_info_for_interface2(
324 i, dst_sw_if_index, last_info[i.sw_if_index])
327 "Port %u: Packet expected from source %u didn't arrive" %
328 (dst_sw_if_index, i.sw_if_index))
330 def verify_vrf(self, vrf_id):
332 Check if the FIB table / VRF ID is configured.
334 :param int vrf_id: The FIB table / VRF ID to be verified.
335 :return: 1 if the FIB table / VRF ID is configured, otherwise return 0.
337 ip_fib_dump = self.vapi.ip_fib_dump()
340 for ip_fib_details in ip_fib_dump:
341 if ip_fib_details.table_id == vrf_id:
344 addr = socket.inet_ntoa(ip_fib_details.address)
346 for pg_if in self.pg_if_by_vrf_id[vrf_id]:
349 for host in pg_if.remote_hosts:
350 if str(addr) == str(host.ip4):
354 if not vrf_exist and vrf_count == 0:
355 self.logger.info("IPv4 VRF ID %d is not configured" % vrf_id)
356 return VRFState.not_configured
357 elif vrf_exist and vrf_count == 0:
358 self.logger.info("IPv4 VRF ID %d has been reset" % vrf_id)
359 return VRFState.reset
361 self.logger.info("IPv4 VRF ID %d is configured" % vrf_id)
362 return VRFState.configured
364 def run_verify_test(self):
366 Create packet streams for all configured pg interfaces, send all \
367 prepared packet streams and verify that:
368 - all packets received correctly on all pg-ip4 interfaces assigned
370 - no packet received on all pg-ip4 interfaces not assigned to VRFs
372 :raise RuntimeError: If no packet captured on pg-ip4 interface assigned
373 to VRF or if any packet is captured on pg-ip4 interface not
377 # Create incoming packet streams for packet-generator interfaces
378 for pg_if in self.pg_interfaces:
379 pkts = self.create_stream(pg_if, self.pg_if_packet_sizes)
380 pg_if.add_stream(pkts)
382 # Enable packet capture and start packet sending
383 self.pg_enable_capture(self.pg_interfaces)
387 # Verify outgoing packet streams per packet-generator interface
388 for pg_if in self.pg_interfaces:
389 if pg_if in self.pg_in_vrf:
390 capture = pg_if.get_capture(remark="interface is in VRF")
391 self.verify_capture(pg_if, capture)
392 elif pg_if in self.pg_not_in_vrf:
393 pg_if.assert_nothing_captured(remark="interface is not in VRF",
394 filter_out_fn=is_ipv4_misc)
395 self.logger.debug("No capture for interface %s" % pg_if.name)
397 raise Exception("Unknown interface: %s" % pg_if.name)
399 def run_crosswise_vrf_test(self):
401 Create packet streams for every pg-ip4 interface in VRF towards all
402 pg-ip4 interfaces in other VRFs, send all prepared packet streams and \
404 - no packet received on all configured pg-ip4 interfaces
406 :raise RuntimeError: If any packet is captured on any pg-ip4 interface.
409 # Create incoming packet streams for packet-generator interfaces
410 for vrf_id in self.vrf_list:
411 for pg_if in self.pg_if_by_vrf_id[vrf_id]:
412 pkts = self.create_stream_crosswise_vrf(
413 pg_if, vrf_id, self.pg_if_packet_sizes)
414 pg_if.add_stream(pkts)
416 # Enable packet capture and start packet sending
417 self.pg_enable_capture(self.pg_interfaces)
421 # Verify outgoing packet streams per packet-generator interface
422 for pg_if in self.pg_interfaces:
423 pg_if.assert_nothing_captured(remark="interface is in other VRF",
424 filter_out_fn=is_ipv4_misc)
425 self.logger.debug("No capture for interface %s" % pg_if.name)
427 def test_ip4_vrf_01(self):
428 """ IP4 VRF Multi-instance test 1 - create 4 VRFs
432 self.create_vrf_and_assign_interfaces(4)
435 for vrf_id in self.vrf_list:
436 self.assert_equal(self.verify_vrf(vrf_id),
437 VRFState.configured, VRFState)
440 self.run_verify_test()
441 self.run_crosswise_vrf_test()
443 def test_ip4_vrf_02(self):
444 """ IP4 VRF Multi-instance test 2 - reset 2 VRFs
448 self.reset_vrf_and_remove_from_vrf_list(1)
449 self.reset_vrf_and_remove_from_vrf_list(2)
452 for vrf_id in self.vrf_reset_list:
453 self.assert_equal(self.verify_vrf(vrf_id),
454 VRFState.reset, VRFState)
455 for vrf_id in self.vrf_list:
456 self.assert_equal(self.verify_vrf(vrf_id),
457 VRFState.configured, VRFState)
460 self.run_verify_test()
461 self.run_crosswise_vrf_test()
463 def test_ip4_vrf_03(self):
464 """ IP4 VRF Multi-instance 3 - add 2 VRFs
467 # Add 1 of reset VRFs and 1 new VRF
468 self.create_vrf_and_assign_interfaces(1)
469 self.create_vrf_and_assign_interfaces(1, start=5)
472 for vrf_id in self.vrf_reset_list:
473 self.assert_equal(self.verify_vrf(vrf_id),
474 VRFState.reset, VRFState)
475 for vrf_id in self.vrf_list:
476 self.assert_equal(self.verify_vrf(vrf_id),
477 VRFState.configured, VRFState)
480 self.run_verify_test()
481 self.run_crosswise_vrf_test()
483 def test_ip4_vrf_04(self):
484 """ IP4 VRF Multi-instance test 4 - reset 4 VRFs
487 # Reset all VRFs (i.e. no VRF except VRF=0 configured)
488 for i in range(len(self.vrf_list)):
489 self.reset_vrf_and_remove_from_vrf_list(self.vrf_list[0])
492 for vrf_id in self.vrf_reset_list:
493 self.assert_equal(self.verify_vrf(vrf_id),
494 VRFState.reset, VRFState)
495 vrf_list_length = len(self.vrf_list)
498 "List of configured VRFs is not empty: %s != 0" % vrf_list_length)
501 self.run_verify_test()
502 self.run_crosswise_vrf_test()
505 if __name__ == '__main__':
506 unittest.main(testRunner=VppTestRunner)