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
70 from scapy.packet import Raw
71 from scapy.layers.l2 import Ether
72 from scapy.layers.inet import IP, UDP, ARP
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_by_vrf_id = 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_by_vrf_id[vrf_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()
167 if not self.vpp_dead:
168 self.logger.info(self.vapi.ppcli("show ip fib"))
169 self.logger.info(self.vapi.ppcli("show ip arp"))
171 def create_vrf_and_assign_interfaces(self, count, start=1):
173 Create required number of FIB tables / VRFs, put 3 pg-ip4 interfaces
174 to every FIB table / VRF.
176 :param int count: Number of FIB tables / VRFs to be created.
177 :param int start: Starting number of the FIB table / VRF ID. \
181 for i in range(count):
183 pg_if = self.pg_if_by_vrf_id[vrf_id][0]
184 dest_addr = pg_if.local_ip4n
186 self.vapi.ip_table_add_del(is_add=1, table_id=vrf_id)
187 self.logger.info("IPv4 VRF ID %d created" % vrf_id)
188 if vrf_id not in self.vrf_list:
189 self.vrf_list.append(vrf_id)
190 if vrf_id in self.vrf_reset_list:
191 self.vrf_reset_list.remove(vrf_id)
192 for j in range(self.pg_ifs_per_vrf):
193 pg_if = self.pg_if_by_vrf_id[vrf_id][j]
194 pg_if.set_table_ip4(vrf_id)
195 self.logger.info("pg-interface %s added to IPv4 VRF ID %d"
196 % (pg_if.name, vrf_id))
197 if pg_if not in self.pg_in_vrf:
198 self.pg_in_vrf.append(pg_if)
199 if pg_if in self.pg_not_in_vrf:
200 self.pg_not_in_vrf.remove(pg_if)
202 pg_if.configure_ipv4_neighbors()
203 self.logger.debug(self.vapi.ppcli("show ip fib"))
204 self.logger.debug(self.vapi.ppcli("show ip arp"))
206 def reset_vrf_and_remove_from_vrf_list(self, vrf_id):
208 Reset required FIB table / VRF and remove it from VRF list.
210 :param int vrf_id: The FIB table / VRF ID to be reset.
212 # self.vapi.reset_vrf(vrf_id, is_ipv6=0)
213 self.vapi.reset_fib(vrf_id, is_ipv6=0)
214 if vrf_id in self.vrf_list:
215 self.vrf_list.remove(vrf_id)
216 if vrf_id not in self.vrf_reset_list:
217 self.vrf_reset_list.append(vrf_id)
218 for j in range(self.pg_ifs_per_vrf):
219 pg_if = self.pg_if_by_vrf_id[vrf_id][j]
221 if pg_if in self.pg_in_vrf:
222 self.pg_in_vrf.remove(pg_if)
223 if pg_if not in self.pg_not_in_vrf:
224 self.pg_not_in_vrf.append(pg_if)
225 self.logger.info("IPv4 VRF ID %d reset finished" % vrf_id)
226 self.logger.debug(self.vapi.ppcli("show ip fib"))
227 self.logger.debug(self.vapi.ppcli("show ip arp"))
228 self.vapi.ip_table_add_del(is_add=0, table_id=vrf_id)
230 def create_stream(self, src_if, packet_sizes):
232 Create input packet stream for defined interface using hosts list.
234 :param object src_if: Interface to create packet stream for.
235 :param list packet_sizes: List of required packet sizes.
236 :return: Stream of packets.
239 src_hosts = src_if.remote_hosts
240 for dst_if in self.flows[src_if]:
241 for dst_host in dst_if.remote_hosts:
242 src_host = random.choice(src_hosts)
243 pkt_info = self.create_packet_info(src_if, dst_if)
244 payload = self.info_to_payload(pkt_info)
245 p = (Ether(dst=src_if.local_mac, src=src_host.mac) /
246 IP(src=src_host.ip4, dst=dst_host.ip4) /
247 UDP(sport=1234, dport=1234) /
249 pkt_info.data = p.copy()
250 size = random.choice(packet_sizes)
251 self.extend_packet(p, size)
253 self.logger.debug("Input stream created for port %s. Length: %u pkt(s)"
254 % (src_if.name, len(pkts)))
257 def create_stream_crosswise_vrf(self, src_if, vrf_id, packet_sizes):
259 Create input packet stream for negative test for leaking across
260 different VRFs for defined interface using hosts list.
262 :param object src_if: Interface to create packet stream for.
263 :param int vrf_id: The FIB table / VRF ID where src_if is assigned.
264 :param list packet_sizes: List of required packet sizes.
265 :return: Stream of packets.
268 src_hosts = src_if.remote_hosts
269 vrf_lst = list(self.vrf_list)
270 vrf_lst.remove(vrf_id)
272 for dst_if in self.pg_if_by_vrf_id[vrf]:
273 for dst_host in dst_if.remote_hosts:
274 src_host = random.choice(src_hosts)
275 pkt_info = self.create_packet_info(src_if, dst_if)
276 payload = self.info_to_payload(pkt_info)
277 p = (Ether(dst=src_if.local_mac, src=src_host.mac) /
278 IP(src=src_host.ip4, dst=dst_host.ip4) /
279 UDP(sport=1234, dport=1234) /
281 pkt_info.data = p.copy()
282 size = random.choice(packet_sizes)
283 self.extend_packet(p, size)
285 self.logger.debug("Input stream created for port %s. Length: %u pkt(s)"
286 % (src_if.name, len(pkts)))
289 def verify_capture(self, pg_if, capture):
291 Verify captured input packet stream for defined interface.
293 :param object pg_if: Interface to verify captured packet stream for.
294 :param list capture: Captured packet stream.
297 for i in self.pg_interfaces:
298 last_info[i.sw_if_index] = None
299 dst_sw_if_index = pg_if.sw_if_index
300 for packet in capture:
304 payload_info = self.payload_to_info(packet[Raw])
305 packet_index = payload_info.index
306 self.assertEqual(payload_info.dst, dst_sw_if_index)
307 self.logger.debug("Got packet on port %s: src=%u (id=%u)" %
308 (pg_if.name, payload_info.src, packet_index))
309 next_info = self.get_next_packet_info_for_interface2(
310 payload_info.src, dst_sw_if_index,
311 last_info[payload_info.src])
312 last_info[payload_info.src] = next_info
313 self.assertIsNotNone(next_info)
314 self.assertEqual(packet_index, next_info.index)
315 saved_packet = next_info.data
316 # Check standard fields
317 self.assertEqual(ip.src, saved_packet[IP].src)
318 self.assertEqual(ip.dst, saved_packet[IP].dst)
319 self.assertEqual(udp.sport, saved_packet[UDP].sport)
320 self.assertEqual(udp.dport, saved_packet[UDP].dport)
322 self.logger.error(ppp("Unexpected or invalid packet:", packet))
324 for i in self.pg_interfaces:
325 remaining_packet = self.get_next_packet_info_for_interface2(
326 i, dst_sw_if_index, last_info[i.sw_if_index])
329 "Port %u: Packet expected from source %u didn't arrive" %
330 (dst_sw_if_index, i.sw_if_index))
332 def verify_vrf(self, vrf_id):
334 Check if the FIB table / VRF ID is configured.
336 :param int vrf_id: The FIB table / VRF ID to be verified.
337 :return: 1 if the FIB table / VRF ID is configured, otherwise return 0.
339 ip_fib_dump = self.vapi.ip_fib_dump()
342 for ip_fib_details in ip_fib_dump:
343 if ip_fib_details.table_id == vrf_id:
346 addr = socket.inet_ntoa(ip_fib_details.address)
348 for pg_if in self.pg_if_by_vrf_id[vrf_id]:
351 for host in pg_if.remote_hosts:
352 if scapy.compat.raw(addr) == \
353 scapy.compat.raw(host.ip4):
357 if not vrf_exist and vrf_count == 0:
358 self.logger.info("IPv4 VRF ID %d is not configured" % vrf_id)
359 return VRFState.not_configured
360 elif vrf_exist and vrf_count == 0:
361 self.logger.info("IPv4 VRF ID %d has been reset" % vrf_id)
362 return VRFState.reset
364 self.logger.info("IPv4 VRF ID %d is configured" % vrf_id)
365 return VRFState.configured
367 def run_verify_test(self):
369 Create packet streams for all configured pg interfaces, send all \
370 prepared packet streams and verify that:
371 - all packets received correctly on all pg-ip4 interfaces assigned
373 - no packet received on all pg-ip4 interfaces not assigned to VRFs
375 :raise RuntimeError: If no packet captured on pg-ip4 interface assigned
376 to VRF or if any packet is captured on pg-ip4 interface not
380 # Create incoming packet streams for packet-generator interfaces
381 for pg_if in self.pg_interfaces:
382 pkts = self.create_stream(pg_if, self.pg_if_packet_sizes)
383 pg_if.add_stream(pkts)
385 # Enable packet capture and start packet sending
386 self.pg_enable_capture(self.pg_interfaces)
390 # Verify outgoing packet streams per packet-generator interface
391 for pg_if in self.pg_interfaces:
392 if pg_if in self.pg_in_vrf:
393 capture = pg_if.get_capture(remark="interface is in VRF")
394 self.verify_capture(pg_if, capture)
395 elif pg_if in self.pg_not_in_vrf:
396 pg_if.assert_nothing_captured(remark="interface is not in VRF",
397 filter_out_fn=is_ipv4_misc)
398 self.logger.debug("No capture for interface %s" % pg_if.name)
400 raise Exception("Unknown interface: %s" % pg_if.name)
402 def run_crosswise_vrf_test(self):
404 Create packet streams for every pg-ip4 interface in VRF towards all
405 pg-ip4 interfaces in other VRFs, send all prepared packet streams and \
407 - no packet received on all configured pg-ip4 interfaces
409 :raise RuntimeError: If any packet is captured on any pg-ip4 interface.
412 # Create incoming packet streams for packet-generator interfaces
413 for vrf_id in self.vrf_list:
414 for pg_if in self.pg_if_by_vrf_id[vrf_id]:
415 pkts = self.create_stream_crosswise_vrf(
416 pg_if, vrf_id, self.pg_if_packet_sizes)
417 pg_if.add_stream(pkts)
419 # Enable packet capture and start packet sending
420 self.pg_enable_capture(self.pg_interfaces)
424 # Verify outgoing packet streams per packet-generator interface
425 for pg_if in self.pg_interfaces:
426 pg_if.assert_nothing_captured(remark="interface is in other VRF",
427 filter_out_fn=is_ipv4_misc)
428 self.logger.debug("No capture for interface %s" % pg_if.name)
430 def test_ip4_vrf_01(self):
431 """ IP4 VRF Multi-instance test 1 - create 4 VRFs
435 self.create_vrf_and_assign_interfaces(4)
438 for vrf_id in self.vrf_list:
439 self.assert_equal(self.verify_vrf(vrf_id),
440 VRFState.configured, VRFState)
443 self.run_verify_test()
444 self.run_crosswise_vrf_test()
446 def test_ip4_vrf_02(self):
447 """ IP4 VRF Multi-instance test 2 - reset 2 VRFs
451 self.reset_vrf_and_remove_from_vrf_list(1)
452 self.reset_vrf_and_remove_from_vrf_list(2)
455 for vrf_id in self.vrf_reset_list:
456 self.assert_equal(self.verify_vrf(vrf_id),
457 VRFState.reset, VRFState)
458 for vrf_id in self.vrf_list:
459 self.assert_equal(self.verify_vrf(vrf_id),
460 VRFState.configured, VRFState)
463 self.run_verify_test()
464 self.run_crosswise_vrf_test()
466 def test_ip4_vrf_03(self):
467 """ IP4 VRF Multi-instance 3 - add 2 VRFs
470 # Add 1 of reset VRFs and 1 new VRF
471 self.create_vrf_and_assign_interfaces(1)
472 self.create_vrf_and_assign_interfaces(1, start=5)
475 for vrf_id in self.vrf_reset_list:
476 self.assert_equal(self.verify_vrf(vrf_id),
477 VRFState.reset, VRFState)
478 for vrf_id in self.vrf_list:
479 self.assert_equal(self.verify_vrf(vrf_id),
480 VRFState.configured, VRFState)
483 self.run_verify_test()
484 self.run_crosswise_vrf_test()
486 def test_ip4_vrf_04(self):
487 """ IP4 VRF Multi-instance test 4 - reset 4 VRFs
490 # Reset all VRFs (i.e. no VRF except VRF=0 configured)
491 for i in range(len(self.vrf_list)):
492 self.reset_vrf_and_remove_from_vrf_list(self.vrf_list[0])
495 for vrf_id in self.vrf_reset_list:
496 self.assert_equal(self.verify_vrf(vrf_id),
497 VRFState.reset, VRFState)
498 vrf_list_length = len(self.vrf_list)
501 "List of configured VRFs is not empty: %s != 0" % vrf_list_length)
504 self.run_verify_test()
505 self.run_crosswise_vrf_test()
508 if __name__ == '__main__':
509 unittest.main(testRunner=VppTestRunner)