1f2b28636950d0d0bcf55f1f91d33dc113fe7b5a
[vpp.git] / vnet / 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_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       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       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       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       src_fib_index = *(u32 *) fib_entry_get_source_data (dst_fei,
122                                                           FIB_SOURCE_LISP);
123     }
124
125   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 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   u8 have_default = 0;
145   u32 n_entries;
146
147   ASSERT (NULL != dst_prefix);
148   ASSERT (NULL != src_prefix);
149
150   ip_prefix_to_fib_prefix (dst_prefix, &dst_fib_prefix);
151   ip_prefix_to_fib_prefix (src_prefix, &src_fib_prefix);
152
153   fib_table_entry_delete (src_fib_index, &src_fib_prefix, FIB_SOURCE_LISP);
154
155   /* check if only default left or empty */
156   fib_prefix_t default_pref = {
157     .fp_proto = dst_fib_prefix.fp_proto
158   };
159
160   if (fib_table_lookup_exact_match (src_fib_index,
161                                     &default_pref) != FIB_NODE_INDEX_INVALID)
162     have_default = 1;
163
164   n_entries = fib_table_get_num_entries (src_fib_index,
165                                          src_fib_prefix.fp_proto,
166                                          FIB_SOURCE_LISP);
167   if (n_entries == 0 || (have_default && n_entries == 1))
168     {
169       /*
170        * remove src FIB default route
171        */
172       if (have_default)
173         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       fib_table_entry_special_remove (dst_fib_index,
181                                       &dst_fib_prefix, FIB_SOURCE_LISP);
182       fib_table_unlock (src_fib_index, src_fib_prefix.fp_proto);
183     }
184 }
185
186 /**
187  * @brief Add route to IP4 or IP6 SRC FIB.
188  *
189  * Adds a route to in the LISP SRC FIB with the result of the route
190  * being the DPO passed.
191  *
192  * @param[in]   src_fib_index   The index/ID of the SRC FIB
193  * @param[in]   src_prefix      Source IP prefix.
194  * @param[in]   src_dpo         The DPO the route will link to.
195  */
196 static void
197 ip_src_fib_add_route_w_dpo (u32 src_fib_index,
198                             const ip_prefix_t * src_prefix,
199                             const dpo_id_t * src_dpo)
200 {
201   fib_prefix_t src_fib_prefix;
202
203   ip_prefix_to_fib_prefix (src_prefix, &src_fib_prefix);
204
205   /*
206    * add the entry into the source fib.
207    */
208   fib_node_index_t src_fei;
209
210   src_fei = fib_table_lookup_exact_match (src_fib_index, &src_fib_prefix);
211
212   if (FIB_NODE_INDEX_INVALID == src_fei ||
213       !fib_entry_is_sourced (src_fei, FIB_SOURCE_LISP))
214     {
215       fib_table_entry_special_dpo_add (src_fib_index,
216                                        &src_fib_prefix,
217                                        FIB_SOURCE_LISP,
218                                        FIB_ENTRY_FLAG_EXCLUSIVE, src_dpo);
219     }
220 }
221
222 static fib_route_path_t *
223 lisp_gpe_mk_fib_paths (const lisp_fwd_path_t * paths)
224 {
225   const lisp_gpe_adjacency_t *ladj;
226   fib_route_path_t *rpaths = NULL;
227   u8 best_priority;
228   u32 ii;
229
230   vec_validate (rpaths, vec_len (paths) - 1);
231
232   best_priority = paths[0].priority;
233
234   vec_foreach_index (ii, paths)
235   {
236     if (paths[0].priority != best_priority)
237       break;
238
239     ladj = lisp_gpe_adjacency_get (paths[ii].lisp_adj);
240
241     ip_address_to_46 (&ladj->remote_rloc,
242                       &rpaths[ii].frp_addr, &rpaths[ii].frp_proto);
243
244     rpaths[ii].frp_sw_if_index = ladj->sw_if_index;
245     rpaths[ii].frp_weight = (paths[ii].weight ? paths[ii].weight : 1);
246     rpaths[ii].frp_label = MPLS_LABEL_INVALID;
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
288   dproto = (ip_prefix_version (&lfe->key->rmt.ippref) == IP4 ?
289             DPO_PROTO_IP4 : DPO_PROTO_IP6);
290
291   lfe->src_fib_index = ip_dst_fib_add_route (lfe->eid_fib_index,
292                                              &lfe->key->rmt.ippref);
293
294   if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE == lfe->type)
295     {
296       dpo_id_t dpo = DPO_INVALID;
297
298       switch (lfe->action)
299         {
300         case LISP_NO_ACTION:
301           /* TODO update timers? */
302         case LISP_FORWARD_NATIVE:
303           /* TODO check if route/next-hop for eid exists in fib and add
304            * more specific for the eid with the next-hop found */
305         case LISP_SEND_MAP_REQUEST:
306           /* insert tunnel that always sends map-request */
307           dpo_copy (&dpo, lisp_cp_dpo_get (dproto));
308           break;
309         case LISP_DROP:
310           /* for drop fwd entries, just add route, no need to add encap tunnel */
311           dpo_copy (&dpo, drop_dpo_get (dproto));
312           break;
313         }
314       ip_src_fib_add_route_w_dpo (lfe->src_fib_index,
315                                   &lfe->key->lcl.ippref, &dpo);
316       dpo_reset (&dpo);
317     }
318   else
319     {
320       ip_src_fib_add_route (lfe->src_fib_index,
321                             &lfe->key->lcl.ippref, lfe->paths);
322     }
323 }
324
325 static void
326 delete_fib_entries (lisp_gpe_fwd_entry_t * lfe)
327 {
328   ip_src_dst_fib_del_route (lfe->src_fib_index,
329                             &lfe->key->lcl.ippref,
330                             lfe->eid_fib_index, &lfe->key->rmt.ippref);
331 }
332
333 static void
334 gid_to_dp_address (gid_address_t * g, dp_address_t * d)
335 {
336   switch (gid_address_type (g))
337     {
338     case GID_ADDR_IP_PREFIX:
339     case GID_ADDR_SRC_DST:
340       ip_prefix_copy (&d->ippref, &gid_address_ippref (g));
341       d->type = FID_ADDR_IP_PREF;
342       break;
343     case GID_ADDR_MAC:
344     default:
345       mac_copy (&d->mac, &gid_address_mac (g));
346       d->type = FID_ADDR_MAC;
347       break;
348     }
349 }
350
351 static lisp_gpe_fwd_entry_t *
352 find_fwd_entry (lisp_gpe_main_t * lgm,
353                 vnet_lisp_gpe_add_del_fwd_entry_args_t * a,
354                 lisp_gpe_fwd_entry_key_t * key)
355 {
356   uword *p;
357
358   memset (key, 0, sizeof (*key));
359
360   if (GID_ADDR_IP_PREFIX == gid_address_type (&a->rmt_eid))
361     {
362       /*
363        * the ip version of the source is not set to ip6 when the
364        * source is all zeros. force it.
365        */
366       ip_prefix_version (&gid_address_ippref (&a->lcl_eid)) =
367         ip_prefix_version (&gid_address_ippref (&a->rmt_eid));
368     }
369
370   gid_to_dp_address (&a->rmt_eid, &key->rmt);
371   gid_to_dp_address (&a->lcl_eid, &key->lcl);
372   key->vni = a->vni;
373
374   p = hash_get_mem (lgm->lisp_gpe_fwd_entries, key);
375
376   if (NULL != p)
377     {
378       return (pool_elt_at_index (lgm->lisp_fwd_entry_pool, p[0]));
379     }
380   return (NULL);
381 }
382
383 static int
384 lisp_gpe_fwd_entry_path_sort (void *a1, void *a2)
385 {
386   lisp_fwd_path_t *p1 = a1, *p2 = a2;
387
388   return (p1->priority - p2->priority);
389 }
390
391 static void
392 lisp_gpe_fwd_entry_mk_paths (lisp_gpe_fwd_entry_t * lfe,
393                              vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
394 {
395   lisp_fwd_path_t *path;
396   u32 index;
397
398   vec_validate (lfe->paths, vec_len (a->locator_pairs) - 1);
399
400   vec_foreach_index (index, a->locator_pairs)
401   {
402     path = &lfe->paths[index];
403
404     path->priority = a->locator_pairs[index].priority;
405     path->weight = a->locator_pairs[index].weight;
406
407     path->lisp_adj =
408       lisp_gpe_adjacency_find_or_create_and_lock (&a->locator_pairs
409                                                   [index],
410                                                   a->dp_table, lfe->key->vni);
411   }
412   vec_sort_with_function (lfe->paths, lisp_gpe_fwd_entry_path_sort);
413 }
414
415 /**
416  * @brief Add/Delete LISP IP forwarding entry.
417  *
418  * creation of forwarding entries for IP LISP overlay:
419  *
420  * @param[in]   lgm     Reference to @ref lisp_gpe_main_t.
421  * @param[in]   a       Parameters for building the forwarding entry.
422  *
423  * @return 0 on success.
424  */
425 static int
426 add_ip_fwd_entry (lisp_gpe_main_t * lgm,
427                   vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
428 {
429   lisp_gpe_fwd_entry_key_t key;
430   lisp_gpe_fwd_entry_t *lfe;
431   fib_protocol_t fproto;
432
433   lfe = find_fwd_entry (lgm, a, &key);
434
435   if (NULL != lfe)
436     /* don't support updates */
437     return VNET_API_ERROR_INVALID_VALUE;
438
439   pool_get (lgm->lisp_fwd_entry_pool, lfe);
440   memset (lfe, 0, sizeof (*lfe));
441   lfe->key = clib_mem_alloc (sizeof (key));
442   memcpy (lfe->key, &key, sizeof (key));
443
444   hash_set_mem (lgm->lisp_gpe_fwd_entries, lfe->key,
445                 lfe - lgm->lisp_fwd_entry_pool);
446
447   fproto = (IP4 == ip_prefix_version (&fid_addr_ippref (&lfe->key->rmt)) ?
448             FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6);
449
450   lfe->type = (a->is_negative ?
451                LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE :
452                LISP_GPE_FWD_ENTRY_TYPE_NORMAL);
453   lfe->tenant = lisp_gpe_tenant_find_or_create (lfe->key->vni);
454   lfe->eid_table_id = a->table_id;
455   lfe->eid_fib_index = fib_table_find_or_create_and_lock (fproto,
456                                                           lfe->eid_table_id);
457
458   if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE != lfe->type)
459     {
460       lisp_gpe_fwd_entry_mk_paths (lfe, a);
461     }
462
463   create_fib_entries (lfe);
464
465   return (0);
466 }
467
468 static void
469 del_ip_fwd_entry_i (lisp_gpe_main_t * lgm, lisp_gpe_fwd_entry_t * lfe)
470 {
471   lisp_fwd_path_t *path;
472   fib_protocol_t fproto;
473
474   vec_foreach (path, lfe->paths)
475   {
476     lisp_gpe_adjacency_unlock (path->lisp_adj);
477   }
478
479   delete_fib_entries (lfe);
480
481   fproto = (IP4 == ip_prefix_version (&fid_addr_ippref (&lfe->key->rmt)) ?
482             FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6);
483   fib_table_unlock (lfe->eid_fib_index, fproto);
484
485   hash_unset_mem (lgm->lisp_gpe_fwd_entries, lfe->key);
486   clib_mem_free (lfe->key);
487   pool_put (lgm->lisp_fwd_entry_pool, lfe);
488 }
489
490 /**
491  * @brief Add/Delete LISP IP forwarding entry.
492  *
493  * removal of forwarding entries for IP LISP overlay:
494  *
495  * @param[in]   lgm     Reference to @ref lisp_gpe_main_t.
496  * @param[in]   a       Parameters for building the forwarding entry.
497  *
498  * @return 0 on success.
499  */
500 static int
501 del_ip_fwd_entry (lisp_gpe_main_t * lgm,
502                   vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
503 {
504   lisp_gpe_fwd_entry_key_t key;
505   lisp_gpe_fwd_entry_t *lfe;
506
507   lfe = find_fwd_entry (lgm, a, &key);
508
509   if (NULL == lfe)
510     /* no such entry */
511     return VNET_API_ERROR_INVALID_VALUE;
512
513   del_ip_fwd_entry_i (lgm, lfe);
514
515   return (0);
516 }
517
518 static void
519 make_mac_fib_key (BVT (clib_bihash_kv) * kv, u16 bd_index, u8 src_mac[6],
520                   u8 dst_mac[6])
521 {
522   kv->key[0] = (((u64) bd_index) << 48) | mac_to_u64 (dst_mac);
523   kv->key[1] = mac_to_u64 (src_mac);
524   kv->key[2] = 0;
525 }
526
527 /**
528  * @brief Lookup L2 SD FIB entry
529  *
530  * Does a vni + dest + source lookup in the L2 LISP FIB. If the lookup fails
531  * it tries a second time with source set to 0 (i.e., a simple dest lookup).
532  *
533  * @param[in]   lgm             Reference to @ref lisp_gpe_main_t.
534  * @param[in]   bd_index        Bridge domain index.
535  * @param[in]   src_mac         Source mac address.
536  * @param[in]   dst_mac         Destination mac address.
537  *
538  * @return index of mapping matching the lookup key.
539  */
540 index_t
541 lisp_l2_fib_lookup (lisp_gpe_main_t * lgm, u16 bd_index, u8 src_mac[6],
542                     u8 dst_mac[6])
543 {
544   int rv;
545   BVT (clib_bihash_kv) kv, value;
546
547   make_mac_fib_key (&kv, bd_index, src_mac, dst_mac);
548   rv = BV (clib_bihash_search_inline_2) (&lgm->l2_fib, &kv, &value);
549
550   /* no match, try with src 0, catch all for dst */
551   if (rv != 0)
552     {
553       kv.key[1] = 0;
554       rv = BV (clib_bihash_search_inline_2) (&lgm->l2_fib, &kv, &value);
555       if (rv == 0)
556         return value.value;
557     }
558   else
559     return value.value;
560
561   return lisp_gpe_main.l2_lb_cp_lkup.dpoi_index;
562 }
563
564 /**
565  * @brief Add/del L2 SD FIB entry
566  *
567  * Inserts value in L2 FIB keyed by vni + dest + source. If entry is
568  * overwritten the associated value is returned.
569  *
570  * @param[in]   lgm             Reference to @ref lisp_gpe_main_t.
571  * @param[in]   bd_index        Bridge domain index.
572  * @param[in]   src_mac         Source mac address.
573  * @param[in]   dst_mac         Destination mac address.
574  * @param[in]   val             Value to add.
575  * @param[in]   is_add          Add/del flag.
576  *
577  * @return ~0 or value of overwritten entry.
578  */
579 static u32
580 lisp_l2_fib_add_del_entry (u16 bd_index, u8 src_mac[6],
581                            u8 dst_mac[6], const dpo_id_t * dpo, u8 is_add)
582 {
583   lisp_gpe_main_t *lgm = &lisp_gpe_main;
584   BVT (clib_bihash_kv) kv, value;
585   u32 old_val = ~0;
586
587   make_mac_fib_key (&kv, bd_index, src_mac, dst_mac);
588
589   if (BV (clib_bihash_search) (&lgm->l2_fib, &kv, &value) == 0)
590     old_val = value.value;
591
592   if (!is_add)
593     BV (clib_bihash_add_del) (&lgm->l2_fib, &kv, 0 /* is_add */ );
594   else
595     {
596       kv.value = dpo->dpoi_index;
597       BV (clib_bihash_add_del) (&lgm->l2_fib, &kv, 1 /* is_add */ );
598     }
599   return old_val;
600 }
601
602 #define L2_FIB_DEFAULT_HASH_NUM_BUCKETS (64 * 1024)
603 #define L2_FIB_DEFAULT_HASH_MEMORY_SIZE (32<<20)
604
605 static void
606 l2_fib_init (lisp_gpe_main_t * lgm)
607 {
608   index_t lbi;
609
610   BV (clib_bihash_init) (&lgm->l2_fib, "l2 fib",
611                          1 << max_log2 (L2_FIB_DEFAULT_HASH_NUM_BUCKETS),
612                          L2_FIB_DEFAULT_HASH_MEMORY_SIZE);
613
614   /*
615    * the result from a 'miss' in a L2 Table
616    */
617   lbi = load_balance_create (1, DPO_PROTO_ETHERNET, 0);
618   load_balance_set_bucket (lbi, 0, lisp_cp_dpo_get (DPO_PROTO_ETHERNET));
619
620   dpo_set (&lgm->l2_lb_cp_lkup, DPO_LOAD_BALANCE, DPO_PROTO_ETHERNET, lbi);
621 }
622
623 static void
624 del_l2_fwd_entry_i (lisp_gpe_main_t * lgm, lisp_gpe_fwd_entry_t * lfe)
625 {
626   lisp_fwd_path_t *path;
627
628   if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE != lfe->type)
629     {
630       vec_foreach (path, lfe->paths)
631       {
632         lisp_gpe_adjacency_unlock (path->lisp_adj);
633       }
634       fib_path_list_child_remove (lfe->l2.path_list_index,
635                                   lfe->l2.child_index);
636     }
637
638   lisp_l2_fib_add_del_entry (lfe->l2.eid_bd_index,
639                              fid_addr_mac (&lfe->key->lcl),
640                              fid_addr_mac (&lfe->key->rmt), NULL, 0);
641
642   hash_unset_mem (lgm->lisp_gpe_fwd_entries, lfe->key);
643   clib_mem_free (lfe->key);
644   pool_put (lgm->lisp_fwd_entry_pool, lfe);
645 }
646
647 /**
648  * @brief Delete LISP L2 forwarding entry.
649  *
650  * Coordinates the removal of forwarding entries for L2 LISP overlay:
651  *
652  * @param[in]   lgm     Reference to @ref lisp_gpe_main_t.
653  * @param[in]   a       Parameters for building the forwarding entry.
654  *
655  * @return 0 on success.
656  */
657 static int
658 del_l2_fwd_entry (lisp_gpe_main_t * lgm,
659                   vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
660 {
661   lisp_gpe_fwd_entry_key_t key;
662   lisp_gpe_fwd_entry_t *lfe;
663
664   lfe = find_fwd_entry (lgm, a, &key);
665
666   if (NULL == lfe)
667     return VNET_API_ERROR_INVALID_VALUE;
668
669   del_l2_fwd_entry_i (lgm, lfe);
670
671   return (0);
672 }
673
674 /**
675  * @brief Construct and insert the forwarding information used by a L2 entry
676  */
677 static void
678 lisp_gpe_l2_update_fwding (lisp_gpe_fwd_entry_t * lfe)
679 {
680   lisp_gpe_main_t *lgm = &lisp_gpe_main;
681   dpo_id_t dpo = DPO_INVALID;
682
683   if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE != lfe->type)
684     {
685       fib_path_list_contribute_forwarding (lfe->l2.path_list_index,
686                                            FIB_FORW_CHAIN_TYPE_ETHERNET,
687                                            &lfe->l2.dpo);
688       dpo_copy (&dpo, &lfe->l2.dpo);
689     }
690   else
691     {
692       dpo_copy (&dpo, &lgm->l2_lb_cp_lkup);
693     }
694
695   /* add entry to l2 lisp fib */
696   lisp_l2_fib_add_del_entry (lfe->l2.eid_bd_index,
697                              fid_addr_mac (&lfe->key->lcl),
698                              fid_addr_mac (&lfe->key->rmt), &dpo, 1);
699
700   dpo_reset (&dpo);
701 }
702
703 /**
704  * @brief Add LISP L2 forwarding entry.
705  *
706  * Coordinates the creation of forwarding entries for L2 LISP overlay:
707  * creates lisp-gpe tunnel and injects new entry in Source/Dest L2 FIB.
708  *
709  * @param[in]   lgm     Reference to @ref lisp_gpe_main_t.
710  * @param[in]   a       Parameters for building the forwarding entry.
711  *
712  * @return 0 on success.
713  */
714 static int
715 add_l2_fwd_entry (lisp_gpe_main_t * lgm,
716                   vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
717 {
718   lisp_gpe_fwd_entry_key_t key;
719   bd_main_t *bdm = &bd_main;
720   lisp_gpe_fwd_entry_t *lfe;
721   uword *bd_indexp;
722
723   bd_indexp = hash_get (bdm->bd_index_by_bd_id, a->bd_id);
724   if (!bd_indexp)
725     {
726       clib_warning ("bridge domain %d doesn't exist", a->bd_id);
727       return -1;
728     }
729
730   lfe = find_fwd_entry (lgm, a, &key);
731
732   if (NULL != lfe)
733     /* don't support updates */
734     return VNET_API_ERROR_INVALID_VALUE;
735
736   pool_get (lgm->lisp_fwd_entry_pool, lfe);
737   memset (lfe, 0, sizeof (*lfe));
738   lfe->key = clib_mem_alloc (sizeof (key));
739   memcpy (lfe->key, &key, sizeof (key));
740
741   hash_set_mem (lgm->lisp_gpe_fwd_entries, lfe->key,
742                 lfe - lgm->lisp_fwd_entry_pool);
743
744   lfe->type = (a->is_negative ?
745                LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE :
746                LISP_GPE_FWD_ENTRY_TYPE_NORMAL);
747   lfe->l2.eid_bd_id = a->bd_id;
748   lfe->l2.eid_bd_index = bd_indexp[0];
749   lfe->tenant = lisp_gpe_tenant_find_or_create (lfe->key->vni);
750
751   if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE != lfe->type)
752     {
753       fib_route_path_t *rpaths;
754
755       /*
756        * Make the sorted array of LISP paths with their resp. adjacency
757        */
758       lisp_gpe_fwd_entry_mk_paths (lfe, a);
759
760       /*
761        * From the LISP paths, construct a FIB path list that will
762        * contribute a load-balance.
763        */
764       rpaths = lisp_gpe_mk_fib_paths (lfe->paths);
765
766       lfe->l2.path_list_index =
767         fib_path_list_create (FIB_PATH_LIST_FLAG_NONE, rpaths);
768
769       /*
770        * become a child of the path-list so we receive updates when
771        * its forwarding state changes. this includes an implicit lock.
772        */
773       lfe->l2.child_index =
774         fib_path_list_child_add (lfe->l2.path_list_index,
775                                  FIB_NODE_TYPE_LISP_GPE_FWD_ENTRY,
776                                  lfe - lgm->lisp_fwd_entry_pool);
777     }
778   else
779     {
780       lfe->action = a->action;
781     }
782
783   lisp_gpe_l2_update_fwding (lfe);
784
785   return 0;
786 }
787
788 /**
789  * @brief conver from the embedded fib_node_t struct to the LSIP entry
790  */
791 static lisp_gpe_fwd_entry_t *
792 lisp_gpe_fwd_entry_from_fib_node (fib_node_t * node)
793 {
794   return ((lisp_gpe_fwd_entry_t *) (((char *) node) -
795                                     STRUCT_OFFSET_OF (lisp_gpe_fwd_entry_t,
796                                                       node)));
797 }
798
799 /**
800  * @brief Function invoked during a backwalk of the FIB graph
801  */
802 static fib_node_back_walk_rc_t
803 lisp_gpe_fib_node_back_walk (fib_node_t * node,
804                              fib_node_back_walk_ctx_t * ctx)
805 {
806   lisp_gpe_l2_update_fwding (lisp_gpe_fwd_entry_from_fib_node (node));
807
808   return (FIB_NODE_BACK_WALK_CONTINUE);
809 }
810
811 /**
812  * @brief Get a fib_node_t struct from the index of a LISP fwd entry
813  */
814 static fib_node_t *
815 lisp_gpe_fwd_entry_get_fib_node (fib_node_index_t index)
816 {
817   lisp_gpe_main_t *lgm = &lisp_gpe_main;
818   lisp_gpe_fwd_entry_t *lfe;
819
820   lfe = pool_elt_at_index (lgm->lisp_fwd_entry_pool, index);
821
822   return (&(lfe->node));
823 }
824
825 /**
826  * @brief An indication from the graph that the last lock has gone
827  */
828 static void
829 lisp_gpe_fwd_entry_fib_node_last_lock_gone (fib_node_t * node)
830 {
831   /* We don't manage the locks of the LISP objects via the graph, since
832    * this object has no children. so this is a no-op. */
833 }
834
835 /**
836  * @brief Virtual function table to register with FIB for the LISP type
837  */
838 const static fib_node_vft_t lisp_fwd_vft = {
839   .fnv_get = lisp_gpe_fwd_entry_get_fib_node,
840   .fnv_last_lock = lisp_gpe_fwd_entry_fib_node_last_lock_gone,
841   .fnv_back_walk = lisp_gpe_fib_node_back_walk,
842 };
843
844 /**
845  * @brief Forwarding entry create/remove dispatcher.
846  *
847  * Calls l2 or l3 forwarding entry add/del function based on input data.
848  *
849  * @param[in]   a       Forwarding entry parameters.
850  * @param[out]  hw_if_indexp    NOT USED
851  *
852  * @return 0 on success.
853  */
854 int
855 vnet_lisp_gpe_add_del_fwd_entry (vnet_lisp_gpe_add_del_fwd_entry_args_t * a,
856                                  u32 * hw_if_indexp)
857 {
858   lisp_gpe_main_t *lgm = &lisp_gpe_main;
859   u8 type;
860
861   if (vnet_lisp_gpe_enable_disable_status () == 0)
862     {
863       clib_warning ("LISP is disabled!");
864       return VNET_API_ERROR_LISP_DISABLED;
865     }
866
867   type = gid_address_type (&a->rmt_eid);
868   switch (type)
869     {
870     case GID_ADDR_IP_PREFIX:
871       if (a->is_add)
872         return add_ip_fwd_entry (lgm, a);
873       else
874         return del_ip_fwd_entry (lgm, a);
875       break;
876     case GID_ADDR_MAC:
877       if (a->is_add)
878         return add_l2_fwd_entry (lgm, a);
879       else
880         return del_l2_fwd_entry (lgm, a);
881     default:
882       clib_warning ("Forwarding entries for type %d not supported!", type);
883       return -1;
884     }
885 }
886
887 /**
888  * @brief Flush all the forwrding entries
889  */
890 void
891 vnet_lisp_gpe_fwd_entry_flush (void)
892 {
893   lisp_gpe_main_t *lgm = &lisp_gpe_main;
894   lisp_gpe_fwd_entry_t *lfe;
895
896   /* *INDENT-OFF* */
897   pool_foreach (lfe, lgm->lisp_fwd_entry_pool,
898   ({
899     switch (fid_addr_type(&lfe->key->rmt))
900       {
901       case FID_ADDR_MAC:
902         del_l2_fwd_entry_i (lgm, lfe);
903         break;
904       case FID_ADDR_IP_PREF:
905         del_ip_fwd_entry_i (lgm, lfe);
906         break;
907       }
908   }));
909   /* *INDENT-ON* */
910 }
911
912 static u8 *
913 format_lisp_fwd_path (u8 * s, va_list ap)
914 {
915   lisp_fwd_path_t *lfp = va_arg (ap, lisp_fwd_path_t *);
916
917   s = format (s, "priority:%d weight:%d ", lfp->priority, lfp->weight);
918   s = format (s, "adj:[%U]\n",
919               format_lisp_gpe_adjacency,
920               lisp_gpe_adjacency_get (lfp->lisp_adj),
921               LISP_GPE_ADJ_FORMAT_FLAG_NONE);
922
923   return (s);
924 }
925
926 typedef enum lisp_gpe_fwd_entry_format_flag_t_
927 {
928   LISP_GPE_FWD_ENTRY_FORMAT_NONE = (0 << 0),
929   LISP_GPE_FWD_ENTRY_FORMAT_DETAIL = (1 << 1),
930 } lisp_gpe_fwd_entry_format_flag_t;
931
932
933 static u8 *
934 format_lisp_gpe_fwd_entry (u8 * s, va_list ap)
935 {
936   lisp_gpe_main_t *lgm = &lisp_gpe_main;
937   lisp_gpe_fwd_entry_t *lfe = va_arg (ap, lisp_gpe_fwd_entry_t *);
938   lisp_gpe_fwd_entry_format_flag_t flags =
939     va_arg (ap, lisp_gpe_fwd_entry_format_flag_t);
940
941   s = format (s, "VNI:%d VRF:%d EID: %U -> %U  [index:%d]",
942               lfe->key->vni, lfe->eid_table_id,
943               format_fid_address, &lfe->key->lcl,
944               format_fid_address, &lfe->key->rmt,
945               lfe - lgm->lisp_fwd_entry_pool);
946
947   if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE == lfe->type)
948     {
949       s = format (s, "\n Negative - action:%U",
950                   format_negative_mapping_action, lfe->action);
951     }
952   else
953     {
954       lisp_fwd_path_t *path;
955
956       s = format (s, "\n via:");
957       vec_foreach (path, lfe->paths)
958       {
959         s = format (s, "\n  %U", format_lisp_fwd_path, path);
960       }
961     }
962
963   if (flags & LISP_GPE_FWD_ENTRY_FORMAT_DETAIL)
964     {
965       switch (fid_addr_type (&lfe->key->rmt))
966         {
967         case FID_ADDR_MAC:
968           s = format (s, " fib-path-list:%d\n", lfe->l2.path_list_index);
969           s = format (s, " dpo:%U\n", format_dpo_id, &lfe->l2.dpo, 0);
970           break;
971         case FID_ADDR_IP_PREF:
972           break;
973         }
974     }
975
976   return (s);
977 }
978
979 static clib_error_t *
980 lisp_gpe_fwd_entry_show (vlib_main_t * vm,
981                          unformat_input_t * input, vlib_cli_command_t * cmd)
982 {
983   lisp_gpe_main_t *lgm = &lisp_gpe_main;
984   lisp_gpe_fwd_entry_t *lfe;
985   index_t index;
986   u32 vni = ~0;
987
988   if (unformat (input, "vni %d", &vni))
989     ;
990   else if (unformat (input, "%d", &index))
991     {
992       if (!pool_is_free_index (lgm->lisp_fwd_entry_pool, index))
993         {
994           lfe = pool_elt_at_index (lgm->lisp_fwd_entry_pool, index);
995
996           vlib_cli_output (vm, "[%d@] %U",
997                            index,
998                            format_lisp_gpe_fwd_entry, lfe,
999                            LISP_GPE_FWD_ENTRY_FORMAT_DETAIL);
1000         }
1001       else
1002         {
1003           vlib_cli_output (vm, "entry %d invalid", index);
1004         }
1005
1006       return (NULL);
1007     }
1008
1009   /* *INDENT-OFF* */
1010   pool_foreach (lfe, lgm->lisp_fwd_entry_pool,
1011   ({
1012     if ((vni == ~0) ||
1013         (lfe->key->vni == vni))
1014       vlib_cli_output (vm, "%U", format_lisp_gpe_fwd_entry, lfe,
1015                        LISP_GPE_FWD_ENTRY_FORMAT_NONE);
1016   }));
1017   /* *INDENT-ON* */
1018
1019   return (NULL);
1020 }
1021
1022 /* *INDENT-OFF* */
1023 VLIB_CLI_COMMAND (lisp_gpe_fwd_entry_show_command, static) = {
1024   .path = "show lisp gpe entry",
1025   .short_help = "show lisp gpe entry vni <vni> vrf <vrf> [leid <leid>] reid <reid>",
1026   .function = lisp_gpe_fwd_entry_show,
1027 };
1028 /* *INDENT-ON* */
1029
1030 clib_error_t *
1031 lisp_gpe_fwd_entry_init (vlib_main_t * vm)
1032 {
1033   lisp_gpe_main_t *lgm = &lisp_gpe_main;
1034   clib_error_t *error = NULL;
1035
1036   if ((error = vlib_call_init_function (vm, lisp_cp_dpo_module_init)))
1037     return (error);
1038
1039   l2_fib_init (lgm);
1040
1041   fib_node_register_type (FIB_NODE_TYPE_LISP_GPE_FWD_ENTRY, &lisp_fwd_vft);
1042
1043   return (error);
1044 }
1045
1046 VLIB_INIT_FUNCTION (lisp_gpe_fwd_entry_init);
1047
1048 /*
1049  * fd.io coding-style-patch-verification: ON
1050  *
1051  * Local Variables:
1052  * eval: (c-set-style "gnu")
1053  * End:
1054  */