LCOV - code coverage report
Current view: top level - vlib - punt_node.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 81 84 96.4 %
Date: 2023-10-26 01:39:38 Functions: 13 16 81.2 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2019 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/punt.h>
      17             : 
      18             : #define foreach_punt_error                     \
      19             :   _(DISPATCHED, "dispatched")                  \
      20             :   _(NO_REASON, "No such punt reason")          \
      21             :   _(NO_REG, "No registrations")                \
      22             :   _(REP_FAIL, "Replication Failure")
      23             : 
      24             : typedef enum punt_error_t_
      25             : {
      26             : #define _(v,s) PUNT_ERROR_##v,
      27             :   foreach_punt_error
      28             : #undef _
      29             :     PUNT_N_ERRORS,
      30             : } punt_error_t;
      31             : 
      32             : static char *punt_error_strings[] = {
      33             : #define _(v,s) [PUNT_ERROR_##v] = s,
      34             :   foreach_punt_error
      35             : #undef _
      36             : };
      37             : 
      38             : typedef enum punt_next_t_
      39             : {
      40             :   PUNT_NEXT_DROP,
      41             :   PUNT_N_NEXT,
      42             : } punt_next_t;
      43             : 
      44             : typedef struct punt_trace_t_
      45             : {
      46             :   vlib_punt_reason_t pt_reason;
      47             : } punt_trace_t;
      48             : 
      49             : /**
      50             :  * Per-thread clone vectors
      51             :  */
      52             : #ifndef CLIB_MARCH_VARIANT
      53             : u32 **punt_clones;
      54             : #else
      55             : extern u32 **punt_clones;
      56             : #endif
      57             : 
      58             : static u8 *
      59        1417 : format_punt_trace (u8 * s, va_list * args)
      60             : {
      61        1417 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      62        1417 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      63        1417 :   punt_trace_t *t = va_arg (*args, punt_trace_t *);
      64             : 
      65        1417 :   s = format (s, "reason: %U", format_vlib_punt_reason, t->pt_reason);
      66             : 
      67        1417 :   return s;
      68             : }
      69             : 
      70             : always_inline u32
      71         134 : punt_replicate (vlib_main_t * vm,
      72             :                 vlib_node_runtime_t * node,
      73             :                 u32 thread_index,
      74             :                 vlib_buffer_t * b0,
      75             :                 u32 bi0,
      76             :                 vlib_punt_reason_t pr0,
      77             :                 u32 * next_index,
      78             :                 u32 * n_left_to_next, u32 ** to_next, u32 * n_dispatched)
      79             : {
      80             :   /* multiple clients => replicate a copy to each */
      81             :   u16 n_clones0, n_cloned0, clone0;
      82             :   u32 ci0, next0;
      83             : 
      84         134 :   n_clones0 = vec_len (punt_dp_db[pr0]);
      85         134 :   vec_validate (punt_clones[thread_index], n_clones0);
      86             : 
      87         134 :   n_cloned0 = vlib_buffer_clone (vm, bi0,
      88         134 :                                  punt_clones[thread_index],
      89             :                                  n_clones0, 2 * CLIB_CACHE_LINE_BYTES);
      90             : 
      91         134 :   if (PREDICT_FALSE (n_cloned0 != n_clones0))
      92             :     {
      93           0 :       b0->error = node->errors[PUNT_ERROR_REP_FAIL];
      94             :     }
      95             : 
      96         268 :   for (clone0 = 1; clone0 < n_cloned0; clone0++)
      97             :     {
      98         134 :       ci0 = punt_clones[thread_index][clone0];
      99             : 
     100         134 :       *to_next[0] = ci0;
     101         134 :       *to_next += 1;
     102         134 :       *n_left_to_next -= 1;
     103             : 
     104         134 :       next0 = punt_dp_db[pr0][clone0];
     105             : 
     106         134 :       if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
     107             :         {
     108             :           vlib_buffer_t *c0;
     109             :           punt_trace_t *t;
     110             : 
     111         134 :           c0 = vlib_get_buffer (vm, ci0);
     112         134 :           t = vlib_add_trace (vm, node, c0, sizeof (*t));
     113         134 :           t->pt_reason = pr0;
     114             :         }
     115             : 
     116         134 :       vlib_validate_buffer_enqueue_x1 (vm, node, *next_index,
     117             :                                        *to_next, *n_left_to_next, ci0, next0);
     118             : 
     119             :       /* replications here always go to different next-nodes
     120             :        * so there's no need to check if the to_next frame
     121             :        * is full */
     122             :     }
     123         134 :   *n_dispatched = *n_dispatched + n_cloned0;
     124             : 
     125             :   /* The original buffer is the first clone */
     126         134 :   next0 = punt_dp_db[pr0][0];
     127             :   /*
     128             :    * Note: the original buffer is enqueued in punt_dispatch_node.
     129             :    * Don't do it here.
     130             :    *
     131             :    * *to_next[0] = bi0;
     132             :    */
     133         134 :   return next0;
     134             : }
     135             : 
     136             : always_inline u32
     137        1672 : punt_dispatch_one (vlib_main_t * vm,
     138             :                    vlib_node_runtime_t * node,
     139             :                    vlib_combined_counter_main_t * cm,
     140             :                    u32 thread_index,
     141             :                    u32 bi0,
     142             :                    u32 * next_index,
     143             :                    u32 * n_left_to_next, u32 ** to_next, u32 * n_dispatched)
     144             : {
     145             :   vlib_punt_reason_t pr0;
     146             :   vlib_buffer_t *b0;
     147             :   u32 next0;
     148             : 
     149        1672 :   b0 = vlib_get_buffer (vm, bi0);
     150        1672 :   pr0 = b0->punt_reason;
     151             : 
     152        1672 :   if (PREDICT_FALSE (pr0 >= vec_len (punt_dp_db)))
     153             :     {
     154           0 :       b0->error = node->errors[PUNT_ERROR_NO_REASON];
     155           0 :       next0 = PUNT_NEXT_DROP;
     156             :     }
     157             :   else
     158             :     {
     159        1672 :       vlib_increment_combined_counter
     160             :         (cm, thread_index, pr0, 1, vlib_buffer_length_in_chain (vm, b0));
     161             : 
     162        1672 :       if (PREDICT_TRUE (1 == vec_len (punt_dp_db[pr0])))
     163             :         {
     164             :           /*
     165             :            * one registered client => give it the packet
     166             :            * This is the most likely outcome.
     167             :            */
     168         143 :           next0 = punt_dp_db[pr0][0];
     169         143 :           *n_dispatched = *n_dispatched + 1;
     170             :         }
     171        1529 :       else if (0 == vec_len (punt_dp_db[pr0]))
     172             :         {
     173             :           /* no registered clients => drop */
     174        1395 :           next0 = PUNT_NEXT_DROP;
     175        1395 :           b0->error = node->errors[PUNT_ERROR_NO_REG];
     176             :         }
     177             :       else
     178             :         {
     179             :           /*
     180             :            * multiple registered clients => replicate
     181             :            */
     182         134 :           next0 = punt_replicate (vm, node, thread_index, b0, bi0, pr0,
     183             :                                   next_index, n_left_to_next, to_next,
     184             :                                   n_dispatched);
     185             :         }
     186             :     }
     187             : 
     188        1672 :   if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
     189             :     {
     190             :       punt_trace_t *t;
     191             : 
     192        1672 :       t = vlib_add_trace (vm, node, b0, sizeof (*t));
     193        1672 :       t->pt_reason = pr0;
     194             :     }
     195             : 
     196        1672 :   return (next0);
     197             : }
     198             : 
     199        2334 : VLIB_NODE_FN (punt_dispatch_node) (vlib_main_t * vm,
     200             :                                    vlib_node_runtime_t * node,
     201             :                                    vlib_frame_t * frame)
     202             : {
     203             :   u32 n_left_from, *from, *to_next, next_index, thread_index;
     204             :   vlib_combined_counter_main_t *cm;
     205             :   u32 n_dispatched;
     206             : 
     207          34 :   cm = &punt_counters;
     208          34 :   from = vlib_frame_vector_args (frame);
     209          34 :   n_left_from = frame->n_vectors;
     210          34 :   next_index = node->cached_next_index;
     211          34 :   thread_index = vlib_get_thread_index ();
     212          34 :   n_dispatched = 0;
     213             : 
     214          68 :   while (n_left_from > 0)
     215             :     {
     216             :       u32 n_left_to_next;
     217             : 
     218          34 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     219             : 
     220         828 :       while (n_left_from > 4 && n_left_to_next > 2)
     221             :         {
     222             :           punt_next_t next0, next1;
     223             :           u32 bi0, bi1;
     224             : 
     225             :           {
     226             :             vlib_buffer_t *b2, *b3;
     227             : 
     228         794 :             b2 = vlib_get_buffer (vm, from[2]);
     229         794 :             b3 = vlib_get_buffer (vm, from[3]);
     230             : 
     231         794 :             vlib_prefetch_buffer_header (b2, LOAD);
     232         794 :             vlib_prefetch_buffer_header (b3, LOAD);
     233             :           }
     234             : 
     235         794 :           bi0 = to_next[0] = from[0];
     236         794 :           bi1 = to_next[1] = from[1];
     237         794 :           from += 2;
     238         794 :           n_left_from -= 2;
     239             : 
     240         794 :           next0 = punt_dispatch_one (vm, node, cm, thread_index, bi0,
     241             :                                      &next_index, &n_left_to_next,
     242             :                                      &to_next, &n_dispatched);
     243         794 :           next1 = punt_dispatch_one (vm, node, cm, thread_index, bi1,
     244             :                                      &next_index, &n_left_to_next,
     245             :                                      &to_next, &n_dispatched);
     246             : 
     247         794 :           to_next += 2;
     248         794 :           n_left_to_next -= 2;
     249             : 
     250         794 :           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
     251             :                                            to_next, n_left_to_next,
     252             :                                            bi0, bi1, next0, next1);
     253             :         }
     254         118 :       while (n_left_from > 0 && n_left_to_next > 0)
     255             :         {
     256             :           punt_next_t next0;
     257             :           u32 bi0;
     258             : 
     259          84 :           bi0 = to_next[0] = from[0];
     260          84 :           from += 1;
     261          84 :           n_left_from -= 1;
     262             : 
     263          84 :           next0 = punt_dispatch_one (vm, node, cm, thread_index, bi0,
     264             :                                      &next_index, &n_left_to_next,
     265             :                                      &to_next, &n_dispatched);
     266             : 
     267          84 :           to_next += 1;
     268          84 :           n_left_to_next -= 1;
     269             : 
     270          84 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     271             :                                            to_next, n_left_to_next,
     272             :                                            bi0, next0);
     273             :         }
     274          34 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     275             :     }
     276             : 
     277          34 :   vlib_node_increment_counter (vm, node->node_index,
     278             :                                PUNT_ERROR_DISPATCHED, n_dispatched);
     279             : 
     280          34 :   return frame->n_vectors;
     281             : }
     282             : 
     283             : /* *INDENT-OFF* */
     284      183788 : VLIB_REGISTER_NODE (punt_dispatch_node) = {
     285             :   .name = "punt-dispatch",
     286             :   .vector_size = sizeof (u32),
     287             :   .format_trace = format_punt_trace,
     288             :   .n_errors = PUNT_N_ERRORS,
     289             :   .error_strings = punt_error_strings,
     290             :   .n_next_nodes = PUNT_N_NEXT,
     291             :   .next_nodes = {
     292             :     [PUNT_NEXT_DROP] = "drop",
     293             :   },
     294             : };
     295             : 
     296             : /* *INDENT-ON* */
     297             : 
     298             : #ifndef CLIB_MARCH_VARIANT
     299             : clib_error_t *
     300         575 : punt_node_init (vlib_main_t * vm)
     301             : {
     302         575 :   vec_validate (punt_clones, vlib_num_workers ());
     303             : 
     304         575 :   return NULL;
     305             : }
     306             : 
     307        3455 : VLIB_INIT_FUNCTION (punt_node_init);
     308             : #endif
     309             : 
     310             : /*
     311             :  * fd.io coding-style-patch-verification: ON
     312             :  *
     313             :  * Local Variables:
     314             :  * eval: (c-set-style "gnu")
     315             :  * End:
     316             :  */

Generated by: LCOV version 1.14