LCOV - code coverage report
Current view: top level - plugins/nat/nat44-ei - nat44_ei_handoff.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 63 138 45.7 %
Date: 2023-07-05 22:20:52 Functions: 12 14 85.7 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2020 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : 
      16             : #include <vlib/vlib.h>
      17             : #include <vnet/vnet.h>
      18             : #include <vnet/fib/ip4_fib.h>
      19             : #include <vppinfra/error.h>
      20             : 
      21             : #include <nat/nat44-ei/nat44_ei.h>
      22             : 
      23             : typedef struct
      24             : {
      25             :   u32 next_worker_index;
      26             :   u32 trace_index;
      27             :   u8 in2out;
      28             :   u8 output;
      29             : } nat44_ei_handoff_trace_t;
      30             : 
      31             : #define foreach_nat44_ei_handoff_error                                        \
      32             :   _ (CONGESTION_DROP, "congestion drop")                                      \
      33             :   _ (SAME_WORKER, "same worker")                                              \
      34             :   _ (DO_HANDOFF, "do handoff")
      35             : 
      36             : typedef enum
      37             : {
      38             : #define _(sym, str) NAT44_EI_HANDOFF_ERROR_##sym,
      39             :   foreach_nat44_ei_handoff_error
      40             : #undef _
      41             :     NAT44_EI_HANDOFF_N_ERROR,
      42             : } nat44_ei_handoff_error_t;
      43             : 
      44             : static char *nat44_ei_handoff_error_strings[] = {
      45             : #define _(sym, string) string,
      46             :   foreach_nat44_ei_handoff_error
      47             : #undef _
      48             : };
      49             : 
      50             : static u8 *
      51           4 : format_nat44_ei_handoff_trace (u8 *s, va_list *args)
      52             : {
      53           4 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      54           4 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      55           4 :   nat44_ei_handoff_trace_t *t = va_arg (*args, nat44_ei_handoff_trace_t *);
      56             :   char *tag, *output;
      57             : 
      58           4 :   tag = t->in2out ? "IN2OUT" : "OUT2IN";
      59           4 :   output = t->output ? "OUTPUT-FEATURE" : "";
      60             :   s =
      61           4 :     format (s, "NAT44_EI_%s_WORKER_HANDOFF %s: next-worker %d trace index %d",
      62             :             tag, output, t->next_worker_index, t->trace_index);
      63             : 
      64           4 :   return s;
      65             : }
      66             : 
      67             : static inline uword
      68           6 : nat44_ei_worker_handoff_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
      69             :                                    vlib_frame_t *frame, u8 is_output,
      70             :                                    u8 is_in2out)
      71             : {
      72           6 :   u32 n_enq, n_left_from, *from, do_handoff = 0, same_worker = 0;
      73             : 
      74           6 :   u16 thread_indices[VLIB_FRAME_SIZE], *ti = thread_indices;
      75           6 :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
      76           6 :   nat44_ei_main_t *nm = &nat44_ei_main;
      77             : 
      78           6 :   u32 fq_index, thread_index = vm->thread_index;
      79             : 
      80           6 :   from = vlib_frame_vector_args (frame);
      81           6 :   n_left_from = frame->n_vectors;
      82             : 
      83           6 :   vlib_get_buffers (vm, from, b, n_left_from);
      84             : 
      85           6 :   if (is_in2out)
      86             :     {
      87           6 :       fq_index = is_output ? nm->fq_in2out_output_index : nm->fq_in2out_index;
      88             :     }
      89             :   else
      90             :     {
      91           0 :       fq_index = nm->fq_out2in_index;
      92             :     }
      93             : 
      94           6 :   while (n_left_from >= 4)
      95             :     {
      96             :       u32 arc_next0, arc_next1, arc_next2, arc_next3;
      97             :       u32 sw_if_index0, sw_if_index1, sw_if_index2, sw_if_index3;
      98             :       u32 rx_fib_index0, rx_fib_index1, rx_fib_index2, rx_fib_index3;
      99           0 :       u32 iph_offset0 = 0, iph_offset1 = 0, iph_offset2 = 0, iph_offset3 = 0;
     100             :       ip4_header_t *ip0, *ip1, *ip2, *ip3;
     101             : 
     102           0 :       if (PREDICT_TRUE (n_left_from >= 8))
     103             :         {
     104           0 :           vlib_prefetch_buffer_header (b[4], LOAD);
     105           0 :           vlib_prefetch_buffer_header (b[5], LOAD);
     106           0 :           vlib_prefetch_buffer_header (b[6], LOAD);
     107           0 :           vlib_prefetch_buffer_header (b[7], LOAD);
     108           0 :           clib_prefetch_load (&b[4]->data);
     109           0 :           clib_prefetch_load (&b[5]->data);
     110           0 :           clib_prefetch_load (&b[6]->data);
     111           0 :           clib_prefetch_load (&b[7]->data);
     112             :         }
     113             : 
     114           0 :       if (is_output)
     115             :         {
     116           0 :           iph_offset0 = vnet_buffer (b[0])->ip.save_rewrite_length;
     117           0 :           iph_offset1 = vnet_buffer (b[1])->ip.save_rewrite_length;
     118           0 :           iph_offset2 = vnet_buffer (b[2])->ip.save_rewrite_length;
     119           0 :           iph_offset3 = vnet_buffer (b[3])->ip.save_rewrite_length;
     120             :         }
     121             : 
     122           0 :       ip0 =
     123           0 :         (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b[0]) + iph_offset0);
     124           0 :       ip1 =
     125           0 :         (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b[1]) + iph_offset1);
     126           0 :       ip2 =
     127           0 :         (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b[2]) + iph_offset2);
     128           0 :       ip3 =
     129           0 :         (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b[3]) + iph_offset3);
     130             : 
     131           0 :       vnet_feature_next (&arc_next0, b[0]);
     132           0 :       vnet_feature_next (&arc_next1, b[1]);
     133           0 :       vnet_feature_next (&arc_next2, b[2]);
     134           0 :       vnet_feature_next (&arc_next3, b[3]);
     135             : 
     136           0 :       vnet_buffer2 (b[0])->nat.arc_next = arc_next0;
     137           0 :       vnet_buffer2 (b[1])->nat.arc_next = arc_next1;
     138           0 :       vnet_buffer2 (b[2])->nat.arc_next = arc_next2;
     139           0 :       vnet_buffer2 (b[3])->nat.arc_next = arc_next3;
     140             : 
     141           0 :       sw_if_index0 = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
     142           0 :       sw_if_index1 = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
     143           0 :       sw_if_index2 = vnet_buffer (b[2])->sw_if_index[VLIB_RX];
     144           0 :       sw_if_index3 = vnet_buffer (b[3])->sw_if_index[VLIB_RX];
     145             : 
     146           0 :       rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
     147           0 :       rx_fib_index1 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index1);
     148           0 :       rx_fib_index2 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index2);
     149           0 :       rx_fib_index3 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index3);
     150             : 
     151           0 :       if (is_in2out)
     152             :         {
     153           0 :           ti[0] =
     154           0 :             nat44_ei_get_in2out_worker_index (ip0, rx_fib_index0, is_output);
     155           0 :           ti[1] =
     156           0 :             nat44_ei_get_in2out_worker_index (ip1, rx_fib_index1, is_output);
     157           0 :           ti[2] =
     158           0 :             nat44_ei_get_in2out_worker_index (ip2, rx_fib_index2, is_output);
     159           0 :           ti[3] =
     160           0 :             nat44_ei_get_in2out_worker_index (ip3, rx_fib_index3, is_output);
     161             :         }
     162             :       else
     163             :         {
     164           0 :           ti[0] = nat44_ei_get_out2in_worker_index (b[0], ip0, rx_fib_index0,
     165             :                                                     is_output);
     166           0 :           ti[1] = nat44_ei_get_out2in_worker_index (b[1], ip1, rx_fib_index1,
     167             :                                                     is_output);
     168           0 :           ti[2] = nat44_ei_get_out2in_worker_index (b[2], ip2, rx_fib_index2,
     169             :                                                     is_output);
     170           0 :           ti[3] = nat44_ei_get_out2in_worker_index (b[3], ip3, rx_fib_index3,
     171             :                                                     is_output);
     172             :         }
     173             : 
     174           0 :       if (ti[0] == thread_index)
     175           0 :         same_worker++;
     176             :       else
     177           0 :         do_handoff++;
     178             : 
     179           0 :       if (ti[1] == thread_index)
     180           0 :         same_worker++;
     181             :       else
     182           0 :         do_handoff++;
     183             : 
     184           0 :       if (ti[2] == thread_index)
     185           0 :         same_worker++;
     186             :       else
     187           0 :         do_handoff++;
     188             : 
     189           0 :       if (ti[3] == thread_index)
     190           0 :         same_worker++;
     191             :       else
     192           0 :         do_handoff++;
     193             : 
     194           0 :       b += 4;
     195           0 :       ti += 4;
     196           0 :       n_left_from -= 4;
     197             :     }
     198             : 
     199          20 :   while (n_left_from > 0)
     200             :     {
     201             :       u32 arc_next0;
     202             :       u32 sw_if_index0;
     203             :       u32 rx_fib_index0;
     204          14 :       u32 iph_offset0 = 0;
     205             :       ip4_header_t *ip0;
     206             : 
     207          14 :       if (is_output)
     208           0 :         iph_offset0 = vnet_buffer (b[0])->ip.save_rewrite_length;
     209             : 
     210          14 :       ip0 =
     211          14 :         (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b[0]) + iph_offset0);
     212             : 
     213          14 :       vnet_feature_next (&arc_next0, b[0]);
     214          14 :       vnet_buffer2 (b[0])->nat.arc_next = arc_next0;
     215             : 
     216          14 :       sw_if_index0 = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
     217          14 :       rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
     218             : 
     219          14 :       if (is_in2out)
     220             :         {
     221          14 :           ti[0] =
     222          14 :             nat44_ei_get_in2out_worker_index (ip0, rx_fib_index0, is_output);
     223             :         }
     224             :       else
     225             :         {
     226           0 :           ti[0] = nat44_ei_get_out2in_worker_index (b[0], ip0, rx_fib_index0,
     227             :                                                     is_output);
     228             :         }
     229             : 
     230          14 :       if (ti[0] == thread_index)
     231           7 :         same_worker++;
     232             :       else
     233           7 :         do_handoff++;
     234             : 
     235          14 :       b += 1;
     236          14 :       ti += 1;
     237          14 :       n_left_from -= 1;
     238             :     }
     239             : 
     240           6 :   if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
     241             :     {
     242             :       u32 i;
     243           6 :       b = bufs;
     244           6 :       ti = thread_indices;
     245             : 
     246          20 :       for (i = 0; i < frame->n_vectors; i++)
     247             :         {
     248          14 :           if (b[0]->flags & VLIB_BUFFER_IS_TRACED)
     249             :             {
     250             :               nat44_ei_handoff_trace_t *t =
     251          14 :                 vlib_add_trace (vm, node, b[0], sizeof (*t));
     252          14 :               t->next_worker_index = ti[0];
     253          14 :               t->trace_index = vlib_buffer_get_trace_index (b[0]);
     254          14 :               t->in2out = is_in2out;
     255          14 :               t->output = is_output;
     256             : 
     257          14 :               b += 1;
     258          14 :               ti += 1;
     259             :             }
     260             :           else
     261           0 :             break;
     262             :         }
     263             :     }
     264             : 
     265           6 :   n_enq = vlib_buffer_enqueue_to_thread (vm, node, fq_index, from,
     266           6 :                                          thread_indices, frame->n_vectors, 1);
     267             : 
     268           6 :   if (n_enq < frame->n_vectors)
     269             :     {
     270           0 :       vlib_node_increment_counter (vm, node->node_index,
     271             :                                    NAT44_EI_HANDOFF_ERROR_CONGESTION_DROP,
     272           0 :                                    frame->n_vectors - n_enq);
     273             :     }
     274             : 
     275           6 :   vlib_node_increment_counter (
     276             :     vm, node->node_index, NAT44_EI_HANDOFF_ERROR_SAME_WORKER, same_worker);
     277           6 :   vlib_node_increment_counter (vm, node->node_index,
     278             :                                NAT44_EI_HANDOFF_ERROR_DO_HANDOFF, do_handoff);
     279           6 :   return frame->n_vectors;
     280             : }
     281             : 
     282         565 : VLIB_NODE_FN (nat44_ei_in2out_worker_handoff_node)
     283             : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
     284             : {
     285           6 :   return nat44_ei_worker_handoff_fn_inline (vm, node, frame, 0, 1);
     286             : }
     287             : 
     288         559 : VLIB_NODE_FN (nat44_ei_in2out_output_worker_handoff_node)
     289             : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
     290             : {
     291           0 :   return nat44_ei_worker_handoff_fn_inline (vm, node, frame, 1, 1);
     292             : }
     293             : 
     294         559 : VLIB_NODE_FN (nat44_ei_out2in_worker_handoff_node)
     295             : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
     296             : {
     297           0 :   return nat44_ei_worker_handoff_fn_inline (vm, node, frame, 0, 0);
     298             : }
     299             : 
     300       62744 : VLIB_REGISTER_NODE (nat44_ei_in2out_output_worker_handoff_node) = {
     301             :   .name = "nat44-ei-in2out-output-worker-handoff",
     302             :   .vector_size = sizeof (u32),
     303             :   .format_trace = format_nat44_ei_handoff_trace,
     304             :   .type = VLIB_NODE_TYPE_INTERNAL,
     305             :   .n_errors = ARRAY_LEN (nat44_ei_handoff_error_strings),
     306             :   .error_strings = nat44_ei_handoff_error_strings,
     307             : };
     308             : 
     309       62744 : VLIB_REGISTER_NODE (nat44_ei_in2out_worker_handoff_node) = {
     310             :   .name = "nat44-ei-in2out-worker-handoff",
     311             :   .vector_size = sizeof (u32),
     312             :   .format_trace = format_nat44_ei_handoff_trace,
     313             :   .type = VLIB_NODE_TYPE_INTERNAL,
     314             :   .n_errors = ARRAY_LEN (nat44_ei_handoff_error_strings),
     315             :   .error_strings = nat44_ei_handoff_error_strings,
     316             : };
     317             : 
     318       62744 : VLIB_REGISTER_NODE (nat44_ei_out2in_worker_handoff_node) = {
     319             :   .name = "nat44-ei-out2in-worker-handoff",
     320             :   .vector_size = sizeof (u32),
     321             :   .format_trace = format_nat44_ei_handoff_trace,
     322             :   .type = VLIB_NODE_TYPE_INTERNAL,
     323             :   .n_errors = ARRAY_LEN (nat44_ei_handoff_error_strings),
     324             :   .error_strings = nat44_ei_handoff_error_strings,
     325             : };
     326             : 
     327             : /*
     328             :  * fd.io coding-style-patch-verification: ON
     329             :  *
     330             :  * Local Variables:
     331             :  * eval: (c-set-style "gnu")
     332             :  * End:
     333             :  */

Generated by: LCOV version 1.14