LCOV - code coverage report
Current view: top level - vnet/mpls - mpls_output.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 219 221 99.1 %
Date: 2023-07-05 22:20:52 Functions: 28 37 75.7 %

          Line data    Source code
       1             : /*
       2             :  * mpls_output.c: MPLS Adj rewrite
       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/ip/ip.h>
      20             : #include <vnet/mpls/mpls.h>
      21             : #include <vnet/ip/ip_frag.h>
      22             : #include <vnet/adj/adj_dp.h>
      23             : #include <vnet/mpls/mpls.api_enum.h>
      24             : 
      25             : typedef struct {
      26             :   /* Adjacency taken. */
      27             :   u32 adj_index;
      28             :   u32 flow_hash;
      29             : } mpls_output_trace_t;
      30             : 
      31             : typedef enum {
      32             :   MPLS_OUTPUT_MODE,
      33             :   MPLS_OUTPUT_MIDCHAIN_MODE
      34             : }mpls_output_mode_t;
      35             : 
      36             : #define foreach_mpls_output_next                \
      37             : _(DROP, "error-drop")                           \
      38             : _(FRAG, "mpls-frag")
      39             : 
      40             : typedef enum {
      41             : #define _(s,n) MPLS_OUTPUT_NEXT_##s,
      42             :   foreach_mpls_output_next
      43             : #undef _
      44             :   MPLS_OUTPUT_N_NEXT,
      45             : } mpls_output_next_t;
      46             : 
      47             : static u8 *
      48        8510 : format_mpls_output_trace (u8 * s, va_list * args)
      49             : {
      50        8510 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      51        8510 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      52        8510 :   mpls_output_trace_t * t = va_arg (*args, mpls_output_trace_t *);
      53             : 
      54        8510 :   s = format (s, "adj-idx %d : %U flow hash: 0x%08x",
      55             :               t->adj_index,
      56             :               format_ip_adjacency, t->adj_index, FORMAT_IP_ADJACENCY_NONE,
      57             :               t->flow_hash);
      58        8510 :   return s;
      59             : }
      60             : 
      61             : static inline uword
      62         137 : mpls_output_inline (vlib_main_t * vm,
      63             :                     vlib_node_runtime_t * node,
      64             :                     vlib_frame_t * from_frame,
      65             :                     mpls_output_mode_t mode)
      66             : {
      67             :   u32 n_left_from, next_index, * from, * to_next, thread_index;
      68             :   vlib_node_runtime_t * error_node;
      69             :   u32 n_left_to_next;
      70             :   mpls_main_t *mm;
      71             : 
      72         137 :   thread_index = vlib_get_thread_index();
      73         137 :   error_node = vlib_node_get_runtime (vm, mpls_output_node.index);
      74         137 :   from = vlib_frame_vector_args (from_frame);
      75         137 :   n_left_from = from_frame->n_vectors;
      76         137 :   next_index = node->cached_next_index;
      77         137 :   mm = &mpls_main;
      78             : 
      79         277 :   while (n_left_from > 0)
      80             :     {
      81         140 :       vlib_get_next_frame (vm, node, next_index,
      82             :                            to_next, n_left_to_next);
      83             : 
      84        8265 :       while (n_left_from >= 4 && n_left_to_next >= 2)
      85             :         {
      86             :           ip_adjacency_t * adj0;
      87             :           mpls_unicast_header_t *hdr0;
      88             :           vlib_buffer_t * p0;
      89             :           u32 pi0, adj_index0, next0, error0;
      90             :           word rw_len0;
      91             : 
      92             :           ip_adjacency_t * adj1;
      93             :           mpls_unicast_header_t *hdr1;
      94             :           vlib_buffer_t * p1;
      95             :           u32 pi1, adj_index1, next1, error1;
      96             :           word rw_len1;
      97             : 
      98             :           /* Prefetch next iteration. */
      99             :           {
     100             :             vlib_buffer_t * p2, * p3;
     101             : 
     102        8125 :             p2 = vlib_get_buffer (vm, from[2]);
     103        8125 :             p3 = vlib_get_buffer (vm, from[3]);
     104             : 
     105        8125 :             vlib_prefetch_buffer_header (p2, STORE);
     106        8125 :             vlib_prefetch_buffer_header (p3, STORE);
     107             : 
     108        8125 :             CLIB_PREFETCH (p2->data, sizeof (hdr0[0]), STORE);
     109        8125 :             CLIB_PREFETCH (p3->data, sizeof (hdr1[0]), STORE);
     110             :           }
     111             : 
     112        8125 :           pi0 = to_next[0] = from[0];
     113        8125 :           pi1 = to_next[1] = from[1];
     114             : 
     115        8125 :           from += 2;
     116        8125 :           n_left_from -= 2;
     117        8125 :           to_next += 2;
     118        8125 :           n_left_to_next -= 2;
     119             : 
     120        8125 :           p0 = vlib_get_buffer (vm, pi0);
     121        8125 :           p1 = vlib_get_buffer (vm, pi1);
     122             : 
     123        8125 :           adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
     124        8125 :           adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
     125             : 
     126        8125 :           adj0 = adj_get(adj_index0);
     127        8125 :           adj1 = adj_get(adj_index1);
     128        8125 :           hdr0 = vlib_buffer_get_current (p0);
     129        8125 :           hdr1 = vlib_buffer_get_current (p1);
     130             : 
     131             :           /* Guess we are only writing on simple Ethernet header. */
     132        8125 :           vnet_rewrite_two_headers (adj0[0], adj1[0], hdr0, hdr1,
     133             :                                    sizeof (ethernet_header_t));
     134             : 
     135             :           /* Update packet buffer attributes/set output interface. */
     136        8125 :           rw_len0 = adj0[0].rewrite_header.data_bytes;
     137        8125 :           rw_len1 = adj1[0].rewrite_header.data_bytes;
     138        8125 :           vnet_buffer (p0)->mpls.save_rewrite_length = rw_len0;
     139        8125 :           vnet_buffer (p1)->mpls.save_rewrite_length = rw_len1;
     140             : 
     141             :           /* Bump the adj counters for packet and bytes */
     142        8125 :           vlib_increment_combined_counter
     143             :               (&adjacency_counters,
     144             :                thread_index,
     145             :                adj_index0,
     146             :                1,
     147        8125 :                vlib_buffer_length_in_chain (vm, p0) + rw_len0);
     148        8125 :           vlib_increment_combined_counter
     149             :               (&adjacency_counters,
     150             :                thread_index,
     151             :                adj_index1,
     152             :                1,
     153        8125 :                vlib_buffer_length_in_chain (vm, p1) + rw_len1);
     154             : 
     155             :           /* Check MTU of outgoing interface. */
     156        8125 :           if (PREDICT_TRUE(vlib_buffer_length_in_chain (vm, p0) <=
     157             :                            adj0[0].rewrite_header.max_l3_packet_bytes))
     158             :             {
     159        7617 :               vlib_buffer_advance(p0, -rw_len0);
     160             : 
     161        7617 :               vnet_buffer (p0)->sw_if_index[VLIB_TX] =
     162        7617 :                   adj0[0].rewrite_header.sw_if_index;
     163        7617 :               next0 = adj0[0].rewrite_header.next_index;
     164        7617 :               error0 = IP4_ERROR_NONE;
     165             : 
     166        7617 :               if (PREDICT_FALSE(adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
     167          96 :                 vnet_feature_arc_start (mm->output_feature_arc_index,
     168             :                                         adj0[0].rewrite_header.sw_if_index,
     169             :                                         &next0, p0);
     170             :             }
     171             :           else
     172             :             {
     173         508 :               error0 = IP4_ERROR_MTU_EXCEEDED;
     174         508 :               next0 = MPLS_OUTPUT_NEXT_FRAG;
     175         508 :               vlib_node_increment_counter (vm, mpls_output_node.index,
     176             :                                            MPLS_ERROR_PKTS_NEED_FRAG,
     177             :                                            1);
     178             :             }
     179        8125 :           if (PREDICT_TRUE(vlib_buffer_length_in_chain (vm, p1) <=
     180             :                            adj1[0].rewrite_header.max_l3_packet_bytes))
     181             :             {
     182        7617 :               vlib_buffer_advance(p1, -rw_len1);
     183             : 
     184        7617 :               vnet_buffer (p1)->sw_if_index[VLIB_TX] =
     185        7617 :                   adj1[0].rewrite_header.sw_if_index;
     186        7617 :               next1 = adj1[0].rewrite_header.next_index;
     187        7617 :               error1 = IP4_ERROR_NONE;
     188             : 
     189        7617 :               if (PREDICT_FALSE(adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
     190          96 :                 vnet_feature_arc_start (mm->output_feature_arc_index,
     191             :                                         adj1[0].rewrite_header.sw_if_index,
     192             :                                         &next1, p1);
     193             :             }
     194             :           else
     195             :             {
     196         508 :               error1 = IP4_ERROR_MTU_EXCEEDED;
     197         508 :               next1 = MPLS_OUTPUT_NEXT_FRAG;
     198         508 :               vlib_node_increment_counter (vm, mpls_output_node.index,
     199             :                                            MPLS_ERROR_PKTS_NEED_FRAG,
     200             :                                            1);
     201             :             }
     202        8125 :           if (mode == MPLS_OUTPUT_MIDCHAIN_MODE)
     203             :           {
     204        1327 :             adj_midchain_fixup (vm, adj0, p0, VNET_LINK_MPLS);
     205        1327 :             adj_midchain_fixup (vm, adj1, p1, VNET_LINK_MPLS);
     206             :           }
     207             : 
     208        8125 :           p0->error = error_node->errors[error0];
     209        8125 :           p1->error = error_node->errors[error1];
     210             : 
     211        8125 :           if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
     212             :             {
     213             :               mpls_output_trace_t *tr =
     214        8125 :                 vlib_add_trace (vm, node, p0, sizeof (*tr));
     215        8125 :               tr->adj_index = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
     216        8125 :               tr->flow_hash = vnet_buffer (p0)->ip.flow_hash;
     217             :             }
     218        8125 :           if (PREDICT_FALSE (p1->flags & VLIB_BUFFER_IS_TRACED))
     219             :             {
     220             :               mpls_output_trace_t *tr =
     221        8125 :                 vlib_add_trace (vm, node, p1, sizeof (*tr));
     222        8125 :               tr->adj_index = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
     223        8125 :               tr->flow_hash = vnet_buffer (p1)->ip.flow_hash;
     224             :             }
     225             : 
     226        8125 :           vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
     227             :                                            n_left_to_next, pi0, pi1, next0,
     228             :                                            next1);
     229             :         }
     230             : 
     231         383 :       while (n_left_from > 0 && n_left_to_next > 0)
     232             :         {
     233             :           ip_adjacency_t * adj0;
     234             :           mpls_unicast_header_t *hdr0;
     235             :           vlib_buffer_t * p0;
     236             :           u32 pi0, adj_index0, next0, error0;
     237             :           word rw_len0;
     238             : 
     239         243 :           pi0 = to_next[0] = from[0];
     240             : 
     241         243 :           p0 = vlib_get_buffer (vm, pi0);
     242             : 
     243         243 :           adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
     244             : 
     245         243 :           adj0 = adj_get(adj_index0);
     246         243 :           hdr0 = vlib_buffer_get_current (p0);
     247             : 
     248             :           /* Guess we are only writing on simple Ethernet header. */
     249         243 :           vnet_rewrite_one_header (adj0[0], hdr0,
     250             :                                    sizeof (ethernet_header_t));
     251             : 
     252             :           /* Update packet buffer attributes/set output interface. */
     253         243 :           rw_len0 = adj0[0].rewrite_header.data_bytes;
     254         243 :           vnet_buffer (p0)->mpls.save_rewrite_length = rw_len0;
     255             : 
     256         243 :           vlib_increment_combined_counter
     257             :               (&adjacency_counters,
     258             :                thread_index,
     259             :                adj_index0,
     260             :                1,
     261         243 :                vlib_buffer_length_in_chain (vm, p0) + rw_len0);
     262             : 
     263             :           /* Check MTU of outgoing interface. */
     264         243 :           if (PREDICT_TRUE(vlib_buffer_length_in_chain (vm, p0) <=
     265             :                            adj0[0].rewrite_header.max_l3_packet_bytes))
     266             :             {
     267         229 :               vlib_buffer_advance(p0, -rw_len0);
     268             : 
     269         229 :               vnet_buffer (p0)->sw_if_index[VLIB_TX] =
     270         229 :                   adj0[0].rewrite_header.sw_if_index;
     271         229 :               next0 = adj0[0].rewrite_header.next_index;
     272         229 :               error0 = IP4_ERROR_NONE;
     273             : 
     274         229 :               if (PREDICT_FALSE(adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
     275           9 :                 vnet_feature_arc_start (mm->output_feature_arc_index,
     276             :                                         adj0[0].rewrite_header.sw_if_index,
     277             :                                         &next0, p0);
     278             :             }
     279             :           else
     280             :             {
     281          14 :               error0 = IP4_ERROR_MTU_EXCEEDED;
     282          14 :               next0 = MPLS_OUTPUT_NEXT_FRAG;
     283          14 :               vlib_node_increment_counter (vm, mpls_output_node.index,
     284             :                                            MPLS_ERROR_PKTS_NEED_FRAG,
     285             :                                            1);
     286             :             }
     287         243 :           if (mode == MPLS_OUTPUT_MIDCHAIN_MODE)
     288             :           {
     289          39 :             adj_midchain_fixup (vm, adj0, p0, VNET_LINK_MPLS);
     290             :           }
     291             : 
     292         243 :           p0->error = error_node->errors[error0];
     293             : 
     294         243 :           from += 1;
     295         243 :           n_left_from -= 1;
     296         243 :           to_next += 1;
     297         243 :           n_left_to_next -= 1;
     298             : 
     299         243 :           if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED))
     300             :             {
     301         243 :               mpls_output_trace_t *tr = vlib_add_trace (vm, node,
     302             :                                                         p0, sizeof (*tr));
     303         243 :               tr->adj_index = vnet_buffer(p0)->ip.adj_index[VLIB_TX];
     304         243 :               tr->flow_hash = vnet_buffer(p0)->ip.flow_hash;
     305             :             }
     306             : 
     307         243 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     308             :                                            to_next, n_left_to_next,
     309             :                                            pi0, next0);
     310             :         }
     311             : 
     312         140 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     313             :     }
     314         137 :   vlib_node_increment_counter (vm, mpls_output_node.index,
     315             :                                MPLS_ERROR_PKTS_ENCAP,
     316         137 :                                from_frame->n_vectors);
     317             : 
     318         137 :   return from_frame->n_vectors;
     319             : }
     320             : 
     321        2352 : VLIB_NODE_FN (mpls_output_node) (vlib_main_t * vm,
     322             :              vlib_node_runtime_t * node,
     323             :              vlib_frame_t * from_frame)
     324             : {
     325         116 :     return (mpls_output_inline(vm, node, from_frame, MPLS_OUTPUT_MODE));
     326             : }
     327             : 
     328      178120 : VLIB_REGISTER_NODE (mpls_output_node) = {
     329             :   .name = "mpls-output",
     330             :   /* Takes a vector of packets. */
     331             :   .vector_size = sizeof (u32),
     332             :   .n_errors = MPLS_N_ERROR,
     333             :   .error_counters = mpls_error_counters,
     334             : 
     335             :   .n_next_nodes = MPLS_OUTPUT_N_NEXT,
     336             :   .next_nodes = {
     337             :         [MPLS_OUTPUT_NEXT_DROP] = "mpls-drop",
     338             :         [MPLS_OUTPUT_NEXT_FRAG] = "mpls-frag",
     339             :     },
     340             :   .format_trace = format_mpls_output_trace,
     341             : };
     342             : 
     343        2257 : VLIB_NODE_FN (mpls_midchain_node) (vlib_main_t * vm,
     344             :                vlib_node_runtime_t * node,
     345             :                vlib_frame_t * from_frame)
     346             : {
     347          21 :     return (mpls_output_inline(vm, node, from_frame, MPLS_OUTPUT_MIDCHAIN_MODE));
     348             : }
     349             : 
     350      178120 : VLIB_REGISTER_NODE (mpls_midchain_node) = {
     351             :   .name = "mpls-midchain",
     352             :   .vector_size = sizeof (u32),
     353             : 
     354             :   .n_errors = MPLS_N_ERROR,
     355             :   .error_counters = mpls_error_counters,
     356             : 
     357             :   .sibling_of = "mpls-output",
     358             :   .format_trace = format_mpls_output_trace,
     359             : };
     360             : 
     361             : typedef struct mpls_frag_trace_t_
     362             : {
     363             :     u16 pkt_size;
     364             :     u16 mtu;
     365             : } mpls_frag_trace_t;
     366             : 
     367             : typedef enum
     368             : {
     369             :   MPLS_FRAG_NEXT_REWRITE,
     370             :   MPLS_FRAG_NEXT_REWRITE_MIDCHAIN,
     371             :   MPLS_FRAG_NEXT_ICMP4_ERROR,
     372             :   MPLS_FRAG_NEXT_ICMP6_ERROR,
     373             :   MPLS_FRAG_NEXT_DROP,
     374             :   MPLS_FRAG_N_NEXT,
     375             : } mpls_frag_next_t;
     376             : 
     377             : static uword
     378          10 : mpls_frag (vlib_main_t * vm,
     379             :            vlib_node_runtime_t * node,
     380             :            vlib_frame_t * frame)
     381             : {
     382             :     u32 n_left_from, next_index, * from, * to_next, n_left_to_next, *frags;
     383             : 
     384          10 :     from = vlib_frame_vector_args (frame);
     385          10 :     n_left_from = frame->n_vectors;
     386          10 :     next_index = node->cached_next_index;
     387          10 :     frags = NULL;
     388             : 
     389          20 :     while (n_left_from > 0)
     390             :     {
     391          10 :         vlib_get_next_frame (vm, node, next_index,
     392             :                              to_next, n_left_to_next);
     393             : 
     394        1040 :         while (n_left_from > 0 && n_left_to_next > 0)
     395             :         {
     396             :             ip_adjacency_t * adj0;
     397             :             vlib_buffer_t * p0;
     398             :             mpls_frag_next_t next0;
     399             :             u32 pi0, adj_index0;
     400        1030 :             ip_frag_error_t error0 = IP_FRAG_ERROR_NONE;
     401             :             i16 encap_size, mtu;
     402             :             u8 is_ip4;
     403             : 
     404        1030 :             pi0 = to_next[0] = from[0];
     405        1030 :             p0 = vlib_get_buffer (vm, pi0);
     406        1030 :             from += 1;
     407        1030 :             n_left_from -= 1;
     408        1030 :             is_ip4 = vnet_buffer (p0)->mpls.pyld_proto == DPO_PROTO_IP4;
     409             : 
     410        1030 :             adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
     411        1030 :             adj0 = adj_get (adj_index0);
     412             : 
     413             :             /* the size of the MPLS stack */
     414        1030 :             encap_size = vnet_buffer (p0)->l3_hdr_offset - p0->current_data;
     415        1030 :             mtu = adj0->rewrite_header.max_l3_packet_bytes - encap_size;
     416             : 
     417             :             /* IP fragmentation */
     418        1030 :             if (is_ip4)
     419         771 :               error0 = ip4_frag_do_fragment (vm, pi0, mtu, encap_size, &frags);
     420             :             else
     421             :               {
     422         259 :                 if (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
     423             :                   {
     424             :                     /* only fragment locally generated IPv6 */
     425         257 :                     error0 = IP_FRAG_ERROR_DONT_FRAGMENT_SET;
     426             :                   }
     427             :                 else
     428             :                   {
     429             :                     error0 =
     430           2 :                       ip6_frag_do_fragment (vm, pi0, mtu, encap_size, &frags);
     431             :                   }
     432             :               }
     433             : 
     434        1030 :             if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
     435             :               {
     436             :                 mpls_frag_trace_t *tr =
     437        1030 :                   vlib_add_trace (vm, node, p0, sizeof (*tr));
     438        1030 :                 tr->mtu = mtu;
     439        1030 :                 tr->pkt_size = vlib_buffer_length_in_chain (vm, p0);
     440             :               }
     441             : 
     442        1030 :             if (PREDICT_TRUE (error0 == IP_FRAG_ERROR_NONE))
     443             :               {
     444             :                 /* Free original buffer chain */
     445         516 :                 vlib_buffer_free_one (vm, pi0);
     446         516 :                 next0 = (IP_LOOKUP_NEXT_MIDCHAIN == adj0->lookup_next_index ?
     447         516 :                            MPLS_FRAG_NEXT_REWRITE_MIDCHAIN :
     448             :                            MPLS_FRAG_NEXT_REWRITE);
     449             :               }
     450             :             else
     451             :               {
     452         514 :                 vlib_error_count (vm, node->node_index, error0, 1);
     453             : 
     454         514 :                 if (error0 == IP_FRAG_ERROR_DONT_FRAGMENT_SET)
     455             :                   {
     456         514 :                     vlib_buffer_advance (p0, encap_size);
     457         514 :                     if (is_ip4)
     458             :                       {
     459         257 :                         icmp4_error_set_vnet_buffer (
     460             :                           p0, ICMP4_destination_unreachable,
     461             :                           ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
     462             :                           mtu);
     463         257 :                         next0 = MPLS_FRAG_NEXT_ICMP4_ERROR;
     464             :                       }
     465             :                     else
     466             :                       {
     467         257 :                         icmp6_error_set_vnet_buffer (p0, ICMP6_packet_too_big,
     468             :                                                      0, mtu);
     469         257 :                         next0 = MPLS_FRAG_NEXT_ICMP6_ERROR;
     470             :                       }
     471             :                   }
     472             :                 else
     473             :                   {
     474           0 :                     next0 = MPLS_FRAG_NEXT_DROP;
     475             :                   }
     476             : 
     477             :                 /* Get rid of the original buffer */
     478         514 :                 vec_add1 (frags, pi0);
     479             :               }
     480             : 
     481             :             /* Send fragments that were added in the frame */
     482             :             u32 *frag_from, frag_left;
     483             : 
     484        1030 :             frag_from = frags;
     485        1030 :             frag_left = vec_len (frags);
     486             : 
     487        2064 :             while (frag_left > 0)
     488             :               {
     489        3353 :                 while (frag_left > 0 && n_left_to_next > 0)
     490             :                   {
     491             :                     u32 i;
     492        2319 :                     i = to_next[0] = frag_from[0];
     493        2319 :                     frag_from += 1;
     494        2319 :                     frag_left -= 1;
     495        2319 :                     to_next += 1;
     496        2319 :                     n_left_to_next -= 1;
     497             : 
     498        2319 :                     vlib_validate_buffer_enqueue_x1 (
     499             :                       vm, node, next_index, to_next, n_left_to_next, i, next0);
     500             :                   }
     501        1034 :                 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     502        1034 :                 vlib_get_next_frame (vm, node, next_index, to_next,
     503             :                                      n_left_to_next);
     504             :               }
     505        1030 :             vec_reset_length (frags);
     506             :         }
     507          10 :         vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     508             :     }
     509          10 :     vec_free (frags);
     510             : 
     511          10 :     return frame->n_vectors;
     512             : }
     513             : 
     514             : static u8 *
     515         716 : format_mpls_frag_trace (u8 * s, va_list * args)
     516             : {
     517         716 :     CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
     518         716 :     CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
     519         716 :     mpls_frag_trace_t *t = va_arg (*args, mpls_frag_trace_t *);
     520             : 
     521         716 :     s = format (s, "mtu:%d pkt-size:%d", t->mtu, t->pkt_size);
     522         716 :   return s;
     523             : }
     524             : 
     525      178120 : VLIB_REGISTER_NODE (mpls_frag_node) = {
     526             :   .function = mpls_frag,
     527             :   .name = "mpls-frag",
     528             :   .vector_size = sizeof (u32),
     529             :   .format_trace = format_mpls_frag_trace,
     530             :   .type = VLIB_NODE_TYPE_INTERNAL,
     531             : 
     532             :   .n_errors = IP_FRAG_N_ERROR,
     533             :   .error_counters = ip_frag_error_counters,
     534             : 
     535             :   .n_next_nodes = MPLS_FRAG_N_NEXT,
     536             :   .next_nodes = { [MPLS_FRAG_NEXT_REWRITE] = "mpls-output",
     537             :                   [MPLS_FRAG_NEXT_REWRITE_MIDCHAIN] = "mpls-midchain",
     538             :                   [MPLS_FRAG_NEXT_ICMP4_ERROR] = "ip4-icmp-error",
     539             :                   [MPLS_FRAG_NEXT_ICMP6_ERROR] = "ip6-icmp-error",
     540             :                   [MPLS_FRAG_NEXT_DROP] = "mpls-drop" },
     541             : };
     542             : 
     543             : /*
     544             :  * @brief Next index values from the MPLS incomplete adj node
     545             :  */
     546             : #define foreach_mpls_adj_incomplete_next        \
     547             : _(DROP, "error-drop")                   \
     548             : _(IP4,  "ip4-arp")                      \
     549             : _(IP6,  "ip6-discover-neighbor")
     550             : 
     551             : typedef enum {
     552             : #define _(s,n) MPLS_ADJ_INCOMPLETE_NEXT_##s,
     553             :   foreach_mpls_adj_incomplete_next
     554             : #undef _
     555             :   MPLS_ADJ_INCOMPLETE_N_NEXT,
     556             : } mpls_adj_incomplete_next_t;
     557             : 
     558             : /**
     559             :  * @brief A struct to hold tracing information for the MPLS label imposition
     560             :  * node.
     561             :  */
     562             : typedef struct mpls_adj_incomplete_trace_t_
     563             : {
     564             :     u32 next;
     565             : } mpls_adj_incomplete_trace_t;
     566             : 
     567             : 
     568             : /**
     569             :  * @brief Graph node for incomplete MPLS adjacency.
     570             :  * This node will push traffic to either the v4-arp or v6-nd node
     571             :  * based on the next-hop proto of the adj.
     572             :  * We pay a cost for this 'routing' node, but an incomplete adj is the
     573             :  * exception case.
     574             :  */
     575        2238 : VLIB_NODE_FN (mpls_adj_incomplete_node) (vlib_main_t * vm,
     576             :                      vlib_node_runtime_t * node,
     577             :                      vlib_frame_t * from_frame)
     578             : {
     579             :     u32 n_left_from, next_index, * from, * to_next;
     580             : 
     581           2 :   from = vlib_frame_vector_args (from_frame);
     582           2 :   n_left_from = from_frame->n_vectors;
     583           2 :   next_index = node->cached_next_index;
     584             : 
     585           4 :   while (n_left_from > 0)
     586             :     {
     587             :       u32 n_left_to_next;
     588             : 
     589           2 :       vlib_get_next_frame (vm, node, next_index,
     590             :                            to_next, n_left_to_next);
     591             : 
     592           4 :       while (n_left_from > 0 && n_left_to_next > 0)
     593             :         {
     594             :           u32 pi0, next0, adj_index0;
     595             :           ip_adjacency_t * adj0;
     596             :           vlib_buffer_t * p0;
     597             : 
     598           2 :           pi0 = to_next[0] = from[0];
     599           2 :           p0 = vlib_get_buffer (vm, pi0);
     600           2 :           from += 1;
     601           2 :           n_left_from -= 1;
     602           2 :           to_next += 1;
     603           2 :           n_left_to_next -= 1;
     604             : 
     605           2 :           adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
     606             : 
     607           2 :           adj0 = adj_get(adj_index0);
     608             : 
     609           2 :           if (PREDICT_TRUE(FIB_PROTOCOL_IP4 == adj0->ia_nh_proto))
     610             :           {
     611           2 :               next0 = MPLS_ADJ_INCOMPLETE_NEXT_IP4;
     612             :           }
     613             :           else
     614             :           {
     615           0 :               next0 = MPLS_ADJ_INCOMPLETE_NEXT_IP6;
     616             :           }
     617             : 
     618           2 :           if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED))
     619             :           {
     620             :               mpls_adj_incomplete_trace_t *tr =
     621           2 :                   vlib_add_trace (vm, node, p0, sizeof (*tr));
     622           2 :               tr->next = next0;
     623             :           }
     624             : 
     625           2 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     626             :                                            to_next, n_left_to_next,
     627             :                                            pi0, next0);
     628             :         }
     629             : 
     630           2 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     631             :     }
     632             : 
     633           2 :   return from_frame->n_vectors;
     634             : }
     635             : 
     636             : static u8 *
     637           1 : format_mpls_adj_incomplete_trace (u8 * s, va_list * args)
     638             : {
     639           1 :     CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
     640           1 :     CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
     641             :     mpls_adj_incomplete_trace_t * t;
     642             :     u32 indent;
     643             : 
     644           1 :     t = va_arg (*args, mpls_adj_incomplete_trace_t *);
     645           1 :     indent = format_get_indent (s);
     646             : 
     647           1 :     s = format (s, "%Unext:%d",
     648             :                 format_white_space, indent,
     649             :                 t->next);
     650           1 :     return (s);
     651             : }
     652             : 
     653      178120 : VLIB_REGISTER_NODE (mpls_adj_incomplete_node) = {
     654             :   .name = "mpls-adj-incomplete",
     655             :   .format_trace = format_mpls_adj_incomplete_trace,
     656             :   /* Takes a vector of packets. */
     657             :   .vector_size = sizeof (u32),
     658             :   .n_errors = MPLS_N_ERROR,
     659             :   .error_counters = mpls_error_counters,
     660             : 
     661             :   .n_next_nodes = MPLS_ADJ_INCOMPLETE_N_NEXT,
     662             :   .next_nodes = {
     663             : #define _(s,n) [MPLS_ADJ_INCOMPLETE_NEXT_##s] = n,
     664             :     foreach_mpls_adj_incomplete_next
     665             : #undef _
     666             :   },
     667             : };

Generated by: LCOV version 1.14