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