diff options
Diffstat (limited to 'src/plugins/ping/ping.c')
-rw-r--r-- | src/plugins/ping/ping.c | 281 |
1 files changed, 203 insertions, 78 deletions
diff --git a/src/plugins/ping/ping.c b/src/plugins/ping/ping.c index 5973b484045..40e4495aaf2 100644 --- a/src/plugins/ping/ping.c +++ b/src/plugins/ping/ping.c @@ -99,70 +99,6 @@ format_ip46_ping_result (u8 * s, va_list * args) * */ - -static_always_inline uword -get_cli_process_id_by_icmp_id_mt (vlib_main_t * vm, u16 icmp_id) -{ - ping_main_t *pm = &ping_main; - uword cli_process_id = PING_CLI_UNKNOWN_NODE; - ping_run_t *pr; - - clib_spinlock_lock_if_init (&pm->ping_run_check_lock); - vec_foreach (pr, pm->active_ping_runs) - { - if (pr->icmp_id == icmp_id) - { - cli_process_id = pr->cli_process_id; - break; - } - } - clib_spinlock_unlock_if_init (&pm->ping_run_check_lock); - return cli_process_id; -} - - -static_always_inline void -set_cli_process_id_by_icmp_id_mt (vlib_main_t * vm, u16 icmp_id, - uword cli_process_id) -{ - ping_main_t *pm = &ping_main; - ping_run_t *pr; - - clib_spinlock_lock_if_init (&pm->ping_run_check_lock); - vec_foreach (pr, pm->active_ping_runs) - { - if (pr->icmp_id == icmp_id) - { - pr->cli_process_id = cli_process_id; - goto have_found_and_set; - } - } - /* no such key yet - add a new one */ - ping_run_t new_pr = {.icmp_id = icmp_id,.cli_process_id = cli_process_id }; - vec_add1 (pm->active_ping_runs, new_pr); -have_found_and_set: - clib_spinlock_unlock_if_init (&pm->ping_run_check_lock); -} - - -static_always_inline void -clear_cli_process_id_by_icmp_id_mt (vlib_main_t * vm, u16 icmp_id) -{ - ping_main_t *pm = &ping_main; - ping_run_t *pr; - - clib_spinlock_lock_if_init (&pm->ping_run_check_lock); - vec_foreach (pr, pm->active_ping_runs) - { - if (pr->icmp_id == icmp_id) - { - vec_del1 (pm->active_ping_runs, pm->active_ping_runs - pr); - break; - } - } - clib_spinlock_unlock_if_init (&pm->ping_run_check_lock); -} - static_always_inline int ip46_get_icmp_id_and_seq (vlib_main_t * vm, vlib_buffer_t * b0, u16 * out_icmp_id, u16 * out_icmp_seq, int is_ip6) @@ -339,7 +275,6 @@ ip6_icmp_echo_reply_node_fn (vlib_main_t * vm, 1 /* is_ip6 */ ); } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (ip6_icmp_echo_reply_node, static) = { .function = ip6_icmp_echo_reply_node_fn, @@ -365,7 +300,6 @@ VLIB_REGISTER_NODE (ip4_icmp_echo_reply_node, static) = [ICMP46_ECHO_REPLY_NEXT_PUNT] = "ip4-punt", }, }; -/* *INDENT-ON* */ static uword ip4_icmp_echo_request (vlib_main_t * vm, @@ -560,7 +494,6 @@ format_icmp_input_trace (u8 * s, va_list * va) return s; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (ip4_icmp_echo_request_node,static) = { .function = ip4_icmp_echo_request, .name = "ip4-icmp-echo-request", @@ -574,7 +507,200 @@ VLIB_REGISTER_NODE (ip4_icmp_echo_request_node,static) = { [0] = "ip4-load-balance", }, }; -/* *INDENT-ON* */ + +typedef enum +{ + ICMP6_ECHO_REQUEST_NEXT_LOOKUP, + ICMP6_ECHO_REQUEST_NEXT_OUTPUT, + ICMP6_ECHO_REQUEST_N_NEXT, +} icmp6_echo_request_next_t; + +static uword +ip6_icmp_echo_request (vlib_main_t *vm, vlib_node_runtime_t *node, + vlib_frame_t *frame) +{ + u32 *from, *to_next; + u32 n_left_from, n_left_to_next, next_index; + ip6_main_t *im = &ip6_main; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + if (node->flags & VLIB_NODE_FLAG_TRACE) + vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors, + /* stride */ 1, + sizeof (icmp6_input_trace_t)); + + while (n_left_from > 0) + { + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from > 2 && n_left_to_next > 2) + { + vlib_buffer_t *p0, *p1; + ip6_header_t *ip0, *ip1; + icmp46_header_t *icmp0, *icmp1; + ip6_address_t tmp0, tmp1; + ip_csum_t sum0, sum1; + u32 bi0, bi1; + u32 fib_index0, fib_index1; + u32 next0 = ICMP6_ECHO_REQUEST_NEXT_LOOKUP; + u32 next1 = ICMP6_ECHO_REQUEST_NEXT_LOOKUP; + + bi0 = to_next[0] = from[0]; + bi1 = to_next[1] = from[1]; + + from += 2; + n_left_from -= 2; + to_next += 2; + n_left_to_next -= 2; + + p0 = vlib_get_buffer (vm, bi0); + p1 = vlib_get_buffer (vm, bi1); + ip0 = vlib_buffer_get_current (p0); + ip1 = vlib_buffer_get_current (p1); + icmp0 = ip6_next_header (ip0); + icmp1 = ip6_next_header (ip1); + + /* Check icmp type to echo reply and update icmp checksum. */ + sum0 = icmp0->checksum; + sum1 = icmp1->checksum; + + ASSERT (icmp0->type == ICMP6_echo_request); + ASSERT (icmp1->type == ICMP6_echo_request); + sum0 = ip_csum_update (sum0, ICMP6_echo_request, ICMP6_echo_reply, + icmp46_header_t, type); + sum1 = ip_csum_update (sum1, ICMP6_echo_request, ICMP6_echo_reply, + icmp46_header_t, type); + + icmp0->checksum = ip_csum_fold (sum0); + icmp1->checksum = ip_csum_fold (sum1); + + icmp0->type = ICMP6_echo_reply; + icmp1->type = ICMP6_echo_reply; + + /* Swap source and destination address. */ + tmp0 = ip0->src_address; + tmp1 = ip1->src_address; + + ip0->src_address = ip0->dst_address; + ip1->src_address = ip1->dst_address; + + ip0->dst_address = tmp0; + ip1->dst_address = tmp1; + + /* New hop count. */ + ip0->hop_limit = im->host_config.ttl; + ip1->hop_limit = im->host_config.ttl; + + if (ip6_address_is_link_local_unicast (&ip0->src_address) && + !ip6_address_is_link_local_unicast (&ip0->dst_address)) + { + fib_index0 = vec_elt (im->fib_index_by_sw_if_index, + vnet_buffer (p0)->sw_if_index[VLIB_RX]); + vnet_buffer (p0)->sw_if_index[VLIB_TX] = fib_index0; + } + if (ip6_address_is_link_local_unicast (&ip1->src_address) && + !ip6_address_is_link_local_unicast (&ip1->dst_address)) + { + fib_index1 = vec_elt (im->fib_index_by_sw_if_index, + vnet_buffer (p1)->sw_if_index[VLIB_RX]); + vnet_buffer (p1)->sw_if_index[VLIB_TX] = fib_index1; + } + p0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED; + p1->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED; + + /* verify speculative enqueues, maybe switch current next frame */ + /* if next0==next1==next_index then nothing special needs to be done + */ + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, + n_left_to_next, bi0, bi1, next0, + next1); + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + vlib_buffer_t *p0; + ip6_header_t *ip0; + icmp46_header_t *icmp0; + u32 bi0; + ip6_address_t tmp0; + ip_csum_t sum0; + u32 fib_index0; + u32 next0 = ICMP6_ECHO_REQUEST_NEXT_LOOKUP; + + bi0 = to_next[0] = from[0]; + + from += 1; + n_left_from -= 1; + to_next += 1; + n_left_to_next -= 1; + + p0 = vlib_get_buffer (vm, bi0); + ip0 = vlib_buffer_get_current (p0); + icmp0 = ip6_next_header (ip0); + + /* Check icmp type to echo reply and update icmp checksum. */ + sum0 = icmp0->checksum; + + ASSERT (icmp0->type == ICMP6_echo_request); + sum0 = ip_csum_update (sum0, ICMP6_echo_request, ICMP6_echo_reply, + icmp46_header_t, type); + + icmp0->checksum = ip_csum_fold (sum0); + + icmp0->type = ICMP6_echo_reply; + + /* Swap source and destination address. */ + tmp0 = ip0->src_address; + ip0->src_address = ip0->dst_address; + ip0->dst_address = tmp0; + + ip0->hop_limit = im->host_config.ttl; + + if (ip6_address_is_link_local_unicast (&ip0->src_address) && + !ip6_address_is_link_local_unicast (&ip0->dst_address)) + { + /* if original packet was to the link local, then the + * fib index is that of the LL table, we can't use that + * to foward the response if the new destination + * is global, so reset to the fib index of the link. + * In other case, the fib index we need has been written + * to the buffer already. */ + fib_index0 = vec_elt (im->fib_index_by_sw_if_index, + vnet_buffer (p0)->sw_if_index[VLIB_RX]); + vnet_buffer (p0)->sw_if_index[VLIB_TX] = fib_index0; + } + p0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED; + /* Verify speculative enqueue, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, + n_left_to_next, bi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + vlib_error_count (vm, ip6_icmp_input_node.index, + ICMP6_ERROR_ECHO_REPLIES_SENT, frame->n_vectors); + + return frame->n_vectors; +} + +VLIB_REGISTER_NODE (ip6_icmp_echo_request_node,static) = { + .function = ip6_icmp_echo_request, + .name = "ip6-icmp-echo-request", + + .vector_size = sizeof (u32), + + .format_trace = format_icmp6_input_trace, + + .n_next_nodes = ICMP6_ECHO_REQUEST_N_NEXT, + .next_nodes = { + [ICMP6_ECHO_REQUEST_NEXT_LOOKUP] = "ip6-lookup", + [ICMP6_ECHO_REQUEST_NEXT_OUTPUT] = "interface-output", + }, +}; /* * A swarm of address-family agnostic helper functions @@ -990,6 +1116,7 @@ send_ip46_ping (vlib_main_t * vm, ERROR_OUT (SEND_PING_NO_INTERFACE); vnet_buffer (b0)->sw_if_index[VLIB_RX] = sw_if_index; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = fib_index; int l4_header_offset = ip46_fill_l3_header (pa46, b0, is_ip6); @@ -1034,9 +1161,8 @@ done: return err; } -static send_ip46_ping_result_t -send_ip6_ping (vlib_main_t * vm, - u32 table_id, ip6_address_t * pa6, +send_ip46_ping_result_t +send_ip6_ping (vlib_main_t *vm, u32 table_id, ip6_address_t *pa6, u32 sw_if_index, u16 seq_host, u16 id_host, u16 data_len, u32 burst, u8 verbose) { @@ -1046,9 +1172,8 @@ send_ip6_ping (vlib_main_t * vm, id_host, data_len, burst, verbose, 1 /* is_ip6 */ ); } -static send_ip46_ping_result_t -send_ip4_ping (vlib_main_t * vm, - u32 table_id, ip4_address_t * pa4, +send_ip46_ping_result_t +send_ip4_ping (vlib_main_t *vm, u32 table_id, ip4_address_t *pa4, u32 sw_if_index, u16 seq_host, u16 id_host, u16 data_len, u32 burst, u8 verbose) { @@ -1451,7 +1576,6 @@ done: * @cliexend * @endparblock ?*/ -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (ping_command, static) = { .path = "ping", @@ -1462,7 +1586,6 @@ VLIB_CLI_COMMAND (ping_command, static) = " [burst <count:1>] [verbose]", .is_mp_safe = 1, }; -/* *INDENT-ON* */ static clib_error_t * ping_cli_init (vlib_main_t * vm) @@ -1480,18 +1603,20 @@ ping_cli_init (vlib_main_t * vm) ip4_icmp_register_type (vm, ICMP4_echo_request, ip4_icmp_echo_request_node.index); + icmp6_register_type (vm, ICMP6_echo_request, + ip6_icmp_echo_request_node.index); + + ping_plugin_api_hookup (vm); return 0; } VLIB_INIT_FUNCTION (ping_cli_init); -/* *INDENT-OFF* */ VLIB_PLUGIN_REGISTER () = { .version = VPP_BUILD_VER, .description = "Ping (ping)", }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON |