policer classify 69/1669/8
authorMatus Fabian <matfabia@cisco.com>
Mon, 20 Jun 2016 15:10:42 +0000 (08:10 -0700)
committerDave Barach <openvpp@barachs.net>
Tue, 26 Jul 2016 15:52:03 +0000 (15:52 +0000)
JIRA: VPP-114

If the classifier finds a matching entry, it sends packet to the policer,
packet should be pre-colored for color-aware policers.

Change-Id: I10cb53b49907137769418f230df2cab577d0f3a0
Signed-off-by: Matus Fabian <matfabia@cisco.com>
20 files changed:
vnet/Makefile.am
vnet/vnet/classify/policer_classify.c [new file with mode: 0644]
vnet/vnet/classify/policer_classify.h [new file with mode: 0644]
vnet/vnet/classify/vnet_classify.c
vnet/vnet/classify/vnet_classify.h
vnet/vnet/ip/ip4.h
vnet/vnet/ip/ip4_forward.c
vnet/vnet/ip/ip6.h
vnet/vnet/ip/ip6_forward.c
vnet/vnet/ip/ip_init.c
vnet/vnet/l2/l2_input.h
vnet/vnet/policer/node_funcs.c
vnet/vnet/policer/policer.c
vnet/vnet/policer/policer.h
vnet/vnet/policer/xlate.c
vnet/vnet/policer/xlate.h
vpp-api-test/vat/api_format.c
vpp/vpp-api/api.c
vpp/vpp-api/custom_dump.c
vpp/vpp-api/vpe.api

index 47e14b7..e9a7347 100644 (file)
@@ -230,11 +230,13 @@ libvnet_la_SOURCES +=                             \
   vnet/classify/vnet_classify.c                        \
   vnet/classify/ip_classify.c                  \
   vnet/classify/input_acl.c                    \
+  vnet/classify/policer_classify.c             \
   vnet/classify/vnet_classify.h
 
 nobase_include_HEADERS +=                      \
   vnet/classify/vnet_classify.h                        \
-  vnet/classify/input_acl.h
+  vnet/classify/input_acl.h                     \
+  vnet/classify/policer_classify.h
 
 ########################################
 # Layer 3 protocols go here
diff --git a/vnet/vnet/classify/policer_classify.c b/vnet/vnet/classify/policer_classify.c
new file mode 100644 (file)
index 0000000..c4c4484
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vnet/classify/policer_classify.h>
+
+static void
+vnet_policer_classify_feature_enable (vlib_main_t * vnm,
+                                      policer_classify_main_t * pcm,
+                                      u32 sw_if_index,
+                                      policer_classify_table_id_t tid,
+                                      int feature_enable)
+{
+  if (tid == POLICER_CLASSIFY_TABLE_L2)
+    {
+      l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_POLICER_CLAS,
+                                  feature_enable);
+    }
+  else
+    {
+      ip_lookup_main_t * lm;
+      ip_config_main_t * ipcm;
+      u32 ftype;
+      u32 ci;
+
+      if (tid == POLICER_CLASSIFY_TABLE_IP4)
+        {
+          lm = &ip4_main.lookup_main;
+          ftype = ip4_main.ip4_unicast_rx_feature_policer_classify;
+        }
+      else
+        {
+          lm = &ip6_main.lookup_main;
+          ftype = ip6_main.ip6_unicast_rx_feature_policer_classify;
+        }
+
+      ipcm = &lm->rx_config_mains[VNET_UNICAST];
+
+      ci = ipcm->config_index_by_sw_if_index[sw_if_index];
+      ci = (feature_enable ? vnet_config_add_feature : vnet_config_del_feature)
+        (vnm, &ipcm->config_main, ci, ftype, 0, 0);
+
+      ipcm->config_index_by_sw_if_index[sw_if_index] = ci;
+      pcm->vnet_config_main[tid] = &ipcm->config_main;
+    }
+}
+
+int vnet_set_policer_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
+                                     u32 ip4_table_index, u32 ip6_table_index,
+                                     u32 l2_table_index, u32 is_add)
+{
+  policer_classify_main_t * pcm = &policer_classify_main;
+  vnet_classify_main_t * vcm = pcm->vnet_classify_main;
+  u32 pct[POLICER_CLASSIFY_N_TABLES] = {ip4_table_index, ip6_table_index,
+                                        l2_table_index};
+  u32 ti;
+
+  /* Assume that we've validated sw_if_index in the API layer */
+
+  for (ti = 0; ti < POLICER_CLASSIFY_N_TABLES; ti++)
+    {
+      if (pct[ti] == ~0)
+        continue;
+
+      if (pool_is_free_index (vcm->tables, pct[ti]))
+        return VNET_API_ERROR_NO_SUCH_TABLE;
+
+      vec_validate_init_empty
+        (pcm->classify_table_index_by_sw_if_index[ti], sw_if_index, ~0);
+
+      /* Reject any DEL operation with wrong sw_if_index */
+      if (!is_add &&
+          (pct[ti] != pcm->classify_table_index_by_sw_if_index[ti][sw_if_index]))
+        {
+          clib_warning ("Non-existent intf_idx=%d with table_index=%d for delete",
+                        sw_if_index, pct[ti]);
+          return VNET_API_ERROR_NO_SUCH_TABLE;
+        }
+
+      /* Return ok on ADD operaton if feature is already enabled */
+      if (is_add &&
+          pcm->classify_table_index_by_sw_if_index[ti][sw_if_index] != ~0)
+          return 0;
+
+      vnet_policer_classify_feature_enable (vm, pcm, sw_if_index, ti, is_add);
+
+      if (is_add)
+        pcm->classify_table_index_by_sw_if_index[ti][sw_if_index] = pct[ti];
+      else
+        pcm->classify_table_index_by_sw_if_index[ti][sw_if_index] = ~0;
+    }
+
+
+  return 0;
+}
+
+static clib_error_t *
+set_policer_classify_command_fn (vlib_main_t * vm,
+                                 unformat_input_t * input,
+                                 vlib_cli_command_t * cmd)
+{
+  vnet_main_t * vnm = vnet_get_main();
+  u32 sw_if_index = ~0;
+  u32 ip4_table_index = ~0;
+  u32 ip6_table_index = ~0;
+  u32 l2_table_index = ~0;
+  u32 is_add = 1;
+  u32 idx_cnt = 0;
+  int rv;
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "interface %U", unformat_vnet_sw_interface,
+                    vnm, &sw_if_index))
+        ;
+      else if (unformat (input, "ip4-table %d", &ip4_table_index))
+        idx_cnt++;
+      else if (unformat (input, "ip6-table %d", &ip6_table_index))
+        idx_cnt++;
+      else if (unformat (input, "l2-table %d", &l2_table_index))
+        idx_cnt++;
+      else if (unformat (input, "del"))
+        is_add = 0;
+      else
+        break;
+    }
+
+  if (sw_if_index == ~0)
+    return clib_error_return (0, "Interface must be specified.");
+
+  if (!idx_cnt)
+    return clib_error_return (0, "Table index should be specified.");
+
+  if (idx_cnt > 1)
+    return clib_error_return (0, "Only one table index per API is allowed.");
+
+  rv = vnet_set_policer_classify_intfc(vm, sw_if_index, ip4_table_index,
+                                       ip6_table_index, l2_table_index, is_add);
+
+  switch (rv)
+    {
+    case 0:
+      break;
+
+    case VNET_API_ERROR_NO_MATCHING_INTERFACE:
+      return clib_error_return (0, "No such interface");
+
+    case VNET_API_ERROR_NO_SUCH_ENTRY:
+      return clib_error_return (0, "No such classifier table");
+    }
+  return 0;
+}
+
+VLIB_CLI_COMMAND (set_input_acl_command, static) = {
+    .path = "set policer classify",
+    .short_help =
+    "set policer classify interface <int> [ip4-table <index>]\n"
+    "  [ip6-table <index>] [l2-table <index>] [del]",
+    .function = set_policer_classify_command_fn,
+};
+
+static uword
+unformat_table_type (unformat_input_t * input, va_list * va)
+{
+  u32 * r = va_arg (*va, u32 *);
+  u32 tid;
+
+  if (unformat (input, "ip4"))
+    tid = POLICER_CLASSIFY_TABLE_IP4;
+  else if (unformat (input, "ip6"))
+    tid = POLICER_CLASSIFY_TABLE_IP6;
+  else if (unformat (input, "l2"))
+    tid = POLICER_CLASSIFY_TABLE_L2;
+  else
+    return 0;
+
+  *r = tid;
+  return 1;
+}
+static clib_error_t *
+show_policer_classify_command_fn (vlib_main_t * vm,
+                                  unformat_input_t * input,
+                                  vlib_cli_command_t * cmd)
+{
+  policer_classify_main_t * pcm = &policer_classify_main;
+  u32 type = POLICER_CLASSIFY_N_TABLES;
+  u32 * vec_tbl;
+  int i;
+
+  if (unformat (input, "type %U", unformat_table_type, &type))
+    ;
+  else
+    return clib_error_return (0, "Type must be specified.");;
+
+  if (type == POLICER_CLASSIFY_N_TABLES)
+    return clib_error_return (0, "Invalid table type.");
+
+  vec_tbl = pcm->classify_table_index_by_sw_if_index[type];
+
+  if (vec_len(vec_tbl))
+      vlib_cli_output (vm, "%10s%20s\t\t%s", "Intfc idx", "Classify table",
+                       "Interface name");
+  else
+    vlib_cli_output (vm, "No tables configured.");
+
+  for (i = 0; i < vec_len (vec_tbl); i++)
+    {
+      if (vec_elt(vec_tbl, i) == ~0)
+        continue;
+
+      vlib_cli_output (vm, "%10d%20d\t\t%U", i, vec_elt(vec_tbl, i),
+                       format_vnet_sw_if_index_name, pcm->vnet_main, i);
+    }
+
+  return 0;
+}
+
+VLIB_CLI_COMMAND (show_policer_classify_command, static) = {
+    .path = "show classify policer",
+    .short_help = "show classify policer type [ip4|ip6|l2]",
+    .function = show_policer_classify_command_fn,
+};
diff --git a/vnet/vnet/classify/policer_classify.h b/vnet/vnet/classify/policer_classify.h
new file mode 100644 (file)
index 0000000..3065644
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __included_vnet_policer_classify_h__
+#define __included_vnet_policer_classify_h__
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vnet/classify/vnet_classify.h>
+
+typedef enum {
+  POLICER_CLASSIFY_TABLE_IP4,
+  POLICER_CLASSIFY_TABLE_IP6,
+  POLICER_CLASSIFY_TABLE_L2,
+  POLICER_CLASSIFY_N_TABLES,
+} policer_classify_table_id_t;
+
+typedef enum {
+  POLICER_CLASSIFY_NEXT_INDEX_DROP,
+  POLICER_CLASSIFY_NEXT_INDEX_N_NEXT,
+} policer_classify_next_index_t;
+
+typedef struct {
+  /* Classifier table vectors */
+  u32 * classify_table_index_by_sw_if_index [POLICER_CLASSIFY_N_TABLES];
+
+  /* L2 next nodes for each feature */
+  u32 feat_next_node_index[32];
+
+  /* Convenience variables */
+  vlib_main_t * vlib_main;
+  vnet_main_t * vnet_main;
+  vnet_classify_main_t * vnet_classify_main;
+  vnet_config_main_t * vnet_config_main [POLICER_CLASSIFY_N_TABLES];
+} policer_classify_main_t;
+
+policer_classify_main_t policer_classify_main;
+
+int vnet_set_policer_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
+                                     u32 ip4_table_index, u32 ip6_table_index,
+                                     u32 l2_table_index, u32 is_add);
+
+#endif /* __included_vnet_policer_classify_h__ */
index 11d3714..23aa515 100644 (file)
@@ -88,6 +88,14 @@ vnet_classify_register_unformat_acl_next_index_fn (unformat_function_t * fn)
   vec_add1 (cm->unformat_acl_next_index_fns, fn);
 }
 
+void
+vnet_classify_register_unformat_policer_next_index_fn (unformat_function_t * fn)
+{
+  vnet_classify_main_t * cm = &vnet_classify_main;
+
+  vec_add1 (cm->unformat_policer_next_index_fns, fn);
+}
+
 void vnet_classify_register_unformat_opaque_index_fn (unformat_function_t * fn)
 {
   vnet_classify_main_t * cm = &vnet_classify_main;
@@ -1141,6 +1149,37 @@ uword unformat_acl_next_index (unformat_input_t * input, va_list * args)
   return 1;
 }
 
+uword unformat_policer_next_index (unformat_input_t * input, va_list * args)
+{
+  u32 * next_indexp = va_arg (*args, u32 *);
+  vnet_classify_main_t * cm = &vnet_classify_main;
+  u32 next_index = 0;
+  u32 tmp;
+  int i;
+
+  /* First try registered unformat fns, allowing override... */
+  for (i = 0; i < vec_len (cm->unformat_policer_next_index_fns); i++)
+    {
+      if (unformat (input, "%U", cm->unformat_policer_next_index_fns[i], &tmp))
+        {
+          next_index = tmp;
+          goto out;
+        }
+    }
+
+  if (unformat (input, "%d", &tmp))
+    {
+      next_index = tmp;
+      goto out;
+    }
+
+  return 0;
+
+ out:
+  *next_indexp = next_index;
+  return 1;
+}
+
 static clib_error_t *
 classify_table_command_fn (vlib_main_t * vm,
                            unformat_input_t * input,
@@ -1763,6 +1802,9 @@ classify_session_command_fn (vlib_main_t * vm,
       else if (unformat (input, "acl-hit-next %U", unformat_acl_next_index,
                          &hit_next_index))
         ;
+      else if (unformat (input, "policer-hit-next %U",
+                         unformat_policer_next_index, &hit_next_index))
+        ;
       else if (unformat (input, "opaque-index %lld", &opaque_index))
         ;
       else if (unformat (input, "match %U", unformat_classify_match,
@@ -1813,7 +1855,8 @@ classify_session_command_fn (vlib_main_t * vm,
 VLIB_CLI_COMMAND (classify_session_command, static) = {
     .path = "classify session",
     .short_help = 
-    "classify session [hit-next|l2-hit-next|acl-hit-next <next_index>]"
+    "classify session [hit-next|l2-hit-next|acl-hit-next <next_index>|"
+    "policer-hit-next <policer_name>]"
     "\n table-index <nn> match [hex] [l2] [l3 ip4] [opaque-index <index>]",
     .function = classify_session_command_fn,
 };
index b19704e..f609aaa 100644 (file)
@@ -162,6 +162,7 @@ struct _vnet_classify_main {
   unformat_function_t ** unformat_l2_next_index_fns;
   unformat_function_t ** unformat_ip_next_index_fns;
   unformat_function_t ** unformat_acl_next_index_fns;
+  unformat_function_t ** unformat_policer_next_index_fns;
   unformat_function_t ** unformat_opaque_index_fns;
 
   /* convenience variables */
@@ -484,6 +485,9 @@ void vnet_classify_register_unformat_l2_next_index_fn
 void vnet_classify_register_unformat_acl_next_index_fn 
 (unformat_function_t * fn);
 
+void  vnet_classify_register_unformat_policer_next_index_fn
+(unformat_function_t * fn);
+
 void vnet_classify_register_unformat_opaque_index_fn (unformat_function_t * fn);
 
 #endif /* __included_vnet_classify_h__ */
index 5ea4ebf..fb04893 100644 (file)
@@ -137,6 +137,7 @@ typedef struct ip4_main_t {
   u32 ip4_unicast_rx_feature_check_access;
   u32 ip4_unicast_rx_feature_source_reachable_via_rx;
   u32 ip4_unicast_rx_feature_source_reachable_via_any;
+  u32 ip4_unicast_rx_feature_policer_classify;
   u32 ip4_unicast_rx_feature_ipsec;
   u32 ip4_unicast_rx_feature_vpath;
   u32 ip4_unicast_rx_feature_lookup;
index d2e761f..2ccdd37 100644 (file)
@@ -1380,11 +1380,18 @@ VNET_IP4_UNICAST_FEATURE_INIT (ip4_source_check_1, static) = {
 
 VNET_IP4_UNICAST_FEATURE_INIT (ip4_source_check_2, static) = {
   .node_name = "ip4-source-check-via-any",
-  .runs_before = {"ipsec-input-ip4", 0},
+  .runs_before = {"ip4-policer-classify", 0},
   .feature_index = 
   &ip4_main.ip4_unicast_rx_feature_source_reachable_via_any,
 };
 
+VNET_IP4_UNICAST_FEATURE_INIT (ip4_policer_classify, static) = {
+  .node_name = "ip4-policer-classify",
+  .runs_before = {"ipsec-input-ip4", 0},
+  .feature_index =
+  &ip4_main.ip4_unicast_rx_feature_policer_classify,
+};
+
 VNET_IP4_UNICAST_FEATURE_INIT (ip4_ipsec, static) = {
   .node_name = "ipsec-input-ip4",
   .runs_before = {"vpath-input-ip4", 0},
index 22d1a4f..3d6c9f4 100644 (file)
@@ -148,6 +148,7 @@ typedef struct ip6_main_t {
 
   /* Built-in unicast feature path indices, see ip_feature_init_cast(...)  */
   u32 ip6_unicast_rx_feature_check_access;
+  u32 ip6_unicast_rx_feature_policer_classify;
   u32 ip6_unicast_rx_feature_ipsec;
   u32 ip6_unicast_rx_feature_l2tp_decap;
   u32 ip6_unicast_rx_feature_vpath;
index 823daa6..57057a7 100644 (file)
@@ -1260,10 +1260,16 @@ VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip6_sw_interface_admin_up_down);
 /* Built-in ip6 unicast rx feature path definition */
 VNET_IP6_UNICAST_FEATURE_INIT (ip6_inacl, static) = {
   .node_name = "ip6-inacl", 
-  .runs_before = {"ipsec-input-ip6", 0}, 
+  .runs_before = {"ip6-policer-classify", 0},
   .feature_index = &ip6_main.ip6_unicast_rx_feature_check_access,
 };
 
+VNET_IP6_UNICAST_FEATURE_INIT (ip6_policer_classify, static) = {
+  .node_name = "ip6-policer-classify",
+  .runs_before = {"ipsec-input-ip6", 0},
+  .feature_index = &ip6_main.ip6_unicast_rx_feature_policer_classify,
+};
+
 VNET_IP6_UNICAST_FEATURE_INIT (ip6_ipsec, static) = {
   .node_name = "ipsec-input-ip6",
   .runs_before = {"l2tp-decap", 0},
index 8b6659d..c0c1c95 100644 (file)
@@ -133,6 +133,9 @@ do {                                                \
   if ((error = vlib_call_init_function (vm, input_acl_init)))
     return error;
 
+  if ((error = vlib_call_init_function (vm, policer_classify_init)))
+    return error;
+
   return error;
 }
 
index 50649e7..f040755 100644 (file)
@@ -109,7 +109,8 @@ l2input_bd_config_from_index (l2input_main_t * l2im, u32 bd_index)
  _(ACL,           "l2-input-acl")               \
  _(QOS,           "feature-bitmap-drop")        \
  _(CFM,           "feature-bitmap-drop")        \
- _(SPAN,          "feature-bitmap-drop")
+ _(SPAN,          "feature-bitmap-drop")        \
+ _(POLICER_CLAS,  "l2-policer-classify")
 
 // Feature bitmap positions
 typedef enum {
index 6147ea5..0858a86 100644 (file)
@@ -19,6 +19,8 @@
 #include <vnet/vnet.h>
 #include <vnet/policer/policer.h>
 #include <vnet/ip/ip.h>
+#include <vnet/classify/policer_classify.h>
+#include <vnet/classify/vnet_classify.h>
 
 #define IP4_NON_DSCP_BITS 0x03
 #define IP4_DSCP_SHIFT    2
@@ -93,6 +95,31 @@ void vnet_policer_mark (vlib_buffer_t * b, u8 dscp)
     }
 }
 
+static_always_inline
+u8 vnet_policer_police (vlib_main_t * vm,
+                        vlib_buffer_t * b,
+                        u32 policer_index,
+                        u64 time_in_policer_periods,
+                        policer_result_e packet_color)
+{
+  u8 act;
+  u32 len;
+  u32 col;
+  policer_read_response_type_st *pol;
+  vnet_policer_main_t * pm = &vnet_policer_main;
+
+  len = vlib_buffer_length_in_chain (vm, b);
+  pol = &pm->policers [policer_index];
+  col = vnet_police_packet (pol, len,
+                            packet_color,
+                            time_in_policer_periods);
+  act = pol->action[col];
+  if (PREDICT_TRUE(act == SSE2_QOS_ACTION_MARK_AND_TRANSMIT))
+      vnet_policer_mark(b, pol->mark_dscp[col]);
+
+  return act;
+ }
+
 static inline
 uword vnet_policer_inline (vlib_main_t * vm,
                            vlib_node_runtime_t * node,
@@ -126,9 +153,6 @@ uword vnet_policer_inline (vlib_main_t * vm,
           u32 next0, next1;
           u32 sw_if_index0, sw_if_index1;
           u32 pi0 = 0, pi1 = 0;
-          u32 len0, len1;
-          u32 col0, col1;
-          policer_read_response_type_st * pol0, * pol1;
           u8 act0, act1;
           
          /* Prefetch next iteration. */
@@ -182,19 +206,11 @@ uword vnet_policer_inline (vlib_main_t * vm,
                 pm->policer_index_by_sw_if_index [sw_if_index1];
             }
 
-          len0 = vlib_buffer_length_in_chain (vm, b0);
-          pol0 = &pm->policers [pi0];
-          col0 = vnet_police_packet (pol0, len0, 
-                                     POLICE_CONFORM /* no chaining */,
-                                     time_in_policer_periods);
-          act0 = pol0->action[col0];
+          act0 = vnet_policer_police(vm, b0, pi0, time_in_policer_periods,
+            POLICE_CONFORM /* no chaining */);
 
-          len1 = vlib_buffer_length_in_chain (vm, b1);
-          pol1 = &pm->policers [pi1];
-          col1 = vnet_police_packet (pol1, len1, 
-                                     POLICE_CONFORM /* no chaining */,
-                                     time_in_policer_periods);
-          act1 = pol1->action[col1];
+          act1 = vnet_policer_police(vm, b1, pi1, time_in_policer_periods,
+            POLICE_CONFORM /* no chaining */);
 
           if (PREDICT_FALSE(act0 == SSE2_QOS_ACTION_DROP)) /* drop action */
             {
@@ -203,8 +219,6 @@ uword vnet_policer_inline (vlib_main_t * vm,
             }
           else /* transmit or mark-and-transmit action */
             {
-              if (PREDICT_TRUE(act0 == SSE2_QOS_ACTION_MARK_AND_TRANSMIT))
-                vnet_policer_mark(b0, pol0->mark_dscp[col0]);
               transmitted++;
             }
 
@@ -215,8 +229,6 @@ uword vnet_policer_inline (vlib_main_t * vm,
             }
           else /* transmit or mark-and-transmit action */
             {
-              if (PREDICT_TRUE(act1 == SSE2_QOS_ACTION_MARK_AND_TRANSMIT))
-                vnet_policer_mark(b1, pol1->mark_dscp[col1]);
               transmitted++;
             }
 
@@ -252,9 +264,6 @@ uword vnet_policer_inline (vlib_main_t * vm,
           u32 next0;
           u32 sw_if_index0;
           u32 pi0 = 0;
-          u32 len0;
-          u32 col0;
-          policer_read_response_type_st * pol0;
           u8 act0;
 
          bi0 = from[0];
@@ -282,13 +291,9 @@ uword vnet_policer_inline (vlib_main_t * vm,
                 pm->policer_index_by_sw_if_index [sw_if_index0];
             }
 
-          len0 = vlib_buffer_length_in_chain (vm, b0);
-          pol0 = &pm->policers [pi0];
-          col0 = vnet_police_packet (pol0, len0, 
-                                     POLICE_CONFORM /* no chaining */,
-                                     time_in_policer_periods);
-          act0 = pol0->action[col0];
-          
+          act0 = vnet_policer_police(vm, b0, pi0, time_in_policer_periods,
+            POLICE_CONFORM /* no chaining */);
+
           if (PREDICT_FALSE(act0 == SSE2_QOS_ACTION_DROP)) /* drop action */
             {
               next0 = VNET_POLICER_NEXT_DROP;
@@ -296,8 +301,6 @@ uword vnet_policer_inline (vlib_main_t * vm,
             }
           else /* transmit or mark-and-transmit action */
             {
-              if (PREDICT_TRUE(act0 == SSE2_QOS_ACTION_MARK_AND_TRANSMIT))
-                vnet_policer_mark(b0, pol0->mark_dscp[col0]);
               transmitted++;
             }
           
@@ -507,3 +510,415 @@ VLIB_CLI_COMMAND (test_patch_command, static) = {
 
 
 #endif /* TEST_CODE */
+
+
+typedef struct {
+  u32 sw_if_index;
+  u32 next_index;
+  u32 table_index;
+  u32 offset;
+  u32 policer_index;
+} policer_classify_trace_t;
+
+static u8 *
+format_policer_classify_trace (u8 * s, va_list * args)
+{
+  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+  policer_classify_trace_t * t = va_arg (*args, policer_classify_trace_t *);
+
+  s = format (s, "POLICER_CLASSIFY: sw_if_index %d next %d table %d offset %d"
+              " policer_index %d",
+              t->sw_if_index, t->next_index, t->table_index, t->offset,
+              t->policer_index);
+  return s;
+}
+
+#define foreach_policer_classify_error                 \
+_(MISS, "Policer classify misses")                     \
+_(HIT, "Policer classify hits")                        \
+_(CHAIN_HIT, "Polcier classify hits after chain walk") \
+_(DROP, "Policer classify action drop")
+
+typedef enum {
+#define _(sym,str) POLICER_CLASSIFY_ERROR_##sym,
+  foreach_policer_classify_error
+#undef _
+  POLICER_CLASSIFY_N_ERROR,
+} policer_classify_error_t;
+
+static char * policer_classify_error_strings[] = {
+#define _(sym,string) string,
+  foreach_policer_classify_error
+#undef _
+};
+
+static inline uword
+policer_classify_inline (vlib_main_t * vm,
+                         vlib_node_runtime_t * node,
+                         vlib_frame_t * frame,
+                         policer_classify_table_id_t tid)
+{
+  u32 n_left_from, * from, * to_next;
+  policer_classify_next_index_t next_index;
+  policer_classify_main_t * pcm = &policer_classify_main;
+  vnet_classify_main_t * vcm = pcm->vnet_classify_main;
+  f64 now = vlib_time_now (vm);
+  u32 hits = 0;
+  u32 misses = 0;
+  u32 chain_hits = 0;
+  u32 drop = 0;
+  u32 n_next_nodes;
+  u64 time_in_policer_periods;
+
+  time_in_policer_periods =
+    clib_cpu_time_now() >> POLICER_TICKS_PER_PERIOD_SHIFT;
+
+  n_next_nodes = node->n_next_nodes;
+
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+
+  /* First pass: compute hashes */
+  while (n_left_from > 2)
+    {
+      vlib_buffer_t * b0, * b1;
+      u32 bi0, bi1;
+      u8 * h0, * h1;
+      u32 sw_if_index0, sw_if_index1;
+      u32 table_index0, table_index1;
+      vnet_classify_table_t * t0, * t1;
+
+      /* Prefetch next iteration */
+      {
+        vlib_buffer_t * p1, * p2;
+
+        p1 = vlib_get_buffer (vm, from[1]);
+        p2 = vlib_get_buffer (vm, from[2]);
+
+        vlib_prefetch_buffer_header (p1, STORE);
+        CLIB_PREFETCH (p1->data, CLIB_CACHE_LINE_BYTES, STORE);
+        vlib_prefetch_buffer_header (p2, STORE);
+        CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
+      }
+
+      bi0 = from[0];
+      b0 = vlib_get_buffer (vm, bi0);
+      h0 = b0->data;
+
+      bi1 = from[1];
+      b1 = vlib_get_buffer (vm, bi1);
+      h1 = b1->data;
+
+      sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+      table_index0 = pcm->classify_table_index_by_sw_if_index[tid][sw_if_index0];
+
+      sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
+      table_index1 = pcm->classify_table_index_by_sw_if_index[tid][sw_if_index1];
+
+      t0 = pool_elt_at_index (vcm->tables, table_index0);
+
+      t1 = pool_elt_at_index (vcm->tables, table_index1);
+
+      vnet_buffer(b0)->l2_classify.hash =
+        vnet_classify_hash_packet (t0, (u8 *) h0);
+
+      vnet_classify_prefetch_bucket (t0, vnet_buffer(b0)->l2_classify.hash);
+
+      vnet_buffer(b1)->l2_classify.hash =
+        vnet_classify_hash_packet (t1, (u8 *) h1);
+
+      vnet_classify_prefetch_bucket (t1, vnet_buffer(b1)->l2_classify.hash);
+
+      vnet_buffer(b0)->l2_classify.table_index = table_index0;
+
+      vnet_buffer(b1)->l2_classify.table_index = table_index1;
+
+      from += 2;
+      n_left_from -= 2;
+    }
+
+  while (n_left_from > 0)
+    {
+      vlib_buffer_t * b0;
+      u32 bi0;
+      u8 * h0;
+      u32 sw_if_index0;
+      u32 table_index0;
+      vnet_classify_table_t * t0;
+
+      bi0 = from[0];
+      b0 = vlib_get_buffer (vm, bi0);
+      h0 = b0->data;
+
+      sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+      table_index0 = pcm->classify_table_index_by_sw_if_index[tid][sw_if_index0];
+
+      t0 = pool_elt_at_index (vcm->tables, table_index0);
+      vnet_buffer(b0)->l2_classify.hash =
+        vnet_classify_hash_packet (t0, (u8 *) h0);
+
+      vnet_buffer(b0)->l2_classify.table_index = table_index0;
+      vnet_classify_prefetch_bucket (t0, vnet_buffer(b0)->l2_classify.hash);
+
+      from++;
+      n_left_from--;
+    }
+
+  next_index = node->cached_next_index;
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+
+  while (n_left_from > 0)
+    {
+      u32 n_left_to_next;
+
+      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+      /* Not enough load/store slots to dual loop... */
+      while (n_left_from > 0 && n_left_to_next > 0)
+        {
+          u32 bi0;
+          vlib_buffer_t * b0;
+          u32 next0 = POLICER_CLASSIFY_NEXT_INDEX_DROP;
+          u32 table_index0;
+          vnet_classify_table_t * t0;
+          vnet_classify_entry_t * e0;
+          u64 hash0;
+          u8 * h0;
+          u8 act0;
+
+          /* Stride 3 seems to work best */
+          if (PREDICT_TRUE (n_left_from > 3))
+            {
+              vlib_buffer_t * p1 = vlib_get_buffer(vm, from[3]);
+              vnet_classify_table_t * tp1;
+              u32 table_index1;
+              u64 phash1;
+
+              table_index1 = vnet_buffer(p1)->l2_classify.table_index;
+
+              if (PREDICT_TRUE (table_index1 != ~0))
+                {
+                  tp1 = pool_elt_at_index (vcm->tables, table_index1);
+                  phash1 = vnet_buffer(p1)->l2_classify.hash;
+                  vnet_classify_prefetch_entry (tp1, phash1);
+                }
+            }
+
+          /* Speculatively enqueue b0 to the current next frame */
+          bi0 = from[0];
+          to_next[0] = bi0;
+          from += 1;
+          to_next += 1;
+          n_left_from -= 1;
+          n_left_to_next -= 1;
+
+          b0 = vlib_get_buffer (vm, bi0);
+          h0 = b0->data;
+          table_index0 = vnet_buffer(b0)->l2_classify.table_index;
+          e0 = 0;
+          t0 = 0;
+
+          if (tid == POLICER_CLASSIFY_TABLE_L2)
+            {
+              /* Feature bitmap update */
+              vnet_buffer(b0)->l2.feature_bitmap &= ~L2INPUT_FEAT_POLICER_CLAS;
+              /* Determine the next node */
+              next0 = feat_bitmap_get_next_node_index(pcm->feat_next_node_index,
+                vnet_buffer(b0)->l2.feature_bitmap);
+            }
+          else
+            vnet_get_config_data (pcm->vnet_config_main[tid],
+                                  &b0->current_config_index,
+                                  &next0,
+                                  /* # bytes of config data */ 0);
+
+          vnet_buffer(b0)->l2_classify.opaque_index = ~0;
+
+          if (PREDICT_TRUE(table_index0 != ~0))
+            {
+              hash0 = vnet_buffer(b0)->l2_classify.hash;
+              t0 = pool_elt_at_index (vcm->tables, table_index0);
+              e0 = vnet_classify_find_entry (t0, (u8 *) h0, hash0, now);
+
+              if (e0)
+                {
+                  act0 = vnet_policer_police(vm,
+                                             b0,
+                                             e0->next_index,
+                                             time_in_policer_periods,
+                                             e0->opaque_index);
+                  if (PREDICT_FALSE(act0 == SSE2_QOS_ACTION_DROP))
+                    {
+                      next0 = POLICER_CLASSIFY_NEXT_INDEX_DROP;
+                      b0->error = node->errors[POLICER_CLASSIFY_ERROR_DROP];
+                      drop++;
+                    }
+                  hits++;
+                }
+              else
+                {
+                  while (1)
+                    {
+                      if (PREDICT_TRUE(t0->next_table_index != ~0))
+                        {
+                          t0 = pool_elt_at_index (vcm->tables,
+                                                  t0->next_table_index);
+                        }
+                      else
+                        {
+                          next0 = (t0->miss_next_index < n_next_nodes)?
+                                   t0->miss_next_index:next0;
+                          misses++;
+                          break;
+                        }
+
+                      hash0 = vnet_classify_hash_packet (t0, (u8 *) h0);
+                      e0 = vnet_classify_find_entry (t0, (u8 *) h0, hash0, now);
+                      if (e0)
+                        {
+                          act0 = vnet_policer_police(vm,
+                                                     b0,
+                                                     e0->next_index,
+                                                     time_in_policer_periods,
+                                                     e0->opaque_index);
+                          if (PREDICT_FALSE(act0 == SSE2_QOS_ACTION_DROP))
+                            {
+                              next0 = POLICER_CLASSIFY_NEXT_INDEX_DROP;
+                              b0->error = node->errors[POLICER_CLASSIFY_ERROR_DROP];
+                              drop++;
+                            }
+                          hits++;
+                          chain_hits++;
+                          break;
+                        }
+                    }
+                }
+            }
+          if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
+                            && (b0->flags & VLIB_BUFFER_IS_TRACED)))
+            {
+              policer_classify_trace_t * t =
+                vlib_add_trace (vm, node, b0, sizeof (*t));
+              t->sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX];
+              t->next_index = next0;
+              t->table_index = t0 ? t0 - vcm->tables : ~0;
+              t->offset = e0 ? vnet_classify_get_offset (t0, e0): ~0;
+              t->policer_index = e0 ? e0->next_index: ~0;
+            }
+
+          /* Verify speculative enqueue, maybe switch current next frame */
+          vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+                                           n_left_to_next, bi0, next0);
+        }
+
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, node->node_index,
+                               POLICER_CLASSIFY_ERROR_MISS,
+                               misses);
+  vlib_node_increment_counter (vm, node->node_index,
+                               POLICER_CLASSIFY_ERROR_HIT,
+                               hits);
+  vlib_node_increment_counter (vm, node->node_index,
+                               POLICER_CLASSIFY_ERROR_CHAIN_HIT,
+                               chain_hits);
+  vlib_node_increment_counter (vm, node->node_index,
+                               POLICER_CLASSIFY_ERROR_DROP,
+                               drop);
+
+  return frame->n_vectors;
+}
+
+static uword
+ip4_policer_classify (vlib_main_t * vm,
+                      vlib_node_runtime_t * node,
+                      vlib_frame_t * frame)
+{
+  return policer_classify_inline(vm, node, frame, POLICER_CLASSIFY_TABLE_IP4);
+}
+
+VLIB_REGISTER_NODE (ip4_policer_classify_node) = {
+  .function = ip4_policer_classify,
+  .name = "ip4-policer-classify",
+  .vector_size = sizeof (u32),
+  .format_trace = format_policer_classify_trace,
+  .n_errors = ARRAY_LEN(policer_classify_error_strings),
+  .error_strings = policer_classify_error_strings,
+  .n_next_nodes = POLICER_CLASSIFY_NEXT_INDEX_N_NEXT,
+  .next_nodes = {
+    [POLICER_CLASSIFY_NEXT_INDEX_DROP] = "error-drop",
+  },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_policer_classify_node, ip4_policer_classify);
+
+static uword
+ip6_policer_classify (vlib_main_t * vm,
+                      vlib_node_runtime_t * node,
+                      vlib_frame_t * frame)
+{
+  return policer_classify_inline(vm, node, frame, POLICER_CLASSIFY_TABLE_IP6);
+}
+
+VLIB_REGISTER_NODE (ip6_policer_classify_node) = {
+  .function = ip6_policer_classify,
+  .name = "ip6-policer-classify",
+  .vector_size = sizeof (u32),
+  .format_trace = format_policer_classify_trace,
+  .n_errors = ARRAY_LEN(policer_classify_error_strings),
+  .error_strings = policer_classify_error_strings,
+  .n_next_nodes = POLICER_CLASSIFY_NEXT_INDEX_N_NEXT,
+  .next_nodes = {
+    [POLICER_CLASSIFY_NEXT_INDEX_DROP] = "error-drop",
+  },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_policer_classify_node, ip6_policer_classify);
+
+static uword
+l2_policer_classify (vlib_main_t * vm,
+                     vlib_node_runtime_t * node,
+                     vlib_frame_t * frame)
+{
+  return policer_classify_inline(vm, node, frame, POLICER_CLASSIFY_TABLE_L2);
+}
+
+VLIB_REGISTER_NODE (l2_policer_classify_node) = {
+  .function = l2_policer_classify,
+  .name = "l2-policer-classify",
+  .vector_size = sizeof (u32),
+  .format_trace = format_policer_classify_trace,
+  .n_errors = ARRAY_LEN(policer_classify_error_strings),
+  .error_strings = policer_classify_error_strings,
+  .n_next_nodes = POLICER_CLASSIFY_NEXT_INDEX_N_NEXT,
+  .next_nodes = {
+    [POLICER_CLASSIFY_NEXT_INDEX_DROP] = "error-drop",
+  },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (l2_policer_classify_node, l2_policer_classify);
+
+
+static clib_error_t *
+policer_classify_init (vlib_main_t *vm)
+{
+  policer_classify_main_t * pcm = &policer_classify_main;
+
+  pcm->vlib_main = vm;
+  pcm->vnet_main = vnet_get_main();
+  pcm->vnet_classify_main = &vnet_classify_main;
+
+  /* Initialize L2 feature next-node indexes */
+  feat_bitmap_init_next_nodes(vm,
+                              l2_policer_classify_node.index,
+                              L2INPUT_N_FEAT,
+                              l2input_get_feat_names(),
+                              pcm->feat_next_node_index);
+
+  return 0;
+}
+
+VLIB_INIT_FUNCTION (policer_classify_init);
index 8ffa967..f60f7a7 100644 (file)
  */
 #include <stdint.h>
 #include <vnet/policer/policer.h>
+#include <vnet/classify/vnet_classify.h>
 
 clib_error_t *
 policer_add_del (vlib_main_t *vm,
-                 u8 * name, sse2_qos_pol_cfg_params_st * cfg,
+                 u8 * name,
+                 sse2_qos_pol_cfg_params_st * cfg,
+                 u32 * policer_index,
                  u8 is_add)
 {
   vnet_policer_main_t *pm = &vnet_policer_main;
   policer_read_response_type_st test_policer;
+  policer_read_response_type_st * policer;
   uword * p;
+  u32 pi;
   int rv;
 
+  p = hash_get_mem (pm->policer_config_by_name, name);
+
   if (is_add == 0)
     {
-      p = hash_get_mem (pm->policer_config_by_name, name);
       if (p == 0)
         {
           vec_free(name);
           return clib_error_return (0, "No such policer configuration");
         }
       hash_unset_mem (pm->policer_config_by_name, name);
+      hash_unset_mem (pm->policer_index_by_name, name);
       vec_free(name);
       return 0;
     }
 
+  if (p != 0)
+    {
+      vec_free(name);
+      return clib_error_return (0, "Policer already exists");
+    }
+
   /* Vet the configuration before adding it to the table */
   rv = sse2_pol_logical_2_physical (cfg, &test_policer);
 
@@ -55,6 +68,11 @@ policer_add_del (vlib_main_t *vm,
       clib_memcpy (pp, &test_policer, sizeof (*pp));
 
       hash_set_mem (pm->policer_config_by_name, name, cp - pm->configs);
+      pool_get_aligned (pm->policers, policer, CLIB_CACHE_LINE_BYTES);
+      policer[0] = pp[0];
+      pi = policer - pm->policers;
+      hash_set_mem (pm->policer_index_by_name, name, pi);
+      *policer_index = pi;
     }
   else
     {
@@ -348,6 +366,44 @@ unformat_policer_action (unformat_input_t * input, va_list * va)
   return 0;
 }
 
+static uword
+unformat_policer_classify_next_index (unformat_input_t * input, va_list * va)
+{
+  u32 * r = va_arg (*va, u32 *);
+  vnet_policer_main_t *pm = &vnet_policer_main;
+  uword * p;
+  u8 * match_name = 0;
+
+  if (unformat (input, "%s", &match_name))
+    ;
+  else
+    return 0;
+
+  p = hash_get_mem (pm->policer_index_by_name, match_name);
+
+  if (p == 0)
+    return 0;
+
+  *r = p[0];
+
+  return 1;
+}
+
+static uword
+unformat_policer_classify_precolor (unformat_input_t * input, va_list * va)
+{
+  u32 * r = va_arg (*va, u32 *);
+
+  if (unformat (input, "conform-color"))
+    *r = POLICE_CONFORM;
+  else if (unformat (input, "exceed-color"))
+    *r = POLICE_EXCEED;
+  else
+    return 0;
+
+  return 1;
+}
+
 #define foreach_config_param                    \
 _(eb)                                           \
 _(cb)                                           \
@@ -367,6 +423,7 @@ configure_policer_command_fn (vlib_main_t * vm,
   unformat_input_t _line_input, * line_input = &_line_input;
   u8 is_add = 1;
   u8 * name = 0;
+  u32 pi;
 
   /* Get a line of input. */
   if (! unformat_user (input, unformat_line_input, line_input))
@@ -380,6 +437,8 @@ configure_policer_command_fn (vlib_main_t * vm,
         is_add = 0;
       else if (unformat(line_input, "name %s", &name))
         ;
+      else if (unformat(line_input, "color-aware"))
+        c.color_aware = 1;
 
 #define _(a) else if (unformat (line_input, "%U", unformat_policer_##a, &c)) ;
       foreach_config_param
@@ -392,7 +451,7 @@ configure_policer_command_fn (vlib_main_t * vm,
 
   unformat_free (line_input);
 
-  return policer_add_del(vm, name, &c, is_add);
+  return policer_add_del(vm, name, &c, &pi, is_add);
 }
 
 VLIB_CLI_COMMAND (configure_policer_command, static) = {
@@ -453,6 +512,13 @@ clib_error_t *policer_init (vlib_main_t * vm)
   pm->vnet_main = vnet_get_main();
 
   pm->policer_config_by_name = hash_create_string (0, sizeof (uword));
+  pm->policer_index_by_name = hash_create_string (0, sizeof (uword));
+
+  vnet_classify_register_unformat_policer_next_index_fn
+    (unformat_policer_classify_next_index);
+  vnet_classify_register_unformat_opaque_index_fn
+    (unformat_policer_classify_precolor);
+
   return 0;
 }
 
index fba866f..beef5b6 100644 (file)
@@ -32,6 +32,9 @@ typedef struct {
   /* Config by name hash */
   uword * policer_config_by_name;
 
+  /* Policer by name hash */
+  uword * policer_index_by_name;
+
   /* Policer by sw_if_index vector */
   u32 * policer_index_by_sw_if_index;
 
@@ -85,7 +88,9 @@ typedef enum {
 
 u8 * format_policer_instance (u8 * s, va_list * va);
 clib_error_t * policer_add_del (vlib_main_t *vm,
-                                u8 * name, sse2_qos_pol_cfg_params_st * cfg,
+                                u8 * name,
+                                sse2_qos_pol_cfg_params_st * cfg,
+                                u32 * policer_index,
                                 u8 is_add);
 
 #endif /* __included_policer_h__ */
index f47982e..934c488 100644 (file)
@@ -1045,10 +1045,6 @@ x86_pol_compute_hw_params (sse2_qos_pol_cfg_params_st *cfg,
                (cfg->rfc == SSE2_QOS_POLICER_TYPE_2R3C_RFC_4115)) {
         // Two-rate policer
 
-        if (cfg->rfc == SSE2_QOS_POLICER_TYPE_2R3C_RFC_4115) {
-            hw->color_aware = 1;
-        }
-
         if ((cfg->rb.kbps.cir_kbps == 0) || (cfg->rb.kbps.eir_kbps == 0) || (cfg->rb.kbps.eir_kbps < cfg->rb.kbps.cir_kbps) ||
                 (cfg->rb.kbps.cb_bytes == 0) || (cfg->rb.kbps.eb_bytes == 0)) {
             SSE2_QOS_DEBUG_ERROR("Config parameter validation failed.");
@@ -1136,6 +1132,8 @@ sse2_pol_logical_2_physical (sse2_qos_pol_cfg_params_st    *cfg,
     phys->action[POLICE_VIOLATE]    = cfg->violate_action.action_type;
     phys->mark_dscp[POLICE_VIOLATE] = cfg->violate_action.dscp;
 
+    phys->color_aware = cfg->color_aware;
+
 #if !defined (INTERNAL_SS) && !defined (X86)
     // convert logical into hw params which involves qos calculations
     rc = sse2_pol_compute_hw_params(&kbps_cfg, &pol_hw);
index d3fdede..69a58d2 100644 (file)
@@ -136,6 +136,7 @@ typedef struct sse2_qos_pol_cfg_params_st_ {
     uint8_t  rate_type;        /* sse2_qos_rate_type_en */
     uint8_t  rnd_type;         /* sse2_qos_round_type_en */
     uint8_t  rfc;              /* sse2_qos_policer_type_en */
+    uint8_t  color_aware;
     uint8_t  overwrite_bucket; /* for debugging purposes */
     uint32_t current_bucket;   /* for debugging purposes */
     uint32_t extended_bucket;  /* for debugging purposes */
index fa37989..dac6788 100644 (file)
@@ -34,6 +34,7 @@
 #include <vnet/l2/l2_classify.h>
 #include <vnet/l2/l2_vtr.h>
 #include <vnet/classify/input_acl.h>
+#include <vnet/classify/policer_classify.h>
 #include <vnet/mpls-gre/mpls.h>
 #if DPDK > 0
 #include <vnet/ipsec/ipsec.h>
@@ -46,6 +47,7 @@
 #include <vnet/ip/ip6_hop_by_hop.h>
 #include <vnet/policer/xlate.h>
 #include <vnet/policer/policer.h>
+#include <vnet/policer/police.h>
 
 #include "vat/json_format.h"
 
@@ -450,6 +452,25 @@ unformat_policer_action_type (unformat_input_t * input, va_list * va)
   return 1;
 }
 
+uword
+unformat_classify_table_type (unformat_input_t * input, va_list * va)
+{
+  u32 * r = va_arg (*va, u32 *);
+  u32 tid;
+
+  if (unformat (input, "ip4"))
+    tid = POLICER_CLASSIFY_TABLE_IP4;
+  else if (unformat (input, "ip6"))
+    tid = POLICER_CLASSIFY_TABLE_IP6;
+  else if (unformat (input, "l2"))
+    tid = POLICER_CLASSIFY_TABLE_L2;
+  else
+    return 0;
+
+  *r = tid;
+  return 1;
+}
+
 u8 * format_ip4_address (u8 * s, va_list * args)
 {
   u8 * a = va_arg (*args, u8 *);
@@ -2513,8 +2534,8 @@ static void vl_api_policer_details_t_handler
              format_policer_type, mp->type,
              ntohl(mp->cir),
              ntohl(mp->eir),
-             ntohl(mp->cb),
-             ntohl(mp->eb),
+             clib_net_to_host_u64(mp->cb),
+             clib_net_to_host_u64(mp->eb),
              format_policer_rate_type, mp->rate_type,
              format_policer_round_type, mp->round_type,
              mp->single_rate ? "single" : "dual",
@@ -2691,6 +2712,42 @@ static void vl_api_classify_table_by_interface_reply_t_handler_json (vl_api_clas
     vam->result_ready = 1;
 }
 
+static void vl_api_policer_add_del_reply_t_handler
+(vl_api_policer_add_del_reply_t * mp)
+{
+    vat_main_t * vam = &vat_main;
+    i32 retval = ntohl(mp->retval);
+    if (vam->async_mode) {
+        vam->async_errors += (retval < 0);
+    } else {
+        vam->retval = retval;
+        vam->result_ready = 1;
+        if (retval == 0 && mp->policer_index != 0xFFFFFFFF)
+            /*
+             * Note: this is just barely thread-safe, depends on
+             * the main thread spinning waiting for an answer...
+             */
+            errmsg ("policer index %d\n", ntohl(mp->policer_index));
+    }
+}
+
+static void vl_api_policer_add_del_reply_t_handler_json
+(vl_api_policer_add_del_reply_t * mp)
+{
+    vat_main_t * vam = &vat_main;
+    vat_json_node_t node;
+
+    vat_json_init_object(&node);
+    vat_json_object_add_int(&node, "retval", ntohl(mp->retval));
+    vat_json_object_add_uint(&node, "policer_index", ntohl(mp->policer_index));
+
+    vat_json_print(vam->ofp, &node);
+    vat_json_free(&node);
+
+    vam->retval = ntohl(mp->retval);
+    vam->result_ready = 1;
+}
+
 /* Format hex dump. */
 u8 * format_hex_bytes (u8 * s, va_list * va)
 {
@@ -2811,6 +2868,33 @@ static void vl_api_pg_create_interface_reply_t_handler_json
     vam->result_ready = 1;
 }
 
+static void vl_api_policer_classify_details_t_handler
+(vl_api_policer_classify_details_t * mp)
+{
+    vat_main_t * vam = &vat_main;
+
+    fformat (vam->ofp, "%10d%20d\n", ntohl(mp->sw_if_index),
+             ntohl(mp->table_index));
+}
+
+static void vl_api_policer_classify_details_t_handler_json
+(vl_api_policer_classify_details_t * mp)
+{
+    vat_main_t * vam = &vat_main;
+    vat_json_node_t * node;
+
+    if (VAT_JSON_ARRAY != vam->json_tree.type) {
+        ASSERT(VAT_JSON_NONE == vam->json_tree.type);
+        vat_json_init_array(&vam->json_tree);
+    }
+    node = vat_json_array_add(&vam->json_tree);
+
+    vat_json_init_object(node);
+    vat_json_object_add_uint(node, "sw_if_index", ntohl(mp->sw_if_index));
+    vat_json_object_add_uint(node, "table_index", ntohl(mp->table_index));
+}
+
+
 #define vl_api_vnet_ip4_fib_counters_t_endian vl_noop_handler
 #define vl_api_vnet_ip4_fib_counters_t_print vl_noop_handler
 #define vl_api_vnet_ip6_fib_counters_t_endian vl_noop_handler
@@ -2909,7 +2993,7 @@ _(lisp_add_del_map_request_itr_rlocs_reply)             \
 _(lisp_eid_table_add_del_map_reply)                     \
 _(vxlan_gpe_add_del_tunnel_reply)                      \
 _(af_packet_delete_reply)                               \
-_(policer_add_del_reply)                                \
+_(policer_classify_set_interface_reply)                 \
 _(netmap_create_reply)                                  \
 _(netmap_delete_reply)                                  \
 _(ipfix_enable_reply)                                   \
@@ -3108,6 +3192,8 @@ _(AF_PACKET_CREATE_REPLY, af_packet_create_reply)                       \
 _(AF_PACKET_DELETE_REPLY, af_packet_delete_reply)                       \
 _(POLICER_ADD_DEL_REPLY, policer_add_del_reply)                         \
 _(POLICER_DETAILS, policer_details)                                     \
+_(POLICER_CLASSIFY_SET_INTERFACE_REPLY, policer_classify_set_interface_reply) \
+_(POLICER_CLASSIFY_DETAILS, policer_classify_details)                   \
 _(NETMAP_CREATE_REPLY, netmap_create_reply)                             \
 _(NETMAP_DELETE_REPLY, netmap_delete_reply)                             \
 _(MPLS_GRE_TUNNEL_DETAILS, mpls_gre_tunnel_details)                     \
@@ -7060,6 +7146,20 @@ uword unformat_acl_next_index (unformat_input_t * input, va_list * args)
   return 1;
 }
 
+uword unformat_policer_precolor (unformat_input_t * input, va_list * args)
+{
+  u32 * r = va_arg (*args, u32 *);
+
+  if (unformat (input, "conform-color"))
+    *r = POLICE_CONFORM;
+  else if (unformat (input, "exceed-color"))
+    *r = POLICE_EXCEED;
+  else
+    return 0;
+
+  return 1;
+}
+
 static int api_classify_add_del_table (vat_main_t * vam)
 {
   unformat_input_t * i = vam->input;
@@ -7553,6 +7653,10 @@ static int api_classify_add_del_session (vat_main_t * vam)
         else if (unformat (i, "acl-hit-next %U", unformat_acl_next_index,
                            &hit_next_index))
             ;
+        else if (unformat (i, "policer-hit-next %d", &hit_next_index))
+            ;
+        else if (unformat (i, "%U", unformat_policer_precolor, &opaque_index))
+            ;
         else if (unformat (i, "opaque-index %d", &opaque_index))
             ;
         else if (unformat (i, "skip_n %d", &skip_n_vectors))
@@ -11705,6 +11809,7 @@ api_policer_add_del (vat_main_t * vam)
     u8 rate_type = 0;
     u8 round_type = 0;
     u8 type = 0;
+    u8 color_aware = 0;
     sse2_qos_pol_action_params_st conform_action, exceed_action, violate_action;
 
     while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) {
@@ -11737,6 +11842,8 @@ api_policer_add_del (vat_main_t * vam)
         else if (unformat (i, "violate_action %U", unformat_policer_action_type,
                            &violate_action))
             ;
+        else if (unformat (i, "color-aware"))
+            color_aware = 1;
         else
           break;
     }
@@ -11769,6 +11876,7 @@ api_policer_add_del (vat_main_t * vam)
     mp->exceed_dscp = exceed_action.dscp;
     mp->violate_action_type = violate_action.action_type;
     mp->violate_dscp = violate_action.dscp;
+    mp->color_aware = color_aware;
 
     S; W;
     /* NOTREACHED */
@@ -11812,6 +11920,93 @@ api_policer_dump(vat_main_t *vam)
     return 0;
 }
 
+static int
+api_policer_classify_set_interface (vat_main_t * vam)
+{
+    unformat_input_t * i = vam->input;
+    vl_api_policer_classify_set_interface_t *mp;
+    f64 timeout;
+    u32 sw_if_index;
+    int sw_if_index_set;
+    u32 ip4_table_index = ~0;
+    u32 ip6_table_index = ~0;
+    u32 l2_table_index = ~0;
+    u8 is_add = 1;
+
+    while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) {
+       if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
+            sw_if_index_set = 1;
+       else if (unformat (i, "sw_if_index %d", &sw_if_index))
+           sw_if_index_set = 1;
+        else if (unformat (i, "del"))
+            is_add = 0;
+       else if (unformat (i, "ip4-table %d", &ip4_table_index))
+           ;
+       else if (unformat (i, "ip6-table %d", &ip6_table_index))
+           ;
+       else if (unformat (i, "l2-table %d", &l2_table_index))
+           ;
+        else {
+            clib_warning ("parse error '%U'", format_unformat_error, i);
+            return -99;
+        }
+    }
+
+    if (sw_if_index_set == 0) {
+        errmsg ("missing interface name or sw_if_index\n");
+        return -99;
+    }
+
+    M(POLICER_CLASSIFY_SET_INTERFACE, policer_classify_set_interface);
+
+    mp->sw_if_index = ntohl(sw_if_index);
+    mp->ip4_table_index = ntohl(ip4_table_index);
+    mp->ip6_table_index = ntohl(ip6_table_index);
+    mp->l2_table_index = ntohl(l2_table_index);
+    mp->is_add = is_add;
+
+    S; W;
+    /* NOTREACHED */
+    return 0;
+}
+
+static int
+api_policer_classify_dump(vat_main_t *vam)
+{
+    unformat_input_t * i = vam->input;
+    vl_api_policer_classify_dump_t *mp;
+    f64 timeout = ~0;
+    u8 type = POLICER_CLASSIFY_N_TABLES;
+
+    if (unformat (i, "type %U", unformat_classify_table_type, &type))
+        ;
+    else {
+        errmsg ("classify table type must be specified\n");
+        return -99;
+    }
+
+    if (!vam->json_output) {
+        fformat(vam->ofp, "%10s%20s\n", "Intfc idx", "Classify table");
+    }
+
+    M(POLICER_CLASSIFY_DUMP, policer_classify_dump);
+    mp->type = type;
+    /* send it... */
+    S;
+
+    /* Use a control ping for synchronization */
+    {
+        vl_api_control_ping_t * mp;
+        M(CONTROL_PING, control_ping);
+        S;
+    }
+    /* Wait for a reply... */
+    W;
+
+    /* NOTREACHED */
+    return 0;
+}
+
 static int
 api_netmap_create (vat_main_t * vam)
 {
@@ -12849,8 +13044,9 @@ _(classify_add_del_table,                                               \
   "[del] mask <mask-value>\n"                                          \
   " [l2-miss-next | miss-next | acl-miss-next] <name|nn>")             \
 _(classify_add_del_session,                                             \
-  "[hit-next|l2-hit-next|acl-hit-next] <name|nn> table-index <nn>\n"    \
-  "skip_n <nn> match_n <nn> match [hex] [l2] [l3 [ip4|ip6]]")          \
+  "[hit-next|l2-hit-next|acl-hit-next|policer-hit-next] <name|nn>\n"    \
+  "  table-index <nn> skip_n <nn> match_n <nn> match [hex] [l2]\n"      \
+  "  [l3 [ip4|ip6]]")                                                  \
 _(classify_set_interface_ip_table,                                      \
   "<intfc> | sw_if_index <nn> table <nn>")                             \
 _(classify_set_interface_l2_tables,                                     \
@@ -12985,6 +13181,10 @@ _(af_packet_create, "name <host interface name> [hw_addr <mac>]")       \
 _(af_packet_delete, "name <host interface name>")                       \
 _(policer_add_del, "name <policer name> <params> [del]")                \
 _(policer_dump, "[name <policer name>]")                                \
+_(policer_classify_set_interface,                                       \
+  "<intfc> | sw_if_index <nn> [ip4-table <nn>] [ip6-table <nn>]\n"      \
+  "  [l2-table <nn>] [del]")                                            \
+_(policer_classify_dump, "type [ip4|ip6|l2]")                           \
 _(netmap_create, "name <interface name> [hw-addr <mac>] [pipe] "        \
     "[master|slave]")                                                   \
 _(netmap_delete, "name <interface name>")                               \
index feb1a61..822b990 100644 (file)
@@ -66,6 +66,7 @@
 #include <vlibmemory/api.h>
 #include <vnet/classify/vnet_classify.h>
 #include <vnet/classify/input_acl.h>
+#include <vnet/classify/policer_classify.h>
 #include <vnet/l2/l2_classify.h>
 #include <vnet/vxlan/vxlan.h>
 #include <vnet/gre/gre.h>
@@ -353,6 +354,8 @@ _(AF_PACKET_CREATE, af_packet_create)                                   \
 _(AF_PACKET_DELETE, af_packet_delete)                                   \
 _(POLICER_ADD_DEL, policer_add_del)                                     \
 _(POLICER_DUMP, policer_dump)                                           \
+_(POLICER_CLASSIFY_SET_INTERFACE, policer_classify_set_interface)       \
+_(POLICER_CLASSIFY_DUMP, policer_classify_dump)                         \
 _(NETMAP_CREATE, netmap_create)                                         \
 _(NETMAP_DELETE, netmap_delete)                                         \
 _(MPLS_GRE_TUNNEL_DUMP, mpls_gre_tunnel_dump)                           \
@@ -6435,6 +6438,7 @@ vl_api_policer_add_del_t_handler
     u8 *name = NULL;
     sse2_qos_pol_cfg_params_st cfg;
     clib_error_t * error;
+    u32 policer_index;
 
     name = format(0, "%s", mp->name);
 
@@ -6452,13 +6456,20 @@ vl_api_policer_add_del_t_handler
     cfg.exceed_action.dscp = mp->exceed_dscp;
     cfg.violate_action.action_type = mp->violate_action_type;
     cfg.violate_action.dscp = mp->violate_dscp;
+    cfg.color_aware = mp->color_aware;
 
-    error = policer_add_del(vm, name, &cfg, mp->is_add);
+    error = policer_add_del(vm, name, &cfg, &policer_index, mp->is_add);
 
     if (error)
       rv = VNET_API_ERROR_UNSPECIFIED;
 
-    REPLY_MACRO(VL_API_POLICER_ADD_DEL_REPLY);
+    REPLY_MACRO2(VL_API_POLICER_ADD_DEL_REPLY,
+    ({
+        if (rv == 0 &&  mp->is_add)
+          rmp->policer_index = ntohl(policer_index);
+        else
+          rmp->policer_index = ~0;
+    }));
 }
 
 static void
@@ -6545,6 +6556,75 @@ vl_api_policer_dump_t_handler
     }
 }
 
+static void
+vl_api_policer_classify_set_interface_t_handler
+(vl_api_policer_classify_set_interface_t * mp)
+{
+    vlib_main_t *vm = vlib_get_main();
+    vl_api_policer_classify_set_interface_reply_t * rmp;
+    int rv;
+    u32 sw_if_index, ip4_table_index, ip6_table_index, l2_table_index;
+
+    ip4_table_index = ntohl(mp->ip4_table_index);
+    ip6_table_index = ntohl(mp->ip6_table_index);
+    l2_table_index = ntohl(mp->l2_table_index);
+    sw_if_index = ntohl(mp->sw_if_index);
+
+    VALIDATE_SW_IF_INDEX(mp);
+
+    rv = vnet_set_policer_classify_intfc(vm, sw_if_index, ip4_table_index,
+                                         ip6_table_index, l2_table_index,
+                                         mp->is_add);
+
+    BAD_SW_IF_INDEX_LABEL;
+
+    REPLY_MACRO(VL_API_POLICER_CLASSIFY_SET_INTERFACE_REPLY);
+}
+
+static void
+send_policer_classify_details (u32 sw_if_index,
+                               u32 table_index,
+                               unix_shared_memory_queue_t *q,
+                               u32 context)
+{
+    vl_api_policer_classify_details_t * mp;
+
+    mp = vl_msg_api_alloc (sizeof (*mp));
+    memset (mp, 0, sizeof (*mp));
+    mp->_vl_msg_id = ntohs (VL_API_POLICER_CLASSIFY_DETAILS);
+    mp->context = context;
+    mp->sw_if_index= htonl(sw_if_index);
+    mp->table_index= htonl(table_index);
+
+    vl_msg_api_send_shmem (q, (u8 *)&mp);
+}
+
+static void
+vl_api_policer_classify_dump_t_handler
+(vl_api_policer_classify_dump_t *mp)
+{
+    unix_shared_memory_queue_t * q;
+    policer_classify_main_t * pcm = &policer_classify_main;
+    u32 * vec_tbl;
+    int i;
+
+    q = vl_api_client_index_to_input_queue (mp->client_index);
+    if (q == 0)
+        return;
+
+    vec_tbl = pcm->classify_table_index_by_sw_if_index[mp->type];
+
+    if (vec_len(vec_tbl)) {
+        for (i = 0; i < vec_len (vec_tbl); i++) {
+            if (vec_elt(vec_tbl, i) == ~0)
+                continue;
+
+            send_policer_classify_details(i, vec_elt(vec_tbl, i), q,
+                                          mp->context);
+        }
+    }
+}
+
 static void
 vl_api_netmap_create_t_handler
 (vl_api_netmap_create_t *mp)
index 53eb2c4..651fdd3 100644 (file)
@@ -27,6 +27,9 @@
 #include <vnet/l2/l2_input.h>
 #include <vnet/sr/sr_packet.h>
 #include <vnet/vxlan-gpe/vxlan_gpe.h>
+#include <vnet/classify/policer_classify.h>
+#include <vnet/policer/xlate.h>
+#include <vnet/policer/policer.h>
 #include <vlib/vlib.h>
 #include <vlib/unix/unix.h>
 #include <vlibapi/api.h>
@@ -1746,6 +1749,157 @@ static void * vl_api_af_packet_delete_t_print
     FINISH;
 }
 
+static u8 * format_policer_action (u8 * s, va_list * va)
+{
+    u32 action = va_arg (*va, u32);
+    u32 dscp = va_arg (*va, u32);
+    char * t = 0;
+
+    if (action == SSE2_QOS_ACTION_DROP)
+        s = format (s, "drop");
+    else if (action == SSE2_QOS_ACTION_TRANSMIT)
+        s = format (s, "transmit");
+    else if (action == SSE2_QOS_ACTION_MARK_AND_TRANSMIT) {
+        s = format (s, "mark-and-transmit ");
+        switch (dscp) {
+        #define _(v,f,str) case VNET_DSCP_##f: t = str; break;
+            foreach_vnet_dscp
+        #undef _
+        default:
+            break;
+        }
+        s = format (s, "%s", t);
+    }
+
+    return s;
+}
+
+static void * vl_api_policer_add_del_t_print
+(vl_api_policer_add_del_t * mp, void *handle)
+{
+    u8 * s;
+
+    s = format (0, "SCRIPT: policer_add_del ");
+    s = format (s, "name %s ", mp->name);
+    s = format (s, "cir %d ", mp->cir);
+    s = format (s, "eir %d ", mp->eir);
+    s = format (s, "cb %d ", mp->cb);
+    s = format (s, "eb %d ", mp->eb);
+
+    switch (mp->rate_type) {
+    case SSE2_QOS_RATE_KBPS:
+        s = format (s, "rate_type kbps ");
+        break;
+    case SSE2_QOS_RATE_PPS:
+        s = format (s, "rate_type pps ");
+        break;
+    default:
+        break;
+    }
+
+    switch (mp->round_type) {
+    case SSE2_QOS_ROUND_TO_CLOSEST:
+        s = format (s, "round_type closest ");
+        break;
+    case SSE2_QOS_ROUND_TO_UP:
+        s = format (s, "round_type up ");
+        break;
+    case SSE2_QOS_ROUND_TO_DOWN:
+        s = format (s, "round_type down ");
+        break;
+    default:
+        break;
+    }
+
+    switch (mp->type) {
+    case SSE2_QOS_POLICER_TYPE_1R2C:
+        s = format (s, "type 1r2c ");
+        break;
+    case SSE2_QOS_POLICER_TYPE_1R3C_RFC_2697:
+        s = format (s, "type 1r3c ");
+        break;
+    case SSE2_QOS_POLICER_TYPE_2R3C_RFC_2698:
+        s = format (s, "type 2r3c-2698 ");
+        break;
+    case SSE2_QOS_POLICER_TYPE_2R3C_RFC_4115:
+        s = format (s, "type 2r3c-4115 ");
+        break;
+    case SSE2_QOS_POLICER_TYPE_2R3C_RFC_MEF5CF1:
+        s = format (s, "type 2r3c-mef5cf1 ");
+        break;
+    default:
+         break;
+    }
+
+    s = format (s, "conform_action %U ", format_policer_action,
+                mp->conform_action_type, mp->conform_dscp);
+    s = format (s, "exceed_action %U ", format_policer_action,
+                mp->exceed_action_type, mp->exceed_dscp);
+    s = format (s, "violate_action %U ", format_policer_action,
+                mp->violate_action_type, mp->violate_dscp);
+
+    if (mp->color_aware)
+        s = format (s, "color-aware ");
+    if (mp->is_add == 0)
+        s = format (s, "del ");
+
+    FINISH;
+}
+
+static void * vl_api_policer_dump_t_print
+(vl_api_policer_dump_t * mp, void *handle)
+{
+    u8 * s;
+
+    s = format (0, "SCRIPT: policer_dump ");
+    if (mp->match_name_valid)
+        s = format (s, "name %s ", mp->match_name);
+
+    FINISH;
+}
+
+static void * vl_api_policer_classify_set_interface_t_print
+(vl_api_policer_classify_set_interface_t * mp, void *handle)
+{
+    u8 * s;
+
+    s = format (0, "SCRIPT: policer_classify_set_interface ");
+    s = format (s, "sw_if_index %d ", ntohl(mp->sw_if_index));
+    if (mp->ip4_table_index != ~0)
+        s = format (s, "ip4-table %d ", ntohl(mp->ip4_table_index));
+    if (mp->ip6_table_index != ~0)
+        s = format (s, "ip6-table %d ", ntohl(mp->ip6_table_index));
+    if (mp->l2_table_index != ~0)
+        s = format (s, "l2-table %d ", ntohl(mp->l2_table_index));
+    if (mp->is_add == 0)
+        s = format (s, "del ");
+
+    FINISH;
+}
+
+static void * vl_api_policer_classify_dump_t_print
+(vl_api_policer_classify_dump_t * mp, void *handle)
+{
+    u8 * s;
+
+    s = format (0, "SCRIPT: policer_classify_dump ");
+    switch (mp->type) {
+    case POLICER_CLASSIFY_TABLE_IP4:
+        s = format (s, "type ip4 ");
+        break;
+    case POLICER_CLASSIFY_TABLE_IP6:
+        s = format (s, "type ip6 ");
+        break;
+    case POLICER_CLASSIFY_TABLE_L2:
+        s = format (s, "type l2 ");
+        break;
+    default:
+        break;
+    }
+
+    FINISH;
+}
+
 static void *vl_api_sw_interface_clear_stats_t_print
 (vl_api_sw_interface_clear_stats_t * mp, void *handle)
 {
@@ -2031,7 +2185,11 @@ _(IPFIX_DUMP,ipfix_dump)                                                \
 _(GET_NEXT_INDEX, get_next_index)                                       \
 _(PG_CREATE_INTERFACE,pg_create_interface)                              \
 _(PG_CAPTURE, pg_capture)                                               \
-_(PG_ENABLE_DISABLE, pg_enable_disable)
+_(PG_ENABLE_DISABLE, pg_enable_disable)                                 \
+_(POLICER_ADD_DEL, policer_add_del)                                     \
+_(POLICER_DUMP, policer_dump)                                           \
+_(POLICER_CLASSIFY_SET_INTERFACE, policer_classify_set_interface)       \
+_(POLICER_CLASSIFY_DUMP, policer_classify_dump)
 
 void vl_msg_api_custom_dump_configure (api_main_t *am)
 {
index 1477289..4571c92 100644 (file)
@@ -3644,6 +3644,7 @@ define af_packet_delete_reply {
     @param rate_type - rate type
     @param round_type - rounding type
     @param type - policer algorithm
+    @param color_aware - 0=color-blind, 1=color-aware
     @param conform_action_type - conform action type
     @param conform_dscp - DSCP for conform mar-and-transmit action
     @param exceed_action_type - exceed action type
@@ -3664,6 +3665,7 @@ define policer_add_del {
     u8 rate_type;
     u8 round_type;
     u8 type;
+    u8 color_aware;
     u8 conform_action_type;
     u8 conform_dscp;
     u8 exceed_action_type;
@@ -3675,10 +3677,12 @@ define policer_add_del {
 /** \brief Add/del policer response
     @param context - sender context, to match reply w/ request
     @param retval - return value for request
+    @param policer_index - for add, returned index of the new policer
 */
 define policer_add_del_reply {
     u32 context;
     i32 retval;
+    u32 policer_index;
 };
 
 /** \brief Get list of policers
@@ -3751,6 +3755,58 @@ define policer_details {
     u64 last_update_time;
 };
 
+/** \brief Set/unset policer classify interface
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param sw_if_index - interface to set/unset policer classify
+    @param ip4_table_index - ip4 classify table index (~0 for skip)
+    @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.
+          (ip4_table_index, ip6_table_index, or l2_table_index)
+*/
+define policer_classify_set_interface {
+    u32 client_index;
+    u32 context;
+    u32 sw_if_index;
+    u32 ip4_table_index;
+    u32 ip6_table_index;
+    u32 l2_table_index;
+    u8  is_add;
+};
+
+/** \brief Set/unset policer classify interface response
+    @param context - sender context, to match reply w/ request
+    @param retval - return value for request
+*/
+define policer_classify_set_interface_reply {
+    u32 context;
+    i32 retval;
+};
+
+/** \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
+*/
+define policer_classify_dump {
+    u32 client_index;
+    u32 context;
+    u8 type;
+};
+
+/** \brief Policer iclassify 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
+*/
+define policer_classify_details {
+    u32 context;
+    u32 sw_if_index;
+    u32 table_index;
+};
+
 /** \brief Create netmap
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request