LCOV - code coverage report
Current view: top level - vnet/mpls - mpls_lookup.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 304 317 95.9 %
Date: 2023-07-05 22:20:52 Functions: 19 25 76.0 %

          Line data    Source code
       1             : /*
       2             :  * mpls_lookup.c: MPLS lookup
       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/mpls/mpls_lookup.h>
      20             : #include <vnet/fib/mpls_fib.h>
      21             : #include <vnet/dpo/load_balance_map.h>
      22             : #include <vnet/dpo/replicate_dpo.h>
      23             : #include <vnet/mpls/mpls.api_enum.h>
      24             : 
      25             : /**
      26             :  * The arc/edge from the MPLS lookup node to the MPLS replicate node
      27             :  */
      28             : #ifndef CLIB_MARCH_VARIANT
      29             : u32 mpls_lookup_to_replicate_edge;
      30             : #endif /* CLIB_MARCH_VARIANT */
      31             : 
      32             : typedef struct {
      33             :   u32 next_index;
      34             :   u32 lb_index;
      35             :   u32 lfib_index;
      36             :   u32 label_net_byte_order;
      37             :   u32 hash;
      38             : } mpls_lookup_trace_t;
      39             : 
      40             : static u8 *
      41        5317 : format_mpls_lookup_trace (u8 * s, va_list * args)
      42             : {
      43        5317 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      44        5317 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      45        5317 :   mpls_lookup_trace_t * t = va_arg (*args, mpls_lookup_trace_t *);
      46             : 
      47        5317 :   s = format (s, "MPLS: next [%d], lookup fib index %d, LB index %d hash %x "
      48             :               "label %d eos %d", 
      49             :               t->next_index, t->lfib_index, t->lb_index, t->hash,
      50             :               vnet_mpls_uc_get_label(
      51             :                   clib_net_to_host_u32(t->label_net_byte_order)),
      52             :               vnet_mpls_uc_get_s(
      53             :                   clib_net_to_host_u32(t->label_net_byte_order)));
      54        5317 :   return s;
      55             : }
      56             : 
      57        2352 : VLIB_NODE_FN (mpls_lookup_node) (vlib_main_t * vm,
      58             :              vlib_node_runtime_t * node,
      59             :              vlib_frame_t * from_frame)
      60             : {
      61         116 :   vlib_combined_counter_main_t * cm = &load_balance_main.lbm_to_counters;
      62             :   u32 n_left_from, next_index, * from, * to_next;
      63         116 :   mpls_main_t * mm = &mpls_main;
      64         116 :   u32 thread_index = vlib_get_thread_index();
      65             : 
      66         116 :   from = vlib_frame_vector_args (from_frame);
      67         116 :   n_left_from = from_frame->n_vectors;
      68         116 :   next_index = node->cached_next_index;
      69             : 
      70         232 :   while (n_left_from > 0)
      71             :     {
      72             :       u32 n_left_to_next;
      73             : 
      74         116 :       vlib_get_next_frame (vm, node, next_index,
      75             :                            to_next, n_left_to_next);
      76             : 
      77        2925 :       while (n_left_from >= 8 && n_left_to_next >= 4)
      78             :         {
      79             :           u32 lbi0, next0, lfib_index0, bi0, hash_c0;
      80             :           const mpls_unicast_header_t * h0;
      81             :           const load_balance_t *lb0;
      82             :           const dpo_id_t *dpo0;
      83             :           vlib_buffer_t * b0;
      84             :           u32 lbi1, next1, lfib_index1, bi1, hash_c1;
      85             :           const mpls_unicast_header_t * h1;
      86             :           const load_balance_t *lb1;
      87             :           const dpo_id_t *dpo1;
      88             :           vlib_buffer_t * b1;
      89             :           u32 lbi2, next2, lfib_index2, bi2, hash_c2;
      90             :           const mpls_unicast_header_t * h2;
      91             :           const load_balance_t *lb2;
      92             :           const dpo_id_t *dpo2;
      93             :           vlib_buffer_t * b2;
      94             :           u32 lbi3, next3, lfib_index3, bi3, hash_c3;
      95             :           const mpls_unicast_header_t * h3;
      96             :           const load_balance_t *lb3;
      97             :           const dpo_id_t *dpo3;
      98             :           vlib_buffer_t * b3;
      99             : 
     100             :            /* Prefetch next iteration. */
     101             :           {
     102             :               vlib_buffer_t *p4, *p5, *p6, *p7;
     103             : 
     104        2809 :             p4 = vlib_get_buffer (vm, from[4]);
     105        2809 :             p5 = vlib_get_buffer (vm, from[5]);
     106        2809 :             p6 = vlib_get_buffer (vm, from[6]);
     107        2809 :             p7 = vlib_get_buffer (vm, from[7]);
     108             : 
     109        2809 :             vlib_prefetch_buffer_header (p4, STORE);
     110        2809 :             vlib_prefetch_buffer_header (p5, STORE);
     111        2809 :             vlib_prefetch_buffer_header (p6, STORE);
     112        2809 :             vlib_prefetch_buffer_header (p7, STORE);
     113             : 
     114        2809 :             CLIB_PREFETCH (p4->data, sizeof (h0[0]), LOAD);
     115        2809 :             CLIB_PREFETCH (p5->data, sizeof (h0[0]), LOAD);
     116        2809 :             CLIB_PREFETCH (p6->data, sizeof (h0[0]), LOAD);
     117        2809 :             CLIB_PREFETCH (p7->data, sizeof (h0[0]), LOAD);
     118             :           }
     119             : 
     120        2809 :           bi0 = to_next[0] = from[0];
     121        2809 :           bi1 = to_next[1] = from[1];
     122        2809 :           bi2 = to_next[2] = from[2];
     123        2809 :           bi3 = to_next[3] = from[3];
     124             : 
     125        2809 :           from += 4;
     126        2809 :           n_left_from -= 4;
     127        2809 :           to_next += 4;
     128        2809 :           n_left_to_next -= 4;
     129             : 
     130        2809 :           b0 = vlib_get_buffer (vm, bi0);
     131        2809 :           b1 = vlib_get_buffer (vm, bi1);
     132        2809 :           b2 = vlib_get_buffer (vm, bi2);
     133        2809 :           b3 = vlib_get_buffer (vm, bi3);
     134        2809 :           h0 = vlib_buffer_get_current (b0);
     135        2809 :           h1 = vlib_buffer_get_current (b1);
     136        2809 :           h2 = vlib_buffer_get_current (b2);
     137        2809 :           h3 = vlib_buffer_get_current (b3);
     138             : 
     139        2809 :           lfib_index0 = vec_elt(mm->fib_index_by_sw_if_index,
     140             :                                 vnet_buffer(b0)->sw_if_index[VLIB_RX]);
     141        2809 :           lfib_index1 = vec_elt(mm->fib_index_by_sw_if_index,
     142             :                                 vnet_buffer(b1)->sw_if_index[VLIB_RX]);
     143        2809 :           lfib_index2 = vec_elt(mm->fib_index_by_sw_if_index,
     144             :                                 vnet_buffer(b2)->sw_if_index[VLIB_RX]);
     145        2809 :           lfib_index3 = vec_elt(mm->fib_index_by_sw_if_index,
     146             :                                 vnet_buffer(b3)->sw_if_index[VLIB_RX]);
     147             : 
     148        2809 :           lbi0 = mpls_fib_table_forwarding_lookup (lfib_index0, h0);
     149        2809 :           lbi1 = mpls_fib_table_forwarding_lookup (lfib_index1, h1);
     150        2809 :           lbi2 = mpls_fib_table_forwarding_lookup (lfib_index2, h2);
     151        2809 :           lbi3 = mpls_fib_table_forwarding_lookup (lfib_index3, h3);
     152             : 
     153        2809 :           hash_c0 = vnet_buffer(b0)->ip.flow_hash = 0;
     154        2809 :           hash_c1 = vnet_buffer(b1)->ip.flow_hash = 0;
     155        2809 :           hash_c2 = vnet_buffer(b2)->ip.flow_hash = 0;
     156        2809 :           hash_c3 = vnet_buffer(b3)->ip.flow_hash = 0;
     157             : 
     158        2809 :           if (MPLS_IS_REPLICATE & lbi0)
     159             :           {
     160         456 :               next0 = mpls_lookup_to_replicate_edge;
     161         456 :               vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
     162         456 :                   (lbi0 & ~MPLS_IS_REPLICATE);
     163             :           }
     164             :           else
     165             :           {
     166        2353 :               lb0 = load_balance_get(lbi0);
     167        2353 :               ASSERT (lb0->lb_n_buckets > 0);
     168        2353 :               ASSERT (is_pow2 (lb0->lb_n_buckets));
     169             : 
     170        2353 :               if (PREDICT_FALSE(lb0->lb_n_buckets > 1))
     171             :               {
     172         984 :                   hash_c0 = vnet_buffer (b0)->ip.flow_hash =
     173         492 :                       mpls_compute_flow_hash(h0, lb0->lb_hash_config);
     174         492 :                   dpo0 = load_balance_get_fwd_bucket
     175             :                       (lb0,
     176         492 :                        (hash_c0 & (lb0->lb_n_buckets_minus_1)));
     177             :               }
     178             :               else
     179             :               {
     180        1861 :                   dpo0 = load_balance_get_bucket_i (lb0, 0);
     181             :               }
     182        2353 :               next0 = dpo0->dpoi_next_node;
     183             : 
     184        2353 :               vnet_buffer (b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
     185             : 
     186        2353 :               vlib_increment_combined_counter
     187             :                   (cm, thread_index, lbi0, 1,
     188             :                    vlib_buffer_length_in_chain (vm, b0));
     189             :           }
     190        2809 :           if (MPLS_IS_REPLICATE & lbi1)
     191             :           {
     192         456 :               next1 = mpls_lookup_to_replicate_edge;
     193         456 :               vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
     194         456 :                   (lbi1 & ~MPLS_IS_REPLICATE);
     195             :           }
     196             :           else
     197             :           {
     198        2353 :               lb1 = load_balance_get(lbi1);
     199        2353 :               ASSERT (lb1->lb_n_buckets > 0);
     200        2353 :               ASSERT (is_pow2 (lb1->lb_n_buckets));
     201             : 
     202        2353 :               if (PREDICT_FALSE(lb1->lb_n_buckets > 1))
     203             :               {
     204         984 :                   hash_c1 = vnet_buffer (b1)->ip.flow_hash =
     205         492 :                       mpls_compute_flow_hash(h1, lb1->lb_hash_config);
     206         492 :                   dpo1 = load_balance_get_fwd_bucket
     207             :                       (lb1,
     208         492 :                        (hash_c1 & (lb1->lb_n_buckets_minus_1)));
     209             :               }
     210             :               else
     211             :               {
     212        1861 :                   dpo1 = load_balance_get_bucket_i (lb1, 0);
     213             :               }
     214        2353 :               next1 = dpo1->dpoi_next_node;
     215             : 
     216        2353 :               vnet_buffer (b1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
     217             : 
     218        2353 :               vlib_increment_combined_counter
     219             :                   (cm, thread_index, lbi1, 1,
     220             :                    vlib_buffer_length_in_chain (vm, b1));
     221             :           }
     222        2809 :           if (MPLS_IS_REPLICATE & lbi2)
     223             :           {
     224         456 :               next2 = mpls_lookup_to_replicate_edge;
     225         456 :               vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
     226         456 :                   (lbi2 & ~MPLS_IS_REPLICATE);
     227             :           }
     228             :           else
     229             :           {
     230        2353 :               lb2 = load_balance_get(lbi2);
     231        2353 :               ASSERT (lb2->lb_n_buckets > 0);
     232        2353 :               ASSERT (is_pow2 (lb2->lb_n_buckets));
     233             : 
     234        2353 :               if (PREDICT_FALSE(lb2->lb_n_buckets > 1))
     235             :               {
     236         984 :                   hash_c2 = vnet_buffer (b2)->ip.flow_hash =
     237         492 :                       mpls_compute_flow_hash(h2, lb2->lb_hash_config);
     238         492 :                   dpo2 = load_balance_get_fwd_bucket
     239             :                       (lb2,
     240         492 :                        (hash_c2 & (lb2->lb_n_buckets_minus_1)));
     241             :               }
     242             :               else
     243             :               {
     244        1861 :                   dpo2 = load_balance_get_bucket_i (lb2, 0);
     245             :               }
     246        2353 :               next2 = dpo2->dpoi_next_node;
     247             : 
     248        2353 :               vnet_buffer (b2)->ip.adj_index[VLIB_TX] = dpo2->dpoi_index;
     249             : 
     250        2353 :               vlib_increment_combined_counter
     251             :                   (cm, thread_index, lbi2, 1,
     252             :                    vlib_buffer_length_in_chain (vm, b2));
     253             :           }
     254        2809 :           if (MPLS_IS_REPLICATE & lbi3)
     255             :           {
     256         456 :               next3 = mpls_lookup_to_replicate_edge;
     257         456 :               vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
     258         456 :                   (lbi3 & ~MPLS_IS_REPLICATE);
     259             :           }
     260             :           else
     261             :           {
     262        2353 :               lb3 = load_balance_get(lbi3);
     263        2353 :               ASSERT (lb3->lb_n_buckets > 0);
     264        2353 :               ASSERT (is_pow2 (lb3->lb_n_buckets));
     265             : 
     266        2353 :               if (PREDICT_FALSE(lb3->lb_n_buckets > 1))
     267             :               {
     268         984 :                   hash_c3 = vnet_buffer (b3)->ip.flow_hash =
     269         492 :                       mpls_compute_flow_hash(h3, lb3->lb_hash_config);
     270         492 :                   dpo3 = load_balance_get_fwd_bucket
     271             :                       (lb3,
     272         492 :                        (hash_c3 & (lb3->lb_n_buckets_minus_1)));
     273             :               }
     274             :               else
     275             :               {
     276        1861 :                   dpo3 = load_balance_get_bucket_i (lb3, 0);
     277             :               }
     278        2353 :               next3 = dpo3->dpoi_next_node;
     279             : 
     280        2353 :               vnet_buffer (b3)->ip.adj_index[VLIB_TX] = dpo3->dpoi_index;
     281             : 
     282        2353 :               vlib_increment_combined_counter
     283             :                   (cm, thread_index, lbi3, 1,
     284             :                    vlib_buffer_length_in_chain (vm, b3));
     285             :           }
     286             : 
     287             :           /*
     288             :            * before we pop the label copy th values we need to maintain.
     289             :            * The label header is in network byte order.
     290             :            *  last byte is the TTL.
     291             :            *  bits 2 to 4 inclusive are the EXP bits
     292             :            */
     293        2809 :           vnet_buffer (b0)->mpls.ttl = ((char*)h0)[3];
     294        2809 :           vnet_buffer (b0)->mpls.exp = (((char*)h0)[2] & 0xe) >> 1;
     295        2809 :           vnet_buffer (b0)->mpls.first = 1;
     296        2809 :           vnet_buffer (b1)->mpls.ttl = ((char*)h1)[3];
     297        2809 :           vnet_buffer (b1)->mpls.exp = (((char*)h1)[2] & 0xe) >> 1;
     298        2809 :           vnet_buffer (b1)->mpls.first = 1;
     299        2809 :           vnet_buffer (b2)->mpls.ttl = ((char*)h2)[3];
     300        2809 :           vnet_buffer (b2)->mpls.exp = (((char*)h2)[2] & 0xe) >> 1;
     301        2809 :           vnet_buffer (b2)->mpls.first = 1;
     302        2809 :           vnet_buffer (b3)->mpls.ttl = ((char*)h3)[3];
     303        2809 :           vnet_buffer (b3)->mpls.exp = (((char*)h3)[2] & 0xe) >> 1;
     304        2809 :           vnet_buffer (b3)->mpls.first = 1;
     305             : 
     306             :           /*
     307             :            * pop the label that was just used in the lookup
     308             :            */
     309        2809 :           vlib_buffer_advance(b0, sizeof(*h0));
     310        2809 :           vlib_buffer_advance(b1, sizeof(*h1));
     311        2809 :           vlib_buffer_advance(b2, sizeof(*h2));
     312        2809 :           vlib_buffer_advance(b3, sizeof(*h3));
     313             : 
     314        2809 :           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
     315             :           {
     316        2809 :               mpls_lookup_trace_t *tr = vlib_add_trace (vm, node,
     317             :                                                         b0, sizeof (*tr));
     318        2809 :               tr->next_index = next0;
     319        2809 :               tr->lb_index = lbi0;
     320        2809 :               tr->lfib_index = lfib_index0;
     321        2809 :               tr->hash = hash_c0;
     322        2809 :               tr->label_net_byte_order = h0->label_exp_s_ttl;
     323             :           }
     324             : 
     325        2809 :           if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
     326             :           {
     327        2809 :               mpls_lookup_trace_t *tr = vlib_add_trace (vm, node,
     328             :                                                         b1, sizeof (*tr));
     329        2809 :               tr->next_index = next1;
     330        2809 :               tr->lb_index = lbi1;
     331        2809 :               tr->lfib_index = lfib_index1;
     332        2809 :               tr->hash = hash_c1;
     333        2809 :               tr->label_net_byte_order = h1->label_exp_s_ttl;
     334             :           }
     335             : 
     336        2809 :           if (PREDICT_FALSE(b2->flags & VLIB_BUFFER_IS_TRACED))
     337             :           {
     338        2809 :               mpls_lookup_trace_t *tr = vlib_add_trace (vm, node,
     339             :                                                         b2, sizeof (*tr));
     340        2809 :               tr->next_index = next2;
     341        2809 :               tr->lb_index = lbi2;
     342        2809 :               tr->lfib_index = lfib_index2;
     343        2809 :               tr->hash = hash_c2;
     344        2809 :               tr->label_net_byte_order = h2->label_exp_s_ttl;
     345             :           }
     346             : 
     347        2809 :           if (PREDICT_FALSE(b3->flags & VLIB_BUFFER_IS_TRACED))
     348             :           {
     349        2809 :               mpls_lookup_trace_t *tr = vlib_add_trace (vm, node,
     350             :                                                         b3, sizeof (*tr));
     351        2809 :               tr->next_index = next3;
     352        2809 :               tr->lb_index = lbi3;
     353        2809 :               tr->lfib_index = lfib_index3;
     354        2809 :               tr->hash = hash_c3;
     355        2809 :               tr->label_net_byte_order = h3->label_exp_s_ttl;
     356             :           }
     357             : 
     358        2809 :           vlib_validate_buffer_enqueue_x4 (vm, node, next_index,
     359             :                                            to_next, n_left_to_next,
     360             :                                            bi0, bi1, bi2, bi3,
     361             :                                            next0, next1, next2, next3);
     362             :         }
     363             : 
     364         520 :       while (n_left_from > 0 && n_left_to_next > 0)
     365             :       {
     366             :           u32 lbi0, next0, lfib_index0, bi0, hash_c0;
     367             :           const mpls_unicast_header_t * h0;
     368             :           const load_balance_t *lb0;
     369             :           const dpo_id_t *dpo0;
     370             :           vlib_buffer_t * b0;
     371             : 
     372         404 :           bi0 = from[0];
     373         404 :           to_next[0] = bi0;
     374         404 :           from += 1;
     375         404 :           to_next += 1;
     376         404 :           n_left_from -= 1;
     377         404 :           n_left_to_next -= 1;
     378             : 
     379         404 :           b0 = vlib_get_buffer (vm, bi0);
     380         404 :           h0 = vlib_buffer_get_current (b0);
     381             : 
     382         404 :           lfib_index0 = vec_elt(mm->fib_index_by_sw_if_index,
     383             :                                 vnet_buffer(b0)->sw_if_index[VLIB_RX]);
     384             : 
     385         404 :           lbi0 = mpls_fib_table_forwarding_lookup(lfib_index0, h0);
     386         404 :           hash_c0 = vnet_buffer(b0)->ip.flow_hash = 0;
     387             : 
     388         404 :           if (MPLS_IS_REPLICATE & lbi0)
     389             :           {
     390          41 :               next0 = mpls_lookup_to_replicate_edge;
     391          41 :               vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
     392          41 :                   (lbi0 & ~MPLS_IS_REPLICATE);
     393             :           }
     394             :           else
     395             :           {
     396         363 :               lb0 = load_balance_get(lbi0);
     397         363 :               ASSERT (lb0->lb_n_buckets > 0);
     398         363 :               ASSERT (is_pow2 (lb0->lb_n_buckets));
     399             : 
     400         363 :               if (PREDICT_FALSE(lb0->lb_n_buckets > 1))
     401             :               {
     402         280 :                   hash_c0 = vnet_buffer (b0)->ip.flow_hash =
     403         140 :                       mpls_compute_flow_hash(h0, lb0->lb_hash_config);
     404         140 :                   dpo0 = load_balance_get_fwd_bucket
     405             :                       (lb0,
     406         140 :                        (hash_c0 & (lb0->lb_n_buckets_minus_1)));
     407             :               }
     408             :               else
     409             :               {
     410         223 :                   dpo0 = load_balance_get_bucket_i (lb0, 0);
     411             :               }
     412         363 :               next0 = dpo0->dpoi_next_node;
     413         363 :               vnet_buffer (b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
     414             : 
     415         363 :               vlib_increment_combined_counter
     416             :                   (cm, thread_index, lbi0, 1,
     417             :                    vlib_buffer_length_in_chain (vm, b0));
     418             :           }
     419             : 
     420             :           /*
     421             :            * before we pop the label copy, values we need to maintain.
     422             :            * The label header is in network byte order.
     423             :            *  last byte is the TTL.
     424             :            *  bits 2 to 4 inclusive are the EXP bits
     425             :            */
     426         404 :           vnet_buffer (b0)->mpls.ttl = ((char*)h0)[3];
     427         404 :           vnet_buffer (b0)->mpls.exp = (((char*)h0)[2] & 0xe) >> 1;
     428         404 :           vnet_buffer (b0)->mpls.first = 1;
     429             : 
     430             :           /*
     431             :            * pop the label that was just used in the lookup
     432             :            */
     433         404 :           vlib_buffer_advance(b0, sizeof(*h0));
     434             : 
     435         404 :           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
     436             :           {
     437         404 :               mpls_lookup_trace_t *tr = vlib_add_trace (vm, node,
     438             :                                                         b0, sizeof (*tr));
     439         404 :               tr->next_index = next0;
     440         404 :               tr->lb_index = lbi0;
     441         404 :               tr->lfib_index = lfib_index0;
     442         404 :               tr->hash = hash_c0;
     443         404 :               tr->label_net_byte_order = h0->label_exp_s_ttl;
     444             :           }
     445             : 
     446         404 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     447             :                                            to_next, n_left_to_next,
     448             :                                            bi0, next0);
     449             :         }
     450             : 
     451         116 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     452             :     }
     453         116 :   vlib_node_increment_counter (vm, mm->mpls_lookup_node_index,
     454         116 :                                MPLS_ERROR_PKTS_DECAP, from_frame->n_vectors);
     455         116 :   return from_frame->n_vectors;
     456             : }
     457             : 
     458      178120 : VLIB_REGISTER_NODE (mpls_lookup_node) = {
     459             :   .name = "mpls-lookup",
     460             :   /* Takes a vector of packets. */
     461             :   .vector_size = sizeof (u32),
     462             :   .n_errors = MPLS_N_ERROR,
     463             :   .error_counters = mpls_error_counters,
     464             : 
     465             :   .sibling_of = "mpls-load-balance",
     466             : 
     467             :   .format_buffer = format_mpls_header,
     468             :   .format_trace = format_mpls_lookup_trace,
     469             :   .unformat_buffer = unformat_mpls_header,
     470             : };
     471             : 
     472             : typedef struct {
     473             :   u32 next_index;
     474             :   u32 lb_index;
     475             :   u32 hash;
     476             : } mpls_load_balance_trace_t;
     477             : 
     478             : static u8 *
     479        4701 : format_mpls_load_balance_trace (u8 * s, va_list * args)
     480             : {
     481        4701 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
     482        4701 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
     483        4701 :   mpls_load_balance_trace_t * t = va_arg (*args, mpls_load_balance_trace_t *);
     484             : 
     485        4701 :   s = format (s, "MPLS: next [%d], LB index %d hash %d",
     486             :               t->next_index, t->lb_index, t->hash);
     487        4701 :   return s;
     488             : }
     489             : 
     490        2308 : VLIB_NODE_FN (mpls_load_balance_node) (vlib_main_t * vm,
     491             :                   vlib_node_runtime_t * node,
     492             :                   vlib_frame_t * frame)
     493             : {
     494          72 :   vlib_combined_counter_main_t * cm = &load_balance_main.lbm_via_counters;
     495             :   u32 n_left_from, n_left_to_next, * from, * to_next;
     496          72 :   u32 thread_index = vlib_get_thread_index();
     497             :   u32 next;
     498             : 
     499          72 :   from = vlib_frame_vector_args (frame);
     500          72 :   n_left_from = frame->n_vectors;
     501          72 :   next = node->cached_next_index;
     502             : 
     503         144 :   while (n_left_from > 0)
     504             :     {
     505          72 :       vlib_get_next_frame (vm, node, next,
     506             :                            to_next, n_left_to_next);
     507             : 
     508             : 
     509        4201 :       while (n_left_from >= 4 && n_left_to_next >= 2)
     510             :         {
     511             :           const load_balance_t *lb0, *lb1;
     512             :           vlib_buffer_t * p0, *p1;
     513             :           u32 pi0, lbi0, hc0, pi1, lbi1, hc1, next0, next1;
     514             :           const mpls_unicast_header_t *mpls0, *mpls1;
     515             :           const dpo_id_t *dpo0, *dpo1;
     516             : 
     517             :           /* Prefetch next iteration. */
     518             :           {
     519             :             vlib_buffer_t * p2, * p3;
     520             : 
     521        4129 :             p2 = vlib_get_buffer (vm, from[2]);
     522        4129 :             p3 = vlib_get_buffer (vm, from[3]);
     523             : 
     524        4129 :             vlib_prefetch_buffer_header (p2, STORE);
     525        4129 :             vlib_prefetch_buffer_header (p3, STORE);
     526             : 
     527        4129 :             CLIB_PREFETCH (p2->data, sizeof (mpls0[0]), LOAD);
     528        4129 :             CLIB_PREFETCH (p3->data, sizeof (mpls0[0]), LOAD);
     529             :           }
     530             : 
     531        4129 :           pi0 = to_next[0] = from[0];
     532        4129 :           pi1 = to_next[1] = from[1];
     533             : 
     534        4129 :           from += 2;
     535        4129 :           n_left_from -= 2;
     536        4129 :           to_next += 2;
     537        4129 :           n_left_to_next -= 2;
     538             : 
     539        4129 :           p0 = vlib_get_buffer (vm, pi0);
     540        4129 :           p1 = vlib_get_buffer (vm, pi1);
     541             : 
     542        4129 :           mpls0 = vlib_buffer_get_current (p0);
     543        4129 :           mpls1 = vlib_buffer_get_current (p1);
     544        4129 :           lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
     545        4129 :           lbi1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
     546             : 
     547        4129 :           lb0 = load_balance_get(lbi0);
     548        4129 :           lb1 = load_balance_get(lbi1);
     549             : 
     550             :           /*
     551             :            * this node is for via FIBs we can re-use the hash value from the
     552             :            * to node if present.
     553             :            * We don't want to use the same hash value at each level in the recursion
     554             :            * graph as that would lead to polarisation
     555             :            */
     556        4129 :           hc0 = vnet_buffer (p0)->ip.flow_hash = 0;
     557        4129 :           hc1 = vnet_buffer (p1)->ip.flow_hash = 0;
     558             : 
     559        4129 :           if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
     560             :           {
     561           0 :               if (PREDICT_TRUE (vnet_buffer(p0)->ip.flow_hash))
     562             :               {
     563           0 :                   hc0 = vnet_buffer(p0)->ip.flow_hash = vnet_buffer(p0)->ip.flow_hash >> 1;
     564             :               }
     565             :               else
     566             :               {
     567           0 :                   hc0 = vnet_buffer(p0)->ip.flow_hash = mpls_compute_flow_hash(mpls0, hc0);
     568             :               }
     569           0 :               dpo0 = load_balance_get_fwd_bucket(lb0, (hc0 & lb0->lb_n_buckets_minus_1));
     570             :           }
     571             :           else
     572             :           {
     573        4129 :               dpo0 = load_balance_get_bucket_i (lb0, 0);
     574             :           }
     575        4129 :           if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
     576             :           {
     577           0 :               if (PREDICT_TRUE (vnet_buffer(p1)->ip.flow_hash))
     578             :               {
     579           0 :                   hc1 = vnet_buffer(p1)->ip.flow_hash = vnet_buffer(p1)->ip.flow_hash >> 1;
     580             :               }
     581             :               else
     582             :               {
     583           0 :                   hc1 = vnet_buffer(p1)->ip.flow_hash = mpls_compute_flow_hash(mpls1, hc1);
     584             :               }
     585           0 :               dpo1 = load_balance_get_fwd_bucket(lb1, (hc1 & lb1->lb_n_buckets_minus_1));
     586             :           }
     587             :           else
     588             :           {
     589        4129 :               dpo1 = load_balance_get_bucket_i (lb1, 0);
     590             :           }
     591             : 
     592        4129 :           next0 = dpo0->dpoi_next_node;
     593        4129 :           next1 = dpo1->dpoi_next_node;
     594             : 
     595        4129 :           vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
     596        4129 :           vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
     597             : 
     598        4129 :           vlib_increment_combined_counter
     599             :               (cm, thread_index, lbi0, 1,
     600             :                vlib_buffer_length_in_chain (vm, p0));
     601        4129 :           vlib_increment_combined_counter
     602             :               (cm, thread_index, lbi1, 1,
     603             :                vlib_buffer_length_in_chain (vm, p1));
     604             : 
     605        4129 :           if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED))
     606             :           {
     607        4129 :               mpls_load_balance_trace_t *tr = vlib_add_trace (vm, node,
     608             :                                                               p0, sizeof (*tr));
     609        4129 :               tr->next_index = next0;
     610        4129 :               tr->lb_index = lbi0;
     611        4129 :               tr->hash = hc0;
     612             :           }
     613        4129 :           if (PREDICT_FALSE(p1->flags & VLIB_BUFFER_IS_TRACED))
     614             :           {
     615        4129 :               mpls_load_balance_trace_t *tr = vlib_add_trace (vm, node,
     616             :                                                               p1, sizeof (*tr));
     617        4129 :               tr->next_index = next1;
     618        4129 :               tr->lb_index = lbi1;
     619        4129 :               tr->hash = hc1;
     620             :           }
     621             : 
     622        4129 :           vlib_validate_buffer_enqueue_x2 (vm, node, next,
     623             :                                            to_next, n_left_to_next,
     624             :                                            pi0, pi1, next0, next1);
     625             :        }
     626             : 
     627         201 :       while (n_left_from > 0 && n_left_to_next > 0)
     628             :         {
     629             :           const load_balance_t *lb0;
     630             :           vlib_buffer_t * p0;
     631             :           u32 pi0, lbi0, hc0, next0;
     632             :           const mpls_unicast_header_t *mpls0;
     633             :           const dpo_id_t *dpo0;
     634             : 
     635         129 :           pi0 = from[0];
     636         129 :           to_next[0] = pi0;
     637         129 :           from += 1;
     638         129 :           to_next += 1;
     639         129 :           n_left_to_next -= 1;
     640         129 :           n_left_from -= 1;
     641             : 
     642         129 :           p0 = vlib_get_buffer (vm, pi0);
     643             : 
     644         129 :           mpls0 = vlib_buffer_get_current (p0);
     645         129 :           lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
     646             : 
     647         129 :           lb0 = load_balance_get(lbi0);
     648             : 
     649         129 :           hc0 = vnet_buffer (p0)->ip.flow_hash = 0;
     650         129 :           if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
     651             :           {
     652           0 :               if (PREDICT_TRUE (vnet_buffer(p0)->ip.flow_hash))
     653             :               {
     654           0 :                   hc0 = vnet_buffer(p0)->ip.flow_hash = vnet_buffer(p0)->ip.flow_hash >> 1;
     655             :               }
     656             :               else
     657             :               {
     658           0 :                   hc0 = vnet_buffer(p0)->ip.flow_hash = mpls_compute_flow_hash(mpls0, hc0);
     659             :               }
     660           0 :                dpo0 = load_balance_get_fwd_bucket(lb0, (hc0 & lb0->lb_n_buckets_minus_1));
     661             :           }
     662             :           else
     663             :           {
     664         129 :               dpo0 = load_balance_get_bucket_i (lb0, 0);
     665             :           }
     666             : 
     667         129 :           next0 = dpo0->dpoi_next_node;
     668         129 :           vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
     669             : 
     670         129 :           if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED))
     671             :           {
     672         129 :               mpls_load_balance_trace_t *tr = vlib_add_trace (vm, node,
     673             :                                                               p0, sizeof (*tr));
     674         129 :               tr->next_index = next0;
     675         129 :               tr->lb_index = lbi0;
     676         129 :               tr->hash = hc0;
     677             :           }
     678             : 
     679         129 :           vlib_increment_combined_counter
     680             :               (cm, thread_index, lbi0, 1,
     681             :                vlib_buffer_length_in_chain (vm, p0));
     682             : 
     683         129 :           vlib_validate_buffer_enqueue_x1 (vm, node, next,
     684             :                                            to_next, n_left_to_next,
     685             :                                            pi0, next0);
     686             :         }
     687             : 
     688          72 :       vlib_put_next_frame (vm, node, next, n_left_to_next);
     689             :     }
     690             : 
     691          72 :   return frame->n_vectors;
     692             : }
     693             : 
     694      178120 : VLIB_REGISTER_NODE (mpls_load_balance_node) = {
     695             :   .name = "mpls-load-balance",
     696             :   .vector_size = sizeof (u32),
     697             :   .format_trace = format_mpls_load_balance_trace,
     698             :   .n_next_nodes = 1,
     699             :   .next_nodes =
     700             :   {
     701             :       [MPLS_LOOKUP_NEXT_DROP] = "mpls-drop",
     702             :   },
     703             : 
     704             : };
     705             : 
     706             : 
     707             : #ifndef CLIB_MARCH_VARIANT
     708             : static clib_error_t *
     709         559 : mpls_lookup_init (vlib_main_t * vm)
     710             : {
     711         559 :   mpls_main_t *mm = &mpls_main;
     712             :   clib_error_t * error;
     713         559 :   vlib_node_t *node = vlib_get_node_by_name (vm, (u8*)"mpls-lookup" );
     714             : 
     715         559 :   mm->mpls_lookup_node_index = node->index;
     716             : 
     717         559 :   if ((error = vlib_call_init_function (vm, mpls_init)))
     718           0 :     return error;
     719             : 
     720         559 :   mpls_lookup_to_replicate_edge =
     721         559 :       vlib_node_add_named_next(vm,
     722         559 :                                mm->mpls_lookup_node_index,
     723             :                                "mpls-replicate");
     724             : 
     725         559 :   return (NULL);
     726             : }
     727             : 
     728       62719 : VLIB_INIT_FUNCTION (mpls_lookup_init);
     729             : #endif /* CLIB_MARCH_VARIANT */

Generated by: LCOV version 1.14