blob: 492b4f8326043edbeda6c65e09763414d3535f40 [file] [log] [blame]
Ole Troan298c6952018-03-08 12:30:43 +01001/*
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>
Neale Ranns1f50bf82019-07-16 15:28:52 +000037#include <vnet/fib/fib_entry_track.h>
Ole Troan298c6952018-03-08 12:30:43 +010038#include <vnet/fib/ip6_fib.h>
39#include <vnet/plugin/plugin.h>
Ole Troan298c6952018-03-08 12:30:43 +010040
41extern vlib_node_registration_t ip4_sixrd_node;
42
43/**
44 * Adj delegate data
45 */
46typedef 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 */
57static sixrd_adj_delegate_t *sixrd_adj_delegate_pool;
58
59/**
60 * Adj delegate registered type
61 */
62static adj_delegate_type_t sixrd_adj_delegate_type;
63
64/**
65 * FIB node registered type
66 */
67static fib_node_type_t sixrd_fib_node_type;
68
69static inline sixrd_adj_delegate_t *
70sixrd_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
77static inline const sixrd_adj_delegate_t *
78sixrd_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
87static void
Neale Ranns960eeea2019-12-02 23:28:50 +000088sixrd_fixup (vlib_main_t * vm,
89 const ip_adjacency_t * adj, vlib_buffer_t * b0, const void *data)
Ole Troan298c6952018-03-08 12:30:43 +010090{
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
101static void
Neale Ranns960eeea2019-12-02 23:28:50 +0000102ip6ip_fixup (vlib_main_t * vm,
103 const ip_adjacency_t * adj, vlib_buffer_t * b0, const void *data)
Ole Troan298c6952018-03-08 12:30:43 +0100104{
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
113static u8 *
114sixrd_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
137static void
138ip6ip_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 {
Neale Ranns521a8d72018-12-06 13:46:49 +0000156 adj_nbr_midchain_stack_on_fib_entry (ai,
157 fib_entry_index,
158 FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
Ole Troan298c6952018-03-08 12:30:43 +0100159 }
160 else
161 {
162 adj_nbr_midchain_unstack (ai);
163 }
164}
165
166static void
167sixrd_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);
Neale Ranns61502112018-08-22 00:21:14 -0700181 dpo_reset (&dpo);
Ole Troan298c6952018-03-08 12:30:43 +0100182}
183
Ole Troan298c6952018-03-08 12:30:43 +0100184static void
185sixrd_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
Ole Troan1d977dc2018-03-19 12:14:02 +0100190 /* Not our tunnel */
191 if (!t)
192 return;
Neale Ranns579092c2018-07-30 08:14:14 -0700193 if (IP_LOOKUP_NEXT_BCAST == adj->lookup_next_index)
Ole Troan298c6952018-03-08 12:30:43 +0100194 {
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 =
Neale Ranns1f50bf82019-07-16 15:28:52 +0000231 fib_entry_track (t->fib_index, &pfx,
232 sixrd_fib_node_type,
233 sixrd_ad - sixrd_adj_delegate_pool,
234 &sixrd_ad->sixrd_sibling);
Ole Troan298c6952018-03-08 12:30:43 +0100235
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
244clib_error_t *
245sixrd_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* */
254VNET_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
260VNET_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
270int
271sixrd_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,
Neale Ranns61502112018-08-22 00:21:14 -0700274 u32 ip4_fib_index, u32 ip6_fib_index, u32 * sw_if_index)
Ole Troan298c6952018-03-08 12:30:43 +0100275{
276 ipip_main_t *gm = &ipip_main;
277 ipip_tunnel_t *t;
278
Ole Troan298c6952018-03-08 12:30:43 +0100279 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);
Neale Ranns14053c92019-12-29 23:55:18 +0000286 ipip_tunnel_key_t key;
287
288 ipip_mk_key_i (IPIP_TRANSPORT_IP4, IPIP_MODE_6RD, &src, &dst, ip4_fib_index,
289 &key);
Ole Troan298c6952018-03-08 12:30:43 +0100290
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);
Dave Barachb7b92992018-10-17 10:38:51 -0400297 clib_memset (t, 0, sizeof (*t));
Ole Troan298c6952018-03-08 12:30:43 +0100298 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;
Neale Ranns61502112018-08-22 00:21:14 -0700306 t->sixrd.ip6_fib_index = ip6_fib_index;
Ole Troan298c6952018-03-08 12:30:43 +0100307 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;
Neale Ranns61502112018-08-22 00:21:14 -0700322 t->fib_index = ip4_fib_index;
Ole Troan298c6952018-03-08 12:30:43 +0100323 t->sw_if_index = hi->sw_if_index;
324 t->dev_instance = t_idx;
325 t->user_instance = t_idx;
326
Ole Troand7231612018-06-07 10:17:57 +0200327 vnet_sw_interface_set_mtu (vnet_get_main (), t->sw_if_index, 1480);
Ole Troan298c6952018-03-08 12:30:43 +0100328
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);
Neale Ranns61502112018-08-22 00:21:14 -0700339 ip6_sw_interface_enable_disable (t->sw_if_index, true);
Ole Troan298c6952018-03-08 12:30:43 +0100340
341 /* Create IPv6 route/adjacency */
Neale Ranns61502112018-08-22 00:21:14 -0700342 /* *INDENT-OFF* */
Ole Troan298c6952018-03-08 12:30:43 +0100343 fib_prefix_t pfx6 = {
344 .fp_proto = FIB_PROTOCOL_IP6,
345 .fp_len = t->sixrd.ip6_prefix_len,
346 .fp_addr = {
Neale Ranns61502112018-08-22 00:21:14 -0700347 .ip6 = t->sixrd.ip6_prefix,
348 },
Ole Troan298c6952018-03-08 12:30:43 +0100349 };
Neale Ranns61502112018-08-22 00:21:14 -0700350 /* *INDENT-ON* */
Ole Troan298c6952018-03-08 12:30:43 +0100351
Neale Ranns61502112018-08-22 00:21:14 -0700352 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,
Ole Troan298c6952018-03-08 12:30:43 +0100354 FIB_ENTRY_FLAG_ATTACHED, DPO_PROTO_IP6,
Neale Ranns61502112018-08-22 00:21:14 -0700355 &ADJ_BCAST_ADDR, t->sw_if_index, ~0, 1,
Ole Troan298c6952018-03-08 12:30:43 +0100356 NULL, FIB_ROUTE_PATH_FLAG_NONE);
357
Neale Ranns61502112018-08-22 00:21:14 -0700358 *sw_if_index = t->sw_if_index;
Ole Troan298c6952018-03-08 12:30:43 +0100359
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 */
373int
374sixrd_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);
Neale Ranns14053c92019-12-29 23:55:18 +0000378 ipip_tunnel_key_t key;
Ole Troan298c6952018-03-08 12:30:43 +0100379
380 if (!t)
381 {
382 clib_warning ("SIXRD tunnel delete: tunnel does not exist: %d",
383 sw_if_index);
384 return -1;
385 }
386
Neale Ranns61502112018-08-22 00:21:14 -0700387 /* *INDENT-OFF* */
Ole Troan298c6952018-03-08 12:30:43 +0100388 fib_prefix_t pfx6 = {
389 .fp_proto = FIB_PROTOCOL_IP6,
390 .fp_len = t->sixrd.ip6_prefix_len,
391 .fp_addr = {
Neale Ranns61502112018-08-22 00:21:14 -0700392 .ip6 = t->sixrd.ip6_prefix,
393 },
Ole Troan298c6952018-03-08 12:30:43 +0100394 };
Neale Ranns61502112018-08-22 00:21:14 -0700395 /* *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
Ole Troan298c6952018-03-08 12:30:43 +0100404 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);
Neale Ranns14053c92019-12-29 23:55:18 +0000410 ipip_mk_key (t, &key);
411 ipip_tunnel_db_remove (t, &key);
Ole Troan298c6952018-03-08 12:30:43 +0100412 pool_put (gm->tunnels, t);
413
414 return 0;
415}
416
417static void
418sixrd_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);
Neale Ranns1f50bf82019-07-16 15:28:52 +0000423 fib_entry_untrack (sixrd_ad->sixrd_fib_entry_index,
424 sixrd_ad->sixrd_sibling);
Ole Troan298c6952018-03-08 12:30:43 +0100425 pool_put (sixrd_adj_delegate_pool, sixrd_ad);
426}
427
428static u8 *
429sixrd_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
439static void
440sixrd_fib_node_last_lock_gone (fib_node_t * node)
441{
442 /* top of the dependency tree, locks not managed here. */
443}
444
445static sixrd_adj_delegate_t *
446sixrd_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
453static fib_node_back_walk_rc_t
454sixrd_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 */
468static fib_node_t *
469sixrd_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 */
481const 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 */
489const 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
495static clib_error_t *
496sixrd_init (vlib_main_t * vm)
497{
498 clib_error_t *error = 0;
499
500 /* Make sure the IPIP tunnel subsystem is initialised */
Neale Ranns756cd942018-04-06 09:18:11 -0700501 error = vlib_call_init_function (vm, ipip_init);
Ole Troan298c6952018-03-08 12:30:43 +0100502
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
510VLIB_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 */