vlib: improvement to automatic core pinning
[vpp.git] / test / test_ip6_vrf_multi_instance.py
1 #!/usr/bin/env python3
2 """IP6 VRF Multi-instance Test Case HLD:
3
4 **NOTES:**
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 \
8       problems too
9
10 **config 1**
11     - add 15 pg-ip6 interfaces
12     - configure 5 hosts per pg-ip6 interface
13     - configure 4 VRFs
14     - add 3 pg-ip6 interfaces per VRF
15
16 **test 1**
17     - send IP6 packets between all pg-ip6 interfaces in all VRF groups
18
19 **verify 1**
20     - check VRF data by parsing output of ip_route_dump API command
21     - all packets received correctly in case of pg-ip6 interfaces in the
22       same VRF
23     - no packet received in case of pg-ip6 interfaces not in VRF
24     - no packet received in case of pg-ip6 interfaces in different VRFs
25
26 **config 2**
27     - reset 2 VRFs
28
29 **test 2**
30     - send IP6 packets between all pg-ip6 interfaces in all VRF groups
31
32 **verify 2**
33     - check VRF data by parsing output of ip_route_dump API command
34     - all packets received correctly in case of pg-ip6 interfaces in the
35       same VRF
36     - no packet received in case of pg-ip6 interfaces not in VRF
37     - no packet received in case of pg-ip6 interfaces in different VRFs
38
39 **config 3**
40     - add 1 of reset VRFs and 1 new VRF
41
42 **test 3**
43     - send IP6 packets between all pg-ip6 interfaces in all VRF groups
44
45 **verify 3**
46     - check VRF data by parsing output of ip_route_dump API command
47     - all packets received correctly in case of pg-ip6 interfaces in the
48       same VRF
49     - no packet received in case of pg-ip6 interfaces not in VRF
50     - no packet received in case of pg-ip6 interfaces in different VRFs
51
52 **config 4**
53     - reset all VRFs (i.e. no VRF except VRF=0 created)
54
55 **test 4**
56     - send IP6 packets between all pg-ip6 interfaces in all VRF groups
57
58 **verify 4**
59     - check VRF data by parsing output of ip_route_dump API command
60     - all packets received correctly in case of pg-ip6 interfaces in the
61       same VRF
62     - no packet received in case of pg-ip6 interfaces not in VRF
63     - no packet received in case of pg-ip6 interfaces in different VRFs
64 """
65
66 import unittest
67 import random
68
69 from scapy.packet import Raw
70 from scapy.layers.l2 import Ether
71 from scapy.layers.inet6 import (
72     UDP,
73     IPv6,
74     ICMPv6ND_NS,
75     ICMPv6ND_RA,
76     RouterAlert,
77     IPv6ExtHdrHopByHop,
78 )
79 from scapy.utils6 import in6_ismaddr, in6_isllsnmaddr
80
81 from framework import VppTestCase
82 from asfframework import VppTestRunner
83 from util import ppp
84 from vrf import VRFState
85
86
87 def is_ipv6_misc_ext(p):
88     """Is packet one of uninteresting IPv6 broadcasts (extended to filter out
89     ICMPv6 Neighbor Discovery - Neighbor Advertisement packets too)?"""
90     if p.haslayer(ICMPv6ND_RA):
91         if in6_ismaddr(p[IPv6].dst):
92             return True
93     if p.haslayer(ICMPv6ND_NS):
94         if in6_isllsnmaddr(p[IPv6].dst):
95             return True
96     if p.haslayer(IPv6ExtHdrHopByHop):
97         for o in p[IPv6ExtHdrHopByHop].options:
98             if isinstance(o, RouterAlert):
99                 return True
100     return False
101
102
103 class TestIP6VrfMultiInst(VppTestCase):
104     """IP6 VRF  Multi-instance Test Case"""
105
106     @classmethod
107     def setUpClass(cls):
108         """
109         Perform standard class setup (defined by class method setUpClass in
110         class VppTestCase) before running the test case, set test case related
111         variables and configure VPP.
112         """
113         super(TestIP6VrfMultiInst, cls).setUpClass()
114
115         # Test variables
116         cls.hosts_per_pg = 5
117         cls.nr_of_vrfs = 5
118         cls.pg_ifs_per_vrf = 3
119
120         try:
121             # Create pg interfaces
122             cls.create_pg_interfaces(range(cls.nr_of_vrfs * cls.pg_ifs_per_vrf))
123
124             # Packet flows mapping pg0 -> pg1, pg2 etc.
125             cls.flows = dict()
126             for i in range(len(cls.pg_interfaces)):
127                 multiplicand = i // cls.pg_ifs_per_vrf
128                 pg_list = [
129                     cls.pg_interfaces[multiplicand * cls.pg_ifs_per_vrf + j]
130                     for j in range(cls.pg_ifs_per_vrf)
131                     if (multiplicand * cls.pg_ifs_per_vrf + j) != i
132                 ]
133                 cls.flows[cls.pg_interfaces[i]] = pg_list
134
135             # Packet sizes - jumbo packet (9018 bytes) skipped
136             cls.pg_if_packet_sizes = [64, 512, 1518]
137
138             # Set up all interfaces
139             for pg_if in cls.pg_interfaces:
140                 pg_if.admin_up()
141                 pg_if.generate_remote_hosts(cls.hosts_per_pg)
142
143             # Create list of VRFs
144             cls.vrf_list = list()
145
146             # Create list of reset VRFs
147             cls.vrf_reset_list = list()
148
149             # Create list of pg_interfaces in VRFs
150             cls.pg_in_vrf = list()
151
152             # Create list of pg_interfaces not in VRFs
153             cls.pg_not_in_vrf = [pg_if for pg_if in cls.pg_interfaces]
154
155             # Create mapping of pg_interfaces to VRF IDs
156             cls.pg_if_sets = dict()
157             for i in range(cls.nr_of_vrfs):
158                 set_id = i + 1
159                 pg_list = [
160                     cls.pg_interfaces[i * cls.pg_ifs_per_vrf + j]
161                     for j in range(cls.pg_ifs_per_vrf)
162                 ]
163                 cls.pg_if_sets[set_id] = pg_list
164
165         except Exception:
166             super(TestIP6VrfMultiInst, cls).tearDownClass()
167             raise
168
169     @classmethod
170     def tearDownClass(cls):
171         super(TestIP6VrfMultiInst, cls).tearDownClass()
172
173     def setUp(self):
174         """
175         Clear trace and packet infos before running each test.
176         """
177         super(TestIP6VrfMultiInst, self).setUp()
178         self.reset_packet_infos()
179
180     def tearDown(self):
181         """
182         Show various debug prints after each test.
183         """
184         super(TestIP6VrfMultiInst, self).tearDown()
185
186     def show_commands_at_teardown(self):
187         self.logger.info(self.vapi.ppcli("show ip6 fib"))
188         self.logger.info(self.vapi.ppcli("show ip6 neighbors"))
189
190     def _assign_interfaces(self, vrf_id, if_set_id):
191         for i in range(self.pg_ifs_per_vrf):
192             pg_if = self.pg_if_sets[if_set_id][i]
193             pg_if.set_table_ip6(vrf_id)
194             self.logger.info(
195                 "pg-interface %s added to IPv6 VRF ID %d" % (pg_if.name, vrf_id)
196             )
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)
201             pg_if.config_ip6()
202             pg_if.disable_ipv6_ra()
203             pg_if.configure_ipv6_neighbors()
204
205     def create_vrf_and_assign_interfaces(self, count, start=1):
206         """
207         Create required number of FIB tables / VRFs, put 3 pg-ip6 interfaces
208         to every FIB table / VRF.
209
210         :param int count: Number of FIB tables / VRFs to be created.
211         :param int start: Starting number of the FIB table / VRF ID. \
212         (Default value = 1)
213         """
214         for i in range(count):
215             vrf_id = i + start
216             self.vapi.ip_table_add_del(
217                 is_add=1, table={"table_id": vrf_id, "is_ip6": 1}
218             )
219             self.logger.info("IPv6 VRF ID %d created" % vrf_id)
220             if vrf_id not in self.vrf_list:
221                 self.vrf_list.append(vrf_id)
222             if vrf_id in self.vrf_reset_list:
223                 self.vrf_reset_list.remove(vrf_id)
224             self._assign_interfaces(vrf_id, vrf_id)
225         self.logger.debug(self.vapi.ppcli("show ip6 fib"))
226         self.logger.debug(self.vapi.ppcli("show ip6 neighbors"))
227
228     def create_vrf_by_id_and_assign_interfaces(self, set_id, vrf_id=0xFFFFFFFF):
229         """
230         Create a FIB table / VRF by vrf_id, put 3 pg-ip6 interfaces
231         to FIB table / VRF.
232
233         :param int vrf_id: Required table ID / VRF ID. \
234         (Default value = 0xffffffff, ID will be selected automatically)
235         """
236         ret = self.vapi.ip_table_allocate(table={"table_id": vrf_id, "is_ip6": 1})
237         vrf_id = ret.table.table_id
238         self.logger.info("IPv6 VRF ID %d created" % vrf_id)
239         if vrf_id not in self.vrf_list:
240             self.vrf_list.append(vrf_id)
241         if vrf_id in self.vrf_reset_list:
242             self.vrf_reset_list.remove(vrf_id)
243         self._assign_interfaces(vrf_id, set_id)
244         self.logger.debug(self.vapi.ppcli("show ip6 fib"))
245         self.logger.debug(self.vapi.ppcli("show ip6 neighbors"))
246
247         return vrf_id
248
249     def reset_vrf_and_remove_from_vrf_list(self, vrf_id, if_set_id=None):
250         """
251         Reset required FIB table / VRF and remove it from VRF list.
252
253         :param int vrf_id: The FIB table / VRF ID to be reset.
254         """
255         if if_set_id is None:
256             if_set_id = vrf_id
257         self.vapi.ip_table_flush(table={"table_id": vrf_id, "is_ip6": 1})
258         if vrf_id in self.vrf_list:
259             self.vrf_list.remove(vrf_id)
260         if vrf_id not in self.vrf_reset_list:
261             self.vrf_reset_list.append(vrf_id)
262         for j in range(self.pg_ifs_per_vrf):
263             pg_if = self.pg_if_sets[if_set_id][j]
264             pg_if.unconfig_ip6()
265             pg_if.set_table_ip6(0)
266             if pg_if in self.pg_in_vrf:
267                 self.pg_in_vrf.remove(pg_if)
268             if pg_if not in self.pg_not_in_vrf:
269                 self.pg_not_in_vrf.append(pg_if)
270         self.logger.info("IPv6 VRF ID %d reset finished" % vrf_id)
271         self.logger.debug(self.vapi.ppcli("show ip6 fib"))
272         self.logger.debug(self.vapi.ppcli("show ip6 neighbors"))
273
274     def delete_vrf(self, vrf_id):
275         if vrf_id in self.vrf_list:
276             self.vrf_list.remove(vrf_id)
277         if vrf_id in self.vrf_reset_list:
278             self.vrf_reset_list.remove(vrf_id)
279         self.vapi.ip_table_add_del(is_add=0, table={"table_id": vrf_id, "is_ip6": 1})
280
281     def create_stream(self, src_if, packet_sizes):
282         """
283         Create input packet stream for defined interface using hosts list.
284
285         :param object src_if: Interface to create packet stream for.
286         :param list packet_sizes: List of required packet sizes.
287         :return: Stream of packets.
288         """
289         pkts = []
290         src_hosts = src_if.remote_hosts
291         for dst_if in self.flows[src_if]:
292             for dst_host in dst_if.remote_hosts:
293                 src_host = random.choice(src_hosts)
294                 pkt_info = self.create_packet_info(src_if, dst_if)
295                 payload = self.info_to_payload(pkt_info)
296                 p = (
297                     Ether(dst=src_if.local_mac, src=src_host.mac)
298                     / IPv6(src=src_host.ip6, dst=dst_host.ip6)
299                     / UDP(sport=1234, dport=1234)
300                     / Raw(payload)
301                 )
302                 pkt_info.data = p.copy()
303                 size = random.choice(packet_sizes)
304                 self.extend_packet(p, size)
305                 pkts.append(p)
306         self.logger.debug(
307             "Input stream created for port %s. Length: %u pkt(s)"
308             % (src_if.name, len(pkts))
309         )
310         return pkts
311
312     def create_stream_crosswise_vrf(self, src_if, vrf_id, packet_sizes):
313         """
314         Create input packet stream for negative test for leaking across
315         different VRFs for defined interface using hosts list.
316
317         :param object src_if: Interface to create packet stream for.
318         :param int vrf_id: The FIB table / VRF ID where src_if is assigned.
319         :param list packet_sizes: List of required packet sizes.
320         :return: Stream of packets.
321         """
322         pkts = []
323         src_hosts = src_if.remote_hosts
324         vrf_lst = list(self.vrf_list)
325         vrf_lst.remove(vrf_id)
326         for vrf in vrf_lst:
327             for dst_if in self.pg_if_sets[vrf]:
328                 for dst_host in dst_if.remote_hosts:
329                     src_host = random.choice(src_hosts)
330                     pkt_info = self.create_packet_info(src_if, dst_if)
331                     payload = self.info_to_payload(pkt_info)
332                     p = (
333                         Ether(dst=src_if.local_mac, src=src_host.mac)
334                         / IPv6(src=src_host.ip6, dst=dst_host.ip6)
335                         / UDP(sport=1234, dport=1234)
336                         / Raw(payload)
337                     )
338                     pkt_info.data = p.copy()
339                     size = random.choice(packet_sizes)
340                     self.extend_packet(p, size)
341                     pkts.append(p)
342         self.logger.debug(
343             "Input stream created for port %s. Length: %u pkt(s)"
344             % (src_if.name, len(pkts))
345         )
346         return pkts
347
348     def verify_capture(self, pg_if, capture):
349         """
350         Verify captured input packet stream for defined interface.
351
352         :param object pg_if: Interface to verify captured packet stream for.
353         :param list capture: Captured packet stream.
354         """
355         last_info = dict()
356         for i in self.pg_interfaces:
357             last_info[i.sw_if_index] = None
358         dst_sw_if_index = pg_if.sw_if_index
359         for packet in capture:
360             try:
361                 ip = packet[IPv6]
362                 udp = packet[UDP]
363                 payload_info = self.payload_to_info(packet[Raw])
364                 packet_index = payload_info.index
365                 self.assertEqual(payload_info.dst, dst_sw_if_index)
366                 self.logger.debug(
367                     "Got packet on port %s: src=%u (id=%u)"
368                     % (pg_if.name, payload_info.src, packet_index)
369                 )
370                 next_info = self.get_next_packet_info_for_interface2(
371                     payload_info.src, dst_sw_if_index, last_info[payload_info.src]
372                 )
373                 last_info[payload_info.src] = next_info
374                 self.assertIsNotNone(next_info)
375                 self.assertEqual(packet_index, next_info.index)
376                 saved_packet = next_info.data
377                 # Check standard fields
378                 self.assertEqual(ip.src, saved_packet[IPv6].src)
379                 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
380                 self.assertEqual(udp.sport, saved_packet[UDP].sport)
381                 self.assertEqual(udp.dport, saved_packet[UDP].dport)
382             except:
383                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
384                 raise
385         for i in self.pg_interfaces:
386             remaining_packet = self.get_next_packet_info_for_interface2(
387                 i, dst_sw_if_index, last_info[i.sw_if_index]
388             )
389             self.assertIsNone(
390                 remaining_packet,
391                 "Port %u: Packet expected from source %u didn't arrive"
392                 % (dst_sw_if_index, i.sw_if_index),
393             )
394
395     def verify_vrf(self, vrf_id, if_set_id=None):
396         """
397         Check if the FIB table / VRF ID is configured.
398
399         :param int vrf_id: The FIB table / VRF ID to be verified.
400         :return: 1 if the FIB table / VRF ID is configured, otherwise return 0.
401         """
402         if if_set_id is None:
403             if_set_id = vrf_id
404         ip6_fib_dump = self.vapi.ip_route_dump(vrf_id, True)
405         vrf_exist = len(ip6_fib_dump)
406         vrf_count = 0
407         for ip6_fib_details in ip6_fib_dump:
408             addr = ip6_fib_details.route.prefix.network_address
409             found = False
410             for pg_if in self.pg_if_sets[if_set_id]:
411                 if found:
412                     break
413                 for host in pg_if.remote_hosts:
414                     if str(addr) == host.ip6:
415                         vrf_count += 1
416                         found = True
417                         break
418         if not vrf_exist and vrf_count == 0:
419             self.logger.info("IPv6 VRF ID %d is not configured" % vrf_id)
420             return VRFState.not_configured
421         elif vrf_exist and vrf_count == 0:
422             self.logger.info("IPv6 VRF ID %d has been reset" % vrf_id)
423             return VRFState.reset
424         else:
425             self.logger.info("IPv6 VRF ID %d is configured" % vrf_id)
426             return VRFState.configured
427
428     def run_verify_test(self):
429         """
430         Create packet streams for all configured pg interfaces, send all \
431         prepared packet streams and verify that:
432             - all packets received correctly on all pg-ip6 interfaces assigned
433               to VRFs
434             - no packet received on all pg-ip6 interfaces not assigned to VRFs
435
436         :raise RuntimeError: If no packet captured on pg-ip6 interface assigned
437             to VRF or if any packet is captured on pg-ip6 interface not
438             assigned to VRF.
439         """
440         # Test
441         # Create incoming packet streams for packet-generator interfaces
442         for pg_if in self.pg_interfaces:
443             pkts = self.create_stream(pg_if, self.pg_if_packet_sizes)
444             pg_if.add_stream(pkts)
445
446         # Enable packet capture and start packet sending
447         self.pg_enable_capture(self.pg_interfaces)
448         self.pg_start()
449
450         # Verify
451         # Verify outgoing packet streams per packet-generator interface
452         for pg_if in self.pg_interfaces:
453             if pg_if in self.pg_in_vrf:
454                 capture = pg_if.get_capture(remark="interface is in VRF")
455                 self.verify_capture(pg_if, capture)
456             elif pg_if in self.pg_not_in_vrf:
457                 pg_if.assert_nothing_captured(
458                     remark="interface is not in VRF", filter_out_fn=is_ipv6_misc_ext
459                 )
460                 self.logger.debug("No capture for interface %s" % pg_if.name)
461             else:
462                 raise Exception("Unknown interface: %s" % pg_if.name)
463
464     def run_crosswise_vrf_test(self):
465         """
466         Create packet streams for every pg-ip6 interface in VRF towards all
467         pg-ip6 interfaces in other VRFs, send all prepared packet streams and
468         verify that:
469
470         - no packet received on all configured pg-ip6 interfaces
471
472         :raise RuntimeError: If any packet is captured on any pg-ip6 interface.
473         """
474         # Test
475         # Create incoming packet streams for packet-generator interfaces
476         for vrf_id in self.vrf_list:
477             for pg_if in self.pg_if_sets[vrf_id]:
478                 pkts = self.create_stream_crosswise_vrf(
479                     pg_if, vrf_id, self.pg_if_packet_sizes
480                 )
481                 pg_if.add_stream(pkts)
482
483         # Enable packet capture and start packet sending
484         self.pg_enable_capture(self.pg_interfaces)
485         self.pg_start()
486
487         # Verify
488         # Verify outgoing packet streams per packet-generator interface
489         for pg_if in self.pg_interfaces:
490             pg_if.assert_nothing_captured(
491                 remark="interface is in other VRF", filter_out_fn=is_ipv6_misc_ext
492             )
493             self.logger.debug("No capture for interface %s" % pg_if.name)
494
495     def test_ip6_vrf_01(self):
496         """IP6 VRF  Multi-instance test 1 - create 4 VRFs"""
497         # Config 1
498         # Create 4 VRFs
499         self.create_vrf_and_assign_interfaces(4)
500
501         # Verify 1
502         for vrf_id in self.vrf_list:
503             self.assert_equal(self.verify_vrf(vrf_id), VRFState.configured, VRFState)
504
505         # Test 1
506         self.run_verify_test()
507         self.run_crosswise_vrf_test()
508
509     def test_ip6_vrf_02(self):
510         """IP6 VRF  Multi-instance test 2 - reset 2 VRFs"""
511         # Config 2
512         # Delete 2 VRFs
513         self.reset_vrf_and_remove_from_vrf_list(1)
514         self.reset_vrf_and_remove_from_vrf_list(2)
515
516         # Verify 2
517         for vrf_id in self.vrf_reset_list:
518             self.assert_equal(self.verify_vrf(vrf_id), VRFState.reset, VRFState)
519         for vrf_id in self.vrf_list:
520             self.assert_equal(self.verify_vrf(vrf_id), VRFState.configured, VRFState)
521
522         # Test 2
523         self.run_verify_test()
524         self.run_crosswise_vrf_test()
525
526         # Reset routes learned from ICMPv6 Neighbor Discovery
527         # for vrf_id in self.vrf_reset_list:
528         #     self.reset_vrf_and_remove_from_vrf_list(vrf_id)
529
530     def test_ip6_vrf_03(self):
531         """IP6 VRF  Multi-instance 3 - add 2 VRFs"""
532         # Config 3
533         # Add 1 of reset VRFs and 1 new VRF
534         self.create_vrf_and_assign_interfaces(1)
535         self.create_vrf_and_assign_interfaces(1, start=5)
536
537         # Verify 3
538         for vrf_id in self.vrf_reset_list:
539             self.assert_equal(self.verify_vrf(vrf_id), VRFState.reset, VRFState)
540         for vrf_id in self.vrf_list:
541             self.assert_equal(self.verify_vrf(vrf_id), VRFState.configured, VRFState)
542
543         # Test 3
544         self.run_verify_test()
545         self.run_crosswise_vrf_test()
546
547         # Reset routes learned from ICMPv6 Neighbor Discovery
548         # for vrf_id in self.vrf_reset_list:
549         #     self.reset_vrf_and_remove_from_vrf_list(vrf_id)
550
551     def test_ip6_vrf_04(self):
552         """IP6 VRF  Multi-instance test 4 - reset 4 VRFs"""
553         # Config 4
554         # Reset all VRFs (i.e. no VRF except VRF=0 configured)
555         for i in range(len(self.vrf_list)):
556             # This call removes the first item of vrf_list as a side effect
557             self.reset_vrf_and_remove_from_vrf_list(self.vrf_list[0])
558
559         # Verify 4
560         for vrf_id in self.vrf_reset_list:
561             self.assert_equal(self.verify_vrf(vrf_id), VRFState.reset, VRFState)
562         vrf_list_length = len(self.vrf_list)
563         self.assertEqual(
564             vrf_list_length,
565             0,
566             "List of configured VRFs is not empty: %s != 0" % vrf_list_length,
567         )
568
569         # Test 4
570         self.run_verify_test()
571         self.run_crosswise_vrf_test()
572
573     def test_ip6_vrf_05(self):
574         """IP6 VRF  Multi-instance test 5 - auto allocate vrf id"""
575         # Config 5
576         # Create several VRFs
577         # Set vrf_id manually first
578         self.create_vrf_by_id_and_assign_interfaces(1, 10)
579         # Set vrf_id automatically a few times
580         auto_vrf_id = [
581             self.create_vrf_by_id_and_assign_interfaces(i) for i in range(2, 5)
582         ]
583
584         # Verify 5
585         self.assert_equal(self.verify_vrf(10, 1), VRFState.configured, VRFState)
586         for i, vrf in enumerate(auto_vrf_id):
587             self.assert_equal(
588                 self.verify_vrf(vrf, i + 2), VRFState.configured, VRFState
589             )
590
591         # Test 5
592         self.run_verify_test()
593
594         # Config 5.1
595         # Reset VRFs
596         self.reset_vrf_and_remove_from_vrf_list(10, 1)
597         for i, vrf in enumerate(auto_vrf_id):
598             self.reset_vrf_and_remove_from_vrf_list(vrf, i + 2)
599
600         # Verify 5.1
601         self.assert_equal(self.verify_vrf(10, 1), VRFState.reset, VRFState)
602         for i, vrf in enumerate(auto_vrf_id):
603             self.assert_equal(self.verify_vrf(vrf, i + 2), VRFState.reset, VRFState)
604
605         vrf_list_length = len(self.vrf_list)
606         self.assertEqual(
607             vrf_list_length,
608             0,
609             "List of configured VRFs is not empty: %s != 0" % vrf_list_length,
610         )
611
612         # Cleanup our extra created VRFs
613         for vrf in auto_vrf_id:
614             self.delete_vrf(vrf)
615         self.delete_vrf(5)
616         self.delete_vrf(10)
617
618     def test_ip6_vrf_06(self):
619         """IP6 VRF  Multi-instance test 6 - recreate 4 VRFs"""
620         # Reconfigure all the VRFs
621         self.create_vrf_and_assign_interfaces(4)
622         # Verify
623         for vrf_id in self.vrf_list:
624             self.assert_equal(self.verify_vrf(vrf_id), VRFState.configured, VRFState)
625         # Test
626         self.run_verify_test()
627         self.run_crosswise_vrf_test()
628         # Cleanup
629         for i in range(len(self.vrf_list)):
630             self.reset_vrf_and_remove_from_vrf_list(self.vrf_list[0])
631         # Verify
632         for vrf_id in self.vrf_reset_list:
633             self.assert_equal(self.verify_vrf(vrf_id), VRFState.reset, VRFState)
634         vrf_list_length = len(self.vrf_list)
635         self.assertEqual(
636             vrf_list_length,
637             0,
638             "List of configured VRFs is not empty: %s != 0" % vrf_list_length,
639         )
640         # Test
641         self.run_verify_test()
642         self.run_crosswise_vrf_test()
643
644
645 if __name__ == "__main__":
646     unittest.main(testRunner=VppTestRunner)