LCOV - code coverage report
Current view: top level - plugins/lisp/lisp-gpe - lisp_gpe_fwd_entry.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 181 583 31.0 %
Date: 2023-10-26 01:39:38 Functions: 21 50 42.0 %

          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 <lisp/lisp-gpe/lisp_gpe_fwd_entry.h>
      17             : #include <lisp/lisp-gpe/lisp_gpe_adjacency.h>
      18             : #include <lisp/lisp-gpe/lisp_gpe_tenant.h>
      19             : #include <lisp/lisp-cp/lisp_cp_dpo.h>
      20             : #include <vnet/fib/fib_table.h>
      21             : #include <vnet/fib/fib_entry.h>
      22             : #include <vnet/fib/fib_path_list.h>
      23             : #include <vnet/dpo/drop_dpo.h>
      24             : #include <vnet/dpo/lookup_dpo.h>
      25             : #include <vnet/dpo/load_balance.h>
      26             : #include <vnet/adj/adj_midchain.h>
      27             : 
      28             : /**
      29             :  * @brief Add route to IP4 or IP6 Destination FIB.
      30             :  *
      31             :  * Add a route to the destination FIB that results in the lookup
      32             :  * in the SRC FIB. The SRC FIB is created is it does not yet exist.
      33             :  *
      34             :  * @param[in]   dst_table_id    Destination FIB Table-ID
      35             :  * @param[in]   dst_prefix      Destination IP prefix.
      36             :  *
      37             :  * @return  src_fib_index   The index/ID of the SRC FIB created.
      38             :  */
      39             : static u32
      40           0 : ip_dst_fib_add_route (u32 dst_fib_index, const ip_prefix_t * dst_prefix)
      41             : {
      42             :   fib_node_index_t src_fib_index;
      43             :   fib_prefix_t dst_fib_prefix;
      44             :   fib_node_index_t dst_fei;
      45             : 
      46           0 :   ASSERT (NULL != dst_prefix);
      47             : 
      48           0 :   ip_prefix_to_fib_prefix (dst_prefix, &dst_fib_prefix);
      49             : 
      50             :   /*
      51             :    * lookup the destination prefix in the VRF table and retrieve the
      52             :    * LISP associated data
      53             :    */
      54           0 :   dst_fei = fib_table_lookup_exact_match (dst_fib_index, &dst_fib_prefix);
      55             : 
      56             :   /*
      57             :    * If the FIB entry is not present, or not LISP sourced, add it
      58             :    */
      59           0 :   if (dst_fei == FIB_NODE_INDEX_INVALID ||
      60           0 :       NULL == fib_entry_get_source_data (dst_fei, FIB_SOURCE_LISP))
      61           0 :     {
      62           0 :       dpo_id_t src_lkup_dpo = DPO_INVALID;
      63             : 
      64             :       /* create a new src FIB.  */
      65           0 :       src_fib_index =
      66           0 :         fib_table_create_and_lock (dst_fib_prefix.fp_proto,
      67             :                                    FIB_SOURCE_LISP,
      68             :                                    "LISP-src for [%d,%U]",
      69             :                                    dst_fib_index,
      70             :                                    format_fib_prefix, &dst_fib_prefix);
      71             :       /*
      72             :        * add src fib default route
      73             :        */
      74           0 :       fib_prefix_t prefix = {
      75           0 :         .fp_proto = dst_fib_prefix.fp_proto,
      76             :       };
      77           0 :       fib_table_entry_special_dpo_add (src_fib_index, &prefix,
      78             :                                        FIB_SOURCE_LISP,
      79             :                                        FIB_ENTRY_FLAG_EXCLUSIVE,
      80           0 :                                        lisp_cp_dpo_get (fib_proto_to_dpo
      81           0 :                                                         (dst_fib_prefix.fp_proto)));
      82             :       /*
      83             :        * create a data-path object to perform the source address lookup
      84             :        * in the SRC FIB
      85             :        */
      86           0 :       lookup_dpo_add_or_lock_w_fib_index (src_fib_index,
      87           0 :                                           (ip_prefix_version (dst_prefix) ==
      88             :                                            AF_IP6 ? DPO_PROTO_IP6 :
      89             :                                            DPO_PROTO_IP4),
      90             :                                           LOOKUP_UNICAST,
      91             :                                           LOOKUP_INPUT_SRC_ADDR,
      92             :                                           LOOKUP_TABLE_FROM_CONFIG,
      93             :                                           &src_lkup_dpo);
      94             : 
      95             :       /*
      96             :        * add the entry to the destination FIB that uses the lookup DPO
      97             :        */
      98           0 :       dst_fei = fib_table_entry_special_dpo_add (dst_fib_index,
      99             :                                                  &dst_fib_prefix,
     100             :                                                  FIB_SOURCE_LISP,
     101             :                                                  FIB_ENTRY_FLAG_EXCLUSIVE,
     102             :                                                  &src_lkup_dpo);
     103             : 
     104             :       /*
     105             :        * the DPO is locked by the FIB entry, and we have no further
     106             :        * need for it.
     107             :        */
     108           0 :       dpo_unlock (&src_lkup_dpo);
     109             : 
     110             :       /*
     111             :        * save the SRC FIB index on the entry so we can retrieve it for
     112             :        * subsequent routes.
     113             :        */
     114           0 :       fib_entry_set_source_data (dst_fei, FIB_SOURCE_LISP, &src_fib_index);
     115             :     }
     116             :   else
     117             :     {
     118             :       /*
     119             :        * destination FIB entry already present
     120             :        */
     121           0 :       src_fib_index = *(u32 *) fib_entry_get_source_data (dst_fei,
     122             :                                                           FIB_SOURCE_LISP);
     123             :     }
     124             : 
     125           0 :   return (src_fib_index);
     126             : }
     127             : 
     128             : /**
     129             :  * @brief Del route to IP4 or IP6 SD FIB.
     130             :  *
     131             :  * Remove routes from both destination and source FIBs.
     132             :  *
     133             :  * @param[in]   src_fib_index   The index/ID of the SRC FIB
     134             :  * @param[in]   src_prefix      Source IP prefix.
     135             :  * @param[in]   dst_fib_index   The index/ID of the DST FIB
     136             :  * @param[in]   dst_prefix      Destination IP prefix.
     137             :  */
     138             : static void
     139           0 : ip_src_dst_fib_del_route (u32 src_fib_index,
     140             :                           const ip_prefix_t * src_prefix,
     141             :                           u32 dst_fib_index, const ip_prefix_t * dst_prefix)
     142             : {
     143             :   fib_prefix_t dst_fib_prefix, src_fib_prefix;
     144           0 :   u8 have_default = 0;
     145             :   u32 n_entries;
     146             : 
     147           0 :   ASSERT (NULL != dst_prefix);
     148           0 :   ASSERT (NULL != src_prefix);
     149             : 
     150           0 :   ip_prefix_to_fib_prefix (dst_prefix, &dst_fib_prefix);
     151           0 :   ip_prefix_to_fib_prefix (src_prefix, &src_fib_prefix);
     152             : 
     153           0 :   fib_table_entry_delete (src_fib_index, &src_fib_prefix, FIB_SOURCE_LISP);
     154             : 
     155             :   /* check if only default left or empty */
     156           0 :   fib_prefix_t default_pref = {
     157           0 :     .fp_proto = dst_fib_prefix.fp_proto
     158             :   };
     159             : 
     160           0 :   if (fib_table_lookup_exact_match (src_fib_index,
     161             :                                     &default_pref) != FIB_NODE_INDEX_INVALID)
     162           0 :     have_default = 1;
     163             : 
     164           0 :   n_entries = fib_table_get_num_entries (src_fib_index,
     165           0 :                                          src_fib_prefix.fp_proto,
     166             :                                          FIB_SOURCE_LISP);
     167           0 :   if (n_entries == 0 || (have_default && n_entries == 1))
     168             :     {
     169             :       /*
     170             :        * remove src FIB default route
     171             :        */
     172           0 :       if (have_default)
     173           0 :         fib_table_entry_special_remove (src_fib_index, &default_pref,
     174             :                                         FIB_SOURCE_LISP);
     175             : 
     176             :       /*
     177             :        * there's nothing left now, unlock the source FIB and the
     178             :        * destination route
     179             :        */
     180           0 :       fib_table_entry_special_remove (dst_fib_index,
     181             :                                       &dst_fib_prefix, FIB_SOURCE_LISP);
     182           0 :       fib_table_unlock (src_fib_index, src_fib_prefix.fp_proto,
     183             :                         FIB_SOURCE_LISP);
     184             :     }
     185           0 : }
     186             : 
     187             : /**
     188             :  * @brief Add route to IP4 or IP6 SRC FIB.
     189             :  *
     190             :  * Adds a route to in the LISP SRC FIB with the result of the route
     191             :  * being the DPO passed.
     192             :  *
     193             :  * @param[in]   src_fib_index   The index/ID of the SRC FIB
     194             :  * @param[in]   src_prefix      Source IP prefix.
     195             :  * @param[in]   src_dpo         The DPO the route will link to.
     196             :  *
     197             :  * @return fib index of the inserted prefix
     198             :  */
     199             : static fib_node_index_t
     200           0 : ip_src_fib_add_route_w_dpo (u32 src_fib_index,
     201             :                             const ip_prefix_t * src_prefix,
     202             :                             const dpo_id_t * src_dpo)
     203             : {
     204           0 :   fib_node_index_t fei = ~0;
     205             :   fib_prefix_t src_fib_prefix;
     206             : 
     207           0 :   ip_prefix_to_fib_prefix (src_prefix, &src_fib_prefix);
     208             : 
     209             :   /*
     210             :    * add the entry into the source fib.
     211             :    */
     212             :   fib_node_index_t src_fei;
     213             : 
     214           0 :   src_fei = fib_table_lookup_exact_match (src_fib_index, &src_fib_prefix);
     215             : 
     216           0 :   if (FIB_NODE_INDEX_INVALID == src_fei ||
     217           0 :       !fib_entry_is_sourced (src_fei, FIB_SOURCE_LISP))
     218             :     {
     219           0 :       fei = fib_table_entry_special_dpo_add (src_fib_index,
     220             :                                              &src_fib_prefix,
     221             :                                              FIB_SOURCE_LISP,
     222             :                                              FIB_ENTRY_FLAG_EXCLUSIVE,
     223             :                                              src_dpo);
     224             :     }
     225           0 :   return fei;
     226             : }
     227             : 
     228             : static fib_route_path_t *
     229           1 : lisp_gpe_mk_fib_paths (const lisp_fwd_path_t * paths)
     230             : {
     231             :   const lisp_gpe_adjacency_t *ladj;
     232           1 :   fib_route_path_t *rpaths = NULL;
     233             :   fib_protocol_t fp;
     234             :   u8 best_priority;
     235             :   u32 ii;
     236             : 
     237           1 :   vec_validate (rpaths, vec_len (paths) - 1);
     238             : 
     239           1 :   best_priority = paths[0].priority;
     240             : 
     241           2 :   vec_foreach_index (ii, paths)
     242             :   {
     243           1 :     if (paths[0].priority != best_priority)
     244           0 :       break;
     245             : 
     246           1 :     ladj = lisp_gpe_adjacency_get (paths[ii].lisp_adj);
     247             : 
     248           1 :     fp = ip_address_to_46 (&ladj->remote_rloc, &rpaths[ii].frp_addr);
     249             : 
     250           1 :     rpaths[ii].frp_proto = fib_proto_to_dpo (fp);
     251           1 :     rpaths[ii].frp_sw_if_index = ladj->sw_if_index;
     252           1 :     rpaths[ii].frp_weight = (paths[ii].weight ? paths[ii].weight : 1);
     253             :   }
     254             : 
     255           1 :   ASSERT (0 != vec_len (rpaths));
     256             : 
     257           1 :   return (rpaths);
     258             : }
     259             : 
     260             : /**
     261             :  * @brief Add route to IP4 or IP6 SRC FIB.
     262             :  *
     263             :  * Adds a route to in the LISP SRC FIB for the tunnel.
     264             :  *
     265             :  * @param[in]   src_fib_index   The index/ID of the SRC FIB
     266             :  * @param[in]   src_prefix      Source IP prefix.
     267             :  * @param[in]   paths           The paths from which to construct the
     268             :  *                              load balance
     269             :  */
     270             : static fib_node_index_t
     271           1 : ip_src_fib_add_route (u32 src_fib_index,
     272             :                       const ip_prefix_t * src_prefix,
     273             :                       const lisp_fwd_path_t * paths)
     274             : {
     275             :   fib_prefix_t src_fib_prefix;
     276             :   fib_route_path_t *rpaths;
     277             : 
     278           1 :   ip_prefix_to_fib_prefix (src_prefix, &src_fib_prefix);
     279             : 
     280           1 :   rpaths = lisp_gpe_mk_fib_paths (paths);
     281             : 
     282             :   fib_node_index_t fib_entry_index =
     283           1 :     fib_table_entry_update (src_fib_index, &src_fib_prefix, FIB_SOURCE_LISP,
     284             :                             FIB_ENTRY_FLAG_NONE, rpaths);
     285           1 :   vec_free (rpaths);
     286           1 :   return fib_entry_index;
     287             : }
     288             : 
     289             : static void
     290           1 : gpe_native_fwd_add_del_lfe (lisp_gpe_fwd_entry_t * lfe, u8 is_add)
     291             : {
     292           1 :   lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
     293           1 :   u8 found = 0, ip_version;
     294             :   u32 *lfei, new_lfei;
     295           1 :   ip_version = ip_prefix_version (&lfe->key->rmt.ippref);
     296             : 
     297           1 :   new_lfei = lfe - lgm->lisp_fwd_entry_pool;
     298           1 :   vec_foreach (lfei, lgm->native_fwd_lfes[ip_version])
     299             :   {
     300           0 :     lfe = pool_elt_at_index (lgm->lisp_fwd_entry_pool, lfei[0]);
     301           0 :     if (lfei[0] == new_lfei)
     302             :       {
     303           0 :         found = 1;
     304           0 :         break;
     305             :       }
     306             :   }
     307             : 
     308           1 :   if (is_add)
     309             :     {
     310           0 :       if (!found)
     311           0 :         vec_add1 (lgm->native_fwd_lfes[ip_version], new_lfei);
     312             :     }
     313             :   else
     314             :     {
     315           1 :       if (found)
     316           0 :         vec_del1 (lgm->native_fwd_lfes[ip_version], lfei[0]);
     317             :     }
     318           1 : }
     319             : 
     320             : static index_t
     321           1 : create_fib_entries (lisp_gpe_fwd_entry_t * lfe)
     322             : {
     323             :   fib_node_index_t fi;
     324             :   fib_entry_t *fe;
     325           1 :   lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
     326             :   dpo_proto_t dproto;
     327             :   ip_prefix_t ippref;
     328             :   fib_prefix_t fib_prefix;
     329           1 :   u8 ip_version = ip_prefix_version (&lfe->key->rmt.ippref);
     330           1 :   dproto = (ip_version == AF_IP4 ? DPO_PROTO_IP4 : DPO_PROTO_IP6);
     331             : 
     332           1 :   if (lfe->is_src_dst)
     333             :     {
     334           0 :       lfe->src_fib_index = ip_dst_fib_add_route (lfe->eid_fib_index,
     335           0 :                                                  &lfe->key->rmt.ippref);
     336           0 :       memcpy (&ippref, &lfe->key->lcl.ippref, sizeof (ippref));
     337             :     }
     338             :   else
     339             :     {
     340           1 :       lfe->src_fib_index = lfe->eid_fib_index;
     341           1 :       memcpy (&ippref, &lfe->key->rmt.ippref, sizeof (ippref));
     342             :     }
     343             : 
     344           1 :   if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE == lfe->type)
     345             :     {
     346           0 :       dpo_id_t dpo = DPO_INVALID;
     347             : 
     348           0 :       switch (lfe->action)
     349             :         {
     350           0 :         case LISP_FORWARD_NATIVE:
     351             :           /* TODO handle route overlaps with fib and default route */
     352           0 :           if (vec_len (lgm->native_fwd_rpath[ip_version]))
     353             :             {
     354           0 :               ip_prefix_to_fib_prefix (&lfe->key->rmt.ippref, &fib_prefix);
     355           0 :               fi = fib_table_entry_update (lfe->eid_fib_index, &fib_prefix,
     356             :                                            FIB_SOURCE_LISP,
     357             :                                            FIB_ENTRY_FLAG_NONE,
     358             :                                            lgm->native_fwd_rpath[ip_version]);
     359           0 :               gpe_native_fwd_add_del_lfe (lfe, 1);
     360           0 :               goto done;
     361             :             }
     362             :         case LISP_NO_ACTION:
     363             :           /* TODO update timers? */
     364             :         case LISP_SEND_MAP_REQUEST:
     365             :           /* insert tunnel that always sends map-request */
     366           0 :           dpo_copy (&dpo, lisp_cp_dpo_get (dproto));
     367           0 :           break;
     368           0 :         case LISP_DROP:
     369             :           /* for drop fwd entries, just add route, no need to add encap tunnel */
     370           0 :           dpo_copy (&dpo, drop_dpo_get (dproto));
     371           0 :           break;
     372             :         }
     373           0 :       fi = ip_src_fib_add_route_w_dpo (lfe->src_fib_index, &ippref, &dpo);
     374           0 :       dpo_reset (&dpo);
     375             :     }
     376             :   else
     377             :     {
     378           1 :       fi = ip_src_fib_add_route (lfe->src_fib_index, &ippref, lfe->paths);
     379             :     }
     380           1 : done:
     381           1 :   fe = fib_entry_get (fi);
     382           1 :   return fe->fe_lb.dpoi_index;
     383             : }
     384             : 
     385             : static void
     386           1 : delete_fib_entries (lisp_gpe_fwd_entry_t * lfe)
     387             : {
     388             :   fib_prefix_t dst_fib_prefix;
     389             : 
     390           1 :   if (lfe->is_src_dst)
     391           0 :     ip_src_dst_fib_del_route (lfe->src_fib_index,
     392           0 :                               &lfe->key->lcl.ippref,
     393           0 :                               lfe->eid_fib_index, &lfe->key->rmt.ippref);
     394             :   else
     395             :     {
     396           1 :       ip_prefix_to_fib_prefix (&lfe->key->rmt.ippref, &dst_fib_prefix);
     397           1 :       fib_table_entry_delete (lfe->src_fib_index, &dst_fib_prefix,
     398             :                               FIB_SOURCE_LISP);
     399           1 :       gpe_native_fwd_add_del_lfe (lfe, 0);
     400             :     }
     401           1 : }
     402             : 
     403             : static lisp_gpe_fwd_entry_t *
     404           4 : find_fwd_entry (lisp_gpe_main_t * lgm,
     405             :                 vnet_lisp_gpe_add_del_fwd_entry_args_t * a,
     406             :                 lisp_gpe_fwd_entry_key_t * key)
     407             : {
     408             :   uword *p;
     409             : 
     410           4 :   clib_memset (key, 0, sizeof (*key));
     411             : 
     412           4 :   if (GID_ADDR_IP_PREFIX == gid_address_type (&a->rmt_eid))
     413             :     {
     414             :       /*
     415             :        * the ip version of the source is not set to ip6 when the
     416             :        * source is all zeros. force it.
     417             :        */
     418           4 :       ip_prefix_version (&gid_address_ippref (&a->lcl_eid)) =
     419           4 :         ip_prefix_version (&gid_address_ippref (&a->rmt_eid));
     420             :     }
     421             : 
     422           4 :   gid_to_dp_address (&a->rmt_eid, &key->rmt);
     423           4 :   gid_to_dp_address (&a->lcl_eid, &key->lcl);
     424           4 :   key->vni = a->vni;
     425             : 
     426           4 :   p = hash_get_mem (lgm->lisp_gpe_fwd_entries, key);
     427             : 
     428           4 :   if (NULL != p)
     429             :     {
     430           3 :       return (pool_elt_at_index (lgm->lisp_fwd_entry_pool, p[0]));
     431             :     }
     432           1 :   return (NULL);
     433             : }
     434             : 
     435             : static int
     436           0 : lisp_gpe_fwd_entry_path_sort (void *a1, void *a2)
     437             : {
     438           0 :   lisp_fwd_path_t *p1 = a1, *p2 = a2;
     439             : 
     440           0 :   return (p1->priority - p2->priority);
     441             : }
     442             : 
     443             : static void
     444           1 : lisp_gpe_fwd_entry_mk_paths (lisp_gpe_fwd_entry_t * lfe,
     445             :                              vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
     446             : {
     447             :   lisp_fwd_path_t *path;
     448             :   u32 index;
     449             : 
     450           1 :   vec_validate (lfe->paths, vec_len (a->locator_pairs) - 1);
     451             : 
     452           2 :   vec_foreach_index (index, a->locator_pairs)
     453             :   {
     454           1 :     path = &lfe->paths[index];
     455             : 
     456           1 :     path->priority = a->locator_pairs[index].priority;
     457           1 :     path->weight = a->locator_pairs[index].weight;
     458             : 
     459           1 :     path->lisp_adj =
     460           1 :       lisp_gpe_adjacency_find_or_create_and_lock (&a->locator_pairs
     461           1 :                                                   [index],
     462           1 :                                                   a->dp_table, lfe->key->vni);
     463             :   }
     464           1 :   vec_sort_with_function (lfe->paths, lisp_gpe_fwd_entry_path_sort);
     465           1 : }
     466             : 
     467             : void
     468           1 : vnet_lisp_gpe_add_fwd_counters (vnet_lisp_gpe_add_del_fwd_entry_args_t * a,
     469             :                                 u32 fwd_entry_index)
     470             : {
     471             :   const lisp_gpe_adjacency_t *ladj;
     472             :   lisp_fwd_path_t *path;
     473           1 :   lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
     474             :   u8 *placeholder_elt;
     475             :   lisp_gpe_fwd_entry_t *lfe;
     476             :   lisp_gpe_fwd_entry_key_t fe_key;
     477             :   lisp_stats_key_t key;
     478             : 
     479           1 :   lfe = find_fwd_entry (lgm, a, &fe_key);
     480             : 
     481           1 :   if (!lfe)
     482           0 :     return;
     483             : 
     484           1 :   if (LISP_GPE_FWD_ENTRY_TYPE_NORMAL != lfe->type)
     485           0 :     return;
     486             : 
     487           1 :   clib_memset (&key, 0, sizeof (key));
     488           1 :   key.fwd_entry_index = fwd_entry_index;
     489             : 
     490           2 :   vec_foreach (path, lfe->paths)
     491             :   {
     492           1 :     ladj = lisp_gpe_adjacency_get (path->lisp_adj);
     493           1 :     key.tunnel_index = ladj->tunnel_index;
     494           1 :     lisp_stats_key_t *key_copy = clib_mem_alloc (sizeof (*key_copy));
     495           1 :     memcpy (key_copy, &key, sizeof (*key_copy));
     496           1 :     pool_get (lgm->placeholder_stats_pool, placeholder_elt);
     497           2 :     hash_set_mem (lgm->lisp_stats_index_by_key, key_copy,
     498             :                   placeholder_elt - lgm->placeholder_stats_pool);
     499             : 
     500           1 :     vlib_validate_combined_counter (&lgm->counters,
     501           1 :                                     placeholder_elt -
     502           1 :                                     lgm->placeholder_stats_pool);
     503           1 :     vlib_zero_combined_counter (&lgm->counters,
     504           1 :                                 placeholder_elt -
     505           1 :                                 lgm->placeholder_stats_pool);
     506             :   }
     507             : }
     508             : 
     509             : /**
     510             :  * @brief Add/Delete LISP IP forwarding entry.
     511             :  *
     512             :  * creation of forwarding entries for IP LISP overlay:
     513             :  *
     514             :  * @param[in]   lgm     Reference to @ref lisp_gpe_main_t.
     515             :  * @param[in]   a       Parameters for building the forwarding entry.
     516             :  *
     517             :  * @return 0 on success.
     518             :  */
     519             : static int
     520           1 : add_ip_fwd_entry (lisp_gpe_main_t * lgm,
     521             :                   vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
     522             : {
     523             :   lisp_gpe_fwd_entry_key_t key;
     524             :   lisp_gpe_fwd_entry_t *lfe;
     525             :   fib_protocol_t fproto;
     526             : 
     527           1 :   lfe = find_fwd_entry (lgm, a, &key);
     528             : 
     529           1 :   if (NULL != lfe)
     530             :     /* don't support updates */
     531           0 :     return VNET_API_ERROR_INVALID_VALUE;
     532             : 
     533           1 :   pool_get (lgm->lisp_fwd_entry_pool, lfe);
     534           1 :   clib_memset (lfe, 0, sizeof (*lfe));
     535           1 :   lfe->key = clib_mem_alloc (sizeof (key));
     536           1 :   memcpy (lfe->key, &key, sizeof (key));
     537             : 
     538           2 :   hash_set_mem (lgm->lisp_gpe_fwd_entries, lfe->key,
     539             :                 lfe - lgm->lisp_fwd_entry_pool);
     540           1 :   a->fwd_entry_index = lfe - lgm->lisp_fwd_entry_pool;
     541             : 
     542           1 :   fproto = (AF_IP4 == ip_prefix_version (&fid_addr_ippref (&lfe->key->rmt)) ?
     543           1 :             FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6);
     544             : 
     545           1 :   lfe->type = (a->is_negative ?
     546           1 :                LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE :
     547             :                LISP_GPE_FWD_ENTRY_TYPE_NORMAL);
     548           1 :   lfe->tenant = lisp_gpe_tenant_find_or_create (lfe->key->vni);
     549           1 :   lfe->eid_table_id = a->table_id;
     550           2 :   lfe->eid_fib_index = fib_table_find_or_create_and_lock (fproto,
     551           1 :                                                           lfe->eid_table_id,
     552             :                                                           FIB_SOURCE_LISP);
     553           1 :   lfe->is_src_dst = a->is_src_dst;
     554             : 
     555           1 :   if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE != lfe->type)
     556             :     {
     557           1 :       lisp_gpe_fwd_entry_mk_paths (lfe, a);
     558             :     }
     559             :   else
     560             :     {
     561           0 :       lfe->action = a->action;
     562             :     }
     563             : 
     564           1 :   lfe->dpoi_index = create_fib_entries (lfe);
     565           1 :   return (0);
     566             : }
     567             : 
     568             : static void
     569           1 : del_ip_fwd_entry_i (lisp_gpe_main_t * lgm, lisp_gpe_fwd_entry_t * lfe)
     570             : {
     571             :   lisp_fwd_path_t *path;
     572             :   fib_protocol_t fproto;
     573             : 
     574           1 :   if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE != lfe->type)
     575             :     {
     576           2 :       vec_foreach (path, lfe->paths)
     577             :       {
     578           1 :         lisp_gpe_adjacency_unlock (path->lisp_adj);
     579             :       }
     580             :     }
     581             : 
     582           1 :   delete_fib_entries (lfe);
     583             : 
     584           1 :   fproto = (AF_IP4 == ip_prefix_version (&fid_addr_ippref (&lfe->key->rmt)) ?
     585           1 :             FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6);
     586           1 :   fib_table_unlock (lfe->eid_fib_index, fproto, FIB_SOURCE_LISP);
     587             : 
     588           2 :   hash_unset_mem (lgm->lisp_gpe_fwd_entries, lfe->key);
     589           1 :   clib_mem_free (lfe->key);
     590           1 :   pool_put (lgm->lisp_fwd_entry_pool, lfe);
     591           1 : }
     592             : 
     593             : /**
     594             :  * @brief Add/Delete LISP IP forwarding entry.
     595             :  *
     596             :  * removal of forwarding entries for IP LISP overlay:
     597             :  *
     598             :  * @param[in]   lgm     Reference to @ref lisp_gpe_main_t.
     599             :  * @param[in]   a       Parameters for building the forwarding entry.
     600             :  *
     601             :  * @return 0 on success.
     602             :  */
     603             : static int
     604           1 : del_ip_fwd_entry (lisp_gpe_main_t * lgm,
     605             :                   vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
     606             : {
     607             :   lisp_gpe_fwd_entry_key_t key;
     608             :   lisp_gpe_fwd_entry_t *lfe;
     609             : 
     610           1 :   lfe = find_fwd_entry (lgm, a, &key);
     611             : 
     612           1 :   if (NULL == lfe)
     613             :     /* no such entry */
     614           0 :     return VNET_API_ERROR_INVALID_VALUE;
     615             : 
     616           1 :   del_ip_fwd_entry_i (lgm, lfe);
     617             : 
     618           1 :   return (0);
     619             : }
     620             : 
     621             : static void
     622           0 : make_mac_fib_key (BVT (clib_bihash_kv) * kv, u16 bd_index, u8 src_mac[6],
     623             :                   u8 dst_mac[6])
     624             : {
     625           0 :   kv->key[0] = (((u64) bd_index) << 48) | mac_to_u64 (dst_mac);
     626           0 :   kv->key[1] = mac_to_u64 (src_mac);
     627           0 :   kv->key[2] = 0;
     628           0 : }
     629             : 
     630             : /**
     631             :  * @brief Lookup L2 SD FIB entry
     632             :  *
     633             :  * Does a vni + dest + source lookup in the L2 LISP FIB. If the lookup fails
     634             :  * it tries a second time with source set to 0 (i.e., a simple dest lookup).
     635             :  *
     636             :  * @param[in]   lgm             Reference to @ref lisp_gpe_main_t.
     637             :  * @param[in]   bd_index        Bridge domain index.
     638             :  * @param[in]   src_mac         Source mac address.
     639             :  * @param[in]   dst_mac         Destination mac address.
     640             :  *
     641             :  * @return index of mapping matching the lookup key.
     642             :  */
     643             : index_t
     644           0 : lisp_l2_fib_lookup (lisp_gpe_main_t * lgm, u16 bd_index, u8 src_mac[6],
     645             :                     u8 dst_mac[6])
     646             : {
     647             :   int rv;
     648             :   BVT (clib_bihash_kv) kv, value;
     649             : 
     650           0 :   make_mac_fib_key (&kv, bd_index, src_mac, dst_mac);
     651           0 :   rv = BV (clib_bihash_search_inline_2) (&lgm->l2_fib, &kv, &value);
     652             : 
     653             :   /* no match, try with src 0, catch all for dst */
     654           0 :   if (rv != 0)
     655             :     {
     656           0 :       kv.key[1] = 0;
     657           0 :       rv = BV (clib_bihash_search_inline_2) (&lgm->l2_fib, &kv, &value);
     658           0 :       if (rv == 0)
     659           0 :         return value.value;
     660             :     }
     661             :   else
     662           0 :     return value.value;
     663             : 
     664           0 :   return lisp_gpe_main.l2_lb_cp_lkup.dpoi_index;
     665             : }
     666             : 
     667             : /**
     668             :  * @brief Add/del L2 SD FIB entry
     669             :  *
     670             :  * Inserts value in L2 FIB keyed by vni + dest + source. If entry is
     671             :  * overwritten the associated value is returned.
     672             :  *
     673             :  * @param[in]   lgm             Reference to @ref lisp_gpe_main_t.
     674             :  * @param[in]   bd_index        Bridge domain index.
     675             :  * @param[in]   src_mac         Source mac address.
     676             :  * @param[in]   dst_mac         Destination mac address.
     677             :  * @param[in]   val             Value to add.
     678             :  * @param[in]   is_add          Add/del flag.
     679             :  *
     680             :  * @return ~0 or value of overwritten entry.
     681             :  */
     682             : static u32
     683           0 : lisp_l2_fib_add_del_entry (u16 bd_index, u8 src_mac[6],
     684             :                            u8 dst_mac[6], const dpo_id_t * dpo, u8 is_add)
     685             : {
     686           0 :   lisp_gpe_main_t *lgm = &lisp_gpe_main;
     687             :   BVT (clib_bihash_kv) kv, value;
     688           0 :   u32 old_val = ~0;
     689             : 
     690           0 :   make_mac_fib_key (&kv, bd_index, src_mac, dst_mac);
     691             : 
     692           0 :   if (BV (clib_bihash_search) (&lgm->l2_fib, &kv, &value) == 0)
     693           0 :     old_val = value.value;
     694             : 
     695           0 :   if (!is_add)
     696           0 :     BV (clib_bihash_add_del) (&lgm->l2_fib, &kv, 0 /* is_add */ );
     697             :   else
     698             :     {
     699           0 :       kv.value = dpo->dpoi_index;
     700           0 :       BV (clib_bihash_add_del) (&lgm->l2_fib, &kv, 1 /* is_add */ );
     701             :     }
     702           0 :   return old_val;
     703             : }
     704             : 
     705             : #define L2_FIB_DEFAULT_HASH_NUM_BUCKETS (64 * 1024)
     706             : #define L2_FIB_DEFAULT_HASH_MEMORY_SIZE (32<<20)
     707             : 
     708             : static void
     709         575 : l2_fib_init (lisp_gpe_main_t * lgm)
     710             : {
     711             :   index_t lbi;
     712             : 
     713         575 :   BV (clib_bihash_init) (&lgm->l2_fib, "l2 fib",
     714         575 :                          1 << max_log2 (L2_FIB_DEFAULT_HASH_NUM_BUCKETS),
     715             :                          L2_FIB_DEFAULT_HASH_MEMORY_SIZE);
     716             : 
     717             :   /*
     718             :    * the result from a 'miss' in a L2 Table
     719             :    */
     720         575 :   lbi = load_balance_create (1, DPO_PROTO_ETHERNET, 0);
     721         575 :   load_balance_set_bucket (lbi, 0, lisp_cp_dpo_get (DPO_PROTO_ETHERNET));
     722             : 
     723         575 :   dpo_set (&lgm->l2_lb_cp_lkup, DPO_LOAD_BALANCE, DPO_PROTO_ETHERNET, lbi);
     724         575 : }
     725             : 
     726             : static void
     727           0 : del_l2_fwd_entry_i (lisp_gpe_main_t * lgm, lisp_gpe_fwd_entry_t * lfe)
     728             : {
     729             :   lisp_fwd_path_t *path;
     730             : 
     731           0 :   if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE != lfe->type)
     732             :     {
     733           0 :       vec_foreach (path, lfe->paths)
     734             :       {
     735           0 :         lisp_gpe_adjacency_unlock (path->lisp_adj);
     736             :       }
     737           0 :       fib_path_list_child_remove (lfe->l2.path_list_index,
     738             :                                   lfe->l2.child_index);
     739             :     }
     740             : 
     741           0 :   lisp_l2_fib_add_del_entry (lfe->l2.eid_bd_index,
     742           0 :                              fid_addr_mac (&lfe->key->lcl),
     743           0 :                              fid_addr_mac (&lfe->key->rmt), NULL, 0);
     744             : 
     745           0 :   hash_unset_mem (lgm->lisp_gpe_fwd_entries, lfe->key);
     746           0 :   clib_mem_free (lfe->key);
     747           0 :   pool_put (lgm->lisp_fwd_entry_pool, lfe);
     748           0 : }
     749             : 
     750             : /**
     751             :  * @brief Delete LISP L2 forwarding entry.
     752             :  *
     753             :  * Coordinates the removal of forwarding entries for L2 LISP overlay:
     754             :  *
     755             :  * @param[in]   lgm     Reference to @ref lisp_gpe_main_t.
     756             :  * @param[in]   a       Parameters for building the forwarding entry.
     757             :  *
     758             :  * @return 0 on success.
     759             :  */
     760             : static int
     761           0 : del_l2_fwd_entry (lisp_gpe_main_t * lgm,
     762             :                   vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
     763             : {
     764             :   lisp_gpe_fwd_entry_key_t key;
     765             :   lisp_gpe_fwd_entry_t *lfe;
     766             : 
     767           0 :   lfe = find_fwd_entry (lgm, a, &key);
     768             : 
     769           0 :   if (NULL == lfe)
     770           0 :     return VNET_API_ERROR_INVALID_VALUE;
     771             : 
     772           0 :   del_l2_fwd_entry_i (lgm, lfe);
     773             : 
     774           0 :   return (0);
     775             : }
     776             : 
     777             : /**
     778             :  * @brief Construct and insert the forwarding information used by an L2 entry
     779             :  */
     780             : static void
     781           0 : lisp_gpe_l2_update_fwding (lisp_gpe_fwd_entry_t * lfe)
     782             : {
     783           0 :   lisp_gpe_main_t *lgm = &lisp_gpe_main;
     784           0 :   dpo_id_t dpo = DPO_INVALID;
     785             : 
     786           0 :   if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE != lfe->type)
     787             :     {
     788           0 :       fib_path_list_contribute_forwarding (lfe->l2.path_list_index,
     789             :                                            FIB_FORW_CHAIN_TYPE_ETHERNET,
     790             :                                            FIB_PATH_LIST_FWD_FLAG_NONE,
     791             :                                            &lfe->l2.dpo);
     792           0 :       dpo_copy (&dpo, &lfe->l2.dpo);
     793             :     }
     794             :   else
     795             :     {
     796           0 :       switch (lfe->action)
     797             :         {
     798           0 :         case SEND_MAP_REQUEST:
     799           0 :           dpo_copy (&dpo, &lgm->l2_lb_cp_lkup);
     800           0 :           break;
     801           0 :         case NO_ACTION:
     802             :         case FORWARD_NATIVE:
     803             :         case DROP:
     804           0 :           dpo_copy (&dpo, drop_dpo_get (DPO_PROTO_ETHERNET));
     805             :         }
     806           0 :     }
     807             : 
     808             :   /* add entry to l2 lisp fib */
     809           0 :   lisp_l2_fib_add_del_entry (lfe->l2.eid_bd_index,
     810           0 :                              fid_addr_mac (&lfe->key->lcl),
     811           0 :                              fid_addr_mac (&lfe->key->rmt), &dpo, 1);
     812           0 :   lfe->dpoi_index = dpo.dpoi_index;
     813             : 
     814           0 :   dpo_reset (&dpo);
     815           0 : }
     816             : 
     817             : /**
     818             :  * @brief Add LISP L2 forwarding entry.
     819             :  *
     820             :  * Coordinates the creation of forwarding entries for L2 LISP overlay:
     821             :  * creates lisp-gpe tunnel and injects new entry in Source/Dest L2 FIB.
     822             :  *
     823             :  * @param[in]   lgm     Reference to @ref lisp_gpe_main_t.
     824             :  * @param[in]   a       Parameters for building the forwarding entry.
     825             :  *
     826             :  * @return 0 on success.
     827             :  */
     828             : static int
     829           0 : add_l2_fwd_entry (lisp_gpe_main_t * lgm,
     830             :                   vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
     831             : {
     832             :   lisp_gpe_fwd_entry_key_t key;
     833           0 :   bd_main_t *bdm = &bd_main;
     834             :   lisp_gpe_fwd_entry_t *lfe;
     835             :   uword *bd_indexp;
     836             : 
     837           0 :   bd_indexp = hash_get (bdm->bd_index_by_bd_id, a->bd_id);
     838           0 :   if (!bd_indexp)
     839             :     {
     840           0 :       clib_warning ("bridge domain %d doesn't exist", a->bd_id);
     841           0 :       return -1;
     842             :     }
     843             : 
     844           0 :   lfe = find_fwd_entry (lgm, a, &key);
     845             : 
     846           0 :   if (NULL != lfe)
     847             :     /* don't support updates */
     848           0 :     return VNET_API_ERROR_INVALID_VALUE;
     849             : 
     850           0 :   pool_get (lgm->lisp_fwd_entry_pool, lfe);
     851           0 :   clib_memset (lfe, 0, sizeof (*lfe));
     852           0 :   lfe->key = clib_mem_alloc (sizeof (key));
     853           0 :   memcpy (lfe->key, &key, sizeof (key));
     854             : 
     855           0 :   hash_set_mem (lgm->lisp_gpe_fwd_entries, lfe->key,
     856             :                 lfe - lgm->lisp_fwd_entry_pool);
     857           0 :   a->fwd_entry_index = lfe - lgm->lisp_fwd_entry_pool;
     858             : 
     859           0 :   lfe->type = (a->is_negative ?
     860           0 :                LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE :
     861             :                LISP_GPE_FWD_ENTRY_TYPE_NORMAL);
     862           0 :   lfe->l2.eid_bd_id = a->bd_id;
     863           0 :   lfe->l2.eid_bd_index = bd_indexp[0];
     864           0 :   lfe->tenant = lisp_gpe_tenant_find_or_create (lfe->key->vni);
     865             : 
     866           0 :   if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE != lfe->type)
     867             :     {
     868             :       fib_route_path_t *rpaths;
     869             : 
     870             :       /*
     871             :        * Make the sorted array of LISP paths with their resp. adjacency
     872             :        */
     873           0 :       lisp_gpe_fwd_entry_mk_paths (lfe, a);
     874             : 
     875             :       /*
     876             :        * From the LISP paths, construct a FIB path list that will
     877             :        * contribute a load-balance.
     878             :        */
     879           0 :       rpaths = lisp_gpe_mk_fib_paths (lfe->paths);
     880             : 
     881           0 :       lfe->l2.path_list_index =
     882           0 :         fib_path_list_create (FIB_PATH_LIST_FLAG_NONE, rpaths);
     883             : 
     884             :       /*
     885             :        * become a child of the path-list so we receive updates when
     886             :        * its forwarding state changes. this includes an implicit lock.
     887             :        */
     888           0 :       lfe->l2.child_index =
     889           0 :         fib_path_list_child_add (lfe->l2.path_list_index,
     890             :                                  FIB_NODE_TYPE_LISP_GPE_FWD_ENTRY,
     891           0 :                                  lfe - lgm->lisp_fwd_entry_pool);
     892             :     }
     893             :   else
     894             :     {
     895           0 :       lfe->action = a->action;
     896             :     }
     897             : 
     898           0 :   lisp_gpe_l2_update_fwding (lfe);
     899             : 
     900           0 :   return 0;
     901             : }
     902             : 
     903             : /**
     904             :  * @brief Lookup NSH SD FIB entry
     905             :  *
     906             :  * Does an SPI+SI lookup in the NSH LISP FIB.
     907             :  *
     908             :  * @param[in]   lgm             Reference to @ref lisp_gpe_main_t.
     909             :  * @param[in]   spi_si          SPI + SI.
     910             :  *
     911             :  * @return next node index.
     912             :  */
     913             : const dpo_id_t *
     914           0 : lisp_nsh_fib_lookup (lisp_gpe_main_t * lgm, u32 spi_si_net_order)
     915             : {
     916             :   int rv;
     917             :   BVT (clib_bihash_kv) kv, value;
     918             : 
     919           0 :   clib_memset (&kv, 0, sizeof (kv));
     920           0 :   kv.key[0] = spi_si_net_order;
     921           0 :   rv = BV (clib_bihash_search_inline_2) (&lgm->nsh_fib, &kv, &value);
     922             : 
     923           0 :   if (rv != 0)
     924             :     {
     925           0 :       return lgm->nsh_cp_lkup;
     926             :     }
     927             :   else
     928             :     {
     929             :       lisp_gpe_fwd_entry_t *lfe;
     930           0 :       lfe = pool_elt_at_index (lgm->lisp_fwd_entry_pool, value.value);
     931           0 :       return &lfe->nsh.choice;
     932             :     }
     933             : }
     934             : 
     935             : /**
     936             :  * @brief Add/del NSH FIB entry
     937             :  *
     938             :  * Inserts value in NSH FIB keyed by SPI+SI. If entry is
     939             :  * overwritten the associated value is returned.
     940             :  *
     941             :  * @param[in]   lgm             Reference to @ref lisp_gpe_main_t.
     942             :  * @param[in]   spi_si          SPI + SI.
     943             :  * @param[in]   dpo             Load balanced mapped to SPI + SI
     944             :  *
     945             :  * @return ~0 or value of overwritten entry.
     946             :  */
     947             : static u32
     948           0 : lisp_nsh_fib_add_del_entry (u32 spi_si_host_order, u32 lfei, u8 is_add)
     949             : {
     950           0 :   lisp_gpe_main_t *lgm = &lisp_gpe_main;
     951             :   BVT (clib_bihash_kv) kv, value;
     952           0 :   u32 old_val = ~0;
     953             : 
     954           0 :   clib_memset (&kv, 0, sizeof (kv));
     955           0 :   kv.key[0] = clib_host_to_net_u32 (spi_si_host_order);
     956           0 :   kv.value = 0ULL;
     957             : 
     958           0 :   if (BV (clib_bihash_search) (&lgm->nsh_fib, &kv, &value) == 0)
     959           0 :     old_val = value.value;
     960             : 
     961           0 :   if (!is_add)
     962           0 :     BV (clib_bihash_add_del) (&lgm->nsh_fib, &kv, 0 /* is_add */ );
     963             :   else
     964             :     {
     965           0 :       kv.value = lfei;
     966           0 :       BV (clib_bihash_add_del) (&lgm->nsh_fib, &kv, 1 /* is_add */ );
     967             :     }
     968           0 :   return old_val;
     969             : }
     970             : 
     971             : #define NSH_FIB_DEFAULT_HASH_NUM_BUCKETS (64 * 1024)
     972             : #define NSH_FIB_DEFAULT_HASH_MEMORY_SIZE (32<<20)
     973             : 
     974             : static void
     975         575 : nsh_fib_init (lisp_gpe_main_t * lgm)
     976             : {
     977         575 :   BV (clib_bihash_init) (&lgm->nsh_fib, "nsh fib",
     978         575 :                          1 << max_log2 (NSH_FIB_DEFAULT_HASH_NUM_BUCKETS),
     979             :                          NSH_FIB_DEFAULT_HASH_MEMORY_SIZE);
     980             : 
     981             :   /*
     982             :    * the result from a 'miss' in a NSH Table
     983             :    */
     984         575 :   lgm->nsh_cp_lkup = lisp_cp_dpo_get (DPO_PROTO_NSH);
     985         575 : }
     986             : 
     987             : static void
     988           0 : del_nsh_fwd_entry_i (lisp_gpe_main_t * lgm, lisp_gpe_fwd_entry_t * lfe)
     989             : {
     990             :   lisp_fwd_path_t *path;
     991             : 
     992           0 :   if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE != lfe->type)
     993             :     {
     994           0 :       vec_foreach (path, lfe->paths)
     995             :       {
     996           0 :         lisp_gpe_adjacency_unlock (path->lisp_adj);
     997             :       }
     998           0 :       fib_path_list_child_remove (lfe->nsh.path_list_index,
     999             :                                   lfe->nsh.child_index);
    1000           0 :       dpo_reset (&lfe->nsh.choice);
    1001             :     }
    1002             : 
    1003           0 :   lisp_nsh_fib_add_del_entry (fid_addr_nsh (&lfe->key->rmt), (u32) ~ 0, 0);
    1004             : 
    1005           0 :   hash_unset_mem (lgm->lisp_gpe_fwd_entries, lfe->key);
    1006           0 :   clib_mem_free (lfe->key);
    1007           0 :   pool_put (lgm->lisp_fwd_entry_pool, lfe);
    1008           0 : }
    1009             : 
    1010             : /**
    1011             :  * @brief Delete LISP NSH forwarding entry.
    1012             :  *
    1013             :  * Coordinates the removal of forwarding entries for NSH LISP overlay:
    1014             :  *
    1015             :  * @param[in]   lgm     Reference to @ref lisp_gpe_main_t.
    1016             :  * @param[in]   a       Parameters for building the forwarding entry.
    1017             :  *
    1018             :  * @return 0 on success.
    1019             :  */
    1020             : static int
    1021           0 : del_nsh_fwd_entry (lisp_gpe_main_t * lgm,
    1022             :                    vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
    1023             : {
    1024             :   lisp_gpe_fwd_entry_key_t key;
    1025             :   lisp_gpe_fwd_entry_t *lfe;
    1026             : 
    1027           0 :   lfe = find_fwd_entry (lgm, a, &key);
    1028             : 
    1029           0 :   if (NULL == lfe)
    1030           0 :     return VNET_API_ERROR_INVALID_VALUE;
    1031             : 
    1032           0 :   del_nsh_fwd_entry_i (lgm, lfe);
    1033             : 
    1034           0 :   return (0);
    1035             : }
    1036             : 
    1037             : /**
    1038             :  * @brief Construct and insert the forwarding information used by an NSH entry
    1039             :  */
    1040             : static void
    1041           0 : lisp_gpe_nsh_update_fwding (lisp_gpe_fwd_entry_t * lfe)
    1042             : {
    1043           0 :   lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
    1044           0 :   dpo_id_t dpo = DPO_INVALID;
    1045             :   vnet_hw_interface_t *hi;
    1046             :   uword *hip;
    1047             : 
    1048           0 :   if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE != lfe->type)
    1049             :     {
    1050           0 :       fib_path_list_contribute_forwarding (lfe->nsh.path_list_index,
    1051             :                                            FIB_FORW_CHAIN_TYPE_NSH,
    1052             :                                            FIB_PATH_LIST_FWD_FLAG_NONE,
    1053             :                                            &lfe->nsh.dpo);
    1054             : 
    1055             :       /*
    1056             :        * LISP encap is always the same for this SPI+SI so we do that hash now
    1057             :        * and stack on the choice.
    1058             :        */
    1059           0 :       if (DPO_LOAD_BALANCE == lfe->nsh.dpo.dpoi_type)
    1060             :         {
    1061             :           const dpo_id_t *tmp;
    1062             :           const load_balance_t *lb;
    1063             :           int hash;
    1064             : 
    1065           0 :           lb = load_balance_get (lfe->nsh.dpo.dpoi_index);
    1066           0 :           hash = fid_addr_nsh (&lfe->key->rmt) % lb->lb_n_buckets;
    1067             :           tmp =
    1068           0 :             load_balance_get_bucket_i (lb, hash & lb->lb_n_buckets_minus_1);
    1069             : 
    1070           0 :           dpo_copy (&dpo, tmp);
    1071             :         }
    1072             :     }
    1073             :   else
    1074             :     {
    1075           0 :       switch (lfe->action)
    1076             :         {
    1077           0 :         case SEND_MAP_REQUEST:
    1078           0 :           dpo_copy (&dpo, lgm->nsh_cp_lkup);
    1079           0 :           break;
    1080           0 :         case NO_ACTION:
    1081             :         case FORWARD_NATIVE:
    1082             :         case DROP:
    1083           0 :           dpo_copy (&dpo, drop_dpo_get (DPO_PROTO_NSH));
    1084             :         }
    1085           0 :     }
    1086             : 
    1087             :   /* We have only one nsh-lisp interface (no NSH virtualization) */
    1088           0 :   hip = hash_get (lgm->nsh_ifaces.hw_if_index_by_dp_table, 0);
    1089           0 :   if (hip)
    1090             :     {
    1091           0 :       hi = vnet_get_hw_interface (lgm->vnet_main, hip[0]);
    1092           0 :       dpo_stack_from_node (hi->tx_node_index, &lfe->nsh.choice, &dpo);
    1093             :     }
    1094             :   /* add entry to nsh lisp fib */
    1095           0 :   lisp_nsh_fib_add_del_entry (fid_addr_nsh (&lfe->key->rmt),
    1096           0 :                               lfe - lgm->lisp_fwd_entry_pool, 1);
    1097           0 :   dpo_reset (&dpo);
    1098             : 
    1099           0 : }
    1100             : 
    1101             : /**
    1102             :  * @brief Add LISP NSH forwarding entry.
    1103             :  *
    1104             :  * Coordinates the creation of forwarding entries for L2 LISP overlay:
    1105             :  * creates lisp-gpe tunnel and injects new entry in Source/Dest L2 FIB.
    1106             :  *
    1107             :  * @param[in]   lgm     Reference to @ref lisp_gpe_main_t.
    1108             :  * @param[in]   a       Parameters for building the forwarding entry.
    1109             :  *
    1110             :  * @return 0 on success.
    1111             :  */
    1112             : static int
    1113           0 : add_nsh_fwd_entry (lisp_gpe_main_t * lgm,
    1114             :                    vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
    1115             : {
    1116             :   lisp_gpe_fwd_entry_key_t key;
    1117             :   lisp_gpe_fwd_entry_t *lfe;
    1118             : 
    1119           0 :   lfe = find_fwd_entry (lgm, a, &key);
    1120             : 
    1121           0 :   if (NULL != lfe)
    1122             :     /* don't support updates */
    1123           0 :     return VNET_API_ERROR_INVALID_VALUE;
    1124             : 
    1125           0 :   pool_get (lgm->lisp_fwd_entry_pool, lfe);
    1126           0 :   clib_memset (lfe, 0, sizeof (*lfe));
    1127           0 :   lfe->key = clib_mem_alloc (sizeof (key));
    1128           0 :   memcpy (lfe->key, &key, sizeof (key));
    1129             : 
    1130           0 :   hash_set_mem (lgm->lisp_gpe_fwd_entries, lfe->key,
    1131             :                 lfe - lgm->lisp_fwd_entry_pool);
    1132           0 :   a->fwd_entry_index = lfe - lgm->lisp_fwd_entry_pool;
    1133             : 
    1134           0 :   lfe->type = (a->is_negative ?
    1135           0 :                LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE :
    1136             :                LISP_GPE_FWD_ENTRY_TYPE_NORMAL);
    1137           0 :   lfe->tenant = 0;
    1138             : 
    1139           0 :   if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE != lfe->type)
    1140             :     {
    1141             :       fib_route_path_t *rpaths;
    1142             : 
    1143             :       /*
    1144             :        * Make the sorted array of LISP paths with their resp. adjacency
    1145             :        */
    1146           0 :       lisp_gpe_fwd_entry_mk_paths (lfe, a);
    1147             : 
    1148             :       /*
    1149             :        * From the LISP paths, construct a FIB path list that will
    1150             :        * contribute a load-balance.
    1151             :        */
    1152           0 :       rpaths = lisp_gpe_mk_fib_paths (lfe->paths);
    1153             : 
    1154           0 :       lfe->nsh.path_list_index =
    1155           0 :         fib_path_list_create (FIB_PATH_LIST_FLAG_NONE, rpaths);
    1156             : 
    1157             :       /*
    1158             :        * become a child of the path-list so we receive updates when
    1159             :        * its forwarding state changes. this includes an implicit lock.
    1160             :        */
    1161           0 :       lfe->nsh.child_index =
    1162           0 :         fib_path_list_child_add (lfe->nsh.path_list_index,
    1163             :                                  FIB_NODE_TYPE_LISP_GPE_FWD_ENTRY,
    1164           0 :                                  lfe - lgm->lisp_fwd_entry_pool);
    1165             :     }
    1166             :   else
    1167             :     {
    1168           0 :       lfe->action = a->action;
    1169             :     }
    1170             : 
    1171           0 :   lisp_gpe_nsh_update_fwding (lfe);
    1172             : 
    1173           0 :   return 0;
    1174             : }
    1175             : 
    1176             : /**
    1177             :  * @brief conver from the embedded fib_node_t struct to the LSIP entry
    1178             :  */
    1179             : static lisp_gpe_fwd_entry_t *
    1180           0 : lisp_gpe_fwd_entry_from_fib_node (fib_node_t * node)
    1181             : {
    1182           0 :   return ((lisp_gpe_fwd_entry_t *) (((char *) node) -
    1183             :                                     STRUCT_OFFSET_OF (lisp_gpe_fwd_entry_t,
    1184             :                                                       node)));
    1185             : }
    1186             : 
    1187             : /**
    1188             :  * @brief Function invoked during a backwalk of the FIB graph
    1189             :  */
    1190             : static fib_node_back_walk_rc_t
    1191           0 : lisp_gpe_fib_node_back_walk (fib_node_t * node,
    1192             :                              fib_node_back_walk_ctx_t * ctx)
    1193             : {
    1194           0 :   lisp_gpe_fwd_entry_t *lfe = lisp_gpe_fwd_entry_from_fib_node (node);
    1195             : 
    1196           0 :   if (fid_addr_type (&lfe->key->rmt) == FID_ADDR_MAC)
    1197           0 :     lisp_gpe_l2_update_fwding (lfe);
    1198           0 :   else if (fid_addr_type (&lfe->key->rmt) == FID_ADDR_NSH)
    1199           0 :     lisp_gpe_nsh_update_fwding (lfe);
    1200             : 
    1201           0 :   return (FIB_NODE_BACK_WALK_CONTINUE);
    1202             : }
    1203             : 
    1204             : /**
    1205             :  * @brief Get a fib_node_t struct from the index of a LISP fwd entry
    1206             :  */
    1207             : static fib_node_t *
    1208           0 : lisp_gpe_fwd_entry_get_fib_node (fib_node_index_t index)
    1209             : {
    1210           0 :   lisp_gpe_main_t *lgm = &lisp_gpe_main;
    1211             :   lisp_gpe_fwd_entry_t *lfe;
    1212             : 
    1213           0 :   lfe = pool_elt_at_index (lgm->lisp_fwd_entry_pool, index);
    1214             : 
    1215           0 :   return (&(lfe->node));
    1216             : }
    1217             : 
    1218             : /**
    1219             :  * @brief An indication from the graph that the last lock has gone
    1220             :  */
    1221             : static void
    1222           0 : lisp_gpe_fwd_entry_fib_node_last_lock_gone (fib_node_t * node)
    1223             : {
    1224             :   /* We don't manage the locks of the LISP objects via the graph, since
    1225             :    * this object has no children. so this is a no-op. */
    1226           0 : }
    1227             : 
    1228             : /**
    1229             :  * @brief Virtual function table to register with FIB for the LISP type
    1230             :  */
    1231             : const static fib_node_vft_t lisp_fwd_vft = {
    1232             :   .fnv_get = lisp_gpe_fwd_entry_get_fib_node,
    1233             :   .fnv_last_lock = lisp_gpe_fwd_entry_fib_node_last_lock_gone,
    1234             :   .fnv_back_walk = lisp_gpe_fib_node_back_walk,
    1235             : };
    1236             : 
    1237             : /**
    1238             :  * @brief Forwarding entry create/remove dispatcher.
    1239             :  *
    1240             :  * Calls l2 or l3 forwarding entry add/del function based on input data.
    1241             :  *
    1242             :  * @param[in]   a       Forwarding entry parameters.
    1243             :  * @param[out]  hw_if_indexp    NOT USED
    1244             :  *
    1245             :  * @return 0 on success.
    1246             :  */
    1247             : int
    1248           2 : vnet_lisp_gpe_add_del_fwd_entry (vnet_lisp_gpe_add_del_fwd_entry_args_t * a,
    1249             :                                  u32 * hw_if_indexp)
    1250             : {
    1251           2 :   lisp_gpe_main_t *lgm = &lisp_gpe_main;
    1252             :   u8 type;
    1253             : 
    1254           2 :   if (vnet_lisp_gpe_enable_disable_status () == 0)
    1255             :     {
    1256           0 :       clib_warning ("LISP is disabled!");
    1257           0 :       return VNET_API_ERROR_LISP_DISABLED;
    1258             :     }
    1259             : 
    1260           2 :   type = gid_address_type (&a->rmt_eid);
    1261           2 :   switch (type)
    1262             :     {
    1263           2 :     case GID_ADDR_IP_PREFIX:
    1264           2 :       if (a->is_add)
    1265           1 :         return add_ip_fwd_entry (lgm, a);
    1266             :       else
    1267           1 :         return del_ip_fwd_entry (lgm, a);
    1268             :       break;
    1269           0 :     case GID_ADDR_MAC:
    1270           0 :       if (a->is_add)
    1271           0 :         return add_l2_fwd_entry (lgm, a);
    1272             :       else
    1273           0 :         return del_l2_fwd_entry (lgm, a);
    1274           0 :     case GID_ADDR_NSH:
    1275           0 :       if (a->is_add)
    1276           0 :         return add_nsh_fwd_entry (lgm, a);
    1277             :       else
    1278           0 :         return del_nsh_fwd_entry (lgm, a);
    1279           0 :     default:
    1280           0 :       clib_warning ("Forwarding entries for type %d not supported!", type);
    1281           0 :       return -1;
    1282             :     }
    1283             : }
    1284             : 
    1285             : int
    1286           0 : vnet_lisp_flush_stats (void)
    1287             : {
    1288           0 :   lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
    1289           0 :   vlib_combined_counter_main_t *cm = &lgm->counters;
    1290             :   u32 i;
    1291             : 
    1292           0 :   if (cm->counters == NULL)
    1293           0 :     return 0;
    1294             : 
    1295           0 :   for (i = 0; i < vlib_combined_counter_n_counters (cm); i++)
    1296           0 :     vlib_zero_combined_counter (cm, i);
    1297             : 
    1298           0 :   return 0;
    1299             : }
    1300             : 
    1301             : static void
    1302           1 : lisp_del_adj_stats (lisp_gpe_main_t * lgm, u32 fwd_entry_index, u32 ti)
    1303             : {
    1304             :   hash_pair_t *hp;
    1305             :   lisp_stats_key_t key;
    1306             :   void *key_copy;
    1307             :   uword *p;
    1308             :   u8 *s;
    1309             : 
    1310           1 :   clib_memset (&key, 0, sizeof (key));
    1311           1 :   key.fwd_entry_index = fwd_entry_index;
    1312           1 :   key.tunnel_index = ti;
    1313             : 
    1314           1 :   p = hash_get_mem (lgm->lisp_stats_index_by_key, &key);
    1315           1 :   if (p)
    1316             :     {
    1317           1 :       s = pool_elt_at_index (lgm->placeholder_stats_pool, p[0]);
    1318           1 :       hp = hash_get_pair (lgm->lisp_stats_index_by_key, &key);
    1319           1 :       key_copy = (void *) (hp->key);
    1320           1 :       hash_unset_mem (lgm->lisp_stats_index_by_key, &key);
    1321           1 :       clib_mem_free (key_copy);
    1322           1 :       pool_put (lgm->placeholder_stats_pool, s);
    1323             :     }
    1324           1 : }
    1325             : 
    1326             : void
    1327           1 : vnet_lisp_gpe_del_fwd_counters (vnet_lisp_gpe_add_del_fwd_entry_args_t * a,
    1328             :                                 u32 fwd_entry_index)
    1329             : {
    1330           1 :   lisp_gpe_main_t *lgm = &lisp_gpe_main;
    1331             :   lisp_gpe_fwd_entry_key_t fe_key;
    1332             :   lisp_gpe_fwd_entry_t *lfe;
    1333             :   lisp_fwd_path_t *path;
    1334             :   const lisp_gpe_adjacency_t *ladj;
    1335             : 
    1336           1 :   lfe = find_fwd_entry (lgm, a, &fe_key);
    1337           1 :   if (!lfe)
    1338           0 :     return;
    1339             : 
    1340           1 :   if (LISP_GPE_FWD_ENTRY_TYPE_NORMAL != lfe->type)
    1341           0 :     return;
    1342             : 
    1343           2 :   vec_foreach (path, lfe->paths)
    1344             :   {
    1345           1 :     ladj = lisp_gpe_adjacency_get (path->lisp_adj);
    1346           1 :     lisp_del_adj_stats (lgm, fwd_entry_index, ladj->tunnel_index);
    1347             :   }
    1348             : }
    1349             : 
    1350             : /**
    1351             :  * @brief Flush all the forwrding entries
    1352             :  */
    1353             : void
    1354           0 : vnet_lisp_gpe_fwd_entry_flush (void)
    1355             : {
    1356           0 :   lisp_gpe_main_t *lgm = &lisp_gpe_main;
    1357             :   lisp_gpe_fwd_entry_t *lfe;
    1358             : 
    1359             :   /* *INDENT-OFF* */
    1360           0 :   pool_foreach (lfe, lgm->lisp_fwd_entry_pool)
    1361             :    {
    1362           0 :     switch (fid_addr_type(&lfe->key->rmt))
    1363             :       {
    1364           0 :       case FID_ADDR_MAC:
    1365           0 :         del_l2_fwd_entry_i (lgm, lfe);
    1366           0 :         break;
    1367           0 :       case FID_ADDR_IP_PREF:
    1368           0 :         del_ip_fwd_entry_i (lgm, lfe);
    1369           0 :         break;
    1370           0 :       case FID_ADDR_NSH:
    1371           0 :         del_nsh_fwd_entry_i (lgm, lfe);
    1372           0 :         break;
    1373             :       }
    1374           0 :   }
    1375             :   /* *INDENT-ON* */
    1376           0 : }
    1377             : 
    1378             : static u8 *
    1379           0 : format_lisp_fwd_path (u8 * s, va_list * ap)
    1380             : {
    1381           0 :   lisp_fwd_path_t *lfp = va_arg (*ap, lisp_fwd_path_t *);
    1382             : 
    1383           0 :   s = format (s, "weight:%d ", lfp->weight);
    1384           0 :   s = format (s, "adj:[%U]\n",
    1385             :               format_lisp_gpe_adjacency,
    1386             :               lisp_gpe_adjacency_get (lfp->lisp_adj),
    1387             :               LISP_GPE_ADJ_FORMAT_FLAG_NONE);
    1388             : 
    1389           0 :   return (s);
    1390             : }
    1391             : 
    1392             : typedef enum lisp_gpe_fwd_entry_format_flag_t_
    1393             : {
    1394             :   LISP_GPE_FWD_ENTRY_FORMAT_NONE = (0 << 0),
    1395             :   LISP_GPE_FWD_ENTRY_FORMAT_DETAIL = (1 << 1),
    1396             : } lisp_gpe_fwd_entry_format_flag_t;
    1397             : 
    1398             : 
    1399             : static u8 *
    1400           0 : format_lisp_gpe_fwd_entry (u8 * s, va_list * ap)
    1401             : {
    1402           0 :   lisp_gpe_main_t *lgm = &lisp_gpe_main;
    1403           0 :   lisp_gpe_fwd_entry_t *lfe = va_arg (*ap, lisp_gpe_fwd_entry_t *);
    1404           0 :   lisp_gpe_fwd_entry_format_flag_t flags =
    1405             :     va_arg (*ap, lisp_gpe_fwd_entry_format_flag_t);
    1406             : 
    1407           0 :   s = format (s, "VNI:%d VRF:%d EID: %U -> %U  [index:%d]",
    1408           0 :               lfe->key->vni, lfe->eid_table_id,
    1409           0 :               format_fid_address, &lfe->key->lcl,
    1410           0 :               format_fid_address, &lfe->key->rmt,
    1411           0 :               lfe - lgm->lisp_fwd_entry_pool);
    1412             : 
    1413           0 :   if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE == lfe->type)
    1414             :     {
    1415           0 :       s = format (s, "\n Negative - action:%U",
    1416           0 :                   format_negative_mapping_action, lfe->action);
    1417             :     }
    1418             :   else
    1419             :     {
    1420             :       lisp_fwd_path_t *path;
    1421             : 
    1422           0 :       s = format (s, "\n via:");
    1423           0 :       vec_foreach (path, lfe->paths)
    1424             :       {
    1425           0 :         s = format (s, "\n  %U", format_lisp_fwd_path, path);
    1426             :       }
    1427             :     }
    1428             : 
    1429           0 :   if (flags & LISP_GPE_FWD_ENTRY_FORMAT_DETAIL)
    1430             :     {
    1431           0 :       switch (fid_addr_type (&lfe->key->rmt))
    1432             :         {
    1433           0 :         case FID_ADDR_MAC:
    1434           0 :           s = format (s, " fib-path-list:%d\n", lfe->l2.path_list_index);
    1435           0 :           s = format (s, " dpo:%U\n", format_dpo_id, &lfe->l2.dpo, 0);
    1436           0 :           break;
    1437           0 :         case FID_ADDR_NSH:
    1438           0 :           s = format (s, " fib-path-list:%d\n", lfe->nsh.path_list_index);
    1439           0 :           s = format (s, " dpo:%U\n", format_dpo_id, &lfe->nsh.dpo, 0);
    1440           0 :           break;
    1441           0 :         case FID_ADDR_IP_PREF:
    1442           0 :           break;
    1443             :         }
    1444           0 :     }
    1445             : 
    1446           0 :   return (s);
    1447             : }
    1448             : 
    1449             : static clib_error_t *
    1450           0 : lisp_gpe_fwd_entry_show (vlib_main_t * vm,
    1451             :                          unformat_input_t * input, vlib_cli_command_t * cmd)
    1452             : {
    1453           0 :   lisp_gpe_main_t *lgm = &lisp_gpe_main;
    1454             :   lisp_gpe_fwd_entry_t *lfe;
    1455             :   index_t index;
    1456           0 :   u32 vni = ~0;
    1457             : 
    1458           0 :   if (unformat (input, "vni %d", &vni))
    1459             :     ;
    1460           0 :   else if (unformat (input, "%d", &index))
    1461             :     {
    1462           0 :       if (!pool_is_free_index (lgm->lisp_fwd_entry_pool, index))
    1463             :         {
    1464           0 :           lfe = pool_elt_at_index (lgm->lisp_fwd_entry_pool, index);
    1465             : 
    1466           0 :           vlib_cli_output (vm, "[%d@] %U",
    1467             :                            index,
    1468             :                            format_lisp_gpe_fwd_entry, lfe,
    1469             :                            LISP_GPE_FWD_ENTRY_FORMAT_DETAIL);
    1470             :         }
    1471             :       else
    1472             :         {
    1473           0 :           vlib_cli_output (vm, "entry %d invalid", index);
    1474             :         }
    1475             : 
    1476           0 :       return (NULL);
    1477             :     }
    1478             : 
    1479             :   /* *INDENT-OFF* */
    1480           0 :   pool_foreach (lfe, lgm->lisp_fwd_entry_pool)
    1481             :    {
    1482           0 :     if ((vni == ~0) ||
    1483           0 :         (lfe->key->vni == vni))
    1484           0 :       vlib_cli_output (vm, "%U", format_lisp_gpe_fwd_entry, lfe,
    1485             :                        LISP_GPE_FWD_ENTRY_FORMAT_NONE);
    1486             :   }
    1487             :   /* *INDENT-ON* */
    1488             : 
    1489           0 :   return (NULL);
    1490             : }
    1491             : 
    1492             : /* *INDENT-OFF* */
    1493      123991 : VLIB_CLI_COMMAND (lisp_gpe_fwd_entry_show_command, static) = {
    1494             :   .path = "show gpe entry",
    1495             :   .short_help = "show gpe entry vni <vni> vrf <vrf> [leid <leid>] reid <reid>",
    1496             :   .function = lisp_gpe_fwd_entry_show,
    1497             : };
    1498             : /* *INDENT-ON* */
    1499             : 
    1500             : clib_error_t *
    1501         575 : lisp_gpe_fwd_entry_init (vlib_main_t * vm)
    1502             : {
    1503         575 :   lisp_gpe_main_t *lgm = &lisp_gpe_main;
    1504         575 :   clib_error_t *error = NULL;
    1505             : 
    1506         575 :   if ((error = vlib_call_init_function (vm, lisp_cp_dpo_module_init)))
    1507           0 :     return (error);
    1508             : 
    1509         575 :   l2_fib_init (lgm);
    1510         575 :   nsh_fib_init (lgm);
    1511             : 
    1512         575 :   fib_node_register_type (FIB_NODE_TYPE_LISP_GPE_FWD_ENTRY, &lisp_fwd_vft);
    1513             : 
    1514         575 :   return (error);
    1515             : }
    1516             : 
    1517             : u32 *
    1518           0 : vnet_lisp_gpe_get_fwd_entry_vnis (void)
    1519             : {
    1520           0 :   lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
    1521             :   lisp_gpe_fwd_entry_t *lfe;
    1522           0 :   u32 *vnis = 0;
    1523             : 
    1524             :   /* *INDENT-OFF* */
    1525           0 :   pool_foreach (lfe, lgm->lisp_fwd_entry_pool)
    1526             :    {
    1527           0 :     hash_set (vnis, lfe->key->vni, 0);
    1528             :   }
    1529             :   /* *INDENT-ON* */
    1530             : 
    1531           0 :   return vnis;
    1532             : }
    1533             : 
    1534             : lisp_api_gpe_fwd_entry_t *
    1535           0 : vnet_lisp_gpe_fwd_entries_get_by_vni (u32 vni)
    1536             : {
    1537           0 :   lisp_gpe_main_t *lgm = &lisp_gpe_main;
    1538             :   lisp_gpe_fwd_entry_t *lfe;
    1539           0 :   lisp_api_gpe_fwd_entry_t *entries = 0, e;
    1540             : 
    1541             :   /* *INDENT-OFF* */
    1542           0 :   pool_foreach (lfe, lgm->lisp_fwd_entry_pool)
    1543             :    {
    1544           0 :     if (lfe->key->vni == vni)
    1545             :       {
    1546           0 :         clib_memset (&e, 0, sizeof (e));
    1547           0 :         e.dp_table = lfe->eid_table_id;
    1548           0 :         e.vni = lfe->key->vni;
    1549           0 :         if (lfe->type == LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE)
    1550           0 :           e.action = lfe->action;
    1551           0 :         e.fwd_entry_index = lfe - lgm->lisp_fwd_entry_pool;
    1552           0 :         memcpy (&e.reid, &lfe->key->rmt, sizeof (e.reid));
    1553           0 :         memcpy (&e.leid, &lfe->key->lcl, sizeof (e.leid));
    1554           0 :         vec_add1 (entries, e);
    1555             :       }
    1556             :   }
    1557             :   /* *INDENT-ON* */
    1558             : 
    1559           0 :   return entries;
    1560             : }
    1561             : 
    1562             : int
    1563           0 : vnet_lisp_gpe_get_fwd_stats (vnet_lisp_gpe_add_del_fwd_entry_args_t * a,
    1564             :                              vlib_counter_t * c)
    1565             : {
    1566           0 :   lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
    1567             :   lisp_gpe_fwd_entry_t *lfe;
    1568             :   lisp_gpe_fwd_entry_key_t unused;
    1569             : 
    1570           0 :   lfe = find_fwd_entry (lgm, a, &unused);
    1571           0 :   if (NULL == lfe)
    1572           0 :     return -1;
    1573             : 
    1574           0 :   if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE == lfe->type)
    1575           0 :     return -1;
    1576             : 
    1577           0 :   if (~0 == lfe->dpoi_index)
    1578           0 :     return -1;
    1579             : 
    1580           0 :   vlib_get_combined_counter (&load_balance_main.lbm_to_counters,
    1581             :                              lfe->dpoi_index, c);
    1582           0 :   return 0;
    1583             : }
    1584             : 
    1585        4031 : VLIB_INIT_FUNCTION (lisp_gpe_fwd_entry_init);
    1586             : 
    1587             : /*
    1588             :  * fd.io coding-style-patch-verification: ON
    1589             :  *
    1590             :  * Local Variables:
    1591             :  * eval: (c-set-style "gnu")
    1592             :  * End:
    1593             :  */

Generated by: LCOV version 1.14