L2 over LISP and GRE (VPP-457)
[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   vec_foreach (path, lfe->paths)
621   {
622     lisp_gpe_adjacency_unlock (path->lisp_adj);
623   }
624
625   lisp_l2_fib_add_del_entry (lfe->l2.eid_bd_index,
626                              fid_addr_mac (&lfe->key->lcl),
627                              fid_addr_mac (&lfe->key->rmt), NULL, 0);
628
629   fib_path_list_child_remove (lfe->l2.path_list_index, lfe->l2.child_index);
630
631   hash_unset_mem (lgm->lisp_gpe_fwd_entries, lfe->key);
632   clib_mem_free (lfe->key);
633   pool_put (lgm->lisp_fwd_entry_pool, lfe);
634 }
635
636 /**
637  * @brief Delete LISP L2 forwarding entry.
638  *
639  * Coordinates the removal of forwarding entries for L2 LISP overlay:
640  *
641  * @param[in]   lgm     Reference to @ref lisp_gpe_main_t.
642  * @param[in]   a       Parameters for building the forwarding entry.
643  *
644  * @return 0 on success.
645  */
646 static int
647 del_l2_fwd_entry (lisp_gpe_main_t * lgm,
648                   vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
649 {
650   lisp_gpe_fwd_entry_key_t key;
651   lisp_gpe_fwd_entry_t *lfe;
652
653   lfe = find_fwd_entry (lgm, a, &key);
654
655   if (NULL != lfe)
656     return VNET_API_ERROR_INVALID_VALUE;
657
658   del_l2_fwd_entry_i (lgm, lfe);
659
660   return (0);
661 }
662
663 /**
664  * @brief Construct and insert the forwarding information used by a L2 entry
665  */
666 static void
667 lisp_gpe_l2_update_fwding (lisp_gpe_fwd_entry_t * lfe)
668 {
669   lisp_gpe_main_t *lgm = &lisp_gpe_main;
670   dpo_id_t dpo = DPO_NULL;
671
672   if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE != lfe->type)
673     {
674       fib_path_list_contribute_forwarding (lfe->l2.path_list_index,
675                                            FIB_FORW_CHAIN_TYPE_ETHERNET,
676                                            &lfe->l2.dpo);
677       dpo_copy (&dpo, &lfe->l2.dpo);
678     }
679   else
680     {
681       dpo_copy (&dpo, &lgm->l2_lb_cp_lkup);
682     }
683
684   /* add entry to l2 lisp fib */
685   lisp_l2_fib_add_del_entry (lfe->l2.eid_bd_index,
686                              fid_addr_mac (&lfe->key->lcl),
687                              fid_addr_mac (&lfe->key->rmt), &dpo, 1);
688
689   dpo_reset (&dpo);
690 }
691
692 /**
693  * @brief Add LISP L2 forwarding entry.
694  *
695  * Coordinates the creation of forwarding entries for L2 LISP overlay:
696  * creates lisp-gpe tunnel and injects new entry in Source/Dest L2 FIB.
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 add_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   bd_main_t *bdm = &bd_main;
709   lisp_gpe_fwd_entry_t *lfe;
710   uword *bd_indexp;
711
712   bd_indexp = hash_get (bdm->bd_index_by_bd_id, a->bd_id);
713   if (!bd_indexp)
714     {
715       clib_warning ("bridge domain %d doesn't exist", a->bd_id);
716       return -1;
717     }
718
719   lfe = find_fwd_entry (lgm, a, &key);
720
721   if (NULL != lfe)
722     /* don't support updates */
723     return VNET_API_ERROR_INVALID_VALUE;
724
725   pool_get (lgm->lisp_fwd_entry_pool, lfe);
726   memset (lfe, 0, sizeof (*lfe));
727   lfe->key = clib_mem_alloc (sizeof (key));
728   memcpy (lfe->key, &key, sizeof (key));
729
730   hash_set_mem (lgm->lisp_gpe_fwd_entries, lfe->key,
731                 lfe - lgm->lisp_fwd_entry_pool);
732
733   lfe->type = (a->is_negative ?
734                LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE :
735                LISP_GPE_FWD_ENTRY_TYPE_NORMAL);
736   lfe->l2.eid_bd_id = a->bd_id;
737   lfe->l2.eid_bd_index = bd_indexp[0];
738   lfe->tenant = lisp_gpe_tenant_find_or_create (lfe->key->vni);
739
740   if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE != lfe->type)
741     {
742       fib_route_path_t *rpaths;
743
744       /*
745        * Make the sorted array of LISP paths with their resp. adjacency
746        */
747       lisp_gpe_fwd_entry_mk_paths (lfe, a);
748
749       /*
750        * From the LISP paths, construct a FIB path list that will
751        * contribute a load-balance.
752        */
753       rpaths = lisp_gpe_mk_fib_paths (lfe->paths);
754
755       lfe->l2.path_list_index =
756         fib_path_list_create (FIB_PATH_LIST_FLAG_NONE, rpaths);
757
758       /*
759        * become a child of the path-list so we receive updates when
760        * its forwarding state changes. this includes an implicit lock.
761        */
762       lfe->l2.child_index =
763         fib_path_list_child_add (lfe->l2.path_list_index,
764                                  FIB_NODE_TYPE_LISP_GPE_FWD_ENTRY,
765                                  lfe - lgm->lisp_fwd_entry_pool);
766     }
767   else
768     {
769       lfe->action = a->action;
770     }
771
772   lisp_gpe_l2_update_fwding (lfe);
773
774   return 0;
775 }
776
777 /**
778  * @brief conver from the embedded fib_node_t struct to the LSIP entry
779  */
780 static lisp_gpe_fwd_entry_t *
781 lisp_gpe_fwd_entry_from_fib_node (fib_node_t * node)
782 {
783   return ((lisp_gpe_fwd_entry_t *) (((char *) node) -
784                                     STRUCT_OFFSET_OF (lisp_gpe_fwd_entry_t,
785                                                       node)));
786 }
787
788 /**
789  * @brief Function invoked during a backwalk of the FIB graph
790  */
791 static fib_node_back_walk_rc_t
792 lisp_gpe_fib_node_back_walk (fib_node_t * node,
793                              fib_node_back_walk_ctx_t * ctx)
794 {
795   lisp_gpe_l2_update_fwding (lisp_gpe_fwd_entry_from_fib_node (node));
796
797   return (FIB_NODE_BACK_WALK_CONTINUE);
798 }
799
800 /**
801  * @brief Get a fib_node_t struct from the index of a LISP fwd entry
802  */
803 static fib_node_t *
804 lisp_gpe_fwd_entry_get_fib_node (fib_node_index_t index)
805 {
806   lisp_gpe_main_t *lgm = &lisp_gpe_main;
807   lisp_gpe_fwd_entry_t *lfe;
808
809   lfe = pool_elt_at_index (lgm->lisp_fwd_entry_pool, index);
810
811   return (&(lfe->node));
812 }
813
814 /**
815  * @brief An indication from the graph that the last lock has gone
816  */
817 static void
818 lisp_gpe_fwd_entry_fib_node_last_lock_gone (fib_node_t * node)
819 {
820   /* We don't manage the locks of the LISP objects via the graph, since
821    * this object has no children. so this is a no-op. */
822 }
823
824 /**
825  * @brief Virtual function table to register with FIB for the LISP type
826  */
827 const static fib_node_vft_t lisp_fwd_vft = {
828   .fnv_get = lisp_gpe_fwd_entry_get_fib_node,
829   .fnv_last_lock = lisp_gpe_fwd_entry_fib_node_last_lock_gone,
830   .fnv_back_walk = lisp_gpe_fib_node_back_walk,
831 };
832
833 /**
834  * @brief Forwarding entry create/remove dispatcher.
835  *
836  * Calls l2 or l3 forwarding entry add/del function based on input data.
837  *
838  * @param[in]   a       Forwarding entry parameters.
839  * @param[out]  hw_if_indexp    NOT USED
840  *
841  * @return 0 on success.
842  */
843 int
844 vnet_lisp_gpe_add_del_fwd_entry (vnet_lisp_gpe_add_del_fwd_entry_args_t * a,
845                                  u32 * hw_if_indexp)
846 {
847   lisp_gpe_main_t *lgm = &lisp_gpe_main;
848   u8 type;
849
850   if (vnet_lisp_gpe_enable_disable_status () == 0)
851     {
852       clib_warning ("LISP is disabled!");
853       return VNET_API_ERROR_LISP_DISABLED;
854     }
855
856   type = gid_address_type (&a->rmt_eid);
857   switch (type)
858     {
859     case GID_ADDR_IP_PREFIX:
860       if (a->is_add)
861         return add_ip_fwd_entry (lgm, a);
862       else
863         return del_ip_fwd_entry (lgm, a);
864       break;
865     case GID_ADDR_MAC:
866       if (a->is_add)
867         return add_l2_fwd_entry (lgm, a);
868       else
869         return del_l2_fwd_entry (lgm, a);
870     default:
871       clib_warning ("Forwarding entries for type %d not supported!", type);
872       return -1;
873     }
874 }
875
876 /**
877  * @brief Flush all the forwrding entries
878  */
879 void
880 vnet_lisp_gpe_fwd_entry_flush (void)
881 {
882   lisp_gpe_main_t *lgm = &lisp_gpe_main;
883   lisp_gpe_fwd_entry_t *lfe;
884
885   /* *INDENT-OFF* */
886   pool_foreach (lfe, lgm->lisp_fwd_entry_pool,
887   ({
888     switch (fid_addr_type(&lfe->key->rmt))
889       {
890       case FID_ADDR_MAC:
891         del_l2_fwd_entry_i (lgm, lfe);
892         break;
893       case FID_ADDR_IP_PREF:
894         del_ip_fwd_entry_i (lgm, lfe);
895         break;
896       }
897   }));
898   /* *INDENT-ON* */
899 }
900
901 static u8 *
902 format_lisp_fwd_path (u8 * s, va_list ap)
903 {
904   lisp_fwd_path_t *lfp = va_arg (ap, lisp_fwd_path_t *);
905
906   s = format (s, "pirority:%d weight:%d ", lfp->priority, lfp->weight);
907   s = format (s, "adj:[%U]\n",
908               format_lisp_gpe_adjacency,
909               lisp_gpe_adjacency_get (lfp->lisp_adj),
910               LISP_GPE_ADJ_FORMAT_FLAG_NONE);
911
912   return (s);
913 }
914
915 typedef enum lisp_gpe_fwd_entry_format_flag_t_
916 {
917   LISP_GPE_FWD_ENTRY_FORMAT_NONE = (0 << 0),
918   LISP_GPE_FWD_ENTRY_FORMAT_DETAIL = (1 << 1),
919 } lisp_gpe_fwd_entry_format_flag_t;
920
921
922 static u8 *
923 format_lisp_gpe_fwd_entry (u8 * s, va_list ap)
924 {
925   lisp_gpe_main_t *lgm = &lisp_gpe_main;
926   lisp_gpe_fwd_entry_t *lfe = va_arg (ap, lisp_gpe_fwd_entry_t *);
927   lisp_gpe_fwd_entry_format_flag_t flags =
928     va_arg (ap, lisp_gpe_fwd_entry_format_flag_t);
929
930   s = format (s, "VNI:%d VRF:%d EID: %U -> %U  [index:%d]",
931               lfe->key->vni, lfe->eid_table_id,
932               format_fid_address, &lfe->key->lcl,
933               format_fid_address, &lfe->key->rmt,
934               lfe - lgm->lisp_fwd_entry_pool);
935
936   if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE == lfe->type)
937     {
938       s = format (s, "\n Negative - action:%U",
939                   format_negative_mapping_action, lfe->action);
940     }
941   else
942     {
943       lisp_fwd_path_t *path;
944
945       s = format (s, "\n via:");
946       vec_foreach (path, lfe->paths)
947       {
948         s = format (s, "\n  %U", format_lisp_fwd_path, path);
949       }
950     }
951
952   if (flags & LISP_GPE_FWD_ENTRY_FORMAT_DETAIL)
953     {
954       switch (fid_addr_type (&lfe->key->rmt))
955         {
956         case FID_ADDR_MAC:
957           s = format (s, " fib-path-list:%d\n", lfe->l2.path_list_index);
958           s = format (s, " dpo:%U\n", format_dpo_id, &lfe->l2.dpo, 0);
959           break;
960         case FID_ADDR_IP_PREF:
961           break;
962         }
963     }
964
965   return (s);
966 }
967
968 static clib_error_t *
969 lisp_gpe_fwd_entry_show (vlib_main_t * vm,
970                          unformat_input_t * input, vlib_cli_command_t * cmd)
971 {
972   lisp_gpe_main_t *lgm = &lisp_gpe_main;
973   lisp_gpe_fwd_entry_t *lfe;
974   index_t index;
975   u32 vni = ~0;
976
977   if (unformat (input, "vni %d", &vni))
978     ;
979   else if (unformat (input, "%d", &index))
980     {
981       if (!pool_is_free_index (lgm->lisp_fwd_entry_pool, index))
982         {
983           lfe = pool_elt_at_index (lgm->lisp_fwd_entry_pool, index);
984
985           vlib_cli_output (vm, "[%d@] %U",
986                            index,
987                            format_lisp_gpe_fwd_entry, lfe,
988                            LISP_GPE_FWD_ENTRY_FORMAT_DETAIL);
989         }
990       else
991         {
992           vlib_cli_output (vm, "entry %d invalid", index);
993         }
994
995       return (NULL);
996     }
997
998   /* *INDENT-OFF* */
999   pool_foreach (lfe, lgm->lisp_fwd_entry_pool,
1000   ({
1001     if ((vni == ~0) ||
1002         (lfe->key->vni == vni))
1003       vlib_cli_output (vm, "%U", format_lisp_gpe_fwd_entry, lfe,
1004                        LISP_GPE_FWD_ENTRY_FORMAT_NONE);
1005   }));
1006   /* *INDENT-ON* */
1007
1008   return (NULL);
1009 }
1010
1011 /* *INDENT-OFF* */
1012 VLIB_CLI_COMMAND (lisp_gpe_fwd_entry_show_command, static) = {
1013   .path = "show lisp gpe entry",
1014   .short_help = "show lisp gpe entry vni <vni> vrf <vrf> [leid <leid>] reid <reid>",
1015   .function = lisp_gpe_fwd_entry_show,
1016 };
1017 /* *INDENT-ON* */
1018
1019 clib_error_t *
1020 lisp_gpe_fwd_entry_init (vlib_main_t * vm)
1021 {
1022   lisp_gpe_main_t *lgm = &lisp_gpe_main;
1023   clib_error_t *error = NULL;
1024
1025   if ((error = vlib_call_init_function (vm, lisp_cp_dpo_module_init)))
1026     return (error);
1027
1028   l2_fib_init (lgm);
1029
1030   fib_node_register_type (FIB_NODE_TYPE_LISP_GPE_FWD_ENTRY, &lisp_fwd_vft);
1031
1032   return (error);
1033 }
1034
1035 VLIB_INIT_FUNCTION (lisp_gpe_fwd_entry_init);
1036
1037 /*
1038  * fd.io coding-style-patch-verification: ON
1039  *
1040  * Local Variables:
1041  * eval: (c-set-style "gnu")
1042  * End:
1043  */