/* * 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: */