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 VRF
22 - no packet received in case of pg-ip4 interfaces not in VRF
28 - send IP4 packets between all pg-ip4 interfaces in all VRF groups
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
36 - add 1 of reset VRFs and 1 new VRF
39 - send IP4 packets between all pg-ip4 interfaces in all VRF groups
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
47 - reset all created VRFs
50 - send IP4 packets between all pg-ip4 interfaces in all VRF groups
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
62 from scapy.packet import Raw
63 from scapy.layers.l2 import Ether
64 from scapy.layers.inet import IP, UDP, ARP
66 from framework import VppTestCase, VppTestRunner
68 from vrf import VRFState
72 """ Is packet one of uninteresting IPv4 broadcasts? """
78 class TestIp4VrfMultiInst(VppTestCase):
79 """ IP4 VRF Multi-instance Test Case """
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.
88 super(TestIp4VrfMultiInst, cls).setUpClass()
93 cls.pg_ifs_per_vrf = 3
96 # Create pg interfaces
97 cls.create_pg_interfaces(
98 range(cls.nr_of_vrfs * cls.pg_ifs_per_vrf))
100 # Packet flows mapping pg0 -> pg1, pg2 etc.
102 for i in range(len(cls.pg_interfaces)):
103 multiplicand = i / cls.pg_ifs_per_vrf
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
110 # Packet sizes - jumbo packet (9018 bytes) skipped
111 cls.pg_if_packet_sizes = [64, 512, 1518]
113 # Set up all interfaces
114 for pg_if in cls.pg_interfaces:
116 pg_if.generate_remote_hosts(cls.hosts_per_pg)
118 # Create list of VRFs
119 cls.vrf_list = list()
121 # Create list of reset VRFs
122 cls.vrf_reset_list = list()
124 # Create list of pg_interfaces in VRFs
125 cls.pg_in_vrf = list()
127 # Create list of pg_interfaces not in BDs
128 cls.pg_not_in_vrf = [pg_if for pg_if in cls.pg_interfaces]
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):
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
140 super(TestIp4VrfMultiInst, cls).tearDownClass()
145 Clear trace and packet infos before running each test.
147 super(TestIp4VrfMultiInst, self).setUp()
148 self.reset_packet_infos()
152 Show various debug prints after each test.
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"))
159 def create_vrf_and_assign_interfaces(self, count, start=1):
161 Create required number of FIB tables / VRFs, put 3 l2-pg interfaces
162 to every FIB table / VRF.
164 :param int count: Number of FIB tables / VRFs to be created.
165 :param int start: Starting number of the FIB table / VRF ID. \
169 for i in range(count):
171 pg_if = self.pg_if_by_vrf_id[vrf_id][0]
172 dest_addr = pg_if.local_ip4n
174 self.vapi.ip_table_add_del(vrf_id, is_add=1)
175 self.vapi.ip_add_del_route(
176 dest_addr, dest_addr_len, pg_if.local_ip4n,
177 table_id=vrf_id, 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_reset_list:
182 self.vrf_reset_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()
194 self.logger.debug(self.vapi.ppcli("show ip fib"))
195 self.logger.debug(self.vapi.ppcli("show ip arp"))
197 def reset_vrf_and_remove_from_vrf_list(self, vrf_id):
199 Reset required FIB table / VRF and remove it from VRF list.
201 :param int vrf_id: The FIB table / VRF ID to be reset.
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_reset_list:
208 self.vrf_reset_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]
212 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)
216 self.logger.info("IPv4 VRF ID %d reset finished" % vrf_id)
217 self.logger.debug(self.vapi.ppcli("show ip fib"))
218 self.logger.debug(self.vapi.ppcli("show ip arp"))
219 self.vapi.ip_table_add_del(vrf_id, is_add=0)
221 def create_stream(self, src_if, packet_sizes):
223 Create input packet stream for defined interface using hosts list.
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.
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) /
240 pkt_info.data = p.copy()
241 size = random.choice(packet_sizes)
242 self.extend_packet(p, size)
244 self.logger.debug("Input stream created for port %s. Length: %u pkt(s)"
245 % (src_if.name, len(pkts)))
248 def verify_capture(self, pg_if, capture):
250 Verify captured input packet stream for defined interface.
252 :param object pg_if: Interface to verify captured packet stream for.
253 :param list capture: Captured packet stream.
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:
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)
281 self.logger.error(ppp("Unexpected or invalid packet:", packet))
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])
288 "Port %u: Packet expected from source %u didn't arrive" %
289 (dst_sw_if_index, i.sw_if_index))
291 def verify_vrf(self, vrf_id):
293 Check if the FIB table / VRF ID is configured.
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.
298 ip_fib_dump = self.vapi.ip_fib_dump()
301 for ip_fib_details in ip_fib_dump:
302 if ip_fib_details.table_id == vrf_id:
305 addr = socket.inet_ntoa(ip_fib_details.address)
307 for pg_if in self.pg_if_by_vrf_id[vrf_id]:
310 for host in pg_if.remote_hosts:
311 if str(addr) == str(host.ip4):
315 if not vrf_exist and vrf_count == 0:
316 self.logger.info("IPv4 VRF ID %d is not configured" % vrf_id)
317 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
322 self.logger.info("IPv4 VRF ID %d is configured" % vrf_id)
323 return VRFState.configured
325 def run_verify_test(self):
327 Create packet streams for all configured l2-pg interfaces, send all \
328 prepared packet streams and verify that:
329 - all packets received correctly on all pg-l2 interfaces assigned
331 - no packet received on all pg-l2 interfaces not assigned to bridge
334 :raise RuntimeError: If no packet captured on l2-pg interface assigned
335 to the bridge domain or if any packet is captured on l2-pg
336 interface not assigned to the bridge domain.
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)
344 # Enable packet capture and start packet sending
345 self.pg_enable_capture(self.pg_interfaces)
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)
359 raise Exception("Unknown interface: %s" % pg_if.name)
361 def test_ip4_vrf_01(self):
362 """ IP4 VRF Multi-instance test 1 - create 4 VRFs
366 self.create_vrf_and_assign_interfaces(4)
369 for vrf_id in self.vrf_list:
370 self.assert_equal(self.verify_vrf(vrf_id),
371 VRFState.configured, VRFState)
374 self.run_verify_test()
376 def test_ip4_vrf_02(self):
377 """ IP4 VRF Multi-instance test 2 - reset 2 VRFs
381 self.reset_vrf_and_remove_from_vrf_list(1)
382 self.reset_vrf_and_remove_from_vrf_list(2)
385 for vrf_id in self.vrf_reset_list:
386 self.assert_equal(self.verify_vrf(vrf_id),
387 VRFState.reset, VRFState)
388 for vrf_id in self.vrf_list:
389 self.assert_equal(self.verify_vrf(vrf_id),
390 VRFState.configured, VRFState)
393 self.run_verify_test()
395 def test_ip4_vrf_03(self):
396 """ IP4 VRF Multi-instance 3 - add 2 VRFs
399 # Add 1 of reset VRFs and 1 new VRF
400 self.create_vrf_and_assign_interfaces(1)
401 self.create_vrf_and_assign_interfaces(1, start=5)
404 for vrf_id in self.vrf_reset_list:
405 self.assert_equal(self.verify_vrf(vrf_id),
406 VRFState.reset, VRFState)
407 for vrf_id in self.vrf_list:
408 self.assert_equal(self.verify_vrf(vrf_id),
409 VRFState.configured, VRFState)
412 self.run_verify_test()
414 def test_ip4_vrf_04(self):
415 """ IP4 VRF Multi-instance test 4 - reset 4 VRFs
418 # Reset all VRFs (i.e. no VRF except VRF=0 configured)
419 for i in range(len(self.vrf_list)):
420 self.reset_vrf_and_remove_from_vrf_list(self.vrf_list[0])
423 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)
429 "List of configured VRFs is not empty: %s != 0" % vrf_list_length)
432 self.run_verify_test()
435 if __name__ == '__main__':
436 unittest.main(testRunner=VppTestRunner)