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_node.c | 803 ++++++++++++++++++++++++++++++ 1 file changed, 803 insertions(+) create mode 100644 src/plugins/ioam/udp-ping/udp_ping_node.c (limited to 'src/plugins/ioam/udp-ping/udp_ping_node.c') 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