blob: c7aafc6a9caa1c462457c38ff26e8488b772736c [file] [log] [blame]
Neale Ranns5e575b12016-10-03 09:40:25 +01001/*
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 */
41static u32
42ip_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 {
Neale Ranns948e00f2016-10-20 13:39:34 +010064 dpo_id_t src_lkup_dpo = DPO_INVALID;
Neale Ranns5e575b12016-10-03 09:40:25 +010065
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);
Filip Tehlard5fcc462016-10-17 16:20:18 +020072 /*
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)));
Neale Ranns5e575b12016-10-03 09:40:25 +010083 /*
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 */
138static void
139ip_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 */
177static void
178ip_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
Neale Ranns5e575b12016-10-03 09:40:25 +0100203static fib_route_path_t *
204lisp_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 */
245static void
246ip_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
264static void
265create_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 ?
Neale Ranns450cd302016-11-09 17:49:42 +0000270 DPO_PROTO_IP4 : DPO_PROTO_IP6);
Neale Ranns5e575b12016-10-03 09:40:25 +0100271
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 {
Neale Ranns948e00f2016-10-20 13:39:34 +0100277 dpo_id_t dpo = DPO_INVALID;
Neale Ranns5e575b12016-10-03 09:40:25 +0100278
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
306static void
307delete_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
314static void
315gid_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
332static lisp_gpe_fwd_entry_t *
333find_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
364static int
365lisp_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
372static void
373lisp_gpe_fwd_entry_mk_paths (lisp_gpe_fwd_entry_t * lfe,
374 vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
375{
Neale Ranns5e575b12016-10-03 09:40:25 +0100376 lisp_fwd_path_t *path;
377 u32 index;
378
Neale Ranns5e575b12016-10-03 09:40:25 +0100379 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],
Filip Tehlard5fcc462016-10-17 16:20:18 +0200391 a->dp_table, lfe->key->vni);
Neale Ranns5e575b12016-10-03 09:40:25 +0100392 }
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 */
406static int
407add_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
449static void
450del_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 */
481static int
482del_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
499static void
500make_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 */
521index_t
522lisp_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 }
Filip Tehlard5fcc462016-10-17 16:20:18 +0200539 else
540 return value.value;
Neale Ranns5e575b12016-10-03 09:40:25 +0100541
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 */
560static u32
561lisp_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
586static void
587l2_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
604static void
605del_l2_fwd_entry_i (lisp_gpe_main_t * lgm, lisp_gpe_fwd_entry_t * lfe)
606{
607 lisp_fwd_path_t *path;
608
Florin Coras2ccf7682016-10-04 18:03:49 +0300609 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 }
Neale Ranns5e575b12016-10-03 09:40:25 +0100618
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
Neale Ranns5e575b12016-10-03 09:40:25 +0100623 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 */
638static int
639del_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
Florin Coras2ccf7682016-10-04 18:03:49 +0300647 if (NULL == lfe)
Neale Ranns5e575b12016-10-03 09:40:25 +0100648 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 */
658static void
659lisp_gpe_l2_update_fwding (lisp_gpe_fwd_entry_t * lfe)
660{
661 lisp_gpe_main_t *lgm = &lisp_gpe_main;
Neale Ranns948e00f2016-10-20 13:39:34 +0100662 dpo_id_t dpo = DPO_INVALID;
Neale Ranns5e575b12016-10-03 09:40:25 +0100663
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 */
695static int
696add_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 */
772static lisp_gpe_fwd_entry_t *
773lisp_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 */
783static fib_node_back_walk_rc_t
784lisp_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 */
795static fib_node_t *
796lisp_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 */
809static void
810lisp_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 */
819const 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 */
835int
836vnet_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 */
871void
872vnet_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
893static u8 *
894format_lisp_fwd_path (u8 * s, va_list ap)
895{
896 lisp_fwd_path_t *lfp = va_arg (ap, lisp_fwd_path_t *);
897
Filip Tehlard5fcc462016-10-17 16:20:18 +0200898 s = format (s, "priority:%d weight:%d ", lfp->priority, lfp->weight);
Neale Ranns5e575b12016-10-03 09:40:25 +0100899 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
907typedef 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
914static u8 *
915format_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
960static clib_error_t *
961lisp_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* */
1004VLIB_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
1011clib_error_t *
1012lisp_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
1027VLIB_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 */