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(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 deleted VRFs
122 cls.vrf_deleted_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.remote_hosts[0].ip4n
174 self.vapi.ip_add_del_route(
175 dest_addr, dest_addr_len, pg_if.local_ip4n,
176 table_id=vrf_id, create_vrf_if_needed=1, is_multipath=1)
177 self.logger.info("IPv4 VRF ID %d created" % vrf_id)
178 if vrf_id not in self.vrf_list:
179 self.vrf_list.append(vrf_id)
180 if vrf_id in self.vrf_deleted_list:
181 self.vrf_deleted_list.remove(vrf_id)
182 for j in range(self.pg_ifs_per_vrf):
183 pg_if = self.pg_if_by_vrf_id[vrf_id][j]
184 pg_if.set_table_ip4(vrf_id)
185 self.logger.info("pg-interface %s added to IPv4 VRF ID %d"
186 % (pg_if.name, vrf_id))
187 if pg_if not in self.pg_in_vrf:
188 self.pg_in_vrf.append(pg_if)
189 if pg_if in self.pg_not_in_vrf:
190 self.pg_not_in_vrf.remove(pg_if)
192 pg_if.configure_ipv4_neighbors(vrf_id)
193 self.logger.debug(self.vapi.ppcli("show ip fib"))
194 self.logger.debug(self.vapi.ppcli("show ip arp"))
196 def delete_vrf(self, vrf_id):
198 Delete required FIB table / VRF.
200 :param int vrf_id: The FIB table / VRF ID to be deleted.
202 # self.vapi.reset_vrf(vrf_id, is_ipv6=0)
203 self.vapi.reset_fib(vrf_id, is_ipv6=0)
204 if vrf_id in self.vrf_list:
205 self.vrf_list.remove(vrf_id)
206 if vrf_id not in self.vrf_deleted_list:
207 self.vrf_deleted_list.append(vrf_id)
208 for j in range(self.pg_ifs_per_vrf):
209 pg_if = self.pg_if_by_vrf_id[vrf_id][j]
210 if pg_if in self.pg_in_vrf:
211 self.pg_in_vrf.remove(pg_if)
212 if pg_if not in self.pg_not_in_vrf:
213 self.pg_not_in_vrf.append(pg_if)
214 self.logger.info("IPv4 VRF ID %d reset" % vrf_id)
215 self.logger.debug(self.vapi.ppcli("show ip fib"))
216 self.logger.debug(self.vapi.ppcli("show ip arp"))
218 def create_stream(self, src_if, packet_sizes):
220 Create input packet stream for defined interface using hosts list.
222 :param object src_if: Interface to create packet stream for.
223 :param list packet_sizes: List of required packet sizes.
224 :return: Stream of packets.
227 src_hosts = src_if.remote_hosts
228 for dst_if in self.flows[src_if]:
229 for dst_host in dst_if.remote_hosts:
230 src_host = random.choice(src_hosts)
231 pkt_info = self.create_packet_info(src_if, dst_if)
232 payload = self.info_to_payload(pkt_info)
233 p = (Ether(dst=src_if.local_mac, src=src_host.mac) /
234 IP(src=src_host.ip4, dst=dst_host.ip4) /
235 UDP(sport=1234, dport=1234) /
237 pkt_info.data = p.copy()
238 size = random.choice(packet_sizes)
239 self.extend_packet(p, size)
241 self.logger.debug("Input stream created for port %s. Length: %u pkt(s)"
242 % (src_if.name, len(pkts)))
245 def verify_capture(self, pg_if, capture):
247 Verify captured input packet stream for defined interface.
249 :param object pg_if: Interface to verify captured packet stream for.
250 :param list capture: Captured packet stream.
253 for i in self.pg_interfaces:
254 last_info[i.sw_if_index] = None
255 dst_sw_if_index = pg_if.sw_if_index
256 for packet in capture:
260 payload_info = self.payload_to_info(str(packet[Raw]))
261 packet_index = payload_info.index
262 self.assertEqual(payload_info.dst, dst_sw_if_index)
263 self.logger.debug("Got packet on port %s: src=%u (id=%u)" %
264 (pg_if.name, payload_info.src, packet_index))
265 next_info = self.get_next_packet_info_for_interface2(
266 payload_info.src, dst_sw_if_index,
267 last_info[payload_info.src])
268 last_info[payload_info.src] = next_info
269 self.assertIsNotNone(next_info)
270 self.assertEqual(packet_index, next_info.index)
271 saved_packet = next_info.data
272 # Check standard fields
273 self.assertEqual(ip.src, saved_packet[IP].src)
274 self.assertEqual(ip.dst, saved_packet[IP].dst)
275 self.assertEqual(udp.sport, saved_packet[UDP].sport)
276 self.assertEqual(udp.dport, saved_packet[UDP].dport)
278 self.logger.error(ppp("Unexpected or invalid packet:", packet))
280 for i in self.pg_interfaces:
281 remaining_packet = self.get_next_packet_info_for_interface2(
282 i, dst_sw_if_index, last_info[i.sw_if_index])
285 "Port %u: Packet expected from source %u didn't arrive" %
286 (dst_sw_if_index, i.sw_if_index))
288 def verify_vrf(self, vrf_id):
290 Check if the FIB table / VRF ID is configured.
292 :param int vrf_id: The FIB table / VRF ID to be verified.
293 :return: 1 if the FIB table / VRF ID is configured, otherwise return 0.
295 ip_fib_dump = self.vapi.ip_fib_dump()
297 for ip_fib_details in ip_fib_dump:
298 if ip_fib_details[2] == vrf_id:
301 self.logger.info("IPv4 VRF ID %d is not configured" % vrf_id)
304 self.logger.info("IPv4 VRF ID %d is configured" % vrf_id)
307 def run_verify_test(self):
309 Create packet streams for all configured l2-pg interfaces, send all
310 prepared packet streams and verify that:
311 - all packets received correctly on all pg-l2 interfaces assigned to
313 - no packet received on all pg-l2 interfaces not assigned to bridge
316 :raise RuntimeError: If no packet captured on l2-pg interface assigned
317 to the bridge domain or if any packet is captured on l2-pg interface
318 not assigned to the bridge domain.
321 # Create incoming packet streams for packet-generator interfaces
322 for pg_if in self.pg_interfaces:
323 pkts = self.create_stream(pg_if, self.pg_if_packet_sizes)
324 pg_if.add_stream(pkts)
326 # Enable packet capture and start packet sending
327 self.pg_enable_capture(self.pg_interfaces)
331 # Verify outgoing packet streams per packet-generator interface
332 for pg_if in self.pg_interfaces:
333 if pg_if in self.pg_in_vrf:
334 capture = pg_if.get_capture(remark="interface is in VRF")
335 self.verify_capture(pg_if, capture)
336 elif pg_if in self.pg_not_in_vrf:
337 pg_if.assert_nothing_captured(remark="interface is not in VRF",
338 filter_out_fn=is_ipv4_misc)
339 self.logger.debug("No capture for interface %s" % pg_if.name)
341 raise Exception("Unknown interface: %s" % pg_if.name)
343 def test_ip4_vrf_01(self):
344 """ IP4 VRF Multi-instance test 1 - create 5 BDs
348 self.create_vrf_and_assign_interfaces(4)
351 for vrf_id in self.vrf_list:
352 self.assertEqual(self.verify_vrf(vrf_id), 1)
355 self.run_verify_test()
357 def test_ip4_vrf_02(self):
358 """ IP4 VRF Multi-instance test 2 - delete 2 VRFs
366 # for vrf_id in self.vrf_deleted_list:
367 # self.assertEqual(self.verify_vrf(vrf_id), 0)
368 for vrf_id in self.vrf_list:
369 self.assertEqual(self.verify_vrf(vrf_id), 1)
372 self.run_verify_test()
374 def test_ip4_vrf_03(self):
375 """ IP4 VRF Multi-instance 3 - add 2 VRFs
378 # Add 1 of deleted VRFs and 1 new VRF
379 self.create_vrf_and_assign_interfaces(1)
380 self.create_vrf_and_assign_interfaces(1, start=5)
383 # for vrf_id in self.vrf_deleted_list:
384 # self.assertEqual(self.verify_vrf(vrf_id), 0)
385 for vrf_id in self.vrf_list:
386 self.assertEqual(self.verify_vrf(vrf_id), 1)
389 self.run_verify_test()
391 def test_ip4_vrf_04(self):
392 """ IP4 VRF Multi-instance test 4 - delete 4 VRFs
395 # Delete all VRFs (i.e. no VRF except VRF=0 created)
396 for i in range(len(self.vrf_list)):
397 self.delete_vrf(self.vrf_list[0])
400 # for vrf_id in self.vrf_deleted_list:
401 # self.assertEqual(self.verify_vrf(vrf_id), 0)
402 for vrf_id in self.vrf_list:
403 self.assertEqual(self.verify_vrf(vrf_id), 1)
406 self.run_verify_test()
409 if __name__ == '__main__':
410 unittest.main(testRunner=VppTestRunner)