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()
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 ip arp"))
172 def create_vrf_and_assign_interfaces(self, count, start=1):
174 Create required number of FIB tables / VRFs, put 3 pg-ip4 interfaces
175 to every FIB table / VRF.
177 :param int count: Number of FIB tables / VRFs to be created.
178 :param int start: Starting number of the FIB table / VRF ID. \
182 for i in range(count):
184 pg_if = self.pg_if_by_vrf_id[vrf_id][0]
185 dest_addr = pg_if.local_ip4n
187 self.vapi.ip_table_add_del(is_add=1, table_id=vrf_id)
188 self.logger.info("IPv4 VRF ID %d created" % vrf_id)
189 if vrf_id not in self.vrf_list:
190 self.vrf_list.append(vrf_id)
191 if vrf_id in self.vrf_reset_list:
192 self.vrf_reset_list.remove(vrf_id)
193 for j in range(self.pg_ifs_per_vrf):
194 pg_if = self.pg_if_by_vrf_id[vrf_id][j]
195 pg_if.set_table_ip4(vrf_id)
196 self.logger.info("pg-interface %s added to IPv4 VRF ID %d"
197 % (pg_if.name, vrf_id))
198 if pg_if not in self.pg_in_vrf:
199 self.pg_in_vrf.append(pg_if)
200 if pg_if in self.pg_not_in_vrf:
201 self.pg_not_in_vrf.remove(pg_if)
203 pg_if.configure_ipv4_neighbors()
204 self.logger.debug(self.vapi.ppcli("show ip fib"))
205 self.logger.debug(self.vapi.ppcli("show ip arp"))
207 def reset_vrf_and_remove_from_vrf_list(self, vrf_id):
209 Reset required FIB table / VRF and remove it from VRF list.
211 :param int vrf_id: The FIB table / VRF ID to be reset.
213 # self.vapi.reset_vrf(vrf_id, is_ipv6=0)
214 self.vapi.reset_fib(vrf_id, is_ipv6=0)
215 if vrf_id in self.vrf_list:
216 self.vrf_list.remove(vrf_id)
217 if vrf_id not in self.vrf_reset_list:
218 self.vrf_reset_list.append(vrf_id)
219 for j in range(self.pg_ifs_per_vrf):
220 pg_if = self.pg_if_by_vrf_id[vrf_id][j]
222 if pg_if in self.pg_in_vrf:
223 self.pg_in_vrf.remove(pg_if)
224 if pg_if not in self.pg_not_in_vrf:
225 self.pg_not_in_vrf.append(pg_if)
226 self.logger.info("IPv4 VRF ID %d reset finished" % vrf_id)
227 self.logger.debug(self.vapi.ppcli("show ip fib"))
228 self.logger.debug(self.vapi.ppcli("show ip arp"))
229 self.vapi.ip_table_add_del(is_add=0, table_id=vrf_id)
231 def create_stream(self, src_if, packet_sizes):
233 Create input packet stream for defined interface using hosts list.
235 :param object src_if: Interface to create packet stream for.
236 :param list packet_sizes: List of required packet sizes.
237 :return: Stream of packets.
240 src_hosts = src_if.remote_hosts
241 for dst_if in self.flows[src_if]:
242 for dst_host in dst_if.remote_hosts:
243 src_host = random.choice(src_hosts)
244 pkt_info = self.create_packet_info(src_if, dst_if)
245 payload = self.info_to_payload(pkt_info)
246 p = (Ether(dst=src_if.local_mac, src=src_host.mac) /
247 IP(src=src_host.ip4, dst=dst_host.ip4) /
248 UDP(sport=1234, dport=1234) /
250 pkt_info.data = p.copy()
251 size = random.choice(packet_sizes)
252 self.extend_packet(p, size)
254 self.logger.debug("Input stream created for port %s. Length: %u pkt(s)"
255 % (src_if.name, len(pkts)))
258 def create_stream_crosswise_vrf(self, src_if, vrf_id, packet_sizes):
260 Create input packet stream for negative test for leaking across
261 different VRFs for defined interface using hosts list.
263 :param object src_if: Interface to create packet stream for.
264 :param int vrf_id: The FIB table / VRF ID where src_if is assigned.
265 :param list packet_sizes: List of required packet sizes.
266 :return: Stream of packets.
269 src_hosts = src_if.remote_hosts
270 vrf_lst = list(self.vrf_list)
271 vrf_lst.remove(vrf_id)
273 for dst_if in self.pg_if_by_vrf_id[vrf]:
274 for dst_host in dst_if.remote_hosts:
275 src_host = random.choice(src_hosts)
276 pkt_info = self.create_packet_info(src_if, dst_if)
277 payload = self.info_to_payload(pkt_info)
278 p = (Ether(dst=src_if.local_mac, src=src_host.mac) /
279 IP(src=src_host.ip4, dst=dst_host.ip4) /
280 UDP(sport=1234, dport=1234) /
282 pkt_info.data = p.copy()
283 size = random.choice(packet_sizes)
284 self.extend_packet(p, size)
286 self.logger.debug("Input stream created for port %s. Length: %u pkt(s)"
287 % (src_if.name, len(pkts)))
290 def verify_capture(self, pg_if, capture):
292 Verify captured input packet stream for defined interface.
294 :param object pg_if: Interface to verify captured packet stream for.
295 :param list capture: Captured packet stream.
298 for i in self.pg_interfaces:
299 last_info[i.sw_if_index] = None
300 dst_sw_if_index = pg_if.sw_if_index
301 for packet in capture:
305 payload_info = self.payload_to_info(packet[Raw])
306 packet_index = payload_info.index
307 self.assertEqual(payload_info.dst, dst_sw_if_index)
308 self.logger.debug("Got packet on port %s: src=%u (id=%u)" %
309 (pg_if.name, payload_info.src, packet_index))
310 next_info = self.get_next_packet_info_for_interface2(
311 payload_info.src, dst_sw_if_index,
312 last_info[payload_info.src])
313 last_info[payload_info.src] = next_info
314 self.assertIsNotNone(next_info)
315 self.assertEqual(packet_index, next_info.index)
316 saved_packet = next_info.data
317 # Check standard fields
318 self.assertEqual(ip.src, saved_packet[IP].src)
319 self.assertEqual(ip.dst, saved_packet[IP].dst)
320 self.assertEqual(udp.sport, saved_packet[UDP].sport)
321 self.assertEqual(udp.dport, saved_packet[UDP].dport)
323 self.logger.error(ppp("Unexpected or invalid packet:", packet))
325 for i in self.pg_interfaces:
326 remaining_packet = self.get_next_packet_info_for_interface2(
327 i, dst_sw_if_index, last_info[i.sw_if_index])
330 "Port %u: Packet expected from source %u didn't arrive" %
331 (dst_sw_if_index, i.sw_if_index))
333 def verify_vrf(self, vrf_id):
335 Check if the FIB table / VRF ID is configured.
337 :param int vrf_id: The FIB table / VRF ID to be verified.
338 :return: 1 if the FIB table / VRF ID is configured, otherwise return 0.
340 ip_fib_dump = self.vapi.ip_route_dump(vrf_id)
341 vrf_exist = len(ip_fib_dump)
343 for ip_fib_details in ip_fib_dump:
344 addr = ip_fib_details.route.prefix.network_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) == host.ip4:
354 for host in pg_if.remote_hosts:
355 if scapy.compat.raw(addr) == \
356 scapy.compat.raw(host.ip4):
360 if not vrf_exist and vrf_count == 0:
361 self.logger.info("IPv4 VRF ID %d is not configured" % vrf_id)
362 return VRFState.not_configured
363 elif vrf_exist and vrf_count == 0:
364 self.logger.info("IPv4 VRF ID %d has been reset" % vrf_id)
365 return VRFState.reset
367 self.logger.info("IPv4 VRF ID %d is configured" % vrf_id)
368 return VRFState.configured
370 def run_verify_test(self):
372 Create packet streams for all configured pg interfaces, send all \
373 prepared packet streams and verify that:
374 - all packets received correctly on all pg-ip4 interfaces assigned
376 - no packet received on all pg-ip4 interfaces not assigned to VRFs
378 :raise RuntimeError: If no packet captured on pg-ip4 interface assigned
379 to VRF or if any packet is captured on pg-ip4 interface not
383 # Create incoming packet streams for packet-generator interfaces
384 for pg_if in self.pg_interfaces:
385 pkts = self.create_stream(pg_if, self.pg_if_packet_sizes)
386 pg_if.add_stream(pkts)
388 # Enable packet capture and start packet sending
389 self.pg_enable_capture(self.pg_interfaces)
393 # Verify outgoing packet streams per packet-generator interface
394 for pg_if in self.pg_interfaces:
395 if pg_if in self.pg_in_vrf:
396 capture = pg_if.get_capture(remark="interface is in VRF")
397 self.verify_capture(pg_if, capture)
398 elif pg_if in self.pg_not_in_vrf:
399 pg_if.assert_nothing_captured(remark="interface is not in VRF",
400 filter_out_fn=is_ipv4_misc)
401 self.logger.debug("No capture for interface %s" % pg_if.name)
403 raise Exception("Unknown interface: %s" % pg_if.name)
405 def run_crosswise_vrf_test(self):
407 Create packet streams for every pg-ip4 interface in VRF towards all
408 pg-ip4 interfaces in other VRFs, send all prepared packet streams and \
410 - no packet received on all configured pg-ip4 interfaces
412 :raise RuntimeError: If any packet is captured on any pg-ip4 interface.
415 # Create incoming packet streams for packet-generator interfaces
416 for vrf_id in self.vrf_list:
417 for pg_if in self.pg_if_by_vrf_id[vrf_id]:
418 pkts = self.create_stream_crosswise_vrf(
419 pg_if, vrf_id, self.pg_if_packet_sizes)
420 pg_if.add_stream(pkts)
422 # Enable packet capture and start packet sending
423 self.pg_enable_capture(self.pg_interfaces)
427 # Verify outgoing packet streams per packet-generator interface
428 for pg_if in self.pg_interfaces:
429 pg_if.assert_nothing_captured(remark="interface is in other VRF",
430 filter_out_fn=is_ipv4_misc)
431 self.logger.debug("No capture for interface %s" % pg_if.name)
433 def test_ip4_vrf_01(self):
434 """ IP4 VRF Multi-instance test 1 - create 4 VRFs
438 self.create_vrf_and_assign_interfaces(4)
441 for vrf_id in self.vrf_list:
442 self.assert_equal(self.verify_vrf(vrf_id),
443 VRFState.configured, VRFState)
446 self.run_verify_test()
447 self.run_crosswise_vrf_test()
449 def test_ip4_vrf_02(self):
450 """ IP4 VRF Multi-instance test 2 - reset 2 VRFs
454 self.reset_vrf_and_remove_from_vrf_list(1)
455 self.reset_vrf_and_remove_from_vrf_list(2)
458 for vrf_id in self.vrf_reset_list:
459 self.assert_equal(self.verify_vrf(vrf_id),
460 VRFState.reset, VRFState)
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_03(self):
470 """ IP4 VRF Multi-instance 3 - add 2 VRFs
473 # Add 1 of reset VRFs and 1 new VRF
474 self.create_vrf_and_assign_interfaces(1)
475 self.create_vrf_and_assign_interfaces(1, start=5)
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_04(self):
490 """ IP4 VRF Multi-instance test 4 - reset 4 VRFs
493 # Reset all VRFs (i.e. no VRF except VRF=0 configured)
494 for i in range(len(self.vrf_list)):
495 self.reset_vrf_and_remove_from_vrf_list(self.vrf_list[0])
498 for vrf_id in self.vrf_reset_list:
499 self.assert_equal(self.verify_vrf(vrf_id),
500 VRFState.reset, VRFState)
501 vrf_list_length = len(self.vrf_list)
504 "List of configured VRFs is not empty: %s != 0" % vrf_list_length)
507 self.run_verify_test()
508 self.run_crosswise_vrf_test()
511 if __name__ == '__main__':
512 unittest.main(testRunner=VppTestRunner)