classify: API cleanup 51/21551/28
authorJakub Grajciar <jgrajcia@cisco.com>
Tue, 27 Aug 2019 08:16:44 +0000 (10:16 +0200)
committerOle Trøan <otroan@employees.org>
Tue, 3 Dec 2019 14:53:47 +0000 (14:53 +0000)
Use consistent API types.

Type: fix

Change-Id: Ib5b1efa76f0a9cecc0bc146f8f8a47c2442fc1db
Signed-off-by: Jakub Grajciar <jgrajcia@cisco.com>
Signed-off-by: Ole Troan <ot@cisco.com>
Signed-off-by: Paul Vinciguerra <pvinci@vinciconsulting.com>
MAINTAINERS
src/plugins/acl/test/test_classify_l2_acl.py
src/vnet/classify/classify.api
src/vnet/classify/classify_api.c
src/vpp/api/custom_dump.c
test/template_classifier.py [new file with mode: 0644]
test/test_classifier.py
test/test_classifier_ip6.py
test/vpp_papi_provider.py

index 440a1da..6c3e36a 100644 (file)
@@ -290,6 +290,11 @@ I: flow
 M:     Damjan Marion <damarion@cisco.com>
 F:     src/vnet/flow/
 
+VNET Classify
+I:     classify
+M:     N/A
+F:     src/vnet/classify/
+
 Plugin - Access Control List (ACL) Based Forwarding
 I:     abf
 M:     Neale Ranns <nranns@cisco.com>
index c9962d6..0cba6c8 100644 (file)
@@ -16,9 +16,10 @@ from scapy.layers.inet6 import IPv6, ICMPv6EchoRequest
 from scapy.layers.inet6 import IPv6ExtHdrFragment
 from framework import VppTestCase, VppTestRunner
 from util import Host, ppp
+from template_classifier import TestClassifier
 
 
-class TestClassifyAcl(VppTestCase):
+class TestClassifyAcl(TestClassifier):
     """ Classifier-based L2 input and output ACL Test Case """
 
     # traffic types
@@ -88,6 +89,7 @@ class TestClassifyAcl(VppTestCase):
         variables and configure VPP.
         """
         super(TestClassifyAcl, cls).setUpClass()
+        cls.af = None
 
         try:
             # Create 2 pg interfaces
@@ -138,9 +140,7 @@ class TestClassifyAcl(VppTestCase):
 
     def setUp(self):
         super(TestClassifyAcl, self).setUp()
-
         self.acl_tbl_idx = {}
-        self.reset_packet_infos()
 
     def tearDown(self):
         """
@@ -164,60 +164,6 @@ class TestClassifyAcl(VppTestCase):
 
         super(TestClassifyAcl, self).tearDown()
 
-    def show_commands_at_teardown(self):
-        self.logger.info(self.vapi.ppcli("show inacl type l2"))
-        self.logger.info(self.vapi.ppcli("show outacl type l2"))
-        self.logger.info(self.vapi.ppcli("show classify tables verbose"))
-        self.logger.info(self.vapi.ppcli("show bridge-domain %s detail"
-                                         % self.bd_id))
-
-    @staticmethod
-    def build_mac_mask(dst_mac='', src_mac='', ether_type=''):
-        """Build MAC ACL mask data with hexstring format
-
-        :param str dst_mac: source MAC address <0-ffffffffffff>
-        :param str src_mac: destination MAC address <0-ffffffffffff>
-        :param str ether_type: ethernet type <0-ffff>
-        """
-
-        return ('{!s:0>12}{!s:0>12}{!s:0>4}'.format(
-            dst_mac, src_mac, ether_type)).rstrip('0')
-
-    @staticmethod
-    def build_mac_match(dst_mac='', src_mac='', ether_type=''):
-        """Build MAC ACL match data with hexstring format
-
-        :param str dst_mac: source MAC address <x:x:x:x:x:x>
-        :param str src_mac: destination MAC address <x:x:x:x:x:x>
-        :param str ether_type: ethernet type <0-ffff>
-        """
-        if dst_mac:
-            dst_mac = dst_mac.replace(':', '')
-        if src_mac:
-            src_mac = src_mac.replace(':', '')
-
-        return ('{!s:0>12}{!s:0>12}{!s:0>4}'.format(
-            dst_mac, src_mac, ether_type)).rstrip('0')
-
-    def create_classify_table(self, key, mask, data_offset=0, is_add=1):
-        """Create Classify Table
-
-        :param str key: key for classify table (ex, ACL name).
-        :param str mask: mask value for interested traffic.
-        :param int match_n_vectors:
-        :param int is_add: option to configure classify table.
-            - create(1) or delete(0)
-        """
-        r = self.vapi.classify_add_del_table(
-            is_add,
-            binascii.unhexlify(mask),
-            match_n_vectors=(len(mask) - 1) // 32 + 1,
-            miss_next_index=0,
-            current_data_flag=1,
-            current_data_offset=data_offset)
-        self.assertIsNotNone(r, 'No response msg for add_del_table')
-        self.acl_tbl_idx[key] = r.new_table_index
-
     def create_classify_session(self, intf, table_index, match,
                                 hit_next_index=0xffffffff, is_add=1):
         """Create Classify Session
@@ -225,46 +171,18 @@ class TestClassifyAcl(VppTestCase):
         :param VppInterface intf: Interface to apply classify session.
         :param int table_index: table index to identify classify table.
         :param str match: matched value for interested traffic.
-        :param int pbr_action: enable/disable PBR feature.
-        :param int vrfid: VRF id.
         :param int is_add: option to configure classify session.
             - create(1) or delete(0)
         """
+        mask_match, mask_match_len = self._resolve_mask_match(match)
         r = self.vapi.classify_add_del_session(
-            is_add,
-            table_index,
-            binascii.unhexlify(match),
+            is_add=is_add,
+            table_index=table_index,
+            match=mask_match,
+            match_len=mask_match_len,
             hit_next_index=hit_next_index)
         self.assertIsNotNone(r, 'No response msg for add_del_session')
 
-    def input_acl_set_interface(self, intf, table_index, is_add=1):
-        """Configure Input ACL interface
-
-        :param VppInterface intf: Interface to apply Input ACL feature.
-        :param int table_index: table index to identify classify table.
-        :param int is_add: option to configure classify session.
-            - enable(1) or disable(0)
-        """
-        r = self.vapi.input_acl_set_interface(
-            is_add,
-            intf.sw_if_index,
-            l2_table_index=table_index)
-        self.assertIsNotNone(r, 'No response msg for acl_set_interface')
-
-    def output_acl_set_interface(self, intf, table_index, is_add=1):
-        """Configure Output ACL interface
-
-        :param VppInterface intf: Interface to apply Output ACL feature.
-        :param int table_index: table index to identify classify table.
-        :param int is_add: option to configure classify session.
-            - enable(1) or disable(0)
-        """
-        r = self.vapi.output_acl_set_interface(
-            is_add,
-            intf.sw_if_index,
-            l2_table_index=table_index)
-        self.assertIsNotNone(r, 'No response msg for acl_set_interface')
-
     def create_hosts(self, count, start=0):
         """
         Create required number of host MAC addresses and distribute them among
index 52ab186..38c7343 100644 (file)
  * limitations under the License.
  */
 
-option version = "2.0.0";
+option version = "3.0.0";
+
+import "vnet/interface_types.api";
 
 /** \brief Add/Delete classification table request
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
     @param is_add- if non-zero add the table, else delete it
     @param del_chain - if non-zero delete the whole chain of tables
-    @param table_index - if add, reuturns index of the created table, else specifies the table to delete  
+    @param table_index - if add, returns index of the created table, else specifies the table to delete
     @param nbuckets - number of buckets when adding a table
     @param memory_size - memory size when adding a table
     @param match_n_vectors - number of match vectors
@@ -44,24 +46,24 @@ define classify_add_del_table
 {
   u32 client_index;
   u32 context;
-  u8 is_add;
-  u8 del_chain;
-  u32 table_index;
-  u32 nbuckets;
-  u32 memory_size;
-  u32 skip_n_vectors;
-  u32 match_n_vectors;
-  u32 next_table_index;
-  u32 miss_next_index;
-  u32 current_data_flag;
-  i32 current_data_offset;
+  bool is_add;
+  bool del_chain;
+  u32 table_index [default=0xffffffff];
+  u32 nbuckets [default=2];
+  u32 memory_size [default=2097152];
+  u32 skip_n_vectors [default=0];
+  u32 match_n_vectors [default=1];
+  u32 next_table_index [default=0xffffffff];
+  u32 miss_next_index [default=0xffffffff];
+  u8 current_data_flag [default=0];
+  i16 current_data_offset [default=0];
   u32 mask_len;
   u8 mask[mask_len];
 };
 
 /** \brief Add/Delete classification table response
     @param context - sender context, to match reply w/ request
-    @param retval - return code for the table add/del requst
+    @param retval - return code for the table add/del request
     @param new_table_index - for add, returned index of the new table
     @param skip_n_vectors - for add, returned value of skip_n_vectors in table
     @param match_n_vectors -for add, returned value of match_n_vectors in table
@@ -75,6 +77,14 @@ define classify_add_del_table_reply
   u32 match_n_vectors;
 };
 
+enum classify_action : u8
+{
+  CLASSIFY_API_ACTION_NONE = 0,
+  CLASSIFY_API_ACTION_SET_IP4_FIB_INDEX = 1,
+  CLASSIFY_API_ACTION_SET_IP6_FIB_INDEX = 2,
+  CLASSIFY_API_ACTION_SET_METADATA = 3,
+};
+
 /** \brief Classify add / del session request
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
@@ -92,7 +102,7 @@ define classify_add_del_table_reply
            2: Classified IP packets will be looked up from the
               specified ipv6 fib table (configured by metadata as VRF id).
               Only valid for L3 input ACL node
-           3: Classified packet will be steered to source routig policy
+           3: Classified packet will be steered to source routing policy
               of given index (in metadata).
               This is only valid for IPv6 packets redirected to a source
               routing node.
@@ -110,13 +120,13 @@ autoreply define classify_add_del_session
 {
   u32 client_index;
   u32 context;
-  u8 is_add;
+  bool is_add;
   u32 table_index;
-  u32 hit_next_index;
-  u32 opaque_index;
-  i32 advance;
-  u8 action;
-  u32 metadata;
+  u32 hit_next_index [default=0xffffffff];
+  u32 opaque_index [default=0xffffffff];
+  i32 advance [default=0];
+  vl_api_classify_action_t action [default=0];
+  u32 metadata [default=0];
   u32 match_len;
   u8 match[match_len];
 };
@@ -129,33 +139,43 @@ autoreply define classify_add_del_session
     @param ip6_table_index - ip6 classify table index (~0 for skip)
     @param l2_table_index  -  l2 classify table index (~0 for skip)
     @param is_add - Set if non-zero, else unset
-    Note: User is recommeneded to use just one valid table_index per call.
+    Note: User is recommended to use just one valid table_index per call.
           (ip4_table_index, ip6_table_index, or l2_table_index)
 */
 autoreply define policer_classify_set_interface
 {
   u32 client_index;
   u32 context;
-  u32 sw_if_index;
+  vl_api_interface_index_t sw_if_index;
   u32 ip4_table_index;
   u32 ip6_table_index;
   u32 l2_table_index;
-  u8 is_add;
+  bool is_add;
+};
+
+enum policer_classify_table : u8
+{
+  POLICER_CLASSIFY_API_TABLE_IP4,
+  POLICER_CLASSIFY_API_TABLE_IP6,
+  POLICER_CLASSIFY_API_TABLE_L2,
 };
 
+
 /** \brief Get list of policer classify interfaces and tables
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
     @param type - classify table type
+    @param sw_if_index - filter on sw_if_index
 */
 define policer_classify_dump
 {
   u32 client_index;
   u32 context;
-  u8 type;
+  vl_api_policer_classify_table_t type;
+  vl_api_interface_index_t sw_if_index;
 };
 
-/** \brief Policer iclassify operational state response.
+/** \brief Policer classify operational state response.
     @param context - sender context, to match reply w/ request
     @param sw_if_index - software interface index
     @param table_index - classify table index
@@ -163,7 +183,7 @@ define policer_classify_dump
 define policer_classify_details
 {
   u32 context;
-  u32 sw_if_index;
+  vl_api_interface_index_t sw_if_index;
   u32 table_index;
 };
 
@@ -199,7 +219,7 @@ define classify_table_by_interface
 {
   u32 client_index;
   u32 context;
-  u32 sw_if_index;
+  vl_api_interface_index_t sw_if_index;
 };
 
 /** \brief Reply for classify table id by interface index request
@@ -214,7 +234,7 @@ define classify_table_by_interface_reply
 {
   u32 context;
   i32 retval;
-  u32 sw_if_index;
+  vl_api_interface_index_t sw_if_index;
   u32 l2_table_id;
   u32 ip4_table_id;
   u32 ip6_table_id;
@@ -300,27 +320,35 @@ define classify_session_details
     @param ip6_table_index - ip6 classify table index (~0 for skip)
     @param l2_table_index  -  l2 classify table index (~0 for skip)
     @param is_add - Set if non-zero, else unset
-    Note: User is recommeneded to use just one valid table_index per call.
+    Note: User is recommended to use just one valid table_index per call.
           (ip4_table_index, ip6_table_index, or l2_table_index)
 */
 autoreply define flow_classify_set_interface {
     u32 client_index;
     u32 context;
-    u32 sw_if_index;
+    vl_api_interface_index_t sw_if_index;
     u32 ip4_table_index;
     u32 ip6_table_index;
-    u8  is_add;
+    bool is_add;
+};
+
+enum flow_classify_table : u8
+{
+  FLOW_CLASSIFY_API_TABLE_IP4,
+  FLOW_CLASSIFY_API_TABLE_IP6,
 };
 
 /** \brief Get list of flow classify interfaces and tables
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
-    @param type - classify table type
+    @param type - flow classify table type
+    @param sw_if_index - filter on sw_if_index
 */
 define flow_classify_dump {
     u32 client_index;
     u32 context;
-    u8 type;
+    vl_api_flow_classify_table_t type;
+    vl_api_interface_index_t sw_if_index;
 };
 
 /** \brief Flow classify operational state response.
@@ -330,11 +358,11 @@ define flow_classify_dump {
 */
 define flow_classify_details {
     u32 context;
-    u32 sw_if_index;
+    vl_api_interface_index_t sw_if_index;
     u32 table_index;
 };
 
-/** \brief Set/unset the classification table for an interface request 
+/** \brief Set/unset the classification table for an interface request
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
     @param is_ipv6 - ipv6 if non-zero, else ipv4
@@ -345,8 +373,8 @@ autoreply define classify_set_interface_ip_table
 {
   u32 client_index;
   u32 context;
-  u8 is_ipv6;
-  u32 sw_if_index;
+  bool is_ipv6;
+  vl_api_interface_index_t sw_if_index;
   u32 table_index;             /* ~0 => off */
 };
 
@@ -362,12 +390,12 @@ autoreply define classify_set_interface_l2_tables
 {
   u32 client_index;
   u32 context;
-  u32 sw_if_index;
+  vl_api_interface_index_t sw_if_index;
   /* 3 x ~0 => off */
   u32 ip4_table_index;
   u32 ip6_table_index;
   u32 other_table_index;
-  u8 is_input;
+  bool is_input;
 };
 
 /** \brief Set/unset input ACL interface
@@ -378,18 +406,18 @@ autoreply define classify_set_interface_l2_tables
     @param ip6_table_index - ip6 classify table index (~0 for skip)
     @param l2_table_index  -  l2 classify table index (~0 for skip)
     @param is_add - Set input ACL if non-zero, else unset
-    Note: User is recommeneded to use just one valid table_index per call.
+    Note: User is recommended to use just one valid table_index per call.
           (ip4_table_index, ip6_table_index, or l2_table_index)
 */
 autoreply define input_acl_set_interface
 {
   u32 client_index;
   u32 context;
-  u32 sw_if_index;
+  vl_api_interface_index_t sw_if_index;
   u32 ip4_table_index;
   u32 ip6_table_index;
   u32 l2_table_index;
-  u8 is_add;
+  bool is_add;
 };
 
 /** \brief Set/unset output ACL interface
@@ -400,18 +428,18 @@ autoreply define input_acl_set_interface
     @param ip6_table_index - ip6 classify table index (~0 for skip)
     @param l2_table_index  -  l2 classify table index (~0 for skip)
     @param is_add - Set output ACL if non-zero, else unset
-    Note: User is recommeneded to use just one valid table_index per call.
+    Note: User is recommended to use just one valid table_index per call.
           (ip4_table_index, ip6_table_index, or l2_table_index)
 */
 autoreply define output_acl_set_interface
 {
   u32 client_index;
   u32 context;
-  u32 sw_if_index;
+  vl_api_interface_index_t sw_if_index;
   u32 ip4_table_index;
   u32 ip6_table_index;
   u32 l2_table_index;
-  u8 is_add;
+  bool is_add;
 };
 
 /*
@@ -419,4 +447,3 @@ autoreply define output_acl_set_interface
  * eval: (c-set-style "gnu")
  * End:
  */
index 98f4366..0725a9c 100644 (file)
@@ -71,8 +71,6 @@ _(skip_n_vectors)                               \
 _(match_n_vectors)                              \
 _(next_table_index)                             \
 _(miss_next_index)                              \
-_(current_data_flag)                            \
-_(current_data_offset)                          \
 _(mask_len)
 
 static void vl_api_classify_add_del_table_t_handler
@@ -112,6 +110,9 @@ static void vl_api_classify_add_del_table_t_handler
        table_index = ~0;
     }
 
+  u8 current_data_flag = mp->current_data_flag;
+  i16 current_data_offset = clib_net_to_host_i16 (mp->current_data_offset);
+
   rv = vnet_classify_add_del_table
     (cm, mp->mask, nbuckets, memory_size,
      skip_n_vectors, match_n_vectors,
@@ -125,9 +126,9 @@ out:
     if (rv == 0 && mp->is_add)
       {
         t = pool_elt_at_index (cm->tables, table_index);
-        rmp->skip_n_vectors = ntohl(t->skip_n_vectors);
-        rmp->match_n_vectors = ntohl(t->match_n_vectors);
-        rmp->new_table_index = ntohl(table_index);
+        rmp->skip_n_vectors = htonl(t->skip_n_vectors);
+        rmp->match_n_vectors = htonl(t->match_n_vectors);
+        rmp->new_table_index = htonl(table_index);
       }
     else
       {
@@ -229,12 +230,18 @@ vl_api_policer_classify_dump_t_handler (vl_api_policer_classify_dump_t * mp)
   policer_classify_main_t *pcm = &policer_classify_main;
   u32 *vec_tbl;
   int i;
+  u32 filter_sw_if_index;
 
   reg = vl_api_client_index_to_registration (mp->client_index);
   if (!reg)
     return;
 
-  vec_tbl = pcm->classify_table_index_by_sw_if_index[mp->type];
+  filter_sw_if_index = ntohl (mp->sw_if_index);
+  if (filter_sw_if_index != ~0)
+    vec_tbl =
+      &pcm->classify_table_index_by_sw_if_index[mp->type][filter_sw_if_index];
+  else
+    vec_tbl = pcm->classify_table_index_by_sw_if_index[mp->type];
 
   if (vec_len (vec_tbl))
     {
@@ -505,12 +512,18 @@ vl_api_flow_classify_dump_t_handler (vl_api_flow_classify_dump_t * mp)
   flow_classify_main_t *pcm = &flow_classify_main;
   u32 *vec_tbl;
   int i;
+  u32 filter_sw_if_index;
 
   reg = vl_api_client_index_to_registration (mp->client_index);
   if (!reg)
     return;
 
-  vec_tbl = pcm->classify_table_index_by_sw_if_index[mp->type];
+  filter_sw_if_index = ntohl (mp->sw_if_index);
+  if (filter_sw_if_index != ~0)
+    vec_tbl =
+      &pcm->classify_table_index_by_sw_if_index[mp->type][filter_sw_if_index];
+  else
+    vec_tbl = pcm->classify_table_index_by_sw_if_index[mp->type];
 
   if (vec_len (vec_tbl))
     {
index 2424efc..4421cc9 100644 (file)
@@ -2453,13 +2453,13 @@ static void *vl_api_policer_classify_dump_t_print
   s = format (0, "SCRIPT: policer_classify_dump ");
   switch (mp->type)
     {
-    case POLICER_CLASSIFY_TABLE_IP4:
+    case POLICER_CLASSIFY_API_TABLE_IP4:
       s = format (s, "type ip4 ");
       break;
-    case POLICER_CLASSIFY_TABLE_IP6:
+    case POLICER_CLASSIFY_API_TABLE_IP6:
       s = format (s, "type ip6 ");
       break;
-    case POLICER_CLASSIFY_TABLE_L2:
+    case POLICER_CLASSIFY_API_TABLE_L2:
       s = format (s, "type l2 ");
       break;
     default:
@@ -3431,10 +3431,10 @@ static void *vl_api_flow_classify_dump_t_print
   s = format (0, "SCRIPT: flow_classify_dump ");
   switch (mp->type)
     {
-    case FLOW_CLASSIFY_TABLE_IP4:
+    case FLOW_CLASSIFY_API_TABLE_IP4:
       s = format (s, "type ip4 ");
       break;
-    case FLOW_CLASSIFY_TABLE_IP6:
+    case FLOW_CLASSIFY_API_TABLE_IP6:
       s = format (s, "type ip6 ");
       break;
     default:
diff --git a/test/template_classifier.py b/test/template_classifier.py
new file mode 100644 (file)
index 0000000..49cb3b3
--- /dev/null
@@ -0,0 +1,428 @@
+#!/usr/bin/env python
+
+import binascii
+import socket
+from socket import AF_INET, AF_INET6
+import unittest
+import sys
+
+from framework import VppTestCase
+
+from scapy.packet import Raw
+from scapy.layers.l2 import Ether
+from scapy.layers.inet import IP, UDP, TCP
+from scapy.layers.inet6 import IPv6
+from util import ppp
+
+
+class TestClassifier(VppTestCase):
+
+    @staticmethod
+    def _resolve_mask_match(mask_match):
+        mask_match = binascii.unhexlify(mask_match)
+        mask_match_len = ((len(mask_match) - 1) // 16 + 1) * 16
+        mask_match = mask_match + b'\0' * \
+            (mask_match_len - len(mask_match))
+        return mask_match, mask_match_len
+
+    @classmethod
+    def setUpClass(cls):
+        """
+        Perform standard class setup (defined by class method setUpClass in
+        class VppTestCase) before running the test case, set test case related
+        variables and configure VPP.
+        """
+        super(TestClassifier, cls).setUpClass()
+        cls.acl_active_table = ''
+        cls.af = AF_INET
+
+    def setUp(self):
+        """
+        Perform test setup before test case.
+
+        **Config:**
+            - create 4 pg interfaces
+                - untagged pg0/pg1/pg2 interface
+                    pg0 -------> pg1 (IP ACL)
+                           \
+                            ---> pg2 (MAC ACL))
+                             \
+                              -> pg3 (PBR)
+            - setup interfaces:
+                - put it into UP state
+                - set IPv4/6 addresses
+                - resolve neighbor address using ARP
+
+        :ivar list interfaces: pg interfaces.
+        :ivar list pg_if_packet_sizes: packet sizes in test.
+        :ivar dict acl_tbl_idx: ACL table index.
+        :ivar int pbr_vrfid: VRF id for PBR test.
+        """
+        self.reset_packet_infos()
+        super(TestClassifier, self).setUp()
+        if self.af is None:  # l2_acl test case
+            return
+
+        # create 4 pg interfaces
+        self.create_pg_interfaces(range(4))
+
+        # packet sizes to test
+        self.pg_if_packet_sizes = [64, 9018]
+
+        self.interfaces = list(self.pg_interfaces)
+
+        # ACL & PBR vars
+        self.acl_tbl_idx = {}
+        self.pbr_vrfid = 200
+
+        # setup all interfaces
+        for intf in self.interfaces:
+            intf.admin_up()
+            if self.af == AF_INET:
+                intf.config_ip4()
+                intf.resolve_arp()
+            elif self.af == AF_INET6:
+                intf.config_ip6()
+                intf.resolve_ndp()
+
+    def tearDown(self):
+        """Run standard test teardown and acl related log."""
+        if self.af is not None and not self.vpp_dead:
+            if self.af == AF_INET:
+                self.logger.info(self.vapi.ppcli("show inacl type ip4"))
+                self.logger.info(self.vapi.ppcli("show outacl type ip4"))
+            elif self.af == AF_INET6:
+                self.logger.info(self.vapi.ppcli("show inacl type ip6"))
+                self.logger.info(self.vapi.ppcli("show outacl type ip6"))
+
+            self.logger.info(self.vapi.cli("show classify table verbose"))
+            self.logger.info(self.vapi.cli("show ip fib"))
+
+            acl_active_table = 'ip_out'
+            if self.af == AF_INET6:
+                acl_active_table = 'ip6_out'
+
+            if self.acl_active_table == acl_active_table:
+                self.output_acl_set_interface(
+                    self.pg0, self.acl_tbl_idx.get(self.acl_active_table), 0)
+                self.acl_active_table = ''
+            elif self.acl_active_table != '':
+                self.input_acl_set_interface(
+                    self.pg0, self.acl_tbl_idx.get(self.acl_active_table), 0)
+                self.acl_active_table = ''
+
+            for intf in self.interfaces:
+                if self.af == AF_INET:
+                    intf.unconfig_ip4()
+                elif self.af == AF_INET6:
+                    intf.unconfig_ip6()
+                intf.admin_down()
+
+        super(TestClassifier, self).tearDown()
+
+    @staticmethod
+    def build_mac_match(dst_mac='', src_mac='', ether_type=''):
+        """Build MAC ACL match data with hexstring format.
+
+        :param str dst_mac: source MAC address <x:x:x:x:x:x>
+        :param str src_mac: destination MAC address <x:x:x:x:x:x>
+        :param str ether_type: ethernet type <0-ffff>
+        """
+        if dst_mac:
+            dst_mac = dst_mac.replace(':', '')
+        if src_mac:
+            src_mac = src_mac.replace(':', '')
+
+        return ('{!s:0>12}{!s:0>12}{!s:0>4}'.format(
+            dst_mac, src_mac, ether_type)).rstrip('0')
+
+    @staticmethod
+    def build_mac_mask(dst_mac='', src_mac='', ether_type=''):
+        """Build MAC ACL mask data with hexstring format.
+
+        :param str dst_mac: source MAC address <0-ffffffffffff>
+        :param str src_mac: destination MAC address <0-ffffffffffff>
+        :param str ether_type: ethernet type <0-ffff>
+        """
+
+        return ('{!s:0>12}{!s:0>12}{!s:0>4}'.format(
+            dst_mac, src_mac, ether_type)).rstrip('0')
+
+    @staticmethod
+    def build_ip_mask(proto='', src_ip='', dst_ip='',
+                      src_port='', dst_port=''):
+        """Build IP ACL mask data with hexstring format.
+
+        :param str proto: protocol number <0-ff>
+        :param str src_ip: source ip address <0-ffffffff>
+        :param str dst_ip: destination ip address <0-ffffffff>
+        :param str src_port: source port number <0-ffff>
+        :param str dst_port: destination port number <0-ffff>
+        """
+
+        return ('{!s:0>20}{!s:0>12}{!s:0>8}{!s:0>4}{!s:0>4}'.format(
+            proto, src_ip, dst_ip, src_port, dst_port)).rstrip('0')
+
+    @staticmethod
+    def build_ip6_mask(nh='', src_ip='', dst_ip='',
+                       src_port='', dst_port=''):
+        """Build IPv6 ACL mask data with hexstring format.
+
+        :param str nh: next header number <0-ff>
+        :param str src_ip: source ip address <0-ffffffff>
+        :param str dst_ip: destination ip address <0-ffffffff>
+        :param str src_port: source port number <0-ffff>
+        :param str dst_port: destination port number <0-ffff>
+        """
+
+        return ('{!s:0>14}{!s:0>34}{!s:0>32}{!s:0>4}{!s:0>4}'.format(
+            nh, src_ip, dst_ip, src_port, dst_port)).rstrip('0')
+
+    @staticmethod
+    def build_ip_match(proto=0, src_ip='', dst_ip='',
+                       src_port=0, dst_port=0):
+        """Build IP ACL match data with hexstring format.
+
+        :param int proto: protocol number with valid option "x"
+        :param str src_ip: source ip address with format of "x.x.x.x"
+        :param str dst_ip: destination ip address with format of "x.x.x.x"
+        :param int src_port: source port number "x"
+        :param int dst_port: destination port number "x"
+        """
+        if src_ip:
+            src_ip = binascii.hexlify(socket.inet_aton(src_ip)).decode('ascii')
+        if dst_ip:
+            dst_ip = binascii.hexlify(socket.inet_aton(dst_ip)).decode('ascii')
+
+        return ('{!s:0>20}{!s:0>12}{!s:0>8}{!s:0>4}{!s:0>4}'.format(
+            hex(proto)[2:], src_ip, dst_ip, hex(src_port)[2:],
+            hex(dst_port)[2:])).rstrip('0')
+
+    @staticmethod
+    def build_ip6_match(nh=0, src_ip='', dst_ip='',
+                        src_port=0, dst_port=0):
+        """Build IPv6 ACL match data with hexstring format.
+
+        :param int nh: next header number with valid option "x"
+        :param str src_ip: source ip6 address with format of "xxx:xxxx::xxxx"
+        :param str dst_ip: destination ip6 address with format of
+            "xxx:xxxx::xxxx"
+        :param int src_port: source port number "x"
+        :param int dst_port: destination port number "x"
+        """
+        if src_ip:
+            if sys.version_info[0] == 2:
+                src_ip = binascii.hexlify(socket.inet_pton(
+                    socket.AF_INET6, src_ip))
+            else:
+                src_ip = socket.inet_pton(socket.AF_INET6, src_ip).hex()
+
+        if dst_ip:
+            if sys.version_info[0] == 2:
+                dst_ip = binascii.hexlify(socket.inet_pton(
+                    socket.AF_INET6, dst_ip))
+            else:
+                dst_ip = socket.inet_pton(socket.AF_INET6, dst_ip).hex()
+
+        return ('{!s:0>14}{!s:0>34}{!s:0>32}{!s:0>4}{!s:0>4}'.format(
+            hex(nh)[2:], src_ip, dst_ip, hex(src_port)[2:],
+            hex(dst_port)[2:])).rstrip('0')
+
+    def create_stream(self, src_if, dst_if, packet_sizes,
+                      proto_l=UDP(sport=1234, dport=5678)):
+        """Create input packet stream for defined interfaces.
+
+        :param VppInterface src_if: Source Interface for packet stream.
+        :param VppInterface dst_if: Destination Interface for packet stream.
+        :param list packet_sizes: packet size to test.
+        :param Scapy proto_l: Required IP protocol. Default protocol is UDP.
+        """
+        pkts = []
+
+        for size in packet_sizes:
+            info = self.create_packet_info(src_if, dst_if)
+            payload = self.info_to_payload(info)
+            if self.af == AF_INET:
+                p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
+                     IP(src=src_if.remote_ip4, dst=dst_if.remote_ip4) /
+                     proto_l /
+                     Raw(payload))
+            elif self.af == AF_INET6:
+                p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
+                     IPv6(src=src_if.remote_ip6, dst=dst_if.remote_ip6) /
+                     proto_l /
+                     Raw(payload))
+            info.data = p.copy()
+            self.extend_packet(p, size)
+            pkts.append(p)
+        return pkts
+
+    def verify_capture(self, dst_if, capture, proto_l=UDP):
+        """Verify captured input packet stream for defined interface.
+
+        :param VppInterface dst_if: Interface to verify captured packet stream.
+        :param list capture: Captured packet stream.
+        :param Scapy proto_l: Required IP protocol. Default protocol is UDP.
+        """
+        ip_proto = IP
+        if self.af == AF_INET6:
+            ip_proto = IPv6
+        self.logger.info("Verifying capture on interface %s" % dst_if.name)
+        last_info = dict()
+        for i in self.interfaces:
+            last_info[i.sw_if_index] = None
+        dst_sw_if_index = dst_if.sw_if_index
+        for packet in capture:
+            try:
+                ip_received = packet[ip_proto]
+                proto_received = packet[proto_l]
+                payload_info = self.payload_to_info(packet[Raw])
+                packet_index = payload_info.index
+                self.assertEqual(payload_info.dst, dst_sw_if_index)
+                self.logger.debug(
+                    "Got packet on port %s: src=%u (id=%u)" %
+                    (dst_if.name, payload_info.src, packet_index))
+                next_info = self.get_next_packet_info_for_interface2(
+                    payload_info.src, dst_sw_if_index,
+                    last_info[payload_info.src])
+                last_info[payload_info.src] = next_info
+                self.assertTrue(next_info is not None)
+                self.assertEqual(packet_index, next_info.index)
+                saved_packet = next_info.data
+                ip_saved = saved_packet[ip_proto]
+                proto_saved = saved_packet[proto_l]
+                # Check standard fields
+                self.assertEqual(ip_received.src, ip_saved.src)
+                self.assertEqual(ip_received.dst, ip_saved.dst)
+                self.assertEqual(proto_received.sport, proto_saved.sport)
+                self.assertEqual(proto_received.dport, proto_saved.dport)
+            except BaseException:
+                self.logger.error(ppp("Unexpected or invalid packet:", packet))
+                raise
+        for i in self.interfaces:
+            remaining_packet = self.get_next_packet_info_for_interface2(
+                i.sw_if_index, dst_sw_if_index, last_info[i.sw_if_index])
+            self.assertTrue(remaining_packet is None,
+                            "Interface %s: Packet expected from interface %s "
+                            "didn't arrive" % (dst_if.name, i.name))
+
+    def create_classify_table(self, key, mask, data_offset=0):
+        """Create Classify Table
+
+        :param str key: key for classify table (ex, ACL name).
+        :param str mask: mask value for interested traffic.
+        :param int data_offset:
+        """
+        mask_match, mask_match_len = self._resolve_mask_match(mask)
+        r = self.vapi.classify_add_del_table(
+            is_add=1,
+            mask=mask_match,
+            mask_len=mask_match_len,
+            match_n_vectors=(len(mask) - 1) // 32 + 1,
+            miss_next_index=0,
+            current_data_flag=1,
+            current_data_offset=data_offset)
+        self.assertIsNotNone(r, 'No response msg for add_del_table')
+        self.acl_tbl_idx[key] = r.new_table_index
+
+    def create_classify_session(self, table_index, match, pbr_option=0,
+                                vrfid=0, is_add=1):
+        """Create Classify Session
+
+        :param int table_index: table index to identify classify table.
+        :param str match: matched value for interested traffic.
+        :param int pbr_option: enable/disable PBR feature.
+        :param int vrfid: VRF id.
+        :param int is_add: option to configure classify session.
+            - create(1) or delete(0)
+        """
+        mask_match, mask_match_len = self._resolve_mask_match(match)
+        r = self.vapi.classify_add_del_session(
+            is_add=is_add,
+            table_index=table_index,
+            match=mask_match,
+            match_len=mask_match_len,
+            opaque_index=0,
+            action=pbr_option,
+            metadata=vrfid)
+        self.assertIsNotNone(r, 'No response msg for add_del_session')
+
+    def input_acl_set_interface(self, intf, table_index, is_add=1):
+        """Configure Input ACL interface
+
+        :param VppInterface intf: Interface to apply Input ACL feature.
+        :param int table_index: table index to identify classify table.
+        :param int is_add: option to configure classify session.
+            - enable(1) or disable(0)
+        """
+        r = None
+        if self.af == AF_INET:
+            r = self.vapi.input_acl_set_interface(
+                is_add,
+                intf.sw_if_index,
+                ip4_table_index=table_index)
+        elif self.af == AF_INET6:
+            r = self.vapi.input_acl_set_interface(
+                is_add,
+                intf.sw_if_index,
+                ip6_table_index=table_index)
+        else:
+            r = self.vapi.input_acl_set_interface(
+                is_add,
+                intf.sw_if_index,
+                l2_table_index=table_index)
+        self.assertIsNotNone(r, 'No response msg for acl_set_interface')
+
+    def output_acl_set_interface(self, intf, table_index, is_add=1):
+        """Configure Output ACL interface
+
+        :param VppInterface intf: Interface to apply Output ACL feature.
+        :param int table_index: table index to identify classify table.
+        :param int is_add: option to configure classify session.
+            - enable(1) or disable(0)
+        """
+        r = None
+        if self.af == AF_INET:
+            r = self.vapi.output_acl_set_interface(
+                is_add,
+                intf.sw_if_index,
+                ip4_table_index=table_index)
+        elif self.af == AF_INET6:
+            r = self.vapi.output_acl_set_interface(
+                is_add,
+                intf.sw_if_index,
+                ip6_table_index=table_index)
+        else:
+            r = self.vapi.output_acl_set_interface(
+                is_add,
+                intf.sw_if_index,
+                l2_table_index=table_index)
+        self.assertIsNotNone(r, 'No response msg for acl_set_interface')
+
+    def config_pbr_fib_entry(self, intf, is_add=1):
+        """Configure fib entry to route traffic toward PBR VRF table
+
+        :param VppInterface intf: destination interface to be routed for PBR.
+
+        """
+        addr_len = 24
+        self.vapi.ip_add_del_route(dst_address=intf.local_ip4n,
+                                   dst_address_length=addr_len,
+                                   next_hop_address=intf.remote_ip4n,
+                                   table_id=self.pbr_vrfid, is_add=is_add)
+
+    def verify_vrf(self, vrf_id):
+        """
+        Check if the FIB table / VRF ID is configured.
+
+        :param int vrf_id: The FIB table / VRF ID to be verified.
+        :return: 1 if the FIB table / VRF ID is configured, otherwise return 0.
+        """
+        ip_fib_dump = self.vapi.ip_route_dump(vrf_id, False)
+        vrf_count = len(ip_fib_dump)
+        if vrf_count == 0:
+            self.logger.info("IPv4 VRF ID %d is not configured" % vrf_id)
+            return 0
+        else:
+            self.logger.info("IPv4 VRF ID %d is configured" % vrf_id)
+            return 1
index d99f66c..11c0985 100644 (file)
@@ -10,308 +10,11 @@ from scapy.packet import Raw
 from scapy.layers.l2 import Ether
 from scapy.layers.inet import IP, UDP, TCP
 from util import ppp
+from template_classifier import TestClassifier
 from vpp_ip_route import VppIpRoute, VppRoutePath
 from vpp_ip import INVALID_INDEX
 
 
-class TestClassifier(VppTestCase):
-    """ Classifier Test Case """
-
-    @classmethod
-    def setUpClass(cls):
-        """
-        Perform standard class setup (defined by class method setUpClass in
-        class VppTestCase) before running the test case, set test case related
-        variables and configure VPP.
-        """
-        super(TestClassifier, cls).setUpClass()
-        cls.acl_active_table = ''
-
-    @classmethod
-    def tearDownClass(cls):
-        super(TestClassifier, cls).tearDownClass()
-
-    def setUp(self):
-        """
-        Perform test setup before test case.
-
-        **Config:**
-            - create 4 pg interfaces
-                - untagged pg0/pg1/pg2 interface
-                    pg0 -------> pg1 (IP ACL)
-                           \
-                            ---> pg2 (MAC ACL))
-                             \
-                              -> pg3 (PBR)
-            - setup interfaces:
-                - put it into UP state
-                - set IPv4 addresses
-                - resolve neighbor address using ARP
-
-        :ivar list interfaces: pg interfaces.
-        :ivar list pg_if_packet_sizes: packet sizes in test.
-        :ivar dict acl_tbl_idx: ACL table index.
-        :ivar int pbr_vrfid: VRF id for PBR test.
-        """
-        self.reset_packet_infos()
-        super(TestClassifier, self).setUp()
-
-        # create 4 pg interfaces
-        self.create_pg_interfaces(range(4))
-
-        # packet sizes to test
-        self.pg_if_packet_sizes = [64, 9018]
-
-        self.interfaces = list(self.pg_interfaces)
-
-        # ACL & PBR vars
-        self.acl_tbl_idx = {}
-        self.pbr_vrfid = 200
-
-        # setup all interfaces
-        for intf in self.interfaces:
-            intf.admin_up()
-            intf.config_ip4()
-            intf.resolve_arp()
-
-    def tearDown(self):
-        """Run standard test teardown and acl related log."""
-        if not self.vpp_dead:
-            if self.acl_active_table == 'ip_out':
-                self.output_acl_set_interface(
-                    self.pg0, self.acl_tbl_idx.get(self.acl_active_table), 0)
-                self.acl_active_table = ''
-            elif self.acl_active_table != '':
-                self.input_acl_set_interface(
-                    self.pg0, self.acl_tbl_idx.get(self.acl_active_table), 0)
-                self.acl_active_table = ''
-            for intf in self.interfaces:
-                intf.unconfig_ip4()
-                intf.admin_down()
-
-        super(TestClassifier, self).tearDown()
-
-    def show_commands_at_teardown(self):
-        self.logger.info(self.vapi.ppcli("show inacl type ip4"))
-        self.logger.info(self.vapi.ppcli("show outacl type ip4"))
-        self.logger.info(self.vapi.cli("show classify table verbose"))
-        self.logger.info(self.vapi.cli("show ip fib"))
-
-    def create_stream(self, src_if, dst_if, packet_sizes,
-                      proto_l=UDP(sport=1234, dport=5678)):
-        """Create input packet stream for defined interfaces.
-
-        :param VppInterface src_if: Source Interface for packet stream.
-        :param VppInterface dst_if: Destination Interface for packet stream.
-        :param list packet_sizes: packet size to test.
-        :param Scapy proto_l: Required IP protocol. Default protocol is UDP.
-        """
-        pkts = []
-
-        for size in packet_sizes:
-            info = self.create_packet_info(src_if, dst_if)
-            payload = self.info_to_payload(info)
-            p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
-                 IP(src=src_if.remote_ip4, dst=dst_if.remote_ip4) /
-                 proto_l /
-                 Raw(payload))
-            info.data = p.copy()
-            self.extend_packet(p, size)
-            pkts.append(p)
-        return pkts
-
-    def verify_capture(self, dst_if, capture, proto_l=UDP):
-        """Verify captured input packet stream for defined interface.
-
-        :param VppInterface dst_if: Interface to verify captured packet stream.
-        :param list capture: Captured packet stream.
-        :param Scapy proto_l: Required IP protocol. Default protocol is UDP.
-        """
-        self.logger.info("Verifying capture on interface %s" % dst_if.name)
-        last_info = dict()
-        for i in self.interfaces:
-            last_info[i.sw_if_index] = None
-        dst_sw_if_index = dst_if.sw_if_index
-        for packet in capture:
-            try:
-                ip_received = packet[IP]
-                proto_received = packet[proto_l]
-                payload_info = self.payload_to_info(packet[Raw])
-                packet_index = payload_info.index
-                self.assertEqual(payload_info.dst, dst_sw_if_index)
-                self.logger.debug(
-                    "Got packet on port %s: src=%u (id=%u)" %
-                    (dst_if.name, payload_info.src, packet_index))
-                next_info = self.get_next_packet_info_for_interface2(
-                    payload_info.src, dst_sw_if_index,
-                    last_info[payload_info.src])
-                last_info[payload_info.src] = next_info
-                self.assertTrue(next_info is not None)
-                self.assertEqual(packet_index, next_info.index)
-                saved_packet = next_info.data
-                ip_saved = saved_packet[IP]
-                proto_saved = saved_packet[proto_l]
-                # Check standard fields
-                self.assertEqual(ip_received.src, ip_saved.src)
-                self.assertEqual(ip_received.dst, ip_saved.dst)
-                self.assertEqual(proto_received.sport, proto_saved.sport)
-                self.assertEqual(proto_received.dport, proto_saved.dport)
-            except:
-                self.logger.error(ppp("Unexpected or invalid packet:", packet))
-                raise
-        for i in self.interfaces:
-            remaining_packet = self.get_next_packet_info_for_interface2(
-                i.sw_if_index, dst_sw_if_index, last_info[i.sw_if_index])
-            self.assertTrue(remaining_packet is None,
-                            "Interface %s: Packet expected from interface %s "
-                            "didn't arrive" % (dst_if.name, i.name))
-
-    def verify_vrf(self, vrf_id):
-        """
-        Check if the FIB table / VRF ID is configured.
-
-        :param int vrf_id: The FIB table / VRF ID to be verified.
-        :return: 1 if the FIB table / VRF ID is configured, otherwise return 0.
-        """
-        ip_fib_dump = self.vapi.ip_route_dump(vrf_id, False)
-        vrf_count = len(ip_fib_dump)
-
-        if vrf_count == 0:
-            self.logger.info("IPv4 VRF ID %d is not configured" % vrf_id)
-            return 0
-        else:
-            self.logger.info("IPv4 VRF ID %d is configured" % vrf_id)
-            return 1
-
-    @staticmethod
-    def build_ip_mask(proto='', src_ip='', dst_ip='',
-                      src_port='', dst_port=''):
-        """Build IP ACL mask data with hexstring format.
-
-        :param str proto: protocol number <0-ff>
-        :param str src_ip: source ip address <0-ffffffff>
-        :param str dst_ip: destination ip address <0-ffffffff>
-        :param str src_port: source port number <0-ffff>
-        :param str dst_port: destination port number <0-ffff>
-        """
-
-        return ('{!s:0>20}{!s:0>12}{!s:0>8}{!s:0>4}{!s:0>4}'.format(
-            proto, src_ip, dst_ip, src_port, dst_port)).rstrip('0')
-
-    @staticmethod
-    def build_ip_match(proto=0, src_ip='', dst_ip='',
-                       src_port=0, dst_port=0):
-        """Build IP ACL match data with hexstring format.
-
-        :param int proto: protocol number with valid option "x"
-        :param str src_ip: source ip address with format of "x.x.x.x"
-        :param str dst_ip: destination ip address with format of "x.x.x.x"
-        :param int src_port: source port number "x"
-        :param int dst_port: destination port number "x"
-        """
-        if src_ip:
-            src_ip = binascii.hexlify(socket.inet_aton(src_ip)).decode('ascii')
-        if dst_ip:
-            dst_ip = binascii.hexlify(socket.inet_aton(dst_ip)).decode('ascii')
-
-        return ('{!s:0>20}{!s:0>12}{!s:0>8}{!s:0>4}{!s:0>4}'.format(
-            hex(proto)[2:], src_ip, dst_ip, hex(src_port)[2:],
-            hex(dst_port)[2:])).rstrip('0')
-
-    @staticmethod
-    def build_mac_mask(dst_mac='', src_mac='', ether_type=''):
-        """Build MAC ACL mask data with hexstring format.
-
-        :param str dst_mac: source MAC address <0-ffffffffffff>
-        :param str src_mac: destination MAC address <0-ffffffffffff>
-        :param str ether_type: ethernet type <0-ffff>
-        """
-
-        return ('{!s:0>12}{!s:0>12}{!s:0>4}'.format(
-            dst_mac, src_mac, ether_type)).rstrip('0')
-
-    @staticmethod
-    def build_mac_match(dst_mac='', src_mac='', ether_type=''):
-        """Build MAC ACL match data with hexstring format.
-
-        :param str dst_mac: source MAC address <x:x:x:x:x:x>
-        :param str src_mac: destination MAC address <x:x:x:x:x:x>
-        :param str ether_type: ethernet type <0-ffff>
-        """
-        if dst_mac:
-            dst_mac = dst_mac.replace(':', '')
-        if src_mac:
-            src_mac = src_mac.replace(':', '')
-
-        return ('{!s:0>12}{!s:0>12}{!s:0>4}'.format(
-            dst_mac, src_mac, ether_type)).rstrip('0')
-
-    def create_classify_table(self, key, mask, data_offset=0):
-        """Create Classify Table
-
-        :param str key: key for classify table (ex, ACL name).
-        :param str mask: mask value for interested traffic.
-        :param int data_offset:
-        """
-        r = self.vapi.classify_add_del_table(
-            is_add=1,
-            mask=binascii.unhexlify(mask),
-            match_n_vectors=(len(mask) - 1) // 32 + 1,
-            miss_next_index=0,
-            current_data_flag=1,
-            current_data_offset=data_offset)
-        self.assertIsNotNone(r, 'No response msg for add_del_table')
-        self.acl_tbl_idx[key] = r.new_table_index
-
-    def create_classify_session(self, table_index, match, pbr_option=0,
-                                vrfid=0, is_add=1):
-        """Create Classify Session
-
-        :param int table_index: table index to identify classify table.
-        :param str match: matched value for interested traffic.
-        :param int pbr_option: enable/disable PBR feature.
-        :param int vrfid: VRF id.
-        :param int is_add: option to configure classify session.
-            - create(1) or delete(0)
-        """
-        r = self.vapi.classify_add_del_session(
-            is_add,
-            table_index,
-            binascii.unhexlify(match),
-            opaque_index=0,
-            action=pbr_option,
-            metadata=vrfid)
-        self.assertIsNotNone(r, 'No response msg for add_del_session')
-
-    def input_acl_set_interface(self, intf, table_index, is_add=1):
-        """Configure Input ACL interface
-
-        :param VppInterface intf: Interface to apply Input ACL feature.
-        :param int table_index: table index to identify classify table.
-        :param int is_add: option to configure classify session.
-            - enable(1) or disable(0)
-        """
-        r = self.vapi.input_acl_set_interface(
-            is_add,
-            intf.sw_if_index,
-            ip4_table_index=table_index)
-        self.assertIsNotNone(r, 'No response msg for acl_set_interface')
-
-    def output_acl_set_interface(self, intf, table_index, is_add=1):
-        """Configure Output ACL interface
-
-        :param VppInterface intf: Interface to apply Output ACL feature.
-        :param int table_index: table index to identify classify table.
-        :param int is_add: option to configure classify session.
-            - enable(1) or disable(0)
-        """
-        r = self.vapi.output_acl_set_interface(
-            is_add,
-            intf.sw_if_index,
-            ip4_table_index=table_index)
-        self.assertIsNotNone(r, 'No response msg for acl_set_interface')
-
-
 # Tests split to different test case classes because of issue reported in
 # ticket VPP-1336
 class TestClassifierIP(TestClassifier):
index 464034d..211374b 100644 (file)
@@ -3,7 +3,6 @@
 import unittest
 import socket
 import binascii
-import sys
 
 from framework import VppTestCase, VppTestRunner
 
@@ -11,291 +10,7 @@ from scapy.packet import Raw
 from scapy.layers.l2 import Ether
 from scapy.layers.inet6 import IPv6, UDP, TCP
 from util import ppp
-
-
-class TestClassifier(VppTestCase):
-    """ Classifier Test Case """
-
-    @classmethod
-    def setUpClass(cls):
-        """
-        Perform standard class setup (defined by class method setUpClass in
-        class VppTestCase) before running the test case, set test case related
-        variables and configure VPP.
-        """
-        super(TestClassifier, cls).setUpClass()
-        cls.acl_active_table = ''
-
-    @classmethod
-    def tearDownClass(cls):
-        super(TestClassifier, cls).tearDownClass()
-
-    def setUp(self):
-        """
-        Perform test setup before test case.
-
-        **Config:**
-            - create 4 pg interfaces
-                - untagged pg0/pg1/pg2 interface
-                    pg0 -------> pg1 (IP ACL)
-                           \
-                            ---> pg2 (MAC ACL))
-            - setup interfaces:
-                - put it into UP state
-                - set IPv6 addresses
-                - resolve neighbor address using NDP
-
-        :ivar list interfaces: pg interfaces.
-        :ivar list pg_if_packet_sizes: packet sizes in test.
-        :ivar dict acl_tbl_idx: ACL table index.
-        :ivar int pbr_vrfid: VRF id for PBR test.
-        """
-        self.reset_packet_infos()
-        super(TestClassifier, self).setUp()
-
-        # create 4 pg interfaces
-        self.create_pg_interfaces(range(3))
-
-        # packet sizes to test
-        self.pg_if_packet_sizes = [64, 9018]
-
-        self.interfaces = list(self.pg_interfaces)
-
-        # ACL vars
-        self.acl_tbl_idx = {}
-
-        # setup all interfaces
-        for intf in self.interfaces:
-            intf.admin_up()
-            intf.config_ip6()
-            intf.resolve_ndp()
-
-    def tearDown(self):
-        """Run standard test teardown and acl related log."""
-        if not self.vpp_dead:
-            if self.acl_active_table == 'ip6_out':
-                self.output_acl_set_interface(
-                    self.pg0, self.acl_tbl_idx.get(self.acl_active_table), 0)
-                self.acl_active_table = ''
-            elif self.acl_active_table != '':
-                self.input_acl_set_interface(
-                    self.pg0, self.acl_tbl_idx.get(self.acl_active_table), 0)
-                self.acl_active_table = ''
-            for intf in self.interfaces:
-                intf.unconfig_ip6()
-                intf.admin_down()
-
-        super(TestClassifier, self).tearDown()
-
-    def show_commands_at_teardown(self):
-        self.logger.info(self.vapi.ppcli("show inacl type ip6"))
-        self.logger.info(self.vapi.ppcli("show outacl type ip6"))
-        self.logger.info(self.vapi.cli("show classify table verbose"))
-        self.logger.info(self.vapi.cli("show ip fib"))
-
-    def create_stream(self, src_if, dst_if, packet_sizes,
-                      proto_l=UDP(sport=1234, dport=5678)):
-        """Create input packet stream for defined interfaces.
-
-        :param VppInterface src_if: Source Interface for packet stream.
-        :param VppInterface dst_if: Destination Interface for packet stream.
-        :param list packet_sizes: packet size to test.
-        :param Scapy proto_l: Required IP protocol. Default protocol is UDP.
-        """
-        pkts = []
-
-        for size in packet_sizes:
-            info = self.create_packet_info(src_if, dst_if)
-            payload = self.info_to_payload(info)
-            p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
-                 IPv6(src=src_if.remote_ip6, dst=dst_if.remote_ip6) /
-                 proto_l /
-                 Raw(payload))
-            info.data = p.copy()
-            self.extend_packet(p, size)
-            pkts.append(p)
-        return pkts
-
-    def verify_capture(self, dst_if, capture, proto_l=UDP):
-        """Verify captured input packet stream for defined interface.
-
-        :param VppInterface dst_if: Interface to verify captured packet stream.
-        :param list capture: Captured packet stream.
-        :param Scapy proto_l: Required IP protocol. Default protocol is UDP.
-        """
-        self.logger.info("Verifying capture on interface %s" % dst_if.name)
-        last_info = dict()
-        for i in self.interfaces:
-            last_info[i.sw_if_index] = None
-        dst_sw_if_index = dst_if.sw_if_index
-        for packet in capture:
-            try:
-                ip6_received = packet[IPv6]
-                proto_received = packet[proto_l]
-                payload_info = self.payload_to_info(packet[Raw])
-                packet_index = payload_info.index
-                self.assertEqual(payload_info.dst, dst_sw_if_index)
-                self.logger.debug(
-                    "Got packet on port %s: src=%u (id=%u)" %
-                    (dst_if.name, payload_info.src, packet_index))
-                next_info = self.get_next_packet_info_for_interface2(
-                    payload_info.src, dst_sw_if_index,
-                    last_info[payload_info.src])
-                last_info[payload_info.src] = next_info
-                self.assertTrue(next_info is not None)
-                self.assertEqual(packet_index, next_info.index)
-                saved_packet = next_info.data
-                ip_saved = saved_packet[IPv6]
-                proto_saved = saved_packet[proto_l]
-                # Check standard fields
-                self.assertEqual(ip6_received.src, ip_saved.src)
-                self.assertEqual(ip6_received.dst, ip_saved.dst)
-                self.assertEqual(proto_received.sport, proto_saved.sport)
-                self.assertEqual(proto_received.dport, proto_saved.dport)
-            except:
-                self.logger.error(ppp("Unexpected or invalid packet:", packet))
-                raise
-        for i in self.interfaces:
-            remaining_packet = self.get_next_packet_info_for_interface2(
-                i.sw_if_index, dst_sw_if_index, last_info[i.sw_if_index])
-            self.assertTrue(remaining_packet is None,
-                            "Interface %s: Packet expected from interface %s "
-                            "didn't arrive" % (dst_if.name, i.name))
-
-    @staticmethod
-    def build_ip6_mask(nh='', src_ip='', dst_ip='',
-                       src_port='', dst_port=''):
-        """Build IPv6 ACL mask data with hexstring format.
-
-        :param str nh: next header number <0-ff>
-        :param str src_ip: source ip address <0-ffffffff>
-        :param str dst_ip: destination ip address <0-ffffffff>
-        :param str src_port: source port number <0-ffff>
-        :param str dst_port: destination port number <0-ffff>
-        """
-
-        return ('{!s:0>14}{!s:0>34}{!s:0>32}{!s:0>4}{!s:0>4}'.format(
-            nh, src_ip, dst_ip, src_port, dst_port)).rstrip('0')
-
-    @staticmethod
-    def build_ip6_match(nh=0, src_ip='', dst_ip='',
-                        src_port=0, dst_port=0):
-        """Build IPv6 ACL match data with hexstring format.
-
-        :param int nh: next header number with valid option "x"
-        :param str src_ip: source ip6 address with format of "xxx:xxxx::xxxx"
-        :param str dst_ip: destination ip6 address with format of
-            "xxx:xxxx::xxxx"
-        :param int src_port: source port number "x"
-        :param int dst_port: destination port number "x"
-        """
-        if src_ip:
-            if sys.version_info[0] == 2:
-                src_ip = binascii.hexlify(socket.inet_pton(
-                    socket.AF_INET6, src_ip))
-            else:
-                src_ip = socket.inet_pton(socket.AF_INET6, src_ip).hex()
-
-        if dst_ip:
-            if sys.version_info[0] == 2:
-                dst_ip = binascii.hexlify(socket.inet_pton(
-                    socket.AF_INET6, dst_ip))
-            else:
-                dst_ip = socket.inet_pton(socket.AF_INET6, dst_ip).hex()
-
-        return ('{!s:0>14}{!s:0>34}{!s:0>32}{!s:0>4}{!s:0>4}'.format(
-            hex(nh)[2:], src_ip, dst_ip, hex(src_port)[2:],
-            hex(dst_port)[2:])).rstrip('0')
-
-    @staticmethod
-    def build_mac_mask(dst_mac='', src_mac='', ether_type=''):
-        """Build MAC ACL mask data with hexstring format.
-
-        :param str dst_mac: source MAC address <0-ffffffffffff>
-        :param str src_mac: destination MAC address <0-ffffffffffff>
-        :param str ether_type: ethernet type <0-ffff>
-        """
-
-        return ('{!s:0>12}{!s:0>12}{!s:0>4}'.format(
-            dst_mac, src_mac, ether_type)).rstrip('0')
-
-    @staticmethod
-    def build_mac_match(dst_mac='', src_mac='', ether_type=''):
-        """Build MAC ACL match data with hexstring format.
-
-        :param str dst_mac: source MAC address <x:x:x:x:x:x>
-        :param str src_mac: destination MAC address <x:x:x:x:x:x>
-        :param str ether_type: ethernet type <0-ffff>
-        """
-        if dst_mac:
-            dst_mac = dst_mac.replace(':', '')
-        if src_mac:
-            src_mac = src_mac.replace(':', '')
-
-        return ('{!s:0>12}{!s:0>12}{!s:0>4}'.format(
-            dst_mac, src_mac, ether_type)).rstrip('0')
-
-    def create_classify_table(self, key, mask, data_offset=0):
-        """Create Classify Table
-
-        :param str key: key for classify table (ex, ACL name).
-        :param str mask: mask value for interested traffic.
-        :param int data_offset:
-        """
-        r = self.vapi.classify_add_del_table(
-            is_add=1,
-            mask=binascii.unhexlify(mask),
-            match_n_vectors=(len(mask) - 1) // 32 + 1,
-            miss_next_index=0,
-            current_data_flag=1,
-            current_data_offset=data_offset)
-        self.assertIsNotNone(r, 'No response msg for add_del_table')
-        self.acl_tbl_idx[key] = r.new_table_index
-
-    def create_classify_session(self, table_index, match, vrfid=0, is_add=1):
-        """Create Classify Session
-
-        :param int table_index: table index to identify classify table.
-        :param str match: matched value for interested traffic.
-        :param int vrfid: VRF id.
-        :param int is_add: option to configure classify session.
-            - create(1) or delete(0)
-        """
-        r = self.vapi.classify_add_del_session(
-            is_add,
-            table_index,
-            binascii.unhexlify(match),
-            opaque_index=0,
-            metadata=vrfid)
-        self.assertIsNotNone(r, 'No response msg for add_del_session')
-
-    def input_acl_set_interface(self, intf, table_index, is_add=1):
-        """Configure Input ACL interface
-
-        :param VppInterface intf: Interface to apply Input ACL feature.
-        :param int table_index: table index to identify classify table.
-        :param int is_add: option to configure classify session.
-            - enable(1) or disable(0)
-        """
-        r = self.vapi.input_acl_set_interface(
-            is_add,
-            intf.sw_if_index,
-            ip6_table_index=table_index)
-        self.assertIsNotNone(r, 'No response msg for acl_set_interface')
-
-    def output_acl_set_interface(self, intf, table_index, is_add=1):
-        """Configure Output ACL interface
-
-        :param VppInterface intf: Interface to apply Output ACL feature.
-        :param int table_index: table index to identify classify table.
-        :param int is_add: option to configure classify session.
-            - enable(1) or disable(0)
-        """
-        r = self.vapi.output_acl_set_interface(
-            is_add,
-            intf.sw_if_index,
-            ip6_table_index=table_index)
-        self.assertIsNotNone(r, 'No response msg for acl_set_interface')
+from template_classifier import TestClassifier
 
 
 class TestClassifierIP6(TestClassifier):
@@ -304,6 +19,7 @@ class TestClassifierIP6(TestClassifier):
     @classmethod
     def setUpClass(cls):
         super(TestClassifierIP6, cls).setUpClass()
+        cls.af = socket.AF_INET6
 
     @classmethod
     def tearDownClass(cls):
@@ -413,10 +129,7 @@ class TestClassifierIP6UDP(TestClassifier):
     @classmethod
     def setUpClass(cls):
         super(TestClassifierIP6UDP, cls).setUpClass()
-
-    @classmethod
-    def tearDownClass(cls):
-        super(TestClassifierIP6UDP, cls).tearDownClass()
+        cls.af = socket.AF_INET6
 
     def test_iacl_proto_udp(self):
         """ IP6 UDP protocol iACL test
@@ -556,10 +269,7 @@ class TestClassifierIP6TCP(TestClassifier):
     @classmethod
     def setUpClass(cls):
         super(TestClassifierIP6TCP, cls).setUpClass()
-
-    @classmethod
-    def tearDownClass(cls):
-        super(TestClassifierIP6TCP, cls).tearDownClass()
+        cls.af = socket.AF_INET6
 
     def test_iacl_proto_tcp(self):
         """ IP6 TCP protocol iACL test
@@ -701,10 +411,7 @@ class TestClassifierIP6Out(TestClassifier):
     @classmethod
     def setUpClass(cls):
         super(TestClassifierIP6Out, cls).setUpClass()
-
-    @classmethod
-    def tearDownClass(cls):
-        super(TestClassifierIP6Out, cls).tearDownClass()
+        cls.af = socket.AF_INET6
 
     def test_acl_ip_out(self):
         """ Output IP6 ACL test
@@ -746,10 +453,7 @@ class TestClassifierIP6MAC(TestClassifier):
     @classmethod
     def setUpClass(cls):
         super(TestClassifierIP6MAC, cls).setUpClass()
-
-    @classmethod
-    def tearDownClass(cls):
-        super(TestClassifierIP6MAC, cls).tearDownClass()
+        cls.af = socket.AF_INET6
 
     def test_acl_mac(self):
         """ IP6 MAC iACL test
index 692d007..556145a 100644 (file)
@@ -42,10 +42,6 @@ defaultmapping = {
                               'learn': 1, 'is_add': 1, },
     'bvi_create': {'user_instance': 4294967295, },
     'bvi_delete': {},
-    'classify_add_del_table': {'match_n_vectors': 1, 'table_index': 4294967295,
-                               'nbuckets': 2, 'memory_size': 2097152,
-                               'next_table_index': 4294967295,
-                               'miss_next_index': 4294967295, },
     'gbp_subnet_add_del': {'sw_if_index': 4294967295, 'epg_id': 65535, },
     'geneve_add_del_tunnel': {'mcast_sw_if_index': 4294967295, 'is_add': 1,
                               'decap_next_index': 4294967295, },
@@ -693,84 +689,6 @@ class VppPapiProvider(object):
                  'mt_paths': paths,
              }})
 
-    def classify_add_del_table(
-            self,
-            is_add,
-            mask,
-            match_n_vectors=1,
-            table_index=0xFFFFFFFF,
-            nbuckets=2,
-            memory_size=2097152,
-            skip_n_vectors=0,
-            next_table_index=0xFFFFFFFF,
-            miss_next_index=0xFFFFFFFF,
-            current_data_flag=0,
-            current_data_offset=0):
-        """
-        :param is_add:
-        :param mask:
-        :param match_n_vectors: (Default value = 1)
-        :param table_index: (Default value = 0xFFFFFFFF)
-        :param nbuckets:  (Default value = 2)
-        :param memory_size:  (Default value = 2097152)
-        :param skip_n_vectors:  (Default value = 0)
-        :param next_table_index:  (Default value = 0xFFFFFFFF)
-        :param miss_next_index:  (Default value = 0xFFFFFFFF)
-        :param current_data_flag:  (Default value = 0)
-        :param current_data_offset:  (Default value = 0)
-        """
-        mask_len = ((len(mask) - 1) // 16 + 1) * 16
-        mask = mask + b'\0' * (mask_len - len(mask))
-        return self.api(
-            self.papi.classify_add_del_table,
-            {'is_add': is_add,
-             'table_index': table_index,
-             'nbuckets': nbuckets,
-             'memory_size': memory_size,
-             'skip_n_vectors': skip_n_vectors,
-             'match_n_vectors': match_n_vectors,
-             'next_table_index': next_table_index,
-             'miss_next_index': miss_next_index,
-             'current_data_flag': current_data_flag,
-             'current_data_offset': current_data_offset,
-             'mask_len': mask_len,
-             'mask': mask})
-
-    def classify_add_del_session(
-            self,
-            is_add,
-            table_index,
-            match,
-            opaque_index=0xFFFFFFFF,
-            hit_next_index=0xFFFFFFFF,
-            advance=0,
-            action=0,
-            metadata=0):
-        """
-        :param is_add:
-        :param table_index:
-        :param match:
-        :param opaque_index:  (Default value = 0xFFFFFFFF)
-        :param hit_next_index:  (Default value = 0xFFFFFFFF)
-        :param advance:  (Default value = 0)
-        :param action:  (Default value = 0)
-        :param metadata:  (Default value = 0)
-        """
-
-        match_len = ((len(match) - 1) // 16 + 1) * 16
-        match = match + b'\0' * (match_len - len(match))
-        return self.api(
-            self.papi.classify_add_del_session,
-            {'is_add': is_add,
-             'table_index': table_index,
-             'hit_next_index': hit_next_index,
-             'opaque_index': opaque_index,
-             'advance': advance,
-             'action': action,
-             'metadata': metadata,
-             'match_len': match_len,
-             'match': match})
-
     def input_acl_set_interface(
             self,
             is_add,