LCOV - code coverage report
Current view: top level - vnet/udp - udp_output.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 49 83 59.0 %
Date: 2023-10-26 01:39:38 Functions: 10 13 76.9 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: Apache-2.0
       2             :  * Copyright(c) 2022 Cisco Systems, Inc.
       3             :  */
       4             : 
       5             : #include <vnet/udp/udp.h>
       6             : #include <vnet/ip/ip4_inlines.h>
       7             : #include <vnet/ip/ip6_inlines.h>
       8             : 
       9             : #define udp_node_index(node_id, is_ip4)                                       \
      10             :   ((is_ip4) ? udp4_##node_id##_node.index : udp6_##node_id##_node.index)
      11             : 
      12             : typedef enum udp_output_next_
      13             : {
      14             :   UDP_OUTPUT_NEXT_DROP,
      15             :   UDP_OUTPUT_NEXT_IP_LOOKUP,
      16             :   UDP_OUTPUT_N_NEXT
      17             : } udp_output_next_t;
      18             : 
      19             : #define foreach_udp4_output_next                                              \
      20             :   _ (DROP, "error-drop")                                                      \
      21             :   _ (IP_LOOKUP, "ip4-lookup")
      22             : 
      23             : #define foreach_udp6_output_next                                              \
      24             :   _ (DROP, "error-drop")                                                      \
      25             :   _ (IP_LOOKUP, "ip6-lookup")
      26             : 
      27             : static vlib_error_desc_t udp_output_error_counters[] = {
      28             : #define udp_error(f, n, s, d) { #n, d, VL_COUNTER_SEVERITY_##s },
      29             : #include <vnet/udp/udp_error.def>
      30             : #undef udp_error
      31             : };
      32             : 
      33             : typedef struct udp_tx_trace_
      34             : {
      35             :   udp_header_t udp_header;
      36             :   udp_connection_t udp_connection;
      37             : } udp_tx_trace_t;
      38             : 
      39             : static u8 *
      40           0 : format_udp_tx_trace (u8 *s, va_list *args)
      41             : {
      42           0 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      43           0 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      44           0 :   udp_tx_trace_t *t = va_arg (*args, udp_tx_trace_t *);
      45           0 :   udp_connection_t *uc = &t->udp_connection;
      46           0 :   u32 indent = format_get_indent (s);
      47             : 
      48           0 :   s = format (s, "%U\n%U%U", format_udp_connection, uc, 1, format_white_space,
      49             :               indent, format_udp_header, &t->udp_header, 128);
      50             : 
      51           0 :   return s;
      52             : }
      53             : 
      54             : always_inline udp_connection_t *
      55       59065 : udp_output_get_connection (vlib_buffer_t *b, u32 thread_index)
      56             : {
      57       59065 :   if (PREDICT_FALSE (vnet_buffer (b)->tcp.flags & UDP_CONN_F_LISTEN))
      58           0 :     return udp_listener_get (vnet_buffer (b)->tcp.connection_index);
      59             : 
      60       59065 :   return udp_connection_get (vnet_buffer (b)->tcp.connection_index,
      61             :                              thread_index);
      62             : }
      63             : 
      64             : static void
      65           0 : udp46_output_trace_frame (vlib_main_t *vm, vlib_node_runtime_t *node,
      66             :                           u32 *to_next, u32 n_bufs)
      67             : {
      68             :   udp_connection_t *uc;
      69             :   udp_tx_trace_t *t;
      70             :   vlib_buffer_t *b;
      71             :   udp_header_t *uh;
      72             :   int i;
      73             : 
      74           0 :   for (i = 0; i < n_bufs; i++)
      75             :     {
      76           0 :       b = vlib_get_buffer (vm, to_next[i]);
      77           0 :       if (!(b->flags & VLIB_BUFFER_IS_TRACED))
      78           0 :         continue;
      79           0 :       uh = vlib_buffer_get_current (b);
      80           0 :       uc = udp_output_get_connection (b, vm->thread_index);
      81           0 :       t = vlib_add_trace (vm, node, b, sizeof (*t));
      82           0 :       clib_memcpy_fast (&t->udp_header, uh, sizeof (t->udp_header));
      83           0 :       clib_memcpy_fast (&t->udp_connection, uc, sizeof (t->udp_connection));
      84             :     }
      85           0 : }
      86             : 
      87             : always_inline void
      88       59065 : udp_output_handle_packet (udp_connection_t *uc0, vlib_buffer_t *b0,
      89             :                           vlib_node_runtime_t *error_node, u16 *next0,
      90             :                           u8 is_ip4)
      91             : {
      92             :   /* If next_index is not drop use it */
      93       59065 :   if (uc0->next_node_index)
      94             :     {
      95           0 :       *next0 = uc0->next_node_index;
      96           0 :       vnet_buffer (b0)->tcp.next_node_opaque = uc0->next_node_opaque;
      97             :     }
      98             :   else
      99             :     {
     100       59065 :       *next0 = UDP_OUTPUT_NEXT_IP_LOOKUP;
     101             :     }
     102             : 
     103       59065 :   vnet_buffer (b0)->sw_if_index[VLIB_TX] = uc0->c_fib_index;
     104       59065 :   vnet_buffer (b0)->sw_if_index[VLIB_RX] = uc0->sw_if_index;
     105       59065 : }
     106             : 
     107             : always_inline uword
     108       10787 : udp46_output_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
     109             :                      vlib_frame_t *frame, int is_ip4)
     110             : {
     111       10787 :   u32 n_left_from, *from, thread_index = vm->thread_index;
     112             :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
     113             :   u16 nexts[VLIB_FRAME_SIZE], *next;
     114             : 
     115       10787 :   from = vlib_frame_vector_args (frame);
     116       10787 :   n_left_from = frame->n_vectors;
     117             : 
     118       10787 :   if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
     119           0 :     udp46_output_trace_frame (vm, node, from, n_left_from);
     120             : 
     121       10787 :   vlib_get_buffers (vm, from, bufs, n_left_from);
     122       10787 :   b = bufs;
     123       10787 :   next = nexts;
     124             : 
     125       33009 :   while (n_left_from >= 4)
     126             :     {
     127             :       udp_connection_t *uc0, *uc1;
     128             : 
     129       22222 :       vlib_prefetch_buffer_header (b[2], STORE);
     130       22222 :       CLIB_PREFETCH (b[2]->data, 2 * CLIB_CACHE_LINE_BYTES, STORE);
     131             : 
     132       22222 :       vlib_prefetch_buffer_header (b[3], STORE);
     133       22222 :       CLIB_PREFETCH (b[3]->data, 2 * CLIB_CACHE_LINE_BYTES, STORE);
     134             : 
     135       22222 :       uc0 = udp_output_get_connection (b[0], thread_index);
     136       22222 :       uc1 = udp_output_get_connection (b[1], thread_index);
     137             : 
     138       22222 :       if (PREDICT_TRUE (!uc0 + !uc1 == 0))
     139             :         {
     140       22222 :           udp_output_handle_packet (uc0, b[0], node, &next[0], is_ip4);
     141       22222 :           udp_output_handle_packet (uc1, b[1], node, &next[1], is_ip4);
     142             :         }
     143             :       else
     144             :         {
     145           0 :           if (uc0 != 0)
     146             :             {
     147           0 :               udp_output_handle_packet (uc0, b[0], node, &next[0], is_ip4);
     148             :             }
     149             :           else
     150             :             {
     151           0 :               b[0]->error = node->errors[UDP_ERROR_INVALID_CONNECTION];
     152           0 :               next[0] = UDP_OUTPUT_NEXT_DROP;
     153             :             }
     154           0 :           if (uc1 != 0)
     155             :             {
     156           0 :               udp_output_handle_packet (uc1, b[1], node, &next[1], is_ip4);
     157             :             }
     158             :           else
     159             :             {
     160           0 :               b[1]->error = node->errors[UDP_ERROR_INVALID_CONNECTION];
     161           0 :               next[1] = UDP_OUTPUT_NEXT_DROP;
     162             :             }
     163             :         }
     164             : 
     165       22222 :       b += 2;
     166       22222 :       next += 2;
     167       22222 :       n_left_from -= 2;
     168             :     }
     169       25408 :   while (n_left_from > 0)
     170             :     {
     171             :       udp_connection_t *uc0;
     172             : 
     173       14621 :       if (n_left_from > 1)
     174             :         {
     175        3834 :           vlib_prefetch_buffer_header (b[1], STORE);
     176        3834 :           CLIB_PREFETCH (b[1]->data, 2 * CLIB_CACHE_LINE_BYTES, STORE);
     177             :         }
     178             : 
     179       14621 :       uc0 = udp_output_get_connection (b[0], thread_index);
     180             : 
     181       14621 :       if (PREDICT_TRUE (uc0 != 0))
     182             :         {
     183       14621 :           udp_output_handle_packet (uc0, b[0], node, &next[0], is_ip4);
     184             :         }
     185             :       else
     186             :         {
     187           0 :           b[0]->error = node->errors[UDP_ERROR_INVALID_CONNECTION];
     188           0 :           next[0] = UDP_OUTPUT_NEXT_DROP;
     189             :         }
     190             : 
     191       14621 :       b += 1;
     192       14621 :       next += 1;
     193       14621 :       n_left_from -= 1;
     194             :     }
     195             : 
     196       10787 :   vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
     197       10787 :   vlib_node_increment_counter (vm, udp_node_index (output, is_ip4),
     198       10787 :                                UDP_ERROR_PKTS_SENT, frame->n_vectors);
     199       10787 :   return frame->n_vectors;
     200             : }
     201             : 
     202       11362 : VLIB_NODE_FN (udp4_output_node)
     203             : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
     204             : {
     205       10787 :   return udp46_output_inline (vm, node, from_frame, 1 /* is_ip4 */);
     206             : }
     207             : 
     208         575 : VLIB_NODE_FN (udp6_output_node)
     209             : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
     210             : {
     211           0 :   return udp46_output_inline (vm, node, from_frame, 0 /* is_ip4 */);
     212             : }
     213             : 
     214      183788 : VLIB_REGISTER_NODE (udp4_output_node) =
     215             : {
     216             :   .name = "udp4-output",
     217             :   .vector_size = sizeof (u32),
     218             :   .n_errors = UDP_N_ERROR,
     219             :   .protocol_hint = VLIB_NODE_PROTO_HINT_UDP,
     220             :   .error_counters = udp_output_error_counters,
     221             :   .n_next_nodes = UDP_OUTPUT_N_NEXT,
     222             :   .next_nodes = {
     223             : #define _(s, n) [UDP_OUTPUT_NEXT_##s] = n,
     224             :     foreach_udp4_output_next
     225             : #undef _
     226             :   },
     227             :   .format_buffer = format_udp_header,
     228             :   .format_trace = format_udp_tx_trace,
     229             : };
     230             : 
     231      183788 : VLIB_REGISTER_NODE (udp6_output_node) =
     232             : {
     233             :   .name = "udp6-output",
     234             :   .vector_size = sizeof (u32),
     235             :   .n_errors = UDP_N_ERROR,
     236             :   .protocol_hint = VLIB_NODE_PROTO_HINT_UDP,
     237             :   .error_counters = udp_output_error_counters,
     238             :   .n_next_nodes = UDP_OUTPUT_N_NEXT,
     239             :   .next_nodes = {
     240             : #define _(s, n) [UDP_OUTPUT_NEXT_##s] = n,
     241             :     foreach_udp6_output_next
     242             : #undef _
     243             :   },
     244             :   .format_buffer = format_udp_header,
     245             :   .format_trace = format_udp_tx_trace,
     246             : };
     247             : 
     248             : /*
     249             :  * fd.io coding-style-patch-verification: ON
     250             :  *
     251             :  * Local Variables:
     252             :  * eval: (c-set-style "gnu")
     253             :  * End:
     254             :  */

Generated by: LCOV version 1.14