aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/flowprobe
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/flowprobe')
-rw-r--r--src/plugins/flowprobe/FEATURE.yaml9
-rw-r--r--src/plugins/flowprobe/flowprobe.api119
-rw-r--r--src/plugins/flowprobe/flowprobe.c593
-rw-r--r--src/plugins/flowprobe/flowprobe.h19
-rw-r--r--src/plugins/flowprobe/flowprobe_plugin_doc.md13
-rw-r--r--src/plugins/flowprobe/flowprobe_plugin_doc.rst18
-rw-r--r--src/plugins/flowprobe/flowprobe_test.c218
-rw-r--r--src/plugins/flowprobe/node.c327
8 files changed, 1086 insertions, 230 deletions
diff --git a/src/plugins/flowprobe/FEATURE.yaml b/src/plugins/flowprobe/FEATURE.yaml
index 66382433d03..9c80b12dc9f 100644
--- a/src/plugins/flowprobe/FEATURE.yaml
+++ b/src/plugins/flowprobe/FEATURE.yaml
@@ -2,12 +2,11 @@
name: IPFIX probe
maintainer: Ole Troan <ot@cisco.com>
features:
- - L2 input feature
- - IPv4 / IPv6 input feature
- - Recording of L2, L3 and L4 information
-description: "IPFIX flow probe. Works in the L2, or IP input feature path."
+ - L2 input and output feature path
+ - IPv4 / IPv6 input and output feature path
+ - Recording of L2, L3, and L4 information
+description: "IPFIX flow probe. Works in the L2 or IP feature path both input and output."
missing:
- - Output path
- Export over IPv6
- Export over TCP/SCTP
state: production
diff --git a/src/plugins/flowprobe/flowprobe.api b/src/plugins/flowprobe/flowprobe.api
index 55dd51d3c30..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 = "1.0.0";
+option version = "2.1.0";
import "vnet/interface_types.api";
@@ -16,6 +16,13 @@ enum flowprobe_which_flags : u8
FLOWPROBE_WHICH_FLAG_IP6 = 0x4,
};
+enum flowprobe_which : u8
+{
+ FLOWPROBE_WHICH_IP4 = 0,
+ FLOWPROBE_WHICH_IP6,
+ FLOWPROBE_WHICH_L2,
+};
+
enum flowprobe_record_flags : u8
{
FLOWPROBE_RECORD_FLAG_L2 = 0x1,
@@ -23,6 +30,13 @@ enum flowprobe_record_flags : u8
FLOWPROBE_RECORD_FLAG_L4 = 0x4,
};
+enum flowprobe_direction : u8
+{
+ FLOWPROBE_DIRECTION_RX = 0,
+ FLOWPROBE_DIRECTION_TX,
+ FLOWPROBE_DIRECTION_BOTH,
+};
+
/** \brief Enable / disable per-packet IPFIX recording on an interface
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@@ -32,6 +46,8 @@ enum flowprobe_record_flags : u8
*/
autoreply define flowprobe_tx_interface_add_del
{
+ option replaced_by="flowprobe_interface_add_del";
+
/* Client identifier, set from api_main.my_client_index */
u32 client_index;
@@ -47,8 +63,59 @@ autoreply define flowprobe_tx_interface_add_del
option vat_help = "<intfc> [disable]";
};
+/** \brief Enable or disable IPFIX flow record generation on an interface
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param is_add - add interface if non-zero, else delete
+ @param which - datapath on which to record flows
+ @param direction - direction of recorded flows
+ @param sw_if_index - index of the interface
+*/
+autoreply define flowprobe_interface_add_del
+{
+ option in_progress;
+ u32 client_index;
+ u32 context;
+ bool is_add;
+ vl_api_flowprobe_which_t which;
+ vl_api_flowprobe_direction_t direction;
+ vl_api_interface_index_t sw_if_index;
+ option vat_help = "(<intfc> | sw_if_index <if-idx>) [(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 = "[<if-idx>]";
+};
+
+/** \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;
@@ -56,3 +123,53 @@ autoreply define flowprobe_params
u32 passive_timer; /* ~0 is off, 0 is default */
option vat_help = "record <[l2] [l3] [l4]> [active <timer> passive <timer>]";
};
+
+/** \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 <timer>] [passive <timer>]";
+};
+
+/** \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 ffc43bcd440..58a7cfe22f1 100644
--- a/src/plugins/flowprobe/flowprobe.c
+++ b/src/plugins/flowprobe/flowprobe.c
@@ -45,35 +45,54 @@ uword flowprobe_walker_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
#include <vlibapi/api_helper_macros.h>
/* 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* */
-/* Macro to finish up custom dump fns */
-#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
-#define FINISH \
- vec_add1 (s, 0); \
- vl_print (handle, (char *)s); \
- vec_free (s); \
- return handle;
+#define FINISH \
+ vec_add1 (s, 0); \
+ vlib_cli_output (handle, (char *) s); \
+ vec_free (s); \
+ return handle;
static inline ipfix_field_specifier_t *
flowprobe_template_ip4_fields (ipfix_field_specifier_t * f)
@@ -143,7 +162,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 +173,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);
@@ -202,10 +225,7 @@ flowprobe_template_l4_fields (ipfix_field_specifier_t * f)
* @returns u8 * vector containing the indicated IPFIX template packet
*/
static inline u8 *
-flowprobe_template_rewrite_inline (flow_report_main_t * frm,
- flow_report_t * fr,
- ip4_address_t * collector_address,
- ip4_address_t * src_address,
+flowprobe_template_rewrite_inline (ipfix_exporter_t *exp, flow_report_t *fr,
u16 collector_port,
flowprobe_variant_t which)
{
@@ -223,8 +243,9 @@ flowprobe_template_rewrite_inline (flow_report_main_t * frm,
flowprobe_main_t *fm = &flowprobe_main;
flowprobe_record_t flags = fr->opaque.as_uword;
bool collect_ip4 = false, collect_ip6 = false;
+ bool collect_l4 = false;
- stream = &frm->streams[fr->stream_index];
+ stream = &exp->streams[fr->stream_index];
if (flags & FLOW_RECORD_L3)
{
@@ -235,6 +256,10 @@ flowprobe_template_rewrite_inline (flow_report_main_t * frm,
if (which == FLOW_VARIANT_L2_IP6)
flags |= FLOW_RECORD_L2_IP6;
}
+ if (flags & FLOW_RECORD_L4)
+ {
+ collect_l4 = (which != FLOW_VARIANT_L2);
+ }
field_count += flowprobe_template_common_field_count ();
if (flags & FLOW_RECORD_L2)
@@ -243,7 +268,7 @@ flowprobe_template_rewrite_inline (flow_report_main_t * frm,
field_count += flowprobe_template_ip4_field_count ();
if (collect_ip6)
field_count += flowprobe_template_ip6_field_count ();
- if (flags & FLOW_RECORD_L4)
+ if (collect_l4)
field_count += flowprobe_template_l4_field_count ();
/* allocate rewrite space */
@@ -263,8 +288,8 @@ flowprobe_template_rewrite_inline (flow_report_main_t * frm,
ip->ip_version_and_header_length = 0x45;
ip->ttl = 254;
ip->protocol = IP_PROTOCOL_UDP;
- ip->src_address.as_u32 = src_address->as_u32;
- ip->dst_address.as_u32 = collector_address->as_u32;
+ ip->src_address.as_u32 = exp->src_address.ip.ip4.as_u32;
+ ip->dst_address.as_u32 = exp->ipfix_collector.ip.ip4.as_u32;
udp->src_port = clib_host_to_net_u16 (stream->src_port);
udp->dst_port = clib_host_to_net_u16 (collector_port);
udp->length = clib_host_to_net_u16 (vec_len (rewrite) - sizeof (*ip));
@@ -282,7 +307,7 @@ flowprobe_template_rewrite_inline (flow_report_main_t * frm,
f = flowprobe_template_ip4_fields (f);
if (collect_ip6)
f = flowprobe_template_ip6_fields (f);
- if (flags & FLOW_RECORD_L4)
+ if (collect_l4)
f = flowprobe_template_l4_fields (f);
/* Back to the template packet... */
@@ -309,73 +334,53 @@ flowprobe_template_rewrite_inline (flow_report_main_t * frm,
}
static u8 *
-flowprobe_template_rewrite_ip6 (flow_report_main_t * frm,
- flow_report_t * fr,
- ip4_address_t * collector_address,
- ip4_address_t * src_address,
+flowprobe_template_rewrite_ip6 (ipfix_exporter_t *exp, flow_report_t *fr,
u16 collector_port,
- ipfix_report_element_t * elts,
- u32 n_elts, u32 * stream_index)
+ ipfix_report_element_t *elts, u32 n_elts,
+ u32 *stream_index)
{
- return flowprobe_template_rewrite_inline
- (frm, fr, collector_address, src_address, collector_port,
- FLOW_VARIANT_IP6);
+ return flowprobe_template_rewrite_inline (exp, fr, collector_port,
+ FLOW_VARIANT_IP6);
}
static u8 *
-flowprobe_template_rewrite_ip4 (flow_report_main_t * frm,
- flow_report_t * fr,
- ip4_address_t * collector_address,
- ip4_address_t * src_address,
+flowprobe_template_rewrite_ip4 (ipfix_exporter_t *exp, flow_report_t *fr,
u16 collector_port,
- ipfix_report_element_t * elts,
- u32 n_elts, u32 * stream_index)
+ ipfix_report_element_t *elts, u32 n_elts,
+ u32 *stream_index)
{
- return flowprobe_template_rewrite_inline
- (frm, fr, collector_address, src_address, collector_port,
- FLOW_VARIANT_IP4);
+ return flowprobe_template_rewrite_inline (exp, fr, collector_port,
+ FLOW_VARIANT_IP4);
}
static u8 *
-flowprobe_template_rewrite_l2 (flow_report_main_t * frm,
- flow_report_t * fr,
- ip4_address_t * collector_address,
- ip4_address_t * src_address,
+flowprobe_template_rewrite_l2 (ipfix_exporter_t *exp, flow_report_t *fr,
u16 collector_port,
- ipfix_report_element_t * elts,
- u32 n_elts, u32 * stream_index)
+ ipfix_report_element_t *elts, u32 n_elts,
+ u32 *stream_index)
{
- return flowprobe_template_rewrite_inline
- (frm, fr, collector_address, src_address, collector_port,
- FLOW_VARIANT_L2);
+ return flowprobe_template_rewrite_inline (exp, fr, collector_port,
+ FLOW_VARIANT_L2);
}
static u8 *
-flowprobe_template_rewrite_l2_ip4 (flow_report_main_t * frm,
- flow_report_t * fr,
- ip4_address_t * collector_address,
- ip4_address_t * src_address,
+flowprobe_template_rewrite_l2_ip4 (ipfix_exporter_t *exp, flow_report_t *fr,
u16 collector_port,
- ipfix_report_element_t * elts,
- u32 n_elts, u32 * stream_index)
+ ipfix_report_element_t *elts, u32 n_elts,
+ u32 *stream_index)
{
- return flowprobe_template_rewrite_inline
- (frm, fr, collector_address, src_address, collector_port,
- FLOW_VARIANT_L2_IP4);
+ return flowprobe_template_rewrite_inline (exp, fr, collector_port,
+ FLOW_VARIANT_L2_IP4);
}
static u8 *
-flowprobe_template_rewrite_l2_ip6 (flow_report_main_t * frm,
- flow_report_t * fr,
- ip4_address_t * collector_address,
- ip4_address_t * src_address,
+flowprobe_template_rewrite_l2_ip6 (ipfix_exporter_t *exp, flow_report_t *fr,
u16 collector_port,
- ipfix_report_element_t * elts,
- u32 n_elts, u32 * stream_index)
+ ipfix_report_element_t *elts, u32 n_elts,
+ u32 *stream_index)
{
- return flowprobe_template_rewrite_inline
- (frm, fr, collector_address, src_address, collector_port,
- FLOW_VARIANT_L2_IP6);
+ return flowprobe_template_rewrite_inline (exp, fr, collector_port,
+ FLOW_VARIANT_L2_IP6);
}
/**
@@ -389,27 +394,27 @@ flowprobe_template_rewrite_l2_ip6 (flow_report_main_t * frm,
* will be sent.
*/
vlib_frame_t *
-flowprobe_data_callback_ip4 (flow_report_main_t * frm,
- flow_report_t * fr,
- vlib_frame_t * f, u32 * to_next, u32 node_index)
+flowprobe_data_callback_ip4 (flow_report_main_t *frm, ipfix_exporter_t *exp,
+ flow_report_t *fr, vlib_frame_t *f, u32 *to_next,
+ u32 node_index)
{
flowprobe_flush_callback_ip4 ();
return f;
}
vlib_frame_t *
-flowprobe_data_callback_ip6 (flow_report_main_t * frm,
- flow_report_t * fr,
- vlib_frame_t * f, u32 * to_next, u32 node_index)
+flowprobe_data_callback_ip6 (flow_report_main_t *frm, ipfix_exporter_t *exp,
+ flow_report_t *fr, vlib_frame_t *f, u32 *to_next,
+ u32 node_index)
{
flowprobe_flush_callback_ip6 ();
return f;
}
vlib_frame_t *
-flowprobe_data_callback_l2 (flow_report_main_t * frm,
- flow_report_t * fr,
- vlib_frame_t * f, u32 * to_next, u32 node_index)
+flowprobe_data_callback_l2 (flow_report_main_t *frm, ipfix_exporter_t *exp,
+ flow_report_t *fr, vlib_frame_t *f, u32 *to_next,
+ u32 node_index)
{
flowprobe_flush_callback_l2 ();
return f;
@@ -422,7 +427,7 @@ flowprobe_template_add_del (u32 domain_id, u16 src_port,
vnet_flow_rewrite_callback_t * rewrite_callback,
bool is_add, u16 * template_id)
{
- flow_report_main_t *frm = &flow_report_main;
+ ipfix_exporter_t *exp = &flow_report_main.exporters[0];
vnet_flow_report_add_del_args_t a = {
.rewrite_callback = rewrite_callback,
.flow_data_callback = flow_data_callback,
@@ -431,7 +436,7 @@ flowprobe_template_add_del (u32 domain_id, u16 src_port,
.src_port = src_port,
.opaque.as_uword = flags,
};
- return vnet_flow_report_add_del (frm, &a, template_id);
+ return vnet_flow_report_add_del (exp, &a, template_id);
}
static void
@@ -501,11 +506,49 @@ flowprobe_create_state_tables (u32 active_timer)
return error;
}
+static clib_error_t *
+flowprobe_clear_state_if_index (u32 sw_if_index)
+{
+ flowprobe_main_t *fm = &flowprobe_main;
+ clib_error_t *error = 0;
+ u32 worker_i;
+ u32 entry_i;
+
+ if (fm->active_timer > 0)
+ {
+ vec_foreach_index (worker_i, fm->pool_per_worker)
+ {
+ pool_foreach_index (entry_i, fm->pool_per_worker[worker_i])
+ {
+ flowprobe_entry_t *e =
+ pool_elt_at_index (fm->pool_per_worker[worker_i], entry_i);
+ if (e->key.rx_sw_if_index == sw_if_index ||
+ e->key.tx_sw_if_index == sw_if_index)
+ {
+ e->packetcount = 0;
+ e->octetcount = 0;
+ e->prot.tcp.flags = 0;
+ if (fm->passive_timer > 0)
+ {
+ tw_timer_stop_2t_1w_2048sl (
+ fm->timers_per_worker[worker_i],
+ e->passive_timer_handle);
+ }
+ flowprobe_delete_by_index (worker_i, entry_i);
+ }
+ }
+ }
+ }
+
+ return error;
+}
+
static int
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;
@@ -519,13 +562,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;
@@ -533,6 +578,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];
@@ -542,12 +588,17 @@ flowprobe_tx_interface_add_del_feature (flowprobe_main_t * fm,
{
if (which == FLOW_VARIANT_L2)
{
+ if (!is_add)
+ {
+ flowprobe_flush_callback_l2 ();
+ }
if (fm->record & FLOW_RECORD_L2)
{
rv = flowprobe_template_add_del (1, UDP_DST_PORT_ipfix, flags,
flowprobe_data_callback_l2,
flowprobe_template_rewrite_l2,
is_add, &template_id);
+ fm->template_reports[flags] = (is_add) ? template_id : 0;
}
if (fm->record & FLOW_RECORD_L3 || fm->record & FLOW_RECORD_L4)
{
@@ -570,20 +621,30 @@ flowprobe_tx_interface_add_del_feature (flowprobe_main_t * fm,
flags | FLOW_RECORD_L2_IP4;
fm->context[FLOW_VARIANT_L2_IP6].flags =
flags | FLOW_RECORD_L2_IP6;
-
- fm->template_reports[flags] = template_id;
}
}
else if (which == FLOW_VARIANT_IP4)
- rv = flowprobe_template_add_del (1, UDP_DST_PORT_ipfix, flags,
- flowprobe_data_callback_ip4,
- flowprobe_template_rewrite_ip4,
- is_add, &template_id);
+ {
+ if (!is_add)
+ {
+ flowprobe_flush_callback_ip4 ();
+ }
+ rv = flowprobe_template_add_del (
+ 1, UDP_DST_PORT_ipfix, flags, flowprobe_data_callback_ip4,
+ flowprobe_template_rewrite_ip4, is_add, &template_id);
+ fm->template_reports[flags] = (is_add) ? template_id : 0;
+ }
else if (which == FLOW_VARIANT_IP6)
- rv = flowprobe_template_add_del (1, UDP_DST_PORT_ipfix, flags,
- flowprobe_data_callback_ip6,
- flowprobe_template_rewrite_ip6,
- is_add, &template_id);
+ {
+ if (!is_add)
+ {
+ flowprobe_flush_callback_ip6 ();
+ }
+ rv = flowprobe_template_add_del (
+ 1, UDP_DST_PORT_ipfix, flags, flowprobe_data_callback_ip6,
+ flowprobe_template_rewrite_ip6, is_add, &template_id);
+ fm->template_reports[flags] = (is_add) ? template_id : 0;
+ }
}
if (rv && rv != VNET_API_ERROR_VALUE_EXIST)
{
@@ -594,18 +655,41 @@ flowprobe_tx_interface_add_del_feature (flowprobe_main_t * fm,
if (which != (u8) ~ 0)
{
fm->context[which].flags = fm->record;
- 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)
@@ -615,6 +699,11 @@ flowprobe_tx_interface_add_del_feature (flowprobe_main_t * fm,
vlib_process_signal_event (vm, flowprobe_timer_node.index, 1, 0);
}
+ if (!is_add && fm->initialized)
+ {
+ flowprobe_clear_state_if_index (sw_if_index);
+ }
+
return 0;
}
@@ -646,8 +735,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;
@@ -655,6 +744,167 @@ 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);
+}
+
+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; \
@@ -675,7 +925,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;
@@ -715,17 +965,89 @@ vl_api_flowprobe_params_t_handler (vl_api_flowprobe_params_t * mp)
REPLY_MACRO (VL_API_FLOWPROBE_PARAMS_REPLY);
}
-/* *INDENT-OFF* */
+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
+}
+
VLIB_PLUGIN_REGISTER () = {
.version = VPP_BUILD_VER,
.description = "Flow per Packet",
};
-/* *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,
@@ -789,14 +1111,12 @@ flowprobe_show_table_fn (vlib_main_t * vm,
for (i = 0; i < vec_len (fm->pool_per_worker); i++)
{
- /* *INDENT-OFF* */
pool_foreach (e, fm->pool_per_worker[i])
{
vlib_cli_output (vm, "%U",
format_flowprobe_entry,
e);
}
- /* *INDENT-ON* */
}
return 0;
@@ -822,14 +1142,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)
@@ -844,6 +1165,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;
}
@@ -865,9 +1192,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:
@@ -904,9 +1238,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;
}
@@ -983,18 +1318,17 @@ flowprobe_show_params_command_fn (vlib_main_t * vm,
* @cliexend
* @endparblock
?*/
-/* *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",
- .short_help =
- "flowprobe params record <[l2] [l3] [l4]> [active <timer> passive <timer>]",
- .function = flowprobe_params_command_fn,
+ .path = "flowprobe params",
+ .short_help = "flowprobe params record [l2] [l3] [l4] [active <timer>] "
+ "[passive <timer>]",
+ .function = flowprobe_params_command_fn,
};
VLIB_CLI_COMMAND (flowprobe_show_feature_command, static) = {
@@ -1019,7 +1353,6 @@ VLIB_CLI_COMMAND (flowprobe_show_stats_command, static) = {
.short_help = "show flowprobe statistics",
.function = flowprobe_show_stats_fn,
};
-/* *INDENT-ON* */
/*
* Main-core process, sending an interrupt to the per worker input
@@ -1073,13 +1406,11 @@ timer_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
return 0; /* or not */
}
-/* *INDENT-OFF* */
VLIB_REGISTER_NODE (flowprobe_timer_node,static) = {
.function = timer_process,
.name = "flowprobe-timer-process",
.type = VLIB_NODE_TYPE_PROCESS,
};
-/* *INDENT-ON* */
#include <flowprobe/flowprobe.api.c>
diff --git a/src/plugins/flowprobe/flowprobe.h b/src/plugins/flowprobe/flowprobe.h
index 2d28c81de33..1fde5f94491 100644
--- a/src/plugins/flowprobe/flowprobe.h
+++ b/src/plugins/flowprobe/flowprobe.h
@@ -42,17 +42,22 @@ typedef enum
FLOW_N_RECORDS = 1 << 5,
} flowprobe_record_t;
-/* *INDENT-OFF* */
typedef enum __attribute__ ((__packed__))
{
- FLOW_VARIANT_IP4,
+ FLOW_VARIANT_IP4 = 0,
FLOW_VARIANT_IP6,
FLOW_VARIANT_L2,
FLOW_VARIANT_L2_IP4,
FLOW_VARIANT_L2_IP6,
FLOW_N_VARIANTS,
} flowprobe_variant_t;
-/* *INDENT-ON* */
+
+typedef enum __attribute__ ((__packed__))
+{
+ FLOW_DIRECTION_RX = 0,
+ FLOW_DIRECTION_TX,
+ FLOW_DIRECTION_BOTH,
+} flowprobe_direction_t;
STATIC_ASSERT (sizeof (flowprobe_variant_t) == 1,
"flowprobe_variant_t is expected to be 1 byte, "
@@ -72,7 +77,6 @@ typedef struct
u16 *next_record_offset_per_worker;
} flowprobe_protocol_context_t;
-/* *INDENT-OFF* */
typedef struct __attribute__ ((aligned (8))) {
u32 rx_sw_if_index;
u32 tx_sw_if_index;
@@ -85,8 +89,8 @@ typedef struct __attribute__ ((aligned (8))) {
u16 src_port;
u16 dst_port;
flowprobe_variant_t which;
+ flowprobe_direction_t direction;
} flowprobe_key_t;
-/* *INDENT-ON* */
typedef struct
{
@@ -134,9 +138,7 @@ typedef struct
u8 ht_log2len; /* Hash table size is 2^log2len */
u32 **hash_per_worker;
flowprobe_entry_t **pool_per_worker;
- /* *INDENT-OFF* */
TWT (tw_timer_wheel) ** timers_per_worker;
- /* *INDENT-ON* */
u32 **expired_passive_per_worker;
flowprobe_record_t record;
@@ -149,6 +151,7 @@ typedef struct
u16 template_per_flow[FLOW_N_VARIANTS];
u8 *flow_per_interface;
+ u8 *direction_per_interface;
/** convenience vlib_main_t pointer */
vlib_main_t *vlib_main;
@@ -159,6 +162,8 @@ typedef struct
extern flowprobe_main_t flowprobe_main;
extern vlib_node_registration_t flowprobe_walker_node;
+void flowprobe_delete_by_index (u32 my_cpu_number, u32 poolindex);
+
void flowprobe_flush_callback_ip4 (void);
void flowprobe_flush_callback_ip6 (void);
void flowprobe_flush_callback_l2 (void);
diff --git a/src/plugins/flowprobe/flowprobe_plugin_doc.md b/src/plugins/flowprobe/flowprobe_plugin_doc.md
deleted file mode 100644
index 4c9b2342a83..00000000000
--- a/src/plugins/flowprobe/flowprobe_plugin_doc.md
+++ /dev/null
@@ -1,13 +0,0 @@
-IPFIX flow record plugin {#flowprobe_plugin_doc}
-========================
-
-## Introduction
-
-This plugin generates ipfix flow records on interfaces which have the feature enabled
-
-## Sample configuration
-
-set ipfix exporter collector 192.168.6.2 src 192.168.6.1 template-interval 20 port 4739 path-mtu 1500
-
-flowprobe params record l3 active 20 passive 120
-flowprobe feature add-del GigabitEthernet2/3/0 l2 \ No newline at end of file
diff --git a/src/plugins/flowprobe/flowprobe_plugin_doc.rst b/src/plugins/flowprobe/flowprobe_plugin_doc.rst
new file mode 100644
index 00000000000..4add41f5611
--- /dev/null
+++ b/src/plugins/flowprobe/flowprobe_plugin_doc.rst
@@ -0,0 +1,18 @@
+IPFIX flow record plugin
+========================
+
+Introduction
+------------
+
+This plugin generates ipfix flow records on interfaces which have the
+feature enabled
+
+Sample configuration
+--------------------
+
+::
+
+ set ipfix exporter collector 192.168.6.2 src 192.168.6.1 template-interval 20 port 4739 path-mtu 1450
+
+ flowprobe params record l3 active 20 passive 120
+ flowprobe feature add-del GigabitEthernet2/3/0 l2
diff --git a/src/plugins/flowprobe/flowprobe_test.c b/src/plugins/flowprobe/flowprobe_test.c
index a694e45ae9b..37b91207e29 100644
--- a/src/plugins/flowprobe/flowprobe_test.c
+++ b/src/plugins/flowprobe/flowprobe_test.c
@@ -93,6 +93,136 @@ api_flowprobe_tx_interface_add_del (vat_main_t * vam)
}
static int
+api_flowprobe_interface_add_del (vat_main_t *vam)
+{
+ unformat_input_t *i = vam->input;
+ int enable_disable = 1;
+ u8 which = FLOWPROBE_WHICH_IP4;
+ u8 direction = FLOWPROBE_DIRECTION_TX;
+ u32 sw_if_index = ~0;
+ vl_api_flowprobe_interface_add_del_t *mp;
+ int ret;
+
+ /* Parse args required to build the message */
+ while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index))
+ ;
+ else if (unformat (i, "sw_if_index %d", &sw_if_index))
+ ;
+ else if (unformat (i, "disable"))
+ enable_disable = 0;
+ else if (unformat (i, "ip4"))
+ which = FLOWPROBE_WHICH_IP4;
+ else if (unformat (i, "ip6"))
+ which = FLOWPROBE_WHICH_IP6;
+ else if (unformat (i, "l2"))
+ which = FLOWPROBE_WHICH_L2;
+ else if (unformat (i, "rx"))
+ direction = FLOWPROBE_DIRECTION_RX;
+ else if (unformat (i, "tx"))
+ direction = FLOWPROBE_DIRECTION_TX;
+ else if (unformat (i, "both"))
+ direction = FLOWPROBE_DIRECTION_BOTH;
+ else
+ break;
+ }
+
+ if (sw_if_index == ~0)
+ {
+ errmsg ("Missing interface name / explicit sw_if_index number\n");
+ return -99;
+ }
+
+ /* Construct the API message */
+ M (FLOWPROBE_INTERFACE_ADD_DEL, mp);
+ mp->sw_if_index = ntohl (sw_if_index);
+ mp->is_add = enable_disable;
+ mp->which = which;
+ mp->direction = direction;
+
+ /* Send it... */
+ S (mp);
+
+ /* Wait for a reply... */
+ W (ret);
+ 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)
{
unformat_input_t *i = vam->input;
@@ -145,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
diff --git a/src/plugins/flowprobe/node.c b/src/plugins/flowprobe/node.c
index e7a39a7ed7e..03511689dda 100644
--- a/src/plugins/flowprobe/node.c
+++ b/src/plugins/flowprobe/node.c
@@ -17,6 +17,7 @@
#include <vlib/vlib.h>
#include <vnet/vnet.h>
#include <vppinfra/crc32.h>
+#include <vppinfra/xxhash.h>
#include <vppinfra/error.h>
#include <flowprobe/flowprobe.h>
#include <vnet/ip/ip6_packet.h>
@@ -98,9 +99,15 @@ format_flowprobe_trace (u8 * s, va_list * args)
return s;
}
-vlib_node_registration_t flowprobe_ip4_node;
-vlib_node_registration_t flowprobe_ip6_node;
-vlib_node_registration_t flowprobe_l2_node;
+vlib_node_registration_t flowprobe_input_ip4_node;
+vlib_node_registration_t flowprobe_input_ip6_node;
+vlib_node_registration_t flowprobe_input_l2_node;
+vlib_node_registration_t flowprobe_output_ip4_node;
+vlib_node_registration_t flowprobe_output_ip6_node;
+vlib_node_registration_t flowprobe_output_l2_node;
+vlib_node_registration_t flowprobe_flush_ip4_node;
+vlib_node_registration_t flowprobe_flush_ip6_node;
+vlib_node_registration_t flowprobe_flush_l2_node;
/* No counters at the moment */
#define foreach_flowprobe_error \
@@ -166,6 +173,11 @@ flowprobe_common_add (vlib_buffer_t * to_b, flowprobe_entry_t * e, u16 offset)
clib_memcpy_fast (to_b->data + offset, &tx_if, sizeof (tx_if));
offset += sizeof (tx_if);
+ /* Flow direction
+ 0x00: ingress flow
+ 0x01: egress flow */
+ to_b->data[offset++] = (e->key.direction == FLOW_DIRECTION_TX);
+
/* packet delta count */
u64 packetdelta = clib_host_to_net_u64 (e->packetcount);
clib_memcpy_fast (to_b->data + offset, &packetdelta, sizeof (u64));
@@ -357,25 +369,30 @@ flowprobe_create (u32 my_cpu_number, flowprobe_key_t * k, u32 * poolindex)
}
static inline void
-add_to_flow_record_state (vlib_main_t * vm, vlib_node_runtime_t * node,
- flowprobe_main_t * fm, vlib_buffer_t * b,
+add_to_flow_record_state (vlib_main_t *vm, vlib_node_runtime_t *node,
+ flowprobe_main_t *fm, vlib_buffer_t *b,
timestamp_nsec_t timestamp, u16 length,
- flowprobe_variant_t which, flowprobe_trace_t * t)
+ flowprobe_variant_t which,
+ flowprobe_direction_t direction,
+ flowprobe_trace_t *t)
{
if (fm->disabled)
return;
+ ASSERT (direction == FLOW_DIRECTION_RX || direction == FLOW_DIRECTION_TX);
+
u32 my_cpu_number = vm->thread_index;
u16 octets = 0;
flowprobe_record_t flags = fm->context[which].flags;
bool collect_ip4 = false, collect_ip6 = false;
ASSERT (b);
- ethernet_header_t *eth = vlib_buffer_get_current (b);
+ ethernet_header_t *eth = (direction == FLOW_DIRECTION_TX) ?
+ vlib_buffer_get_current (b) :
+ ethernet_buffer_get_header (b);
u16 ethertype = clib_net_to_host_u16 (eth->type);
- /* *INDENT-OFF* */
+ i16 l3_hdr_offset = (u8 *) eth - b->data + sizeof (ethernet_header_t);
flowprobe_key_t k = {};
- /* *INDENT-ON* */
ip4_header_t *ip4 = 0;
ip6_header_t *ip6 = 0;
udp_header_t *udp = 0;
@@ -392,6 +409,7 @@ add_to_flow_record_state (vlib_main_t * vm, vlib_node_runtime_t * node,
k.tx_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_TX];
k.which = which;
+ k.direction = direction;
if (flags & FLOW_RECORD_L2)
{
@@ -399,9 +417,22 @@ add_to_flow_record_state (vlib_main_t * vm, vlib_node_runtime_t * node,
clib_memcpy_fast (k.dst_mac, eth->dst_address, 6);
k.ethertype = ethertype;
}
+ if (ethertype == ETHERNET_TYPE_VLAN)
+ {
+ /*VLAN TAG*/
+ ethernet_vlan_header_tv_t *ethv =
+ (ethernet_vlan_header_tv_t *) (&(eth->type));
+ /*Q in Q possibility */
+ while (clib_net_to_host_u16 (ethv->type) == ETHERNET_TYPE_VLAN)
+ {
+ ethv++;
+ l3_hdr_offset += sizeof (ethernet_vlan_header_tv_t);
+ }
+ k.ethertype = ethertype = clib_net_to_host_u16 ((ethv)->type);
+ }
if (collect_ip6 && ethertype == ETHERNET_TYPE_IP6)
{
- ip6 = (ip6_header_t *) (eth + 1);
+ ip6 = (ip6_header_t *) (b->data + l3_hdr_offset);
if (flags & FLOW_RECORD_L3)
{
k.src_address.as_u64[0] = ip6->src_address.as_u64[0];
@@ -420,7 +451,7 @@ add_to_flow_record_state (vlib_main_t * vm, vlib_node_runtime_t * node,
}
if (collect_ip4 && ethertype == ETHERNET_TYPE_IP4)
{
- ip4 = (ip4_header_t *) (eth + 1);
+ ip4 = (ip4_header_t *) (b->data + l3_hdr_offset);
if (flags & FLOW_RECORD_L3)
{
k.src_address.ip4.as_u32 = ip4->src_address.as_u32;
@@ -520,6 +551,7 @@ flowprobe_export_send (vlib_main_t * vm, vlib_buffer_t * b0,
{
flowprobe_main_t *fm = &flowprobe_main;
flow_report_main_t *frm = &flow_report_main;
+ ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
vlib_frame_t *f;
ip4_ipfix_template_packet_t *tp;
ipfix_set_header_t *s;
@@ -537,19 +569,19 @@ flowprobe_export_send (vlib_main_t * vm, vlib_buffer_t * b0,
flowprobe_get_headersize ())
return;
- u32 i, index = vec_len (frm->streams);
+ u32 i, index = vec_len (exp->streams);
for (i = 0; i < index; i++)
- if (frm->streams[i].domain_id == 1)
+ if (exp->streams[i].domain_id == 1)
{
index = i;
break;
}
- if (i == vec_len (frm->streams))
+ if (i == vec_len (exp->streams))
{
- vec_validate (frm->streams, index);
- frm->streams[index].domain_id = 1;
+ vec_validate (exp->streams, index);
+ exp->streams[index].domain_id = 1;
}
- stream = &frm->streams[index];
+ stream = &exp->streams[index];
tp = vlib_buffer_get_current (b0);
ip = (ip4_header_t *) & tp->ip4;
@@ -561,16 +593,15 @@ flowprobe_export_send (vlib_main_t * vm, vlib_buffer_t * b0,
ip->ttl = 254;
ip->protocol = IP_PROTOCOL_UDP;
ip->flags_and_fragment_offset = 0;
- ip->src_address.as_u32 = frm->src_address.as_u32;
- ip->dst_address.as_u32 = frm->ipfix_collector.as_u32;
+ ip->src_address.as_u32 = exp->src_address.ip.ip4.as_u32;
+ ip->dst_address.as_u32 = exp->ipfix_collector.ip.ip4.as_u32;
udp->src_port = clib_host_to_net_u16 (stream->src_port);
- udp->dst_port = clib_host_to_net_u16 (frm->collector_port);
+ udp->dst_port = clib_host_to_net_u16 (exp->collector_port);
udp->checksum = 0;
/* FIXUP: message header export_time */
- h->export_time = (u32)
- (((f64) frm->unix_time_0) +
- (vlib_time_now (frm->vlib_main) - frm->vlib_time_0));
+ h->export_time =
+ (u32) (((f64) frm->unix_time_0) + (vlib_time_now (vm) - frm->vlib_time_0));
h->export_time = clib_host_to_net_u32 (h->export_time);
h->domain_id = clib_host_to_net_u32 (stream->domain_id);
@@ -590,7 +621,7 @@ flowprobe_export_send (vlib_main_t * vm, vlib_buffer_t * b0,
ip->checksum = ip4_header_checksum (ip);
udp->length = clib_host_to_net_u16 (b0->current_length - sizeof (*ip));
- if (frm->udp_checksum)
+ if (exp->udp_checksum)
{
/* RFC 7011 section 10.3.2. */
udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip);
@@ -616,7 +647,7 @@ flowprobe_export_send (vlib_main_t * vm, vlib_buffer_t * b0,
}
vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
- vlib_node_increment_counter (vm, flowprobe_l2_node.index,
+ vlib_node_increment_counter (vm, flowprobe_output_l2_node.index,
FLOWPROBE_ERROR_EXPORTED_PACKETS, 1);
fm->context[which].frames_per_worker[my_cpu_number] = 0;
@@ -629,7 +660,7 @@ static vlib_buffer_t *
flowprobe_get_buffer (vlib_main_t * vm, flowprobe_variant_t which)
{
flowprobe_main_t *fm = &flowprobe_main;
- flow_report_main_t *frm = &flow_report_main;
+ ipfix_exporter_t *exp = pool_elt_at_index (flow_report_main.exporters, 0);
vlib_buffer_t *b0;
u32 bi0;
u32 my_cpu_number = vm->thread_index;
@@ -642,7 +673,7 @@ flowprobe_get_buffer (vlib_main_t * vm, flowprobe_variant_t which)
{
if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
{
- vlib_node_increment_counter (vm, flowprobe_l2_node.index,
+ vlib_node_increment_counter (vm, flowprobe_output_l2_node.index,
FLOWPROBE_ERROR_BUFFER, 1);
return 0;
}
@@ -656,7 +687,7 @@ flowprobe_get_buffer (vlib_main_t * vm, flowprobe_variant_t which)
b0->flags |=
(VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_FLOW_REPORT);
vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;
- vnet_buffer (b0)->sw_if_index[VLIB_TX] = frm->fib_index;
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] = exp->fib_index;
fm->context[which].next_record_offset_per_worker[my_cpu_number] =
b0->current_length;
}
@@ -669,9 +700,10 @@ flowprobe_export_entry (vlib_main_t * vm, flowprobe_entry_t * e)
{
u32 my_cpu_number = vm->thread_index;
flowprobe_main_t *fm = &flowprobe_main;
- flow_report_main_t *frm = &flow_report_main;
+ ipfix_exporter_t *exp = pool_elt_at_index (flow_report_main.exporters, 0);
vlib_buffer_t *b0;
bool collect_ip4 = false, collect_ip6 = false;
+ bool collect_l4 = false;
flowprobe_variant_t which = e->key.which;
flowprobe_record_t flags = fm->context[which].flags;
u16 offset =
@@ -690,6 +722,10 @@ flowprobe_export_entry (vlib_main_t * vm, flowprobe_entry_t * e)
collect_ip4 = which == FLOW_VARIANT_L2_IP4 || which == FLOW_VARIANT_IP4;
collect_ip6 = which == FLOW_VARIANT_L2_IP6 || which == FLOW_VARIANT_IP6;
}
+ if (flags & FLOW_RECORD_L4)
+ {
+ collect_l4 = (which != FLOW_VARIANT_L2);
+ }
offset += flowprobe_common_add (b0, e, offset);
@@ -699,26 +735,27 @@ flowprobe_export_entry (vlib_main_t * vm, flowprobe_entry_t * e)
offset += flowprobe_l3_ip6_add (b0, e, offset);
if (collect_ip4)
offset += flowprobe_l3_ip4_add (b0, e, offset);
- if (flags & FLOW_RECORD_L4)
+ if (collect_l4)
offset += flowprobe_l4_add (b0, e, offset);
/* Reset per flow-export counters */
e->packetcount = 0;
e->octetcount = 0;
e->last_exported = vlib_time_now (vm);
+ e->prot.tcp.flags = 0;
b0->current_length = offset;
fm->context[which].next_record_offset_per_worker[my_cpu_number] = offset;
/* Time to flush the buffer? */
- if (offset + fm->template_size[flags] > frm->path_mtu)
+ if (offset + fm->template_size[flags] > exp->path_mtu)
flowprobe_export_send (vm, b0, which);
}
uword
-flowprobe_node_fn (vlib_main_t * vm,
- vlib_node_runtime_t * node, vlib_frame_t * frame,
- flowprobe_variant_t which)
+flowprobe_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
+ vlib_frame_t *frame, flowprobe_variant_t which,
+ flowprobe_direction_t direction)
{
u32 n_left_from, *from, *to_next;
flowprobe_next_t next_index;
@@ -778,20 +815,22 @@ flowprobe_node_fn (vlib_main_t * vm,
u16 ethertype0 = clib_net_to_host_u16 (eh0->type);
if (PREDICT_TRUE ((b0->flags & VNET_BUFFER_F_FLOW_REPORT) == 0))
- add_to_flow_record_state (vm, node, fm, b0, timestamp, len0,
- flowprobe_get_variant
- (which, fm->context[which].flags,
- ethertype0), 0);
+ add_to_flow_record_state (
+ vm, node, fm, b0, timestamp, len0,
+ flowprobe_get_variant (which, fm->context[which].flags,
+ ethertype0),
+ direction, 0);
len1 = vlib_buffer_length_in_chain (vm, b1);
ethernet_header_t *eh1 = vlib_buffer_get_current (b1);
u16 ethertype1 = clib_net_to_host_u16 (eh1->type);
if (PREDICT_TRUE ((b1->flags & VNET_BUFFER_F_FLOW_REPORT) == 0))
- add_to_flow_record_state (vm, node, fm, b1, timestamp, len1,
- flowprobe_get_variant
- (which, fm->context[which].flags,
- ethertype1), 0);
+ add_to_flow_record_state (
+ vm, node, fm, b1, timestamp, len1,
+ flowprobe_get_variant (which, fm->context[which].flags,
+ ethertype1),
+ direction, 0);
/* verify speculative enqueues, maybe switch current next frame */
vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
@@ -829,10 +868,11 @@ flowprobe_node_fn (vlib_main_t * vm,
&& (b0->flags & VLIB_BUFFER_IS_TRACED)))
t = vlib_add_trace (vm, node, b0, sizeof (*t));
- add_to_flow_record_state (vm, node, fm, b0, timestamp, len0,
- flowprobe_get_variant
- (which, fm->context[which].flags,
- ethertype0), t);
+ add_to_flow_record_state (
+ vm, node, fm, b0, timestamp, len0,
+ flowprobe_get_variant (which, fm->context[which].flags,
+ ethertype0),
+ direction, t);
}
/* verify speculative enqueue, maybe switch current next frame */
@@ -847,24 +887,51 @@ flowprobe_node_fn (vlib_main_t * vm,
}
static uword
-flowprobe_ip4_node_fn (vlib_main_t * vm,
- vlib_node_runtime_t * node, vlib_frame_t * frame)
+flowprobe_input_ip4_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
+ vlib_frame_t *frame)
+{
+ return flowprobe_node_fn (vm, node, frame, FLOW_VARIANT_IP4,
+ FLOW_DIRECTION_RX);
+}
+
+static uword
+flowprobe_input_ip6_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
+ vlib_frame_t *frame)
+{
+ return flowprobe_node_fn (vm, node, frame, FLOW_VARIANT_IP6,
+ FLOW_DIRECTION_RX);
+}
+
+static uword
+flowprobe_input_l2_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
+ vlib_frame_t *frame)
+{
+ return flowprobe_node_fn (vm, node, frame, FLOW_VARIANT_L2,
+ FLOW_DIRECTION_RX);
+}
+
+static uword
+flowprobe_output_ip4_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
+ vlib_frame_t *frame)
{
- return flowprobe_node_fn (vm, node, frame, FLOW_VARIANT_IP4);
+ return flowprobe_node_fn (vm, node, frame, FLOW_VARIANT_IP4,
+ FLOW_DIRECTION_TX);
}
static uword
-flowprobe_ip6_node_fn (vlib_main_t * vm,
- vlib_node_runtime_t * node, vlib_frame_t * frame)
+flowprobe_output_ip6_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
+ vlib_frame_t *frame)
{
- return flowprobe_node_fn (vm, node, frame, FLOW_VARIANT_IP6);
+ return flowprobe_node_fn (vm, node, frame, FLOW_VARIANT_IP6,
+ FLOW_DIRECTION_TX);
}
static uword
-flowprobe_l2_node_fn (vlib_main_t * vm,
- vlib_node_runtime_t * node, vlib_frame_t * frame)
+flowprobe_output_l2_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
+ vlib_frame_t *frame)
{
- return flowprobe_node_fn (vm, node, frame, FLOW_VARIANT_L2);
+ return flowprobe_node_fn (vm, node, frame, FLOW_VARIANT_L2,
+ FLOW_DIRECTION_TX);
}
static inline void
@@ -879,25 +946,63 @@ flush_record (flowprobe_variant_t which)
void
flowprobe_flush_callback_ip4 (void)
{
+ vlib_main_t *worker_vm;
+ u32 i;
+
+ /* Flush for each worker thread */
+ for (i = 1; i < vlib_get_n_threads (); i++)
+ {
+ worker_vm = vlib_get_main_by_index (i);
+ if (worker_vm)
+ vlib_node_set_interrupt_pending (worker_vm,
+ flowprobe_flush_ip4_node.index);
+ }
+
+ /* Flush for the main thread */
flush_record (FLOW_VARIANT_IP4);
}
void
flowprobe_flush_callback_ip6 (void)
{
+ vlib_main_t *worker_vm;
+ u32 i;
+
+ /* Flush for each worker thread */
+ for (i = 1; i < vlib_get_n_threads (); i++)
+ {
+ worker_vm = vlib_get_main_by_index (i);
+ if (worker_vm)
+ vlib_node_set_interrupt_pending (worker_vm,
+ flowprobe_flush_ip6_node.index);
+ }
+
+ /* Flush for the main thread */
flush_record (FLOW_VARIANT_IP6);
}
void
flowprobe_flush_callback_l2 (void)
{
+ vlib_main_t *worker_vm;
+ u32 i;
+
+ /* Flush for each worker thread */
+ for (i = 1; i < vlib_get_n_threads (); i++)
+ {
+ worker_vm = vlib_get_main_by_index (i);
+ if (worker_vm)
+ vlib_node_set_interrupt_pending (worker_vm,
+ flowprobe_flush_l2_node.index);
+ }
+
+ /* Flush for the main thread */
flush_record (FLOW_VARIANT_L2);
flush_record (FLOW_VARIANT_L2_IP4);
flush_record (FLOW_VARIANT_L2_IP6);
}
-
-static void
+void
flowprobe_delete_by_index (u32 my_cpu_number, u32 poolindex)
{
flowprobe_main_t *fm = &flowprobe_main;
@@ -922,14 +1027,15 @@ flowprobe_walker_process (vlib_main_t * vm,
vlib_node_runtime_t * rt, vlib_frame_t * f)
{
flowprobe_main_t *fm = &flowprobe_main;
- flow_report_main_t *frm = &flow_report_main;
flowprobe_entry_t *e;
+ ipfix_exporter_t *exp = pool_elt_at_index (flow_report_main.exporters, 0);
/*
* $$$$ Remove this check from here and track FRM status and disable
* this process if required.
*/
- if (frm->ipfix_collector.as_u32 == 0 || frm->src_address.as_u32 == 0)
+ if (ip_address_is_zero (&exp->ipfix_collector) ||
+ ip_address_is_zero (&exp->src_address))
{
fm->disabled = true;
return 0;
@@ -996,36 +1102,94 @@ flowprobe_walker_process (vlib_main_t * vm,
return 0;
}
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (flowprobe_ip4_node) = {
- .function = flowprobe_ip4_node_fn,
- .name = "flowprobe-ip4",
+static uword
+flowprobe_flush_ip4 (vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
+{
+ flush_record (FLOW_VARIANT_IP4);
+
+ return 0;
+}
+
+static uword
+flowprobe_flush_ip6 (vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
+{
+ flush_record (FLOW_VARIANT_IP6);
+
+ return 0;
+}
+
+static uword
+flowprobe_flush_l2 (vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
+{
+ flush_record (FLOW_VARIANT_L2);
+ flush_record (FLOW_VARIANT_L2_IP4);
+ flush_record (FLOW_VARIANT_L2_IP6);
+
+ return 0;
+}
+
+VLIB_REGISTER_NODE (flowprobe_input_ip4_node) = {
+ .function = flowprobe_input_ip4_node_fn,
+ .name = "flowprobe-input-ip4",
+ .vector_size = sizeof (u32),
+ .format_trace = format_flowprobe_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .n_errors = ARRAY_LEN (flowprobe_error_strings),
+ .error_strings = flowprobe_error_strings,
+ .n_next_nodes = FLOWPROBE_N_NEXT,
+ .next_nodes = FLOWPROBE_NEXT_NODES,
+};
+VLIB_REGISTER_NODE (flowprobe_input_ip6_node) = {
+ .function = flowprobe_input_ip6_node_fn,
+ .name = "flowprobe-input-ip6",
.vector_size = sizeof (u32),
.format_trace = format_flowprobe_trace,
.type = VLIB_NODE_TYPE_INTERNAL,
- .n_errors = ARRAY_LEN(flowprobe_error_strings),
+ .n_errors = ARRAY_LEN (flowprobe_error_strings),
.error_strings = flowprobe_error_strings,
.n_next_nodes = FLOWPROBE_N_NEXT,
.next_nodes = FLOWPROBE_NEXT_NODES,
};
-VLIB_REGISTER_NODE (flowprobe_ip6_node) = {
- .function = flowprobe_ip6_node_fn,
- .name = "flowprobe-ip6",
+VLIB_REGISTER_NODE (flowprobe_input_l2_node) = {
+ .function = flowprobe_input_l2_node_fn,
+ .name = "flowprobe-input-l2",
.vector_size = sizeof (u32),
.format_trace = format_flowprobe_trace,
.type = VLIB_NODE_TYPE_INTERNAL,
- .n_errors = ARRAY_LEN(flowprobe_error_strings),
+ .n_errors = ARRAY_LEN (flowprobe_error_strings),
.error_strings = flowprobe_error_strings,
.n_next_nodes = FLOWPROBE_N_NEXT,
.next_nodes = FLOWPROBE_NEXT_NODES,
};
-VLIB_REGISTER_NODE (flowprobe_l2_node) = {
- .function = flowprobe_l2_node_fn,
- .name = "flowprobe-l2",
+VLIB_REGISTER_NODE (flowprobe_output_ip4_node) = {
+ .function = flowprobe_output_ip4_node_fn,
+ .name = "flowprobe-output-ip4",
.vector_size = sizeof (u32),
.format_trace = format_flowprobe_trace,
.type = VLIB_NODE_TYPE_INTERNAL,
- .n_errors = ARRAY_LEN(flowprobe_error_strings),
+ .n_errors = ARRAY_LEN (flowprobe_error_strings),
+ .error_strings = flowprobe_error_strings,
+ .n_next_nodes = FLOWPROBE_N_NEXT,
+ .next_nodes = FLOWPROBE_NEXT_NODES,
+};
+VLIB_REGISTER_NODE (flowprobe_output_ip6_node) = {
+ .function = flowprobe_output_ip6_node_fn,
+ .name = "flowprobe-output-ip6",
+ .vector_size = sizeof (u32),
+ .format_trace = format_flowprobe_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .n_errors = ARRAY_LEN (flowprobe_error_strings),
+ .error_strings = flowprobe_error_strings,
+ .n_next_nodes = FLOWPROBE_N_NEXT,
+ .next_nodes = FLOWPROBE_NEXT_NODES,
+};
+VLIB_REGISTER_NODE (flowprobe_output_l2_node) = {
+ .function = flowprobe_output_l2_node_fn,
+ .name = "flowprobe-output-l2",
+ .vector_size = sizeof (u32),
+ .format_trace = format_flowprobe_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .n_errors = ARRAY_LEN (flowprobe_error_strings),
.error_strings = flowprobe_error_strings,
.n_next_nodes = FLOWPROBE_N_NEXT,
.next_nodes = FLOWPROBE_NEXT_NODES,
@@ -1036,7 +1200,24 @@ VLIB_REGISTER_NODE (flowprobe_walker_node) = {
.type = VLIB_NODE_TYPE_INPUT,
.state = VLIB_NODE_STATE_INTERRUPT,
};
-/* *INDENT-ON* */
+VLIB_REGISTER_NODE (flowprobe_flush_ip4_node) = {
+ .function = flowprobe_flush_ip4,
+ .name = "flowprobe-flush-ip4",
+ .type = VLIB_NODE_TYPE_INPUT,
+ .state = VLIB_NODE_STATE_INTERRUPT,
+};
+VLIB_REGISTER_NODE (flowprobe_flush_ip6_node) = {
+ .function = flowprobe_flush_ip6,
+ .name = "flowprobe-flush-ip6",
+ .type = VLIB_NODE_TYPE_INPUT,
+ .state = VLIB_NODE_STATE_INTERRUPT,
+};
+VLIB_REGISTER_NODE (flowprobe_flush_l2_node) = {
+ .function = flowprobe_flush_l2,
+ .name = "flowprobe-flush-l2",
+ .type = VLIB_NODE_TYPE_INPUT,
+ .state = VLIB_NODE_STATE_INTERRUPT,
+};
/*
* fd.io coding-style-patch-verification: ON