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