From 2d1a62bfddbba92a0aeec5c68e9b0a7903b178da Mon Sep 17 00:00:00 2001 From: Maxime Peim Date: Fri, 6 Jan 2023 11:57:38 +0000 Subject: [PATCH] policer: API policer selection by index 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 Change-Id: I4cc8fda0fc7c635a4110da3e757356b150f9b606 --- src/vnet/policer/police.h | 8 +- src/vnet/policer/policer.api | 90 ++++- src/vnet/policer/policer.c | 522 ++++++++++++++++++++--------- src/vnet/policer/policer.h | 17 +- src/vnet/policer/policer_api.c | 401 ++++++++++++++++------ src/vnet/policer/policer_types.api | 28 ++ src/vnet/policer/xlate.c | 2 +- src/vnet/policer/xlate.h | 2 +- test/test_policer_input.py | 79 +++++ test/vpp_policer.py | 59 ++-- 10 files changed, 923 insertions(+), 285 deletions(-) diff --git a/src/vnet/policer/police.h b/src/vnet/policer/police.h index 5ad249ef40e..8f126e22175 100644 --- a/src/vnet/policer/police.h +++ b/src/vnet/policer/police.h @@ -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); diff --git a/src/vnet/policer/policer.api b/src/vnet/policer/policer.api index f4bf9384f10..a5a60b35c6b 100644 --- a/src/vnet/policer/policer.api +++ b/src/vnet/policer/policer.api @@ -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 diff --git a/src/vnet/policer/policer.c b/src/vnet/policer/policer.c index 8389a5ead48..217a4c96389 100644 --- a/src/vnet/policer/policer.c +++ b/src/vnet/policer/policer.c @@ -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); - - /* 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); - - vec_free (name); - return 0; - } - - if (p != 0) - { - vec_free (name); - return clib_error_return (0, "Policer already exists"); - } + if (p != NULL) + return VNET_API_ERROR_VALUE_EXIST; /* Vet the configuration before adding it to the table */ rv = pol_logical_2_physical (cfg, &test_policer); - if (rv == 0) + if (rv != 0) + return VNET_API_ERROR_INVALID_VALUE; + + 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++) { - policer_t *pp; - qos_pol_cfg_params_st *cp; - int i; - - 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; - policer->thread_index = ~0; - - for (i = 0; i < NUM_POLICE_RESULTS; i++) - { - vlib_validate_combined_counter (&policer_counters[i], pi); - vlib_zero_combined_counter (&policer_counters[i], pi); - } - } - else - { - vec_free (name); - return clib_error_return (0, "Config failed sanity check"); + vlib_validate_combined_counter (&policer_counters[i], pi); + vlib_zero_combined_counter (&policer_counters[i], pi); } return 0; } int -policer_bind_worker (u8 *name, u32 worker, bool bind) +policer_del (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) + 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); + + /* free policer config */ + if (p != NULL) { - return VNET_API_ERROR_NO_SUCH_ENTRY; + pool_put_index (pm->configs, p[0]); + hash_unset_mem (pm->policer_config_by_name, policer->name); } - policer = &pm->policers[p[0]]; + /* 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; + + if (pool_is_free_index (pm->policers, policer_index)) + return VNET_API_ERROR_NO_SUCH_ENTRY; + + policer = &pm->policers[policer_index]; + + /* 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; + + p = hash_get_mem (pm->policer_config_by_name, policer->name); + + if (PREDICT_TRUE (p != NULL)) + { + cp = &pm->configs[p[0]]; + } + else + { + /* 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_reset (vlib_main_t *vm, u32 policer_index) +{ + 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[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[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 [type 1r2c | 1r3c | 2r3c-2698 " + .short_help = "configure policer [name | index ] [type 1r2c | " + "1r3c | 2r3c-2698 " "| 2r3c-4115] [color-aware] [cir ] [cb ] [eir ] " "[eb ] [rate kbps | pps] [round closest | up | down] " "[conform-action drop | transmit | mark-and-transmit ] " "[exceed-action drop | transmit | mark-and-transmit ] " "[violate-action drop | transmit | mark-and-transmit ]", .function = policer_add_command_fn, + .function_arg = 1 }; VLIB_CLI_COMMAND (policer_add_command, static) = { .path = "policer add", - .short_help = "policer name [type 1r2c | 1r3c | 2r3c-2698 | " + .short_help = "policer add name [type 1r2c | 1r3c | 2r3c-2698 | " "2r3c-4115] [color-aware] [cir ] [cb ] [eir ] " "[eb ] [rate kbps | pps] [round closest | up | down] " "[conform-action drop | transmit | mark-and-transmit ] " "[exceed-action drop | transmit | mark-and-transmit ] " "[violate-action drop | transmit | mark-and-transmit ]", .function = policer_add_command_fn, + .function_arg = 0 }; VLIB_CLI_COMMAND (policer_del_command, static) = { .path = "policer del", - .short_help = "policer del name ", + .short_help = "policer del [name | index ]", .function = policer_del_command_fn, }; VLIB_CLI_COMMAND (policer_bind_command, static) = { .path = "policer bind", - .short_help = "policer bind [unbind] name ", + .short_help = "policer bind [unbind] [name | index ] ", .function = policer_bind_command_fn, }; VLIB_CLI_COMMAND (policer_input_command, static) = { .path = "policer input", - .short_help = "policer input [unapply] name ", + .short_help = + "policer input [unapply] [name | index ] ", .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 ", + .short_help = + "policer output [unapply] [name | index ] ", .function = policer_input_command_fn, .function_arg = VLIB_TX, }; +VLIB_CLI_COMMAND (policer_reset_command, static) = { + .path = "policer reset", + .short_help = "policer reset [name | 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; + clib_error_t *error = 0; - (void) unformat (input, "name %s", &match_name); + /* 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]); - /* *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); + 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; + } - 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; + 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 ]", + .short_help = "show policer [name | 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* */ diff --git a/src/vnet/policer/policer.h b/src/vnet/policer/policer.h index f5b6c0d3b31..7ce7fc79d47 100644 --- a/src/vnet/policer/policer.h +++ b/src/vnet/policer/policer.h @@ -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__ */ diff --git a/src/vnet/policer/policer_api.c b/src/vnet/policer/policer_api.c index 4f9baa09feb..df35b472a89 100644 --- a/src/vnet/policer/policer_api.c +++ b/src/vnet/policer/policer_api.c @@ -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); + snprintf (name, sizeof (name), "%s", mp->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) + 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]); } - /* *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_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); + + 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); - name = format (0, "%s", mp->name); - vec_terminate_c_string (name); + 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); + + 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); + (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 *) name, ARRAY_LEN (mp->name) - 1); + 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) - { - 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); - } + 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 { - /* *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* */ + 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); + send_policer_details (config, policer, reg, mp->context); + }; + } + else + { + 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); } } diff --git a/src/vnet/policer/policer_types.api b/src/vnet/policer/policer_types.api index 3e21b7d707c..9d4c6447f69 100644 --- a/src/vnet/policer/policer_types.api +++ b/src/vnet/policer/policer_types.api @@ -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") diff --git a/src/vnet/policer/xlate.c b/src/vnet/policer/xlate.c index 9c4d76fd990..bffd208716d 100644 --- a/src/vnet/policer/xlate.c +++ b/src/vnet/policer/xlate.c @@ -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; diff --git a/src/vnet/policer/xlate.h b/src/vnet/policer/xlate.h index 722ac2fb777..7f6ebe7b65d 100644 --- a/src/vnet/policer/xlate.h +++ b/src/vnet/policer/xlate.h @@ -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__ */ diff --git a/test/test_policer_input.py b/test/test_policer_input.py index 9d44fc1a21c..6b4ab54a37e 100644 --- a/test/test_policer_input.py +++ b/test/test_policer_input.py @@ -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 diff --git a/test/vpp_policer.py b/test/vpp_policer.py index b0097b370e5..b48f4c6af1c 100644 --- a/test/vpp_policer.py +++ b/test/vpp_policer.py @@ -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")