ipip: Multi-point interface
[vpp.git] / src / vnet / ipip / sixrd.c
1 /*
2  * sixrd.c - 6RD specific functions (RFC5969)
3  *
4  * Copyright (c) 2018 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 /**
19  * This code supports the following sixrd modes:
20  *
21  * 32 EA bits (Complete IPv4 address is embedded):
22  *   ea_bits_len = 32
23  * IPv4 suffix is embedded:
24  *   ea_bits_len = < 32
25  * No embedded address bits (1:1 mode):
26  *   ea_bits_len = 0
27  */
28
29 #include "ipip.h"
30 #include <vlibapi/api.h>
31 #include <vlibmemory/api.h>
32 #include <vnet/adj/adj.h>
33 #include <vnet/adj/adj_delegate.h>
34 #include <vnet/adj/adj_midchain.h>
35 #include <vnet/dpo/lookup_dpo.h>
36 #include <vnet/fib/fib_table.h>
37 #include <vnet/fib/fib_entry_track.h>
38 #include <vnet/fib/ip6_fib.h>
39 #include <vnet/plugin/plugin.h>
40
41 extern vlib_node_registration_t ip4_sixrd_node;
42
43 /**
44  * Adj delegate data
45  */
46 typedef struct sixrd_adj_delegate_t_
47 {
48   u32 adj_index;
49   fib_node_t sixrd_node;
50   fib_node_index_t sixrd_fib_entry_index;
51   u32 sixrd_sibling;
52 } sixrd_adj_delegate_t;
53
54 /**
55  * Pool of delegate structs
56  */
57 static sixrd_adj_delegate_t *sixrd_adj_delegate_pool;
58
59 /**
60  * Adj delegate registered type
61  */
62 static adj_delegate_type_t sixrd_adj_delegate_type;
63
64 /**
65  * FIB node registered type
66  */
67 static fib_node_type_t sixrd_fib_node_type;
68
69 static inline sixrd_adj_delegate_t *
70 sixrd_adj_from_base (adj_delegate_t * ad)
71 {
72   if (ad == NULL)
73     return (NULL);
74   return (pool_elt_at_index (sixrd_adj_delegate_pool, ad->ad_index));
75 }
76
77 static inline const sixrd_adj_delegate_t *
78 sixrd_adj_from_const_base (const adj_delegate_t * ad)
79 {
80   if (ad == NULL)
81     {
82       return (NULL);
83     }
84   return (pool_elt_at_index (sixrd_adj_delegate_pool, ad->ad_index));
85 }
86
87 static void
88 sixrd_fixup (vlib_main_t * vm,
89              const ip_adjacency_t * adj, vlib_buffer_t * b0, const void *data)
90 {
91   ip4_header_t *ip4 = vlib_buffer_get_current (b0);
92   ip6_header_t *ip6 = vlib_buffer_get_current (b0) + sizeof (ip4_header_t);
93   const ipip_tunnel_t *t = data;
94
95   ip4->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
96   ip4->dst_address.as_u32 =
97     sixrd_get_addr_net (t, ip6->dst_address.as_u64[0]);
98   ip4->checksum = ip4_header_checksum (ip4);
99 }
100
101 static void
102 ip6ip_fixup (vlib_main_t * vm,
103              const ip_adjacency_t * adj, vlib_buffer_t * b0, const void *data)
104 {
105   const ipip_tunnel_t *t = data;
106   ip4_header_t *ip4 = vlib_buffer_get_current (b0);
107   ip4->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
108   ip4->dst_address.as_u32 =
109     sixrd_get_addr_net (t, adj->sub_type.nbr.next_hop.as_u64[0]);
110   ip4->checksum = ip4_header_checksum (ip4);
111 }
112
113 static u8 *
114 sixrd_build_rewrite (vnet_main_t * vnm, u32 sw_if_index,
115                      vnet_link_t link_type, const void *dst_address)
116 {
117   u8 *rewrite = NULL;
118   ipip_tunnel_t *t;
119
120   t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
121   if (!t)
122     return 0;
123
124   vec_validate (rewrite, sizeof (ip4_header_t) - 1);
125   ip4_header_t *ip4 = (ip4_header_t *) rewrite;
126   ip4->ip_version_and_header_length = 0x45;
127   ip4->ttl = 64;
128   ip4->protocol = IP_PROTOCOL_IPV6;
129   /* fixup ip4 header length and checksum after-the-fact */
130   ip4->src_address.as_u32 = t->tunnel_src.ip4.as_u32;
131   ip4->dst_address.as_u32 = 0;
132   ip4->checksum = ip4_header_checksum (ip4);
133
134   return rewrite;
135 }
136
137 static void
138 ip6ip_tunnel_stack (adj_index_t ai, u32 fib_entry_index)
139 {
140   ip_adjacency_t *adj = adj_get (ai);
141   ipip_tunnel_t *t;
142   u32 sw_if_index = adj->rewrite_header.sw_if_index;
143
144   t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
145   if (!t)
146     return;
147
148   /*
149    * find the adjacency that is contributed by the FIB entry
150    * that this tunnel resolves via, and use it as the next adj
151    * in the midchain
152    */
153   if (vnet_hw_interface_get_flags (vnet_get_main (), t->hw_if_index) &
154       VNET_HW_INTERFACE_FLAG_LINK_UP)
155     {
156       adj_nbr_midchain_stack_on_fib_entry (ai,
157                                            fib_entry_index,
158                                            FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
159     }
160   else
161     {
162       adj_nbr_midchain_unstack (ai);
163     }
164 }
165
166 static void
167 sixrd_tunnel_stack (adj_index_t ai, u32 fib_index)
168 {
169   dpo_id_t dpo = DPO_INVALID;
170   ip_adjacency_t *adj = adj_get (ai);
171   u32 sw_if_index = adj->rewrite_header.sw_if_index;
172
173   ipip_tunnel_t *t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
174   if (!t)
175     return;
176
177   lookup_dpo_add_or_lock_w_fib_index (fib_index, DPO_PROTO_IP4,
178                                       LOOKUP_UNICAST, LOOKUP_INPUT_DST_ADDR,
179                                       LOOKUP_TABLE_FROM_CONFIG, &dpo);
180   adj_nbr_midchain_stack (ai, &dpo);
181   dpo_reset (&dpo);
182 }
183
184 static void
185 sixrd_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
186 {
187   ip_adjacency_t *adj = adj_get (ai);
188   ipip_tunnel_t *t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
189
190   /* Not our tunnel */
191   if (!t)
192     return;
193   if (IP_LOOKUP_NEXT_BCAST == adj->lookup_next_index)
194     {
195       adj_nbr_midchain_update_rewrite (ai, sixrd_fixup, t, ADJ_FLAG_NONE,
196                                        sixrd_build_rewrite (vnm, sw_if_index,
197                                                             adj_get_link_type
198                                                             (ai), NULL));
199       sixrd_tunnel_stack (ai, t->fib_index);
200     }
201   else
202     {
203       sixrd_adj_delegate_t *sixrd_ad;
204       ip4_address_t da4;
205
206       da4.as_u32 =
207         sixrd_get_addr_net (t, adj->sub_type.nbr.next_hop.as_u64[0]);
208
209       fib_prefix_t pfx = {
210         .fp_proto = FIB_PROTOCOL_IP4,
211         .fp_len = 32,
212         .fp_addr = {
213                     .ip4 = da4,
214                     }
215         ,
216       };
217
218       adj_nbr_midchain_update_rewrite (ai, ip6ip_fixup, t, ADJ_FLAG_NONE,
219                                        sixrd_build_rewrite (vnm, sw_if_index,
220                                                             adj_get_link_type
221                                                             (ai), NULL));
222
223       sixrd_ad =
224         sixrd_adj_from_base (adj_delegate_get (adj, sixrd_adj_delegate_type));
225       if (sixrd_ad == NULL)
226         {
227           pool_get (sixrd_adj_delegate_pool, sixrd_ad);
228           fib_node_init (&sixrd_ad->sixrd_node, sixrd_fib_node_type);
229           sixrd_ad->adj_index = ai;
230           sixrd_ad->sixrd_fib_entry_index =
231             fib_entry_track (t->fib_index, &pfx,
232                              sixrd_fib_node_type,
233                              sixrd_ad - sixrd_adj_delegate_pool,
234                              &sixrd_ad->sixrd_sibling);
235
236           adj_delegate_add (adj, sixrd_adj_delegate_type,
237                             sixrd_ad - sixrd_adj_delegate_pool);
238
239           ip6ip_tunnel_stack (ai, sixrd_ad->sixrd_fib_entry_index);
240         }
241     }
242 }
243
244 clib_error_t *
245 sixrd_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
246 {
247   /* Always up */
248   vnet_hw_interface_set_flags (vnm, hw_if_index,
249                                VNET_HW_INTERFACE_FLAG_LINK_UP);
250   return /* no error */ 0;
251 }
252
253 /* *INDENT-OFF* */
254 VNET_HW_INTERFACE_CLASS(sixrd_hw_interface_class) = {
255     .name = "ip6ip-6rd",
256     .build_rewrite = sixrd_build_rewrite,
257     .update_adjacency = sixrd_update_adj,
258 };
259
260 VNET_DEVICE_CLASS(sixrd_device_class) = {
261     .name = "ip6ip-6rd",
262     .admin_up_down_function = sixrd_interface_admin_up_down,
263 #ifdef SOON
264     .clear counter = 0;
265 #endif
266 }
267 ;
268 /* *INDENT-ON* */
269
270 int
271 sixrd_add_tunnel (ip6_address_t * ip6_prefix, u8 ip6_prefix_len,
272                   ip4_address_t * ip4_prefix, u8 ip4_prefix_len,
273                   ip4_address_t * ip4_src, bool security_check,
274                   u32 ip4_fib_index, u32 ip6_fib_index, u32 * sw_if_index)
275 {
276   ipip_main_t *gm = &ipip_main;
277   ipip_tunnel_t *t;
278
279   if ((ip6_prefix_len + 32 - ip4_prefix_len) > 64)
280     return VNET_API_ERROR_INVALID_VALUE;
281
282   /* Tunnel already configured */
283   ip46_address_t src = ip46_address_initializer, dst =
284     ip46_address_initializer;
285   ip_set (&src, ip4_src, true);
286   ipip_tunnel_key_t key;
287
288   ipip_mk_key_i (IPIP_TRANSPORT_IP4, IPIP_MODE_6RD, &src, &dst, ip4_fib_index,
289                  &key);
290
291   t = ipip_tunnel_db_find (&key);
292   if (t)
293     return VNET_API_ERROR_IF_ALREADY_EXISTS;
294
295   /* Get tunnel index */
296   pool_get_aligned (gm->tunnels, t, CLIB_CACHE_LINE_BYTES);
297   clib_memset (t, 0, sizeof (*t));
298   u32 t_idx = t - gm->tunnels;  /* tunnel index (or instance) */
299
300   /* Init tunnel struct */
301   t->mode = IPIP_MODE_6RD;
302   t->sixrd.ip4_prefix.as_u32 = ip4_prefix->as_u32;
303   t->sixrd.ip4_prefix_len = ip4_prefix_len;
304   t->sixrd.ip6_prefix = *ip6_prefix;
305   t->sixrd.ip6_prefix_len = ip6_prefix_len;
306   t->sixrd.ip6_fib_index = ip6_fib_index;
307   t->tunnel_src = src;
308   t->sixrd.security_check = security_check;
309   t->sixrd.shift =
310     (ip4_prefix_len < 32) ? 64 - ip6_prefix_len - (32 - ip4_prefix_len) : 0;
311
312   /* Create interface */
313   u32 hw_if_index =
314     vnet_register_interface (vnet_get_main (), sixrd_device_class.index,
315                              t_idx,
316                              sixrd_hw_interface_class.index, t_idx);
317
318   /* Default the interface to up and enable IPv6 (payload) */
319   vnet_hw_interface_t *hi =
320     vnet_get_hw_interface (vnet_get_main (), hw_if_index);
321   t->hw_if_index = hw_if_index;
322   t->fib_index = ip4_fib_index;
323   t->sw_if_index = hi->sw_if_index;
324   t->dev_instance = t_idx;
325   t->user_instance = t_idx;
326
327   vnet_sw_interface_set_mtu (vnet_get_main (), t->sw_if_index, 1480);
328
329   ipip_tunnel_db_add (t, &key);
330
331   vec_validate_init_empty (gm->tunnel_index_by_sw_if_index, hi->sw_if_index,
332                            ~0);
333   gm->tunnel_index_by_sw_if_index[hi->sw_if_index] = t_idx;
334
335   vnet_hw_interface_set_flags (vnet_get_main (), hw_if_index,
336                                VNET_HW_INTERFACE_FLAG_LINK_UP);
337   vnet_sw_interface_set_flags (vnet_get_main (), hi->sw_if_index,
338                                VNET_SW_INTERFACE_FLAG_ADMIN_UP);
339   ip6_sw_interface_enable_disable (t->sw_if_index, true);
340
341   /* Create IPv6 route/adjacency */
342   /* *INDENT-OFF* */
343   fib_prefix_t pfx6 = {
344     .fp_proto = FIB_PROTOCOL_IP6,
345     .fp_len = t->sixrd.ip6_prefix_len,
346     .fp_addr = {
347       .ip6 = t->sixrd.ip6_prefix,
348     },
349   };
350   /* *INDENT-ON* */
351
352   fib_table_lock (ip6_fib_index, FIB_PROTOCOL_IP6, FIB_SOURCE_6RD);
353   fib_table_entry_update_one_path (ip6_fib_index, &pfx6, FIB_SOURCE_6RD,
354                                    FIB_ENTRY_FLAG_ATTACHED, DPO_PROTO_IP6,
355                                    &ADJ_BCAST_ADDR, t->sw_if_index, ~0, 1,
356                                    NULL, FIB_ROUTE_PATH_FLAG_NONE);
357
358   *sw_if_index = t->sw_if_index;
359
360   if (!gm->ip4_protocol_registered)
361     {
362       vlib_node_t *ipip4_input =
363         vlib_get_node_by_name (gm->vlib_main, (u8 *) "ipip4-input");
364       ASSERT (ipip4_input);
365       ip4_register_protocol (IP_PROTOCOL_IPV6, ipip4_input->index);
366     }
367   return 0;
368 }
369
370 /*
371  * sixrd_del_tunnel
372  */
373 int
374 sixrd_del_tunnel (u32 sw_if_index)
375 {
376   ipip_main_t *gm = &ipip_main;
377   ipip_tunnel_t *t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
378   ipip_tunnel_key_t key;
379
380   if (!t)
381     {
382       clib_warning ("SIXRD tunnel delete: tunnel does not exist: %d",
383                     sw_if_index);
384       return -1;
385     }
386
387   /* *INDENT-OFF* */
388   fib_prefix_t pfx6 = {
389     .fp_proto = FIB_PROTOCOL_IP6,
390     .fp_len = t->sixrd.ip6_prefix_len,
391     .fp_addr = {
392       .ip6 = t->sixrd.ip6_prefix,
393     },
394   };
395   /* *INDENT-ON* */
396
397   fib_table_entry_path_remove (t->sixrd.ip6_fib_index, &pfx6,
398                                FIB_SOURCE_6RD,
399                                DPO_PROTO_IP6,
400                                &ADJ_BCAST_ADDR, t->sw_if_index, ~0, 1,
401                                FIB_ROUTE_PATH_FLAG_NONE);
402   fib_table_unlock (t->sixrd.ip6_fib_index, FIB_PROTOCOL_IP6, FIB_SOURCE_6RD);
403
404   vnet_sw_interface_set_flags (vnet_get_main (), t->sw_if_index,
405                                0 /* down */ );
406   ip6_sw_interface_enable_disable (t->sw_if_index, false);
407   gm->tunnel_index_by_sw_if_index[t->sw_if_index] = ~0;
408
409   vnet_delete_hw_interface (vnet_get_main (), t->hw_if_index);
410   ipip_mk_key (t, &key);
411   ipip_tunnel_db_remove (t, &key);
412   pool_put (gm->tunnels, t);
413
414   return 0;
415 }
416
417 static void
418 sixrd_adj_delegate_adj_deleted (adj_delegate_t * aed)
419 {
420   sixrd_adj_delegate_t *sixrd_ad;
421
422   sixrd_ad = sixrd_adj_from_base (aed);
423   fib_entry_untrack (sixrd_ad->sixrd_fib_entry_index,
424                      sixrd_ad->sixrd_sibling);
425   pool_put (sixrd_adj_delegate_pool, sixrd_ad);
426 }
427
428 static u8 *
429 sixrd_adj_delegate_format (const adj_delegate_t * aed, u8 * s)
430 {
431   const sixrd_adj_delegate_t *sixrd_ad;
432
433   sixrd_ad = sixrd_adj_from_const_base (aed);
434   s = format (s, "SIXRD:[fib-entry:%d]", sixrd_ad->sixrd_fib_entry_index);
435
436   return (s);
437 }
438
439 static void
440 sixrd_fib_node_last_lock_gone (fib_node_t * node)
441 {
442   /* top of the dependency tree, locks not managed here. */
443 }
444
445 static sixrd_adj_delegate_t *
446 sixrd_adj_delegate_from_fib_node (fib_node_t * node)
447 {
448   return ((sixrd_adj_delegate_t *) (((char *) node) -
449                                     STRUCT_OFFSET_OF (sixrd_adj_delegate_t,
450                                                       sixrd_node)));
451 }
452
453 static fib_node_back_walk_rc_t
454 sixrd_fib_node_back_walk_notify (fib_node_t * node,
455                                  fib_node_back_walk_ctx_t * ctx)
456 {
457   sixrd_adj_delegate_t *sixrd_ad;
458
459   sixrd_ad = sixrd_adj_delegate_from_fib_node (node);
460   ip6ip_tunnel_stack (sixrd_ad->adj_index, sixrd_ad->sixrd_fib_entry_index);
461
462   return (FIB_NODE_BACK_WALK_CONTINUE);
463 }
464
465 /**
466  * Function definition to get a FIB node from its index
467  */
468 static fib_node_t *
469 sixrd_fib_node_get (fib_node_index_t index)
470 {
471   sixrd_adj_delegate_t *sixrd_ad;
472
473   sixrd_ad = pool_elt_at_index (sixrd_adj_delegate_pool, index);
474
475   return (&sixrd_ad->sixrd_node);
476 }
477
478 /**
479  * VFT registered with the adjacency delegate
480  */
481 const static adj_delegate_vft_t sixrd_adj_delegate_vft = {
482   .adv_adj_deleted = sixrd_adj_delegate_adj_deleted,
483   .adv_format = sixrd_adj_delegate_format,
484 };
485
486 /**
487  * VFT registered with the FIB node for the adj delegate
488  */
489 const static fib_node_vft_t sixrd_fib_node_vft = {
490   .fnv_get = sixrd_fib_node_get,
491   .fnv_last_lock = sixrd_fib_node_last_lock_gone,
492   .fnv_back_walk = sixrd_fib_node_back_walk_notify,
493 };
494
495 static clib_error_t *
496 sixrd_init (vlib_main_t * vm)
497 {
498   clib_error_t *error = 0;
499
500   /* Make sure the IPIP tunnel subsystem is initialised */
501   error = vlib_call_init_function (vm, ipip_init);
502
503   sixrd_adj_delegate_type =
504     adj_delegate_register_new_type (&sixrd_adj_delegate_vft);
505   sixrd_fib_node_type = fib_node_register_new_type (&sixrd_fib_node_vft);
506
507   return error;
508 }
509
510 VLIB_INIT_FUNCTION (sixrd_init);
511
512 /*
513  * fd.io coding-style-patch-verification: ON
514  *
515  * Local Variables:
516  * eval: (c-set-style "gnu")
517  * End:
518  */