LCOV - code coverage report
Current view: top level - vnet/mpls - mpls_input.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 96 96 100.0 %
Date: 2023-10-26 01:39:38 Functions: 13 16 81.2 %

          Line data    Source code
       1             : /*
       2             :  * node.c: MPLS input
       3             :  *
       4             :  * Copyright (c) 2012-2014 Cisco and/or its affiliates.
       5             :  * Licensed under the Apache License, Version 2.0 (the "License");
       6             :  * you may not use this file except in compliance with the License.
       7             :  * You may obtain a copy of the License at:
       8             :  *
       9             :  *     http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  * Unless required by applicable law or agreed to in writing, software
      12             :  * distributed under the License is distributed on an "AS IS" BASIS,
      13             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  * See the License for the specific language governing permissions and
      15             :  * limitations under the License.
      16             :  */
      17             : 
      18             : #include <vlib/vlib.h>
      19             : #include <vnet/pg/pg.h>
      20             : #include <vnet/mpls/mpls.h>
      21             : #include <vnet/feature/feature.h>
      22             : #include <vnet/mpls/mpls.api_enum.h>
      23             : 
      24             : typedef struct {
      25             :   u32 next_index;
      26             :   u32 label_net_byte_order;
      27             : } mpls_input_trace_t;
      28             : 
      29             : #define foreach_mpls_input_next                 \
      30             : _(DROP, "error-drop")                           \
      31             : _(LOOKUP, "mpls-lookup")
      32             : 
      33             : typedef enum {
      34             : #define _(s,n) MPLS_INPUT_NEXT_##s,
      35             :   foreach_mpls_input_next
      36             : #undef _
      37             :   MPLS_INPUT_N_NEXT,
      38             : } mpls_input_next_t;
      39             : 
      40             : static u8 *
      41        5371 : format_mpls_input_trace (u8 * s, va_list * args)
      42             : {
      43        5371 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      44        5371 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      45        5371 :   mpls_input_trace_t * t = va_arg (*args, mpls_input_trace_t *);
      46             :   char * next_name;
      47             :   u32 label;
      48        5371 :   next_name = "BUG!";
      49        5371 :   label = clib_net_to_host_u32(t->label_net_byte_order);
      50             : 
      51             : #define _(a,b) if (t->next_index == MPLS_INPUT_NEXT_##a) next_name = b;
      52        5371 :   foreach_mpls_input_next;
      53             : #undef _
      54             : 
      55        5371 :   s = format (s, "MPLS: next %s[%d]  label %d ttl %d exp %d",
      56             :               next_name, t->next_index,
      57             :               vnet_mpls_uc_get_label(label),
      58             :               vnet_mpls_uc_get_ttl(label),
      59             :               vnet_mpls_uc_get_exp(label));
      60             : 
      61        5371 :   return s;
      62             : }
      63             : 
      64             : typedef struct {
      65             :   u32 last_label;
      66             :   u32 last_inner_fib_index;
      67             :   u32 last_outer_fib_index;
      68             :   mpls_main_t * mpls_main;
      69             : } mpls_input_runtime_t;
      70             : 
      71             : static inline uword
      72         121 : mpls_input_inline (vlib_main_t * vm,
      73             :                    vlib_node_runtime_t * node,
      74             :                    vlib_frame_t * from_frame)
      75             : {
      76             :   u32 n_left_from, next_index, * from, * to_next;
      77         121 :   mpls_main_t * mm = &mpls_main;
      78         121 :   u32 thread_index = vlib_get_thread_index();
      79             :   vlib_simple_counter_main_t * cm;
      80         121 :   vnet_main_t * vnm = vnet_get_main();
      81             : 
      82         121 :   from = vlib_frame_vector_args (from_frame);
      83         121 :   n_left_from = from_frame->n_vectors;
      84             : 
      85         121 :   next_index = node->cached_next_index;
      86             : 
      87         121 :   cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
      88             :                          VNET_INTERFACE_COUNTER_MPLS);
      89             : 
      90         242 :   while (n_left_from > 0)
      91             :     {
      92             :       u32 n_left_to_next;
      93             : 
      94         121 :       vlib_get_next_frame (vm, node, next_index,
      95             :                            to_next, n_left_to_next);
      96             : 
      97        5961 :       while (n_left_from >= 4 && n_left_to_next >= 2)
      98             :         {
      99             :           u32 bi0, next0, sw_if_index0;
     100             :           u32 bi1, next1, sw_if_index1;
     101             :           vlib_buffer_t *b0, *b1;
     102             :           char *h0, *h1;
     103             : 
     104             :           /* Prefetch next iteration. */
     105             :           {
     106             :               vlib_buffer_t * p2, * p3;
     107             : 
     108        5840 :               p2 = vlib_get_buffer (vm, from[2]);
     109        5840 :               p3 = vlib_get_buffer (vm, from[3]);
     110             : 
     111        5840 :               vlib_prefetch_buffer_header (p2, LOAD);
     112        5840 :               vlib_prefetch_buffer_header (p3, LOAD);
     113             : 
     114        5840 :               CLIB_PREFETCH (p2->data, sizeof (h0[0]), LOAD);
     115        5840 :               CLIB_PREFETCH (p3->data, sizeof (h1[0]), LOAD);
     116             :           }
     117             : 
     118        5840 :           bi0 = to_next[0] = from[0];
     119        5840 :           bi1 = to_next[1] = from[1];
     120             : 
     121        5840 :           from += 2;
     122        5840 :           to_next += 2;
     123        5840 :           n_left_from -= 2;
     124        5840 :           n_left_to_next -= 2;
     125             : 
     126        5840 :           b0 = vlib_get_buffer (vm, bi0);
     127        5840 :           b1 = vlib_get_buffer (vm, bi1);
     128             : 
     129        5840 :           h0 = vlib_buffer_get_current (b0);
     130        5840 :           h1 = vlib_buffer_get_current (b1);
     131             : 
     132        5840 :           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
     133        5840 :           sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
     134             : 
     135             :           /* TTL expired? */
     136        5840 :           if (PREDICT_FALSE(h0[3] == 0))
     137             :           {
     138         127 :               next0 = MPLS_INPUT_NEXT_DROP;
     139         127 :               b0->error = node->errors[MPLS_ERROR_TTL_EXPIRED];
     140             :           }
     141             :           else
     142             :           {
     143        5713 :               next0 = MPLS_INPUT_NEXT_LOOKUP;
     144        5713 :               vnet_feature_arc_start(mm->input_feature_arc_index,
     145             :                                      sw_if_index0, &next0, b0);
     146        5713 :               vlib_increment_simple_counter (cm, thread_index, sw_if_index0, 1);
     147             :           }
     148             : 
     149        5840 :           if (PREDICT_FALSE(h1[3] == 0))
     150             :           {
     151         127 :               next1 = MPLS_INPUT_NEXT_DROP;
     152         127 :               b1->error = node->errors[MPLS_ERROR_TTL_EXPIRED];
     153             :           }
     154             :           else
     155             :           {
     156        5713 :               next1 = MPLS_INPUT_NEXT_LOOKUP;
     157        5713 :               vnet_feature_arc_start(mm->input_feature_arc_index,
     158             :                                      sw_if_index1, &next1, b1);
     159        5713 :               vlib_increment_simple_counter (cm, thread_index, sw_if_index1, 1);
     160             :           }
     161             : 
     162        5840 :           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
     163             :           {
     164        5840 :               mpls_input_trace_t *tr = vlib_add_trace (vm, node,
     165             :                                                        b0, sizeof (*tr));
     166        5840 :               tr->next_index = next0;
     167        5840 :               tr->label_net_byte_order = *((u32*)h0);
     168             :           }
     169        5840 :           if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
     170             :           {
     171        5840 :               mpls_input_trace_t *tr = vlib_add_trace (vm, node,
     172             :                                                        b1, sizeof (*tr));
     173        5840 :               tr->next_index = next1;
     174        5840 :               tr->label_net_byte_order = *((u32*)h1);
     175             :           }
     176             : 
     177        5840 :           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
     178             :                                            to_next, n_left_to_next,
     179             :                                            bi0, bi1,
     180             :                                            next0, next1);
     181             :         }
     182             : 
     183         341 :       while (n_left_from > 0 && n_left_to_next > 0)
     184             :         {
     185             :           u32 sw_if_index0, next0, bi0;
     186             :           vlib_buffer_t * b0;
     187             :           char * h0;
     188             : 
     189         220 :           bi0 = from[0];
     190         220 :           to_next[0] = bi0;
     191         220 :           from += 1;
     192         220 :           to_next += 1;
     193         220 :           n_left_from -= 1;
     194         220 :           n_left_to_next -= 1;
     195             : 
     196         220 :           b0 = vlib_get_buffer (vm, bi0);
     197         220 :           h0 = vlib_buffer_get_current (b0);
     198         220 :           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
     199             : 
     200             :           /* TTL expired? */
     201         220 :           if (PREDICT_FALSE(h0[3] == 0))
     202             :            {
     203           3 :               next0 = MPLS_INPUT_NEXT_DROP;
     204           3 :               b0->error = node->errors[MPLS_ERROR_TTL_EXPIRED];
     205             :             }
     206             :           else
     207             :             {
     208         217 :               next0 = MPLS_INPUT_NEXT_LOOKUP;
     209         217 :               vnet_feature_arc_start(mm->input_feature_arc_index, sw_if_index0, &next0, b0);
     210         217 :               vlib_increment_simple_counter (cm, thread_index, sw_if_index0, 1);
     211             :             }
     212             : 
     213         220 :           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
     214             :             {
     215         220 :               mpls_input_trace_t *tr = vlib_add_trace (vm, node,
     216             :                                                        b0, sizeof (*tr));
     217         220 :               tr->next_index = next0;
     218         220 :               tr->label_net_byte_order = *(u32*)h0;
     219             :             }
     220             : 
     221         220 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     222             :                                            to_next, n_left_to_next,
     223             :                                            bi0, next0);
     224             :         }
     225             : 
     226         121 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     227             :     }
     228         121 :   vlib_node_increment_counter (vm, mpls_input_node.index,
     229         121 :                                MPLS_ERROR_PKTS_DECAP, from_frame->n_vectors);
     230         121 :   return from_frame->n_vectors;
     231             : }
     232             : 
     233        2421 : VLIB_NODE_FN (mpls_input_node) (vlib_main_t * vm,
     234             :             vlib_node_runtime_t * node,
     235             :             vlib_frame_t * from_frame)
     236             : {
     237         121 :   return mpls_input_inline (vm, node, from_frame);
     238             : }
     239             : 
     240      183788 : VLIB_REGISTER_NODE (mpls_input_node) = {
     241             :   .name = "mpls-input",
     242             :   /* Takes a vector of packets. */
     243             :   .vector_size = sizeof (u32),
     244             : 
     245             :   .runtime_data_bytes = sizeof(mpls_input_runtime_t),
     246             : 
     247             :   .n_errors = MPLS_N_ERROR,
     248             :   .error_counters = mpls_error_counters,
     249             : 
     250             :   .n_next_nodes = MPLS_INPUT_N_NEXT,
     251             :   .next_nodes = {
     252             : #define _(s,n) [MPLS_INPUT_NEXT_##s] = n,
     253             :     foreach_mpls_input_next
     254             : #undef _
     255             :   },
     256             : 
     257             :   .format_buffer = format_mpls_unicast_header_net_byte_order,
     258             :   .format_trace = format_mpls_input_trace,
     259             : };
     260             : 
     261             : #ifndef CLIB_MARCH_VARIANT
     262             : static void
     263         575 : mpls_setup_nodes (vlib_main_t * vm)
     264             : {
     265             :   pg_node_t * pn;
     266             : 
     267         575 :   pn = pg_get_node (mpls_input_node.index);
     268         575 :   pn->unformat_edit = unformat_pg_mpls_header;
     269             : 
     270         575 :   ethernet_register_input_type (vm, ETHERNET_TYPE_MPLS,
     271             :                                 mpls_input_node.index);
     272         575 : }
     273             : 
     274         575 : static clib_error_t * mpls_input_init (vlib_main_t * vm)
     275             : {
     276         575 :   mpls_setup_nodes (vm);
     277             : 
     278         575 :   return 0;
     279             : }
     280             : 
     281             : /* *INDENT-OFF* */
     282       64511 : VLIB_INIT_FUNCTION (mpls_input_init) =
     283             : {
     284             :   .runs_after = VLIB_INITS("mpls_init"),
     285             : };
     286             : /* *INDENT-ON* */
     287             : #endif /* CLIB_MARCH_VARIANT */

Generated by: LCOV version 1.14