LCOV - code coverage report
Current view: top level - vnet/dpo - lookup_dpo.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 488 541 90.2 %
Date: 2023-07-05 22:20:52 Functions: 56 59 94.9 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2016 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : 
      16             : #include <vnet/ip/ip.h>
      17             : #include <vnet/dpo/lookup_dpo.h>
      18             : #include <vnet/dpo/load_balance_map.h>
      19             : #include <vnet/mpls/mpls_lookup.h>
      20             : #include <vnet/fib/fib_table.h>
      21             : #include <vnet/fib/ip4_fib.h>
      22             : #include <vnet/fib/ip6_fib.h>
      23             : #include <vnet/fib/mpls_fib.h>
      24             : #include <vnet/mfib/mfib_table.h>
      25             : #include <vnet/mfib/ip4_mfib.h>
      26             : #include <vnet/mfib/ip6_mfib.h>
      27             : 
      28             : static const char *const lookup_input_names[] = LOOKUP_INPUTS;
      29             : static const char *const lookup_cast_names[] = LOOKUP_CASTS;
      30             : 
      31             : /**
      32             :  * If a packet encounters a lookup DPO more than the many times
      33             :  * then we assume there is a loop in the forward graph and drop the packet
      34             :  */
      35             : #define MAX_LUKPS_PER_PACKET 4
      36             : 
      37             : /**
      38             :  * @brief Enumeration of the lookup subtypes
      39             :  */
      40             : typedef enum lookup_sub_type_t_
      41             : {
      42             :     LOOKUP_SUB_TYPE_SRC,
      43             :     LOOKUP_SUB_TYPE_DST,
      44             :     LOOKUP_SUB_TYPE_DST_MCAST,
      45             :     LOOKUP_SUB_TYPE_DST_TABLE_FROM_INTERFACE,
      46             : } lookup_sub_type_t;
      47             : #define LOOKUP_SUB_TYPE_NUM (LOOKUP_SUB_TYPE_DST_TABLE_FROM_INTERFACE+1)
      48             : 
      49             : #define FOR_EACH_LOOKUP_SUB_TYPE(_st)                                   \
      50             :     for (_st = LOOKUP_SUB_TYPE_IP4_SRC; _st < LOOKUP_SUB_TYPE_NUM; _st++)
      51             : 
      52             : /**
      53             :  * @brief pool of all MPLS Label DPOs
      54             :  */
      55             : lookup_dpo_t *lookup_dpo_pool;
      56             : 
      57             : /**
      58             :  * @brief An array of registered DPO type values for the sub-types
      59             :  */
      60             : static dpo_type_t lookup_dpo_sub_types[LOOKUP_SUB_TYPE_NUM];
      61             : 
      62             : static lookup_dpo_t *
      63         299 : lookup_dpo_alloc (void)
      64             : {
      65             :     lookup_dpo_t *lkd;
      66             :     vlib_main_t *vm;
      67             :     u8 did_barrier_sync;
      68             : 
      69         299 :     dpo_pool_barrier_sync (vm, lookup_dpo_pool, did_barrier_sync);
      70         299 :     pool_get_aligned(lookup_dpo_pool, lkd, CLIB_CACHE_LINE_BYTES);
      71         299 :     dpo_pool_barrier_release (vm, did_barrier_sync);
      72             : 
      73         299 :     return (lkd);
      74             : }
      75             : 
      76             : static index_t
      77         299 : lookup_dpo_get_index (lookup_dpo_t *lkd)
      78             : {
      79         299 :     return (lkd - lookup_dpo_pool);
      80             : }
      81             : 
      82             : static void
      83         299 : lookup_dpo_add_or_lock_i (fib_node_index_t fib_index,
      84             :                           dpo_proto_t proto,
      85             :                           lookup_cast_t cast,
      86             :                           lookup_input_t input,
      87             :                           lookup_table_t table_config,
      88             :                           dpo_id_t *dpo)
      89             : {
      90             :     lookup_dpo_t *lkd;
      91             :     dpo_type_t type;
      92             : 
      93         299 :     lkd = lookup_dpo_alloc();
      94         299 :     lkd->lkd_fib_index = fib_index;
      95         299 :     lkd->lkd_proto = proto;
      96         299 :     lkd->lkd_input = input;
      97         299 :     lkd->lkd_table = table_config;
      98         299 :     lkd->lkd_cast  = cast;
      99             : 
     100             :     /*
     101             :      * use the input type to select the lookup sub-type
     102             :      */
     103         299 :     type = 0;
     104             : 
     105         299 :     switch (input)
     106             :     {
     107          19 :     case LOOKUP_INPUT_SRC_ADDR:
     108          19 :         type = lookup_dpo_sub_types[LOOKUP_SUB_TYPE_SRC];
     109          19 :         break;
     110         280 :     case LOOKUP_INPUT_DST_ADDR:
     111         280 :         switch (table_config)
     112             :         {
     113         196 :         case LOOKUP_TABLE_FROM_INPUT_INTERFACE:
     114         196 :             type = lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST_TABLE_FROM_INTERFACE];
     115         196 :             break;
     116          84 :         case LOOKUP_TABLE_FROM_CONFIG:
     117          84 :             type = lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST];
     118          84 :             break;
     119             :         }
     120         280 :         if (LOOKUP_MULTICAST == cast)
     121             :         {
     122           8 :             type = lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST_MCAST];
     123             :         }
     124             :     }
     125             : 
     126         299 :     if (0 == type)
     127             :     {
     128           0 :         dpo_reset(dpo);
     129             :     }
     130             :     else
     131             :     {
     132         299 :         dpo_set(dpo, type, proto, lookup_dpo_get_index(lkd));
     133             :     }
     134         299 : }
     135             : 
     136             : void
     137         297 : lookup_dpo_add_or_lock_w_fib_index (fib_node_index_t fib_index,
     138             :                                     dpo_proto_t proto,
     139             :                                     lookup_cast_t cast,
     140             :                                     lookup_input_t input,
     141             :                                     lookup_table_t table_config,
     142             :                                     dpo_id_t *dpo)
     143             : {
     144         297 :     if (LOOKUP_TABLE_FROM_CONFIG == table_config)
     145             :     {
     146         101 :         if (LOOKUP_UNICAST == cast)
     147             :         {
     148          93 :             fib_table_lock(fib_index,
     149          93 :                            dpo_proto_to_fib(proto),
     150             :                            FIB_SOURCE_RR);
     151             :         }
     152             :         else
     153             :         {
     154           8 :             mfib_table_lock(fib_index,
     155           8 :                             dpo_proto_to_fib(proto),
     156             :                             MFIB_SOURCE_RR);
     157             :         }
     158             :     }
     159         297 :     lookup_dpo_add_or_lock_i(fib_index, proto, cast, input, table_config, dpo);
     160         297 : }
     161             : 
     162             : void
     163           2 : lookup_dpo_add_or_lock_w_table_id (u32 table_id,
     164             :                                    dpo_proto_t proto,
     165             :                                    lookup_cast_t cast,
     166             :                                    lookup_input_t input,
     167             :                                    lookup_table_t table_config,
     168             :                                    dpo_id_t *dpo)
     169             : {
     170           2 :     fib_node_index_t fib_index = FIB_NODE_INDEX_INVALID;
     171             : 
     172           2 :     if (LOOKUP_TABLE_FROM_CONFIG == table_config)
     173             :     {
     174           2 :         if (LOOKUP_UNICAST == cast)
     175             :         {
     176             :             fib_index =
     177           2 :                 fib_table_find_or_create_and_lock(dpo_proto_to_fib(proto),
     178             :                                                   table_id,
     179             :                                                   FIB_SOURCE_RR);
     180             :         }
     181             :         else
     182             :         {
     183             :             fib_index =
     184           0 :                 mfib_table_find_or_create_and_lock(dpo_proto_to_fib(proto),
     185             :                                                    table_id,
     186             :                                                    MFIB_SOURCE_RR);
     187             :         }
     188             :     }
     189             : 
     190           2 :     ASSERT(FIB_NODE_INDEX_INVALID != fib_index);
     191           2 :     lookup_dpo_add_or_lock_i(fib_index, proto, cast, input, table_config, dpo);
     192           2 : }
     193             : 
     194             : u8*
     195         927 : format_lookup_dpo (u8 *s, va_list *args)
     196             : {
     197         927 :     index_t index = va_arg (*args, index_t);
     198             :     lookup_dpo_t *lkd;
     199             : 
     200         927 :     lkd = lookup_dpo_get(index);
     201             : 
     202         927 :     if (LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table)
     203             :     {
     204           0 :         s = format(s, "%s,%s lookup in interface's %U table",
     205           0 :                    lookup_input_names[lkd->lkd_input],
     206           0 :                    lookup_cast_names[lkd->lkd_cast],
     207           0 :                    format_dpo_proto, lkd->lkd_proto);
     208             :     }
     209             :     else
     210             :     {
     211         927 :         if (LOOKUP_UNICAST == lkd->lkd_cast)
     212             :         {
     213          62 :             s = format(s, "%s,%s lookup in %U",
     214          62 :                        lookup_input_names[lkd->lkd_input],
     215          62 :                        lookup_cast_names[lkd->lkd_cast],
     216             :                        format_fib_table_name, lkd->lkd_fib_index,
     217          62 :                        dpo_proto_to_fib(lkd->lkd_proto));
     218             :         }
     219             :         else
     220             :         {
     221         865 :             s = format(s, "%s,%s lookup in %U",
     222         865 :                        lookup_input_names[lkd->lkd_input],
     223         865 :                        lookup_cast_names[lkd->lkd_cast],
     224             :                        format_mfib_table_name, lkd->lkd_fib_index,
     225         865 :                        dpo_proto_to_fib(lkd->lkd_proto));
     226             :         }
     227             :     }
     228         927 :     return (s);
     229             : }
     230             : 
     231             : static void
     232        1637 : lookup_dpo_lock (dpo_id_t *dpo)
     233             : {
     234             :     lookup_dpo_t *lkd;
     235             : 
     236        1637 :     lkd = lookup_dpo_get(dpo->dpoi_index);
     237             : 
     238        1637 :     lkd->lkd_locks++;
     239        1637 : }
     240             : 
     241             : static void
     242        1574 : lookup_dpo_unlock (dpo_id_t *dpo)
     243             : {
     244             :     lookup_dpo_t *lkd;
     245             : 
     246        1574 :     lkd = lookup_dpo_get(dpo->dpoi_index);
     247             : 
     248        1574 :     lkd->lkd_locks--;
     249             : 
     250        1574 :     if (0 == lkd->lkd_locks)
     251             :     {
     252         241 :         if (LOOKUP_TABLE_FROM_CONFIG == lkd->lkd_table)
     253             :         {
     254          94 :             if (LOOKUP_UNICAST == lkd->lkd_cast)
     255             :             {
     256          91 :                 fib_table_unlock(lkd->lkd_fib_index,
     257          91 :                                  dpo_proto_to_fib(lkd->lkd_proto),
     258             :                                  FIB_SOURCE_RR);
     259             :             }
     260             :             else
     261             :             {
     262           3 :                 mfib_table_unlock(lkd->lkd_fib_index,
     263           3 :                                   dpo_proto_to_fib(lkd->lkd_proto),
     264             :                                   MFIB_SOURCE_RR);
     265             :             }
     266             :         }
     267         241 :         pool_put(lookup_dpo_pool, lkd);
     268             :     }
     269        1574 : }
     270             : 
     271             : /**
     272             :  * @brief Lookup trace  data
     273             :  */
     274             : typedef struct lookup_trace_t_
     275             : {
     276             :     union {
     277             :         ip46_address_t addr;
     278             :         mpls_unicast_header_t hdr;
     279             :     };
     280             :     fib_node_index_t fib_index;
     281             :     index_t lbi;
     282             : } lookup_trace_t;
     283             : 
     284             : 
     285             : always_inline uword
     286       40983 : lookup_dpo_ip4_inline (vlib_main_t * vm,
     287             :                        vlib_node_runtime_t * node,
     288             :                        vlib_frame_t * from_frame,
     289             :                        int input_src_addr,
     290             :                        int table_from_interface)
     291             : {
     292             :     u32 n_left_from, next_index, * from, * to_next;
     293       40983 :     u32 thread_index = vlib_get_thread_index();
     294       40983 :     vlib_combined_counter_main_t * cm = &load_balance_main.lbm_to_counters;
     295             : 
     296       40983 :     from = vlib_frame_vector_args (from_frame);
     297       40983 :     n_left_from = from_frame->n_vectors;
     298             : 
     299       40983 :     next_index = node->cached_next_index;
     300             : 
     301       81966 :     while (n_left_from > 0)
     302             :     {
     303             :         u32 n_left_to_next;
     304             : 
     305       40983 :         vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
     306             : 
     307      544397 :         while (n_left_from >= 4 && n_left_to_next > 2)
     308             :         {
     309             :             u32 bi0, lkdi0, lbi0, fib_index0, next0, hash_c0;
     310             :             flow_hash_config_t flow_hash_config0;
     311             :             const ip4_address_t *input_addr0;
     312             :             const load_balance_t *lb0;
     313             :             const lookup_dpo_t * lkd0;
     314             :             const ip4_header_t * ip0;
     315             :             const dpo_id_t *dpo0;
     316             :             vlib_buffer_t * b0;
     317             :             u32 bi1, lkdi1, lbi1, fib_index1, next1, hash_c1;
     318             :             flow_hash_config_t flow_hash_config1;
     319             :             const ip4_address_t *input_addr1;
     320             :             const load_balance_t *lb1;
     321             :             const lookup_dpo_t * lkd1;
     322             :             const ip4_header_t * ip1;
     323             :             const dpo_id_t *dpo1;
     324             :             vlib_buffer_t * b1;
     325             : 
     326             :             /* Prefetch next iteration. */
     327             :             {
     328             :                 vlib_buffer_t * p2, * p3;
     329             : 
     330      503414 :                 p2 = vlib_get_buffer (vm, from[2]);
     331      503414 :                 p3 = vlib_get_buffer (vm, from[3]);
     332             : 
     333      503414 :                 vlib_prefetch_buffer_header (p2, LOAD);
     334      503414 :                 vlib_prefetch_buffer_header (p3, LOAD);
     335             : 
     336      503414 :                 clib_prefetch_store (p2->data);
     337      503414 :                 clib_prefetch_store (p3->data);
     338             :             }
     339             : 
     340      503414 :             bi0 = from[0];
     341      503414 :             to_next[0] = bi0;
     342      503414 :             bi1 = from[1];
     343      503414 :             to_next[1] = bi1;
     344      503414 :             from += 2;
     345      503414 :             to_next += 2;
     346      503414 :             n_left_from -= 2;
     347      503414 :             n_left_to_next -= 2;
     348             : 
     349      503414 :             b0 = vlib_get_buffer (vm, bi0);
     350      503414 :             ip0 = vlib_buffer_get_current (b0);
     351      503414 :             b1 = vlib_get_buffer (vm, bi1);
     352      503414 :             ip1 = vlib_buffer_get_current (b1);
     353             : 
     354             :             /* dst lookup was done by ip4 lookup */
     355      503414 :             lkdi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
     356      503414 :             lkdi1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
     357      503414 :             lkd0 = lookup_dpo_get(lkdi0);
     358      503414 :             lkd1 = lookup_dpo_get(lkdi1);
     359             : 
     360             :             /*
     361             :              * choose between a lookup using the fib index in the DPO
     362             :              * or getting the FIB index from the interface.
     363             :              */
     364      503414 :             if (table_from_interface)
     365             :             {
     366             :                 fib_index0 =
     367         254 :                     ip4_fib_table_get_index_for_sw_if_index(
     368         254 :                         vnet_buffer(b0)->sw_if_index[VLIB_RX]);
     369             :                 fib_index1 =
     370         254 :                     ip4_fib_table_get_index_for_sw_if_index(
     371         254 :                         vnet_buffer(b1)->sw_if_index[VLIB_RX]);
     372             :             }
     373             :             else
     374             :             {
     375      503160 :                 fib_index0 = lkd0->lkd_fib_index;
     376      503160 :                 fib_index1 = lkd1->lkd_fib_index;
     377             :             }
     378             : 
     379             :             /*
     380             :              * choose between a source or destination address lookup in the table
     381             :              */
     382      503414 :             if (input_src_addr)
     383             :             {
     384         254 :                 input_addr0 = &ip0->src_address;
     385         254 :                 input_addr1 = &ip1->src_address;
     386             :             }
     387             :             else
     388             :             {
     389      503160 :                 input_addr0 = &ip0->dst_address;
     390      503160 :                 input_addr1 = &ip1->dst_address;
     391             :             }
     392             : 
     393             :             /* do lookup */
     394      503414 :             ip4_fib_forwarding_lookup_x2 (fib_index0, fib_index1, input_addr0,
     395             :                                           input_addr1, &lbi0, &lbi1);
     396      503414 :             lb0 = load_balance_get(lbi0);
     397      503414 :             lb1 = load_balance_get(lbi1);
     398             : 
     399      503414 :             vnet_buffer(b0)->sw_if_index[VLIB_TX] = fib_index0;
     400      503414 :             vnet_buffer(b1)->sw_if_index[VLIB_TX] = fib_index1;
     401             : 
     402             :             /* Use flow hash to compute multipath adjacency. */
     403      503414 :             hash_c0 = vnet_buffer (b0)->ip.flow_hash = 0;
     404      503414 :             hash_c1 = vnet_buffer (b1)->ip.flow_hash = 0;
     405             : 
     406      503414 :             if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
     407             :             {
     408           0 :                 flow_hash_config0 = lb0->lb_hash_config;
     409           0 :                 hash_c0 = vnet_buffer (b0)->ip.flow_hash =
     410           0 :                     ip4_compute_flow_hash (ip0, flow_hash_config0);
     411             :             }
     412             : 
     413      503414 :             if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
     414             :             {
     415           0 :                 flow_hash_config1 = lb1->lb_hash_config;
     416           0 :                 hash_c1 = vnet_buffer (b1)->ip.flow_hash =
     417           0 :                     ip4_compute_flow_hash (ip1, flow_hash_config1);
     418             :             }
     419             : 
     420      503414 :             dpo0 = load_balance_get_bucket_i(lb0,
     421             :                                              (hash_c0 &
     422      503414 :                                               (lb0->lb_n_buckets_minus_1)));
     423      503414 :             dpo1 = load_balance_get_bucket_i(lb1,
     424             :                                              (hash_c1 &
     425      503414 :                                               (lb1->lb_n_buckets_minus_1)));
     426             : 
     427      503414 :             next0 = dpo0->dpoi_next_node;
     428      503414 :             next1 = dpo1->dpoi_next_node;
     429      503414 :             vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
     430      503414 :             vnet_buffer(b1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
     431             : 
     432      503414 :             vlib_increment_combined_counter
     433             :                 (cm, thread_index, lbi0, 1,
     434             :                  vlib_buffer_length_in_chain (vm, b0));
     435      503414 :             vlib_increment_combined_counter
     436             :                 (cm, thread_index, lbi1, 1,
     437             :                  vlib_buffer_length_in_chain (vm, b1));
     438             : 
     439      503414 :             if (!(b0->flags & VNET_BUFFER_F_LOOP_COUNTER_VALID)) {
     440      502779 :                 vnet_buffer2(b0)->loop_counter = 0;
     441      502779 :                 b0->flags |= VNET_BUFFER_F_LOOP_COUNTER_VALID;
     442             :             }
     443      503414 :             if (!(b1->flags & VNET_BUFFER_F_LOOP_COUNTER_VALID)) {
     444      502779 :                 vnet_buffer2(b1)->loop_counter = 0;
     445      502779 :                 b1->flags |= VNET_BUFFER_F_LOOP_COUNTER_VALID;
     446             :             }
     447             : 
     448      503414 :             vnet_buffer2(b0)->loop_counter++;
     449      503414 :             vnet_buffer2(b1)->loop_counter++;
     450             : 
     451      503414 :             if (PREDICT_FALSE(vnet_buffer2(b0)->loop_counter > MAX_LUKPS_PER_PACKET))
     452         127 :                 next0 = IP_LOOKUP_NEXT_DROP;
     453      503414 :             if (PREDICT_FALSE(vnet_buffer2(b1)->loop_counter > MAX_LUKPS_PER_PACKET))
     454         127 :                 next1 = IP_LOOKUP_NEXT_DROP;
     455             : 
     456      503414 :             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
     457             :             {
     458        1850 :                 lookup_trace_t *tr = vlib_add_trace (vm, node,
     459             :                                                      b0, sizeof (*tr));
     460        1850 :                 tr->fib_index = fib_index0;
     461        1850 :                 tr->lbi = lbi0;
     462        1850 :                 tr->addr.ip4 = *input_addr0;
     463             :             }
     464      503414 :             if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
     465             :             {
     466        1850 :                 lookup_trace_t *tr = vlib_add_trace (vm, node,
     467             :                                                      b1, sizeof (*tr));
     468        1850 :                 tr->fib_index = fib_index1;
     469        1850 :                 tr->lbi = lbi1;
     470        1850 :                 tr->addr.ip4 = *input_addr1;
     471             :             }
     472             : 
     473      503414 :             vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
     474             :                                              to_next, n_left_to_next,
     475             :                                              bi0, bi1, next0, next1);
     476             :         }
     477             : 
     478      116961 :         while (n_left_from > 0 && n_left_to_next > 0)
     479             :         {
     480             :             u32 bi0, lkdi0, lbi0, fib_index0, next0, hash_c0;
     481             :             flow_hash_config_t flow_hash_config0;
     482             :             const ip4_address_t *input_addr;
     483             :             const load_balance_t *lb0;
     484             :             const lookup_dpo_t * lkd0;
     485             :             const ip4_header_t * ip0;
     486             :             const dpo_id_t *dpo0;
     487             :             vlib_buffer_t * b0;
     488             : 
     489       75978 :             bi0 = from[0];
     490       75978 :             to_next[0] = bi0;
     491       75978 :             from += 1;
     492       75978 :             to_next += 1;
     493       75978 :             n_left_from -= 1;
     494       75978 :             n_left_to_next -= 1;
     495             : 
     496       75978 :             b0 = vlib_get_buffer (vm, bi0);
     497       75978 :             ip0 = vlib_buffer_get_current (b0);
     498             : 
     499             :             /* dst lookup was done by ip4 lookup */
     500       75978 :             lkdi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
     501       75978 :             lkd0 = lookup_dpo_get(lkdi0);
     502             : 
     503             :             /*
     504             :              * choose between a lookup using the fib index in the DPO
     505             :              * or getting the FIB index from the interface.
     506             :              */
     507       75978 :             if (table_from_interface)
     508             :             {
     509             :                 fib_index0 =
     510           6 :                     ip4_fib_table_get_index_for_sw_if_index(
     511           6 :                         vnet_buffer(b0)->sw_if_index[VLIB_RX]);
     512             :             }
     513             :             else
     514             :             {
     515       75972 :                 fib_index0 = lkd0->lkd_fib_index;
     516             :             }
     517             : 
     518             :             /*
     519             :              * choose between a source or destination address lookup in the table
     520             :              */
     521       75978 :             if (input_src_addr)
     522             :             {
     523           6 :                 input_addr = &ip0->src_address;
     524             :             }
     525             :             else
     526             :             {
     527       75972 :                 input_addr = &ip0->dst_address;
     528             :             }
     529             : 
     530             :             /* do lookup */
     531       75978 :             lbi0 = ip4_fib_forwarding_lookup (fib_index0, input_addr);
     532       75978 :             lb0 = load_balance_get(lbi0);
     533             : 
     534       75978 :             vnet_buffer(b0)->sw_if_index[VLIB_TX] = fib_index0;
     535             : 
     536             :             /* Use flow hash to compute multipath adjacency. */
     537       75978 :             hash_c0 = vnet_buffer (b0)->ip.flow_hash = 0;
     538             : 
     539       75978 :             if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
     540             :             {
     541           0 :                 flow_hash_config0 = lb0->lb_hash_config;
     542           0 :                 hash_c0 = vnet_buffer (b0)->ip.flow_hash =
     543           0 :                     ip4_compute_flow_hash (ip0, flow_hash_config0);
     544             :             }
     545             : 
     546       75978 :             dpo0 = load_balance_get_bucket_i(lb0,
     547             :                                              (hash_c0 &
     548       75978 :                                               (lb0->lb_n_buckets_minus_1)));
     549             : 
     550       75978 :             next0 = dpo0->dpoi_next_node;
     551       75978 :             vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
     552             : 
     553       75978 :             vlib_increment_combined_counter
     554             :                 (cm, thread_index, lbi0, 1,
     555             :                  vlib_buffer_length_in_chain (vm, b0));
     556             : 
     557       75978 :             if (!(b0->flags & VNET_BUFFER_F_LOOP_COUNTER_VALID)) {
     558       75963 :                 vnet_buffer2(b0)->loop_counter = 0;
     559       75963 :                 b0->flags |= VNET_BUFFER_F_LOOP_COUNTER_VALID;
     560             :             }
     561             : 
     562       75978 :             vnet_buffer2(b0)->loop_counter++;
     563             : 
     564       75978 :             if (PREDICT_FALSE(vnet_buffer2(b0)->loop_counter > MAX_LUKPS_PER_PACKET))
     565           3 :                 next0 = IP_LOOKUP_NEXT_DROP;
     566             : 
     567       75978 :             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
     568             :             {
     569          67 :                 lookup_trace_t *tr = vlib_add_trace (vm, node,
     570             :                                                      b0, sizeof (*tr));
     571          67 :                 tr->fib_index = fib_index0;
     572          67 :                 tr->lbi = lbi0;
     573          67 :                 tr->addr.ip4 = *input_addr;
     574             :             }
     575             : 
     576       75978 :             vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
     577             :                                             n_left_to_next, bi0, next0);
     578             :         }
     579       40983 :         vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     580             :     }
     581       40983 :     return from_frame->n_vectors;
     582             : }
     583             : 
     584             : static u8 *
     585       27897 : format_lookup_trace (u8 * s, va_list * args)
     586             : {
     587       27897 :     CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
     588       27897 :     CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
     589       27897 :     lookup_trace_t * t = va_arg (*args, lookup_trace_t *);
     590       27897 :     u32 indent = format_get_indent (s);
     591       27897 :     s = format (s, "%U fib-index:%d addr:%U load-balance:%d",
     592             :                 format_white_space, indent,
     593             :                 t->fib_index,
     594             :                 format_ip46_address, &t->addr, IP46_TYPE_ANY,
     595             :                 t->lbi);
     596       27897 :     return s;
     597             : }
     598             : 
     599       41534 : VLIB_NODE_FN (lookup_ip4_dst_node) (vlib_main_t * vm,
     600             :                 vlib_node_runtime_t * node,
     601             :                 vlib_frame_t * from_frame)
     602             : {
     603       40975 :     return (lookup_dpo_ip4_inline(vm, node, from_frame, 0, 0));
     604             : }
     605             : 
     606      178120 : VLIB_REGISTER_NODE (lookup_ip4_dst_node) = {
     607             :     .name = "lookup-ip4-dst",
     608             :     .vector_size = sizeof (u32),
     609             :     .sibling_of = "ip4-lookup",
     610             :     .format_trace = format_lookup_trace,
     611             : };
     612             : 
     613         563 : VLIB_NODE_FN (lookup_ip4_dst_itf_node) (vlib_main_t * vm,
     614             :                     vlib_node_runtime_t * node,
     615             :                     vlib_frame_t * from_frame)
     616             : {
     617           4 :     return (lookup_dpo_ip4_inline(vm, node, from_frame, 0, 1));
     618             : }
     619             : 
     620      178120 : VLIB_REGISTER_NODE (lookup_ip4_dst_itf_node) = {
     621             :     .name = "lookup-ip4-dst-itf",
     622             :     .vector_size = sizeof (u32),
     623             :     .sibling_of = "ip4-lookup",
     624             :     .format_trace = format_lookup_trace,
     625             : };
     626             : 
     627         563 : VLIB_NODE_FN (lookup_ip4_src_node) (vlib_main_t * vm,
     628             :                 vlib_node_runtime_t * node,
     629             :                 vlib_frame_t * from_frame)
     630             : {
     631           4 :     return (lookup_dpo_ip4_inline(vm, node, from_frame, 1, 0));
     632             : }
     633             : 
     634      178120 : VLIB_REGISTER_NODE (lookup_ip4_src_node) = {
     635             :     .name = "lookup-ip4-src",
     636             :     .vector_size = sizeof (u32),
     637             :     .format_trace = format_lookup_trace,
     638             :     .sibling_of = "ip4-lookup",
     639             : };
     640             : 
     641             : always_inline uword
     642         168 : lookup_dpo_ip6_inline (vlib_main_t * vm,
     643             :                        vlib_node_runtime_t * node,
     644             :                        vlib_frame_t * from_frame,
     645             :                        int input_src_addr,
     646             :                        int table_from_interface)
     647             : {
     648         168 :     vlib_combined_counter_main_t * cm = &load_balance_main.lbm_to_counters;
     649             :     u32 n_left_from, next_index, * from, * to_next;
     650         168 :     u32 thread_index = vlib_get_thread_index();
     651             : 
     652         168 :     from = vlib_frame_vector_args (from_frame);
     653         168 :     n_left_from = from_frame->n_vectors;
     654             : 
     655         168 :     next_index = node->cached_next_index;
     656             : 
     657         336 :     while (n_left_from > 0)
     658             :     {
     659             :         u32 n_left_to_next;
     660             : 
     661         168 :         vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
     662             : 
     663        9693 :         while (n_left_from >= 4 && n_left_to_next > 2)
     664             :         {
     665             :             u32 bi0, lkdi0, lbi0, fib_index0, next0, hash_c0;
     666             :             flow_hash_config_t flow_hash_config0;
     667             :             const ip6_address_t *input_addr0;
     668             :             const load_balance_t *lb0;
     669             :             const lookup_dpo_t * lkd0;
     670             :             const ip6_header_t * ip0;
     671             :             const dpo_id_t *dpo0;
     672             :             vlib_buffer_t * b0;
     673             :             u32 bi1, lkdi1, lbi1, fib_index1, next1, hash_c1;
     674             :             flow_hash_config_t flow_hash_config1;
     675             :             const ip6_address_t *input_addr1;
     676             :             const load_balance_t *lb1;
     677             :             const lookup_dpo_t * lkd1;
     678             :             const ip6_header_t * ip1;
     679             :             const dpo_id_t *dpo1;
     680             :             vlib_buffer_t * b1;
     681             : 
     682             :             /* Prefetch next iteration. */
     683             :             {
     684             :                 vlib_buffer_t * p2, * p3;
     685             : 
     686        9525 :                 p2 = vlib_get_buffer (vm, from[2]);
     687        9525 :                 p3 = vlib_get_buffer (vm, from[3]);
     688             : 
     689        9525 :                 vlib_prefetch_buffer_header (p2, LOAD);
     690        9525 :                 vlib_prefetch_buffer_header (p3, LOAD);
     691             : 
     692        9525 :                 clib_prefetch_store (p2->data);
     693        9525 :                 clib_prefetch_store (p3->data);
     694             :             }
     695             : 
     696        9525 :             bi0 = from[0];
     697        9525 :             to_next[0] = bi0;
     698        9525 :             bi1 = from[1];
     699        9525 :             to_next[1] = bi1;
     700        9525 :             from += 2;
     701        9525 :             to_next += 2;
     702        9525 :             n_left_from -= 2;
     703        9525 :             n_left_to_next -= 2;
     704             : 
     705        9525 :             b0 = vlib_get_buffer (vm, bi0);
     706        9525 :             ip0 = vlib_buffer_get_current (b0);
     707        9525 :             b1 = vlib_get_buffer (vm, bi1);
     708        9525 :             ip1 = vlib_buffer_get_current (b1);
     709             : 
     710             :             /* dst lookup was done by ip6 lookup */
     711        9525 :             lkdi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
     712        9525 :             lkdi1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
     713        9525 :             lkd0 = lookup_dpo_get(lkdi0);
     714        9525 :             lkd1 = lookup_dpo_get(lkdi1);
     715             : 
     716             :             /*
     717             :              * choose between a lookup using the fib index in the DPO
     718             :              * or getting the FIB index from the interface.
     719             :              */
     720        9525 :             if (table_from_interface)
     721             :             {
     722             :                 fib_index0 =
     723         254 :                     ip6_fib_table_get_index_for_sw_if_index(
     724         254 :                         vnet_buffer(b0)->sw_if_index[VLIB_RX]);
     725             :                 fib_index1 =
     726         254 :                     ip6_fib_table_get_index_for_sw_if_index(
     727         254 :                         vnet_buffer(b1)->sw_if_index[VLIB_RX]);
     728             :             }
     729             :             else
     730             :             {
     731        9271 :                 fib_index0 = lkd0->lkd_fib_index;
     732        9271 :                 fib_index1 = lkd1->lkd_fib_index;
     733             :             }
     734             : 
     735             :             /*
     736             :              * choose between a source or destination address lookup in the table
     737             :              */
     738        9525 :             if (input_src_addr)
     739             :             {
     740         254 :                 input_addr0 = &ip0->src_address;
     741         254 :                 input_addr1 = &ip1->src_address;
     742             :             }
     743             :             else
     744             :             {
     745        9271 :                 input_addr0 = &ip0->dst_address;
     746        9271 :                 input_addr1 = &ip1->dst_address;
     747             :             }
     748             : 
     749             :             /* do src lookup */
     750        9525 :             lbi0 = ip6_fib_table_fwding_lookup(
     751             :                                                fib_index0,
     752             :                                                input_addr0);
     753        9525 :             lbi1 = ip6_fib_table_fwding_lookup(
     754             :                                                fib_index1,
     755             :                                                input_addr1);
     756        9525 :             lb0 = load_balance_get(lbi0);
     757        9525 :             lb1 = load_balance_get(lbi1);
     758             : 
     759        9525 :             vnet_buffer(b0)->sw_if_index[VLIB_TX] = fib_index0;
     760        9525 :             vnet_buffer(b1)->sw_if_index[VLIB_TX] = fib_index1;
     761             : 
     762             :             /* Use flow hash to compute multipath adjacency. */
     763        9525 :             hash_c0 = vnet_buffer (b0)->ip.flow_hash = 0;
     764        9525 :             hash_c1 = vnet_buffer (b1)->ip.flow_hash = 0;
     765             : 
     766        9525 :             if (!(b0->flags & VNET_BUFFER_F_LOOP_COUNTER_VALID)) {
     767        1016 :                 vnet_buffer2(b0)->loop_counter = 0;
     768        1016 :                 b0->flags |= VNET_BUFFER_F_LOOP_COUNTER_VALID;
     769             :             }
     770        9525 :             if (!(b1->flags & VNET_BUFFER_F_LOOP_COUNTER_VALID)) {
     771        1016 :                 vnet_buffer2(b1)->loop_counter = 0;
     772        1016 :                 b1->flags |= VNET_BUFFER_F_LOOP_COUNTER_VALID;
     773             :             }
     774             : 
     775        9525 :             vnet_buffer2(b0)->loop_counter++;
     776        9525 :             vnet_buffer2(b1)->loop_counter++;
     777             : 
     778        9525 :             if (PREDICT_FALSE(vnet_buffer2(b0)->loop_counter > MAX_LUKPS_PER_PACKET))
     779        8128 :                 next0 = IP_LOOKUP_NEXT_DROP;
     780        9525 :             if (PREDICT_FALSE(vnet_buffer2(b1)->loop_counter > MAX_LUKPS_PER_PACKET))
     781        8128 :                 next1 = IP_LOOKUP_NEXT_DROP;
     782             : 
     783        9525 :             if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
     784             :             {
     785           0 :                 flow_hash_config0 = lb0->lb_hash_config;
     786           0 :                 hash_c0 = vnet_buffer (b0)->ip.flow_hash =
     787           0 :                     ip6_compute_flow_hash (ip0, flow_hash_config0);
     788             :             }
     789             : 
     790        9525 :             if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
     791             :             {
     792           0 :                 flow_hash_config1 = lb1->lb_hash_config;
     793           0 :                 hash_c1 = vnet_buffer (b1)->ip.flow_hash =
     794           0 :                     ip6_compute_flow_hash (ip1, flow_hash_config1);
     795             :             }
     796             : 
     797        9525 :             dpo0 = load_balance_get_bucket_i(lb0,
     798             :                                              (hash_c0 &
     799        9525 :                                               (lb0->lb_n_buckets_minus_1)));
     800        9525 :             dpo1 = load_balance_get_bucket_i(lb1,
     801             :                                              (hash_c1 &
     802        9525 :                                               (lb1->lb_n_buckets_minus_1)));
     803             : 
     804        9525 :             next0 = dpo0->dpoi_next_node;
     805        9525 :             next1 = dpo1->dpoi_next_node;
     806        9525 :             vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
     807        9525 :             vnet_buffer(b1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
     808             : 
     809        9525 :             vlib_increment_combined_counter
     810             :                 (cm, thread_index, lbi0, 1,
     811             :                  vlib_buffer_length_in_chain (vm, b0));
     812        9525 :             vlib_increment_combined_counter
     813             :                 (cm, thread_index, lbi1, 1,
     814             :                  vlib_buffer_length_in_chain (vm, b1));
     815             : 
     816        9525 :             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
     817             :             {
     818        9525 :                 lookup_trace_t *tr = vlib_add_trace (vm, node,
     819             :                                                      b0, sizeof (*tr));
     820        9525 :                 tr->fib_index = fib_index0;
     821        9525 :                 tr->lbi = lbi0;
     822        9525 :                 tr->addr.ip6 = *input_addr0;
     823             :             }
     824        9525 :             if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
     825             :             {
     826        9525 :                 lookup_trace_t *tr = vlib_add_trace (vm, node,
     827             :                                                      b1, sizeof (*tr));
     828        9525 :                 tr->fib_index = fib_index1;
     829        9525 :                 tr->lbi = lbi1;
     830        9525 :                 tr->addr.ip6 = *input_addr1;
     831             :             }
     832        9525 :             vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
     833             :                                             n_left_to_next, bi0, bi1,
     834             :                                             next0, next1);
     835             :         }
     836         475 :         while (n_left_from > 0 && n_left_to_next > 0)
     837             :         {
     838             :             u32 bi0, lkdi0, lbi0, fib_index0, next0, hash_c0;
     839             :             flow_hash_config_t flow_hash_config0;
     840             :             const ip6_address_t *input_addr0;
     841             :             const load_balance_t *lb0;
     842             :             const lookup_dpo_t * lkd0;
     843             :             const ip6_header_t * ip0;
     844             :             const dpo_id_t *dpo0;
     845             :             vlib_buffer_t * b0;
     846             : 
     847         307 :             bi0 = from[0];
     848         307 :             to_next[0] = bi0;
     849         307 :             from += 1;
     850         307 :             to_next += 1;
     851         307 :             n_left_from -= 1;
     852         307 :             n_left_to_next -= 1;
     853             : 
     854         307 :             b0 = vlib_get_buffer (vm, bi0);
     855         307 :             ip0 = vlib_buffer_get_current (b0);
     856             : 
     857             :             /* dst lookup was done by ip6 lookup */
     858         307 :             lkdi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
     859         307 :             lkd0 = lookup_dpo_get(lkdi0);
     860             : 
     861             :             /*
     862             :              * choose between a lookup using the fib index in the DPO
     863             :              * or getting the FIB index from the interface.
     864             :              */
     865         307 :             if (table_from_interface)
     866             :             {
     867             :                 fib_index0 =
     868           6 :                     ip6_fib_table_get_index_for_sw_if_index(
     869           6 :                         vnet_buffer(b0)->sw_if_index[VLIB_RX]);
     870             :             }
     871             :             else
     872             :             {
     873         301 :                 fib_index0 = lkd0->lkd_fib_index;
     874             :             }
     875             : 
     876             :             /*
     877             :              * choose between a source or destination address lookup in the table
     878             :              */
     879         307 :             if (input_src_addr)
     880             :             {
     881           6 :                 input_addr0 = &ip0->src_address;
     882             :             }
     883             :             else
     884             :             {
     885         301 :                 input_addr0 = &ip0->dst_address;
     886             :             }
     887             : 
     888             :             /* do src lookup */
     889         307 :             lbi0 = ip6_fib_table_fwding_lookup(
     890             :                                                fib_index0,
     891             :                                                input_addr0);
     892         307 :             lb0 = load_balance_get(lbi0);
     893             : 
     894         307 :             vnet_buffer(b0)->sw_if_index[VLIB_TX] = fib_index0;
     895             : 
     896             :             /* Use flow hash to compute multipath adjacency. */
     897         307 :             hash_c0 = vnet_buffer (b0)->ip.flow_hash = 0;
     898             : 
     899         307 :             if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
     900             :             {
     901           0 :                 flow_hash_config0 = lb0->lb_hash_config;
     902           0 :                 hash_c0 = vnet_buffer (b0)->ip.flow_hash =
     903           0 :                     ip6_compute_flow_hash (ip0, flow_hash_config0);
     904             :             }
     905             : 
     906         307 :             dpo0 = load_balance_get_bucket_i(lb0,
     907             :                                              (hash_c0 &
     908         307 :                                               (lb0->lb_n_buckets_minus_1)));
     909             : 
     910         307 :             next0 = dpo0->dpoi_next_node;
     911         307 :             vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
     912             : 
     913         307 :             if (!(b0->flags & VNET_BUFFER_F_LOOP_COUNTER_VALID)) {
     914          41 :                 vnet_buffer2(b0)->loop_counter = 0;
     915          41 :                 b0->flags |= VNET_BUFFER_F_LOOP_COUNTER_VALID;
     916             :             }
     917             : 
     918         307 :             vnet_buffer2(b0)->loop_counter++;
     919             : 
     920         307 :             if (PREDICT_FALSE(vnet_buffer2(b0)->loop_counter > MAX_LUKPS_PER_PACKET))
     921         257 :                 next0 = IP_LOOKUP_NEXT_DROP;
     922             : 
     923         307 :             vlib_increment_combined_counter
     924             :                 (cm, thread_index, lbi0, 1,
     925             :                  vlib_buffer_length_in_chain (vm, b0));
     926             : 
     927         307 :             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
     928             :             {
     929         290 :                 lookup_trace_t *tr = vlib_add_trace (vm, node,
     930             :                                                      b0, sizeof (*tr));
     931         290 :                 tr->fib_index = fib_index0;
     932         290 :                 tr->lbi = lbi0;
     933         290 :                 tr->addr.ip6 = *input_addr0;
     934             :             }
     935         307 :             vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
     936             :                                             n_left_to_next, bi0, next0);
     937             :         }
     938         168 :         vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     939             :     }
     940         168 :     return from_frame->n_vectors;
     941             : }
     942             : 
     943         719 : VLIB_NODE_FN (lookup_ip6_dst_node) (vlib_main_t * vm,
     944             :                 vlib_node_runtime_t * node,
     945             :                 vlib_frame_t * from_frame)
     946             : {
     947         160 :     return (lookup_dpo_ip6_inline(vm, node, from_frame, 0 /*use src*/, 0));
     948             : }
     949             : 
     950      178120 : VLIB_REGISTER_NODE (lookup_ip6_dst_node) = {
     951             :     .name = "lookup-ip6-dst",
     952             :     .vector_size = sizeof (u32),
     953             :     .format_trace = format_lookup_trace,
     954             :     .sibling_of = "ip6-lookup",
     955             : };
     956             : 
     957         563 : VLIB_NODE_FN (lookup_ip6_dst_itf_node) (vlib_main_t * vm,
     958             :                     vlib_node_runtime_t * node,
     959             :                     vlib_frame_t * from_frame)
     960             : {
     961           4 :     return (lookup_dpo_ip6_inline(vm, node, from_frame, 0 /*use src*/, 1));
     962             : }
     963             : 
     964      178120 : VLIB_REGISTER_NODE (lookup_ip6_dst_itf_node) = {
     965             :     .name = "lookup-ip6-dst-itf",
     966             :     .vector_size = sizeof (u32),
     967             :     .format_trace = format_lookup_trace,
     968             :     .sibling_of = "ip6-lookup",
     969             : };
     970             : 
     971         563 : VLIB_NODE_FN (lookup_ip6_src_node) (vlib_main_t * vm,
     972             :                 vlib_node_runtime_t * node,
     973             :                 vlib_frame_t * from_frame)
     974             : {
     975           4 :     return (lookup_dpo_ip6_inline(vm, node, from_frame, 1, 0));
     976             : }
     977             : 
     978      178120 : VLIB_REGISTER_NODE (lookup_ip6_src_node) = {
     979             :     .name = "lookup-ip6-src",
     980             :     .vector_size = sizeof (u32),
     981             :     .format_trace = format_lookup_trace,
     982             :     .sibling_of = "ip6-lookup",
     983             : };
     984             : 
     985             : always_inline uword
     986           2 : lookup_dpo_mpls_inline (vlib_main_t * vm,
     987             :                        vlib_node_runtime_t * node,
     988             :                        vlib_frame_t * from_frame,
     989             :                        int table_from_interface)
     990             : {
     991             :     u32 n_left_from, next_index, * from, * to_next;
     992           2 :     u32 thread_index = vlib_get_thread_index();
     993           2 :     vlib_combined_counter_main_t * cm = &load_balance_main.lbm_to_counters;
     994             : 
     995           2 :     from = vlib_frame_vector_args (from_frame);
     996           2 :     n_left_from = from_frame->n_vectors;
     997             : 
     998           2 :     next_index = node->cached_next_index;
     999             : 
    1000           4 :     while (n_left_from > 0)
    1001             :     {
    1002             :         u32 n_left_to_next;
    1003             : 
    1004           2 :         vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
    1005             : 
    1006             :         /* while (n_left_from >= 4 && n_left_to_next >= 2) */
    1007             :         /*   } */
    1008             : 
    1009         259 :         while (n_left_from > 0 && n_left_to_next > 0)
    1010             :         {
    1011             :             u32 bi0, lkdi0, lbi0, fib_index0, next0, hash0;
    1012             :             const mpls_unicast_header_t * hdr0;
    1013             :             const load_balance_t *lb0;
    1014             :             const lookup_dpo_t * lkd0;
    1015             :             const dpo_id_t *dpo0;
    1016             :             vlib_buffer_t * b0;
    1017             : 
    1018         257 :             bi0 = from[0];
    1019         257 :             to_next[0] = bi0;
    1020         257 :             from += 1;
    1021         257 :             to_next += 1;
    1022         257 :             n_left_from -= 1;
    1023         257 :             n_left_to_next -= 1;
    1024             : 
    1025         257 :             b0 = vlib_get_buffer (vm, bi0);
    1026         257 :             hdr0 = vlib_buffer_get_current (b0);
    1027             : 
    1028             :             /* dst lookup was done by mpls lookup */
    1029         257 :             lkdi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
    1030         257 :             lkd0 = lookup_dpo_get(lkdi0);
    1031             : 
    1032             :             /*
    1033             :              * choose between a lookup using the fib index in the DPO
    1034             :              * or getting the FIB index from the interface.
    1035             :              */
    1036         257 :             if (table_from_interface)
    1037             :             {
    1038             :                 fib_index0 =
    1039           0 :                     mpls_fib_table_get_index_for_sw_if_index(
    1040           0 :                         vnet_buffer(b0)->sw_if_index[VLIB_RX]);
    1041             :             }
    1042             :             else
    1043             :             {
    1044         257 :                 fib_index0 = lkd0->lkd_fib_index;
    1045             :             }
    1046             : 
    1047             :             /* do lookup */
    1048         257 :             lbi0 = mpls_fib_table_forwarding_lookup (fib_index0, hdr0);
    1049         257 :             lb0  = load_balance_get(lbi0);
    1050         257 :             dpo0 = load_balance_get_bucket_i(lb0, 0);
    1051             : 
    1052         257 :             next0 = dpo0->dpoi_next_node;
    1053         257 :             vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
    1054             : 
    1055             : 
    1056         257 :             if (MPLS_IS_REPLICATE & lbi0)
    1057             :             {
    1058           0 :                 next0 = mpls_lookup_to_replicate_edge;
    1059           0 :                 vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
    1060           0 :                     (lbi0 & ~MPLS_IS_REPLICATE);
    1061             :             }
    1062             :             else
    1063             :             {
    1064         257 :                 lb0 = load_balance_get(lbi0);
    1065         257 :                 ASSERT (lb0->lb_n_buckets > 0);
    1066         257 :                 ASSERT (is_pow2 (lb0->lb_n_buckets));
    1067             : 
    1068         257 :                 if (PREDICT_FALSE(lb0->lb_n_buckets > 1))
    1069             :                 {
    1070           0 :                     hash0 = vnet_buffer (b0)->ip.flow_hash =
    1071           0 :                         mpls_compute_flow_hash(hdr0, lb0->lb_hash_config);
    1072           0 :                     dpo0 = load_balance_get_fwd_bucket
    1073             :                         (lb0,
    1074           0 :                          (hash0 & (lb0->lb_n_buckets_minus_1)));
    1075             :                 }
    1076             :                 else
    1077             :                 {
    1078         257 :                     dpo0 = load_balance_get_bucket_i (lb0, 0);
    1079             :                 }
    1080         257 :                 next0 = dpo0->dpoi_next_node;
    1081             : 
    1082         257 :                 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
    1083             : 
    1084         257 :                 vlib_increment_combined_counter
    1085             :                     (cm, thread_index, lbi0, 1,
    1086             :                      vlib_buffer_length_in_chain (vm, b0));
    1087             :             }
    1088             : 
    1089         257 :             vnet_buffer (b0)->mpls.ttl = ((char*)hdr0)[3];
    1090         257 :             vnet_buffer (b0)->mpls.exp = (((char*)hdr0)[2] & 0xe) >> 1;
    1091         257 :             vnet_buffer (b0)->mpls.first = 1;
    1092         257 :             vlib_buffer_advance(b0, sizeof(*hdr0));
    1093             : 
    1094         257 :             if (!(b0->flags & VNET_BUFFER_F_LOOP_COUNTER_VALID)) {
    1095         257 :                 vnet_buffer2(b0)->loop_counter = 0;
    1096         257 :                 b0->flags |= VNET_BUFFER_F_LOOP_COUNTER_VALID;
    1097             :             }
    1098             : 
    1099         257 :             vnet_buffer2(b0)->loop_counter++;
    1100             : 
    1101         257 :             if (PREDICT_FALSE(vnet_buffer2(b0)->loop_counter > MAX_LUKPS_PER_PACKET))
    1102           0 :                 next0 = MPLS_LOOKUP_NEXT_DROP;
    1103             : 
    1104         257 :             if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
    1105             :             {
    1106         257 :                 lookup_trace_t *tr = vlib_add_trace (vm, node,
    1107             :                                                      b0, sizeof (*tr));
    1108         257 :                 tr->fib_index = fib_index0;
    1109         257 :                 tr->lbi = lbi0;
    1110         257 :                 tr->hdr = *hdr0;
    1111             :             }
    1112             : 
    1113         257 :            vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
    1114             :                                             n_left_to_next, bi0, next0);
    1115             :         }
    1116           2 :         vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    1117             :     }
    1118           2 :     return from_frame->n_vectors;
    1119             : }
    1120             : 
    1121             : static u8 *
    1122         307 : format_lookup_mpls_trace (u8 * s, va_list * args)
    1123             : {
    1124         307 :     CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
    1125         307 :     CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
    1126         307 :     lookup_trace_t * t = va_arg (*args, lookup_trace_t *);
    1127         307 :     u32 indent = format_get_indent (s);
    1128             :     mpls_unicast_header_t hdr;
    1129             : 
    1130         307 :     hdr.label_exp_s_ttl = clib_net_to_host_u32(t->hdr.label_exp_s_ttl);
    1131             : 
    1132         307 :     s = format (s, "%U fib-index:%d hdr:%U load-balance:%d",
    1133             :                 format_white_space, indent,
    1134             :                 t->fib_index,
    1135             :                 format_mpls_header, hdr,
    1136             :                 t->lbi);
    1137         307 :     return s;
    1138             : }
    1139             : 
    1140         561 : VLIB_NODE_FN (lookup_mpls_dst_node) (vlib_main_t * vm,
    1141             :                 vlib_node_runtime_t * node,
    1142             :                 vlib_frame_t * from_frame)
    1143             : {
    1144           2 :     return (lookup_dpo_mpls_inline(vm, node, from_frame, 0));
    1145             : }
    1146             : 
    1147      178120 : VLIB_REGISTER_NODE (lookup_mpls_dst_node) = {
    1148             :     .name = "lookup-mpls-dst",
    1149             :     .vector_size = sizeof (u32),
    1150             :     .sibling_of = "mpls-lookup",
    1151             :     .format_trace = format_lookup_mpls_trace,
    1152             :     .n_next_nodes = 0,
    1153             : };
    1154             : 
    1155         559 : VLIB_NODE_FN (lookup_mpls_dst_itf_node) (vlib_main_t * vm,
    1156             :                     vlib_node_runtime_t * node,
    1157             :                     vlib_frame_t * from_frame)
    1158             : {
    1159           0 :     return (lookup_dpo_mpls_inline(vm, node, from_frame, 1));
    1160             : }
    1161             : 
    1162      178120 : VLIB_REGISTER_NODE (lookup_mpls_dst_itf_node) = {
    1163             :     .name = "lookup-mpls-dst-itf",
    1164             :     .vector_size = sizeof (u32),
    1165             :     .sibling_of = "mpls-lookup",
    1166             :     .format_trace = format_lookup_mpls_trace,
    1167             :     .n_next_nodes = 0,
    1168             : };
    1169             : 
    1170             : typedef enum lookup_ip_dst_mcast_next_t_ {
    1171             :     LOOKUP_IP_DST_MCAST_NEXT_DROP,
    1172             :     LOOKUP_IP_DST_MCAST_NEXT_RPF,
    1173             :     LOOKUP_IP_DST_MCAST_N_NEXT,
    1174             : } mfib_forward_lookup_next_t;
    1175             : 
    1176             : always_inline uword
    1177          19 : lookup_dpo_ip_dst_mcast_inline (vlib_main_t * vm,
    1178             :                                 vlib_node_runtime_t * node,
    1179             :                                 vlib_frame_t * from_frame,
    1180             :                                 int is_v4)
    1181             : {
    1182             :     u32 n_left_from, next_index, * from, * to_next;
    1183             : 
    1184          19 :     from = vlib_frame_vector_args (from_frame);
    1185          19 :     n_left_from = from_frame->n_vectors;
    1186             : 
    1187          19 :     next_index = LOOKUP_IP_DST_MCAST_NEXT_RPF;
    1188             : 
    1189          38 :     while (n_left_from > 0)
    1190             :     {
    1191             :         u32 n_left_to_next;
    1192             : 
    1193          19 :         vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
    1194             : 
    1195             :         /* while (n_left_from >= 4 && n_left_to_next >= 2) */
    1196             :         /*   } */
    1197             : 
    1198        1700 :         while (n_left_from > 0 && n_left_to_next > 0)
    1199             :         {
    1200             :             u32 bi0, lkdi0, fib_index0,  next0;
    1201             :             const lookup_dpo_t * lkd0;
    1202             :             fib_node_index_t mfei0;
    1203             :             vlib_buffer_t * b0;
    1204             : 
    1205        1681 :             bi0 = from[0];
    1206        1681 :             to_next[0] = bi0;
    1207        1681 :             from += 1;
    1208        1681 :             to_next += 1;
    1209        1681 :             n_left_from -= 1;
    1210        1681 :             n_left_to_next -= 1;
    1211             : 
    1212        1681 :             b0 = vlib_get_buffer (vm, bi0);
    1213             : 
    1214             :             /* dst lookup was done by mpls lookup */
    1215        1681 :             lkdi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
    1216        1681 :             lkd0 = lookup_dpo_get(lkdi0);
    1217        1681 :             fib_index0 = lkd0->lkd_fib_index;
    1218        1681 :             next0 = LOOKUP_IP_DST_MCAST_NEXT_RPF;
    1219             : 
    1220        1681 :             if (is_v4)
    1221             :             {
    1222             :                 ip4_header_t * ip0;
    1223             : 
    1224         653 :                 ip0 = vlib_buffer_get_current (b0);
    1225         653 :                 mfei0 = ip4_mfib_table_lookup(ip4_mfib_get(fib_index0),
    1226         653 :                                               &ip0->src_address,
    1227         653 :                                               &ip0->dst_address,
    1228             :                                               64);
    1229         653 :                 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
    1230             :                 {
    1231         653 :                     lookup_trace_t *tr = vlib_add_trace (vm, node,
    1232             :                                                          b0, sizeof (*tr));
    1233         653 :                     tr->fib_index = fib_index0;
    1234         653 :                     tr->lbi = mfei0;
    1235         653 :                     tr->addr.ip4 = ip0->dst_address;
    1236             :                 }
    1237             :             }
    1238             :             else
    1239             :             {
    1240             :                 ip6_header_t * ip0;
    1241             : 
    1242        1028 :                 ip0 = vlib_buffer_get_current (b0);
    1243        1028 :                 mfei0 = ip6_mfib_table_fwd_lookup(ip6_mfib_get(fib_index0),
    1244        1028 :                                                   &ip0->src_address,
    1245        1028 :                                                   &ip0->dst_address);
    1246        1028 :                 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
    1247             :                 {
    1248        1028 :                     lookup_trace_t *tr = vlib_add_trace (vm, node,
    1249             :                                                          b0, sizeof (*tr));
    1250        1028 :                     tr->fib_index = fib_index0;
    1251        1028 :                     tr->lbi = mfei0;
    1252        1028 :                     tr->addr.ip6 = ip0->dst_address;
    1253             :                 }
    1254             :             }
    1255             : 
    1256        1681 :             vnet_buffer (b0)->ip.adj_index[VLIB_TX] = mfei0;
    1257             : 
    1258        1681 :             if (!(b0->flags & VNET_BUFFER_F_LOOP_COUNTER_VALID)) {
    1259        1681 :                 vnet_buffer2(b0)->loop_counter = 0;
    1260        1681 :                 b0->flags |= VNET_BUFFER_F_LOOP_COUNTER_VALID;
    1261             :             }
    1262             : 
    1263        1681 :             vnet_buffer2(b0)->loop_counter++;
    1264             : 
    1265        1681 :             if (PREDICT_FALSE(vnet_buffer2(b0)->loop_counter > MAX_LUKPS_PER_PACKET))
    1266           0 :                 next0 = LOOKUP_IP_DST_MCAST_NEXT_DROP;
    1267             : 
    1268        1681 :             vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
    1269             :                                             n_left_to_next, bi0, next0);
    1270             :         }
    1271          19 :         vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    1272             :     }
    1273          19 :     return from_frame->n_vectors;
    1274             : }
    1275             : 
    1276         570 : VLIB_NODE_FN (lookup_ip4_dst_mcast_node) (vlib_main_t * vm,
    1277             :                       vlib_node_runtime_t * node,
    1278             :                       vlib_frame_t * from_frame)
    1279             : {
    1280          11 :     return (lookup_dpo_ip_dst_mcast_inline(vm, node, from_frame, 1));
    1281             : }
    1282             : 
    1283      178120 : VLIB_REGISTER_NODE (lookup_ip4_dst_mcast_node) = {
    1284             :     .name = "lookup-ip4-dst-mcast",
    1285             :     .vector_size = sizeof (u32),
    1286             : 
    1287             :     .format_trace = format_lookup_trace,
    1288             :     .n_next_nodes = LOOKUP_IP_DST_MCAST_N_NEXT,
    1289             :     .next_nodes = {
    1290             :         [LOOKUP_IP_DST_MCAST_NEXT_DROP] = "ip4-drop",
    1291             :         [LOOKUP_IP_DST_MCAST_NEXT_RPF] = "ip4-mfib-forward-rpf",
    1292             :     },
    1293             : };
    1294             : 
    1295         567 : VLIB_NODE_FN (lookup_ip6_dst_mcast_node) (vlib_main_t * vm,
    1296             :                       vlib_node_runtime_t * node,
    1297             :                       vlib_frame_t * from_frame)
    1298             : {
    1299           8 :     return (lookup_dpo_ip_dst_mcast_inline(vm, node, from_frame, 0));
    1300             : }
    1301             : 
    1302      178120 : VLIB_REGISTER_NODE (lookup_ip6_dst_mcast_node) = {
    1303             :     .name = "lookup-ip6-dst-mcast",
    1304             :     .vector_size = sizeof (u32),
    1305             : 
    1306             :     .format_trace = format_lookup_trace,
    1307             :     .n_next_nodes = LOOKUP_IP_DST_MCAST_N_NEXT,
    1308             :     .next_nodes = {
    1309             :         [LOOKUP_IP_DST_MCAST_NEXT_DROP] = "ip6-drop",
    1310             :         [LOOKUP_IP_DST_MCAST_NEXT_RPF] = "ip6-mfib-forward-rpf",
    1311             :     },
    1312             : };
    1313             : 
    1314             : static void
    1315           0 : lookup_dpo_mem_show (void)
    1316             : {
    1317           0 :     fib_show_memory_usage("Lookup",
    1318           0 :                           pool_elts(lookup_dpo_pool),
    1319           0 :                           pool_len(lookup_dpo_pool),
    1320             :                           sizeof(lookup_dpo_t));
    1321           0 : }
    1322             : 
    1323             : const static dpo_vft_t lkd_vft = {
    1324             :     .dv_lock = lookup_dpo_lock,
    1325             :     .dv_unlock = lookup_dpo_unlock,
    1326             :     .dv_format = format_lookup_dpo,
    1327             : };
    1328             : const static dpo_vft_t lkd_vft_w_mem_show = {
    1329             :     .dv_lock = lookup_dpo_lock,
    1330             :     .dv_unlock = lookup_dpo_unlock,
    1331             :     .dv_format = format_lookup_dpo,
    1332             :     .dv_mem_show = lookup_dpo_mem_show,
    1333             : };
    1334             : 
    1335             : const static char* const lookup_src_ip4_nodes[] =
    1336             : {
    1337             :     "lookup-ip4-src",
    1338             :     NULL,
    1339             : };
    1340             : const static char* const lookup_src_ip6_nodes[] =
    1341             : {
    1342             :     "lookup-ip6-src",
    1343             :     NULL,
    1344             : };
    1345             : const static char* const * const lookup_src_nodes[DPO_PROTO_NUM] =
    1346             : {
    1347             :     [DPO_PROTO_IP4]  = lookup_src_ip4_nodes,
    1348             :     [DPO_PROTO_IP6]  = lookup_src_ip6_nodes,
    1349             :     [DPO_PROTO_MPLS] = NULL,
    1350             : };
    1351             : 
    1352             : const static char* const lookup_dst_ip4_nodes[] =
    1353             : {
    1354             :     "lookup-ip4-dst",
    1355             :     NULL,
    1356             : };
    1357             : const static char* const lookup_dst_ip6_nodes[] =
    1358             : {
    1359             :     "lookup-ip6-dst",
    1360             :     NULL,
    1361             : };
    1362             : const static char* const lookup_dst_mpls_nodes[] =
    1363             : {
    1364             :     "lookup-mpls-dst",
    1365             :     NULL,
    1366             : };
    1367             : const static char* const * const lookup_dst_nodes[DPO_PROTO_NUM] =
    1368             : {
    1369             :     [DPO_PROTO_IP4]  = lookup_dst_ip4_nodes,
    1370             :     [DPO_PROTO_IP6]  = lookup_dst_ip6_nodes,
    1371             :     [DPO_PROTO_MPLS] = lookup_dst_mpls_nodes,
    1372             : };
    1373             : 
    1374             : const static char* const lookup_dst_mcast_ip4_nodes[] =
    1375             : {
    1376             :     "lookup-ip4-dst-mcast",
    1377             :     NULL,
    1378             : };
    1379             : const static char* const lookup_dst_mcast_ip6_nodes[] =
    1380             : {
    1381             :     "lookup-ip6-dst-mcast",
    1382             :     NULL,
    1383             : };
    1384             : const static char* const * const lookup_dst_mcast_nodes[DPO_PROTO_NUM] =
    1385             : {
    1386             :     [DPO_PROTO_IP4]  = lookup_dst_mcast_ip4_nodes,
    1387             :     [DPO_PROTO_IP6]  = lookup_dst_mcast_ip6_nodes,
    1388             : };
    1389             : 
    1390             : const static char* const lookup_dst_from_interface_ip4_nodes[] =
    1391             : {
    1392             :     "lookup-ip4-dst-itf",
    1393             :     NULL,
    1394             : };
    1395             : const static char* const lookup_dst_from_interface_ip6_nodes[] =
    1396             : {
    1397             :     "lookup-ip6-dst-itf",
    1398             :     NULL,
    1399             : };
    1400             : const static char* const lookup_dst_from_interface_mpls_nodes[] =
    1401             : {
    1402             :     "lookup-mpls-dst-itf",
    1403             :     NULL,
    1404             : };
    1405             : const static char* const * const lookup_dst_from_interface_nodes[DPO_PROTO_NUM] =
    1406             : {
    1407             :     [DPO_PROTO_IP4]  = lookup_dst_from_interface_ip4_nodes,
    1408             :     [DPO_PROTO_IP6]  = lookup_dst_from_interface_ip6_nodes,
    1409             :     [DPO_PROTO_MPLS] = lookup_dst_from_interface_mpls_nodes,
    1410             : };
    1411             : 
    1412             : static clib_error_t *
    1413           0 : lookup_dpo_show (vlib_main_t * vm,
    1414             :                  unformat_input_t * input,
    1415             :                  vlib_cli_command_t * cmd)
    1416             : {
    1417           0 :     index_t lkdi = INDEX_INVALID;
    1418             : 
    1419           0 :     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    1420             :     {
    1421           0 :         if (unformat (input, "%d", &lkdi))
    1422             :             ;
    1423             :         else
    1424           0 :             break;
    1425             :     }
    1426             : 
    1427           0 :     if (INDEX_INVALID != lkdi)
    1428             :     {
    1429           0 :         if (pool_is_free_index(lookup_dpo_pool, lkdi))
    1430           0 :                 vlib_cli_output (vm, "no such index %d", lkdi);
    1431             :         else
    1432           0 :                 vlib_cli_output (vm, "%U", format_lookup_dpo, lkdi);
    1433             :     }
    1434             :     else
    1435             :     {
    1436             :         lookup_dpo_t *lkd;
    1437             : 
    1438           0 :         pool_foreach (lkd, lookup_dpo_pool)
    1439             :          {
    1440           0 :             vlib_cli_output (vm, "[@%d] %U",
    1441             :                              lookup_dpo_get_index(lkd),
    1442             :                              format_lookup_dpo,
    1443             :                              lookup_dpo_get_index(lkd));
    1444             :         }
    1445             :     }
    1446             : 
    1447           0 :     return 0;
    1448             : }
    1449             : 
    1450      272887 : VLIB_CLI_COMMAND (replicate_show_command, static) = {
    1451             :     .path = "show lookup-dpo",
    1452             :     .short_help = "show lookup-dpo [<index>]",
    1453             :     .function = lookup_dpo_show,
    1454             : };
    1455             : 
    1456             : void
    1457         559 : lookup_dpo_module_init (void)
    1458             : {
    1459         559 :     dpo_register(DPO_LOOKUP, &lkd_vft_w_mem_show, NULL);
    1460             : 
    1461             :     /*
    1462             :      * There are various sorts of lookup; src or dst addr v4 /v6 etc.
    1463             :      * there isn't an object type for each (there is only the lookup_dpo_t),
    1464             :      * but, for performance reasons, there is a data plane function, and hence
    1465             :      * VLIB node for each. VLIB graph node construction is based on DPO types
    1466             :      * so we create sub-types.
    1467             :      */
    1468         559 :     lookup_dpo_sub_types[LOOKUP_SUB_TYPE_SRC] =
    1469         559 :         dpo_register_new_type(&lkd_vft, lookup_src_nodes);
    1470         559 :     lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST] =
    1471         559 :         dpo_register_new_type(&lkd_vft, lookup_dst_nodes);
    1472         559 :     lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST_MCAST] =
    1473         559 :         dpo_register_new_type(&lkd_vft, lookup_dst_mcast_nodes);
    1474         559 :     lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST_TABLE_FROM_INTERFACE] =
    1475         559 :         dpo_register_new_type(&lkd_vft, lookup_dst_from_interface_nodes);
    1476         559 : }

Generated by: LCOV version 1.14