Line data Source code
1 : /*
2 : * ipip.c: ipip
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 aipiped 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 : #include <stddef.h>
19 : #include <vnet/adj/adj_midchain.h>
20 : #include <vnet/ipip/ipip.h>
21 : #include <vnet/vnet.h>
22 : #include <vnet/adj/adj_nbr.h>
23 : #include <vnet/adj/adj_midchain.h>
24 : #include <vnet/fib/ip4_fib.h>
25 : #include <vnet/fib/ip6_fib.h>
26 : #include <vnet/ip/format.h>
27 : #include <vnet/ipip/ipip.h>
28 : #include <vnet/teib/teib.h>
29 : #include <vnet/tunnel/tunnel_dp.h>
30 :
31 : ipip_main_t ipip_main;
32 :
33 : /* Packet trace structure */
34 : typedef struct
35 : {
36 : u32 tunnel_id;
37 : u32 length;
38 : ip46_address_t src;
39 : ip46_address_t dst;
40 : } ipip_tx_trace_t;
41 :
42 : u8 *
43 0 : format_ipip_tx_trace (u8 * s, va_list * args)
44 : {
45 0 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
46 0 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
47 0 : ipip_tx_trace_t *t = va_arg (*args, ipip_tx_trace_t *);
48 :
49 : s =
50 0 : format (s, "IPIP: tunnel %d len %d src %U dst %U", t->tunnel_id,
51 : t->length, format_ip46_address, &t->src, IP46_TYPE_ANY,
52 : format_ip46_address, &t->dst, IP46_TYPE_ANY);
53 0 : return s;
54 : }
55 :
56 : static u8 *
57 210 : ipip_build_rewrite (vnet_main_t * vnm, u32 sw_if_index,
58 : vnet_link_t link_type, const void *dst_address)
59 : {
60 : const ip46_address_t *dst;
61 : ip4_header_t *ip4;
62 : ip6_header_t *ip6;
63 210 : u8 *rewrite = NULL;
64 : ipip_tunnel_t *t;
65 :
66 210 : dst = dst_address;
67 210 : t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
68 :
69 210 : if (!t)
70 : /* not one of ours */
71 0 : return (0);
72 :
73 210 : switch (t->transport)
74 : {
75 120 : case IPIP_TRANSPORT_IP4:
76 120 : vec_validate (rewrite, sizeof (*ip4) - 1);
77 120 : ip4 = (ip4_header_t *) rewrite;
78 120 : ip4->ip_version_and_header_length = 0x45;
79 120 : ip4->ttl = 64;
80 : /* fixup ip4 header length, protocol and checksum after-the-fact */
81 120 : ip4->src_address.as_u32 = t->tunnel_src.ip4.as_u32;
82 120 : ip4->dst_address.as_u32 = dst->ip4.as_u32;
83 120 : if (!(t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP))
84 116 : ip4_header_set_dscp (ip4, t->dscp);
85 120 : if (t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_SET_DF)
86 2 : ip4_header_set_df (ip4);
87 :
88 120 : switch (link_type)
89 : {
90 53 : case VNET_LINK_IP6:
91 53 : ip4->protocol = IP_PROTOCOL_IPV6;
92 53 : break;
93 66 : case VNET_LINK_IP4:
94 66 : ip4->protocol = IP_PROTOCOL_IP_IN_IP;
95 66 : break;
96 1 : case VNET_LINK_MPLS:
97 1 : ip4->protocol = IP_PROTOCOL_MPLS_IN_IP;
98 1 : break;
99 0 : default:
100 0 : break;
101 : }
102 120 : ip4->checksum = ip4_header_checksum (ip4);
103 120 : break;
104 :
105 90 : case IPIP_TRANSPORT_IP6:
106 90 : vec_validate (rewrite, sizeof (*ip6) - 1);
107 90 : ip6 = (ip6_header_t *) rewrite;
108 90 : ip6->ip_version_traffic_class_and_flow_label =
109 90 : clib_host_to_net_u32 (6 << 28);
110 90 : ip6->hop_limit = 64;
111 : /* fixup ip6 header length and protocol after-the-fact */
112 90 : ip6->src_address.as_u64[0] = t->tunnel_src.ip6.as_u64[0];
113 90 : ip6->src_address.as_u64[1] = t->tunnel_src.ip6.as_u64[1];
114 90 : ip6->dst_address.as_u64[0] = dst->ip6.as_u64[0];
115 90 : ip6->dst_address.as_u64[1] = dst->ip6.as_u64[1];
116 90 : if (!(t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP))
117 86 : ip6_set_dscp_network_order (ip6, t->dscp);
118 :
119 90 : switch (link_type)
120 : {
121 46 : case VNET_LINK_IP6:
122 46 : ip6->protocol = IP_PROTOCOL_IPV6;
123 46 : break;
124 43 : case VNET_LINK_IP4:
125 43 : ip6->protocol = IP_PROTOCOL_IP_IN_IP;
126 43 : break;
127 1 : case VNET_LINK_MPLS:
128 1 : ip6->protocol = IP_PROTOCOL_MPLS_IN_IP;
129 1 : break;
130 0 : default:
131 0 : break;
132 : }
133 90 : break;
134 : }
135 210 : return (rewrite);
136 : }
137 :
138 : static void
139 1444 : ipip64_fixup (vlib_main_t * vm, const ip_adjacency_t * adj, vlib_buffer_t * b,
140 : const void *data)
141 : {
142 : tunnel_encap_decap_flags_t flags;
143 : ip4_header_t *ip4;
144 :
145 1444 : flags = pointer_to_uword (data);
146 :
147 1444 : ip4 = vlib_buffer_get_current (b);
148 1444 : ip4->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
149 1444 : tunnel_encap_fixup_6o4 (flags, ((ip6_header_t *) (ip4 + 1)), ip4);
150 :
151 1444 : ip4->checksum = ip4_header_checksum (ip4);
152 1444 : }
153 :
154 : static void
155 1908 : ipip44_fixup (vlib_main_t * vm, const ip_adjacency_t * adj, vlib_buffer_t * b,
156 : const void *data)
157 : {
158 : tunnel_encap_decap_flags_t flags;
159 : ip4_header_t *ip4;
160 :
161 1908 : flags = pointer_to_uword (data);
162 :
163 1908 : ip4 = vlib_buffer_get_current (b);
164 1908 : ip4->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
165 1908 : tunnel_encap_fixup_4o4 (flags, ip4 + 1, ip4);
166 :
167 1908 : ip4->checksum = ip4_header_checksum (ip4);
168 1908 : }
169 :
170 : static void
171 1455 : ipip46_fixup (vlib_main_t * vm, const ip_adjacency_t * adj, vlib_buffer_t * b,
172 : const void *data)
173 : {
174 : tunnel_encap_decap_flags_t flags;
175 : ip6_header_t *ip6;
176 :
177 1455 : flags = pointer_to_uword (data);
178 :
179 : /* Must set locally originated otherwise we're not allowed to
180 : fragment the packet later */
181 1455 : b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
182 :
183 1455 : ip6 = vlib_buffer_get_current (b);
184 1455 : ip6->payload_length =
185 1455 : clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b) -
186 : sizeof (*ip6));
187 1455 : tunnel_encap_fixup_4o6 (flags, b, ((ip4_header_t *) (ip6 + 1)), ip6);
188 1455 : }
189 :
190 : static void
191 4514 : ipip66_fixup (vlib_main_t * vm,
192 : const ip_adjacency_t * adj, vlib_buffer_t * b, const void *data)
193 : {
194 : tunnel_encap_decap_flags_t flags;
195 : ip6_header_t *ip6;
196 :
197 4514 : flags = pointer_to_uword (data);
198 :
199 : /* Must set locally originated otherwise we're not allowed to
200 : fragment the packet later */
201 4514 : b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
202 :
203 4514 : ip6 = vlib_buffer_get_current (b);
204 4514 : ip6->payload_length =
205 4514 : clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b) -
206 : sizeof (*ip6));
207 4514 : tunnel_encap_fixup_6o6 (flags, ip6 + 1, ip6);
208 4514 : }
209 :
210 : static void
211 63 : ipipm6_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b,
212 : const void *data)
213 : {
214 : tunnel_encap_decap_flags_t flags;
215 : ip6_header_t *ip6;
216 :
217 63 : flags = pointer_to_uword (data);
218 :
219 : /* Must set locally originated otherwise we're not allowed to
220 : fragment the packet later and we'll get an unwanted hop-limt
221 : decrement */
222 63 : b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
223 :
224 63 : ip6 = vlib_buffer_get_current (b);
225 63 : ip6->payload_length =
226 63 : clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b) - sizeof (*ip6));
227 63 : tunnel_encap_fixup_mplso6 (flags, b, (mpls_unicast_header_t *) (ip6 + 1),
228 : ip6);
229 63 : }
230 :
231 : static void
232 63 : ipipm4_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b,
233 : const void *data)
234 : {
235 : tunnel_encap_decap_flags_t flags;
236 : ip4_header_t *ip4;
237 :
238 63 : flags = pointer_to_uword (data);
239 :
240 : /* Must set locally originated otherwise we'll do a TTL decrement
241 : * during ip4-rewrite */
242 63 : b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
243 :
244 63 : ip4 = vlib_buffer_get_current (b);
245 63 : ip4->length =
246 63 : clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b) - sizeof (*ip4));
247 63 : tunnel_encap_fixup_mplso4 (flags, (mpls_unicast_header_t *) (ip4 + 1), ip4);
248 63 : ip4->checksum = ip4_header_checksum (ip4);
249 63 : }
250 :
251 : static void
252 365 : ipip_tunnel_stack (adj_index_t ai)
253 : {
254 : ip_adjacency_t *adj;
255 : ipip_tunnel_t *t;
256 : u32 sw_if_index;
257 :
258 365 : adj = adj_get (ai);
259 365 : sw_if_index = adj->rewrite_header.sw_if_index;
260 :
261 365 : t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
262 365 : if (!t)
263 0 : return;
264 :
265 365 : if ((vnet_hw_interface_get_flags (vnet_get_main (), t->hw_if_index) &
266 : VNET_HW_INTERFACE_FLAG_LINK_UP) == 0)
267 : {
268 165 : adj_midchain_delegate_unstack (ai);
269 : }
270 : else
271 : {
272 : /* *INDENT-OFF* */
273 200 : fib_prefix_t dst = {
274 200 : .fp_len = t->transport == IPIP_TRANSPORT_IP6 ? 128 : 32,
275 200 : .fp_proto = (t->transport == IPIP_TRANSPORT_IP6 ?
276 200 : FIB_PROTOCOL_IP6 :
277 : FIB_PROTOCOL_IP4),
278 : .fp_addr = t->tunnel_dst
279 : };
280 : /* *INDENT-ON* */
281 :
282 200 : adj_midchain_delegate_stack (ai, t->fib_index, &dst);
283 : }
284 : }
285 :
286 : static adj_walk_rc_t
287 167 : ipip_adj_walk_cb (adj_index_t ai, void *ctx)
288 : {
289 167 : ipip_tunnel_stack (ai);
290 :
291 167 : return (ADJ_WALK_RC_CONTINUE);
292 : }
293 :
294 : static void
295 206 : ipip_tunnel_restack (ipip_tunnel_t * gt)
296 : {
297 : fib_protocol_t proto;
298 :
299 : /*
300 : * walk all the adjacencies on th IPIP interface and restack them
301 : */
302 618 : FOR_EACH_FIB_IP_PROTOCOL (proto)
303 : {
304 412 : adj_nbr_walk (gt->sw_if_index, proto, ipip_adj_walk_cb, NULL);
305 : }
306 206 : }
307 :
308 : static adj_midchain_fixup_t
309 225 : ipip_get_fixup (const ipip_tunnel_t * t, vnet_link_t lt, adj_flags_t * aflags)
310 : {
311 225 : if (t->transport == IPIP_TRANSPORT_IP6 && lt == VNET_LINK_IP6)
312 46 : return (ipip66_fixup);
313 179 : if (t->transport == IPIP_TRANSPORT_IP6 && lt == VNET_LINK_IP4)
314 43 : return (ipip46_fixup);
315 136 : if (t->transport == IPIP_TRANSPORT_IP6 && lt == VNET_LINK_MPLS)
316 1 : return (ipipm6_fixup);
317 135 : if (t->transport == IPIP_TRANSPORT_IP4 && lt == VNET_LINK_IP6)
318 53 : return (ipip64_fixup);
319 82 : if (t->transport == IPIP_TRANSPORT_IP4 && lt == VNET_LINK_MPLS)
320 1 : return (ipipm4_fixup);
321 81 : if (t->transport == IPIP_TRANSPORT_IP4 && lt == VNET_LINK_IP4)
322 : {
323 81 : *aflags = *aflags | ADJ_FLAG_MIDCHAIN_FIXUP_IP4O4_HDR;
324 81 : return (ipip44_fixup);
325 : }
326 :
327 0 : ASSERT (0);
328 0 : return (ipip44_fixup);
329 : }
330 :
331 : void
332 198 : ipip_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
333 : {
334 : adj_midchain_fixup_t fixup;
335 : ipip_tunnel_t *t;
336 : adj_flags_t af;
337 :
338 198 : af = ADJ_FLAG_NONE;
339 198 : t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
340 198 : if (!t)
341 0 : return;
342 :
343 : /*
344 : * the user has not requested that the load-balancing be based on
345 : * a flow hash of the inner packet. so use the stacking to choose
346 : * a path.
347 : */
348 198 : if (!(t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_INNER_HASH))
349 198 : af |= ADJ_FLAG_MIDCHAIN_IP_STACK;
350 :
351 198 : fixup = ipip_get_fixup (t, adj_get_link_type (ai), &af);
352 198 : adj_nbr_midchain_update_rewrite
353 : (ai, fixup,
354 198 : uword_to_pointer (t->flags, void *), af,
355 : ipip_build_rewrite (vnm, sw_if_index,
356 198 : adj_get_link_type (ai), &t->tunnel_dst));
357 198 : ipip_tunnel_stack (ai);
358 : }
359 :
360 : typedef struct mipip_walk_ctx_t_
361 : {
362 : const ipip_tunnel_t *t;
363 : const teib_entry_t *ne;
364 : } mipip_walk_ctx_t;
365 :
366 : static adj_walk_rc_t
367 12 : mipip_mk_complete_walk (adj_index_t ai, void *data)
368 : {
369 : adj_midchain_fixup_t fixup;
370 12 : mipip_walk_ctx_t *ctx = data;
371 : adj_flags_t af;
372 :
373 12 : af = ADJ_FLAG_NONE;
374 12 : fixup = ipip_get_fixup (ctx->t, adj_get_link_type (ai), &af);
375 :
376 : /*
377 : * the user has not requested that the load-balancing be based on
378 : * a flow hash of the inner packet. so use the stacking to choose
379 : * a path.
380 : */
381 12 : if (!(ctx->t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_INNER_HASH))
382 12 : af |= ADJ_FLAG_MIDCHAIN_IP_STACK;
383 :
384 12 : adj_nbr_midchain_update_rewrite
385 : (ai, fixup,
386 12 : uword_to_pointer (ctx->t->flags, void *),
387 : af, ipip_build_rewrite (vnet_get_main (),
388 12 : ctx->t->sw_if_index,
389 12 : adj_get_link_type (ai),
390 12 : &teib_entry_get_nh (ctx->ne)->fp_addr));
391 :
392 12 : teib_entry_adj_stack (ctx->ne, ai);
393 :
394 12 : return (ADJ_WALK_RC_CONTINUE);
395 : }
396 :
397 : static adj_walk_rc_t
398 9 : mipip_mk_incomplete_walk (adj_index_t ai, void *data)
399 : {
400 : adj_midchain_fixup_t fixup;
401 9 : ipip_tunnel_t *t = data;
402 : adj_flags_t af;
403 :
404 9 : af = ADJ_FLAG_NONE;
405 9 : fixup = ipip_get_fixup (t, adj_get_link_type (ai), &af);
406 :
407 9 : adj_nbr_midchain_update_rewrite (ai, fixup, NULL, ADJ_FLAG_NONE, NULL);
408 :
409 9 : adj_midchain_delegate_unstack (ai);
410 :
411 9 : return (ADJ_WALK_RC_CONTINUE);
412 : }
413 :
414 : void
415 6 : mipip_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
416 : {
417 6 : ipip_main_t *gm = &ipip_main;
418 : adj_midchain_fixup_t fixup;
419 : ip_adjacency_t *adj;
420 : teib_entry_t *ne;
421 : ipip_tunnel_t *t;
422 : adj_flags_t af;
423 : u32 ti;
424 :
425 6 : af = ADJ_FLAG_NONE;
426 6 : adj = adj_get (ai);
427 6 : ti = gm->tunnel_index_by_sw_if_index[sw_if_index];
428 6 : t = pool_elt_at_index (gm->tunnels, ti);
429 :
430 6 : ne = teib_entry_find_46 (sw_if_index,
431 6 : adj->ia_nh_proto, &adj->sub_type.nbr.next_hop);
432 :
433 6 : if (NULL == ne)
434 : {
435 : // no TEIB entry to provide the next-hop
436 6 : fixup = ipip_get_fixup (t, adj_get_link_type (ai), &af);
437 6 : adj_nbr_midchain_update_rewrite
438 6 : (ai, fixup, uword_to_pointer (t->flags, void *), ADJ_FLAG_NONE, NULL);
439 6 : return;
440 : }
441 :
442 0 : mipip_walk_ctx_t ctx = {
443 : .t = t,
444 : .ne = ne
445 : };
446 0 : adj_nbr_walk_nh (sw_if_index,
447 0 : adj->ia_nh_proto,
448 0 : &adj->sub_type.nbr.next_hop, mipip_mk_complete_walk, &ctx);
449 : }
450 :
451 : static u8 *
452 285 : format_ipip_tunnel_name (u8 * s, va_list * args)
453 : {
454 285 : u32 dev_instance = va_arg (*args, u32);
455 285 : ipip_main_t *gm = &ipip_main;
456 : ipip_tunnel_t *t;
457 :
458 285 : if (dev_instance >= vec_len (gm->tunnels))
459 0 : return format (s, "<improperly-referenced>");
460 :
461 285 : t = pool_elt_at_index (gm->tunnels, dev_instance);
462 285 : return format (s, "ipip%d", t->user_instance);
463 : }
464 :
465 : static u8 *
466 160 : format_ipip_device (u8 * s, va_list * args)
467 : {
468 160 : u32 dev_instance = va_arg (*args, u32);
469 160 : CLIB_UNUSED (int verbose) = va_arg (*args, int);
470 :
471 160 : s = format (s, "IPIP tunnel: id %d\n", dev_instance);
472 160 : return s;
473 : }
474 :
475 : static clib_error_t *
476 206 : ipip_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
477 : {
478 : vnet_hw_interface_t *hi;
479 : ipip_tunnel_t *t;
480 :
481 206 : hi = vnet_get_hw_interface (vnm, hw_if_index);
482 :
483 206 : t = ipip_tunnel_db_find_by_sw_if_index (hi->sw_if_index);
484 206 : if (!t)
485 0 : return 0;
486 :
487 206 : if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
488 103 : vnet_hw_interface_set_flags (vnm, hw_if_index,
489 : VNET_HW_INTERFACE_FLAG_LINK_UP);
490 : else
491 103 : vnet_hw_interface_set_flags (vnm, hw_if_index, 0 /* down */ );
492 :
493 206 : ipip_tunnel_restack (t);
494 :
495 206 : return /* no error */ 0;
496 : }
497 :
498 : static int
499 103 : ipip_tunnel_desc (u32 sw_if_index,
500 : ip46_address_t * src, ip46_address_t * dst, u8 * is_l2)
501 : {
502 : ipip_tunnel_t *t;
503 :
504 103 : t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
505 103 : if (!t)
506 0 : return -1;
507 :
508 103 : *src = t->tunnel_src;
509 103 : *dst = t->tunnel_dst;
510 103 : *is_l2 = 0;
511 :
512 103 : return (0);
513 : }
514 :
515 : /* *INDENT-OFF* */
516 11199 : VNET_DEVICE_CLASS(ipip_device_class) = {
517 : .name = "IPIP tunnel device",
518 : .format_device_name = format_ipip_tunnel_name,
519 : .format_device = format_ipip_device,
520 : .format_tx_trace = format_ipip_tx_trace,
521 : .admin_up_down_function = ipip_interface_admin_up_down,
522 : .ip_tun_desc = ipip_tunnel_desc,
523 : #ifdef SOON
524 : .clear counter = 0;
525 : #endif
526 : };
527 :
528 7279 : VNET_HW_INTERFACE_CLASS(ipip_hw_interface_class) = {
529 : .name = "IPIP",
530 : //.format_header = format_ipip_header_with_length,
531 : //.unformat_header = unformat_ipip_header,
532 : .build_rewrite = ipip_build_rewrite,
533 : .update_adjacency = ipip_update_adj,
534 : .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
535 : };
536 :
537 7279 : VNET_HW_INTERFACE_CLASS(mipip_hw_interface_class) = {
538 : .name = "mIPIP",
539 : //.format_header = format_ipip_header_with_length,
540 : //.unformat_header = unformat_ipip_header,
541 : .build_rewrite = ipip_build_rewrite,
542 : .update_adjacency = mipip_update_adj,
543 : .flags = VNET_HW_INTERFACE_CLASS_FLAG_NBMA,
544 : };
545 : /* *INDENT-ON* */
546 :
547 : ipip_tunnel_t *
548 6743 : ipip_tunnel_db_find (const ipip_tunnel_key_t * key)
549 : {
550 6743 : ipip_main_t *gm = &ipip_main;
551 : uword *p;
552 :
553 6743 : p = hash_get_mem (gm->tunnel_by_key, key);
554 6743 : if (!p)
555 972 : return (NULL);
556 5771 : return (pool_elt_at_index (gm->tunnels, p[0]));
557 : }
558 :
559 : ipip_tunnel_t *
560 1351 : ipip_tunnel_db_find_by_sw_if_index (u32 sw_if_index)
561 : {
562 1351 : ipip_main_t *gm = &ipip_main;
563 1351 : if (vec_len (gm->tunnel_index_by_sw_if_index) <= sw_if_index)
564 0 : return NULL;
565 1351 : u32 ti = gm->tunnel_index_by_sw_if_index[sw_if_index];
566 1351 : if (ti == ~0)
567 0 : return NULL;
568 1351 : return pool_elt_at_index (gm->tunnels, ti);
569 : }
570 :
571 : void
572 148 : ipip_tunnel_db_add (ipip_tunnel_t * t, const ipip_tunnel_key_t * key)
573 : {
574 148 : ipip_main_t *gm = &ipip_main;
575 :
576 148 : hash_set_mem_alloc (&gm->tunnel_by_key, key, t->dev_instance);
577 148 : }
578 :
579 : void
580 148 : ipip_tunnel_db_remove (ipip_tunnel_t * t, const ipip_tunnel_key_t * key)
581 : {
582 148 : ipip_main_t *gm = &ipip_main;
583 :
584 148 : hash_unset_mem_free (&gm->tunnel_by_key, key);
585 148 : }
586 :
587 : void
588 304 : ipip_mk_key_i (ipip_transport_t transport,
589 : ipip_mode_t mode,
590 : const ip46_address_t * src,
591 : const ip46_address_t * dst,
592 : u32 fib_index, ipip_tunnel_key_t * key)
593 : {
594 304 : key->transport = transport;
595 304 : key->mode = mode;
596 304 : key->src = *src;
597 304 : key->dst = *dst;
598 304 : key->fib_index = fib_index;
599 304 : key->__pad = 0;;
600 304 : }
601 :
602 : void
603 136 : ipip_mk_key (const ipip_tunnel_t * t, ipip_tunnel_key_t * key)
604 : {
605 136 : ipip_mk_key_i (t->transport, t->mode,
606 : &t->tunnel_src, &t->tunnel_dst, t->fib_index, key);
607 136 : }
608 :
609 : static void
610 24 : ipip_teib_mk_key (const ipip_tunnel_t * t,
611 : const teib_entry_t * ne, ipip_tunnel_key_t * key)
612 : {
613 : const fib_prefix_t *nh;
614 :
615 24 : nh = teib_entry_get_nh (ne);
616 :
617 : /* construct the key using mode P2P so it can be found in the DP */
618 24 : ipip_mk_key_i (t->transport, IPIP_MODE_P2P,
619 : &t->tunnel_src, &nh->fp_addr,
620 : teib_entry_get_fib_index (ne), key);
621 24 : }
622 :
623 : static void
624 85 : ipip_teib_entry_added (const teib_entry_t * ne)
625 : {
626 85 : ipip_main_t *gm = &ipip_main;
627 : const ip_address_t *nh;
628 : ipip_tunnel_key_t key;
629 : ipip_tunnel_t *t;
630 : u32 sw_if_index;
631 : u32 t_idx;
632 :
633 85 : sw_if_index = teib_entry_get_sw_if_index (ne);
634 85 : if (vec_len (gm->tunnel_index_by_sw_if_index) < sw_if_index)
635 73 : return;
636 :
637 12 : t_idx = gm->tunnel_index_by_sw_if_index[sw_if_index];
638 :
639 12 : if (INDEX_INVALID == t_idx)
640 0 : return;
641 :
642 12 : t = pool_elt_at_index (gm->tunnels, t_idx);
643 :
644 12 : ipip_teib_mk_key (t, ne, &key);
645 12 : ipip_tunnel_db_add (t, &key);
646 :
647 : // update the rewrites for each of the adjacencies for this next-hop
648 12 : mipip_walk_ctx_t ctx = {
649 : .t = t,
650 : .ne = ne
651 : };
652 12 : nh = teib_entry_get_peer (ne);
653 12 : adj_nbr_walk_nh (teib_entry_get_sw_if_index (ne),
654 12 : (AF_IP4 == ip_addr_version (nh) ?
655 : FIB_PROTOCOL_IP4 :
656 : FIB_PROTOCOL_IP6),
657 : &ip_addr_46 (nh), mipip_mk_complete_walk, &ctx);
658 : }
659 :
660 : static void
661 85 : ipip_teib_entry_deleted (const teib_entry_t * ne)
662 : {
663 85 : ipip_main_t *gm = &ipip_main;
664 : const ip_address_t *nh;
665 : ipip_tunnel_key_t key;
666 : ipip_tunnel_t *t;
667 : u32 sw_if_index;
668 : u32 t_idx;
669 :
670 85 : sw_if_index = teib_entry_get_sw_if_index (ne);
671 85 : if (vec_len (gm->tunnel_index_by_sw_if_index) < sw_if_index)
672 73 : return;
673 :
674 12 : t_idx = gm->tunnel_index_by_sw_if_index[sw_if_index];
675 :
676 12 : if (INDEX_INVALID == t_idx)
677 0 : return;
678 :
679 12 : t = pool_elt_at_index (gm->tunnels, t_idx);
680 :
681 12 : ipip_teib_mk_key (t, ne, &key);
682 12 : ipip_tunnel_db_remove (t, &key);
683 :
684 12 : nh = teib_entry_get_peer (ne);
685 :
686 : /* make all the adjacencies incomplete */
687 12 : adj_nbr_walk_nh (teib_entry_get_sw_if_index (ne),
688 12 : (AF_IP4 == ip_addr_version (nh) ?
689 : FIB_PROTOCOL_IP4 :
690 : FIB_PROTOCOL_IP6),
691 : &ip_addr_46 (nh), mipip_mk_incomplete_walk, t);
692 : }
693 :
694 : static walk_rc_t
695 0 : ipip_tunnel_delete_teib_walk (index_t nei, void *ctx)
696 : {
697 0 : ipip_tunnel_t *t = ctx;
698 : ipip_tunnel_key_t key;
699 :
700 0 : ipip_teib_mk_key (t, teib_entry_get (nei), &key);
701 0 : ipip_tunnel_db_remove (t, &key);
702 :
703 0 : return (WALK_CONTINUE);
704 : }
705 :
706 : static walk_rc_t
707 0 : ipip_tunnel_add_teib_walk (index_t nei, void *ctx)
708 : {
709 0 : ipip_tunnel_t *t = ctx;
710 : ipip_tunnel_key_t key;
711 :
712 0 : ipip_teib_mk_key (t, teib_entry_get (nei), &key);
713 0 : ipip_tunnel_db_add (t, &key);
714 :
715 0 : return (WALK_CONTINUE);
716 : }
717 :
718 : int
719 133 : ipip_add_tunnel (ipip_transport_t transport,
720 : u32 instance, ip46_address_t * src, ip46_address_t * dst,
721 : u32 fib_index, tunnel_encap_decap_flags_t flags,
722 : ip_dscp_t dscp, tunnel_mode_t tmode, u32 * sw_if_indexp)
723 : {
724 133 : ipip_main_t *gm = &ipip_main;
725 133 : vnet_main_t *vnm = gm->vnet_main;
726 : ipip_tunnel_t *t;
727 : vnet_hw_interface_t *hi;
728 : u32 hw_if_index, sw_if_index;
729 : ipip_tunnel_key_t key;
730 : ipip_mode_t mode;
731 :
732 133 : if (tmode == TUNNEL_MODE_MP && !ip46_address_is_zero (dst))
733 0 : return (VNET_API_ERROR_INVALID_DST_ADDRESS);
734 :
735 133 : mode = (tmode == TUNNEL_MODE_P2P ? IPIP_MODE_P2P : IPIP_MODE_P2MP);
736 133 : ipip_mk_key_i (transport, mode, src, dst, fib_index, &key);
737 :
738 133 : t = ipip_tunnel_db_find (&key);
739 133 : if (t)
740 : {
741 8 : if (sw_if_indexp)
742 8 : sw_if_indexp[0] = t->sw_if_index;
743 8 : return VNET_API_ERROR_IF_ALREADY_EXISTS;
744 : }
745 :
746 125 : pool_get_aligned (gm->tunnels, t, CLIB_CACHE_LINE_BYTES);
747 125 : clib_memset (t, 0, sizeof (*t));
748 :
749 : /* Reconcile the real dev_instance and a possible requested instance */
750 125 : u32 t_idx = t - gm->tunnels; /* tunnel index (or instance) */
751 125 : u32 u_idx = instance; /* user specified instance */
752 125 : if (u_idx == ~0)
753 125 : u_idx = t_idx;
754 125 : if (hash_get (gm->instance_used, u_idx))
755 : {
756 0 : pool_put (gm->tunnels, t);
757 0 : return VNET_API_ERROR_INSTANCE_IN_USE;
758 : }
759 125 : hash_set (gm->instance_used, u_idx, 1);
760 :
761 125 : t->dev_instance = t_idx; /* actual */
762 125 : t->user_instance = u_idx; /* name */
763 :
764 125 : hw_if_index = vnet_register_interface (vnm, ipip_device_class.index, t_idx,
765 : (mode == IPIP_MODE_P2P ?
766 : ipip_hw_interface_class.index :
767 : mipip_hw_interface_class.index),
768 : t_idx);
769 :
770 125 : hi = vnet_get_hw_interface (vnm, hw_if_index);
771 125 : sw_if_index = hi->sw_if_index;
772 :
773 125 : t->mode = mode;
774 125 : t->hw_if_index = hw_if_index;
775 125 : t->fib_index = fib_index;
776 125 : t->sw_if_index = sw_if_index;
777 125 : t->dscp = dscp;
778 125 : t->flags = flags;
779 125 : t->transport = transport;
780 :
781 363 : vec_validate_init_empty (gm->tunnel_index_by_sw_if_index, sw_if_index, ~0);
782 125 : gm->tunnel_index_by_sw_if_index[sw_if_index] = t_idx;
783 :
784 125 : if (t->transport == IPIP_TRANSPORT_IP4)
785 79 : hi->frame_overhead = sizeof (ip4_header_t);
786 : else
787 46 : hi->frame_overhead = sizeof (ip6_header_t);
788 :
789 125 : hi->min_frame_size = hi->frame_overhead + 64;
790 :
791 : /* Standard default ipip MTU. */
792 125 : vnet_sw_interface_set_mtu (vnm, sw_if_index, 9000);
793 125 : vnet_set_interface_l3_output_node (gm->vlib_main, sw_if_index,
794 : (u8 *) "tunnel-output");
795 :
796 125 : t->tunnel_src = *src;
797 125 : t->tunnel_dst = *dst;
798 :
799 125 : ipip_tunnel_db_add (t, &key);
800 :
801 125 : if (t->mode == IPIP_MODE_P2MP)
802 2 : teib_walk_itf (t->sw_if_index, ipip_tunnel_add_teib_walk, t);
803 :
804 125 : if (sw_if_indexp)
805 125 : *sw_if_indexp = sw_if_index;
806 :
807 125 : if (t->transport == IPIP_TRANSPORT_IP6 && !gm->ip6_protocol_registered)
808 : {
809 13 : ip6_register_protocol (IP_PROTOCOL_IP_IN_IP, ipip6_input_node.index);
810 13 : ip6_register_protocol (IP_PROTOCOL_MPLS_IN_IP, ipip6_input_node.index);
811 13 : ip6_register_protocol (IP_PROTOCOL_IPV6, ipip6_input_node.index);
812 13 : gm->ip6_protocol_registered = true;
813 : }
814 112 : else if (t->transport == IPIP_TRANSPORT_IP4 && !gm->ip4_protocol_registered)
815 : {
816 37 : ip4_register_protocol (IP_PROTOCOL_IP_IN_IP, ipip4_input_node.index);
817 37 : ip4_register_protocol (IP_PROTOCOL_MPLS_IN_IP, ipip4_input_node.index);
818 37 : ip4_register_protocol (IP_PROTOCOL_IPV6, ipip4_input_node.index);
819 37 : gm->ip4_protocol_registered = true;
820 : }
821 125 : return 0;
822 : }
823 :
824 : int
825 125 : ipip_del_tunnel (u32 sw_if_index)
826 : {
827 125 : ipip_main_t *gm = &ipip_main;
828 125 : vnet_main_t *vnm = gm->vnet_main;
829 : ipip_tunnel_t *t;
830 : ipip_tunnel_key_t key;
831 :
832 125 : t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
833 125 : if (t == NULL)
834 0 : return VNET_API_ERROR_NO_SUCH_ENTRY;
835 :
836 125 : if (t->mode == IPIP_MODE_P2MP)
837 2 : teib_walk_itf (t->sw_if_index, ipip_tunnel_delete_teib_walk, t);
838 :
839 125 : vnet_sw_interface_set_flags (vnm, sw_if_index, 0 /* down */ );
840 125 : vnet_reset_interface_l3_output_node (gm->vlib_main, t->sw_if_index);
841 125 : gm->tunnel_index_by_sw_if_index[sw_if_index] = ~0;
842 125 : vnet_delete_hw_interface (vnm, t->hw_if_index);
843 125 : hash_unset (gm->instance_used, t->user_instance);
844 :
845 125 : ipip_mk_key (t, &key);
846 125 : ipip_tunnel_db_remove (t, &key);
847 125 : pool_put (gm->tunnels, t);
848 :
849 125 : return 0;
850 : }
851 :
852 : const static teib_vft_t ipip_teib_vft = {
853 : .nv_added = ipip_teib_entry_added,
854 : .nv_deleted = ipip_teib_entry_deleted,
855 : };
856 :
857 : static clib_error_t *
858 559 : ipip_init (vlib_main_t * vm)
859 : {
860 559 : ipip_main_t *gm = &ipip_main;
861 :
862 559 : clib_memset (gm, 0, sizeof (gm[0]));
863 559 : gm->vlib_main = vm;
864 559 : gm->vnet_main = vnet_get_main ();
865 559 : gm->tunnel_by_key =
866 559 : hash_create_mem (0, sizeof (ipip_tunnel_key_t), sizeof (uword));
867 :
868 559 : teib_register (&ipip_teib_vft);
869 :
870 559 : return 0;
871 : }
872 :
873 61039 : VLIB_INIT_FUNCTION (ipip_init);
874 :
875 : /*
876 : * fd.io coding-style-patch-verification: ON
877 : *
878 : * Local Variables:
879 : * eval: (c-set-style "gnu")
880 : * End:
881 : */
|