2 """IP6 VRF Multi-instance Test Case HLD:
5 - higher number of pg-ip6 interfaces causes problems => only 15 pg-ip6 \
6 interfaces in 5 VRFs are tested
7 - jumbo packets in configuration with 15 pg-ip6 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-ip6 interfaces
15 - configure 5 hosts per pg-ip6 interface
17 - add 3 pg-ip6 interfaces per VRF
20 - send IP6 packets between all pg-ip6 interfaces in all VRF groups
23 - check VRF data by parsing output of ip6_fib_dump API command
24 - all packets received correctly in case of pg-ip6 interfaces in VRF
25 - no packet received in case of pg-ip6 interfaces not in VRF
31 - send IP6 packets between all pg-ip6 interfaces in all VRF groups
34 - check VRF data by parsing output of ip6_fib_dump API command
35 - all packets received correctly in case of pg-ip6 interfaces in VRF
36 - no packet received in case of pg-ip6 interfaces not in VRF
39 - add 1 of deleted VRFs and 1 new VRF
42 - send IP6 packets between all pg-ip6 interfaces in all VRF groups
45 - check VRF data by parsing output of ip6_fib_dump API command
46 - all packets received correctly in case of pg-ip6 interfaces in VRF
47 - no packet received in case of pg-ip6 interfaces not in VRF
50 - delete all VRFs (i.e. no VRF except VRF=0 created)
53 - send IP6 packets between all pg-ip6 interfaces in all VRF groups
56 - check VRF data by parsing output of ip6_fib_dump API command
57 - all packets received correctly in case of pg-ip6 interfaces in VRF
58 - no packet received in case of pg-ip6 interfaces not in VRF
64 from scapy.packet import Raw
65 from scapy.layers.l2 import Ether
66 from scapy.layers.inet6 import IPv6, UDP
68 from framework import VppTestCase, VppTestRunner
72 class TestIP6VrfMultiInst(VppTestCase):
73 """ IP6 VRF Multi-instance Test Case """
78 Perform standard class setup (defined by class method setUpClass in
79 class VppTestCase) before running the test case, set test case related
80 variables and configure VPP.
82 super(TestIP6VrfMultiInst, cls).setUpClass()
87 cls.pg_ifs_per_vrf = 3
90 # Create pg interfaces
91 cls.create_pg_interfaces(
92 range(cls.nr_of_vrfs * cls.pg_ifs_per_vrf))
94 # Packet flows mapping pg0 -> pg1, pg2 etc.
96 for i in range(len(cls.pg_interfaces)):
97 multiplicand = i / cls.pg_ifs_per_vrf
99 cls.pg_interfaces[multiplicand * cls.pg_ifs_per_vrf + j]
100 for j in range(cls.pg_ifs_per_vrf)
101 if (multiplicand * cls.pg_ifs_per_vrf + j) != i]
102 cls.flows[cls.pg_interfaces[i]] = pg_list
104 # Packet sizes - jumbo packet (9018 bytes) skipped
105 cls.pg_if_packet_sizes = [64, 512, 1518]
107 # Set up all interfaces
108 for pg_if in cls.pg_interfaces:
110 pg_if.generate_remote_hosts(cls.hosts_per_pg)
112 # Create list of VRFs
113 cls.vrf_list = list()
115 # Create list of deleted VRFs
116 cls.vrf_deleted_list = list()
118 # Create list of pg_interfaces in VRFs
119 cls.pg_in_vrf = list()
121 # Create list of pg_interfaces not in BDs
122 cls.pg_not_in_vrf = [pg_if for pg_if in cls.pg_interfaces]
124 # Create mapping of pg_interfaces to VRF IDs
125 cls.pg_if_by_vrf_id = dict()
126 for i in range(cls.nr_of_vrfs):
129 cls.pg_interfaces[i * cls.pg_ifs_per_vrf + j]
130 for j in range(cls.pg_ifs_per_vrf)]
131 cls.pg_if_by_vrf_id[vrf_id] = pg_list
134 super(TestIP6VrfMultiInst, cls).tearDownClass()
139 Clear trace and packet infos before running each test.
141 super(TestIP6VrfMultiInst, self).setUp()
142 self.reset_packet_infos()
146 Show various debug prints after each test.
148 super(TestIP6VrfMultiInst, self).tearDown()
149 if not self.vpp_dead:
150 self.logger.info(self.vapi.ppcli("show ip6 fib"))
151 self.logger.info(self.vapi.ppcli("show ip6 neighbors"))
153 def create_vrf_and_assign_interfaces(self, count, start=1):
155 Create required number of FIB tables / VRFs, put 3 l2-pg interfaces
156 to every FIB table / VRF.
158 :param int count: Number of FIB tables / VRFs to be created.
159 :param int start: Starting number of the FIB table / VRF ID. \
162 for i in range(count):
164 pg_if = self.pg_if_by_vrf_id[vrf_id][0]
165 dest_addr = pg_if.remote_hosts[0].ip6n
167 self.vapi.ip_add_del_route(
168 dest_addr, dest_addr_len, pg_if.local_ip6n, is_ipv6=1,
169 table_id=vrf_id, create_vrf_if_needed=1, is_multipath=1)
170 self.logger.info("IPv6 VRF ID %d created" % vrf_id)
171 if vrf_id not in self.vrf_list:
172 self.vrf_list.append(vrf_id)
173 if vrf_id in self.vrf_deleted_list:
174 self.vrf_deleted_list.remove(vrf_id)
175 for j in range(self.pg_ifs_per_vrf):
176 pg_if = self.pg_if_by_vrf_id[vrf_id][j]
177 pg_if.set_table_ip6(vrf_id)
178 self.logger.info("pg-interface %s added to IPv6 VRF ID %d"
179 % (pg_if.name, vrf_id))
180 if pg_if not in self.pg_in_vrf:
181 self.pg_in_vrf.append(pg_if)
182 if pg_if in self.pg_not_in_vrf:
183 self.pg_not_in_vrf.remove(pg_if)
185 pg_if.disable_ipv6_ra()
186 pg_if.configure_ipv6_neighbors(vrf_id)
187 self.logger.debug(self.vapi.ppcli("show ip6 fib"))
188 self.logger.debug(self.vapi.ppcli("show ip6 neighbors"))
190 def reset_vrf(self, vrf_id):
192 Delete required FIB table / VRF.
194 :param int vrf_id: The FIB table / VRF ID to be deleted.
196 # self.vapi.reset_vrf(vrf_id, is_ipv6=1)
197 self.vapi.reset_fib(vrf_id, is_ipv6=1)
198 if vrf_id in self.vrf_list:
199 self.vrf_list.remove(vrf_id)
200 if vrf_id not in self.vrf_deleted_list:
201 self.vrf_deleted_list.append(vrf_id)
202 for j in range(self.pg_ifs_per_vrf):
203 pg_if = self.pg_if_by_vrf_id[vrf_id][j]
204 if pg_if in self.pg_in_vrf:
205 self.pg_in_vrf.remove(pg_if)
206 if pg_if not in self.pg_not_in_vrf:
207 self.pg_not_in_vrf.append(pg_if)
208 self.logger.info("IPv6 VRF ID %d reset" % vrf_id)
209 self.logger.debug(self.vapi.ppcli("show ip6 fib"))
210 self.logger.debug(self.vapi.ppcli("show ip6 neighbors"))
212 def create_stream(self, src_if, packet_sizes):
214 Create input packet stream for defined interface using hosts list.
216 :param object src_if: Interface to create packet stream for.
217 :param list packet_sizes: List of required packet sizes.
218 :return: Stream of packets.
221 src_hosts = src_if.remote_hosts
222 for dst_if in self.flows[src_if]:
223 for dst_host in dst_if.remote_hosts:
224 src_host = random.choice(src_hosts)
225 pkt_info = self.create_packet_info(src_if, dst_if)
226 payload = self.info_to_payload(pkt_info)
227 p = (Ether(dst=src_if.local_mac, src=src_host.mac) /
228 IPv6(src=src_host.ip6, dst=dst_host.ip6) /
229 UDP(sport=1234, dport=1234) /
231 pkt_info.data = p.copy()
232 size = random.choice(packet_sizes)
233 self.extend_packet(p, size)
235 self.logger.debug("Input stream created for port %s. Length: %u pkt(s)"
236 % (src_if.name, len(pkts)))
239 def verify_capture(self, pg_if, capture):
241 Verify captured input packet stream for defined interface.
243 :param object pg_if: Interface to verify captured packet stream for.
244 :param list capture: Captured packet stream.
247 for i in self.pg_interfaces:
248 last_info[i.sw_if_index] = None
249 dst_sw_if_index = pg_if.sw_if_index
250 for packet in capture:
254 payload_info = self.payload_to_info(str(packet[Raw]))
255 packet_index = payload_info.index
256 self.assertEqual(payload_info.dst, dst_sw_if_index)
257 self.logger.debug("Got packet on port %s: src=%u (id=%u)" %
258 (pg_if.name, payload_info.src, packet_index))
259 next_info = self.get_next_packet_info_for_interface2(
260 payload_info.src, dst_sw_if_index,
261 last_info[payload_info.src])
262 last_info[payload_info.src] = next_info
263 self.assertIsNotNone(next_info)
264 self.assertEqual(packet_index, next_info.index)
265 saved_packet = next_info.data
266 # Check standard fields
267 self.assertEqual(ip.src, saved_packet[IPv6].src)
268 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
269 self.assertEqual(udp.sport, saved_packet[UDP].sport)
270 self.assertEqual(udp.dport, saved_packet[UDP].dport)
272 self.logger.error(ppp("Unexpected or invalid packet:", packet))
274 for i in self.pg_interfaces:
275 remaining_packet = self.get_next_packet_info_for_interface2(
276 i, dst_sw_if_index, last_info[i.sw_if_index])
279 "Port %u: Packet expected from source %u didn't arrive" %
280 (dst_sw_if_index, i.sw_if_index))
282 def verify_vrf(self, vrf_id):
284 Check if the FIB table / VRF ID is configured.
286 :param int vrf_id: The FIB table / VRF ID to be verified.
287 :return: 1 if the FIB table / VRF ID is configured, otherwise return 0.
289 ip6_fib_dump = self.vapi.ip6_fib_dump()
291 for ip6_fib_details in ip6_fib_dump:
292 if ip6_fib_details[2] == vrf_id:
295 self.logger.info("IPv6 VRF ID %d is not configured" % vrf_id)
298 self.logger.info("IPv6 VRF ID %d is configured" % vrf_id)
301 def run_verify_test(self):
303 Create packet streams for all configured l2-pg interfaces, send all \
304 prepared packet streams and verify that:
305 - all packets received correctly on all pg-l2 interfaces assigned
307 - no packet received on all pg-l2 interfaces not assigned to bridge
310 :raise RuntimeError: If no packet captured on l2-pg interface assigned
311 to the bridge domain or if any packet is captured on l2-pg
312 interface not assigned to the bridge domain.
315 # Create incoming packet streams for packet-generator interfaces
316 for pg_if in self.pg_interfaces:
317 pkts = self.create_stream(pg_if, self.pg_if_packet_sizes)
318 pg_if.add_stream(pkts)
320 # Enable packet capture and start packet sending
321 self.pg_enable_capture(self.pg_interfaces)
325 # Verify outgoing packet streams per packet-generator interface
326 for pg_if in self.pg_interfaces:
327 if pg_if in self.pg_in_vrf:
328 capture = pg_if.get_capture(remark="interface is in VRF")
329 self.verify_capture(pg_if, capture)
330 elif pg_if in self.pg_not_in_vrf:
331 pg_if.assert_nothing_captured(remark="interface is not in VRF")
332 self.logger.debug("No capture for interface %s" % pg_if.name)
334 raise Exception("Unknown interface: %s" % pg_if.name)
336 def test_ip6_vrf_01(self):
337 """ IP6 VRF Multi-instance test 1 - create 4 VRFs
341 self.create_vrf_and_assign_interfaces(4)
344 for vrf_id in self.vrf_list:
345 self.assertEqual(self.verify_vrf(vrf_id), 1)
348 self.run_verify_test()
350 @unittest.skip("IPv6 FIB reset leads to crash of VPP - Jira ticket "
351 "https://jira.fd.io/browse/VPP-643")
352 def test_ip6_vrf_02(self):
353 """ IP6 VRF Multi-instance test 2 - reset 2 VRFs
361 # for vrf_id in self.vrf_deleted_list:
362 # self.assertEqual(self.verify_vrf(vrf_id), 0)
363 for vrf_id in self.vrf_list:
364 self.assertEqual(self.verify_vrf(vrf_id), 1)
367 self.run_verify_test()
369 def test_ip6_vrf_03(self):
370 """ IP6 VRF Multi-instance 3 - add 2 VRFs
373 # Add 1 of deleted VRFs and 1 new VRF
374 # self.create_vrf_and_assign_interfaces(1)
375 self.create_vrf_and_assign_interfaces(1, start=5)
378 # for vrf_id in self.vrf_deleted_list:
379 # self.assertEqual(self.verify_vrf(vrf_id), 0)
380 for vrf_id in self.vrf_list:
381 self.assertEqual(self.verify_vrf(vrf_id), 1)
384 self.run_verify_test()
386 @unittest.skip("IPv6 FIB reset leads to crash of VPP - Jira ticket "
387 "https://jira.fd.io/browse/VPP-643")
388 def test_ip6_vrf_04(self):
389 """ IP6 VRF Multi-instance test 4 - reset 4 VRFs
392 # Delete all VRFs (i.e. no VRF except VRF=0 created)
393 for i in range(len(self.vrf_list)):
394 self.reset_vrf(self.vrf_list[0])
397 # for vrf_id in self.vrf_deleted_list:
398 # self.assertEqual(self.verify_vrf(vrf_id), 0)
399 for vrf_id in self.vrf_list:
400 self.assertEqual(self.verify_vrf(vrf_id), 1)
403 self.run_verify_test()
406 if __name__ == '__main__':
407 unittest.main(testRunner=VppTestRunner)