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