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
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
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
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
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
70 from scapy.packet import Raw
71 from scapy.layers.l2 import Ether, ARP
72 from scapy.layers.inet import IP, UDP
74 from framework import VppTestCase, VppTestRunner
76 from vrf import VRFState
80 """ Is packet one of uninteresting IPv4 broadcasts? """
86 class TestIp4VrfMultiInst(VppTestCase):
87 """ IP4 VRF Multi-instance Test Case """
92 Perform standard class setup (defined by class method setUpClass in
93 class VppTestCase) before running the test case, set test case related
94 variables and configure VPP.
96 super(TestIp4VrfMultiInst, cls).setUpClass()
101 cls.pg_ifs_per_vrf = 3
104 # Create pg interfaces
105 cls.create_pg_interfaces(
106 range(cls.nr_of_vrfs * cls.pg_ifs_per_vrf))
108 # Packet flows mapping pg0 -> pg1, pg2 etc.
110 for i in range(len(cls.pg_interfaces)):
111 multiplicand = i // cls.pg_ifs_per_vrf
113 cls.pg_interfaces[multiplicand * cls.pg_ifs_per_vrf + j]
114 for j in range(cls.pg_ifs_per_vrf)
115 if (multiplicand * cls.pg_ifs_per_vrf + j) != i]
116 cls.flows[cls.pg_interfaces[i]] = pg_list
118 # Packet sizes - jumbo packet (9018 bytes) skipped
119 cls.pg_if_packet_sizes = [64, 512, 1518]
121 # Set up all interfaces
122 for pg_if in cls.pg_interfaces:
124 pg_if.generate_remote_hosts(cls.hosts_per_pg)
126 # Create list of VRFs
127 cls.vrf_list = list()
129 # Create list of reset VRFs
130 cls.vrf_reset_list = list()
132 # Create list of pg_interfaces in VRFs
133 cls.pg_in_vrf = list()
135 # Create list of pg_interfaces not in VRFs
136 cls.pg_not_in_vrf = [pg_if for pg_if in cls.pg_interfaces]
138 # Create mapping of pg_interfaces to VRF IDs
139 cls.pg_if_sets = dict()
140 for i in range(cls.nr_of_vrfs):
143 cls.pg_interfaces[i * cls.pg_ifs_per_vrf + j]
144 for j in range(cls.pg_ifs_per_vrf)]
145 cls.pg_if_sets[set_id] = pg_list
148 super(TestIp4VrfMultiInst, cls).tearDownClass()
152 def tearDownClass(cls):
153 super(TestIp4VrfMultiInst, cls).tearDownClass()
157 Clear trace and packet infos before running each test.
159 super(TestIp4VrfMultiInst, self).setUp()
160 self.reset_packet_infos()
164 Show various debug prints after each test.
166 super(TestIp4VrfMultiInst, self).tearDown()
168 def show_commands_at_teardown(self):
169 self.logger.info(self.vapi.ppcli("show ip fib"))
170 self.logger.info(self.vapi.ppcli("show ip4 neighbors"))
172 def _assign_interfaces(self, vrf_id, if_set_id):
173 for i in range(self.pg_ifs_per_vrf):
174 pg_if = self.pg_if_sets[if_set_id][i]
175 pg_if.set_table_ip4(vrf_id)
176 self.logger.info("pg-interface %s added to IPv4 VRF ID %d"
177 % (pg_if.name, vrf_id))
178 if pg_if not in self.pg_in_vrf:
179 self.pg_in_vrf.append(pg_if)
180 if pg_if in self.pg_not_in_vrf:
181 self.pg_not_in_vrf.remove(pg_if)
183 pg_if.configure_ipv4_neighbors()
185 def create_vrf_and_assign_interfaces(self, count, start=1):
187 Create required number of FIB tables / VRFs, put 3 pg-ip4 interfaces
188 to every FIB table / VRF.
190 :param int count: Number of FIB tables / VRFs to be created.
191 :param int start: Starting number of the FIB table / VRF ID. \
195 for i in range(count):
197 self.vapi.ip_table_add_del(is_add=1, table={'table_id': vrf_id})
198 self.logger.info("IPv4 VRF ID %d created" % vrf_id)
199 if vrf_id not in self.vrf_list:
200 self.vrf_list.append(vrf_id)
201 if vrf_id in self.vrf_reset_list:
202 self.vrf_reset_list.remove(vrf_id)
203 self._assign_interfaces(vrf_id, vrf_id)
204 self.logger.debug(self.vapi.ppcli("show ip fib"))
205 self.logger.debug(self.vapi.ppcli("show ip4 neighbors"))
207 def create_vrf_by_id_and_assign_interfaces(self, set_id,
210 Create a FIB table / VRF by vrf_id, put 3 pg-ip4 interfaces
213 :param int vrf_id: Required table ID / VRF ID. \
214 (Default value = 0xffffffff, ID will be selected automatically)
216 ret = self.vapi.ip_table_allocate(table={'table_id': vrf_id})
217 vrf_id = ret.table.table_id
218 self.logger.info("IPv4 VRF ID %d created" % vrf_id)
219 if vrf_id not in self.vrf_list:
220 self.vrf_list.append(vrf_id)
221 if vrf_id in self.vrf_reset_list:
222 self.vrf_reset_list.remove(vrf_id)
223 self._assign_interfaces(vrf_id, set_id)
224 self.logger.debug(self.vapi.ppcli("show ip fib"))
225 self.logger.debug(self.vapi.ppcli("show ip4 neighbors"))
229 def reset_vrf_and_remove_from_vrf_list(self, vrf_id, if_set_id=None):
231 Reset required FIB table / VRF and remove it from VRF list.
233 :param int vrf_id: The FIB table / VRF ID to be reset.
235 if if_set_id is None:
237 self.vapi.ip_table_flush(table={'table_id': vrf_id})
238 if vrf_id in self.vrf_list:
239 self.vrf_list.remove(vrf_id)
240 if vrf_id not in self.vrf_reset_list:
241 self.vrf_reset_list.append(vrf_id)
242 for j in range(self.pg_ifs_per_vrf):
243 pg_if = self.pg_if_sets[if_set_id][j]
245 if pg_if in self.pg_in_vrf:
246 self.pg_in_vrf.remove(pg_if)
247 if pg_if not in self.pg_not_in_vrf:
248 self.pg_not_in_vrf.append(pg_if)
249 self.logger.info("IPv4 VRF ID %d reset finished" % vrf_id)
250 self.logger.debug(self.vapi.ppcli("show ip fib"))
251 self.logger.debug(self.vapi.ppcli("show ip neighbors"))
252 self.vapi.ip_table_add_del(is_add=0, table={'table_id': vrf_id})
254 def create_stream(self, src_if, packet_sizes):
256 Create input packet stream for defined interface using hosts list.
258 :param object src_if: Interface to create packet stream for.
259 :param list packet_sizes: List of required packet sizes.
260 :return: Stream of packets.
263 src_hosts = src_if.remote_hosts
264 for dst_if in self.flows[src_if]:
265 for dst_host in dst_if.remote_hosts:
266 src_host = random.choice(src_hosts)
267 pkt_info = self.create_packet_info(src_if, dst_if)
268 payload = self.info_to_payload(pkt_info)
269 p = (Ether(dst=src_if.local_mac, src=src_host.mac) /
270 IP(src=src_host.ip4, dst=dst_host.ip4) /
271 UDP(sport=1234, dport=1234) /
273 pkt_info.data = p.copy()
274 size = random.choice(packet_sizes)
275 self.extend_packet(p, size)
277 self.logger.debug("Input stream created for port %s. Length: %u pkt(s)"
278 % (src_if.name, len(pkts)))
281 def create_stream_crosswise_vrf(self, src_if, vrf_id, packet_sizes):
283 Create input packet stream for negative test for leaking across
284 different VRFs for defined interface using hosts list.
286 :param object src_if: Interface to create packet stream for.
287 :param int vrf_id: The FIB table / VRF ID where src_if is assigned.
288 :param list packet_sizes: List of required packet sizes.
289 :return: Stream of packets.
292 src_hosts = src_if.remote_hosts
293 vrf_lst = list(self.vrf_list)
294 vrf_lst.remove(vrf_id)
296 for dst_if in self.pg_if_sets[vrf]:
297 for dst_host in dst_if.remote_hosts:
298 src_host = random.choice(src_hosts)
299 pkt_info = self.create_packet_info(src_if, dst_if)
300 payload = self.info_to_payload(pkt_info)
301 p = (Ether(dst=src_if.local_mac, src=src_host.mac) /
302 IP(src=src_host.ip4, dst=dst_host.ip4) /
303 UDP(sport=1234, dport=1234) /
305 pkt_info.data = p.copy()
306 size = random.choice(packet_sizes)
307 self.extend_packet(p, size)
309 self.logger.debug("Input stream created for port %s. Length: %u pkt(s)"
310 % (src_if.name, len(pkts)))
313 def verify_capture(self, pg_if, capture):
315 Verify captured input packet stream for defined interface.
317 :param object pg_if: Interface to verify captured packet stream for.
318 :param list capture: Captured packet stream.
321 for i in self.pg_interfaces:
322 last_info[i.sw_if_index] = None
323 dst_sw_if_index = pg_if.sw_if_index
324 for packet in capture:
328 payload_info = self.payload_to_info(packet[Raw])
329 packet_index = payload_info.index
330 self.assertEqual(payload_info.dst, dst_sw_if_index)
331 self.logger.debug("Got packet on port %s: src=%u (id=%u)" %
332 (pg_if.name, payload_info.src, packet_index))
333 next_info = self.get_next_packet_info_for_interface2(
334 payload_info.src, dst_sw_if_index,
335 last_info[payload_info.src])
336 last_info[payload_info.src] = next_info
337 self.assertIsNotNone(next_info)
338 self.assertEqual(packet_index, next_info.index)
339 saved_packet = next_info.data
340 # Check standard fields
341 self.assertEqual(ip.src, saved_packet[IP].src)
342 self.assertEqual(ip.dst, saved_packet[IP].dst)
343 self.assertEqual(udp.sport, saved_packet[UDP].sport)
344 self.assertEqual(udp.dport, saved_packet[UDP].dport)
346 self.logger.error(ppp("Unexpected or invalid packet:", packet))
348 for i in self.pg_interfaces:
349 remaining_packet = self.get_next_packet_info_for_interface2(
350 i, dst_sw_if_index, last_info[i.sw_if_index])
353 "Port %u: Packet expected from source %u didn't arrive" %
354 (dst_sw_if_index, i.sw_if_index))
356 def verify_vrf(self, vrf_id, if_set_id=None):
358 Check if the FIB table / VRF ID is configured.
360 :param int vrf_id: The FIB table / VRF ID to be verified.
361 :return: 1 if the FIB table / VRF ID is configured, otherwise return 0.
363 if if_set_id is None:
365 ip_fib_dump = self.vapi.ip_route_dump(vrf_id)
366 vrf_exist = len(ip_fib_dump)
368 for ip_fib_details in ip_fib_dump:
369 addr = ip_fib_details.route.prefix.network_address
371 for pg_if in self.pg_if_sets[if_set_id]:
374 for host in pg_if.remote_hosts:
375 if str(addr) == host.ip4:
379 if not vrf_exist and vrf_count == 0:
380 self.logger.info("IPv4 VRF ID %d is not configured" % vrf_id)
381 return VRFState.not_configured
382 elif vrf_exist and vrf_count == 0:
383 self.logger.info("IPv4 VRF ID %d has been reset" % vrf_id)
384 return VRFState.reset
386 self.logger.info("IPv4 VRF ID %d is configured" % vrf_id)
387 return VRFState.configured
389 def run_verify_test(self):
391 Create packet streams for all configured pg interfaces, send all \
392 prepared packet streams and verify that:
393 - all packets received correctly on all pg-ip4 interfaces assigned
395 - no packet received on all pg-ip4 interfaces not assigned to VRFs
397 :raise RuntimeError: If no packet captured on pg-ip4 interface assigned
398 to VRF or if any packet is captured on pg-ip4 interface not
402 # Create incoming packet streams for packet-generator interfaces
403 for pg_if in self.pg_interfaces:
404 pkts = self.create_stream(pg_if, self.pg_if_packet_sizes)
405 pg_if.add_stream(pkts)
407 # Enable packet capture and start packet sending
408 self.pg_enable_capture(self.pg_interfaces)
412 # Verify outgoing packet streams per packet-generator interface
413 for pg_if in self.pg_interfaces:
414 if pg_if in self.pg_in_vrf:
415 capture = pg_if.get_capture(remark="interface is in VRF")
416 self.verify_capture(pg_if, capture)
417 elif pg_if in self.pg_not_in_vrf:
418 pg_if.assert_nothing_captured(remark="interface is not in VRF",
419 filter_out_fn=is_ipv4_misc)
420 self.logger.debug("No capture for interface %s" % pg_if.name)
422 raise Exception("Unknown interface: %s" % pg_if.name)
424 def run_crosswise_vrf_test(self):
426 Create packet streams for every pg-ip4 interface in VRF towards all
427 pg-ip4 interfaces in other VRFs, send all prepared packet streams and
430 - no packet received on all configured pg-ip4 interfaces
432 :raise RuntimeError: If any packet is captured on any pg-ip4 interface.
435 # Create incoming packet streams for packet-generator interfaces
436 for vrf_id in self.vrf_list:
437 for pg_if in self.pg_if_sets[vrf_id]:
438 pkts = self.create_stream_crosswise_vrf(
439 pg_if, vrf_id, self.pg_if_packet_sizes)
440 pg_if.add_stream(pkts)
442 # Enable packet capture and start packet sending
443 self.pg_enable_capture(self.pg_interfaces)
447 # Verify outgoing packet streams per packet-generator interface
448 for pg_if in self.pg_interfaces:
449 pg_if.assert_nothing_captured(remark="interface is in other VRF",
450 filter_out_fn=is_ipv4_misc)
451 self.logger.debug("No capture for interface %s" % pg_if.name)
453 def test_ip4_vrf_01(self):
454 """ IP4 VRF Multi-instance test 1 - create 4 VRFs
458 self.create_vrf_and_assign_interfaces(4)
461 for vrf_id in self.vrf_list:
462 self.assert_equal(self.verify_vrf(vrf_id),
463 VRFState.configured, VRFState)
466 self.run_verify_test()
467 self.run_crosswise_vrf_test()
469 def test_ip4_vrf_02(self):
470 """ IP4 VRF Multi-instance test 2 - reset 2 VRFs
474 self.reset_vrf_and_remove_from_vrf_list(1)
475 self.reset_vrf_and_remove_from_vrf_list(2)
478 for vrf_id in self.vrf_reset_list:
479 self.assert_equal(self.verify_vrf(vrf_id),
480 VRFState.reset, VRFState)
481 for vrf_id in self.vrf_list:
482 self.assert_equal(self.verify_vrf(vrf_id),
483 VRFState.configured, VRFState)
486 self.run_verify_test()
487 self.run_crosswise_vrf_test()
489 def test_ip4_vrf_03(self):
490 """ IP4 VRF Multi-instance 3 - add 2 VRFs
493 # Add 1 of reset VRFs and 1 new VRF
494 self.create_vrf_and_assign_interfaces(1)
495 self.create_vrf_and_assign_interfaces(1, start=5)
498 for vrf_id in self.vrf_reset_list:
499 self.assert_equal(self.verify_vrf(vrf_id),
500 VRFState.reset, VRFState)
501 for vrf_id in self.vrf_list:
502 self.assert_equal(self.verify_vrf(vrf_id),
503 VRFState.configured, VRFState)
506 self.run_verify_test()
507 self.run_crosswise_vrf_test()
509 def test_ip4_vrf_04(self):
510 """ IP4 VRF Multi-instance test 4 - reset 4 VRFs
513 # Reset all VRFs (i.e. no VRF except VRF=0 configured)
514 for i in range(len(self.vrf_list)):
515 self.reset_vrf_and_remove_from_vrf_list(self.vrf_list[0])
518 for vrf_id in self.vrf_reset_list:
519 self.assert_equal(self.verify_vrf(vrf_id),
520 VRFState.reset, VRFState)
521 vrf_list_length = len(self.vrf_list)
524 "List of configured VRFs is not empty: %s != 0" % vrf_list_length)
527 self.run_verify_test()
528 self.run_crosswise_vrf_test()
530 def test_ip4_vrf_05(self):
531 """ IP4 VRF Multi-instance test 5 - id allocation
534 # Create several VRFs
535 # Set vrf_id manually first
536 self.create_vrf_by_id_and_assign_interfaces(1, 1)
537 # Set vrf_id automatically a few times
539 self.create_vrf_by_id_and_assign_interfaces(i) for i in range(2, 5)
543 self.assert_equal(self.verify_vrf(1, 1), VRFState.configured, VRFState)
544 for i, vrf in enumerate(auto_vrf_id):
545 self.assert_equal(self.verify_vrf(vrf, i+2),
546 VRFState.configured, VRFState)
549 self.run_verify_test()
553 self.reset_vrf_and_remove_from_vrf_list(1)
554 for i, vrf in enumerate(auto_vrf_id):
555 self.reset_vrf_and_remove_from_vrf_list(vrf, i+2)
558 self.assert_equal(self.verify_vrf(1, 1), VRFState.reset, VRFState)
559 for i, vrf in enumerate(auto_vrf_id):
560 self.assert_equal(self.verify_vrf(vrf, i+2),
561 VRFState.reset, VRFState)
563 vrf_list_length = len(self.vrf_list)
566 "List of configured VRFs is not empty: %s != 0" % vrf_list_length)
568 if __name__ == '__main__':
569 unittest.main(testRunner=VppTestRunner)