LCOV - code coverage report
Current view: top level - vnet/policer - policer.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 106 483 21.9 %
Date: 2023-10-26 01:39:38 Functions: 28 52 53.8 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : #include <stdint.h>
      16             : #include <stdbool.h>
      17             : #include <vnet/policer/policer.h>
      18             : #include <vnet/policer/police_inlines.h>
      19             : #include <vnet/classify/vnet_classify.h>
      20             : #include <vnet/ip/ip_packet.h>
      21             : 
      22             : vnet_policer_main_t vnet_policer_main;
      23             : 
      24             : u8 *
      25        1641 : format_policer_handoff_trace (u8 *s, va_list *args)
      26             : {
      27        1641 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      28        1641 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      29        1641 :   policer_handoff_trace_t *t = va_arg (*args, policer_handoff_trace_t *);
      30             : 
      31        1641 :   s = format (s, "policer %d, handoff thread %d to %d", t->policer_index,
      32             :               t->current_worker_index, t->next_worker_index);
      33             : 
      34        1641 :   return s;
      35             : }
      36             : 
      37             : vlib_combined_counter_main_t policer_counters[] = {
      38             :   {
      39             :     .name = "Policer-Conform",
      40             :     .stat_segment_name = "/net/policer/conform",
      41             :   },
      42             :   {
      43             :     .name = "Policer-Exceed",
      44             :     .stat_segment_name = "/net/policer/exceed",
      45             :   },
      46             :   {
      47             :     .name = "Policer-Violate",
      48             :     .stat_segment_name = "/net/policer/violate",
      49             :   },
      50             : };
      51             : 
      52             : int
      53          28 : policer_add (vlib_main_t *vm, const u8 *name, const qos_pol_cfg_params_st *cfg,
      54             :              u32 *policer_index)
      55             : {
      56          28 :   vnet_policer_main_t *pm = &vnet_policer_main;
      57             :   policer_t test_policer;
      58             :   policer_t *policer;
      59             :   policer_t *pp;
      60             :   qos_pol_cfg_params_st *cp;
      61             :   uword *p;
      62             :   u32 pi;
      63             :   int rv;
      64             :   int i;
      65             : 
      66          28 :   p = hash_get_mem (pm->policer_config_by_name, name);
      67             : 
      68          28 :   if (p != NULL)
      69           0 :     return VNET_API_ERROR_VALUE_EXIST;
      70             : 
      71             :   /* Vet the configuration before adding it to the table */
      72          28 :   rv = pol_logical_2_physical (cfg, &test_policer);
      73             : 
      74          28 :   if (rv != 0)
      75           0 :     return VNET_API_ERROR_INVALID_VALUE;
      76             : 
      77          28 :   pool_get (pm->configs, cp);
      78          28 :   pool_get_aligned (pm->policers, policer, CLIB_CACHE_LINE_BYTES);
      79             : 
      80          28 :   clib_memcpy (cp, cfg, sizeof (*cp));
      81          28 :   clib_memcpy (policer, &test_policer, sizeof (*pp));
      82             : 
      83          28 :   policer->name = format (0, "%s%c", name, 0);
      84          28 :   pi = policer - pm->policers;
      85             : 
      86          56 :   hash_set_mem (pm->policer_config_by_name, policer->name, cp - pm->configs);
      87          56 :   hash_set_mem (pm->policer_index_by_name, policer->name, pi);
      88          28 :   *policer_index = pi;
      89          28 :   policer->thread_index = ~0;
      90             : 
      91         112 :   for (i = 0; i < NUM_POLICE_RESULTS; i++)
      92             :     {
      93          84 :       vlib_validate_combined_counter (&policer_counters[i], pi);
      94          84 :       vlib_zero_combined_counter (&policer_counters[i], pi);
      95             :     }
      96             : 
      97          28 :   return 0;
      98             : }
      99             : 
     100             : int
     101          28 : policer_del (vlib_main_t *vm, u32 policer_index)
     102             : {
     103          28 :   vnet_policer_main_t *pm = &vnet_policer_main;
     104             :   policer_t *policer;
     105             :   uword *p;
     106             : 
     107          28 :   if (pool_is_free_index (pm->policers, policer_index))
     108           0 :     return VNET_API_ERROR_NO_SUCH_ENTRY;
     109             : 
     110          28 :   policer = &pm->policers[policer_index];
     111             : 
     112          56 :   p = hash_get_mem (pm->policer_config_by_name, policer->name);
     113             : 
     114             :   /* free policer config */
     115          28 :   if (p != NULL)
     116             :     {
     117          28 :       pool_put_index (pm->configs, p[0]);
     118          56 :       hash_unset_mem (pm->policer_config_by_name, policer->name);
     119             :     }
     120             : 
     121             :   /* free policer */
     122          56 :   hash_unset_mem (pm->policer_index_by_name, policer->name);
     123          28 :   vec_free (policer->name);
     124          28 :   pool_put_index (pm->policers, policer_index);
     125             : 
     126          28 :   return 0;
     127             : }
     128             : 
     129             : int
     130           1 : policer_update (vlib_main_t *vm, u32 policer_index,
     131             :                 const qos_pol_cfg_params_st *cfg)
     132             : {
     133           1 :   vnet_policer_main_t *pm = &vnet_policer_main;
     134             :   policer_t test_policer;
     135             :   policer_t *policer;
     136             :   qos_pol_cfg_params_st *cp;
     137             :   uword *p;
     138             :   u8 *name;
     139             :   int rv;
     140             :   int i;
     141             : 
     142           1 :   if (pool_is_free_index (pm->policers, policer_index))
     143           0 :     return VNET_API_ERROR_NO_SUCH_ENTRY;
     144             : 
     145           1 :   policer = &pm->policers[policer_index];
     146             : 
     147             :   /* Vet the configuration before adding it to the table */
     148           1 :   rv = pol_logical_2_physical (cfg, &test_policer);
     149           1 :   if (rv != 0)
     150           0 :     return VNET_API_ERROR_INVALID_VALUE;
     151             : 
     152           2 :   p = hash_get_mem (pm->policer_config_by_name, policer->name);
     153             : 
     154           1 :   if (PREDICT_TRUE (p != NULL))
     155             :     {
     156           1 :       cp = &pm->configs[p[0]];
     157             :     }
     158             :   else
     159             :     {
     160             :       /* recover from a missing configuration */
     161           0 :       pool_get (pm->configs, cp);
     162           0 :       hash_set_mem (pm->policer_config_by_name, policer->name,
     163             :                     cp - pm->configs);
     164             :     }
     165             : 
     166           1 :   name = policer->name;
     167             : 
     168           1 :   clib_memcpy (cp, cfg, sizeof (*cp));
     169           1 :   clib_memcpy (policer, &test_policer, sizeof (*policer));
     170             : 
     171           1 :   policer->name = name;
     172           1 :   policer->thread_index = ~0;
     173             : 
     174           4 :   for (i = 0; i < NUM_POLICE_RESULTS; i++)
     175           3 :     vlib_zero_combined_counter (&policer_counters[i], policer_index);
     176             : 
     177           1 :   return 0;
     178             : }
     179             : 
     180             : int
     181           1 : policer_reset (vlib_main_t *vm, u32 policer_index)
     182             : {
     183           1 :   vnet_policer_main_t *pm = &vnet_policer_main;
     184             :   policer_t *policer;
     185             : 
     186           1 :   if (pool_is_free_index (pm->policers, policer_index))
     187           0 :     return VNET_API_ERROR_NO_SUCH_ENTRY;
     188             : 
     189           1 :   policer = &pm->policers[policer_index];
     190             : 
     191           1 :   policer->current_bucket = policer->current_limit;
     192           1 :   policer->extended_bucket = policer->extended_limit;
     193             : 
     194           1 :   return 0;
     195             : }
     196             : 
     197             : int
     198          12 : policer_bind_worker (u32 policer_index, u32 worker, bool bind)
     199             : {
     200          12 :   vnet_policer_main_t *pm = &vnet_policer_main;
     201             :   policer_t *policer;
     202             : 
     203          12 :   if (pool_is_free_index (pm->policers, policer_index))
     204           0 :     return VNET_API_ERROR_NO_SUCH_ENTRY;
     205             : 
     206          12 :   policer = &pm->policers[policer_index];
     207             : 
     208          12 :   if (bind)
     209             :     {
     210           8 :       if (worker >= vlib_num_workers ())
     211             :         {
     212           0 :           return VNET_API_ERROR_INVALID_WORKER;
     213             :         }
     214             : 
     215           8 :       policer->thread_index = vlib_get_worker_thread_index (worker);
     216             :     }
     217             :   else
     218             :     {
     219           4 :       policer->thread_index = ~0;
     220             :     }
     221          12 :   return 0;
     222             : }
     223             : 
     224             : int
     225          20 : policer_input (u32 policer_index, u32 sw_if_index, vlib_dir_t dir, bool apply)
     226             : {
     227          20 :   vnet_policer_main_t *pm = &vnet_policer_main;
     228             : 
     229          20 :   if (apply)
     230             :     {
     231          10 :       vec_validate (pm->policer_index_by_sw_if_index[dir], sw_if_index);
     232          10 :       pm->policer_index_by_sw_if_index[dir][sw_if_index] = policer_index;
     233             :     }
     234             :   else
     235             :     {
     236          10 :       pm->policer_index_by_sw_if_index[dir][sw_if_index] = ~0;
     237             :     }
     238             : 
     239          20 :   if (dir == VLIB_RX)
     240             :     {
     241          16 :       vnet_feature_enable_disable ("device-input", "policer-input",
     242             :                                    sw_if_index, apply, 0, 0);
     243             :     }
     244             :   else
     245             :     {
     246           4 :       vnet_feature_enable_disable ("ip4-output", "policer-output", sw_if_index,
     247             :                                    apply, 0, 0);
     248           4 :       vnet_feature_enable_disable ("ip6-output", "policer-output", sw_if_index,
     249             :                                    apply, 0, 0);
     250             :     }
     251          20 :   return 0;
     252             : }
     253             : 
     254             : u8 *
     255           0 : format_policer_instance (u8 * s, va_list * va)
     256             : {
     257           0 :   vnet_policer_main_t *pm = &vnet_policer_main;
     258           0 :   policer_t *i = va_arg (*va, policer_t *);
     259           0 :   u32 policer_index = i - pm->policers;
     260             :   int result;
     261             :   vlib_counter_t counts[NUM_POLICE_RESULTS];
     262             : 
     263           0 :   for (result = 0; result < NUM_POLICE_RESULTS; result++)
     264             :     {
     265           0 :       vlib_get_combined_counter (&policer_counters[result], policer_index,
     266             :                                  &counts[result]);
     267             :     }
     268             : 
     269             :   s =
     270           0 :     format (s, "Policer at index %d: %s rate, %s color-aware\n", policer_index,
     271           0 :             i->single_rate ? "single" : "dual", i->color_aware ? "is" : "not");
     272           0 :   s = format (s, "cir %u tok/period, pir %u tok/period, scale %u\n",
     273             :               i->cir_tokens_per_period, i->pir_tokens_per_period, i->scale);
     274           0 :   s = format (s, "cur lim %u, cur bkt %u, ext lim %u, ext bkt %u\n",
     275             :               i->current_limit,
     276             :               i->current_bucket, i->extended_limit, i->extended_bucket);
     277           0 :   s = format (s, "last update %llu\n", i->last_update_time);
     278           0 :   s = format (s, "conform %llu packets, %llu bytes\n",
     279             :               counts[POLICE_CONFORM].packets, counts[POLICE_CONFORM].bytes);
     280           0 :   s = format (s, "exceed %llu packets, %llu bytes\n",
     281             :               counts[POLICE_EXCEED].packets, counts[POLICE_EXCEED].bytes);
     282           0 :   s = format (s, "violate %llu packets, %llu bytes\n",
     283             :               counts[POLICE_VIOLATE].packets, counts[POLICE_VIOLATE].bytes);
     284           0 :   return s;
     285             : }
     286             : 
     287             : static u8 *
     288           0 : format_policer_round_type (u8 * s, va_list * va)
     289             : {
     290           0 :   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
     291             : 
     292           0 :   if (c->rnd_type == QOS_ROUND_TO_CLOSEST)
     293           0 :     s = format (s, "closest");
     294           0 :   else if (c->rnd_type == QOS_ROUND_TO_UP)
     295           0 :     s = format (s, "up");
     296           0 :   else if (c->rnd_type == QOS_ROUND_TO_DOWN)
     297           0 :     s = format (s, "down");
     298             :   else
     299           0 :     s = format (s, "ILLEGAL");
     300           0 :   return s;
     301             : }
     302             : 
     303             : 
     304             : static u8 *
     305           0 : format_policer_rate_type (u8 * s, va_list * va)
     306             : {
     307           0 :   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
     308             : 
     309           0 :   if (c->rate_type == QOS_RATE_KBPS)
     310           0 :     s = format (s, "kbps");
     311           0 :   else if (c->rate_type == QOS_RATE_PPS)
     312           0 :     s = format (s, "pps");
     313             :   else
     314           0 :     s = format (s, "ILLEGAL");
     315           0 :   return s;
     316             : }
     317             : 
     318             : static u8 *
     319           0 : format_policer_type (u8 * s, va_list * va)
     320             : {
     321           0 :   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
     322             : 
     323           0 :   if (c->rfc == QOS_POLICER_TYPE_1R2C)
     324           0 :     s = format (s, "1r2c");
     325             : 
     326           0 :   else if (c->rfc == QOS_POLICER_TYPE_1R3C_RFC_2697)
     327           0 :     s = format (s, "1r3c");
     328             : 
     329           0 :   else if (c->rfc == QOS_POLICER_TYPE_2R3C_RFC_2698)
     330           0 :     s = format (s, "2r3c-2698");
     331             : 
     332           0 :   else if (c->rfc == QOS_POLICER_TYPE_2R3C_RFC_4115)
     333           0 :     s = format (s, "2r3c-4115");
     334             : 
     335           0 :   else if (c->rfc == QOS_POLICER_TYPE_2R3C_RFC_MEF5CF1)
     336           0 :     s = format (s, "2r3c-mef5cf1");
     337             :   else
     338           0 :     s = format (s, "ILLEGAL");
     339           0 :   return s;
     340             : }
     341             : 
     342             : static u8 *
     343           0 : format_policer_action_type (u8 * s, va_list * va)
     344             : {
     345           0 :   qos_pol_action_params_st *a = va_arg (*va, qos_pol_action_params_st *);
     346             : 
     347           0 :   if (a->action_type == QOS_ACTION_DROP)
     348           0 :     s = format (s, "drop");
     349           0 :   else if (a->action_type == QOS_ACTION_TRANSMIT)
     350           0 :     s = format (s, "transmit");
     351           0 :   else if (a->action_type == QOS_ACTION_MARK_AND_TRANSMIT)
     352           0 :     s = format (s, "mark-and-transmit %U", format_ip_dscp, a->dscp);
     353             :   else
     354           0 :     s = format (s, "ILLEGAL");
     355           0 :   return s;
     356             : }
     357             : 
     358             : u8 *
     359           0 : format_policer_config (u8 * s, va_list * va)
     360             : {
     361           0 :   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
     362             : 
     363           0 :   s = format (s, "type %U cir %u eir %u cb %u eb %u\n",
     364             :               format_policer_type, c,
     365             :               c->rb.kbps.cir_kbps,
     366             :               c->rb.kbps.eir_kbps, c->rb.kbps.cb_bytes, c->rb.kbps.eb_bytes);
     367           0 :   s = format (s, "rate type %U, round type %U\n",
     368             :               format_policer_rate_type, c, format_policer_round_type, c);
     369           0 :   s = format (s, "conform action %U, exceed action %U, violate action %U\n",
     370             :               format_policer_action_type, &c->conform_action,
     371             :               format_policer_action_type, &c->exceed_action,
     372             :               format_policer_action_type, &c->violate_action);
     373           0 :   return s;
     374             : }
     375             : 
     376             : static uword
     377           0 : unformat_policer_type (unformat_input_t * input, va_list * va)
     378             : {
     379           0 :   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
     380             : 
     381           0 :   if (!unformat (input, "type"))
     382           0 :     return 0;
     383             : 
     384           0 :   if (unformat (input, "1r2c"))
     385           0 :     c->rfc = QOS_POLICER_TYPE_1R2C;
     386           0 :   else if (unformat (input, "1r3c"))
     387           0 :     c->rfc = QOS_POLICER_TYPE_1R3C_RFC_2697;
     388           0 :   else if (unformat (input, "2r3c-2698"))
     389           0 :     c->rfc = QOS_POLICER_TYPE_2R3C_RFC_2698;
     390           0 :   else if (unformat (input, "2r3c-4115"))
     391           0 :     c->rfc = QOS_POLICER_TYPE_2R3C_RFC_4115;
     392           0 :   else if (unformat (input, "2r3c-mef5cf1"))
     393           0 :     c->rfc = QOS_POLICER_TYPE_2R3C_RFC_MEF5CF1;
     394             :   else
     395           0 :     return 0;
     396           0 :   return 1;
     397             : }
     398             : 
     399             : static uword
     400           0 : unformat_policer_round_type (unformat_input_t * input, va_list * va)
     401             : {
     402           0 :   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
     403             : 
     404           0 :   if (!unformat (input, "round"))
     405           0 :     return 0;
     406             : 
     407           0 :   if (unformat (input, "closest"))
     408           0 :     c->rnd_type = QOS_ROUND_TO_CLOSEST;
     409           0 :   else if (unformat (input, "up"))
     410           0 :     c->rnd_type = QOS_ROUND_TO_UP;
     411           0 :   else if (unformat (input, "down"))
     412           0 :     c->rnd_type = QOS_ROUND_TO_DOWN;
     413             :   else
     414           0 :     return 0;
     415           0 :   return 1;
     416             : }
     417             : 
     418             : static uword
     419           0 : unformat_policer_rate_type (unformat_input_t * input, va_list * va)
     420             : {
     421           0 :   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
     422             : 
     423           0 :   if (!unformat (input, "rate"))
     424           0 :     return 0;
     425             : 
     426           0 :   if (unformat (input, "kbps"))
     427           0 :     c->rate_type = QOS_RATE_KBPS;
     428           0 :   else if (unformat (input, "pps"))
     429           0 :     c->rate_type = QOS_RATE_PPS;
     430             :   else
     431           0 :     return 0;
     432           0 :   return 1;
     433             : }
     434             : 
     435             : static uword
     436           0 : unformat_policer_cir (unformat_input_t * input, va_list * va)
     437             : {
     438           0 :   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
     439             : 
     440           0 :   if (unformat (input, "cir %u", &c->rb.kbps.cir_kbps))
     441           0 :     return 1;
     442           0 :   return 0;
     443             : }
     444             : 
     445             : static uword
     446           0 : unformat_policer_eir (unformat_input_t * input, va_list * va)
     447             : {
     448           0 :   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
     449             : 
     450           0 :   if (unformat (input, "eir %u", &c->rb.kbps.eir_kbps))
     451           0 :     return 1;
     452           0 :   return 0;
     453             : }
     454             : 
     455             : static uword
     456           0 : unformat_policer_cb (unformat_input_t * input, va_list * va)
     457             : {
     458           0 :   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
     459             : 
     460           0 :   if (unformat (input, "cb %u", &c->rb.kbps.cb_bytes))
     461           0 :     return 1;
     462           0 :   return 0;
     463             : }
     464             : 
     465             : static uword
     466           0 : unformat_policer_eb (unformat_input_t * input, va_list * va)
     467             : {
     468           0 :   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
     469             : 
     470           0 :   if (unformat (input, "eb %u", &c->rb.kbps.eb_bytes))
     471           0 :     return 1;
     472           0 :   return 0;
     473             : }
     474             : 
     475             : static uword
     476           0 : unformat_policer_action_type (unformat_input_t * input, va_list * va)
     477             : {
     478           0 :   qos_pol_action_params_st *a = va_arg (*va, qos_pol_action_params_st *);
     479             : 
     480           0 :   if (unformat (input, "drop"))
     481           0 :     a->action_type = QOS_ACTION_DROP;
     482           0 :   else if (unformat (input, "transmit"))
     483           0 :     a->action_type = QOS_ACTION_TRANSMIT;
     484           0 :   else if (unformat (input, "mark-and-transmit %U", unformat_ip_dscp,
     485             :                      &a->dscp))
     486           0 :     a->action_type = QOS_ACTION_MARK_AND_TRANSMIT;
     487             :   else
     488           0 :     return 0;
     489           0 :   return 1;
     490             : }
     491             : 
     492             : static uword
     493           0 : unformat_policer_action (unformat_input_t * input, va_list * va)
     494             : {
     495           0 :   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
     496             : 
     497           0 :   if (unformat (input, "conform-action %U", unformat_policer_action_type,
     498             :                 &c->conform_action))
     499           0 :     return 1;
     500           0 :   else if (unformat (input, "exceed-action %U", unformat_policer_action_type,
     501             :                      &c->exceed_action))
     502           0 :     return 1;
     503           0 :   else if (unformat (input, "violate-action %U", unformat_policer_action_type,
     504             :                      &c->violate_action))
     505           0 :     return 1;
     506           0 :   return 0;
     507             : }
     508             : 
     509             : static uword
     510           0 : unformat_policer_classify_next_index (unformat_input_t * input, va_list * va)
     511             : {
     512           0 :   u32 *r = va_arg (*va, u32 *);
     513           0 :   vnet_policer_main_t *pm = &vnet_policer_main;
     514             :   uword *p;
     515           0 :   u8 *match_name = 0;
     516             : 
     517           0 :   if (unformat (input, "%s", &match_name))
     518             :     ;
     519             :   else
     520           0 :     return 0;
     521             : 
     522           0 :   p = hash_get_mem (pm->policer_index_by_name, match_name);
     523           0 :   vec_free (match_name);
     524             : 
     525           0 :   if (p == 0)
     526           0 :     return 0;
     527             : 
     528           0 :   *r = p[0];
     529             : 
     530           0 :   return 1;
     531             : }
     532             : 
     533             : static uword
     534           0 : unformat_policer_classify_precolor (unformat_input_t * input, va_list * va)
     535             : {
     536           0 :   u32 *r = va_arg (*va, u32 *);
     537             : 
     538           0 :   if (unformat (input, "conform-color"))
     539           0 :     *r = POLICE_CONFORM;
     540           0 :   else if (unformat (input, "exceed-color"))
     541           0 :     *r = POLICE_EXCEED;
     542             :   else
     543           0 :     return 0;
     544             : 
     545           0 :   return 1;
     546             : }
     547             : 
     548             : #define foreach_config_param                    \
     549             : _(eb)                                           \
     550             : _(cb)                                           \
     551             : _(eir)                                          \
     552             : _(cir)                                          \
     553             : _(rate_type)                                    \
     554             : _(round_type)                                   \
     555             : _(type)                                         \
     556             : _(action)
     557             : 
     558             : static clib_error_t *
     559           0 : policer_add_command_fn (vlib_main_t *vm, unformat_input_t *input,
     560             :                         vlib_cli_command_t *cmd)
     561             : {
     562           0 :   vnet_policer_main_t *pm = &vnet_policer_main;
     563             :   qos_pol_cfg_params_st c;
     564           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     565           0 :   u8 *name = 0;
     566             :   uword *p;
     567             :   u32 pi;
     568           0 :   u32 policer_index = ~0;
     569           0 :   int rv = 0;
     570           0 :   clib_error_t *error = NULL;
     571           0 :   u8 is_update = cmd->function_arg;
     572             : 
     573             :   /* Get a line of input. */
     574           0 :   if (!unformat_user (input, unformat_line_input, line_input))
     575           0 :     return 0;
     576             : 
     577           0 :   clib_memset (&c, 0, sizeof (c));
     578             : 
     579           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     580             :     {
     581           0 :       if (unformat (line_input, "name %s", &name))
     582             :         ;
     583           0 :       else if (is_update && unformat (line_input, "index %u", &policer_index))
     584             :         ;
     585           0 :       else if (unformat (line_input, "color-aware"))
     586           0 :         c.color_aware = 1;
     587             : 
     588             : #define _(a) else if (unformat (line_input, "%U", unformat_policer_##a, &c)) ;
     589           0 :       foreach_config_param
     590             : #undef _
     591             :         else
     592             :         {
     593           0 :           error = clib_error_return (0, "unknown input `%U'",
     594             :                                      format_unformat_error, line_input);
     595           0 :           goto done;
     596             :         }
     597             :     }
     598             : 
     599           0 :   if (is_update)
     600             :     {
     601           0 :       if (~0 == policer_index && 0 != name)
     602             :         {
     603           0 :           p = hash_get_mem (pm->policer_index_by_name, name);
     604           0 :           if (p != NULL)
     605           0 :             policer_index = p[0];
     606             :         }
     607             : 
     608           0 :       if (~0 != policer_index)
     609             :         {
     610           0 :           rv = policer_update (vm, policer_index, &c);
     611             :         }
     612             :     }
     613             :   else
     614             :     {
     615           0 :       rv = policer_add (vm, name, &c, &pi);
     616             :     }
     617             : 
     618           0 :   switch (rv)
     619             :     {
     620           0 :     case VNET_API_ERROR_NO_SUCH_ENTRY:
     621           0 :       error = clib_error_return (0, "No such policer");
     622           0 :       break;
     623           0 :     case VNET_API_ERROR_VALUE_EXIST:
     624           0 :       error = clib_error_return (0, "Policer already exists");
     625           0 :       break;
     626           0 :     case VNET_API_ERROR_INVALID_VALUE:
     627           0 :       error = clib_error_return (0, "Config failed sanity check");
     628           0 :       break;
     629             :     }
     630             : 
     631           0 : done:
     632           0 :   unformat_free (line_input);
     633           0 :   vec_free (name);
     634             : 
     635           0 :   return error;
     636             : }
     637             : 
     638             : static clib_error_t *
     639           0 : policer_del_command_fn (vlib_main_t *vm, unformat_input_t *input,
     640             :                         vlib_cli_command_t *cmd)
     641             : {
     642           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     643           0 :   clib_error_t *error = NULL;
     644           0 :   vnet_policer_main_t *pm = &vnet_policer_main;
     645             :   int rv;
     646           0 :   u32 policer_index = ~0;
     647             :   uword *p;
     648           0 :   u8 *name = 0;
     649             : 
     650             :   /* Get a line of input. */
     651           0 :   if (!unformat_user (input, unformat_line_input, line_input))
     652           0 :     return 0;
     653             : 
     654           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     655             :     {
     656           0 :       if (unformat (line_input, "name %s", &name))
     657             :         ;
     658           0 :       else if (unformat (line_input, "index %u", &policer_index))
     659             :         ;
     660             :       else
     661             :         {
     662           0 :           error = clib_error_return (0, "unknown input `%U'",
     663             :                                      format_unformat_error, line_input);
     664           0 :           goto done;
     665             :         }
     666             :     }
     667             : 
     668           0 :   if (~0 == policer_index && 0 != name)
     669             :     {
     670           0 :       p = hash_get_mem (pm->policer_index_by_name, name);
     671           0 :       if (p != NULL)
     672           0 :         policer_index = p[0];
     673             :     }
     674             : 
     675           0 :   rv = VNET_API_ERROR_NO_SUCH_ENTRY;
     676           0 :   if (~0 != policer_index)
     677           0 :     rv = policer_del (vm, policer_index);
     678             : 
     679           0 :   switch (rv)
     680             :     {
     681           0 :     case VNET_API_ERROR_INVALID_VALUE:
     682           0 :       error = clib_error_return (0, "No such policer configuration");
     683           0 :       break;
     684           0 :     case VNET_API_ERROR_NO_SUCH_ENTRY:
     685           0 :       error = clib_error_return (0, "No such policer");
     686           0 :       break;
     687             :     }
     688             : 
     689           0 : done:
     690           0 :   unformat_free (line_input);
     691           0 :   vec_free (name);
     692             : 
     693           0 :   return error;
     694             : }
     695             : 
     696             : static clib_error_t *
     697           0 : policer_bind_command_fn (vlib_main_t *vm, unformat_input_t *input,
     698             :                          vlib_cli_command_t *cmd)
     699             : {
     700           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     701           0 :   clib_error_t *error = NULL;
     702           0 :   vnet_policer_main_t *pm = &vnet_policer_main;
     703           0 :   u8 bind = 1;
     704           0 :   u8 *name = 0;
     705           0 :   u32 worker = ~0;
     706           0 :   u32 policer_index = ~0;
     707             :   uword *p;
     708             :   int rv;
     709             : 
     710             :   /* Get a line of input. */
     711           0 :   if (!unformat_user (input, unformat_line_input, line_input))
     712           0 :     return 0;
     713             : 
     714           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     715             :     {
     716           0 :       if (unformat (line_input, "name %s", &name))
     717             :         ;
     718           0 :       else if (unformat (line_input, "index %u", &policer_index))
     719             :         ;
     720           0 :       else if (unformat (line_input, "unbind"))
     721           0 :         bind = 0;
     722           0 :       else if (unformat (line_input, "%d", &worker))
     723             :         ;
     724             :       else
     725             :         {
     726           0 :           error = clib_error_return (0, "unknown input `%U'",
     727             :                                      format_unformat_error, line_input);
     728           0 :           goto done;
     729             :         }
     730             :     }
     731             : 
     732           0 :   if (bind && ~0 == worker)
     733             :     {
     734           0 :       error = clib_error_return (0, "specify worker to bind to: `%U'",
     735             :                                  format_unformat_error, line_input);
     736             :     }
     737             :   else
     738             :     {
     739           0 :       if (~0 == policer_index && 0 != name)
     740             :         {
     741           0 :           p = hash_get_mem (pm->policer_index_by_name, name);
     742           0 :           if (p != NULL)
     743           0 :             policer_index = p[0];
     744             :         }
     745             : 
     746           0 :       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
     747           0 :       if (~0 != policer_index)
     748           0 :         rv = policer_bind_worker (policer_index, worker, bind);
     749             : 
     750           0 :       if (rv)
     751           0 :         error = clib_error_return (0, "failed: `%d'", rv);
     752             :     }
     753             : 
     754           0 : done:
     755           0 :   unformat_free (line_input);
     756           0 :   vec_free (name);
     757             : 
     758           0 :   return error;
     759             : }
     760             : 
     761             : static clib_error_t *
     762           0 : policer_input_command_fn (vlib_main_t *vm, unformat_input_t *input,
     763             :                           vlib_cli_command_t *cmd)
     764             : {
     765           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     766           0 :   clib_error_t *error = NULL;
     767           0 :   vnet_policer_main_t *pm = &vnet_policer_main;
     768           0 :   u8 apply = 1;
     769           0 :   u8 *name = 0;
     770           0 :   u32 sw_if_index = ~0;
     771           0 :   u32 policer_index = ~0;
     772             :   uword *p;
     773             :   int rv;
     774           0 :   vlib_dir_t dir = cmd->function_arg;
     775             : 
     776             :   /* Get a line of input. */
     777           0 :   if (!unformat_user (input, unformat_line_input, line_input))
     778           0 :     return 0;
     779             : 
     780           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     781             :     {
     782           0 :       if (unformat (line_input, "name %s", &name))
     783             :         ;
     784           0 :       else if (unformat (line_input, "index %u", &policer_index))
     785             :         ;
     786           0 :       else if (unformat (line_input, "unapply"))
     787           0 :         apply = 0;
     788           0 :       else if (unformat (line_input, "%U", unformat_vnet_sw_interface,
     789             :                          vnet_get_main (), &sw_if_index))
     790             :         ;
     791             :       else
     792             :         {
     793           0 :           error = clib_error_return (0, "unknown input `%U'",
     794             :                                      format_unformat_error, line_input);
     795           0 :           goto done;
     796             :         }
     797             :     }
     798             : 
     799           0 :   if (~0 == sw_if_index)
     800             :     {
     801           0 :       error = clib_error_return (0, "specify interface to apply to: `%U'",
     802             :                                  format_unformat_error, line_input);
     803             :     }
     804             :   else
     805             :     {
     806           0 :       if (~0 == policer_index && 0 != name)
     807             :         {
     808           0 :           p = hash_get_mem (pm->policer_index_by_name, name);
     809           0 :           if (p != NULL)
     810           0 :             policer_index = p[0];
     811             :         }
     812             : 
     813           0 :       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
     814           0 :       if (~0 != policer_index)
     815           0 :         rv = policer_input (policer_index, sw_if_index, dir, apply);
     816             : 
     817           0 :       if (rv)
     818           0 :         error = clib_error_return (0, "failed: `%d'", rv);
     819             :     }
     820             : 
     821           0 : done:
     822           0 :   unformat_free (line_input);
     823           0 :   vec_free (name);
     824             : 
     825           0 :   return error;
     826             : }
     827             : 
     828             : static clib_error_t *
     829           0 : policer_reset_command_fn (vlib_main_t *vm, unformat_input_t *input,
     830             :                           vlib_cli_command_t *cmd)
     831             : {
     832           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     833           0 :   clib_error_t *error = NULL;
     834           0 :   vnet_policer_main_t *pm = &vnet_policer_main;
     835             :   int rv;
     836           0 :   u32 policer_index = ~0;
     837             :   uword *p;
     838           0 :   u8 *name = 0;
     839             : 
     840             :   /* Get a line of input. */
     841           0 :   if (!unformat_user (input, unformat_line_input, line_input))
     842           0 :     return 0;
     843             : 
     844           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     845             :     {
     846           0 :       if (unformat (line_input, "name %s", &name))
     847             :         ;
     848           0 :       else if (unformat (line_input, "index %u", &policer_index))
     849             :         ;
     850             :       else
     851             :         {
     852           0 :           error = clib_error_return (0, "unknown input `%U'",
     853             :                                      format_unformat_error, line_input);
     854           0 :           goto done;
     855             :         }
     856             :     }
     857             : 
     858           0 :   if (~0 == policer_index && 0 != name)
     859             :     {
     860           0 :       p = hash_get_mem (pm->policer_index_by_name, name);
     861           0 :       if (p != NULL)
     862           0 :         policer_index = p[0];
     863             :     }
     864             : 
     865           0 :   rv = VNET_API_ERROR_NO_SUCH_ENTRY;
     866           0 :   if (~0 != policer_index)
     867           0 :     rv = policer_reset (vm, policer_index);
     868             : 
     869           0 :   switch (rv)
     870             :     {
     871           0 :     case VNET_API_ERROR_NO_SUCH_ENTRY:
     872           0 :       error = clib_error_return (0, "No such policer");
     873           0 :       break;
     874             :     }
     875             : 
     876           0 : done:
     877           0 :   unformat_free (line_input);
     878           0 :   vec_free (name);
     879             : 
     880           0 :   return error;
     881             : }
     882             : 
     883      285289 : VLIB_CLI_COMMAND (configure_policer_command, static) = {
     884             :   .path = "configure policer",
     885             :   .short_help = "configure policer [name <name> | index <index>] [type 1r2c | "
     886             :                 "1r3c | 2r3c-2698 "
     887             :                 "| 2r3c-4115] [color-aware] [cir <cir>] [cb <cb>] [eir <eir>] "
     888             :                 "[eb <eb>] [rate kbps | pps] [round closest | up | down] "
     889             :                 "[conform-action drop | transmit | mark-and-transmit <dscp>] "
     890             :                 "[exceed-action drop | transmit | mark-and-transmit <dscp>] "
     891             :                 "[violate-action drop | transmit | mark-and-transmit <dscp>]",
     892             :   .function = policer_add_command_fn,
     893             :   .function_arg = 1
     894             : };
     895             : 
     896      285289 : VLIB_CLI_COMMAND (policer_add_command, static) = {
     897             :   .path = "policer add",
     898             :   .short_help = "policer add name <name> [type 1r2c | 1r3c | 2r3c-2698 | "
     899             :                 "2r3c-4115] [color-aware] [cir <cir>] [cb <cb>] [eir <eir>] "
     900             :                 "[eb <eb>] [rate kbps | pps] [round closest | up | down] "
     901             :                 "[conform-action drop | transmit | mark-and-transmit <dscp>] "
     902             :                 "[exceed-action drop | transmit | mark-and-transmit <dscp>] "
     903             :                 "[violate-action drop | transmit | mark-and-transmit <dscp>]",
     904             :   .function = policer_add_command_fn,
     905             :   .function_arg = 0
     906             : };
     907             : 
     908      285289 : VLIB_CLI_COMMAND (policer_del_command, static) = {
     909             :   .path = "policer del",
     910             :   .short_help = "policer del [name <name> | index <index>]",
     911             :   .function = policer_del_command_fn,
     912             : };
     913             : 
     914      285289 : VLIB_CLI_COMMAND (policer_bind_command, static) = {
     915             :   .path = "policer bind",
     916             :   .short_help = "policer bind [unbind] [name <name> | index <index>] <worker>",
     917             :   .function = policer_bind_command_fn,
     918             : };
     919             : 
     920      285289 : VLIB_CLI_COMMAND (policer_input_command, static) = {
     921             :   .path = "policer input",
     922             :   .short_help =
     923             :     "policer input [unapply] [name <name> | index <index>] <interface>",
     924             :   .function = policer_input_command_fn,
     925             :   .function_arg = VLIB_RX,
     926             : };
     927             : 
     928      285289 : VLIB_CLI_COMMAND (policer_output_command, static) = {
     929             :   .path = "policer output",
     930             :   .short_help =
     931             :     "policer output [unapply] [name <name> | index <index>] <interface>",
     932             :   .function = policer_input_command_fn,
     933             :   .function_arg = VLIB_TX,
     934             : };
     935             : 
     936      285289 : VLIB_CLI_COMMAND (policer_reset_command, static) = {
     937             :   .path = "policer reset",
     938             :   .short_help = "policer reset [name <name> | index <index>]",
     939             :   .function = policer_reset_command_fn
     940             : };
     941             : 
     942             : static clib_error_t *
     943           0 : show_policer_command_fn (vlib_main_t * vm,
     944             :                          unformat_input_t * input, vlib_cli_command_t * cmd)
     945             : {
     946           0 :   vnet_policer_main_t *pm = &vnet_policer_main;
     947           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     948             :   policer_t *policer;
     949           0 :   u32 policer_index = ~0;
     950           0 :   u8 *name = 0;
     951             :   uword *ci, *pi;
     952             :   qos_pol_cfg_params_st *config;
     953           0 :   clib_error_t *error = 0;
     954             : 
     955             :   /* Get a line of input. */
     956           0 :   if (!unformat_user (input, unformat_line_input, line_input))
     957             :     {
     958           0 :       pool_foreach (policer, pm->policers)
     959             :         {
     960           0 :           ci = hash_get_mem (pm->policer_config_by_name, policer->name);
     961           0 :           config = pool_elt_at_index (pm->configs, ci[0]);
     962             : 
     963           0 :           vlib_cli_output (vm, "Name \"%s\" %U ", policer->name,
     964             :                            format_policer_config, config);
     965           0 :           vlib_cli_output (vm, "%U", format_policer_instance, policer);
     966           0 :           vlib_cli_output (vm, "-----------");
     967             :         }
     968           0 :       return 0;
     969             :     }
     970             : 
     971           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     972             :     {
     973           0 :       if (unformat (line_input, "name %s", &name))
     974             :         ;
     975           0 :       else if (unformat (line_input, "index %u", &policer_index))
     976             :         ;
     977             :       else
     978             :         {
     979           0 :           error = clib_error_return (0, "unknown input `%U'",
     980             :                                      format_unformat_error, line_input);
     981           0 :           goto done;
     982             :         }
     983             :     }
     984             : 
     985           0 :   if (~0 == policer_index && 0 != name)
     986             :     {
     987           0 :       pi = hash_get_mem (pm->policer_index_by_name, name);
     988           0 :       if (pi != NULL)
     989           0 :         policer_index = pi[0];
     990             :     }
     991             : 
     992           0 :   if (~0 == policer_index || pool_is_free_index (pm->policers, policer_index))
     993           0 :     goto done;
     994             : 
     995           0 :   policer = &pm->policers[policer_index];
     996           0 :   ci = hash_get_mem (pm->policer_config_by_name, policer->name);
     997           0 :   config = pool_elt_at_index (pm->configs, ci[0]);
     998           0 :   vlib_cli_output (vm, "Name \"%s\" %U ", policer->name, format_policer_config,
     999             :                    config);
    1000           0 :   vlib_cli_output (vm, "%U", format_policer_instance, policer);
    1001           0 :   vlib_cli_output (vm, "-----------");
    1002             : 
    1003           0 : done:
    1004           0 :   unformat_free (line_input);
    1005           0 :   vec_free (name);
    1006             : 
    1007           0 :   return error;
    1008             : }
    1009             : 
    1010             : 
    1011             : /* *INDENT-OFF* */
    1012      285289 : VLIB_CLI_COMMAND (show_policer_command, static) = {
    1013             :   .path = "show policer",
    1014             :   .short_help = "show policer [name <name> | index <index>]",
    1015             :   .function = show_policer_command_fn,
    1016             : };
    1017             : /* *INDENT-ON* */
    1018             : 
    1019             : static clib_error_t *
    1020           0 : show_policer_pools_command_fn (vlib_main_t * vm,
    1021             :                                unformat_input_t * input,
    1022             :                                vlib_cli_command_t * cmd)
    1023             : {
    1024           0 :   vnet_policer_main_t *pm = &vnet_policer_main;
    1025             : 
    1026           0 :   vlib_cli_output (vm, "pool sizes: configs=%d policers=%d",
    1027           0 :                    pool_elts (pm->configs), pool_elts (pm->policers));
    1028           0 :   return 0;
    1029             : }
    1030             : /* *INDENT-OFF* */
    1031      285289 : VLIB_CLI_COMMAND (show_policer_pools_command, static) = {
    1032             :     .path = "show policer pools",
    1033             :     .short_help = "show policer pools",
    1034             :     .function = show_policer_pools_command_fn,
    1035             : };
    1036             : /* *INDENT-ON* */
    1037             : 
    1038             : clib_error_t *
    1039         575 : policer_init (vlib_main_t * vm)
    1040             : {
    1041         575 :   vnet_policer_main_t *pm = &vnet_policer_main;
    1042             : 
    1043         575 :   pm->vlib_main = vm;
    1044         575 :   pm->vnet_main = vnet_get_main ();
    1045         575 :   pm->log_class = vlib_log_register_class ("policer", 0);
    1046         575 :   pm->fq_index[VLIB_RX] =
    1047         575 :     vlib_frame_queue_main_init (policer_input_node.index, 0);
    1048         575 :   pm->fq_index[VLIB_TX] =
    1049         575 :     vlib_frame_queue_main_init (policer_output_node.index, 0);
    1050             : 
    1051         575 :   pm->policer_config_by_name = hash_create_string (0, sizeof (uword));
    1052         575 :   pm->policer_index_by_name = hash_create_string (0, sizeof (uword));
    1053             : 
    1054         575 :   vnet_classify_register_unformat_policer_next_index_fn
    1055             :     (unformat_policer_classify_next_index);
    1056         575 :   vnet_classify_register_unformat_opaque_index_fn
    1057             :     (unformat_policer_classify_precolor);
    1058             : 
    1059         575 :   return 0;
    1060             : }
    1061             : 
    1062       12671 : VLIB_INIT_FUNCTION (policer_init);
    1063             : 
    1064             : 
    1065             : 
    1066             : /*
    1067             :  * fd.io coding-style-patch-verification: ON
    1068             :  *
    1069             :  * Local Variables:
    1070             :  * eval: (c-set-style "gnu")
    1071             :  * End:
    1072             :  */

Generated by: LCOV version 1.14