From 32a2287ba13e4e636482f4a376d0acbc47ccdfe6 Mon Sep 17 00:00:00 2001 From: Florin Coras Date: Fri, 22 Aug 2025 10:49:05 -0400 Subject: [PATCH] udp: add input nolookup node Feature parity with tcp. Useful when other nodes like hsi do the udp session lookup before sending to udp. Type: feature Change-Id: Ib5f39a86cb316d326f0e19f7426b3b97c1bdecf7 Signed-off-by: Florin Coras --- src/vnet/buffer.h | 13 +++++ src/vnet/udp/udp_error.def | 1 + src/vnet/udp/udp_input.c | 118 +++++++++++++++++++++++++++++++++++++-------- 3 files changed, 111 insertions(+), 21 deletions(-) diff --git a/src/vnet/buffer.h b/src/vnet/buffer.h index c9005b70daf..01bd69b5e5a 100644 --- a/src/vnet/buffer.h +++ b/src/vnet/buffer.h @@ -404,6 +404,19 @@ typedef struct u8 flags; } tcp; + struct + { + union + { + struct + { + u32 session_index; + clib_thread_index_t thread_index; + }; + u64 session_handle; + }; + } udp; + /* SNAT */ struct { diff --git a/src/vnet/udp/udp_error.def b/src/vnet/udp/udp_error.def index 843aacfc6ef..011e59cba46 100644 --- a/src/vnet/udp/udp_error.def +++ b/src/vnet/udp/udp_error.def @@ -29,3 +29,4 @@ udp_error (MQ_FULL, mq_full, ERROR, "Application msg queue full") udp_error (INVALID_CONNECTION, invalid_connection, ERROR, "Invalid connection") udp_error (PKTS_SENT, pkts_sent, INFO, "Packets sent") udp_error (CONNECTED, connected, INFO, "Connected session") +udp_error (CREATE_EXISTS, create_exists, ERROR, "Connection already exists") diff --git a/src/vnet/udp/udp_input.c b/src/vnet/udp/udp_input.c index e982895d2d6..4ca09b5920e 100644 --- a/src/vnet/udp/udp_input.c +++ b/src/vnet/udp/udp_input.c @@ -197,8 +197,8 @@ udp_connection_enqueue (udp_connection_t *uc0, session_t *s0, } always_inline session_t * -udp_parse_and_lookup_buffer (vlib_buffer_t * b, session_dgram_hdr_t * hdr, - u8 is_ip4) +udp_parse_and_lookup_buffer (vlib_buffer_t *b, session_dgram_hdr_t *hdr, + u8 is_ip4, u8 is_nolookup) { udp_header_t *udp; u32 fib_index; @@ -224,9 +224,10 @@ udp_parse_and_lookup_buffer (vlib_buffer_t * b, session_dgram_hdr_t * hdr, ip_set (&hdr->rmt_ip, &ip4->src_address, 1); hdr->data_length = clib_net_to_host_u16 (ip4->length); hdr->data_length -= sizeof (ip4_header_t) + sizeof (udp_header_t); - s = session_lookup_safe4 (fib_index, &ip4->dst_address, - &ip4->src_address, udp->dst_port, - udp->src_port, TRANSPORT_PROTO_UDP); + if (!is_nolookup) + s = session_lookup_safe4 (fib_index, &ip4->dst_address, + &ip4->src_address, udp->dst_port, + udp->src_port, TRANSPORT_PROTO_UDP); } else { @@ -237,11 +238,15 @@ udp_parse_and_lookup_buffer (vlib_buffer_t * b, session_dgram_hdr_t * hdr, ip_set (&hdr->rmt_ip, &ip60->src_address, 0); hdr->data_length = clib_net_to_host_u16 (ip60->payload_length); hdr->data_length -= sizeof (udp_header_t); - s = session_lookup_safe6 (fib_index, &ip60->dst_address, - &ip60->src_address, udp->dst_port, - udp->src_port, TRANSPORT_PROTO_UDP); + if (!is_nolookup) + s = session_lookup_safe6 (fib_index, &ip60->dst_address, + &ip60->src_address, udp->dst_port, + udp->src_port, TRANSPORT_PROTO_UDP); } + if (is_nolookup) + s = session_get_from_handle (vnet_buffer (b)->udp.session_handle); + /* Set the sw_if_index[VLIB_RX] to the interface we received * the connection on (the local interface) */ vnet_buffer (b)->sw_if_index[VLIB_RX] = vnet_buffer (b)->ip.rx_sw_if_index; @@ -255,9 +260,26 @@ udp_parse_and_lookup_buffer (vlib_buffer_t * b, session_dgram_hdr_t * hdr, return s; } +static u8 +udp_connection_is_accepted (u32 fib_index, session_dgram_hdr_t *hdr, u8 is_ip4) +{ + session_t *s; + + if (is_ip4) + s = + session_lookup_safe4 (fib_index, &hdr->lcl_ip.ip4, &hdr->rmt_ip.ip4, + hdr->lcl_port, hdr->rmt_port, TRANSPORT_PROTO_UDP); + else + s = + session_lookup_safe6 (fib_index, &hdr->lcl_ip.ip6, &hdr->rmt_ip.ip6, + hdr->lcl_port, hdr->rmt_port, TRANSPORT_PROTO_UDP); + + return (s && s->session_state != SESSION_STATE_LISTENING); +} + always_inline uword -udp46_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * frame, u8 is_ip4) +udp46_input_inline (vlib_main_t *vm, vlib_node_runtime_t *node, + vlib_frame_t *frame, u8 is_ip4, u8 is_nolookup) { clib_thread_index_t thread_index = vm->thread_index; u32 n_left_from, *from, *first_buffer; @@ -277,7 +299,7 @@ udp46_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, udp_connection_t *uc0; session_t *s0; - s0 = udp_parse_and_lookup_buffer (b[0], &hdr0, is_ip4); + s0 = udp_parse_and_lookup_buffer (b[0], &hdr0, is_ip4, is_nolookup); if (PREDICT_FALSE (!s0)) { error0 = UDP_ERROR_NO_LISTENER; @@ -327,6 +349,16 @@ udp46_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, uc0 = udp_connection_from_transport (session_get_transport (s0)); if (uc0->flags & UDP_CONN_F_CONNECTED) { + if (is_nolookup) + { + /* Make sure connection was not already accepted */ + if (udp_connection_is_accepted ( + vnet_buffer (b[0])->ip.fib_index, &hdr0, is_ip4)) + { + error0 = UDP_ERROR_CREATE_EXISTS; + goto done; + } + } uc0 = udp_connection_accept (uc0, &hdr0, thread_index); if (!uc0) { @@ -361,16 +393,15 @@ udp46_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, return frame->n_vectors; } -static uword -udp4_input (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * frame) +VLIB_NODE_FN (udp4_input_node) +(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) { - return udp46_input_inline (vm, node, frame, 1); + return udp46_input_inline (vm, node, frame, 1 /* is_ip4 */, + 0 /* is_nolookup */); } VLIB_REGISTER_NODE (udp4_input_node) = { - .function = udp4_input, .name = "udp4-input", .vector_size = sizeof (u32), .format_trace = format_udp_input_trace, @@ -385,16 +416,38 @@ VLIB_REGISTER_NODE (udp4_input_node) = }, }; -static uword -udp6_input (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * frame) +VLIB_NODE_FN (udp4_input_nolookup_node) +(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) { - return udp46_input_inline (vm, node, frame, 0); + return udp46_input_inline (vm, node, frame, 1 /* is_ip4 */, + 1 /* is_nolookup */); +} + +VLIB_REGISTER_NODE (udp4_input_nolookup_node) = +{ + .name = "udp4-input-nolookup", + .vector_size = sizeof (u32), + .format_trace = format_udp_input_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = UDP_N_ERROR, + .error_counters = udp_error_counters, + .n_next_nodes = UDP_INPUT_N_NEXT, + .next_nodes = { +#define _(s, n) [UDP_INPUT_NEXT_##s] = n, + foreach_udp_input_next +#undef _ + }, +}; + +VLIB_NODE_FN (udp6_input_node) +(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) +{ + return udp46_input_inline (vm, node, frame, 0 /* is_ip4 */, + 0 /* is_nolookup */); } VLIB_REGISTER_NODE (udp6_input_node) = { - .function = udp6_input, .name = "udp6-input", .vector_size = sizeof (u32), .format_trace = format_udp_input_trace, @@ -409,6 +462,29 @@ VLIB_REGISTER_NODE (udp6_input_node) = }, }; +VLIB_NODE_FN (udp6_input_nolookup_node) +(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) +{ + return udp46_input_inline (vm, node, frame, 0 /* is_ip4 */, + 1 /* is_nolookup */); +} + +VLIB_REGISTER_NODE (udp6_input_nolookup_node) = +{ + .name = "udp6-input-nolookup", + .vector_size = sizeof (u32), + .format_trace = format_udp_input_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = UDP_N_ERROR, + .error_counters = udp_error_counters, + .n_next_nodes = UDP_INPUT_N_NEXT, + .next_nodes = { +#define _(s, n) [UDP_INPUT_NEXT_##s] = n, + foreach_udp_input_next +#undef _ + }, +}; + /* * fd.io coding-style-patch-verification: ON * -- 2.16.6