From 1b563527c143903b6e7e79b5978af5310372f605 Mon Sep 17 00:00:00 2001 From: AkshayaNadahalli Date: Mon, 23 Jan 2017 22:05:35 +0530 Subject: In-band OAM active probe (VPP-471) Change-Id: Icf0ddf76ba1c8b588c79387284cd0349ebc6e45f Signed-off-by: AkshayaNadahalli --- src/plugins/ioam/udp-ping/udp_ping.api | 73 +++ src/plugins/ioam/udp-ping/udp_ping.h | 138 +++++ src/plugins/ioam/udp-ping/udp_ping_all_api_h.h | 24 + src/plugins/ioam/udp-ping/udp_ping_api.c | 190 ++++++ src/plugins/ioam/udp-ping/udp_ping_export.c | 304 ++++++++++ src/plugins/ioam/udp-ping/udp_ping_msg_enum.h | 37 ++ src/plugins/ioam/udp-ping/udp_ping_node.c | 803 +++++++++++++++++++++++++ src/plugins/ioam/udp-ping/udp_ping_packet.h | 154 +++++ src/plugins/ioam/udp-ping/udp_ping_test.c | 269 +++++++++ src/plugins/ioam/udp-ping/udp_ping_util.c | 330 ++++++++++ src/plugins/ioam/udp-ping/udp_ping_util.h | 83 +++ 11 files changed, 2405 insertions(+) create mode 100644 src/plugins/ioam/udp-ping/udp_ping.api create mode 100644 src/plugins/ioam/udp-ping/udp_ping.h create mode 100644 src/plugins/ioam/udp-ping/udp_ping_all_api_h.h create mode 100644 src/plugins/ioam/udp-ping/udp_ping_api.c create mode 100644 src/plugins/ioam/udp-ping/udp_ping_export.c create mode 100644 src/plugins/ioam/udp-ping/udp_ping_msg_enum.h create mode 100644 src/plugins/ioam/udp-ping/udp_ping_node.c create mode 100644 src/plugins/ioam/udp-ping/udp_ping_packet.h create mode 100644 src/plugins/ioam/udp-ping/udp_ping_test.c create mode 100644 src/plugins/ioam/udp-ping/udp_ping_util.c create mode 100644 src/plugins/ioam/udp-ping/udp_ping_util.h (limited to 'src/plugins/ioam/udp-ping') diff --git a/src/plugins/ioam/udp-ping/udp_ping.api b/src/plugins/ioam/udp-ping/udp_ping.api new file mode 100644 index 00000000000..87945816044 --- /dev/null +++ b/src/plugins/ioam/udp-ping/udp_ping.api @@ -0,0 +1,73 @@ +/* Hey Emacs use -*- mode: C -*- */ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/** \brief UDP-Probe Add/Delete request + @param src_ip_address - Source ipv4/v6 address for the udp-ping flow + @param dst_ip_address - Destination ipv4/v6 address for the udp-ping flow + @param start_src_port - Starting source port of port range for udp-ping + @param end_src_port - End source port of port range for udp-ping + @param start_dst_port - Starting destination port of port range for udp-ping + @param end_dst_port - End destination port of port range for udp-ping + @param interval - Time interval in seconds at which udp-probe need to be sent + @param is_ipv4 - To determine whether IPv4 or IPv6 address is used + @param dis - TRUE is delete, FALSE if Add +*/ +define udp_ping_add_del_req { + u32 client_index; + u32 context; + u8 src_ip_address[16]; + u8 dst_ip_address[16]; + u16 start_src_port; + u16 end_src_port; + u16 start_dst_port; + u16 end_dst_port; + u16 interval; + u8 is_ipv4; + u8 dis; + u8 fault_det; + u8 reserve[3]; +}; + +/** \brief Udp-probe add/del response + @param context - sender context, to match reply w/ request + @param retval - return value for request +*/ +define udp_ping_add_del_reply { + u32 context; + i32 retval; +}; + +/** \brief Udp-probe export add/del request + @param context - sender context, to match reply w/ request + @param retval - return value for request + @param enable - If TRUE then enable export else disable +*/ +define udp_ping_export_req { + u32 client_index; + u32 context; + u32 enable; +}; + +/** \brief Udp-probe export add/del response + @param context - sender context, to match reply w/ request + @param retval - return value for request +*/ +define udp_ping_export_reply { + u32 context; + i32 retval; +}; + diff --git a/src/plugins/ioam/udp-ping/udp_ping.h b/src/plugins/ioam/udp-ping/udp_ping.h new file mode 100644 index 00000000000..26c4201900e --- /dev/null +++ b/src/plugins/ioam/udp-ping/udp_ping.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PLUGINS_IOAM_PLUGIN_IOAM_UDP_PING_UDP_PING_H_ +#define PLUGINS_IOAM_PLUGIN_IOAM_UDP_PING_UDP_PING_H_ + +#include + +#define MAX_PING_RETRIES 5 + +#define EVENT_SIG_RECHECK 2 + +/** @brief udp-ping session data. + @note cache aligned. +*/ +typedef struct +{ + /** UDP ping packet */ + u8 *ping_rewrite; + + /** Ping packet rewrite string len. */ + u16 rewrite_len; + + /** Number of times ping response was dropped. + * If retry > MAX_PING_RETRIES then declare connectivity as down. + */ + u16 retry; + + u16 reserve[2]; + + /** Analysed data. */ + ioam_analyser_data_t analyse_data; + + /** This is used by ioam e2e for identifying flow and add seq number. */ + u32 flow_ctx; + + /** No of packets sent for this flow. */ + u32 pak_sent; +} udp_ping_flow_data; + +/** @brief udp-ping flow data. + @note cache aligned. +*/ +typedef struct +{ + /** Time at which next udp-ping probe has to be sent out. */ + f64 next_send_time; + + /** Interval for which ping packet to be sent. */ + u16 interval; + + u16 reserve[3]; + + /** Defines start port of the src port range. */ + u16 start_src_port; + + /** Defines end port of the src port range. */ + u16 end_src_port; + + /** Defines start port of the dest port range. */ + u16 start_dst_port; + + /** Defines end port of the dest port range. */ + u16 end_dst_port; + + /** Ping statistics. */ + udp_ping_flow_data *stats; + +} udp_ping_flow; + +/** @brief udp-ping data. +*/ +typedef struct +{ + /** Local source IPv4/6 address to be used. */ + ip46_address_t src; + + /** Remote destination IPv4/6 address to be used. */ + ip46_address_t dst; + + /** Per flow data. */ + udp_ping_flow udp_data; + + /** To enable fault detection/isolation in network. */ + u8 fault_det; +} ip46_udp_ping_flow; + +/** @brief udp-ping main data-structure. +*/ +typedef struct +{ + /** Vector od udp-ping data */ + ip46_udp_ping_flow *ip46_flow; + + /** Stores the time interval at which process node has to wake up. */ + u64 timer_interval; + + /** Pointer to VLib main for the node - ipfix-collector. */ + vlib_main_t *vlib_main; + + /** Pointer to vnet main for convenience. */ + vnet_main_t *vnet_main; + + /** API message ID base */ + u16 msg_id_base; +} udp_ping_main_t; + +extern udp_ping_main_t udp_ping_main; + +void +ip46_udp_ping_set_flow (ip46_address_t src, ip46_address_t dst, + u16 start_src_port, u16 end_src_port, + u16 start_dst_port, u16 end_dst_port, + u16 interval, u8 fault_det, u8 is_disable); + +clib_error_t *udp_ping_flow_create (u8 del); + +#endif /* PLUGINS_IOAM_PLUGIN_IOAM_UDP_PING_UDP_PING_H_ */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/udp-ping/udp_ping_all_api_h.h b/src/plugins/ioam/udp-ping/udp_ping_all_api_h.h new file mode 100644 index 00000000000..1ed2e10b72d --- /dev/null +++ b/src/plugins/ioam/udp-ping/udp_ping_all_api_h.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Include the generated file, see BUILT_SOURCES in Makefile.am */ +#include + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/udp-ping/udp_ping_api.c b/src/plugins/ioam/udp-ping/udp_ping_api.c new file mode 100644 index 00000000000..8cb8cc96224 --- /dev/null +++ b/src/plugins/ioam/udp-ping/udp_ping_api.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + *------------------------------------------------------------------ + * udp_ping_api.c - UDP Ping related APIs to create + * and maintain ping flows + *------------------------------------------------------------------ + */ + +#include +#include +#include + +#include +#include +#include + +/* define message IDs */ +#include + +/* define message structures */ +#define vl_typedefs +#include +#undef vl_typedefs + +/* define generated endian-swappers */ +#define vl_endianfun +#include +#undef vl_endianfun + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) +#define vl_printfun +#include +#undef vl_printfun + +/* Get the API version number */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#undef vl_api_version + +/* + * A handy macro to set up a message reply. + * Assumes that the following variables are available: + * mp - pointer to request message + * rmp - pointer to reply message type + * rv - return value + */ + +#define REPLY_MACRO(t) \ + do { \ + unix_shared_memory_queue_t * q = \ + vl_api_client_index_to_input_queue (mp->client_index); \ + if (!q) \ + return; \ + \ + rmp = vl_msg_api_alloc (sizeof (*rmp)); \ + rmp->_vl_msg_id = ntohs((t)+sm->msg_id_base); \ + rmp->context = mp->context; \ + rmp->retval = ntohl(rv); \ + \ + vl_msg_api_send_shmem (q, (u8 *)&rmp); \ + } while(0); + +#define REPLY_MACRO2(t, body) \ + do { \ + unix_shared_memory_queue_t * q; \ + rv = vl_msg_api_pd_handler (mp, rv); \ + q = vl_api_client_index_to_input_queue (mp->client_index); \ + if (!q) \ + return; \ + \ + rmp = vl_msg_api_alloc (sizeof (*rmp)); \ + rmp->_vl_msg_id = ntohs((t)); \ + rmp->context = mp->context; \ + rmp->retval = ntohl(rv); \ + do {body;} while (0); \ + vl_msg_api_send_shmem (q, (u8 *)&rmp); \ + } while(0); + +/* List of message types that this module understands */ + +#define foreach_udp_ping_api_msg \ + _(UDP_PING_ADD_DEL_REQ, udp_ping_add_del_req) \ + _(UDP_PING_EXPORT_REQ, udp_ping_export_req) \ + +static void vl_api_udp_ping_add_del_req_t_handler + (vl_api_udp_ping_add_del_req_t * mp) +{ + ip46_address_t dst, src; + int rv = 0; + udp_ping_main_t *sm = &udp_ping_main; + vl_api_udp_ping_add_del_reply_t *rmp; + + if (mp->is_ipv4) + { + rv = -1; //Not supported + goto ERROROUT; + } + + clib_memcpy ((void *) &src.ip6, (void *) mp->src_ip_address, + sizeof (ip6_address_t)); + clib_memcpy ((void *) &dst.ip6, (void *) mp->dst_ip_address, + sizeof (ip6_address_t)); + + ip46_udp_ping_set_flow (src, dst, + ntohs (mp->start_src_port), + ntohs (mp->end_src_port), + ntohs (mp->start_dst_port), + ntohs (mp->end_dst_port), + ntohs (mp->interval), mp->fault_det, mp->dis); + rv = 0; //FIXME + +ERROROUT: + REPLY_MACRO (VL_API_UDP_PING_ADD_DEL_REPLY); +} + +static void vl_api_udp_ping_export_req_t_handler + (vl_api_udp_ping_export_req_t * mp) +{ + udp_ping_main_t *sm = &udp_ping_main; + int rv = 0; + vl_api_udp_ping_export_reply_t *rmp; + + (void) udp_ping_flow_create (!mp->enable); + rv = 0; //FIXME + + REPLY_MACRO (VL_API_UDP_PING_EXPORT_REPLY); +} + +/* Set up the API message handling tables */ +static clib_error_t * +udp_ping_api_hookup (vlib_main_t * vm) +{ + udp_ping_main_t *sm = &udp_ping_main; +#define _(N,n) \ + vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base), \ + #n, \ + vl_api_##n##_t_handler, \ + vl_noop_handler, \ + vl_api_##n##_t_endian, \ + vl_api_##n##_t_print, \ + sizeof(vl_api_##n##_t), 1); + foreach_udp_ping_api_msg; +#undef _ + + return 0; +} + +static clib_error_t * +udp_ping_api_init (vlib_main_t * vm) +{ + udp_ping_main_t *sm = &udp_ping_main; + clib_error_t *error = 0; + u8 *name; + + name = format (0, "udp_ping_%08x%c", api_version, 0); + + /* Ask for a correctly-sized block of API message decode slots */ + sm->msg_id_base = vl_msg_api_get_msg_ids + ((char *) name, VL_MSG_FIRST_AVAILABLE); + + error = udp_ping_api_hookup (vm); + + vec_free (name); + + return error; +} + +VLIB_INIT_FUNCTION (udp_ping_api_init); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/udp-ping/udp_ping_export.c b/src/plugins/ioam/udp-ping/udp_ping_export.c new file mode 100644 index 00000000000..ce62d98f861 --- /dev/null +++ b/src/plugins/ioam/udp-ping/udp_ping_export.c @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#define UDP_PING_EXPORT_RECORD_SIZE 400 + +static u8 * +udp_ping_template_rewrite (flow_report_main_t * frm, flow_report_t * fr, + ip4_address_t * collector_address, + ip4_address_t * src_address, u16 collector_port) +{ + return ioam_template_rewrite (frm, fr, collector_address, + src_address, collector_port); +} + +static vlib_frame_t * +udp_ping_send_flows (flow_report_main_t * frm, flow_report_t * fr, + vlib_frame_t * f, u32 * to_next, u32 node_index) +{ + vlib_buffer_t *b0 = NULL; + u32 next_offset = 0; + u32 bi0 = ~0; + int i, j; + ip4_ipfix_template_packet_t *tp; + ipfix_message_header_t *h; + ipfix_set_header_t *s = NULL; + ip4_header_t *ip; + udp_header_t *udp; + u32 records_this_buffer; + u16 new_l0, old_l0; + ip_csum_t sum0; + vlib_main_t *vm = frm->vlib_main; + flow_report_stream_t *stream; + udp_ping_flow_data *stats; + ip46_udp_ping_flow *ip46_flow; + u16 src_port, dst_port; + u16 data_len; + + stream = &frm->streams[fr->stream_index]; + data_len = vec_len (udp_ping_main.ip46_flow); + + for (i = 0; i < data_len; i++) + { + if (pool_is_free_index (udp_ping_main.ip46_flow, i)) + continue; + + ip46_flow = pool_elt_at_index (udp_ping_main.ip46_flow, i); + j = 0; + for (src_port = ip46_flow->udp_data.start_src_port; + src_port <= ip46_flow->udp_data.end_src_port; src_port++) + { + for (dst_port = ip46_flow->udp_data.start_dst_port; + dst_port <= ip46_flow->udp_data.end_dst_port; dst_port++, j++) + { + stats = ip46_flow->udp_data.stats + j; + if (PREDICT_FALSE (b0 == NULL)) + { + if (vlib_buffer_alloc (vm, &bi0, 1) != 1) + break; + + + b0 = vlib_get_buffer (vm, bi0); + memcpy (b0->data, fr->rewrite, vec_len (fr->rewrite)); + b0->current_data = 0; + b0->current_length = vec_len (fr->rewrite); + b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID; + vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0; + + tp = vlib_buffer_get_current (b0); + ip = &tp->ip4; + udp = &tp->udp; + h = &tp->ipfix.h; + s = &tp->ipfix.s; + + /* FIXUP: message header export_time */ + h->export_time = clib_host_to_net_u32 (((u32) time (NULL))); + + /* FIXUP: message header sequence_number */ + h->sequence_number = stream->sequence_number++; + h->sequence_number = + clib_host_to_net_u32 (h->sequence_number); + next_offset = (u32) (((u8 *) (s + 1)) - (u8 *) tp); + records_this_buffer = 0; + } + + next_offset = ioam_analyse_add_ipfix_record (fr, + &stats->analyse_data, + b0, next_offset, + &ip46_flow-> + src.ip6, + &ip46_flow-> + dst.ip6, src_port, + dst_port); + + //u32 pak_sent = clib_host_to_net_u32(stats->pak_sent); + //memcpy (b0->data + next_offset, &pak_sent, sizeof(u32)); + //next_offset += sizeof(u32); + + records_this_buffer++; + + /* Flush data if packet len is about to reach path mtu */ + if (next_offset > (frm->path_mtu - UDP_PING_EXPORT_RECORD_SIZE)) + { + b0->current_length = next_offset; + b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID; + tp = vlib_buffer_get_current (b0); + ip = (ip4_header_t *) & tp->ip4; + udp = (udp_header_t *) (ip + 1); + h = &tp->ipfix.h; + s = &tp->ipfix.s; + + s->set_id_length = + ipfix_set_id_length (IOAM_FLOW_TEMPLATE_ID, + next_offset - (sizeof (*ip) + + sizeof (*udp) + + sizeof (*h))); + h->version_length = + version_length (next_offset - + (sizeof (*ip) + sizeof (*udp))); + + sum0 = ip->checksum; + old_l0 = ip->length; + new_l0 = clib_host_to_net_u16 ((u16) next_offset); + sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t, + length /* changed member */ ); + + ip->checksum = ip_csum_fold (sum0); + ip->length = new_l0; + udp->length = + clib_host_to_net_u16 (b0->current_length - sizeof (*ip)); + + udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip); + if (udp->checksum == 0) + udp->checksum = 0xffff; + + ASSERT (ip->checksum == ip4_header_checksum (ip)); + + to_next[0] = bi0; + f->n_vectors++; + to_next++; + + if (f->n_vectors == VLIB_FRAME_SIZE) + { + vlib_put_frame_to_node (vm, node_index, f); + f = vlib_get_frame_to_node (vm, node_index); + f->n_vectors = 0; + to_next = vlib_frame_vector_args (f); + } + b0 = 0; + bi0 = ~0; + } + } + } + } + + if (b0) + { + b0->current_length = next_offset; + b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID; + tp = vlib_buffer_get_current (b0); + ip = (ip4_header_t *) & tp->ip4; + udp = (udp_header_t *) (ip + 1); + h = &tp->ipfix.h; + s = &tp->ipfix.s; + + s->set_id_length = ipfix_set_id_length (IOAM_FLOW_TEMPLATE_ID, + next_offset - (sizeof (*ip) + + sizeof (*udp) + + sizeof (*h))); + h->version_length = + version_length (next_offset - (sizeof (*ip) + sizeof (*udp))); + + sum0 = ip->checksum; + old_l0 = ip->length; + new_l0 = clib_host_to_net_u16 ((u16) next_offset); + sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t, + length /* changed member */ ); + + ip->checksum = ip_csum_fold (sum0); + ip->length = new_l0; + udp->length = clib_host_to_net_u16 (b0->current_length - sizeof (*ip)); + + udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip); + if (udp->checksum == 0) + udp->checksum = 0xffff; + + ASSERT (ip->checksum == ip4_header_checksum (ip)); + + to_next[0] = bi0; + f->n_vectors++; + to_next++; + + if (f->n_vectors == VLIB_FRAME_SIZE) + { + vlib_put_frame_to_node (vm, node_index, f); + f = vlib_get_frame_to_node (vm, node_index); + f->n_vectors = 0; + to_next = vlib_frame_vector_args (f); + } + b0 = 0; + bi0 = ~0; + } + return f; +} + +clib_error_t * +udp_ping_flow_create (u8 del) +{ + vnet_flow_report_add_del_args_t args; + int rv; + u32 domain_id = 0; + flow_report_main_t *frm = &flow_report_main; + + args.rewrite_callback = udp_ping_template_rewrite; + args.flow_data_callback = udp_ping_send_flows; + del ? (args.is_add = 0) : (args.is_add = 1); + args.domain_id = domain_id; + + rv = vnet_flow_report_add_del (frm, &args); + + switch (rv) + { + case 0: + break; + case VNET_API_ERROR_NO_SUCH_ENTRY: + return clib_error_return (0, "registration not found..."); + default: + return clib_error_return (0, "vnet_flow_report_add_del returned %d", + rv); + } + + return 0; +} + +static clib_error_t * +set_udp_ping_export_command_fn (vlib_main_t * vm, unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + //int rv; + int is_add = 1; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "export-ipfix")) + is_add = 1; + else if (unformat (input, "disable")) + is_add = 0; + else + break; + } + + if (is_add) + (void) udp_ping_flow_create (0); + else + (void) udp_ping_flow_create (1); + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (set_udp_ping_export_command, static) = { + .path = "set udp-ping export-ipfix", + .short_help = "set udp-ping export-ipfix [disable]", + .function = set_udp_ping_export_command_fn, +}; +/* *INDENT-ON* */ + +clib_error_t * +udp_ping_flow_report_init (vlib_main_t * vm) +{ + clib_error_t *error; + + if ((error = vlib_call_init_function (vm, flow_report_init))) + return error; + + return 0; +} + +VLIB_INIT_FUNCTION (udp_ping_flow_report_init); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/udp-ping/udp_ping_msg_enum.h b/src/plugins/ioam/udp-ping/udp_ping_msg_enum.h new file mode 100644 index 00000000000..dded18842d2 --- /dev/null +++ b/src/plugins/ioam/udp-ping/udp_ping_msg_enum.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef included_udp_ping_msg_enum_h +#define included_udp_ping_msg_enum_h + +#include + +#define vl_msg_id(n,h) n, +typedef enum +{ +#include + /* We'll want to know how many messages IDs we need... */ + VL_MSG_FIRST_AVAILABLE, +} vl_msg_id_t; +#undef vl_msg_id + +#endif /* included_udp_ping_msg_enum_h */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ioam/udp-ping/udp_ping_node.c b/src/plugins/ioam/udp-ping/udp_ping_node.c new file mode 100644 index 00000000000..4de8fe2f894 --- /dev/null +++ b/src/plugins/ioam/udp-ping/udp_ping_node.c @@ -0,0 +1,803 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef enum +{ + UDP_PING_NEXT_DROP, + UDP_PING_NEXT_PUNT, + UDP_PING_NEXT_UDP_LOOKUP, + UDP_PING_NEXT_ICMP, + UDP_PING_NEXT_IP6_LOOKUP, + UDP_PING_NEXT_IP6_DROP, + UDP_PING_N_NEXT, +} udp_ping_next_t; + +udp_ping_main_t udp_ping_main; + +uword +udp_ping_process (vlib_main_t * vm, + vlib_node_runtime_t * rt, vlib_frame_t * f); + +extern int +ip6_hbh_ioam_trace_data_list_handler (vlib_buffer_t * b, ip6_header_t * ip, + ip6_hop_by_hop_option_t * opt); + +typedef struct +{ + ip6_address_t src; + ip6_address_t dst; + u16 src_port; + u16 dst_port; + u16 handle; + u16 next_index; + u8 msg_type; +} udp_ping_trace_t; + +/* packet trace format function */ +static u8 * +format_udp_ping_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + udp_ping_trace_t *t = va_arg (*args, udp_ping_trace_t *); + + s = format (s, "udp-ping-local: src %U, dst %U, src_port %u, dst_port %u " + "handle %u, next_index %u, msg_type %u", + format_ip6_address, &t->src, + format_ip6_address, &t->dst, + t->src_port, t->dst_port, + t->handle, t->next_index, t->msg_type); + return s; +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (udp_ping_node, static) = +{ + .function = udp_ping_process, + .type = VLIB_NODE_TYPE_PROCESS, + .name = "udp-ping-process", +}; +/* *INDENT-ON* */ + +void +udp_ping_calculate_timer_interval (void) +{ + int i; + ip46_udp_ping_flow *flow = NULL; + u16 min_interval = 0x1e9; + + for (i = 0; i < vec_len (udp_ping_main.ip46_flow); i++) + { + if (pool_is_free_index (udp_ping_main.ip46_flow, i)) + continue; + + flow = pool_elt_at_index (udp_ping_main.ip46_flow, i); + + if (min_interval > flow->udp_data.interval) + min_interval = flow->udp_data.interval; + } + + if (udp_ping_main.timer_interval != min_interval) + { + udp_ping_main.timer_interval = min_interval; + vlib_process_signal_event (udp_ping_main.vlib_main, + udp_ping_node.index, EVENT_SIG_RECHECK, 0); + } +} + +void +ip46_udp_ping_set_flow (ip46_address_t src, ip46_address_t dst, + u16 start_src_port, u16 end_src_port, + u16 start_dst_port, u16 end_dst_port, + u16 interval, u8 fault_det, u8 is_disable) +{ + u8 found = 0; + ip46_udp_ping_flow *flow = NULL; + int i; + + for (i = 0; i < vec_len (udp_ping_main.ip46_flow); i++) + { + if (pool_is_free_index (udp_ping_main.ip46_flow, i)) + continue; + + flow = pool_elt_at_index (udp_ping_main.ip46_flow, i); + if ((0 == udp_ping_compare_flow (src, dst, + start_src_port, end_src_port, + start_dst_port, end_dst_port, flow))) + { + found = 1; + break; + } + } + + if (found) + { + u16 cur_interval; + if (is_disable) + { + cur_interval = flow->udp_data.interval; + udp_ping_free_flow_data (flow); + pool_put_index (udp_ping_main.ip46_flow, i); + if (udp_ping_main.timer_interval == interval) + udp_ping_calculate_timer_interval (); + return; + } + + cur_interval = flow->udp_data.interval; + flow->udp_data.interval = interval; + if (udp_ping_main.timer_interval > interval) + { + udp_ping_main.timer_interval = interval; + vlib_process_signal_event (udp_ping_main.vlib_main, + udp_ping_node.index, + EVENT_SIG_RECHECK, 0); + } + else if (udp_ping_main.timer_interval == cur_interval) + udp_ping_calculate_timer_interval (); + + return; + } + + /* Delete operation and item not found */ + if (is_disable) + return; + + /* Alloc new session */ + pool_get_aligned (udp_ping_main.ip46_flow, flow, CLIB_CACHE_LINE_BYTES); + udp_ping_populate_flow (src, dst, + start_src_port, end_src_port, + start_dst_port, end_dst_port, + interval, fault_det, flow); + + udp_ping_create_rewrite (flow, (flow - udp_ping_main.ip46_flow)); + + if (udp_ping_main.timer_interval > interval) + { + udp_ping_main.timer_interval = interval; + vlib_process_signal_event (udp_ping_main.vlib_main, + udp_ping_node.index, EVENT_SIG_RECHECK, 0); + } + return; +} + +uword +unformat_port_range (unformat_input_t * input, va_list * args) +{ + u16 *start_port, *end_port; + uword c; + u8 colon_present = 0; + + start_port = va_arg (*args, u16 *); + end_port = va_arg (*args, u16 *); + + *start_port = *end_port = 0; + /* Get start port */ + while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT) + { + switch (c) + { + case '0' ... '9': + *start_port = ((*start_port) * 10) + (c - '0'); + break; + + case ':': + colon_present = 1; + break; + + default: + return 0; + } + + if (colon_present) + break; + } + + if (!colon_present) + return 0; + + /* Get end port */ + while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT) + { + switch (c) + { + case '0' ... '9': + *end_port = ((*end_port) * 10) + (c - '0'); + break; + + default: + return 1; + } + } + + if (end_port < start_port) + return 0; + + return 1; +} + +static clib_error_t * +set_udp_ping_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + ip46_address_t dst, src; + u16 start_src_port, end_src_port; + u16 start_dst_port, end_dst_port; + u32 interval; + u8 is_disable = 0; + u8 fault_det = 0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat + (input, "src %U", unformat_ip46_address, &src, IP46_TYPE_ANY)) + ; + else if (unformat (input, "src-port-range %U", + unformat_port_range, &start_src_port, &end_src_port)) + ; + else + if (unformat + (input, "dst %U", unformat_ip46_address, &dst, IP46_TYPE_ANY)) + ; + else if (unformat (input, "dst-port-range %U", + unformat_port_range, &start_dst_port, &end_dst_port)) + ; + else if (unformat (input, "interval %d", &interval)) + ; + else if (unformat (input, "fault-detect")) + fault_det = 1; + else if (unformat (input, "disable")) + is_disable = 1; + else + break; + } + + ip46_udp_ping_set_flow (src, dst, start_src_port, end_src_port, + start_dst_port, end_dst_port, (u16) interval, + fault_det, is_disable); + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (set_udp_ping_command, static) = +{ + .path = "set udp-ping", + .short_help = + "set udp-ping src src-port-range \ + dst dst-port-range \ + interval