From 86c7856edae44483e7303fb4cf4efdec626716c8 Mon Sep 17 00:00:00 2001 From: Alexander Chernavin Date: Thu, 12 May 2022 14:56:24 +0000 Subject: flowprobe: add api messages to obtain current state Type: improvement With this change: - add dump/details messages to obtain interfaces for which IPFIX flow record generation is enabled; - add get message to obtain parameters; - add a new message to set parameters with validation present and to correspond with get/set naming; - add tests for get/set parameters and dump/details interfaces. Change-Id: I09f6ec990171ac8bcb9d2f5c92629803b8ab6c28 Signed-off-by: Alexander Chernavin --- src/plugins/flowprobe/flowprobe.api | 83 ++++++++++++++++- src/plugins/flowprobe/flowprobe.c | 145 ++++++++++++++++++++++++++++- src/plugins/flowprobe/flowprobe_test.c | 161 +++++++++++++++++++++++++++++++++ 3 files changed, 383 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/plugins/flowprobe/flowprobe.api b/src/plugins/flowprobe/flowprobe.api index 8702568c7ea..c2090637cc8 100644 --- a/src/plugins/flowprobe/flowprobe.api +++ b/src/plugins/flowprobe/flowprobe.api @@ -5,7 +5,7 @@ used to control the flowprobe plugin */ -option version = "2.0.0"; +option version = "2.1.0"; import "vnet/interface_types.api"; @@ -83,8 +83,39 @@ autoreply define flowprobe_interface_add_del option vat_help = "( | sw_if_index ) [(ip4|ip6|l2)] [(rx|tx|both)] [disable]"; }; +/** \brief Dump interfaces for which IPFIX flow record generation is enabled + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param sw_if_index - interface index to use as filter (0xffffffff is "all") +*/ +define flowprobe_interface_dump +{ + option in_progress; + u32 client_index; + u32 context; + vl_api_interface_index_t sw_if_index [default=0xffffffff]; + option vat_help = "[]"; +}; + +/** \brief Details about IPFIX flow record generation enabled on interface + @param context - sender context which was passed in the request + @param which - datapath on which to record flows + @param direction - direction of recorded flows + @param sw_if_index - index of the interface +*/ +define flowprobe_interface_details +{ + option in_progress; + u32 context; + vl_api_flowprobe_which_t which; + vl_api_flowprobe_direction_t direction; + vl_api_interface_index_t sw_if_index; +}; + autoreply define flowprobe_params { + option replaced_by="flowprobe_set_params"; + u32 client_index; u32 context; vl_api_flowprobe_record_flags_t record_flags; @@ -92,3 +123,53 @@ autoreply define flowprobe_params u32 passive_timer; /* ~0 is off, 0 is default */ option vat_help = "record <[l2] [l3] [l4]> [active passive ]"; }; + +/** \brief Set IPFIX flow record generation parameters + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param record_flags - flags indicating what data to record + @param active_timer - time in seconds after which active flow records are + to be exported (0 is "off", 0xffffffff is "use default value") + @param passive_timer - time in seconds after which passive flow records are + to be deleted (0 is "off", 0xffffffff is "use default value") +*/ +autoreply define flowprobe_set_params +{ + option in_progress; + u32 client_index; + u32 context; + vl_api_flowprobe_record_flags_t record_flags; + u32 active_timer [default=0xffffffff]; + u32 passive_timer [default=0xffffffff]; + option vat_help = "record [l2] [l3] [l4] [active ] [passive ]"; +}; + +/** \brief Get IPFIX flow record generation parameters + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define flowprobe_get_params +{ + option in_progress; + u32 client_index; + u32 context; +}; + +/** \brief Reply to get IPFIX flow record generation parameters + @param context - sender context, to match reply w/ request + @param retval - error (0 is "no error") + @param record_flags - flags indicating what data to record + @param active_timer - time in seconds after which active flow records are + to be exported (0 is "off") + @param passive_timer - time in seconds after which passive flow records are + to be deleted (0 is "off") +*/ +define flowprobe_get_params_reply +{ + option in_progress; + u32 context; + i32 retval; + vl_api_flowprobe_record_flags_t record_flags; + u32 active_timer; + u32 passive_timer; +}; diff --git a/src/plugins/flowprobe/flowprobe.c b/src/plugins/flowprobe/flowprobe.c index 5a747a61c73..df0e5ff0f2b 100644 --- a/src/plugins/flowprobe/flowprobe.c +++ b/src/plugins/flowprobe/flowprobe.c @@ -772,6 +772,82 @@ out: REPLY_MACRO (VL_API_FLOWPROBE_INTERFACE_ADD_DEL_REPLY); } +static void +send_flowprobe_interface_details (u32 sw_if_index, u8 which, u8 direction, + vl_api_registration_t *reg, u32 context) +{ + flowprobe_main_t *fm = &flowprobe_main; + vl_api_flowprobe_interface_details_t *rmp = 0; + + rmp = vl_msg_api_alloc (sizeof (*rmp)); + if (!rmp) + return; + clib_memset (rmp, 0, sizeof (*rmp)); + rmp->_vl_msg_id = + ntohs (VL_API_FLOWPROBE_INTERFACE_DETAILS + REPLY_MSG_ID_BASE); + rmp->context = context; + + rmp->sw_if_index = htonl (sw_if_index); + + if (which == FLOW_VARIANT_IP4) + rmp->which = FLOWPROBE_WHICH_IP4; + else if (which == FLOW_VARIANT_IP6) + rmp->which = FLOWPROBE_WHICH_IP6; + else if (which == FLOW_VARIANT_L2) + rmp->which = FLOWPROBE_WHICH_L2; + else + ASSERT (0); + + if (direction == FLOW_DIRECTION_RX) + rmp->direction = FLOWPROBE_DIRECTION_RX; + else if (direction == FLOW_DIRECTION_TX) + rmp->direction = FLOWPROBE_DIRECTION_TX; + else if (direction == FLOW_DIRECTION_BOTH) + rmp->direction = FLOWPROBE_DIRECTION_BOTH; + else + ASSERT (0); + + vl_api_send_msg (reg, (u8 *) rmp); +} + +static void +vl_api_flowprobe_interface_dump_t_handler ( + vl_api_flowprobe_interface_dump_t *mp) +{ + flowprobe_main_t *fm = &flowprobe_main; + vl_api_registration_t *reg; + u32 sw_if_index; + + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return; + + sw_if_index = ntohl (mp->sw_if_index); + + if (sw_if_index == ~0) + { + u8 *which; + + vec_foreach (which, fm->flow_per_interface) + { + if (*which == (u8) ~0) + continue; + + sw_if_index = which - fm->flow_per_interface; + send_flowprobe_interface_details ( + sw_if_index, *which, fm->direction_per_interface[sw_if_index], reg, + mp->context); + } + } + else if (vec_len (fm->flow_per_interface) > sw_if_index && + fm->flow_per_interface[sw_if_index] != (u8) ~0) + { + send_flowprobe_interface_details ( + sw_if_index, fm->flow_per_interface[sw_if_index], + fm->direction_per_interface[sw_if_index], reg, mp->context); + } +} + #define vec_neg_search(v,E) \ ({ \ word _v(i) = 0; \ @@ -792,7 +868,7 @@ flowprobe_params (flowprobe_main_t * fm, u8 record_l2, flowprobe_record_t flags = 0; if (vec_neg_search (fm->flow_per_interface, (u8) ~ 0) != ~0) - return ~0; + return VNET_API_ERROR_UNSUPPORTED; if (record_l2) flags |= FLOW_RECORD_L2; @@ -832,6 +908,65 @@ vl_api_flowprobe_params_t_handler (vl_api_flowprobe_params_t * mp) REPLY_MACRO (VL_API_FLOWPROBE_PARAMS_REPLY); } +void +vl_api_flowprobe_set_params_t_handler (vl_api_flowprobe_set_params_t *mp) +{ + flowprobe_main_t *fm = &flowprobe_main; + vl_api_flowprobe_set_params_reply_t *rmp; + bool record_l2, record_l3, record_l4; + u32 active_timer; + u32 passive_timer; + int rv = 0; + + record_l2 = (mp->record_flags & FLOWPROBE_RECORD_FLAG_L2); + record_l3 = (mp->record_flags & FLOWPROBE_RECORD_FLAG_L3); + record_l4 = (mp->record_flags & FLOWPROBE_RECORD_FLAG_L4); + + active_timer = clib_net_to_host_u32 (mp->active_timer); + passive_timer = clib_net_to_host_u32 (mp->passive_timer); + + if (passive_timer > 0 && active_timer > passive_timer) + { + clib_warning ("Passive timer must be greater than active timer"); + rv = VNET_API_ERROR_INVALID_VALUE; + goto out; + } + + rv = flowprobe_params (fm, record_l2, record_l3, record_l4, active_timer, + passive_timer); + if (rv == VNET_API_ERROR_UNSUPPORTED) + clib_warning ( + "Cannot change params when feature is enabled on some interfaces"); + +out: + REPLY_MACRO (VL_API_FLOWPROBE_SET_PARAMS_REPLY); +} + +void +vl_api_flowprobe_get_params_t_handler (vl_api_flowprobe_get_params_t *mp) +{ + flowprobe_main_t *fm = &flowprobe_main; + vl_api_flowprobe_get_params_reply_t *rmp; + u8 record_flags = 0; + int rv = 0; + + if (fm->record & FLOW_RECORD_L2) + record_flags |= FLOWPROBE_RECORD_FLAG_L2; + if (fm->record & FLOW_RECORD_L3) + record_flags |= FLOWPROBE_RECORD_FLAG_L3; + if (fm->record & FLOW_RECORD_L4) + record_flags |= FLOWPROBE_RECORD_FLAG_L4; + + // clang-format off + REPLY_MACRO2 (VL_API_FLOWPROBE_GET_PARAMS_REPLY, + ({ + rmp->record_flags = record_flags; + rmp->active_timer = htonl (fm->active_timer); + rmp->passive_timer = htonl (fm->passive_timer); + })); + // clang-format on +} + /* *INDENT-OFF* */ VLIB_PLUGIN_REGISTER () = { .version = VPP_BUILD_VER, @@ -1138,10 +1273,10 @@ VLIB_CLI_COMMAND (flowprobe_enable_disable_command, static) = { .function = flowprobe_interface_add_del_feature_command_fn, }; VLIB_CLI_COMMAND (flowprobe_params_command, static) = { - .path = "flowprobe params", - .short_help = - "flowprobe params record <[l2] [l3] [l4]> [active passive ]", - .function = flowprobe_params_command_fn, + .path = "flowprobe params", + .short_help = "flowprobe params record [l2] [l3] [l4] [active ] " + "[passive ]", + .function = flowprobe_params_command_fn, }; VLIB_CLI_COMMAND (flowprobe_show_feature_command, static) = { diff --git a/src/plugins/flowprobe/flowprobe_test.c b/src/plugins/flowprobe/flowprobe_test.c index ae2a3edf64a..37b91207e29 100644 --- a/src/plugins/flowprobe/flowprobe_test.c +++ b/src/plugins/flowprobe/flowprobe_test.c @@ -149,6 +149,79 @@ api_flowprobe_interface_add_del (vat_main_t *vam) return ret; } +static int +api_flowprobe_interface_dump (vat_main_t *vam) +{ + unformat_input_t *i = vam->input; + vl_api_flowprobe_interface_dump_t *mp; + vl_api_control_ping_t *mp_ping; + u32 sw_if_index = ~0; + int ret; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%d", &sw_if_index)) + ; + else + break; + } + + /* Construct the API message */ + M (FLOWPROBE_INTERFACE_DUMP, mp); + mp->sw_if_index = htonl (sw_if_index); + + /* Send it... */ + S (mp); + + /* Use control ping for synchronization */ + PING (&flowprobe_test_main, mp_ping); + S (mp_ping); + + /* Wait for a reply... */ + W (ret); + return ret; +} + +static void +vl_api_flowprobe_interface_details_t_handler ( + vl_api_flowprobe_interface_details_t *mp) +{ + vat_main_t *vam = flowprobe_test_main.vat_main; + u32 sw_if_index; + u8 which; + u8 direction; + u8 *out = 0; + const char *variants[] = { + [FLOWPROBE_WHICH_IP4] = "ip4", + [FLOWPROBE_WHICH_IP6] = "ip6", + [FLOWPROBE_WHICH_L2] = "l2", + "Erroneous variant", + }; + const char *directions[] = { + [FLOWPROBE_DIRECTION_RX] = "rx", + [FLOWPROBE_DIRECTION_TX] = "tx", + [FLOWPROBE_DIRECTION_BOTH] = "rx tx", + "Erroneous direction", + }; + + sw_if_index = ntohl (mp->sw_if_index); + + which = mp->which; + if (which > ARRAY_LEN (variants) - 2) + which = ARRAY_LEN (variants) - 1; + + direction = mp->direction; + if (direction > ARRAY_LEN (directions) - 2) + direction = ARRAY_LEN (directions) - 1; + + out = format (0, "sw_if_index: %u, variant: %s, direction: %s\n%c", + sw_if_index, variants[which], directions[direction], 0); + + fformat (vam->ofp, (char *) out); + vec_free (out); +} + static int api_flowprobe_params (vat_main_t * vam) { @@ -202,6 +275,94 @@ api_flowprobe_params (vat_main_t * vam) return ret; } +static int +api_flowprobe_set_params (vat_main_t *vam) +{ + unformat_input_t *i = vam->input; + vl_api_flowprobe_set_params_t *mp; + u32 active_timer = ~0; + u32 passive_timer = ~0; + u8 record_flags = 0; + int ret; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "active %d", &active_timer)) + ; + else if (unformat (i, "passive %d", &passive_timer)) + ; + else if (unformat (i, "record")) + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "l2")) + record_flags |= FLOWPROBE_RECORD_FLAG_L2; + else if (unformat (i, "l3")) + record_flags |= FLOWPROBE_RECORD_FLAG_L3; + else if (unformat (i, "l4")) + record_flags |= FLOWPROBE_RECORD_FLAG_L4; + else + break; + } + else + break; + } + + /* Construct the API message */ + M (FLOWPROBE_SET_PARAMS, mp); + mp->record_flags = record_flags; + mp->active_timer = ntohl (active_timer); + mp->passive_timer = ntohl (passive_timer); + + /* send it... */ + S (mp); + + /* Wait for a reply... */ + W (ret); + + return ret; +} + +static int +api_flowprobe_get_params (vat_main_t *vam) +{ + vl_api_flowprobe_get_params_t *mp; + int ret; + + /* Construct the API message */ + M (FLOWPROBE_GET_PARAMS, mp); + + /* Send it... */ + S (mp); + + /* Wait for a reply... */ + W (ret); + return ret; +} + +static void +vl_api_flowprobe_get_params_reply_t_handler ( + vl_api_flowprobe_get_params_reply_t *mp) +{ + vat_main_t *vam = flowprobe_test_main.vat_main; + u8 *out = 0; + + out = + format (0, "active: %u, passive: %u, record:", ntohl (mp->active_timer), + ntohl (mp->passive_timer)); + + if (mp->record_flags & FLOWPROBE_RECORD_FLAG_L2) + out = format (out, " l2"); + if (mp->record_flags & FLOWPROBE_RECORD_FLAG_L3) + out = format (out, " l3"); + if (mp->record_flags & FLOWPROBE_RECORD_FLAG_L4) + out = format (out, " l4"); + + out = format (out, "\n%c", 0); + fformat (vam->ofp, (char *) out); + vec_free (out); + vam->result_ready = 1; +} + /* * List of messages that the api test plugin sends, * and that the data plane plugin processes -- cgit 1.2.3-korg