From 504b83009a00d70c777c04014967494642074d52 Mon Sep 17 00:00:00 2001 From: Dave Barach Date: Tue, 20 Dec 2016 17:59:27 -0500 Subject: Add L2 flow-record generation Change-Id: I32a9513f2b66d35e0abe2aeb6eb86a4729ba7f74 Signed-off-by: Dave Barach --- plugins/flowperpkt-plugin/flowperpkt/flowperpkt.c | 299 ++++++++++++++++------ 1 file changed, 226 insertions(+), 73 deletions(-) (limited to 'plugins/flowperpkt-plugin/flowperpkt/flowperpkt.c') diff --git a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt.c b/plugins/flowperpkt-plugin/flowperpkt/flowperpkt.c index 96c930ae599..fb71d5b0ffc 100644 --- a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt.c +++ b/plugins/flowperpkt-plugin/flowperpkt/flowperpkt.c @@ -57,13 +57,21 @@ flowperpkt_main_t flowperpkt_main; #include #undef vl_api_version -/* Define the per-interface configurable feature */ +/* Define the per-interface configurable features */ /* *INDENT-OFF* */ -VNET_FEATURE_INIT (flow_perpacket, static) = { +VNET_FEATURE_INIT (flow_perpacket_ipv4, static) = +{ .arc_name = "ip4-output", - .node_name = "flowperpkt", + .node_name = "flowperpkt-ipv4", .runs_before = VNET_FEATURES ("interface-output"), }; + +VNET_FEATURE_INIT (flow_perpacket_l2, static) = +{ + .arc_name = "interface-output", + .node_name = "flowperpkt-l2", + .runs_before = VNET_FEATURES ("interface-tx"), +}; /* *INDENT-ON* */ /* @@ -120,11 +128,12 @@ bad_sw_if_index: \ * @param collector_port u16 the collector port we should use, host byte order * @returns u8 * vector containing the indicated IPFIX template packet */ -u8 * -flowperpkt_template_rewrite (flow_report_main_t * frm, - flow_report_t * fr, - ip4_address_t * collector_address, - ip4_address_t * src_address, u16 collector_port) +static inline u8 * +flowperpkt_template_rewrite_inline (flow_report_main_t * frm, + flow_report_t * fr, + ip4_address_t * collector_address, + ip4_address_t * src_address, + u16 collector_port, int variant) { ip4_header_t *ip; udp_header_t *udp; @@ -137,32 +146,64 @@ flowperpkt_template_rewrite (flow_report_main_t * frm, ip4_ipfix_template_packet_t *tp; u32 field_count = 0; flow_report_stream_t *stream; + flowperpkt_main_t *fm = &flowperpkt_main; stream = &frm->streams[fr->stream_index]; - /* - * Supported Fields: - * - * ingressInterface, TLV type 10, u32 - * egressInterface, TLV type 14, u32 - * sourceIpv4Address, TLV type 8, u32 - * destinationIPv4Address, TLV type 12, u32 - * ipClassOfService, TLV type 5, u8 - * flowStartNanoseconds, TLV type 156, dateTimeNanoseconds (f64) - * Implementation: f64 nanoseconds since VPP started - * warning: wireshark doesn't really understand this TLV - * dataLinkFrameSize, TLV type 312, u16 - * warning: wireshark doesn't understand this TLV at all - */ - - /* Currently 7 fields */ - field_count += 7; - - /* allocate rewrite space */ - vec_validate_aligned (rewrite, - sizeof (ip4_ipfix_template_packet_t) - + field_count * sizeof (ipfix_field_specifier_t) - 1, - CLIB_CACHE_LINE_BYTES); + if (variant == FLOW_VARIANT_IPV4) + { + /* + * ip4 Supported Fields: + * + * ingressInterface, TLV type 10, u32 + * egressInterface, TLV type 14, u32 + * sourceIpv4Address, TLV type 8, u32 + * destinationIPv4Address, TLV type 12, u32 + * ipClassOfService, TLV type 5, u8 + * flowStartNanoseconds, TLV type 156, dateTimeNanoseconds (f64) + * Implementation: f64 nanoseconds since VPP started + * warning: wireshark doesn't really understand this TLV + * dataLinkFrameSize, TLV type 312, u16 + * warning: wireshark doesn't understand this TLV at all + */ + + /* Currently 7 fields */ + field_count += 7; + + /* allocate rewrite space */ + vec_validate_aligned + (rewrite, + sizeof (ip4_ipfix_template_packet_t) + + field_count * sizeof (ipfix_field_specifier_t) - 1, + CLIB_CACHE_LINE_BYTES); + } + else if (variant == FLOW_VARIANT_L2) + { + /* + * L2 Supported Fields: + * + * ingressInterface, TLV type 10, u32 + * egressInterface, TLV type 14, u32 + * sourceMacAddress, TLV type 56, u8[6] we hope + * destinationMacAddress, TLV type 57, u8[6] we hope + * ethernetType, TLV type 256, u16 + * flowStartNanoseconds, TLV type 156, dateTimeNanoseconds (f64) + * Implementation: f64 nanoseconds since VPP started + * warning: wireshark doesn't really understand this TLV + * dataLinkFrameSize, TLV type 312, u16 + * warning: wireshark doesn't understand this TLV at all + */ + + /* Currently 7 fields */ + field_count += 7; + + /* allocate rewrite space */ + vec_validate_aligned + (rewrite, + sizeof (ip4_ipfix_template_packet_t) + + field_count * sizeof (ipfix_field_specifier_t) - 1, + CLIB_CACHE_LINE_BYTES); + } tp = (ip4_ipfix_template_packet_t *) rewrite; ip = (ip4_header_t *) & tp->ip4; @@ -186,28 +227,66 @@ flowperpkt_template_rewrite (flow_report_main_t * frm, h->domain_id = clib_host_to_net_u32 (stream->domain_id); /* Add TLVs to the template */ - f->e_id_length = ipfix_e_id_length (0 /* enterprise */ , ingressInterface, - 4); - f++; - f->e_id_length = ipfix_e_id_length (0 /* enterprise */ , egressInterface, - 4); - f++; - f->e_id_length = ipfix_e_id_length (0 /* enterprise */ , sourceIPv4Address, - 4); - f++; - f->e_id_length = ipfix_e_id_length (0 /* enterprise */ , - destinationIPv4Address, 4); - f++; - f->e_id_length = ipfix_e_id_length (0 /* enterprise */ , ipClassOfService, - 1); - f++; - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , flowStartNanoseconds, - 8); - f++; - f->e_id_length = ipfix_e_id_length (0 /* enterprise */ , dataLinkFrameSize, - 2); - f++; + if (variant == FLOW_VARIANT_IPV4) + { + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , ingressInterface, + 4); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , egressInterface, + 4); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , sourceIPv4Address, + 4); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , destinationIPv4Address, 4); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , ipClassOfService, + 1); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , flowStartNanoseconds, + 8); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , dataLinkFrameSize, + 2); + f++; + } + else if (variant == FLOW_VARIANT_L2) + { + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , ingressInterface, + 4); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , egressInterface, + 4); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , sourceMacAddress, + 6); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , destinationMacAddress, 6); + f++; + f->e_id_length = ipfix_e_id_length (0 /* enterprise */ , ethernetType, + 2); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , flowStartNanoseconds, + 8); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , dataLinkFrameSize, + 2); + f++; + } + /* Extend in the obvious way, right here... */ /* Back to the template packet... */ @@ -218,6 +297,11 @@ flowperpkt_template_rewrite (flow_report_main_t * frm, /* Field count in this template */ t->id_count = ipfix_id_count (fr->template_id, f - first_field); + if (variant == FLOW_VARIANT_IPV4) + fm->ipv4_report_id = fr->template_id; + else if (variant == FLOW_VARIANT_L2) + fm->l2_report_id = fr->template_id; + /* set length in octets */ s->set_id_length = ipfix_set_id_length (2 /* set_id */ , (u8 *) f - (u8 *) s); @@ -231,6 +315,31 @@ flowperpkt_template_rewrite (flow_report_main_t * frm, return rewrite; } +u8 * +flowperpkt_template_rewrite_ipv4 (flow_report_main_t * frm, + flow_report_t * fr, + ip4_address_t * collector_address, + ip4_address_t * src_address, + u16 collector_port) +{ + return flowperpkt_template_rewrite_inline + (frm, fr, collector_address, src_address, collector_port, + FLOW_VARIANT_IPV4); +} + +u8 * +flowperpkt_template_rewrite_l2 (flow_report_main_t * frm, + flow_report_t * fr, + ip4_address_t * collector_address, + ip4_address_t * src_address, + u16 collector_port) +{ + return flowperpkt_template_rewrite_inline + (frm, fr, collector_address, src_address, collector_port, + FLOW_VARIANT_L2); +} + + /** * @brief Flush accumulated data * @param frm flow_report_main_t * @@ -242,11 +351,21 @@ flowperpkt_template_rewrite (flow_report_main_t * frm, * will be sent. */ vlib_frame_t * -flowperpkt_data_callback (flow_report_main_t * frm, - flow_report_t * fr, - vlib_frame_t * f, u32 * to_next, u32 node_index) +flowperpkt_data_callback_ipv4 (flow_report_main_t * frm, + flow_report_t * fr, + vlib_frame_t * f, u32 * to_next, + u32 node_index) +{ + flowperpkt_flush_callback_ipv4 (); + return f; +} + +vlib_frame_t * +flowperpkt_data_callback_l2 (flow_report_main_t * frm, + flow_report_t * fr, + vlib_frame_t * f, u32 * to_next, u32 node_index) { - flowperpkt_flush_callback (); + flowperpkt_flush_callback_l2 (); return f; } @@ -259,21 +378,21 @@ flowperpkt_data_callback (flow_report_main_t * frm, */ static int flowperpkt_tx_interface_add_del_feature - (flowperpkt_main_t * fm, u32 sw_if_index, int is_add) + (flowperpkt_main_t * fm, u32 sw_if_index, int which, int is_add) { flow_report_main_t *frm = &flow_report_main; vnet_flow_report_add_del_args_t _a, *a = &_a; int rv; - if (!fm->report_created) + if (which == FLOW_VARIANT_IPV4 && !fm->ipv4_report_created) { memset (a, 0, sizeof (*a)); - a->rewrite_callback = flowperpkt_template_rewrite; - a->flow_data_callback = flowperpkt_data_callback; + a->rewrite_callback = flowperpkt_template_rewrite_ipv4; + a->flow_data_callback = flowperpkt_data_callback_ipv4; a->is_add = 1; a->domain_id = 1; /*$$$$ config parameter */ a->src_port = 4739; /*$$$$ config parameter */ - fm->report_created = 1; + fm->ipv4_report_created = 1; rv = vnet_flow_report_add_del (frm, a); if (rv) @@ -282,9 +401,30 @@ static int flowperpkt_tx_interface_add_del_feature return -1; } } + else if (which == FLOW_VARIANT_L2 && !fm->l2_report_created) + { + memset (a, 0, sizeof (*a)); + a->rewrite_callback = flowperpkt_template_rewrite_l2; + a->flow_data_callback = flowperpkt_data_callback_l2; + a->is_add = 1; + a->domain_id = 1; /*$$$$ config parameter */ + a->src_port = 4739; /*$$$$ config parameter */ + fm->l2_report_created = 1; - vnet_feature_enable_disable ("ip4-output", "flowperpkt", sw_if_index, - is_add, 0, 0); + rv = vnet_flow_report_add_del (frm, a); + if (rv) + { + clib_warning ("vnet_flow_report_add_del returned %d", rv); + return -1; + } + } + + if (which == FLOW_VARIANT_IPV4) + vnet_feature_enable_disable ("ip4-output", "flowperpkt-ipv4", + sw_if_index, is_add, 0, 0); + else if (which == FLOW_VARIANT_L2) + vnet_feature_enable_disable ("interface-output", "flowperpkt-l2", + sw_if_index, is_add, 0, 0); return 0; } @@ -303,8 +443,15 @@ void vl_api_flowperpkt_tx_interface_add_del_t_handler VALIDATE_SW_IF_INDEX (mp); - rv = flowperpkt_tx_interface_add_del_feature (fm, sw_if_index, mp->is_add); + if (mp->which != FLOW_VARIANT_IPV4 && mp->which != FLOW_VARIANT_L2) + { + rv = VNET_API_ERROR_UNIMPLEMENTED; + goto out; + } + rv = flowperpkt_tx_interface_add_del_feature (fm, sw_if_index, mp->which, + mp->is_add); +out: BAD_SW_IF_INDEX_LABEL; REPLY_MACRO (VL_API_FLOWPERPKT_TX_INTERFACE_ADD_DEL_REPLY); @@ -322,9 +469,9 @@ static void *vl_api_flowperpkt_tx_interface_add_del_t_print u8 *s; s = format (0, "SCRIPT: flowperpkt_tx_interface_add_del "); - s = format (s, "sw_if_index %d is_add %d is_ipv6 %d ", + s = format (s, "sw_if_index %d is_add %d which %d ", clib_host_to_net_u32 (mp->sw_if_index), - (int) mp->is_add, (int) mp->is_ipv6); + (int) mp->is_add, (int) mp->which); FINISH; } @@ -365,6 +512,7 @@ flowperpkt_tx_interface_add_del_feature_command_fn (vlib_main_t * vm, flowperpkt_main_t *fm = &flowperpkt_main; u32 sw_if_index = ~0; int is_add = 1; + u8 which = FLOW_VARIANT_IPV4; int rv; @@ -373,8 +521,9 @@ flowperpkt_tx_interface_add_del_feature_command_fn (vlib_main_t * vm, if (unformat (input, "disable")) is_add = 0; else if (unformat (input, "%U", unformat_vnet_sw_interface, - fm->vnet_main, &sw_if_index)) - ; + fm->vnet_main, &sw_if_index)); + else if (unformat (input, "l2")) + which = FLOW_VARIANT_L2; else break; } @@ -382,7 +531,8 @@ flowperpkt_tx_interface_add_del_feature_command_fn (vlib_main_t * vm, if (sw_if_index == ~0) return clib_error_return (0, "Please specify an interface..."); - rv = flowperpkt_tx_interface_add_del_feature (fm, sw_if_index, is_add); + rv = + flowperpkt_tx_interface_add_del_feature (fm, sw_if_index, which, is_add); switch (rv) { case 0: @@ -496,9 +646,12 @@ flowperpkt_init (vlib_main_t * vm) num_threads = 1 /* main thread */ + tm->n_eal_threads; /* Allocate per worker thread vectors */ - vec_validate (fm->buffers_per_worker, num_threads - 1); - vec_validate (fm->frames_per_worker, num_threads - 1); - vec_validate (fm->next_record_offset_per_worker, num_threads - 1); + vec_validate (fm->ipv4_buffers_per_worker, num_threads - 1); + vec_validate (fm->l2_buffers_per_worker, num_threads - 1); + vec_validate (fm->ipv4_frames_per_worker, num_threads - 1); + vec_validate (fm->l2_frames_per_worker, num_threads - 1); + vec_validate (fm->ipv4_next_record_offset_per_worker, num_threads - 1); + vec_validate (fm->l2_next_record_offset_per_worker, num_threads - 1); /* Set up time reference pair */ fm->vlib_time_0 = vlib_time_now (vm); -- cgit 1.2.3-korg