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