policer: API policer selection by index 73/37873/6
authorMaxime Peim <mpeim@cisco.com>
Fri, 6 Jan 2023 11:57:38 +0000 (11:57 +0000)
committerNeale Ranns <neale@graphiant.com>
Thu, 2 Feb 2023 00:22:06 +0000 (00:22 +0000)
Policer API calls were only by policer name. It is now possible to
select a policer by its index.
Some functionalities are also added to allow updating a policer
configuration and to refill its token buckets.
Some dead codes are being removed, and small fixes made.

Type: improvement

Signed-off-by: Maxime Peim <mpeim@cisco.com>
Change-Id: I4cc8fda0fc7c635a4110da3e757356b150f9b606

src/vnet/policer/police.h
src/vnet/policer/policer.api
src/vnet/policer/policer.c
src/vnet/policer/policer.h
src/vnet/policer/policer_api.c
src/vnet/policer/policer_types.api
src/vnet/policer/xlate.c
src/vnet/policer/xlate.h
test/test_policer_input.py
test/vpp_policer.py

index 5ad249e..8f126e2 100644 (file)
@@ -73,8 +73,6 @@ typedef enum
 typedef struct
 {
   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
-  u32 lock;                    // for exclusive access to the struct
-
   u32 single_rate;             // 1 = single rate policer, 0 = two rate policer
   u32 color_aware;             // for hierarchical policing
   u32 scale;                   // power-of-2 shift amount for lower rates
@@ -93,11 +91,9 @@ typedef struct
   u32 current_bucket;          // MOD
   u32 extended_limit;
   u32 extended_bucket;         // MOD
-
-  u64 last_update_time;                // MOD
   u32 thread_index;            // Tie policer to a thread, rather than lock
-  u32 pad32;
-
+  u64 last_update_time;                // MOD
+  u8 *name;
 } policer_t;
 
 STATIC_ASSERT_SIZEOF (policer_t, CLIB_CACHE_LINE_BYTES);
index f4bf938..a5a60b3 100644 (file)
@@ -13,7 +13,7 @@
  * limitations under the License.
  */
 
-option version = "2.0.0";
+option version = "3.0.0";
 
 import "vnet/interface_types.api";
 import "vnet/policer/policer_types.api";
@@ -35,6 +35,16 @@ autoreply define policer_bind
   bool bind_enable;
 };
 
+autoreply define policer_bind_v2
+{
+  u32 client_index;
+  u32 context;
+
+  u32 policer_index;
+  u32 worker_index;
+  bool bind_enable;
+};
+
 /** \brief policer input: Apply policer as an input feature.
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
@@ -52,6 +62,16 @@ autoreply define policer_input
   bool apply;
 };
 
+autoreply define policer_input_v2
+{
+  u32 client_index;
+  u32 context;
+
+  u32 policer_index;
+  vl_api_interface_index_t sw_if_index;
+  bool apply;
+};
+
 /** \brief policer output: Apply policer as an output feature.
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
@@ -69,6 +89,16 @@ autoreply define policer_output
   bool apply;
 };
 
+autoreply define policer_output_v2
+{
+  u32 client_index;
+  u32 context;
+
+  u32 policer_index;
+  vl_api_interface_index_t sw_if_index;
+  bool apply;
+};
+
 /** \brief Add/del policer
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
@@ -106,6 +136,40 @@ define policer_add_del
   vl_api_sse2_qos_action_t violate_action;
 };
 
+define policer_add
+{
+  u32 client_index;
+  u32 context;
+
+  string name[64];
+  vl_api_policer_config_t infos;
+};
+
+autoreply define policer_del
+{
+  u32 client_index;
+  u32 context;
+
+  u32 policer_index;
+};
+
+autoreply define policer_update
+{
+  u32 client_index;
+  u32 context;
+
+  u32 policer_index;
+  vl_api_policer_config_t infos;
+};
+
+autoreply define policer_reset
+{
+  u32 client_index;
+  u32 context;
+
+  u32 policer_index;
+};
+
 /** \brief Add/del policer response
     @param context - sender context, to match reply w/ request
     @param retval - return value for request
@@ -118,6 +182,13 @@ define policer_add_del_reply
   u32 policer_index;
 };
 
+define policer_add_reply
+{
+  u32 context;
+  i32 retval;
+  u32 policer_index;
+};
+
 /** \brief Get list of policers
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
@@ -133,6 +204,23 @@ define policer_dump
   string match_name[64];
 };
 
+/** \brief Get list of policers
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param policer_index - index of policer in the pool, ~0 to request all
+*/
+define policer_dump_v2
+{
+  u32 client_index;
+  u32 context;
+
+  u32 policer_index;
+};
+
+service {
+  rpc policer_dump_v2 returns stream policer_details;
+};
+
 /** \brief Policer operational state response.
     @param context - sender context, to match reply w/ request
     @param name - policer name
index 8389a5e..217a4c9 100644 (file)
@@ -49,105 +49,161 @@ vlib_combined_counter_main_t policer_counters[] = {
   },
 };
 
-clib_error_t *
-policer_add_del (vlib_main_t *vm, u8 *name, qos_pol_cfg_params_st *cfg,
-                u32 *policer_index, u8 is_add)
+int
+policer_add (vlib_main_t *vm, const u8 *name, const qos_pol_cfg_params_st *cfg,
+            u32 *policer_index)
 {
   vnet_policer_main_t *pm = &vnet_policer_main;
   policer_t test_policer;
   policer_t *policer;
+  policer_t *pp;
+  qos_pol_cfg_params_st *cp;
   uword *p;
   u32 pi;
   int rv;
+  int i;
 
   p = hash_get_mem (pm->policer_config_by_name, name);
 
-  if (is_add == 0)
-    {
-      /* free policer config and template */
-      if (p == 0)
-       {
-         vec_free (name);
-         return clib_error_return (0, "No such policer configuration");
-       }
-      pool_put_index (pm->configs, p[0]);
-      pool_put_index (pm->policer_templates, p[0]);
-      hash_unset_mem (pm->policer_config_by_name, name);
+  if (p != NULL)
+    return VNET_API_ERROR_VALUE_EXIST;
 
-      /* free policer */
-      p = hash_get_mem (pm->policer_index_by_name, name);
-      if (p == 0)
-       {
-         vec_free (name);
-         return clib_error_return (0, "No such policer");
-       }
-      pool_put_index (pm->policers, p[0]);
-      hash_unset_mem (pm->policer_index_by_name, name);
+  /* Vet the configuration before adding it to the table */
+  rv = pol_logical_2_physical (cfg, &test_policer);
 
-      vec_free (name);
-      return 0;
-    }
+  if (rv != 0)
+    return VNET_API_ERROR_INVALID_VALUE;
 
-  if (p != 0)
+  pool_get (pm->configs, cp);
+  pool_get_aligned (pm->policers, policer, CLIB_CACHE_LINE_BYTES);
+
+  clib_memcpy (cp, cfg, sizeof (*cp));
+  clib_memcpy (policer, &test_policer, sizeof (*pp));
+
+  policer->name = format (0, "%s%c", name, 0);
+  pi = policer - pm->policers;
+
+  hash_set_mem (pm->policer_config_by_name, policer->name, cp - pm->configs);
+  hash_set_mem (pm->policer_index_by_name, policer->name, pi);
+  *policer_index = pi;
+  policer->thread_index = ~0;
+
+  for (i = 0; i < NUM_POLICE_RESULTS; i++)
     {
-      vec_free (name);
-      return clib_error_return (0, "Policer already exists");
+      vlib_validate_combined_counter (&policer_counters[i], pi);
+      vlib_zero_combined_counter (&policer_counters[i], pi);
     }
 
-  /* Vet the configuration before adding it to the table */
-  rv = pol_logical_2_physical (cfg, &test_policer);
+  return 0;
+}
+
+int
+policer_del (vlib_main_t *vm, u32 policer_index)
+{
+  vnet_policer_main_t *pm = &vnet_policer_main;
+  policer_t *policer;
+  uword *p;
+
+  if (pool_is_free_index (pm->policers, policer_index))
+    return VNET_API_ERROR_NO_SUCH_ENTRY;
+
+  policer = &pm->policers[policer_index];
+
+  p = hash_get_mem (pm->policer_config_by_name, policer->name);
 
-  if (rv == 0)
+  /* free policer config */
+  if (p != NULL)
     {
-      policer_t *pp;
-      qos_pol_cfg_params_st *cp;
-      int i;
+      pool_put_index (pm->configs, p[0]);
+      hash_unset_mem (pm->policer_config_by_name, policer->name);
+    }
 
-      pool_get (pm->configs, cp);
-      pool_get (pm->policer_templates, pp);
+  /* free policer */
+  hash_unset_mem (pm->policer_index_by_name, policer->name);
+  vec_free (policer->name);
+  pool_put_index (pm->policers, policer_index);
+
+  return 0;
+}
+
+int
+policer_update (vlib_main_t *vm, u32 policer_index,
+               const qos_pol_cfg_params_st *cfg)
+{
+  vnet_policer_main_t *pm = &vnet_policer_main;
+  policer_t test_policer;
+  policer_t *policer;
+  qos_pol_cfg_params_st *cp;
+  uword *p;
+  u8 *name;
+  int rv;
+  int i;
 
-      ASSERT (cp - pm->configs == pp - pm->policer_templates);
+  if (pool_is_free_index (pm->policers, policer_index))
+    return VNET_API_ERROR_NO_SUCH_ENTRY;
 
-      clib_memcpy (cp, cfg, sizeof (*cp));
-      clib_memcpy (pp, &test_policer, sizeof (*pp));
+  policer = &pm->policers[policer_index];
 
-      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;
-      policer->thread_index = ~0;
+  /* Vet the configuration before adding it to the table */
+  rv = pol_logical_2_physical (cfg, &test_policer);
+  if (rv != 0)
+    return VNET_API_ERROR_INVALID_VALUE;
 
-      for (i = 0; i < NUM_POLICE_RESULTS; i++)
-       {
-         vlib_validate_combined_counter (&policer_counters[i], pi);
-         vlib_zero_combined_counter (&policer_counters[i], pi);
-       }
+  p = hash_get_mem (pm->policer_config_by_name, policer->name);
+
+  if (PREDICT_TRUE (p != NULL))
+    {
+      cp = &pm->configs[p[0]];
     }
   else
     {
-      vec_free (name);
-      return clib_error_return (0, "Config failed sanity check");
+      /* recover from a missing configuration */
+      pool_get (pm->configs, cp);
+      hash_set_mem (pm->policer_config_by_name, policer->name,
+                   cp - pm->configs);
     }
 
+  name = policer->name;
+
+  clib_memcpy (cp, cfg, sizeof (*cp));
+  clib_memcpy (policer, &test_policer, sizeof (*policer));
+
+  policer->name = name;
+  policer->thread_index = ~0;
+
+  for (i = 0; i < NUM_POLICE_RESULTS; i++)
+    vlib_zero_combined_counter (&policer_counters[i], policer_index);
+
   return 0;
 }
 
 int
-policer_bind_worker (u8 *name, u32 worker, bool bind)
+policer_reset (vlib_main_t *vm, u32 policer_index)
 {
   vnet_policer_main_t *pm = &vnet_policer_main;
   policer_t *policer;
-  uword *p;
 
-  p = hash_get_mem (pm->policer_index_by_name, name);
-  if (p == 0)
-    {
-      return VNET_API_ERROR_NO_SUCH_ENTRY;
-    }
+  if (pool_is_free_index (pm->policers, policer_index))
+    return VNET_API_ERROR_NO_SUCH_ENTRY;
+
+  policer = &pm->policers[policer_index];
+
+  policer->current_bucket = policer->current_limit;
+  policer->extended_bucket = policer->extended_limit;
+
+  return 0;
+}
+
+int
+policer_bind_worker (u32 policer_index, u32 worker, bool bind)
+{
+  vnet_policer_main_t *pm = &vnet_policer_main;
+  policer_t *policer;
+
+  if (pool_is_free_index (pm->policers, policer_index))
+    return VNET_API_ERROR_NO_SUCH_ENTRY;
 
-  policer = &pm->policers[p[0]];
+  policer = &pm->policers[policer_index];
 
   if (bind)
     {
@@ -166,21 +222,9 @@ policer_bind_worker (u8 *name, u32 worker, bool bind)
 }
 
 int
-policer_input (u8 *name, u32 sw_if_index, vlib_dir_t dir, bool apply)
+policer_input (u32 policer_index, u32 sw_if_index, vlib_dir_t dir, bool apply)
 {
   vnet_policer_main_t *pm = &vnet_policer_main;
-  policer_t *policer;
-  u32 policer_index;
-  uword *p;
-
-  p = hash_get_mem (pm->policer_index_by_name, name);
-  if (p == 0)
-    {
-      return VNET_API_ERROR_NO_SUCH_ENTRY;
-    }
-
-  policer = &pm->policers[p[0]];
-  policer_index = policer - pm->policers;
 
   if (apply)
     {
@@ -210,20 +254,21 @@ policer_input (u8 *name, u32 sw_if_index, vlib_dir_t dir, bool apply)
 u8 *
 format_policer_instance (u8 * s, va_list * va)
 {
+  vnet_policer_main_t *pm = &vnet_policer_main;
   policer_t *i = va_arg (*va, policer_t *);
-  uword pi = va_arg (*va, uword);
+  u32 policer_index = i - pm->policers;
   int result;
   vlib_counter_t counts[NUM_POLICE_RESULTS];
 
   for (result = 0; result < NUM_POLICE_RESULTS; result++)
     {
-      vlib_get_combined_counter (&policer_counters[result], pi,
+      vlib_get_combined_counter (&policer_counters[result], policer_index,
                                 &counts[result]);
     }
 
-  s = format (s, "policer at %llx: %s rate, %s color-aware\n",
-             i, i->single_rate ? "single" : "dual",
-             i->color_aware ? "is" : "not");
+  s =
+    format (s, "Policer at index %d: %s rate, %s color-aware\n", policer_index,
+           i->single_rate ? "single" : "dual", i->color_aware ? "is" : "not");
   s = format (s, "cir %u tok/period, pir %u tok/period, scale %u\n",
              i->cir_tokens_per_period, i->pir_tokens_per_period, i->scale);
   s = format (s, "cur lim %u, cur bkt %u, ext lim %u, ext bkt %u\n",
@@ -475,6 +520,7 @@ unformat_policer_classify_next_index (unformat_input_t * input, va_list * va)
     return 0;
 
   p = hash_get_mem (pm->policer_index_by_name, match_name);
+  vec_free (match_name);
 
   if (p == 0)
     return 0;
@@ -513,12 +559,16 @@ static clib_error_t *
 policer_add_command_fn (vlib_main_t *vm, unformat_input_t *input,
                        vlib_cli_command_t *cmd)
 {
+  vnet_policer_main_t *pm = &vnet_policer_main;
   qos_pol_cfg_params_st c;
   unformat_input_t _line_input, *line_input = &_line_input;
-  u8 is_add = 1;
   u8 *name = 0;
+  uword *p;
   u32 pi;
+  u32 policer_index = ~0;
+  int rv = 0;
   clib_error_t *error = NULL;
+  u8 is_update = cmd->function_arg;
 
   /* Get a line of input. */
   if (!unformat_user (input, unformat_line_input, line_input))
@@ -528,9 +578,9 @@ policer_add_command_fn (vlib_main_t *vm, unformat_input_t *input,
 
   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     {
-      if (unformat (line_input, "del"))
-       is_add = 0;
-      else if (unformat (line_input, "name %s", &name))
+      if (unformat (line_input, "name %s", &name))
+       ;
+      else if (is_update && unformat (line_input, "index %u", &policer_index))
        ;
       else if (unformat (line_input, "color-aware"))
        c.color_aware = 1;
@@ -546,10 +596,41 @@ policer_add_command_fn (vlib_main_t *vm, unformat_input_t *input,
        }
     }
 
-  error = policer_add_del (vm, name, &c, &pi, is_add);
+  if (is_update)
+    {
+      if (~0 == policer_index && 0 != name)
+       {
+         p = hash_get_mem (pm->policer_index_by_name, name);
+         if (p != NULL)
+           policer_index = p[0];
+       }
+
+      if (~0 != policer_index)
+       {
+         rv = policer_update (vm, policer_index, &c);
+       }
+    }
+  else
+    {
+      rv = policer_add (vm, name, &c, &pi);
+    }
+
+  switch (rv)
+    {
+    case VNET_API_ERROR_NO_SUCH_ENTRY:
+      error = clib_error_return (0, "No such policer");
+      break;
+    case VNET_API_ERROR_VALUE_EXIST:
+      error = clib_error_return (0, "Policer already exists");
+      break;
+    case VNET_API_ERROR_INVALID_VALUE:
+      error = clib_error_return (0, "Config failed sanity check");
+      break;
+    }
 
 done:
   unformat_free (line_input);
+  vec_free (name);
 
   return error;
 }
@@ -560,6 +641,10 @@ policer_del_command_fn (vlib_main_t *vm, unformat_input_t *input,
 {
   unformat_input_t _line_input, *line_input = &_line_input;
   clib_error_t *error = NULL;
+  vnet_policer_main_t *pm = &vnet_policer_main;
+  int rv;
+  u32 policer_index = ~0;
+  uword *p;
   u8 *name = 0;
 
   /* Get a line of input. */
@@ -570,6 +655,8 @@ policer_del_command_fn (vlib_main_t *vm, unformat_input_t *input,
     {
       if (unformat (line_input, "name %s", &name))
        ;
+      else if (unformat (line_input, "index %u", &policer_index))
+       ;
       else
        {
          error = clib_error_return (0, "unknown input `%U'",
@@ -578,10 +665,30 @@ policer_del_command_fn (vlib_main_t *vm, unformat_input_t *input,
        }
     }
 
-  error = policer_add_del (vm, name, NULL, NULL, 0);
+  if (~0 == policer_index && 0 != name)
+    {
+      p = hash_get_mem (pm->policer_index_by_name, name);
+      if (p != NULL)
+       policer_index = p[0];
+    }
+
+  rv = VNET_API_ERROR_NO_SUCH_ENTRY;
+  if (~0 != policer_index)
+    rv = policer_del (vm, policer_index);
+
+  switch (rv)
+    {
+    case VNET_API_ERROR_INVALID_VALUE:
+      error = clib_error_return (0, "No such policer configuration");
+      break;
+    case VNET_API_ERROR_NO_SUCH_ENTRY:
+      error = clib_error_return (0, "No such policer");
+      break;
+    }
 
 done:
   unformat_free (line_input);
+  vec_free (name);
 
   return error;
 }
@@ -592,13 +699,14 @@ policer_bind_command_fn (vlib_main_t *vm, unformat_input_t *input,
 {
   unformat_input_t _line_input, *line_input = &_line_input;
   clib_error_t *error = NULL;
-  u8 bind, *name = 0;
-  u32 worker;
+  vnet_policer_main_t *pm = &vnet_policer_main;
+  u8 bind = 1;
+  u8 *name = 0;
+  u32 worker = ~0;
+  u32 policer_index = ~0;
+  uword *p;
   int rv;
 
-  bind = 1;
-  worker = ~0;
-
   /* Get a line of input. */
   if (!unformat_user (input, unformat_line_input, line_input))
     return 0;
@@ -607,6 +715,8 @@ policer_bind_command_fn (vlib_main_t *vm, unformat_input_t *input,
     {
       if (unformat (line_input, "name %s", &name))
        ;
+      else if (unformat (line_input, "index %u", &policer_index))
+       ;
       else if (unformat (line_input, "unbind"))
        bind = 0;
       else if (unformat (line_input, "%d", &worker))
@@ -626,7 +736,16 @@ policer_bind_command_fn (vlib_main_t *vm, unformat_input_t *input,
     }
   else
     {
-      rv = policer_bind_worker (name, worker, bind);
+      if (~0 == policer_index && 0 != name)
+       {
+         p = hash_get_mem (pm->policer_index_by_name, name);
+         if (p != NULL)
+           policer_index = p[0];
+       }
+
+      rv = VNET_API_ERROR_NO_SUCH_ENTRY;
+      if (~0 != policer_index)
+       rv = policer_bind_worker (policer_index, worker, bind);
 
       if (rv)
        error = clib_error_return (0, "failed: `%d'", rv);
@@ -634,6 +753,7 @@ policer_bind_command_fn (vlib_main_t *vm, unformat_input_t *input,
 
 done:
   unformat_free (line_input);
+  vec_free (name);
 
   return error;
 }
@@ -644,14 +764,15 @@ policer_input_command_fn (vlib_main_t *vm, unformat_input_t *input,
 {
   unformat_input_t _line_input, *line_input = &_line_input;
   clib_error_t *error = NULL;
-  u8 apply, *name = 0;
-  u32 sw_if_index;
+  vnet_policer_main_t *pm = &vnet_policer_main;
+  u8 apply = 1;
+  u8 *name = 0;
+  u32 sw_if_index = ~0;
+  u32 policer_index = ~0;
+  uword *p;
   int rv;
   vlib_dir_t dir = cmd->function_arg;
 
-  apply = 1;
-  sw_if_index = ~0;
-
   /* Get a line of input. */
   if (!unformat_user (input, unformat_line_input, line_input))
     return 0;
@@ -660,6 +781,8 @@ policer_input_command_fn (vlib_main_t *vm, unformat_input_t *input,
     {
       if (unformat (line_input, "name %s", &name))
        ;
+      else if (unformat (line_input, "index %u", &policer_index))
+       ;
       else if (unformat (line_input, "unapply"))
        apply = 0;
       else if (unformat (line_input, "%U", unformat_vnet_sw_interface,
@@ -680,7 +803,16 @@ policer_input_command_fn (vlib_main_t *vm, unformat_input_t *input,
     }
   else
     {
-      rv = policer_input (name, sw_if_index, dir, apply);
+      if (~0 == policer_index && 0 != name)
+       {
+         p = hash_get_mem (pm->policer_index_by_name, name);
+         if (p != NULL)
+           policer_index = p[0];
+       }
+
+      rv = VNET_API_ERROR_NO_SUCH_ENTRY;
+      if (~0 != policer_index)
+       rv = policer_input (policer_index, sw_if_index, dir, apply);
 
       if (rv)
        error = clib_error_return (0, "failed: `%d'", rv);
@@ -688,108 +820,198 @@ policer_input_command_fn (vlib_main_t *vm, unformat_input_t *input,
 
 done:
   unformat_free (line_input);
+  vec_free (name);
+
+  return error;
+}
+
+static clib_error_t *
+policer_reset_command_fn (vlib_main_t *vm, unformat_input_t *input,
+                         vlib_cli_command_t *cmd)
+{
+  unformat_input_t _line_input, *line_input = &_line_input;
+  clib_error_t *error = NULL;
+  vnet_policer_main_t *pm = &vnet_policer_main;
+  int rv;
+  u32 policer_index = ~0;
+  uword *p;
+  u8 *name = 0;
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return 0;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "name %s", &name))
+       ;
+      else if (unformat (line_input, "index %u", &policer_index))
+       ;
+      else
+       {
+         error = clib_error_return (0, "unknown input `%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
+    }
+
+  if (~0 == policer_index && 0 != name)
+    {
+      p = hash_get_mem (pm->policer_index_by_name, name);
+      if (p != NULL)
+       policer_index = p[0];
+    }
+
+  rv = VNET_API_ERROR_NO_SUCH_ENTRY;
+  if (~0 != policer_index)
+    rv = policer_reset (vm, policer_index);
+
+  switch (rv)
+    {
+    case VNET_API_ERROR_NO_SUCH_ENTRY:
+      error = clib_error_return (0, "No such policer");
+      break;
+    }
+
+done:
+  unformat_free (line_input);
+  vec_free (name);
 
   return error;
 }
 
 VLIB_CLI_COMMAND (configure_policer_command, static) = {
   .path = "configure policer",
-  .short_help = "configure policer name <name> [type 1r2c | 1r3c | 2r3c-2698 "
+  .short_help = "configure policer [name <name> | index <index>] [type 1r2c | "
+               "1r3c | 2r3c-2698 "
                "| 2r3c-4115] [color-aware] [cir <cir>] [cb <cb>] [eir <eir>] "
                "[eb <eb>] [rate kbps | pps] [round closest | up | down] "
                "[conform-action drop | transmit | mark-and-transmit <dscp>] "
                "[exceed-action drop | transmit | mark-and-transmit <dscp>] "
                "[violate-action drop | transmit | mark-and-transmit <dscp>]",
   .function = policer_add_command_fn,
+  .function_arg = 1
 };
 
 VLIB_CLI_COMMAND (policer_add_command, static) = {
   .path = "policer add",
-  .short_help = "policer name <name> [type 1r2c | 1r3c | 2r3c-2698 | "
+  .short_help = "policer add name <name> [type 1r2c | 1r3c | 2r3c-2698 | "
                "2r3c-4115] [color-aware] [cir <cir>] [cb <cb>] [eir <eir>] "
                "[eb <eb>] [rate kbps | pps] [round closest | up | down] "
                "[conform-action drop | transmit | mark-and-transmit <dscp>] "
                "[exceed-action drop | transmit | mark-and-transmit <dscp>] "
                "[violate-action drop | transmit | mark-and-transmit <dscp>]",
   .function = policer_add_command_fn,
+  .function_arg = 0
 };
 
 VLIB_CLI_COMMAND (policer_del_command, static) = {
   .path = "policer del",
-  .short_help = "policer del name <name> ",
+  .short_help = "policer del [name <name> | index <index>]",
   .function = policer_del_command_fn,
 };
 
 VLIB_CLI_COMMAND (policer_bind_command, static) = {
   .path = "policer bind",
-  .short_help = "policer bind [unbind] name <name> <worker>",
+  .short_help = "policer bind [unbind] [name <name> | index <index>] <worker>",
   .function = policer_bind_command_fn,
 };
 
 VLIB_CLI_COMMAND (policer_input_command, static) = {
   .path = "policer input",
-  .short_help = "policer input [unapply] name <name> <interface>",
+  .short_help =
+    "policer input [unapply] [name <name> | index <index>] <interface>",
   .function = policer_input_command_fn,
   .function_arg = VLIB_RX,
 };
 
 VLIB_CLI_COMMAND (policer_output_command, static) = {
   .path = "policer output",
-  .short_help = "policer output [unapply] name <name> <interface>",
+  .short_help =
+    "policer output [unapply] [name <name> | index <index>] <interface>",
   .function = policer_input_command_fn,
   .function_arg = VLIB_TX,
 };
 
+VLIB_CLI_COMMAND (policer_reset_command, static) = {
+  .path = "policer reset",
+  .short_help = "policer reset [name <name> | index <index>]",
+  .function = policer_reset_command_fn
+};
+
 static clib_error_t *
 show_policer_command_fn (vlib_main_t * vm,
                         unformat_input_t * input, vlib_cli_command_t * cmd)
 {
   vnet_policer_main_t *pm = &vnet_policer_main;
-  hash_pair_t *p;
-  u32 pool_index;
-  u8 *match_name = 0;
-  u8 *name;
-  uword *pi;
+  unformat_input_t _line_input, *line_input = &_line_input;
+  policer_t *policer;
+  u32 policer_index = ~0;
+  u8 *name = 0;
+  uword *ci, *pi;
   qos_pol_cfg_params_st *config;
-  policer_t *templ;
-
-  (void) unformat (input, "name %s", &match_name);
-
-  /* *INDENT-OFF* */
-  hash_foreach_pair (p, pm->policer_config_by_name,
-  ({
-    name = (u8 *) p->key;
-    if (match_name == 0 || !strcmp((char *) name, (char *) match_name))
-      {
-       pi = hash_get_mem (pm->policer_index_by_name, name);
-
-       pool_index = p->value[0];
-       config = pool_elt_at_index (pm->configs, pool_index);
-       templ = pool_elt_at_index (pm->policer_templates, pool_index);
-       vlib_cli_output (vm, "Name \"%s\" %U ", name, format_policer_config,
-                        config);
-       if (pi)
-         {
-           vlib_cli_output (vm, "Template %U", format_policer_instance, templ,
-                            pi[0]);
-         }
-       else
-         {
-           vlib_cli_output (
-             vm, "Cannot print template - policer index hash lookup failed");
-         }
-       vlib_cli_output (vm, "-----------");
-      }
-  }));
-  /* *INDENT-ON* */
-  return 0;
+  clib_error_t *error = 0;
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    {
+      pool_foreach (policer, pm->policers)
+       {
+         ci = hash_get_mem (pm->policer_config_by_name, policer->name);
+         config = pool_elt_at_index (pm->configs, ci[0]);
+
+         vlib_cli_output (vm, "Name \"%s\" %U ", policer->name,
+                          format_policer_config, config);
+         vlib_cli_output (vm, "%U", format_policer_instance, policer);
+         vlib_cli_output (vm, "-----------");
+       }
+      return 0;
+    }
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "name %s", &name))
+       ;
+      else if (unformat (line_input, "index %u", &policer_index))
+       ;
+      else
+       {
+         error = clib_error_return (0, "unknown input `%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
+    }
+
+  if (~0 == policer_index && 0 != name)
+    {
+      pi = hash_get_mem (pm->policer_index_by_name, name);
+      if (pi != NULL)
+       policer_index = pi[0];
+    }
+
+  if (~0 == policer_index || pool_is_free_index (pm->policers, policer_index))
+    goto done;
+
+  policer = &pm->policers[policer_index];
+  ci = hash_get_mem (pm->policer_config_by_name, policer->name);
+  config = pool_elt_at_index (pm->configs, ci[0]);
+  vlib_cli_output (vm, "Name \"%s\" %U ", policer->name, format_policer_config,
+                  config);
+  vlib_cli_output (vm, "%U", format_policer_instance, policer);
+  vlib_cli_output (vm, "-----------");
+
+done:
+  unformat_free (line_input);
+  vec_free (name);
+
+  return error;
 }
 
 
 /* *INDENT-OFF* */
 VLIB_CLI_COMMAND (show_policer_command, static) = {
   .path = "show policer",
-  .short_help = "show policer [name <name>]",
+  .short_help = "show policer [name <name> | index <index>]",
   .function = show_policer_command_fn,
 };
 /* *INDENT-ON* */
@@ -801,10 +1023,8 @@ show_policer_pools_command_fn (vlib_main_t * vm,
 {
   vnet_policer_main_t *pm = &vnet_policer_main;
 
-  vlib_cli_output (vm, "pool sizes: configs=%d templates=%d policers=%d",
-                  pool_elts (pm->configs),
-                  pool_elts (pm->policer_templates),
-                  pool_elts (pm->policers));
+  vlib_cli_output (vm, "pool sizes: configs=%d policers=%d",
+                  pool_elts (pm->configs), pool_elts (pm->policers));
   return 0;
 }
 /* *INDENT-OFF* */
index f5b6c0d..7ce7fc7 100644 (file)
@@ -32,7 +32,7 @@ typedef struct
   qos_pol_cfg_params_st *configs;
   policer_t *policer_templates;
 
-  /* Config by name hash */
+  /* Config by policer name hash */
   uword *policer_config_by_name;
 
   /* Policer by name hash */
@@ -68,11 +68,16 @@ typedef enum
 } vnet_policer_next_t;
 
 u8 *format_policer_instance (u8 * s, va_list * va);
-clib_error_t *policer_add_del (vlib_main_t *vm, u8 *name,
-                              qos_pol_cfg_params_st *cfg, u32 *policer_index,
-                              u8 is_add);
-int policer_bind_worker (u8 *name, u32 worker, bool bind);
-int policer_input (u8 *name, u32 sw_if_index, vlib_dir_t dir, bool apply);
+int policer_add (vlib_main_t *vm, const u8 *name,
+                const qos_pol_cfg_params_st *cfg, u32 *policer_index);
+
+int policer_update (vlib_main_t *vm, u32 policer_index,
+                   const qos_pol_cfg_params_st *cfg);
+int policer_del (vlib_main_t *vm, u32 policer_index);
+int policer_reset (vlib_main_t *vm, u32 policer_index);
+int policer_bind_worker (u32 policer_index, u32 worker, bool bind);
+int policer_input (u32 policer_index, u32 sw_if_index, vlib_dir_t dir,
+                  bool apply);
 
 #endif /* __included_policer_h__ */
 
index 4f9baa0..df35b47 100644 (file)
@@ -35,126 +35,293 @@ static void
 vl_api_policer_add_del_t_handler (vl_api_policer_add_del_t * mp)
 {
   vlib_main_t *vm = vlib_get_main ();
+  vnet_policer_main_t *pm = &vnet_policer_main;
   vl_api_policer_add_del_reply_t *rmp;
   int rv = 0;
-  u8 *name = NULL;
+  uword *p;
+  char name[sizeof (mp->name) + 1];
   qos_pol_cfg_params_st cfg;
-  clib_error_t *error;
   u32 policer_index;
 
-  name = format (0, "%s", mp->name);
-  vec_terminate_c_string (name);
-
-  clib_memset (&cfg, 0, sizeof (cfg));
-  cfg.rfc = (qos_policer_type_en) mp->type;
-  cfg.rnd_type = (qos_round_type_en) mp->round_type;
-  cfg.rate_type = (qos_rate_type_en) mp->rate_type;
-  cfg.rb.kbps.cir_kbps = ntohl (mp->cir);
-  cfg.rb.kbps.eir_kbps = ntohl (mp->eir);
-  cfg.rb.kbps.cb_bytes = clib_net_to_host_u64 (mp->cb);
-  cfg.rb.kbps.eb_bytes = clib_net_to_host_u64 (mp->eb);
-  cfg.conform_action.action_type =
-    (qos_action_type_en) mp->conform_action.type;
-  cfg.conform_action.dscp = mp->conform_action.dscp;
-  cfg.exceed_action.action_type = (qos_action_type_en) mp->exceed_action.type;
-  cfg.exceed_action.dscp = mp->exceed_action.dscp;
-  cfg.violate_action.action_type =
-    (qos_action_type_en) mp->violate_action.type;
-  cfg.violate_action.dscp = mp->violate_action.dscp;
-
-  cfg.color_aware = mp->color_aware;
-
-  error = policer_add_del (vm, name, &cfg, &policer_index, mp->is_add);
-
-  if (error)
+  snprintf (name, sizeof (name), "%s", mp->name);
+
+  if (mp->is_add)
     {
-      rv = VNET_API_ERROR_UNSPECIFIED;
-      clib_error_free (error);
+      clib_memset (&cfg, 0, sizeof (cfg));
+      cfg.rfc = (qos_policer_type_en) mp->type;
+      cfg.rnd_type = (qos_round_type_en) mp->round_type;
+      cfg.rate_type = (qos_rate_type_en) mp->rate_type;
+      cfg.rb.kbps.cir_kbps = ntohl (mp->cir);
+      cfg.rb.kbps.eir_kbps = ntohl (mp->eir);
+      cfg.rb.kbps.cb_bytes = clib_net_to_host_u64 (mp->cb);
+      cfg.rb.kbps.eb_bytes = clib_net_to_host_u64 (mp->eb);
+      cfg.conform_action.action_type =
+       (qos_action_type_en) mp->conform_action.type;
+      cfg.conform_action.dscp = mp->conform_action.dscp;
+      cfg.exceed_action.action_type =
+       (qos_action_type_en) mp->exceed_action.type;
+      cfg.exceed_action.dscp = mp->exceed_action.dscp;
+      cfg.violate_action.action_type =
+       (qos_action_type_en) mp->violate_action.type;
+      cfg.violate_action.dscp = mp->violate_action.dscp;
+      cfg.color_aware = mp->color_aware;
+
+      rv = policer_add (vm, (u8 *) name, &cfg, &policer_index);
     }
+  else
+    {
+      p = hash_get_mem (pm->policer_index_by_name, name);
+
+      rv = VNET_API_ERROR_NO_SUCH_ENTRY;
+      if (p != NULL)
+       rv = policer_del (vm, p[0]);
+    }
+
+  REPLY_MACRO2 (VL_API_POLICER_ADD_DEL_REPLY, ({
+                 if (rv == 0 && mp->is_add)
+                   rmp->policer_index = htonl (policer_index);
+                 else
+                   rmp->policer_index = ~0;
+               }));
+}
+
+static_always_inline void
+policer_set_configuration (qos_pol_cfg_params_st *cfg,
+                          vl_api_policer_config_t *infos)
+{
+  clib_memset (cfg, 0, sizeof (*cfg));
+  cfg->rfc = (qos_policer_type_en) infos->type;
+  cfg->rnd_type = (qos_round_type_en) infos->round_type;
+  cfg->rate_type = (qos_rate_type_en) infos->rate_type;
+  cfg->rb.kbps.cir_kbps = ntohl (infos->cir);
+  cfg->rb.kbps.eir_kbps = ntohl (infos->eir);
+  cfg->rb.kbps.cb_bytes = clib_net_to_host_u64 (infos->cb);
+  cfg->rb.kbps.eb_bytes = clib_net_to_host_u64 (infos->eb);
+  cfg->conform_action.action_type =
+    (qos_action_type_en) infos->conform_action.type;
+  cfg->conform_action.dscp = infos->conform_action.dscp;
+  cfg->exceed_action.action_type =
+    (qos_action_type_en) infos->exceed_action.type;
+  cfg->exceed_action.dscp = infos->exceed_action.dscp;
+  cfg->violate_action.action_type =
+    (qos_action_type_en) infos->violate_action.type;
+  cfg->violate_action.dscp = infos->violate_action.dscp;
+  cfg->color_aware = infos->color_aware;
+}
+
+static void
+vl_api_policer_add_t_handler (vl_api_policer_add_t *mp)
+{
+  vlib_main_t *vm = vlib_get_main ();
+  vl_api_policer_add_reply_t *rmp;
+  int rv = 0;
+  char name[sizeof (mp->name) + 1];
+  qos_pol_cfg_params_st cfg;
+  u32 policer_index;
+
+  snprintf (name, sizeof (name), "%s", mp->name);
+
+  policer_set_configuration (&cfg, &mp->infos);
+
+  rv = policer_add (vm, (u8 *) name, &cfg, &policer_index);
 
-  /* *INDENT-OFF* */
-  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;
-  }));
-  /* *INDENT-ON* */
+  REPLY_MACRO2 (VL_API_POLICER_ADD_REPLY, ({
+                 if (rv == 0)
+                   rmp->policer_index = htonl (policer_index);
+                 else
+                   rmp->policer_index = ~0;
+               }));
+}
+
+static void
+vl_api_policer_del_t_handler (vl_api_policer_del_t *mp)
+{
+  vlib_main_t *vm = vlib_get_main ();
+  vl_api_policer_del_reply_t *rmp;
+  u32 policer_index;
+  int rv = 0;
+
+  policer_index = ntohl (mp->policer_index);
+  rv = policer_del (vm, policer_index);
+
+  REPLY_MACRO (VL_API_POLICER_DEL_REPLY);
+}
+
+static void
+vl_api_policer_update_t_handler (vl_api_policer_update_t *mp)
+{
+  vlib_main_t *vm = vlib_get_main ();
+  vl_api_policer_update_reply_t *rmp;
+  int rv = 0;
+  qos_pol_cfg_params_st cfg;
+  u32 policer_index;
+
+  policer_set_configuration (&cfg, &mp->infos);
+
+  policer_index = ntohl (mp->policer_index);
+  rv = policer_update (vm, policer_index, &cfg);
+
+  REPLY_MACRO (VL_API_POLICER_UPDATE_REPLY);
+}
+
+static void
+vl_api_policer_reset_t_handler (vl_api_policer_reset_t *mp)
+{
+  vlib_main_t *vm = vlib_get_main ();
+  vl_api_policer_reset_reply_t *rmp;
+  u32 policer_index;
+  int rv = 0;
+
+  policer_index = ntohl (mp->policer_index);
+  rv = policer_reset (vm, policer_index);
+
+  REPLY_MACRO (VL_API_POLICER_RESET_REPLY);
 }
 
 static void
 vl_api_policer_bind_t_handler (vl_api_policer_bind_t *mp)
 {
   vl_api_policer_bind_reply_t *rmp;
-  u8 *name;
+  vnet_policer_main_t *pm = &vnet_policer_main;
+  char name[sizeof (mp->name) + 1];
+  uword *p;
   u32 worker_index;
   u8 bind_enable;
   int rv;
 
-  name = format (0, "%s", mp->name);
-  vec_terminate_c_string (name);
+  snprintf (name, sizeof (name), "%s", mp->name);
 
   worker_index = ntohl (mp->worker_index);
   bind_enable = mp->bind_enable;
 
-  rv = policer_bind_worker (name, worker_index, bind_enable);
-  vec_free (name);
+  p = hash_get_mem (pm->policer_index_by_name, name);
+
+  rv = VNET_API_ERROR_NO_SUCH_ENTRY;
+  if (p != NULL)
+    rv = policer_bind_worker (p[0], worker_index, bind_enable);
+
   REPLY_MACRO (VL_API_POLICER_BIND_REPLY);
 }
 
+static void
+vl_api_policer_bind_v2_t_handler (vl_api_policer_bind_v2_t *mp)
+{
+  vl_api_policer_bind_v2_reply_t *rmp;
+  u32 policer_index;
+  u32 worker_index;
+  u8 bind_enable;
+  int rv;
+
+  policer_index = ntohl (mp->policer_index);
+  worker_index = ntohl (mp->worker_index);
+  bind_enable = mp->bind_enable;
+
+  rv = policer_bind_worker (policer_index, worker_index, bind_enable);
+
+  REPLY_MACRO (VL_API_POLICER_BIND_V2_REPLY);
+}
+
 static void
 vl_api_policer_input_t_handler (vl_api_policer_input_t *mp)
 {
-  vl_api_policer_bind_reply_t *rmp;
-  u8 *name;
+  vl_api_policer_input_reply_t *rmp;
+  vnet_policer_main_t *pm = &vnet_policer_main;
+  char name[sizeof (mp->name) + 1];
+  uword *p;
   u32 sw_if_index;
   u8 apply;
   int rv;
 
   VALIDATE_SW_IF_INDEX (mp);
 
-  name = format (0, "%s", mp->name);
-  vec_terminate_c_string (name);
+  snprintf (name, sizeof (name), "%s", mp->name);
 
   sw_if_index = ntohl (mp->sw_if_index);
   apply = mp->apply;
 
-  rv = policer_input (name, sw_if_index, VLIB_RX, apply);
-  vec_free (name);
+  p = hash_get_mem (pm->policer_index_by_name, name);
+
+  rv = VNET_API_ERROR_NO_SUCH_ENTRY;
+  if (p != NULL)
+    rv = policer_input (p[0], sw_if_index, VLIB_RX, apply);
 
   BAD_SW_IF_INDEX_LABEL;
   REPLY_MACRO (VL_API_POLICER_INPUT_REPLY);
 }
 
 static void
-vl_api_policer_output_t_handler (vl_api_policer_input_t *mp)
+vl_api_policer_input_v2_t_handler (vl_api_policer_input_v2_t *mp)
 {
-  vl_api_policer_bind_reply_t *rmp;
-  u8 *name;
+  vl_api_policer_input_v2_reply_t *rmp;
+  u32 policer_index;
+  u32 sw_if_index;
+  u8 apply;
+  int rv;
+
+  VALIDATE_SW_IF_INDEX (mp);
+
+  policer_index = ntohl (mp->policer_index);
+  sw_if_index = ntohl (mp->sw_if_index);
+  apply = mp->apply;
+
+  rv = policer_input (policer_index, sw_if_index, VLIB_RX, apply);
+
+  BAD_SW_IF_INDEX_LABEL;
+  REPLY_MACRO (VL_API_POLICER_INPUT_REPLY);
+}
+
+static void
+vl_api_policer_output_t_handler (vl_api_policer_output_t *mp)
+{
+  vl_api_policer_output_reply_t *rmp;
+  vnet_policer_main_t *pm = &vnet_policer_main;
+  char name[sizeof (mp->name) + 1];
+  uword *p;
   u32 sw_if_index;
   u8 apply;
   int rv;
 
   VALIDATE_SW_IF_INDEX (mp);
 
-  name = format (0, "%s", mp->name);
-  vec_terminate_c_string (name);
+  snprintf (name, sizeof (name), "%s", mp->name);
 
   sw_if_index = ntohl (mp->sw_if_index);
   apply = mp->apply;
 
-  rv = policer_input (name, sw_if_index, VLIB_TX, apply);
-  vec_free (name);
+  p = hash_get_mem (pm->policer_index_by_name, name);
+
+  rv = VNET_API_ERROR_NO_SUCH_ENTRY;
+  if (p != NULL)
+    rv = policer_input (p[0], sw_if_index, VLIB_TX, apply);
 
   BAD_SW_IF_INDEX_LABEL;
   REPLY_MACRO (VL_API_POLICER_OUTPUT_REPLY);
 }
 
 static void
-send_policer_details (u8 *name, qos_pol_cfg_params_st *config,
-                     policer_t *templ, vl_api_registration_t *reg,
-                     u32 context)
+vl_api_policer_output_v2_t_handler (vl_api_policer_output_v2_t *mp)
+{
+  vl_api_policer_output_reply_t *rmp;
+  u32 policer_index;
+  u32 sw_if_index;
+  u8 apply;
+  int rv;
+
+  VALIDATE_SW_IF_INDEX (mp);
+
+  policer_index = ntohl (mp->policer_index);
+  sw_if_index = ntohl (mp->sw_if_index);
+  apply = mp->apply;
+
+  rv = policer_input (policer_index, sw_if_index, VLIB_TX, apply);
+
+  BAD_SW_IF_INDEX_LABEL;
+  REPLY_MACRO (VL_API_POLICER_OUTPUT_REPLY);
+}
+
+static void
+send_policer_details (qos_pol_cfg_params_st *config, policer_t *policer,
+                     vl_api_registration_t *reg, u32 context)
 {
   vl_api_policer_details_t *mp;
 
@@ -170,26 +337,27 @@ send_policer_details (u8 *name, qos_pol_cfg_params_st *config,
   mp->round_type = (vl_api_sse2_qos_round_type_t) config->rnd_type;
   mp->type = (vl_api_sse2_qos_policer_type_t) config->rfc;
   mp->conform_action.type =
-    (vl_api_sse2_qos_action_type_t) config->conform_action.action_type;
-  mp->conform_action.dscp = config->conform_action.dscp;
+    (vl_api_sse2_qos_action_type_t) policer->action[POLICE_CONFORM];
+  mp->conform_action.dscp = policer->mark_dscp[POLICE_CONFORM];
   mp->exceed_action.type =
-    (vl_api_sse2_qos_action_type_t) config->exceed_action.action_type;
-  mp->exceed_action.dscp = config->exceed_action.dscp;
+    (vl_api_sse2_qos_action_type_t) policer->action[POLICE_EXCEED];
+  mp->exceed_action.dscp = policer->mark_dscp[POLICE_EXCEED];
   mp->violate_action.type =
-    (vl_api_sse2_qos_action_type_t) config->violate_action.action_type;
-  mp->violate_action.dscp = config->violate_action.dscp;
-  mp->single_rate = templ->single_rate ? 1 : 0;
-  mp->color_aware = templ->color_aware ? 1 : 0;
-  mp->scale = htonl (templ->scale);
-  mp->cir_tokens_per_period = htonl (templ->cir_tokens_per_period);
-  mp->pir_tokens_per_period = htonl (templ->pir_tokens_per_period);
-  mp->current_limit = htonl (templ->current_limit);
-  mp->current_bucket = htonl (templ->current_bucket);
-  mp->extended_limit = htonl (templ->extended_limit);
-  mp->extended_bucket = htonl (templ->extended_bucket);
-  mp->last_update_time = clib_host_to_net_u64 (templ->last_update_time);
-
-  strncpy ((char *) mp->name, (char *) name, ARRAY_LEN (mp->name) - 1);
+    (vl_api_sse2_qos_action_type_t) policer->action[POLICE_VIOLATE];
+  mp->violate_action.dscp = policer->mark_dscp[POLICE_VIOLATE];
+  mp->single_rate = policer->single_rate ? 1 : 0;
+  mp->color_aware = policer->color_aware ? 1 : 0;
+  mp->scale = htonl (policer->scale);
+  mp->cir_tokens_per_period = htonl (policer->cir_tokens_per_period);
+  mp->pir_tokens_per_period = htonl (policer->pir_tokens_per_period);
+  mp->current_limit = htonl (policer->current_limit);
+  mp->current_bucket = htonl (policer->current_bucket);
+  mp->extended_limit = htonl (policer->extended_limit);
+  mp->extended_bucket = htonl (policer->extended_bucket);
+  mp->last_update_time = clib_host_to_net_u64 (policer->last_update_time);
+
+  strncpy ((char *) mp->name, (char *) policer->name,
+          ARRAY_LEN (mp->name) - 1);
 
   vl_api_send_msg (reg, (u8 *) mp);
 }
@@ -199,13 +367,11 @@ vl_api_policer_dump_t_handler (vl_api_policer_dump_t * mp)
 {
   vl_api_registration_t *reg;
   vnet_policer_main_t *pm = &vnet_policer_main;
-  hash_pair_t *hp;
-  uword *p;
-  u32 pool_index;
+  uword *p, *pi;
+  u32 pool_index, policer_index;
   u8 *match_name = 0;
-  u8 *name;
   qos_pol_cfg_params_st *config;
-  policer_t *templ;
+  policer_t *policer;
 
   reg = vl_api_client_index_to_registration (mp->client_index);
   if (!reg)
@@ -220,26 +386,67 @@ vl_api_policer_dump_t_handler (vl_api_policer_dump_t * mp)
   if (mp->match_name_valid)
     {
       p = hash_get_mem (pm->policer_config_by_name, match_name);
-      if (p)
+      pi = hash_get_mem (pm->policer_index_by_name, match_name);
+      if (0 == p || 0 == pi)
+       return;
+
+      pool_index = p[0];
+      policer_index = pi[0];
+      config = pool_elt_at_index (pm->configs, pool_index);
+      policer = pool_elt_at_index (pm->policers, policer_index);
+      send_policer_details (config, policer, reg, mp->context);
+    }
+  else
+    {
+      pool_foreach (policer, pm->policers)
+       {
+         p = hash_get_mem (pm->policer_config_by_name, policer->name);
+         if (0 == p)
+           continue;
+
+         pool_index = p[0];
+         config = pool_elt_at_index (pm->configs, pool_index);
+         send_policer_details (config, policer, reg, mp->context);
+       };
+    }
+}
+
+static void
+vl_api_policer_dump_v2_t_handler (vl_api_policer_dump_v2_t *mp)
+{
+  vl_api_registration_t *reg;
+  vnet_policer_main_t *pm = &vnet_policer_main;
+  qos_pol_cfg_params_st *config;
+  u32 policer_index, pool_index;
+  policer_t *policer;
+  uword *p;
+
+  reg = vl_api_client_index_to_registration (mp->client_index);
+  if (!reg)
+    return;
+
+  policer_index = ntohl (mp->policer_index);
+
+  if (~0 == policer_index)
+    {
+      pool_foreach (policer, pm->policers)
        {
+         p = hash_get_mem (pm->policer_config_by_name, policer->name);
          pool_index = p[0];
          config = pool_elt_at_index (pm->configs, pool_index);
-         templ = pool_elt_at_index (pm->policer_templates, pool_index);
-         send_policer_details (match_name, config, templ, reg, mp->context);
-       }
+         send_policer_details (config, policer, reg, mp->context);
+       };
     }
   else
     {
-      /* *INDENT-OFF* */
-      hash_foreach_pair (hp, pm->policer_config_by_name,
-      ({
-        name = (u8 *) hp->key;
-        pool_index = hp->value[0];
-        config = pool_elt_at_index (pm->configs, pool_index);
-        templ = pool_elt_at_index (pm->policer_templates, pool_index);
-        send_policer_details(name, config, templ, reg, mp->context);
-      }));
-      /* *INDENT-ON* */
+      if (pool_is_free_index (pm->policers, policer_index))
+       return;
+
+      policer = &pm->policers[policer_index];
+      p = hash_get_mem (pm->policer_config_by_name, policer->name);
+      pool_index = p[0];
+      config = pool_elt_at_index (pm->configs, pool_index);
+      send_policer_details (config, policer, reg, mp->context);
     }
 }
 
index 3e21b7d..9d4c644 100644 (file)
@@ -56,6 +56,34 @@ typedef sse2_qos_action
   u8 dscp;
 };
 
+/** \brief Policer configuration
+    @param cir - CIR
+    @param eir - EIR
+    @param cb - Committed Burst
+    @param eb - Excess or Peak Burst
+    @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 - conform action
+    @param exceed_action - exceed action type
+    @param violate_action - violate action type
+*/
+typedef policer_config
+{
+  u32 cir;
+  u32 eir;
+  u64 cb;
+  u64 eb;
+  vl_api_sse2_qos_rate_type_t rate_type;
+  vl_api_sse2_qos_round_type_t round_type;
+  vl_api_sse2_qos_policer_type_t type;
+  bool color_aware;
+  vl_api_sse2_qos_action_t conform_action;
+  vl_api_sse2_qos_action_t exceed_action;
+  vl_api_sse2_qos_action_t violate_action;
+};
+
 /*
  * Local Variables:
  * eval: (c-set-style "gnu")
index 9c4d76f..bffd208 100644 (file)
@@ -1058,7 +1058,7 @@ x86_pol_compute_hw_params (qos_pol_cfg_params_st *cfg, policer_t *hw)
  * Return: Status, success or failure code.
  */
 int
-pol_logical_2_physical (qos_pol_cfg_params_st *cfg, policer_t *phys)
+pol_logical_2_physical (const qos_pol_cfg_params_st *cfg, policer_t *phys)
 {
   int rc;
   qos_pol_cfg_params_st kbps_cfg;
index 722ac2f..7f6ebe7 100644 (file)
@@ -158,7 +158,7 @@ typedef struct qos_pol_hw_params_st_
   u32 extd_bkt;
 } qos_pol_hw_params_st;
 
-int pol_logical_2_physical (qos_pol_cfg_params_st *cfg, policer_t *phys);
+int pol_logical_2_physical (const qos_pol_cfg_params_st *cfg, policer_t *phys);
 
 #endif /* __included_xlate_h__ */
 
index 9d44fc1..6b4ab54 100644 (file)
@@ -92,6 +92,85 @@ class TestPolicerInput(VppTestCase):
         """Output Policing"""
         self.policer_interface_test(Dir.TX)
 
+    def test_policer_reset(self):
+        """Policer reset bucket"""
+        pkts = self.pkt * NUM_PKTS
+
+        action_tx = PolicerAction(
+            VppEnum.vl_api_sse2_qos_action_type_t.SSE2_QOS_ACTION_API_TRANSMIT, 0
+        )
+        policer = VppPolicer(
+            self,
+            "pol1",
+            1,
+            0,
+            10000,
+            0,
+            conform_action=action_tx,
+            exceed_action=action_tx,
+            violate_action=action_tx,
+        )
+        policer.add_vpp_config()
+
+        # Start policing on pg0
+        policer.apply_vpp_config(self.pg0.sw_if_index, Dir.RX, True)
+
+        self.send_and_expect(self.pg0, pkts, self.pg1, worker=0)
+        details = policer.get_details()
+
+        self.assertGreater(details.current_limit, details.current_bucket)
+
+        self.send_and_expect(self.pg0, pkts, self.pg1, worker=0)
+        self.vapi.policer_reset(policer_index=policer.policer_index)
+        details = policer.get_details()
+
+        self.assertEqual(details.current_limit, details.current_bucket)
+
+        policer.apply_vpp_config(self.pg0.sw_if_index, Dir.RX, False)
+
+        policer.remove_vpp_config()
+
+    def test_policer_update(self):
+        """Policer update"""
+        pkts = self.pkt * NUM_PKTS
+
+        action_tx = PolicerAction(
+            VppEnum.vl_api_sse2_qos_action_type_t.SSE2_QOS_ACTION_API_TRANSMIT, 0
+        )
+        policer = VppPolicer(
+            self,
+            "pol1",
+            1,
+            0,
+            10000,
+            0,
+            conform_action=action_tx,
+            exceed_action=action_tx,
+            violate_action=action_tx,
+        )
+        policer.add_vpp_config()
+
+        # Start policing on pg0
+        policer.apply_vpp_config(self.pg0.sw_if_index, Dir.RX, True)
+
+        self.send_and_expect(self.pg0, pkts, self.pg1, worker=0)
+        details_before = policer.get_details()
+
+        self.assertGreater(details_before.current_limit, details_before.current_bucket)
+
+        policer.cir = 8000
+        policer.commited_burst = 100000
+        policer.update()
+
+        details_after = policer.get_details()
+
+        self.assertGreater(details_after.cir, details_before.cir)
+        self.assertGreater(details_after.cb, details_before.cb)
+
+        policer.apply_vpp_config(self.pg0.sw_if_index, Dir.RX, False)
+
+        policer.remove_vpp_config()
+
     def policer_handoff_test(self, dir: Dir):
         pkts = self.pkt * NUM_PKTS
 
index b0097b3..b48f4c6 100644 (file)
@@ -57,46 +57,54 @@ class VppPolicer(VppObject):
     def policer_index(self):
         return self._policer_index
 
+    @property
+    def config(self):
+        return {
+            "cir": self.cir,
+            "eir": self.eir,
+            "cb": self.commited_burst,
+            "eb": self.excess_burst,
+            "rate_type": self.rate_type,
+            "round_type": self.round_type,
+            "type": self.type,
+            "color_aware": self.color_aware,
+            "conform_action": self.conform_action.encode(),
+            "exceed_action": self.exceed_action.encode(),
+            "violate_action": self.violate_action.encode(),
+        }
+
     def add_vpp_config(self):
-        r = self._test.vapi.policer_add_del(
-            name=self.name,
-            cir=self.cir,
-            eir=self.eir,
-            cb=self.commited_burst,
-            eb=self.excess_burst,
-            rate_type=self.rate_type,
-            round_type=self.round_type,
-            type=self.type,
-            color_aware=self.color_aware,
-            conform_action=self.conform_action.encode(),
-            exceed_action=self.exceed_action.encode(),
-            violate_action=self.violate_action.encode(),
-        )
+        r = self._test.vapi.policer_add(name=self.name, infos=self.config)
         self._test.registry.register(self, self._test.logger)
         self._policer_index = r.policer_index
         return self
 
+    def update(self):
+        self._test.vapi.policer_update(
+            policer_index=self._policer_index, infos=self.config
+        )
+
     def remove_vpp_config(self):
-        self._test.vapi.policer_add_del(is_add=False, name=self.name)
+        self._test.vapi.policer_del(policer_index=self._policer_index)
         self._policer_index = INVALID_INDEX
 
     def bind_vpp_config(self, worker, bind):
-        self._test.vapi.policer_bind(
-            name=self.name, worker_index=worker, bind_enable=bind
+        self._test.vapi.policer_bind_v2(
+            policer_index=self._policer_index, worker_index=worker, bind_enable=bind
         )
 
     def apply_vpp_config(self, if_index, dir: Dir, apply):
         if dir == Dir.RX:
-            self._test.vapi.policer_input(
-                name=self.name, sw_if_index=if_index, apply=apply
+            self._test.vapi.policer_input_v2(
+                policer_index=self._policer_index, sw_if_index=if_index, apply=apply
             )
         else:
-            self._test.vapi.policer_output(
-                name=self.name, sw_if_index=if_index, apply=apply
+            self._test.vapi.policer_output_v2(
+                policer_index=self._policer_index, sw_if_index=if_index, apply=apply
             )
 
     def query_vpp_config(self):
-        dump = self._test.vapi.policer_dump(match_name_valid=True, match_name=self.name)
+        dump = self._test.vapi.policer_dump_v2(policer_index=self._policer_index)
         for policer in dump:
             if policer.name == self.name:
                 return True
@@ -105,6 +113,13 @@ class VppPolicer(VppObject):
     def object_id(self):
         return "policer-%s" % (self.name)
 
+    def get_details(self):
+        dump = self._test.vapi.policer_dump_v2(policer_index=self._policer_index)
+        for policer in dump:
+            if policer.name == self.name:
+                return policer
+        raise self._test.vapi.VPPValueError("Missing policer")
+
     def get_stats(self, worker=None):
         conform = self._test.statistics.get_counter("/net/policer/conform")
         exceed = self._test.statistics.get_counter("/net/policer/exceed")