summaryrefslogtreecommitdiffstats
path: root/src/plugins/flowprobe/flowprobe.c
diff options
context:
space:
mode:
authorAlexander Chernavin <achernavin@netgate.com>2022-05-06 11:35:59 +0000
committerOle Tr�an <otroan@employees.org>2022-05-13 07:34:41 +0000
commit6f5ddf3461906bbc88f679882744afc74a81cae1 (patch)
tree27a3f0686ddf0fb7efdfd3ac1aa2cefb5fa86153 /src/plugins/flowprobe/flowprobe.c
parent0891b6aa449cca525b61d0cc23759b2efcd158dc (diff)
flowprobe: add support for reporting on inbound packets
Type: feature Currently, the plugin supports only IPFIX flow record generation for outbound packets. With this change: - add a new API message for enabling the feature on an interface that accepts direction (rx, tx, both); - update existing debug command for feature enabling to accept direction; - update existing debug command for showing currently enabled feature on interfaces to display direction; - update templates to include a direction field; - generate flow records on the specified direction and data path; - report direction in flow data; - update tests to use the new API; - add tests for inbound flows. Change-Id: I121fd904b38408641036ebeea848df7a4e5e0b30 Signed-off-by: Alexander Chernavin <achernavin@netgate.com>
Diffstat (limited to 'src/plugins/flowprobe/flowprobe.c')
-rw-r--r--src/plugins/flowprobe/flowprobe.c236
1 files changed, 203 insertions, 33 deletions
diff --git a/src/plugins/flowprobe/flowprobe.c b/src/plugins/flowprobe/flowprobe.c
index 27cb40093ec..5a747a61c73 100644
--- a/src/plugins/flowprobe/flowprobe.c
+++ b/src/plugins/flowprobe/flowprobe.c
@@ -46,23 +46,46 @@ uword flowprobe_walker_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
/* Define the per-interface configurable features */
/* *INDENT-OFF* */
-VNET_FEATURE_INIT (flow_perpacket_ip4, static) =
-{
+VNET_FEATURE_INIT (flowprobe_input_ip4_unicast, static) = {
+ .arc_name = "ip4-unicast",
+ .node_name = "flowprobe-input-ip4",
+ .runs_before = VNET_FEATURES ("ip4-lookup"),
+};
+VNET_FEATURE_INIT (flowprobe_input_ip4_multicast, static) = {
+ .arc_name = "ip4-multicast",
+ .node_name = "flowprobe-input-ip4",
+ .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
+};
+VNET_FEATURE_INIT (flowprobe_input_ip6_unicast, static) = {
+ .arc_name = "ip6-unicast",
+ .node_name = "flowprobe-input-ip6",
+ .runs_before = VNET_FEATURES ("ip6-lookup"),
+};
+VNET_FEATURE_INIT (flowprobe_input_ip6_multicast, static) = {
+ .arc_name = "ip6-multicast",
+ .node_name = "flowprobe-input-ip6",
+ .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
+};
+VNET_FEATURE_INIT (flowprobe_input_l2, static) = {
+ .arc_name = "device-input",
+ .node_name = "flowprobe-input-l2",
+ .runs_before = VNET_FEATURES ("ethernet-input"),
+};
+VNET_FEATURE_INIT (flowprobe_output_ip4, static) = {
.arc_name = "ip4-output",
- .node_name = "flowprobe-ip4",
+ .node_name = "flowprobe-output-ip4",
.runs_before = VNET_FEATURES ("interface-output"),
};
-VNET_FEATURE_INIT (flow_perpacket_ip6, static) =
-{
+VNET_FEATURE_INIT (flowprobe_output_ip6, static) = {
.arc_name = "ip6-output",
- .node_name = "flowprobe-ip6",
+ .node_name = "flowprobe-output-ip6",
.runs_before = VNET_FEATURES ("interface-output"),
};
-VNET_FEATURE_INIT (flow_perpacket_l2, static) = {
+VNET_FEATURE_INIT (flowprobe_output_l2, static) = {
.arc_name = "interface-output",
- .node_name = "flowprobe-l2",
+ .node_name = "flowprobe-output-l2",
.runs_before = VNET_FEATURES ("interface-output-arc-end"),
};
/* *INDENT-ON* */
@@ -143,7 +166,7 @@ flowprobe_template_l2_fields (ipfix_field_specifier_t * f)
static inline ipfix_field_specifier_t *
flowprobe_template_common_fields (ipfix_field_specifier_t * f)
{
-#define flowprobe_template_common_field_count() 5
+#define flowprobe_template_common_field_count() 6
/* ingressInterface, TLV type 10, u32 */
f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
ingressInterface, 4);
@@ -154,6 +177,10 @@ flowprobe_template_common_fields (ipfix_field_specifier_t * f)
egressInterface, 4);
f++;
+ /* flowDirection, TLV type 61, u8 */
+ f->e_id_length = ipfix_e_id_length (0 /* enterprise */, flowDirection, 1);
+ f++;
+
/* packetDeltaCount, TLV type 2, u64 */
f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
packetDeltaCount, 8);
@@ -483,6 +510,7 @@ validate_feature_on_interface (flowprobe_main_t * fm, u32 sw_if_index,
u8 which)
{
vec_validate_init_empty (fm->flow_per_interface, sw_if_index, ~0);
+ vec_validate_init_empty (fm->direction_per_interface, sw_if_index, ~0);
if (fm->flow_per_interface[sw_if_index] == (u8) ~ 0)
return -1;
@@ -496,13 +524,15 @@ validate_feature_on_interface (flowprobe_main_t * fm, u32 sw_if_index,
* @brief configure / deconfigure the IPFIX flow-per-packet
* @param fm flowprobe_main_t * fm
* @param sw_if_index u32 the desired interface
+ * @param which u8 the desired datapath
+ * @param direction u8 the desired direction
* @param is_add int 1 to enable the feature, 0 to disable it
* @returns 0 if successful, non-zero otherwise
*/
static int
-flowprobe_tx_interface_add_del_feature (flowprobe_main_t * fm,
- u32 sw_if_index, u8 which, int is_add)
+flowprobe_interface_add_del_feature (flowprobe_main_t *fm, u32 sw_if_index,
+ u8 which, u8 direction, int is_add)
{
vlib_main_t *vm = vlib_get_main ();
int rv = 0;
@@ -510,6 +540,7 @@ flowprobe_tx_interface_add_del_feature (flowprobe_main_t * fm,
flowprobe_record_t flags = fm->record;
fm->flow_per_interface[sw_if_index] = (is_add) ? which : (u8) ~ 0;
+ fm->direction_per_interface[sw_if_index] = (is_add) ? direction : (u8) ~0;
fm->template_per_flow[which] += (is_add) ? 1 : -1;
if (is_add && fm->template_per_flow[which] > 1)
template_id = fm->template_reports[flags];
@@ -574,15 +605,39 @@ flowprobe_tx_interface_add_del_feature (flowprobe_main_t * fm,
fm->template_reports[flags] = (is_add) ? template_id : 0;
}
- if (which == FLOW_VARIANT_IP4)
- vnet_feature_enable_disable ("ip4-output", "flowprobe-ip4",
- sw_if_index, is_add, 0, 0);
- else if (which == FLOW_VARIANT_IP6)
- vnet_feature_enable_disable ("ip6-output", "flowprobe-ip6",
- sw_if_index, is_add, 0, 0);
- else if (which == FLOW_VARIANT_L2)
- vnet_feature_enable_disable ("interface-output", "flowprobe-l2",
- sw_if_index, is_add, 0, 0);
+ if (direction == FLOW_DIRECTION_RX || direction == FLOW_DIRECTION_BOTH)
+ {
+ if (which == FLOW_VARIANT_IP4)
+ {
+ vnet_feature_enable_disable ("ip4-unicast", "flowprobe-input-ip4",
+ sw_if_index, is_add, 0, 0);
+ vnet_feature_enable_disable ("ip4-multicast", "flowprobe-input-ip4",
+ sw_if_index, is_add, 0, 0);
+ }
+ else if (which == FLOW_VARIANT_IP6)
+ {
+ vnet_feature_enable_disable ("ip6-unicast", "flowprobe-input-ip6",
+ sw_if_index, is_add, 0, 0);
+ vnet_feature_enable_disable ("ip6-multicast", "flowprobe-input-ip6",
+ sw_if_index, is_add, 0, 0);
+ }
+ else if (which == FLOW_VARIANT_L2)
+ vnet_feature_enable_disable ("device-input", "flowprobe-input-l2",
+ sw_if_index, is_add, 0, 0);
+ }
+
+ if (direction == FLOW_DIRECTION_TX || direction == FLOW_DIRECTION_BOTH)
+ {
+ if (which == FLOW_VARIANT_IP4)
+ vnet_feature_enable_disable ("ip4-output", "flowprobe-output-ip4",
+ sw_if_index, is_add, 0, 0);
+ else if (which == FLOW_VARIANT_IP6)
+ vnet_feature_enable_disable ("ip6-output", "flowprobe-output-ip6",
+ sw_if_index, is_add, 0, 0);
+ else if (which == FLOW_VARIANT_L2)
+ vnet_feature_enable_disable ("interface-output", "flowprobe-output-l2",
+ sw_if_index, is_add, 0, 0);
+ }
/* Stateful flow collection */
if (is_add && !fm->initialized)
@@ -623,8 +678,8 @@ void vl_api_flowprobe_tx_interface_add_del_t_handler
goto out;
}
- rv = flowprobe_tx_interface_add_del_feature
- (fm, sw_if_index, mp->which, mp->is_add);
+ rv = flowprobe_interface_add_del_feature (fm, sw_if_index, mp->which,
+ FLOW_DIRECTION_TX, mp->is_add);
out:
BAD_SW_IF_INDEX_LABEL;
@@ -632,6 +687,91 @@ out:
REPLY_MACRO (VL_API_FLOWPROBE_TX_INTERFACE_ADD_DEL_REPLY);
}
+void
+vl_api_flowprobe_interface_add_del_t_handler (
+ vl_api_flowprobe_interface_add_del_t *mp)
+{
+ flowprobe_main_t *fm = &flowprobe_main;
+ vl_api_flowprobe_interface_add_del_reply_t *rmp;
+ u32 sw_if_index;
+ u8 which;
+ u8 direction;
+ bool is_add;
+ int rv = 0;
+
+ VALIDATE_SW_IF_INDEX (mp);
+
+ sw_if_index = ntohl (mp->sw_if_index);
+ is_add = mp->is_add;
+
+ if (mp->which == FLOWPROBE_WHICH_IP4)
+ which = FLOW_VARIANT_IP4;
+ else if (mp->which == FLOWPROBE_WHICH_IP6)
+ which = FLOW_VARIANT_IP6;
+ else if (mp->which == FLOWPROBE_WHICH_L2)
+ which = FLOW_VARIANT_L2;
+ else
+ {
+ clib_warning ("Invalid value of which");
+ rv = VNET_API_ERROR_INVALID_VALUE;
+ goto out;
+ }
+
+ if (mp->direction == FLOWPROBE_DIRECTION_RX)
+ direction = FLOW_DIRECTION_RX;
+ else if (mp->direction == FLOWPROBE_DIRECTION_TX)
+ direction = FLOW_DIRECTION_TX;
+ else if (mp->direction == FLOWPROBE_DIRECTION_BOTH)
+ direction = FLOW_DIRECTION_BOTH;
+ else
+ {
+ clib_warning ("Invalid value of direction");
+ rv = VNET_API_ERROR_INVALID_VALUE;
+ goto out;
+ }
+
+ if (fm->record == 0)
+ {
+ clib_warning ("Please specify flowprobe params record first");
+ rv = VNET_API_ERROR_CANNOT_ENABLE_DISABLE_FEATURE;
+ goto out;
+ }
+
+ rv = validate_feature_on_interface (fm, sw_if_index, which);
+ if (rv == 1)
+ {
+ if (is_add)
+ {
+ clib_warning ("Variant is already enabled for given interface");
+ rv = VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
+ goto out;
+ }
+ }
+ else if (rv == 0)
+ {
+ clib_warning ("Interface has different variant enabled");
+ rv = VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
+ goto out;
+ }
+ else if (rv == -1)
+ {
+ if (!is_add)
+ {
+ clib_warning ("Interface has no variant enabled");
+ rv = VNET_API_ERROR_NO_SUCH_ENTRY;
+ goto out;
+ }
+ }
+
+ rv = flowprobe_interface_add_del_feature (fm, sw_if_index, which, direction,
+ is_add);
+
+out:
+ BAD_SW_IF_INDEX_LABEL;
+
+ REPLY_MACRO (VL_API_FLOWPROBE_INTERFACE_ADD_DEL_REPLY);
+}
+
#define vec_neg_search(v,E) \
({ \
word _v(i) = 0; \
@@ -700,9 +840,24 @@ VLIB_PLUGIN_REGISTER () = {
/* *INDENT-ON* */
u8 *
+format_flowprobe_direction (u8 *s, va_list *args)
+{
+ u8 *direction = va_arg (*args, u8 *);
+ if (*direction == FLOW_DIRECTION_RX)
+ s = format (s, "rx");
+ else if (*direction == FLOW_DIRECTION_TX)
+ s = format (s, "tx");
+ else if (*direction == FLOW_DIRECTION_BOTH)
+ s = format (s, "rx tx");
+
+ return s;
+}
+
+u8 *
format_flowprobe_entry (u8 * s, va_list * args)
{
flowprobe_entry_t *e = va_arg (*args, flowprobe_entry_t *);
+ s = format (s, " %U", format_flowprobe_direction, &e->key.direction);
s = format (s, " %d/%d", e->key.rx_sw_if_index, e->key.tx_sw_if_index);
s = format (s, " %U %U", format_ethernet_address, &e->key.src_mac,
@@ -799,14 +954,15 @@ flowprobe_show_stats_fn (vlib_main_t * vm,
}
static clib_error_t *
-flowprobe_tx_interface_add_del_feature_command_fn (vlib_main_t * vm,
- unformat_input_t * input,
- vlib_cli_command_t * cmd)
+flowprobe_interface_add_del_feature_command_fn (vlib_main_t *vm,
+ unformat_input_t *input,
+ vlib_cli_command_t *cmd)
{
flowprobe_main_t *fm = &flowprobe_main;
u32 sw_if_index = ~0;
int is_add = 1;
u8 which = FLOW_VARIANT_IP4;
+ flowprobe_direction_t direction = FLOW_DIRECTION_TX;
int rv;
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
@@ -821,6 +977,12 @@ flowprobe_tx_interface_add_del_feature_command_fn (vlib_main_t * vm,
which = FLOW_VARIANT_IP6;
else if (unformat (input, "l2"))
which = FLOW_VARIANT_L2;
+ else if (unformat (input, "rx"))
+ direction = FLOW_DIRECTION_RX;
+ else if (unformat (input, "tx"))
+ direction = FLOW_DIRECTION_TX;
+ else if (unformat (input, "both"))
+ direction = FLOW_DIRECTION_BOTH;
else
break;
}
@@ -842,9 +1004,16 @@ flowprobe_tx_interface_add_del_feature_command_fn (vlib_main_t * vm,
else if (rv == 0)
return clib_error_return (0,
"Interface has enable different datapath ...");
+ else if (rv == -1)
+ {
+ if (!is_add)
+ {
+ return clib_error_return (0, "Interface has no datapath enabled");
+ }
+ }
- rv =
- flowprobe_tx_interface_add_del_feature (fm, sw_if_index, which, is_add);
+ rv = flowprobe_interface_add_del_feature (fm, sw_if_index, which, direction,
+ is_add);
switch (rv)
{
case 0:
@@ -881,9 +1050,10 @@ flowprobe_show_feature_command_fn (vlib_main_t * vm,
continue;
sw_if_index = which - fm->flow_per_interface;
- vlib_cli_output (vm, " %U %U", format_vnet_sw_if_index_name,
+ vlib_cli_output (vm, " %U %U %U", format_vnet_sw_if_index_name,
vnet_get_main (), sw_if_index, format_flowprobe_feature,
- which);
+ which, format_flowprobe_direction,
+ &fm->direction_per_interface[sw_if_index]);
}
return 0;
}
@@ -962,10 +1132,10 @@ flowprobe_show_params_command_fn (vlib_main_t * vm,
?*/
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (flowprobe_enable_disable_command, static) = {
- .path = "flowprobe feature add-del",
- .short_help =
- "flowprobe feature add-del <interface-name> <l2|ip4|ip6> disable",
- .function = flowprobe_tx_interface_add_del_feature_command_fn,
+ .path = "flowprobe feature add-del",
+ .short_help = "flowprobe feature add-del <interface-name> [(l2|ip4|ip6)] "
+ "[(rx|tx|both)] [disable]",
+ .function = flowprobe_interface_add_del_feature_command_fn,
};
VLIB_CLI_COMMAND (flowprobe_params_command, static) = {
.path = "flowprobe params",