diff options
Diffstat (limited to 'src/vnet/policer/policer.c')
-rw-r--r-- | src/vnet/policer/policer.c | 528 |
1 files changed, 528 insertions, 0 deletions
diff --git a/src/vnet/policer/policer.c b/src/vnet/policer/policer.c new file mode 100644 index 00000000000..290a6af57e2 --- /dev/null +++ b/src/vnet/policer/policer.c @@ -0,0 +1,528 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <stdint.h> +#include <vnet/policer/policer.h> +#include <vnet/classify/vnet_classify.h> + +clib_error_t * +policer_add_del (vlib_main_t * vm, + u8 * name, + sse2_qos_pol_cfg_params_st * cfg, + u32 * policer_index, u8 is_add) +{ + vnet_policer_main_t *pm = &vnet_policer_main; + policer_read_response_type_st test_policer; + policer_read_response_type_st *policer; + uword *p; + u32 pi; + int rv; + + p = hash_get_mem (pm->policer_config_by_name, name); + + if (is_add == 0) + { + if (p == 0) + { + vec_free (name); + return clib_error_return (0, "No such policer configuration"); + } + hash_unset_mem (pm->policer_config_by_name, name); + hash_unset_mem (pm->policer_index_by_name, name); + vec_free (name); + return 0; + } + + if (p != 0) + { + vec_free (name); + return clib_error_return (0, "Policer already exists"); + } + + /* Vet the configuration before adding it to the table */ + rv = sse2_pol_logical_2_physical (cfg, &test_policer); + + if (rv == 0) + { + policer_read_response_type_st *pp; + sse2_qos_pol_cfg_params_st *cp; + + pool_get (pm->configs, cp); + pool_get (pm->policer_templates, pp); + + ASSERT (cp - pm->configs == pp - pm->policer_templates); + + clib_memcpy (cp, cfg, sizeof (*cp)); + clib_memcpy (pp, &test_policer, sizeof (*pp)); + + hash_set_mem (pm->policer_config_by_name, name, cp - pm->configs); + pool_get_aligned (pm->policers, policer, CLIB_CACHE_LINE_BYTES); + policer[0] = pp[0]; + pi = policer - pm->policers; + hash_set_mem (pm->policer_index_by_name, name, pi); + *policer_index = pi; + } + else + { + vec_free (name); + return clib_error_return (0, "Config failed sanity check"); + } + + return 0; +} + +u8 * +format_policer_instance (u8 * s, va_list * va) +{ + policer_read_response_type_st *i + = va_arg (*va, policer_read_response_type_st *); + + 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, "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", + i->current_limit, + i->current_bucket, i->extended_limit, i->extended_bucket); + s = format (s, "last update %llu\n", i->last_update_time); + return s; +} + +static u8 * +format_policer_round_type (u8 * s, va_list * va) +{ + sse2_qos_pol_cfg_params_st *c = va_arg (*va, sse2_qos_pol_cfg_params_st *); + + if (c->rnd_type == SSE2_QOS_ROUND_TO_CLOSEST) + s = format (s, "closest"); + else if (c->rnd_type == SSE2_QOS_ROUND_TO_UP) + s = format (s, "up"); + else if (c->rnd_type == SSE2_QOS_ROUND_TO_DOWN) + s = format (s, "down"); + else + s = format (s, "ILLEGAL"); + return s; +} + + +static u8 * +format_policer_rate_type (u8 * s, va_list * va) +{ + sse2_qos_pol_cfg_params_st *c = va_arg (*va, sse2_qos_pol_cfg_params_st *); + + if (c->rate_type == SSE2_QOS_RATE_KBPS) + s = format (s, "kbps"); + else if (c->rate_type == SSE2_QOS_RATE_PPS) + s = format (s, "pps"); + else + s = format (s, "ILLEGAL"); + return s; +} + +static u8 * +format_policer_type (u8 * s, va_list * va) +{ + sse2_qos_pol_cfg_params_st *c = va_arg (*va, sse2_qos_pol_cfg_params_st *); + + if (c->rfc == SSE2_QOS_POLICER_TYPE_1R2C) + s = format (s, "1r2c"); + + else if (c->rfc == SSE2_QOS_POLICER_TYPE_1R3C_RFC_2697) + s = format (s, "1r3c"); + + else if (c->rfc == SSE2_QOS_POLICER_TYPE_2R3C_RFC_2698) + s = format (s, "2r3c-2698"); + + else if (c->rfc == SSE2_QOS_POLICER_TYPE_2R3C_RFC_4115) + s = format (s, "2r3c-4115"); + + else if (c->rfc == SSE2_QOS_POLICER_TYPE_2R3C_RFC_MEF5CF1) + s = format (s, "2r3c-mef5cf1"); + else + s = format (s, "ILLEGAL"); + return s; +} + +static u8 * +format_dscp (u8 * s, va_list * va) +{ + u32 i = va_arg (*va, u32); + char *t = 0; + + switch (i) + { +#define _(v,f,str) case VNET_DSCP_##f: t = str; break; + foreach_vnet_dscp +#undef _ + default: + return format (s, "ILLEGAL"); + } + s = format (s, "%s", t); + return s; +} + +static u8 * +format_policer_action_type (u8 * s, va_list * va) +{ + sse2_qos_pol_action_params_st *a + = va_arg (*va, sse2_qos_pol_action_params_st *); + + if (a->action_type == SSE2_QOS_ACTION_DROP) + s = format (s, "drop"); + else if (a->action_type == SSE2_QOS_ACTION_TRANSMIT) + s = format (s, "transmit"); + else if (a->action_type == SSE2_QOS_ACTION_MARK_AND_TRANSMIT) + s = format (s, "mark-and-transmit %U", format_dscp, a->dscp); + else + s = format (s, "ILLEGAL"); + return s; +} + +u8 * +format_policer_config (u8 * s, va_list * va) +{ + sse2_qos_pol_cfg_params_st *c = va_arg (*va, sse2_qos_pol_cfg_params_st *); + + s = format (s, "type %U cir %u eir %u cb %u eb %u\n", + format_policer_type, c, + c->rb.kbps.cir_kbps, + c->rb.kbps.eir_kbps, c->rb.kbps.cb_bytes, c->rb.kbps.eb_bytes); + s = format (s, "rate type %U, round type %U\n", + format_policer_rate_type, c, format_policer_round_type, c); + s = format (s, "conform action %U, exceed action %U, violate action %U\n", + format_policer_action_type, &c->conform_action, + format_policer_action_type, &c->exceed_action, + format_policer_action_type, &c->violate_action); + return s; +} + +static uword +unformat_policer_type (unformat_input_t * input, va_list * va) +{ + sse2_qos_pol_cfg_params_st *c = va_arg (*va, sse2_qos_pol_cfg_params_st *); + + if (!unformat (input, "type")) + return 0; + + if (unformat (input, "1r2c")) + c->rfc = SSE2_QOS_POLICER_TYPE_1R2C; + else if (unformat (input, "1r3c")) + c->rfc = SSE2_QOS_POLICER_TYPE_1R3C_RFC_2697; + else if (unformat (input, "2r3c-2698")) + c->rfc = SSE2_QOS_POLICER_TYPE_2R3C_RFC_2698; + else if (unformat (input, "2r3c-4115")) + c->rfc = SSE2_QOS_POLICER_TYPE_2R3C_RFC_4115; + else if (unformat (input, "2r3c-mef5cf1")) + c->rfc = SSE2_QOS_POLICER_TYPE_2R3C_RFC_MEF5CF1; + else + return 0; + return 1; +} + +static uword +unformat_policer_round_type (unformat_input_t * input, va_list * va) +{ + sse2_qos_pol_cfg_params_st *c = va_arg (*va, sse2_qos_pol_cfg_params_st *); + + if (!unformat (input, "round")) + return 0; + + if (unformat (input, "closest")) + c->rnd_type = SSE2_QOS_ROUND_TO_CLOSEST; + else if (unformat (input, "up")) + c->rnd_type = SSE2_QOS_ROUND_TO_UP; + else if (unformat (input, "down")) + c->rnd_type = SSE2_QOS_ROUND_TO_DOWN; + else + return 0; + return 1; +} + +static uword +unformat_policer_rate_type (unformat_input_t * input, va_list * va) +{ + sse2_qos_pol_cfg_params_st *c = va_arg (*va, sse2_qos_pol_cfg_params_st *); + + if (!unformat (input, "rate")) + return 0; + + if (unformat (input, "kbps")) + c->rate_type = SSE2_QOS_RATE_KBPS; + else if (unformat (input, "pps")) + c->rate_type = SSE2_QOS_RATE_PPS; + else + return 0; + return 1; +} + +static uword +unformat_policer_cir (unformat_input_t * input, va_list * va) +{ + sse2_qos_pol_cfg_params_st *c = va_arg (*va, sse2_qos_pol_cfg_params_st *); + + if (unformat (input, "cir %u", &c->rb.kbps.cir_kbps)) + return 1; + return 0; +} + +static uword +unformat_policer_eir (unformat_input_t * input, va_list * va) +{ + sse2_qos_pol_cfg_params_st *c = va_arg (*va, sse2_qos_pol_cfg_params_st *); + + if (unformat (input, "eir %u", &c->rb.kbps.eir_kbps)) + return 1; + return 0; +} + +static uword +unformat_policer_cb (unformat_input_t * input, va_list * va) +{ + sse2_qos_pol_cfg_params_st *c = va_arg (*va, sse2_qos_pol_cfg_params_st *); + + if (unformat (input, "cb %u", &c->rb.kbps.cb_bytes)) + return 1; + return 0; +} + +static uword +unformat_policer_eb (unformat_input_t * input, va_list * va) +{ + sse2_qos_pol_cfg_params_st *c = va_arg (*va, sse2_qos_pol_cfg_params_st *); + + if (unformat (input, "eb %u", &c->rb.kbps.eb_bytes)) + return 1; + return 0; +} + +static uword +unformat_dscp (unformat_input_t * input, va_list * va) +{ + u8 *r = va_arg (*va, u8 *); + + if (0); +#define _(v,f,str) else if (unformat (input, str)) *r = VNET_DSCP_##f; + foreach_vnet_dscp +#undef _ + else + return 0; + return 1; +} + +static uword +unformat_policer_action_type (unformat_input_t * input, va_list * va) +{ + sse2_qos_pol_action_params_st *a + = va_arg (*va, sse2_qos_pol_action_params_st *); + + if (unformat (input, "drop")) + a->action_type = SSE2_QOS_ACTION_DROP; + else if (unformat (input, "transmit")) + a->action_type = SSE2_QOS_ACTION_TRANSMIT; + else if (unformat (input, "mark-and-transmit %U", unformat_dscp, &a->dscp)) + a->action_type = SSE2_QOS_ACTION_MARK_AND_TRANSMIT; + else + return 0; + return 1; +} + +static uword +unformat_policer_action (unformat_input_t * input, va_list * va) +{ + sse2_qos_pol_cfg_params_st *c = va_arg (*va, sse2_qos_pol_cfg_params_st *); + + if (unformat (input, "conform-action %U", unformat_policer_action_type, + &c->conform_action)) + return 1; + else if (unformat (input, "exceed-action %U", unformat_policer_action_type, + &c->exceed_action)) + return 1; + else if (unformat (input, "violate-action %U", unformat_policer_action_type, + &c->violate_action)) + return 1; + return 0; +} + +static uword +unformat_policer_classify_next_index (unformat_input_t * input, va_list * va) +{ + u32 *r = va_arg (*va, u32 *); + vnet_policer_main_t *pm = &vnet_policer_main; + uword *p; + u8 *match_name = 0; + + if (unformat (input, "%s", &match_name)) + ; + else + return 0; + + p = hash_get_mem (pm->policer_index_by_name, match_name); + + if (p == 0) + return 0; + + *r = p[0]; + + return 1; +} + +static uword +unformat_policer_classify_precolor (unformat_input_t * input, va_list * va) +{ + u32 *r = va_arg (*va, u32 *); + + if (unformat (input, "conform-color")) + *r = POLICE_CONFORM; + else if (unformat (input, "exceed-color")) + *r = POLICE_EXCEED; + else + return 0; + + return 1; +} + +#define foreach_config_param \ +_(eb) \ +_(cb) \ +_(eir) \ +_(cir) \ +_(rate_type) \ +_(round_type) \ +_(type) \ +_(action) + +static clib_error_t * +configure_policer_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + sse2_qos_pol_cfg_params_st c; + unformat_input_t _line_input, *line_input = &_line_input; + u8 is_add = 1; + u8 *name = 0; + u32 pi; + + /* Get a line of input. */ + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + memset (&c, 0, sizeof (c)); + + 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)) + ; + else if (unformat (line_input, "color-aware")) + c.color_aware = 1; + +#define _(a) else if (unformat (line_input, "%U", unformat_policer_##a, &c)) ; + foreach_config_param +#undef _ + else + return clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + } + + unformat_free (line_input); + + return policer_add_del (vm, name, &c, &pi, is_add); +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (configure_policer_command, static) = { + .path = "configure policer", + .short_help = "configure policer name <name> <params> ", + .function = configure_policer_command_fn, +}; +/* *INDENT-ON* */ + +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; + sse2_qos_pol_cfg_params_st *config; + policer_read_response_type_st *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)) + { + 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); + vlib_cli_output (vm, "Template %U", + format_policer_instance, templ); + vlib_cli_output (vm, "-----------"); + } + })); + /* *INDENT-ON* */ + return 0; +} + + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (show_policer_command, static) = { + .path = "show policer", + .short_help = "show policer [name]", + .function = show_policer_command_fn, +}; +/* *INDENT-ON* */ + +clib_error_t * +policer_init (vlib_main_t * vm) +{ + vnet_policer_main_t *pm = &vnet_policer_main; + void vnet_policer_node_funcs_reference (void); + + vnet_policer_node_funcs_reference (); + + pm->vlib_main = vm; + pm->vnet_main = vnet_get_main (); + + pm->policer_config_by_name = hash_create_string (0, sizeof (uword)); + pm->policer_index_by_name = hash_create_string (0, sizeof (uword)); + + vnet_classify_register_unformat_policer_next_index_fn + (unformat_policer_classify_next_index); + vnet_classify_register_unformat_opaque_index_fn + (unformat_policer_classify_precolor); + + return 0; +} + +VLIB_INIT_FUNCTION (policer_init); + + + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ |