blob: dbcf7134103d79e8986d16b370e10b13fe78bb3d [file] [log] [blame]
Neale Ranns0bfe5d82016-08-25 15:29:12 +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 * @file
17 * @brief Common utility functions for IPv4, IPv6 and L2 LISP-GPE adjacencys.
18 *
19 */
20
Neale Rannsb80c5362016-10-08 13:03:40 +010021#include <vnet/dpo/load_balance.h>
22#include <vnet/lisp-cp/lisp_types.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010023#include <vnet/lisp-gpe/lisp_gpe_sub_interface.h>
24#include <vnet/lisp-gpe/lisp_gpe_adjacency.h>
25#include <vnet/lisp-gpe/lisp_gpe_tunnel.h>
26#include <vnet/fib/fib_entry.h>
27#include <vnet/adj/adj_midchain.h>
Dave Barach68b0fb02017-02-28 15:15:56 -050028#include <vppinfra/bihash_24_8.h>
29#include <vppinfra/bihash_template.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010030
31/**
32 * Memory pool of all adjacencies
33 */
34static lisp_gpe_adjacency_t *lisp_adj_pool;
35
36/**
37 * Hash table of all adjacencies. key:{nh, itf}
38 * We never have an all zeros address since the interfaces are multi-access,
39 * therefore there is no ambiguity between a v4 and v6 next-hop, so we don't
40 * need to add the protocol to the key.
41 */
42static
43BVT (clib_bihash)
44 lisp_adj_db;
45
46#define LISP_ADJ_SET_KEY(_key, _itf, _nh) \
47{ \
48 _key.key[0] = (_nh)->ip.v6.as_u64[0]; \
49 _key.key[1] = (_nh)->ip.v6.as_u64[1]; \
50 _key.key[2] = (_itf); \
51}
52
53 static index_t lisp_adj_find (const ip_address_t * addr, u32 sw_if_index)
54{
55 BVT (clib_bihash_kv) kv;
56
57 LISP_ADJ_SET_KEY (kv, sw_if_index, addr);
58
59 if (BV (clib_bihash_search) (&lisp_adj_db, &kv, &kv) < 0)
60 {
61 return (INDEX_INVALID);
62 }
63 else
64 {
65 return (kv.value);
66 }
67}
68
69static void
70lisp_adj_insert (const ip_address_t * addr, u32 sw_if_index, index_t ai)
71{
72 BVT (clib_bihash_kv) kv;
73
74 LISP_ADJ_SET_KEY (kv, sw_if_index, addr);
75 kv.value = ai;
76
77 BV (clib_bihash_add_del) (&lisp_adj_db, &kv, 1);
78}
79
80static void
81lisp_adj_remove (const ip_address_t * addr, u32 sw_if_index)
82{
83 BVT (clib_bihash_kv) kv;
84
85 LISP_ADJ_SET_KEY (kv, sw_if_index, addr);
86
87 BV (clib_bihash_add_del) (&lisp_adj_db, &kv, 0);
88}
89
90static lisp_gpe_adjacency_t *
91lisp_gpe_adjacency_get_i (index_t lai)
92{
93 return (pool_elt_at_index (lisp_adj_pool, lai));
94}
95
96fib_forward_chain_type_t
97lisp_gpe_adj_get_fib_chain_type (const lisp_gpe_adjacency_t * ladj)
98{
99 switch (ip_addr_version (&ladj->remote_rloc))
100 {
101 case IP4:
102 return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
103 case IP6:
104 return (FIB_FORW_CHAIN_TYPE_UNICAST_IP6);
105 default:
106 ASSERT (0);
107 break;
108 }
109 return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
110}
111
Neale Rannsb80c5362016-10-08 13:03:40 +0100112static void
113ip46_address_to_ip_address (const ip46_address_t * a, ip_address_t * b)
114{
115 if (ip46_address_is_ip4 (a))
116 {
117 memset (b, 0, sizeof (*b));
118 ip_address_set (b, &a->ip4, IP4);
119 }
120 else
121 {
122 ip_address_set (b, &a->ip6, IP6);
123 }
124}
125
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100126/**
127 * @brief Stack the tunnel's midchain on the IP forwarding chain of the via
128 */
129static void
Neale Rannsb80c5362016-10-08 13:03:40 +0100130lisp_gpe_adj_stack_one (lisp_gpe_adjacency_t * ladj, adj_index_t ai)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100131{
Neale Ranns5e575b12016-10-03 09:40:25 +0100132 const lisp_gpe_tunnel_t *lgt;
Neale Ranns948e00f2016-10-20 13:39:34 +0100133 dpo_id_t tmp = DPO_INVALID;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100134
135 lgt = lisp_gpe_tunnel_get (ladj->tunnel_index);
136 fib_entry_contribute_forwarding (lgt->fib_entry_index,
137 lisp_gpe_adj_get_fib_chain_type (ladj),
138 &tmp);
139
Neale Rannsb80c5362016-10-08 13:03:40 +0100140 if (DPO_LOAD_BALANCE == tmp.dpoi_type)
141 {
142 /*
143 * post LISP rewrite we will load-balance. However, the LISP encap
144 * is always the same for this adjacency/tunnel and hence the IP/UDP src,dst
145 * hash is always the same result too. So we do that hash now and
146 * stack on the choice.
147 * If the choice is an incomplete adj then we will need a poke when
148 * it becomes complete. This happens since the adj update walk propagates
149 * as far a recursive paths.
150 */
151 const dpo_id_t *choice;
152 load_balance_t *lb;
153 int hash;
154
155 lb = load_balance_get (tmp.dpoi_index);
156
157 if (IP4 == ip_addr_version (&ladj->remote_rloc))
158 {
159 hash = ip4_compute_flow_hash ((ip4_header_t *) adj_get_rewrite (ai),
160 lb->lb_hash_config);
161 }
162 else
163 {
164 hash = ip6_compute_flow_hash ((ip6_header_t *) adj_get_rewrite (ai),
165 lb->lb_hash_config);
166 }
167
168 choice =
169 load_balance_get_bucket_i (lb, hash & lb->lb_n_buckets_minus_1);
170 dpo_copy (&tmp, choice);
171 }
172
173 adj_nbr_midchain_stack (ai, &tmp);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100174 dpo_reset (&tmp);
175}
176
Neale Rannsb80c5362016-10-08 13:03:40 +0100177/**
178 * @brief Call back when restacking all adjacencies on a GRE interface
179 */
180static adj_walk_rc_t
181lisp_gpe_adj_walk_cb (adj_index_t ai, void *ctx)
182{
183 lisp_gpe_adjacency_t *ladj = ctx;
184
185 lisp_gpe_adj_stack_one (ladj, ai);
186
187 return (ADJ_WALK_RC_CONTINUE);
188}
189
190static void
191lisp_gpe_adj_stack (lisp_gpe_adjacency_t * ladj)
192{
193 fib_protocol_t nh_proto;
194 ip46_address_t nh;
195
196 ip_address_to_46 (&ladj->remote_rloc, &nh, &nh_proto);
197
198 /*
199 * walk all the adjacencies on th lisp interface and restack them
200 */
201 adj_nbr_walk_nh (ladj->sw_if_index,
202 nh_proto, &nh, lisp_gpe_adj_walk_cb, ladj);
203}
204
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100205static lisp_gpe_next_protocol_e
Neale Ranns924d03a2016-10-19 08:25:46 +0100206lisp_gpe_adj_proto_from_vnet_link_type (vnet_link_t linkt)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100207{
208 switch (linkt)
209 {
Neale Ranns924d03a2016-10-19 08:25:46 +0100210 case VNET_LINK_IP4:
Neale Ranns5e575b12016-10-03 09:40:25 +0100211 return (LISP_GPE_NEXT_PROTO_IP4);
Neale Ranns924d03a2016-10-19 08:25:46 +0100212 case VNET_LINK_IP6:
Neale Ranns5e575b12016-10-03 09:40:25 +0100213 return (LISP_GPE_NEXT_PROTO_IP6);
Neale Ranns924d03a2016-10-19 08:25:46 +0100214 case VNET_LINK_ETHERNET:
Neale Ranns5e575b12016-10-03 09:40:25 +0100215 return (LISP_GPE_NEXT_PROTO_ETHERNET);
Florin Corasce1b4c72017-01-26 14:25:34 -0800216 case VNET_LINK_NSH:
217 return (LISP_GPE_NEXT_PROTO_NSH);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100218 default:
219 ASSERT (0);
220 }
Neale Ranns5e575b12016-10-03 09:40:25 +0100221 return (LISP_GPE_NEXT_PROTO_IP4);
222}
223
224#define is_v4_packet(_h) ((*(u8*) _h) & 0xF0) == 0x40
225
226static void
227lisp_gpe_fixup (vlib_main_t * vm, ip_adjacency_t * adj, vlib_buffer_t * b)
228{
229 /* Fixup the checksum and len fields in the LISP tunnel encap
230 * that was applied at the midchain node */
231 ip_udp_fixup_one (vm, b, is_v4_packet (vlib_buffer_get_current (b)));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100232}
233
Neale Rannsb80c5362016-10-08 13:03:40 +0100234/**
235 * @brief The LISP-GPE interface registered function to update, i.e.
236 * provide an rewrite string for, an adjacency.
237 */
238void
239lisp_gpe_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
240{
241 const lisp_gpe_tunnel_t *lgt;
242 lisp_gpe_adjacency_t *ladj;
243 ip_adjacency_t *adj;
244 ip_address_t rloc;
245 vnet_link_t linkt;
246 index_t lai;
247
248 adj = adj_get (ai);
249 ip46_address_to_ip_address (&adj->sub_type.nbr.next_hop, &rloc);
250
251 /*
252 * find an existing or create a new adj
253 */
254 lai = lisp_adj_find (&rloc, sw_if_index);
255
256 ASSERT (INDEX_INVALID != lai);
257
258 ladj = pool_elt_at_index (lisp_adj_pool, lai);
259 lgt = lisp_gpe_tunnel_get (ladj->tunnel_index);
260 linkt = adj_get_link_type (ai);
Neale Rannsb80c5362016-10-08 13:03:40 +0100261 adj_nbr_midchain_update_rewrite
262 (ai, lisp_gpe_fixup,
263 (VNET_LINK_ETHERNET == linkt ?
264 ADJ_MIDCHAIN_FLAG_NO_COUNT :
265 ADJ_MIDCHAIN_FLAG_NONE),
Florin Corasce1b4c72017-01-26 14:25:34 -0800266 lisp_gpe_tunnel_build_rewrite (lgt, ladj,
267 lisp_gpe_adj_proto_from_vnet_link_type
268 (linkt)));
Neale Rannsb80c5362016-10-08 13:03:40 +0100269
270 lisp_gpe_adj_stack_one (ladj, ai);
271}
272
273u8 *
274lisp_gpe_build_rewrite (vnet_main_t * vnm,
275 u32 sw_if_index,
276 vnet_link_t link_type, const void *dst_address)
277{
278 ASSERT (0);
279 return (NULL);
280}
281
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100282index_t
283lisp_gpe_adjacency_find_or_create_and_lock (const locator_pair_t * pair,
284 u32 overlay_table_id, u32 vni)
285{
Neale Rannsb80c5362016-10-08 13:03:40 +0100286 const lisp_gpe_sub_interface_t *l3s;
Neale Ranns5e575b12016-10-03 09:40:25 +0100287 const lisp_gpe_tunnel_t *lgt;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100288 lisp_gpe_adjacency_t *ladj;
289 index_t lai, l3si;
290
291 /*
292 * first find the L3 sub-interface that corresponds to the loacl-rloc and vni
293 */
294 l3si = lisp_gpe_sub_interface_find_or_create_and_lock (&pair->lcl_loc,
295 overlay_table_id,
296 vni);
Neale Rannsb80c5362016-10-08 13:03:40 +0100297 l3s = lisp_gpe_sub_interface_get (l3si);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100298
299 /*
300 * find an existing or create a new adj
301 */
Neale Rannsb80c5362016-10-08 13:03:40 +0100302 lai = lisp_adj_find (&pair->rmt_loc, l3s->sw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100303
304 if (INDEX_INVALID == lai)
305 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100306
307 pool_get (lisp_adj_pool, ladj);
308 memset (ladj, 0, sizeof (*ladj));
309 lai = (ladj - lisp_adj_pool);
310
Neale Rannsb80c5362016-10-08 13:03:40 +0100311 ip_address_copy (&ladj->remote_rloc, &pair->rmt_loc);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100312 ladj->vni = vni;
313 /* transfer the lock to the adj */
314 ladj->lisp_l3_sub_index = l3si;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100315 ladj->sw_if_index = l3s->sw_if_index;
316
317 /* if vni is non-default */
318 if (ladj->vni)
319 ladj->flags = LISP_GPE_FLAGS_I;
320
321 /* work in lisp-gpe not legacy mode */
322 ladj->flags |= LISP_GPE_FLAGS_P;
323
324 /*
325 * find the tunnel that will provide the underlying transport
326 * and hence the rewrite.
327 * The RLOC FIB index is default table - always.
328 */
329 ladj->tunnel_index = lisp_gpe_tunnel_find_or_create_and_lock (pair, 0);
330
331 lgt = lisp_gpe_tunnel_get (ladj->tunnel_index);
332
333 /*
334 * become of child of the RLOC FIB entry so we are updated when
335 * its reachability changes, allowing us to re-stack the midcahins
336 */
337 ladj->fib_entry_child_index = fib_entry_child_add (lgt->fib_entry_index,
338 FIB_NODE_TYPE_LISP_ADJ,
339 lai);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100340
Neale Rannsb80c5362016-10-08 13:03:40 +0100341 lisp_adj_insert (&ladj->remote_rloc, ladj->sw_if_index, lai);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100342 }
343 else
344 {
345 /* unlock the interface from the find. */
346 lisp_gpe_sub_interface_unlock (l3si);
347 ladj = lisp_gpe_adjacency_get_i (lai);
348 }
349
350 ladj->locks++;
351
352 return (lai);
353}
354
355/**
356 * @brief Get a pointer to a tunnel from a pointer to a FIB node
357 */
358static lisp_gpe_adjacency_t *
359lisp_gpe_adjacency_from_fib_node (const fib_node_t * node)
360{
361 return ((lisp_gpe_adjacency_t *)
362 ((char *) node -
363 STRUCT_OFFSET_OF (lisp_gpe_adjacency_t, fib_node)));
364}
365
366static void
367lisp_gpe_adjacency_last_lock_gone (lisp_gpe_adjacency_t * ladj)
368{
Neale Rannsb80c5362016-10-08 13:03:40 +0100369 const lisp_gpe_tunnel_t *lgt;
370
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100371 /*
372 * no children so we are not counting locks. no-op.
373 * at least not counting
374 */
Neale Rannsb80c5362016-10-08 13:03:40 +0100375 lisp_adj_remove (&ladj->remote_rloc, ladj->sw_if_index);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100376
377 /*
378 * unlock the resources this adj holds
379 */
Neale Rannsb80c5362016-10-08 13:03:40 +0100380 lgt = lisp_gpe_tunnel_get (ladj->tunnel_index);
381
382 fib_entry_child_remove (lgt->fib_entry_index, ladj->fib_entry_child_index);
383
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100384 lisp_gpe_tunnel_unlock (ladj->tunnel_index);
385 lisp_gpe_sub_interface_unlock (ladj->lisp_l3_sub_index);
386
387 pool_put (lisp_adj_pool, ladj);
388}
389
390void
391lisp_gpe_adjacency_unlock (index_t lai)
392{
393 lisp_gpe_adjacency_t *ladj;
394
395 ladj = lisp_gpe_adjacency_get_i (lai);
396
397 ladj->locks--;
398
399 if (0 == ladj->locks)
400 {
401 lisp_gpe_adjacency_last_lock_gone (ladj);
402 }
403}
404
405const lisp_gpe_adjacency_t *
406lisp_gpe_adjacency_get (index_t lai)
407{
408 return (lisp_gpe_adjacency_get_i (lai));
409}
410
411
412/**
413 * @brief LISP GPE tunnel back walk
414 *
415 * The FIB entry through which this tunnel resolves has been updated.
416 * re-stack the midchain on the new forwarding.
417 */
418static fib_node_back_walk_rc_t
419lisp_gpe_adjacency_back_walk (fib_node_t * node,
420 fib_node_back_walk_ctx_t * ctx)
421{
422 lisp_gpe_adj_stack (lisp_gpe_adjacency_from_fib_node (node));
423
424 return (FIB_NODE_BACK_WALK_CONTINUE);
425}
426
427static fib_node_t *
428lisp_gpe_adjacency_get_fib_node (fib_node_index_t index)
429{
430 lisp_gpe_adjacency_t *ladj;
431
432 ladj = pool_elt_at_index (lisp_adj_pool, index);
433 return (&ladj->fib_node);
434}
435
436static void
437lisp_gpe_adjacency_last_fib_lock_gone (fib_node_t * node)
438{
439 lisp_gpe_adjacency_last_lock_gone (lisp_gpe_adjacency_from_fib_node (node));
440}
441
442const static fib_node_vft_t lisp_gpe_tuennel_vft = {
443 .fnv_get = lisp_gpe_adjacency_get_fib_node,
444 .fnv_back_walk = lisp_gpe_adjacency_back_walk,
445 .fnv_last_lock = lisp_gpe_adjacency_last_fib_lock_gone,
446};
447
448u8 *
449format_lisp_gpe_adjacency (u8 * s, va_list * args)
450{
451 lisp_gpe_adjacency_t *ladj = va_arg (*args, lisp_gpe_adjacency_t *);
452 lisp_gpe_adjacency_format_flags_t flags =
Billy McFallcfcf1e22016-10-14 09:51:49 -0400453 va_arg (*args, lisp_gpe_adjacency_format_flags_t);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100454
455 if (flags & LISP_GPE_ADJ_FORMAT_FLAG_DETAIL)
456 {
457 s =
458 format (s, "index %d locks:%d\n", ladj - lisp_adj_pool, ladj->locks);
459 }
460
461 s = format (s, " vni: %d,", ladj->vni);
462 s = format (s, " remote-RLOC: %U,", format_ip_address, &ladj->remote_rloc);
463
464 if (flags & LISP_GPE_ADJ_FORMAT_FLAG_DETAIL)
465 {
466 s = format (s, " %U\n",
467 format_lisp_gpe_sub_interface,
468 lisp_gpe_sub_interface_get (ladj->lisp_l3_sub_index));
469 s = format (s, " %U\n",
470 format_lisp_gpe_tunnel,
471 lisp_gpe_tunnel_get (ladj->tunnel_index));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100472 }
473 else
474 {
475 s = format (s, " LISP L3 sub-interface index: %d,",
476 ladj->lisp_l3_sub_index);
477 s = format (s, " LISP tunnel index: %d", ladj->tunnel_index);
478 }
479
480
481 return (s);
482}
483
484static clib_error_t *
485lisp_gpe_adjacency_show (vlib_main_t * vm,
486 unformat_input_t * input, vlib_cli_command_t * cmd)
487{
488 lisp_gpe_adjacency_t *ladj;
489 index_t index;
490
491 if (pool_elts (lisp_adj_pool) == 0)
492 vlib_cli_output (vm, "No lisp-gpe Adjacencies");
493
494 if (unformat (input, "%d", &index))
495 {
496 ladj = lisp_gpe_adjacency_get_i (index);
497 vlib_cli_output (vm, "%U", format_lisp_gpe_adjacency, ladj,
498 LISP_GPE_ADJ_FORMAT_FLAG_DETAIL);
499 }
500 else
501 {
502 /* *INDENT-OFF* */
503 pool_foreach (ladj, lisp_adj_pool,
504 ({
505 vlib_cli_output (vm, "[%d] %U\n",
506 ladj - lisp_adj_pool,
507 format_lisp_gpe_adjacency, ladj,
508 LISP_GPE_ADJ_FORMAT_FLAG_NONE);
509 }));
510 /* *INDENT-ON* */
511 }
512
513 return 0;
514}
515
516/* *INDENT-OFF* */
517VLIB_CLI_COMMAND (show_lisp_gpe_tunnel_command, static) =
518{
Filip Tehlar82786c42017-02-20 15:20:37 +0100519 .path = "show gpe adjacency",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100520 .function = lisp_gpe_adjacency_show,
521};
522/* *INDENT-ON* */
523
524#define LISP_ADJ_NBR_DEFAULT_HASH_NUM_BUCKETS (256)
525#define LISP_ADJ_NBR_DEFAULT_HASH_MEMORY_SIZE (1<<20)
526
527static clib_error_t *
528lisp_gpe_adj_module_init (vlib_main_t * vm)
529{
530 BV (clib_bihash_init) (&lisp_adj_db,
531 "Adjacency Neighbour table",
532 LISP_ADJ_NBR_DEFAULT_HASH_NUM_BUCKETS,
533 LISP_ADJ_NBR_DEFAULT_HASH_MEMORY_SIZE);
534
535 fib_node_register_type (FIB_NODE_TYPE_LISP_ADJ, &lisp_gpe_tuennel_vft);
536 return (NULL);
537}
538
539VLIB_INIT_FUNCTION (lisp_gpe_adj_module_init)
540/*
541 * fd.io coding-style-patch-verification: ON
542 *
543 * Local Variables:
544 * eval: (c-set-style "gnu")
545 * End:
546 */