From 5281a9029ea56f397a37ea1cf478ac526882770a Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Tue, 23 Jul 2019 08:16:19 -0700 Subject: qos: QoS dump APIs Type: feature Change-Id: I514b40026986f3828c8727453456b20a0a45f3af Signed-off-by: Neale Ranns --- src/vnet/qos/qos.api | 174 +++++++++++++++++++++++++++++++----------- src/vnet/qos/qos_api.c | 168 ++++++++++++++++++++++++++++++++++++---- src/vnet/qos/qos_egress_map.c | 150 +++++++++++++++++++++--------------- src/vnet/qos/qos_egress_map.h | 9 +++ src/vnet/qos/qos_mark.c | 102 +++++++++++++++++++++++++ src/vnet/qos/qos_mark.h | 6 ++ src/vnet/qos/qos_record.c | 102 ++++++++++++++++++++++++- src/vnet/qos/qos_record.h | 5 ++ 8 files changed, 597 insertions(+), 119 deletions(-) (limited to 'src/vnet/qos') diff --git a/src/vnet/qos/qos.api b/src/vnet/qos/qos.api index 1960ccb9548..11c91638c5b 100644 --- a/src/vnet/qos/qos.api +++ b/src/vnet/qos/qos.api @@ -22,7 +22,7 @@ option version = "1.0.0"; -enum qos_source +enum qos_source : u8 { QOS_API_SOURCE_EXT = 0, QOS_API_SOURCE_VLAN = 1, @@ -30,76 +30,164 @@ enum qos_source QOS_API_SOURCE_IP = 3, }; -/** \brief Enable/Disable QoS recording - The QoS bits from the packet at the specified input layer are copied - into the packet. Recording should be used in conjunction with marking - @param sw_if_index - The interface on which recording is enabled. - @param enable - enable=1 or disable the feature - @param input_source - The input source/layer at which the QoS bits - are copied from the packet. See qos_source_t. -*/ +/** + * QoS recording. + * @param sw_if_index - The interface on which recording is enabled. + * @param input_source - The input source/layer at which the QoS bits + are copied from the packet. See qos_source_t. + */ +typedef qos_record +{ + u32 sw_if_index; + vl_api_qos_source_t input_source; +}; + +/** + * Enable/Disable QoS recording + * The QoS bits from the packet at the specified input layer are copied + * into the packet. Recording should be used in conjunction with marking + * @param enable - enable=1 or disable the feature + * @param record - Recording configuration + */ autoreply define qos_record_enable_disable { u32 client_index; u32 context; - u32 sw_if_index; - vl_api_qos_source_t input_source; u8 enable; + vl_api_qos_record_t record; }; -/** \brief A row within a QoS map - Each value translates from an input value to an output. -*/ -typeonly define qos_egress_map_row +/** + * Dump the QoS record configs + */ +define qos_record_dump { - u8 outputs[256]; + u32 client_index; + u32 context; }; -/** \brief Update a QoS Map - A QoS map, translates from the QoS value in the packet set by the 'record' - feature, to the value used for output in the 'mark' feature. - There is one row in the map for each input/record source. - The MAP is then applied to the egress interface at for a given output source - @param map_id - client provided identifier for the map - @param rows - one row (per-input source) of output values -*/ +/** + * Details of QoS recording configs + */ +define qos_record_details +{ + u32 context; + vl_api_qos_record_t record; +}; + +/** + * @brief A row within a QoS map + * Each value translates from an input value to an output. + */ +typedef qos_egress_map_row +{ + u8 outputs[256]; +}; + +/** + * QoS Translation Map + * + * @param id - client provided identifier for the map + * @param rows - one row (per-input source) of output values + */ +typedef qos_egress_map +{ + u32 id; + vl_api_qos_egress_map_row_t rows[4]; +}; + +/** + * @brief Update a QoS Map + * A QoS map, translates from the QoS value in the packet set by the 'record' + * feature, to the value used for output in the 'mark' feature. + * There is one row in the map for each input/record source. + * The MAP is then applied to the egress interface at for a given output source + * @param map - The Map + */ autoreply define qos_egress_map_update { u32 client_index; u32 context; - u32 map_id; - vl_api_qos_egress_map_row_t rows[4]; + vl_api_qos_egress_map_t map; }; -/** \brief Delete a Qos Map - @param map_id - ID of the map to delete -*/ +/** + * @brief Delete a Qos Map + * @param map_id - ID of the map to delete + */ autoreply define qos_egress_map_delete { u32 client_index; u32 context; - u32 map_id; + u32 id; }; -/** \brief Enable/Disable QoS marking - The QoS bits from the packet are mapped (using the desired egress map) - into the header of the 'output-source'. Marking should be used in - conjunction with recording - @param sw_if_index - The interface on which recording is enabled. - @param enable - enable=1 or disable the feature - @param output_source - The output source/layer at which the QoS bits - are written into the packet. See qos_source_t. - @param map_id - The ID of the MAP in which the translation from input - to output is performed. -*/ -autoreply define qos_mark_enable_disable +/** + * Dump the QoS egress maps + */ +define qos_egress_map_dump { u32 client_index; u32 context; - u32 map_id; +}; + +/** + * QoS map details + */ +define qos_egress_map_details +{ + u32 context; + vl_api_qos_egress_map_t map; +}; + +/** + * QoS marking Cponfiguration + * The QoS bits from the buffer are mapped (using the desired egress map) + * into the header of the 'output-source'. Marking should be used in + * conjunction with recording + * @param sw_if_index - The interface on which recording is enabled. + * @param output_source - The output source/layer at which the QoS bits + * are written into the packet. See qos_source_t. + * @param map_id - The ID of the MAP in which the translation from input + * to output is performed. + */ +typedef qos_mark +{ u32 sw_if_index; + u32 map_id; vl_api_qos_source_t output_source; +}; + +/** + * @brief Enable/Disable QoS marking + * @param enable - enable=1 or disable the feature + * @param mark - Marking config + */ +autoreply define qos_mark_enable_disable +{ + u32 client_index; + u32 context; u8 enable; + vl_api_qos_mark_t mark; +}; + +/** + * Dump QoS marking configs + */ +define qos_mark_dump +{ + u32 client_index; + u32 context; + u32 sw_if_index; +}; + +/** + * QoS marking details + */ +autoreply define qos_mark_details +{ + u32 context; + vl_api_qos_mark_t mark; }; /* diff --git a/src/vnet/qos/qos_api.c b/src/vnet/qos/qos_api.c index 6297c24a843..966ffcce395 100644 --- a/src/vnet/qos/qos_api.c +++ b/src/vnet/qos/qos_api.c @@ -44,15 +44,16 @@ #define foreach_qos_api_msg \ _(QOS_RECORD_ENABLE_DISABLE, qos_record_enable_disable) \ + _(QOS_RECORD_DUMP, qos_record_dump) \ _(QOS_EGRESS_MAP_DELETE, qos_egress_map_delete) \ _(QOS_EGRESS_MAP_UPDATE, qos_egress_map_update) \ - _(QOS_MARK_ENABLE_DISABLE, qos_mark_enable_disable) + _(QOS_EGRESS_MAP_DUMP, qos_egress_map_dump) \ + _(QOS_MARK_ENABLE_DISABLE, qos_mark_enable_disable) \ + _(QOS_MARK_DUMP, qos_mark_dump) static int qos_source_decode (vl_api_qos_source_t v, qos_source_t * q) { - v = ntohl (v); - switch (v) { case QOS_API_SOURCE_EXT: @@ -72,6 +73,12 @@ qos_source_decode (vl_api_qos_source_t v, qos_source_t * q) return (VNET_API_ERROR_INVALID_VALUE); } +static vl_api_qos_source_t +qos_source_encode (qos_source_t q) +{ + return ((vl_api_qos_source_t) q); +} + void vl_api_qos_record_enable_disable_t_handler (vl_api_qos_record_enable_disable_t * mp) @@ -80,19 +87,63 @@ vl_api_qos_record_enable_disable_t_handler (vl_api_qos_record_enable_disable_t qos_source_t qs; int rv = 0; - rv = qos_source_decode (mp->input_source, &qs); + VALIDATE_SW_IF_INDEX (&(mp->record)); + + rv = qos_source_decode (mp->record.input_source, &qs); if (0 == rv) { if (mp->enable) - rv = qos_record_enable (ntohl (mp->sw_if_index), qs); + rv = qos_record_enable (ntohl (mp->record.sw_if_index), qs); else - rv = qos_record_disable (ntohl (mp->sw_if_index), qs); + rv = qos_record_disable (ntohl (mp->record.sw_if_index), qs); } + BAD_SW_IF_INDEX_LABEL; REPLY_MACRO (VL_API_QOS_RECORD_ENABLE_DISABLE_REPLY); } +typedef struct qos_record_send_walk_ctx_t_ +{ + vl_api_registration_t *reg; + u32 context; +} qos_record_send_walk_ctx_t; + +static walk_rc_t +send_qos_record_details (u32 sw_if_index, qos_source_t input_source, void *c) +{ + qos_record_send_walk_ctx_t *ctx; + vl_api_qos_record_details_t *mp; + + ctx = c; + mp = vl_msg_api_alloc_zero (sizeof (*mp)); + + mp->_vl_msg_id = ntohs (VL_API_QOS_RECORD_DETAILS); + mp->context = ctx->context; + mp->record.sw_if_index = htonl (sw_if_index); + mp->record.input_source = qos_source_encode (input_source); + + vl_api_send_msg (ctx->reg, (u8 *) mp); + + return (WALK_CONTINUE); +} + +static void +vl_api_qos_record_dump_t_handler (vl_api_qos_record_dump_t * mp) +{ + vl_api_registration_t *reg; + + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return; + + qos_record_send_walk_ctx_t ctx = { + .reg = reg, + .context = mp->context, + }; + qos_record_walk (send_qos_record_details, &ctx); +} + void vl_api_qos_egress_map_update_t_handler (vl_api_qos_egress_map_update_t * mp) { @@ -102,7 +153,8 @@ vl_api_qos_egress_map_update_t_handler (vl_api_qos_egress_map_update_t * mp) FOR_EACH_QOS_SOURCE (qs) { - qos_egress_map_update (ntohl (mp->map_id), qs, &mp->rows[qs].outputs[0]); + qos_egress_map_update (ntohl (mp->map.id), qs, + &mp->map.rows[qs].outputs[0]); } REPLY_MACRO (VL_API_QOS_EGRESS_MAP_UPDATE_REPLY); @@ -114,33 +166,121 @@ vl_api_qos_egress_map_delete_t_handler (vl_api_qos_egress_map_delete_t * mp) vl_api_qos_egress_map_delete_reply_t *rmp; int rv = 0; - qos_egress_map_delete (ntohl (mp->map_id)); + qos_egress_map_delete (ntohl (mp->id)); REPLY_MACRO (VL_API_QOS_EGRESS_MAP_DELETE_REPLY); } +typedef struct qos_egress_map_send_walk_ctx_t_ +{ + vl_api_registration_t *reg; + u32 context; +} qos_egress_map_send_walk_ctx_t; + +static walk_rc_t +send_qos_egress_map_details (qos_egress_map_id_t id, + const qos_egress_map_t * m, void *c) +{ + qos_egress_map_send_walk_ctx_t *ctx; + vl_api_qos_egress_map_details_t *mp; + u8 ii; + + ctx = c; + mp = vl_msg_api_alloc_zero (sizeof (*mp)); + + mp->_vl_msg_id = ntohs (VL_API_QOS_EGRESS_MAP_DETAILS); + mp->context = ctx->context; + mp->map.id = htonl (id); + + for (ii = 0; ii < 4; ii++) + clib_memcpy (mp->map.rows[ii].outputs, m->qem_output[ii], 256); + + vl_api_send_msg (ctx->reg, (u8 *) mp); + + return (WALK_CONTINUE); +} + +static void +vl_api_qos_egress_map_dump_t_handler (vl_api_qos_egress_map_dump_t * mp) +{ + vl_api_registration_t *reg; + + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return; + + qos_egress_map_send_walk_ctx_t ctx = { + .reg = reg, + .context = mp->context, + }; + qos_egress_map_walk (send_qos_egress_map_details, &ctx); +} + void - vl_api_qos_mark_enable_disable_t_handler - (vl_api_qos_mark_enable_disable_t * mp) +vl_api_qos_mark_enable_disable_t_handler (vl_api_qos_mark_enable_disable_t * + mp) { vl_api_qos_mark_enable_disable_reply_t *rmp; qos_source_t qs; int rv = 0; - rv = qos_source_decode (mp->output_source, &qs); + rv = qos_source_decode (mp->mark.output_source, &qs); if (0 == rv) { if (mp->enable) - rv = - qos_mark_enable (ntohl (mp->sw_if_index), qs, ntohl (mp->map_id)); + rv = qos_mark_enable (ntohl (mp->mark.sw_if_index), + qs, ntohl (mp->mark.map_id)); else - rv = qos_mark_disable (ntohl (mp->sw_if_index), qs); + rv = qos_mark_disable (ntohl (mp->mark.sw_if_index), qs); } REPLY_MACRO (VL_API_QOS_MARK_ENABLE_DISABLE_REPLY); } +typedef struct qos_mark_send_walk_ctx_t_ +{ + vl_api_registration_t *reg; + u32 context; +} qos_mark_send_walk_ctx_t; + +static walk_rc_t +send_qos_mark_details (u32 sw_if_index, + u32 map_id, qos_source_t output_source, void *c) +{ + qos_mark_send_walk_ctx_t *ctx; + vl_api_qos_mark_details_t *mp; + + ctx = c; + mp = vl_msg_api_alloc_zero (sizeof (*mp)); + + mp->_vl_msg_id = ntohs (VL_API_QOS_MARK_DETAILS); + mp->context = ctx->context; + mp->mark.sw_if_index = htonl (sw_if_index); + mp->mark.output_source = qos_source_encode (output_source); + mp->mark.map_id = htonl (map_id); + + vl_api_send_msg (ctx->reg, (u8 *) mp); + + return (WALK_CONTINUE); +} + +static void +vl_api_qos_mark_dump_t_handler (vl_api_qos_mark_dump_t * mp) +{ + vl_api_registration_t *reg; + + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return; + + qos_mark_send_walk_ctx_t ctx = { + .reg = reg, + .context = mp->context, + }; + qos_mark_walk (send_qos_mark_details, &ctx); +} + #define vl_msg_name_crc_list #include #undef vl_msg_name_crc_list diff --git a/src/vnet/qos/qos_egress_map.c b/src/vnet/qos/qos_egress_map.c index 158ff8445c6..7985579d3cf 100644 --- a/src/vnet/qos/qos_egress_map.c +++ b/src/vnet/qos/qos_egress_map.c @@ -41,6 +41,23 @@ qos_egress_map_find (qos_egress_map_id_t mid) return (INDEX_INVALID); } +qos_egress_map_id_t +qos_egress_map_get_id (index_t qemi) +{ + qos_egress_map_id_t qid; + index_t qmi; + + /* *INDENT-OFF* */ + hash_foreach(qid, qmi, qem_db, + ({ + if (qmi == qemi) + return (qid); + })); + /* *INDENT-OFF* */ + + return (~0); +} + qos_egress_map_t * qos_egress_map_find_i (qos_egress_map_id_t mid) { @@ -106,6 +123,20 @@ qos_egress_map_delete (qos_egress_map_id_t mid) } } +void +qos_egress_map_walk (qos_egress_map_walk_cb_t fn, void *c) +{ + qos_egress_map_id_t qid; + index_t qmi; + + /* *INDENT-OFF* */ + hash_foreach(qid, qmi, qem_db, + ({ + fn(qid, pool_elt_at_index(qem_pool, qmi), c); + })); + /* *INDENT-OFF* */ +} + static clib_error_t * qos_egress_map_update_cli (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) @@ -159,55 +190,54 @@ VLIB_CLI_COMMAND (qos_egress_map_update_command, static) = { }; /* *INDENT-ON* */ -u8 * -format_qos_egress_map (u8 * s, va_list * args) -{ - qos_egress_map_t *qem = va_arg (*args, qos_egress_map_t *); - u32 indent = va_arg (*args, u32); - int qs; - u32 ii; - - FOR_EACH_QOS_SOURCE (qs) + u8 *format_qos_egress_map (u8 * s, va_list * args) { - s = format (s, "%U%U:[", - format_white_space, indent, format_qos_source, qs); - - for (ii = 0; ii < ARRAY_LEN (qem->qem_output[qs]) - 1; ii++) - { - s = format (s, "%d,", qem->qem_output[qs][ii]); - } - s = format (s, "%d]\n", qem->qem_output[qs][ii]); - } + qos_egress_map_t *qem = va_arg (*args, qos_egress_map_t *); + u32 indent = va_arg (*args, u32); + int qs; + u32 ii; - return (s); -} - -static clib_error_t * -qos_egress_map_show (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - qos_egress_map_id_t map_id; - qos_egress_map_t *qem; - clib_error_t *error; - - map_id = ~0; - qem = NULL; - error = NULL; - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + FOR_EACH_QOS_SOURCE (qs) { - if (unformat (input, "id %d", &map_id)) - ; - else + s = format (s, "%U%U:[", + format_white_space, indent, format_qos_source, qs); + + for (ii = 0; ii < ARRAY_LEN (qem->qem_output[qs]) - 1; ii++) { - error = unformat_parse_error (input); - goto done; + s = format (s, "%d,", qem->qem_output[qs][ii]); } + s = format (s, "%d]\n", qem->qem_output[qs][ii]); } - if (~0 == map_id) - { - index_t qemi; + return (s); + } + + static clib_error_t *qos_egress_map_show (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) + { + qos_egress_map_id_t map_id; + qos_egress_map_t *qem; + clib_error_t *error; + + map_id = ~0; + qem = NULL; + error = NULL; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "id %d", &map_id)) + ; + else + { + error = unformat_parse_error (input); + goto done; + } + } + + if (~0 == map_id) + { + index_t qemi; /* *INDENT-OFF* */ hash_foreach(map_id, qemi, qem_db, @@ -218,25 +248,25 @@ qos_egress_map_show (vlib_main_t * vm, pool_elt_at_index(qem_pool, qemi), 2); })); /* *INDENT-ON* */ - } - else - { - qem = qos_egress_map_find_i (map_id); - - if (NULL == qem) - { - error = clib_error_return (0, "No Map for ID %d", map_id); - } - else - { - vlib_cli_output (vm, " Map-ID:%d\n%U", - map_id, format_qos_egress_map, qem, 2); - } - } + } + else + { + qem = qos_egress_map_find_i (map_id); + + if (NULL == qem) + { + error = clib_error_return (0, "No Map for ID %d", map_id); + } + else + { + vlib_cli_output (vm, " Map-ID:%d\n%U", + map_id, format_qos_egress_map, qem, 2); + } + } -done: - return (error); -} + done: + return (error); + } /*? * Show Egress Qos Maps diff --git a/src/vnet/qos/qos_egress_map.h b/src/vnet/qos/qos_egress_map.h index 3b6e0b45a43..0dab7adc2dd 100644 --- a/src/vnet/qos/qos_egress_map.h +++ b/src/vnet/qos/qos_egress_map.h @@ -66,6 +66,15 @@ extern void qos_egress_map_delete (qos_egress_map_id_t tid); * Get the VPP QoS map index from the user's map-ID */ extern index_t qos_egress_map_find (qos_egress_map_id_t tid); +extern qos_egress_map_id_t qos_egress_map_get_id (index_t qemi); + +/** + * Walk each of the configured maps + */ +typedef walk_rc_t (*qos_egress_map_walk_cb_t) (qos_egress_map_id_t id, + const qos_egress_map_t * m, + void *c); +void qos_egress_map_walk (qos_egress_map_walk_cb_t fn, void *c); /** * Data-plane functions diff --git a/src/vnet/qos/qos_mark.c b/src/vnet/qos/qos_mark.c index dcb0f9d1ab3..44bb34bd010 100644 --- a/src/vnet/qos/qos_mark.c +++ b/src/vnet/qos/qos_mark.c @@ -117,6 +117,24 @@ qos_mark_disable (u32 sw_if_index, qos_source_t output_source) return (0); } +void +qos_mark_walk (qos_mark_walk_cb_t fn, void *c) +{ + qos_source_t qs; + + FOR_EACH_QOS_SOURCE (qs) + { + u32 sw_if_index; + + vec_foreach_index (sw_if_index, qos_mark_configs[qs]) + { + if (INDEX_INVALID != qos_mark_configs[qs][sw_if_index]) + fn (sw_if_index, + qos_egress_map_get_id (qos_mark_configs[qs][sw_if_index]), qs, c); + } + } +} + static clib_error_t * qos_mark_cli (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) @@ -178,6 +196,90 @@ VLIB_CLI_COMMAND (qos_egress_map_interface_command, static) = { }; /* *INDENT-ON* */ +static void +qos_mark_show_one_interface (vlib_main_t * vm, u32 sw_if_index) +{ + index_t qemis[QOS_N_SOURCES]; + qos_source_t qs; + bool set; + + set = false; + clib_memset_u32 (qemis, INDEX_INVALID, QOS_N_SOURCES); + + FOR_EACH_QOS_SOURCE (qs) + { + if (vec_len (qos_mark_configs[qs]) <= sw_if_index) + continue; + if (INDEX_INVALID != (qemis[qs] = qos_mark_configs[qs][sw_if_index])) + set = true; + } + + if (set) + { + vlib_cli_output (vm, " %U:", format_vnet_sw_if_index_name, + vnet_get_main (), sw_if_index); + + FOR_EACH_QOS_SOURCE (qs) + { + if (qemis[qs] != INDEX_INVALID) + vlib_cli_output (vm, " %U: map:%d", format_qos_source, qs, + qemis[qs]); + } + } +} + +static clib_error_t * +qos_mark_show (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + qos_source_t qs; + u32 sw_if_index; + + sw_if_index = ~0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "%U", unformat_vnet_sw_interface, + vnm, &sw_if_index)) + ; + } + + if (~0 == sw_if_index) + { + u32 ii, n_ints = 0; + + FOR_EACH_QOS_SOURCE (qs) + { + n_ints = clib_max (n_ints, vec_len (qos_mark_configs[qs])); + } + + for (ii = 0; ii < n_ints; ii++) + { + qos_mark_show_one_interface (vm, ii); + } + } + else + qos_mark_show_one_interface (vm, sw_if_index); + + return (NULL); +} + +/*? + * Show Egress Qos Maps + * + * @cliexpar + * @cliexcmd{show qos egress map} + ?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (qos_mark_show_command, static) = { + .path = "show qos mark", + .short_help = "show qos mark [interface]", + .function = qos_mark_show, + .is_mp_safe = 1, +}; +/* *INDENT-ON* */ + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vnet/qos/qos_mark.h b/src/vnet/qos/qos_mark.h index f1705d1bb33..91e2024af94 100644 --- a/src/vnet/qos/qos_mark.h +++ b/src/vnet/qos/qos_mark.h @@ -28,6 +28,12 @@ extern int qos_mark_enable (u32 sw_if_index, qos_egress_map_id_t tid); extern int qos_mark_disable (u32 sw_if_index, qos_source_t output_source); +typedef walk_rc_t (*qos_mark_walk_cb_t) (u32 sw_if_index, + u32 map_id, + qos_source_t input_source, + void *ctx); +void qos_mark_walk (qos_mark_walk_cb_t fn, void *c); + #endif /* diff --git a/src/vnet/qos/qos_record.c b/src/vnet/qos/qos_record.c index 20d0b5bf4f5..40e6b0778bb 100644 --- a/src/vnet/qos/qos_record.c +++ b/src/vnet/qos/qos_record.c @@ -100,6 +100,23 @@ qos_record_disable (u32 sw_if_index, qos_source_t input_source) return (0); } +void +qos_record_walk (qos_record_walk_cb_t fn, void *c) +{ + qos_source_t qs; + + FOR_EACH_QOS_SOURCE (qs) + { + u32 sw_if_index; + + vec_foreach_index (sw_if_index, qos_record_configs[qs]) + { + if (0 != qos_record_configs[qs][sw_if_index]) + fn (sw_if_index, qs, c); + } + } +} + /* * Disable recording feature for all protocols when the interface * is deleted @@ -124,7 +141,7 @@ qos_record_ip_interface_add_del (vnet_main_t * vnm, VNET_SW_INTERFACE_ADD_DEL_FUNCTION (qos_record_ip_interface_add_del); clib_error_t * -l2_ip_qos_init (vlib_main_t * vm) +qos_record_init (vlib_main_t * vm) { qos_source_t qs; vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "l2-ip-qos-record"); @@ -139,7 +156,7 @@ l2_ip_qos_init (vlib_main_t * vm) return 0; } -VLIB_INIT_FUNCTION (l2_ip_qos_init); +VLIB_INIT_FUNCTION (qos_record_init); static clib_error_t * qos_record_cli (vlib_main_t * vm, @@ -199,6 +216,87 @@ VLIB_CLI_COMMAND (qos_record_command, static) = { }; /* *INDENT-ON* */ +static void +qos_record_show_one_interface (vlib_main_t * vm, u32 sw_if_index) +{ + u8 n_cfgs[QOS_N_SOURCES] = { }; + qos_source_t qs; + bool set; + + set = false; + + FOR_EACH_QOS_SOURCE (qs) + { + if (vec_len (qos_record_configs[qs]) <= sw_if_index) + continue; + if (0 != (n_cfgs[qs] = qos_record_configs[qs][sw_if_index])) + set = true; + } + + if (set) + { + vlib_cli_output (vm, " %U:", format_vnet_sw_if_index_name, + vnet_get_main (), sw_if_index); + + FOR_EACH_QOS_SOURCE (qs) + { + if (n_cfgs[qs] != 0) + vlib_cli_output (vm, " %U", format_qos_source, qs); + } + } +} + +static clib_error_t * +qos_record_show (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + qos_source_t qs; + u32 sw_if_index; + + sw_if_index = ~0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "%U", unformat_vnet_sw_interface, + vnm, &sw_if_index)) + ; + } + + if (~0 == sw_if_index) + { + u32 ii, n_ints = 0; + + FOR_EACH_QOS_SOURCE (qs) + { + n_ints = clib_max (n_ints, vec_len (qos_record_configs[qs])); + } + + for (ii = 0; ii < n_ints; ii++) + { + qos_record_show_one_interface (vm, ii); + } + } + else + qos_record_show_one_interface (vm, sw_if_index); + + return (NULL); +} + +/*? + * Show Egress Qos Maps + * + * @cliexpar + * @cliexcmd{show qos egress map} + ?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (qos_record_show_command, static) = { + .path = "show qos record", + .short_help = "show qos record [interface]", + .function = qos_record_show, + .is_mp_safe = 1, +}; +/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/vnet/qos/qos_record.h b/src/vnet/qos/qos_record.h index e5726d650a7..b80041f3241 100644 --- a/src/vnet/qos/qos_record.h +++ b/src/vnet/qos/qos_record.h @@ -21,6 +21,11 @@ extern int qos_record_disable (u32 sw_if_index, qos_source_t input_source); extern int qos_record_enable (u32 sw_if_index, qos_source_t input_source); +typedef walk_rc_t (*qos_record_walk_cb_t) (u32 sw_if_index, + qos_source_t input_source, + void *ctx); +void qos_record_walk (qos_record_walk_cb_t fn, void *c); + #endif /* -- cgit 1.2.3-korg