udp: add input nolookup node 25/43625/6
authorFlorin Coras <[email protected]>
Fri, 22 Aug 2025 14:49:05 +0000 (10:49 -0400)
committerDave Barach <[email protected]>
Fri, 29 Aug 2025 19:23:27 +0000 (19:23 +0000)
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 <[email protected]>
src/vnet/buffer.h
src/vnet/udp/udp_error.def
src/vnet/udp/udp_input.c

index c9005b7..01bd69b 100644 (file)
@@ -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
     {
index 843aacf..011e59c 100644 (file)
@@ -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")
index e982895..4ca09b5 100644 (file)
@@ -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
  *