VPP-598: tcp stack initial commit
[vpp.git] / src / vnet / lisp-gpe / lisp_gpe_adjacency.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  * @file
17  * @brief Common utility functions for IPv4, IPv6 and L2 LISP-GPE adjacencys.
18  *
19  */
20
21 #include <vnet/dpo/load_balance.h>
22 #include <vnet/lisp-cp/lisp_types.h>
23 #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>
28 #include <vppinfra/bihash_24_8.h>
29 #include <vppinfra/bihash_template.h>
30
31 /**
32  * Memory pool of all adjacencies
33  */
34 static 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  */
42 static
43 BVT (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
69 static void
70 lisp_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
80 static void
81 lisp_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
90 static lisp_gpe_adjacency_t *
91 lisp_gpe_adjacency_get_i (index_t lai)
92 {
93   return (pool_elt_at_index (lisp_adj_pool, lai));
94 }
95
96 fib_forward_chain_type_t
97 lisp_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
112 static void
113 ip46_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
126 /**
127  * @brief Stack the tunnel's midchain on the IP forwarding chain of the via
128  */
129 static void
130 lisp_gpe_adj_stack_one (lisp_gpe_adjacency_t * ladj, adj_index_t ai)
131 {
132   const lisp_gpe_tunnel_t *lgt;
133   dpo_id_t tmp = DPO_INVALID;
134
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
140   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);
174   dpo_reset (&tmp);
175 }
176
177 /**
178  * @brief Call back when restacking all adjacencies on a GRE interface
179  */
180 static adj_walk_rc_t
181 lisp_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
190 static void
191 lisp_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
205 static lisp_gpe_next_protocol_e
206 lisp_gpe_adj_proto_from_vnet_link_type (vnet_link_t linkt)
207 {
208   switch (linkt)
209     {
210     case VNET_LINK_IP4:
211       return (LISP_GPE_NEXT_PROTO_IP4);
212     case VNET_LINK_IP6:
213       return (LISP_GPE_NEXT_PROTO_IP6);
214     case VNET_LINK_ETHERNET:
215       return (LISP_GPE_NEXT_PROTO_ETHERNET);
216     case VNET_LINK_NSH:
217       return (LISP_GPE_NEXT_PROTO_NSH);
218     default:
219       ASSERT (0);
220     }
221   return (LISP_GPE_NEXT_PROTO_IP4);
222 }
223
224 #define is_v4_packet(_h) ((*(u8*) _h) & 0xF0) == 0x40
225
226 static void
227 lisp_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)));
232 }
233
234 /**
235  * @brief The LISP-GPE interface registered function to update, i.e.
236  * provide an rewrite string for, an adjacency.
237  */
238 void
239 lisp_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);
261   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),
266      lisp_gpe_tunnel_build_rewrite (lgt, ladj,
267                                     lisp_gpe_adj_proto_from_vnet_link_type
268                                     (linkt)));
269
270   lisp_gpe_adj_stack_one (ladj, ai);
271 }
272
273 u8 *
274 lisp_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
282 index_t
283 lisp_gpe_adjacency_find_or_create_and_lock (const locator_pair_t * pair,
284                                             u32 overlay_table_id, u32 vni)
285 {
286   const lisp_gpe_sub_interface_t *l3s;
287   const lisp_gpe_tunnel_t *lgt;
288   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);
297   l3s = lisp_gpe_sub_interface_get (l3si);
298
299   /*
300    * find an existing or create a new adj
301    */
302   lai = lisp_adj_find (&pair->rmt_loc, l3s->sw_if_index);
303
304   if (INDEX_INVALID == lai)
305     {
306
307       pool_get (lisp_adj_pool, ladj);
308       memset (ladj, 0, sizeof (*ladj));
309       lai = (ladj - lisp_adj_pool);
310
311       ip_address_copy (&ladj->remote_rloc, &pair->rmt_loc);
312       ladj->vni = vni;
313       /* transfer the lock to the adj */
314       ladj->lisp_l3_sub_index = l3si;
315       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);
340
341       lisp_adj_insert (&ladj->remote_rloc, ladj->sw_if_index, lai);
342     }
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  */
358 static lisp_gpe_adjacency_t *
359 lisp_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
366 static void
367 lisp_gpe_adjacency_last_lock_gone (lisp_gpe_adjacency_t * ladj)
368 {
369   const lisp_gpe_tunnel_t *lgt;
370
371   /*
372    * no children so we are not counting locks. no-op.
373    * at least not counting
374    */
375   lisp_adj_remove (&ladj->remote_rloc, ladj->sw_if_index);
376
377   /*
378    * unlock the resources this adj holds
379    */
380   lgt = lisp_gpe_tunnel_get (ladj->tunnel_index);
381
382   fib_entry_child_remove (lgt->fib_entry_index, ladj->fib_entry_child_index);
383
384   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
390 void
391 lisp_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
405 const lisp_gpe_adjacency_t *
406 lisp_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  */
418 static fib_node_back_walk_rc_t
419 lisp_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
427 static fib_node_t *
428 lisp_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
436 static void
437 lisp_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
442 const 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
448 u8 *
449 format_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 =
453     va_arg (*args, lisp_gpe_adjacency_format_flags_t);
454
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));
472     }
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
484 static clib_error_t *
485 lisp_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* */
517 VLIB_CLI_COMMAND (show_lisp_gpe_tunnel_command, static) =
518 {
519   .path = "show gpe adjacency",
520   .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
527 static clib_error_t *
528 lisp_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
539 VLIB_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  */