a15717475f85aa38507ce35b1ce20d26705b514e
[vpp.git] / src / plugins / gre / gre.c
1 /*
2  * gre.c: gre
3  *
4  * Copyright (c) 2012 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 #include <vnet/vnet.h>
19 #include <gre/gre.h>
20 #include <vnet/adj/adj_midchain.h>
21 #include <vnet/tunnel/tunnel_dp.h>
22 #include <vpp/app/version.h>
23 #include <vnet/plugin/plugin.h>
24
25 extern gre_main_t gre_main;
26
27 #ifndef CLIB_MARCH_VARIANT
28 gre_main_t gre_main;
29
30 typedef struct
31 {
32   union
33   {
34     ip4_and_gre_header_t ip4_and_gre;
35     u64 as_u64[3];
36   };
37 } ip4_and_gre_union_t;
38
39 typedef struct
40 {
41   union
42   {
43     ip6_and_gre_header_t ip6_and_gre;
44     u64 as_u64[3];
45   };
46 } ip6_and_gre_union_t;
47 #endif /* CLIB_MARCH_VARIANT */
48
49 /* Packet trace structure */
50 typedef struct
51 {
52   /* Tunnel-id / index in tunnel vector */
53   u32 tunnel_id;
54
55   /* pkt length */
56   u32 length;
57
58   /* tunnel ip addresses */
59   ip46_address_t src;
60   ip46_address_t dst;
61 } gre_tx_trace_t;
62
63 extern u8 *format_gre_tx_trace (u8 *s, va_list *args);
64
65 #ifndef CLIB_MARCH_VARIANT
66 u8 *
67 format_gre_tx_trace (u8 *s, va_list *args)
68 {
69   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
70   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
71   gre_tx_trace_t *t = va_arg (*args, gre_tx_trace_t *);
72
73   s = format (s, "GRE: tunnel %d len %d src %U dst %U", t->tunnel_id,
74               t->length, format_ip46_address, &t->src, IP46_TYPE_ANY,
75               format_ip46_address, &t->dst, IP46_TYPE_ANY);
76   return s;
77 }
78
79 u8 *
80 format_gre_protocol (u8 *s, va_list *args)
81 {
82   gre_protocol_t p = va_arg (*args, u32);
83   gre_main_t *gm = &gre_main;
84   gre_protocol_info_t *pi = gre_get_protocol_info (gm, p);
85
86   if (pi)
87     s = format (s, "%s", pi->name);
88   else
89     s = format (s, "0x%04x", p);
90
91   return s;
92 }
93
94 u8 *
95 format_gre_header_with_length (u8 *s, va_list *args)
96 {
97   gre_main_t *gm = &gre_main;
98   gre_header_t *h = va_arg (*args, gre_header_t *);
99   u32 max_header_bytes = va_arg (*args, u32);
100   gre_protocol_t p = clib_net_to_host_u16 (h->protocol);
101   u32 indent, header_bytes;
102
103   header_bytes = sizeof (h[0]);
104   if (max_header_bytes != 0 && header_bytes > max_header_bytes)
105     return format (s, "gre header truncated");
106
107   indent = format_get_indent (s);
108
109   s = format (s, "GRE %U", format_gre_protocol, p);
110
111   if (max_header_bytes != 0 && header_bytes < max_header_bytes)
112     {
113       gre_protocol_info_t *pi = gre_get_protocol_info (gm, p);
114       vlib_node_t *node = vlib_get_node (gm->vlib_main, pi->node_index);
115       if (node->format_buffer)
116         s =
117           format (s, "\n%U%U", format_white_space, indent, node->format_buffer,
118                   (void *) (h + 1), max_header_bytes - header_bytes);
119     }
120
121   return s;
122 }
123
124 u8 *
125 format_gre_header (u8 *s, va_list *args)
126 {
127   gre_header_t *h = va_arg (*args, gre_header_t *);
128   return format (s, "%U", format_gre_header_with_length, h, 0);
129 }
130
131 /* Returns gre protocol as an int in host byte order. */
132 uword
133 unformat_gre_protocol_host_byte_order (unformat_input_t *input, va_list *args)
134 {
135   u16 *result = va_arg (*args, u16 *);
136   gre_main_t *gm = &gre_main;
137   int i;
138
139   /* Named type. */
140   if (unformat_user (input, unformat_vlib_number_by_name,
141                      gm->protocol_info_by_name, &i))
142     {
143       gre_protocol_info_t *pi = vec_elt_at_index (gm->protocol_infos, i);
144       *result = pi->protocol;
145       return 1;
146     }
147
148   return 0;
149 }
150
151 uword
152 unformat_gre_protocol_net_byte_order (unformat_input_t *input, va_list *args)
153 {
154   u16 *result = va_arg (*args, u16 *);
155   if (!unformat_user (input, unformat_gre_protocol_host_byte_order, result))
156     return 0;
157   *result = clib_host_to_net_u16 ((u16) *result);
158   return 1;
159 }
160
161 uword
162 unformat_gre_header (unformat_input_t *input, va_list *args)
163 {
164   u8 **result = va_arg (*args, u8 **);
165   gre_header_t _h, *h = &_h;
166   u16 p;
167
168   if (!unformat (input, "%U", unformat_gre_protocol_host_byte_order, &p))
169     return 0;
170
171   h->protocol = clib_host_to_net_u16 (p);
172
173   /* Add header to result. */
174   {
175     void *p;
176     u32 n_bytes = sizeof (h[0]);
177
178     vec_add2 (*result, p, n_bytes);
179     clib_memcpy (p, h, n_bytes);
180   }
181
182   return 1;
183 }
184
185 static int
186 gre_proto_from_vnet_link (vnet_link_t link)
187 {
188   switch (link)
189     {
190     case VNET_LINK_IP4:
191       return (GRE_PROTOCOL_ip4);
192     case VNET_LINK_IP6:
193       return (GRE_PROTOCOL_ip6);
194     case VNET_LINK_MPLS:
195       return (GRE_PROTOCOL_mpls_unicast);
196     case VNET_LINK_ETHERNET:
197       return (GRE_PROTOCOL_teb);
198     case VNET_LINK_ARP:
199       return (GRE_PROTOCOL_arp);
200     case VNET_LINK_NSH:
201       ASSERT (0);
202       break;
203     }
204   ASSERT (0);
205   return (GRE_PROTOCOL_ip4);
206 }
207
208 static u8 *
209 gre_build_rewrite (vnet_main_t *vnm, u32 sw_if_index, vnet_link_t link_type,
210                    const void *dst_address)
211 {
212   gre_main_t *gm = &gre_main;
213   const ip46_address_t *dst;
214   ip4_and_gre_header_t *h4;
215   ip6_and_gre_header_t *h6;
216   gre_header_t *gre;
217   u8 *rewrite = NULL;
218   gre_tunnel_t *t;
219   u32 ti;
220   u8 is_ipv6;
221
222   dst = dst_address;
223   ti = gm->tunnel_index_by_sw_if_index[sw_if_index];
224
225   if (~0 == ti)
226     /* not one of ours */
227     return (0);
228
229   t = pool_elt_at_index (gm->tunnels, ti);
230
231   is_ipv6 = t->tunnel_dst.fp_proto == FIB_PROTOCOL_IP6 ? 1 : 0;
232
233   if (!is_ipv6)
234     {
235       vec_validate (rewrite, sizeof (*h4) - 1);
236       h4 = (ip4_and_gre_header_t *) rewrite;
237       gre = &h4->gre;
238       h4->ip4.ip_version_and_header_length = 0x45;
239       h4->ip4.ttl = 254;
240       h4->ip4.protocol = IP_PROTOCOL_GRE;
241       /* fixup ip4 header length and checksum after-the-fact */
242       h4->ip4.src_address.as_u32 = t->tunnel_src.ip4.as_u32;
243       h4->ip4.dst_address.as_u32 = dst->ip4.as_u32;
244       h4->ip4.checksum = ip4_header_checksum (&h4->ip4);
245     }
246   else
247     {
248       vec_validate (rewrite, sizeof (*h6) - 1);
249       h6 = (ip6_and_gre_header_t *) rewrite;
250       gre = &h6->gre;
251       h6->ip6.ip_version_traffic_class_and_flow_label =
252         clib_host_to_net_u32 (6 << 28);
253       h6->ip6.hop_limit = 255;
254       h6->ip6.protocol = IP_PROTOCOL_GRE;
255       /* fixup ip6 header length and checksum after-the-fact */
256       h6->ip6.src_address.as_u64[0] = t->tunnel_src.ip6.as_u64[0];
257       h6->ip6.src_address.as_u64[1] = t->tunnel_src.ip6.as_u64[1];
258       h6->ip6.dst_address.as_u64[0] = dst->ip6.as_u64[0];
259       h6->ip6.dst_address.as_u64[1] = dst->ip6.as_u64[1];
260     }
261
262   if (PREDICT_FALSE (t->type == GRE_TUNNEL_TYPE_ERSPAN))
263     {
264       gre->protocol = clib_host_to_net_u16 (GRE_PROTOCOL_erspan);
265       gre->flags_and_version = clib_host_to_net_u16 (GRE_FLAGS_SEQUENCE);
266     }
267   else
268     gre->protocol =
269       clib_host_to_net_u16 (gre_proto_from_vnet_link (link_type));
270
271   return (rewrite);
272 }
273
274 static void
275 gre44_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b0,
276              const void *data)
277 {
278   tunnel_encap_decap_flags_t flags;
279   ip4_and_gre_header_t *ip0;
280
281   ip0 = vlib_buffer_get_current (b0);
282   flags = pointer_to_uword (data);
283
284   /* Fixup the checksum and len fields in the GRE tunnel encap
285    * that was applied at the midchain node */
286   ip0->ip4.length =
287     clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
288   tunnel_encap_fixup_4o4 (flags, (ip4_header_t *) (ip0 + 1), &ip0->ip4);
289   ip0->ip4.checksum = ip4_header_checksum (&ip0->ip4);
290 }
291
292 static void
293 gre64_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b0,
294              const void *data)
295 {
296   tunnel_encap_decap_flags_t flags;
297   ip4_and_gre_header_t *ip0;
298
299   ip0 = vlib_buffer_get_current (b0);
300   flags = pointer_to_uword (data);
301
302   /* Fixup the checksum and len fields in the GRE tunnel encap
303    * that was applied at the midchain node */
304   ip0->ip4.length =
305     clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
306   tunnel_encap_fixup_6o4 (flags, (ip6_header_t *) (ip0 + 1), &ip0->ip4);
307   ip0->ip4.checksum = ip4_header_checksum (&ip0->ip4);
308 }
309
310 static void
311 grex4_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b0,
312              const void *data)
313 {
314   ip4_header_t *ip0;
315
316   ip0 = vlib_buffer_get_current (b0);
317
318   /* Fixup the checksum and len fields in the GRE tunnel encap
319    * that was applied at the midchain node */
320   ip0->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
321   ip0->checksum = ip4_header_checksum (ip0);
322 }
323
324 static void
325 gre46_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b0,
326              const void *data)
327 {
328   tunnel_encap_decap_flags_t flags;
329   ip6_and_gre_header_t *ip0;
330
331   ip0 = vlib_buffer_get_current (b0);
332   flags = pointer_to_uword (data);
333
334   /* Fixup the payload length field in the GRE tunnel encap that was applied
335    * at the midchain node */
336   ip0->ip6.payload_length = clib_host_to_net_u16 (
337     vlib_buffer_length_in_chain (vm, b0) - sizeof (ip0->ip6));
338   tunnel_encap_fixup_4o6 (flags, b0, (ip4_header_t *) (ip0 + 1), &ip0->ip6);
339 }
340
341 static void
342 gre66_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b0,
343              const void *data)
344 {
345   tunnel_encap_decap_flags_t flags;
346   ip6_and_gre_header_t *ip0;
347
348   ip0 = vlib_buffer_get_current (b0);
349   flags = pointer_to_uword (data);
350
351   /* Fixup the payload length field in the GRE tunnel encap that was applied
352    * at the midchain node */
353   ip0->ip6.payload_length = clib_host_to_net_u16 (
354     vlib_buffer_length_in_chain (vm, b0) - sizeof (ip0->ip6));
355   tunnel_encap_fixup_6o6 (flags, (ip6_header_t *) (ip0 + 1), &ip0->ip6);
356 }
357
358 static void
359 grex6_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b0,
360              const void *data)
361 {
362   ip6_and_gre_header_t *ip0;
363
364   ip0 = vlib_buffer_get_current (b0);
365
366   /* Fixup the payload length field in the GRE tunnel encap that was applied
367    * at the midchain node */
368   ip0->ip6.payload_length = clib_host_to_net_u16 (
369     vlib_buffer_length_in_chain (vm, b0) - sizeof (ip0->ip6));
370 }
371
372 /**
373  * return the appropriate fixup function given the overlay (link-type) and
374  * underlay (fproto) combination
375  */
376 static adj_midchain_fixup_t
377 gre_get_fixup (fib_protocol_t fproto, vnet_link_t lt)
378 {
379   if (fproto == FIB_PROTOCOL_IP6 && lt == VNET_LINK_IP6)
380     return (gre66_fixup);
381   if (fproto == FIB_PROTOCOL_IP6 && lt == VNET_LINK_IP4)
382     return (gre46_fixup);
383   if (fproto == FIB_PROTOCOL_IP4 && lt == VNET_LINK_IP6)
384     return (gre64_fixup);
385   if (fproto == FIB_PROTOCOL_IP4 && lt == VNET_LINK_IP4)
386     return (gre44_fixup);
387   if (fproto == FIB_PROTOCOL_IP6)
388     return (grex6_fixup);
389   if (fproto == FIB_PROTOCOL_IP4)
390     return (grex4_fixup);
391
392   ASSERT (0);
393   return (gre44_fixup);
394 }
395
396 void
397 gre_update_adj (vnet_main_t *vnm, u32 sw_if_index, adj_index_t ai)
398 {
399   gre_main_t *gm = &gre_main;
400   gre_tunnel_t *t;
401   adj_flags_t af;
402   u32 ti;
403
404   ti = gm->tunnel_index_by_sw_if_index[sw_if_index];
405   t = pool_elt_at_index (gm->tunnels, ti);
406   af = ADJ_FLAG_NONE;
407
408   /*
409    * the user has not requested that the load-balancing be based on
410    * a flow hash of the inner packet. so use the stacking to choose
411    * a path.
412    */
413   if (!(t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_INNER_HASH))
414     af |= ADJ_FLAG_MIDCHAIN_IP_STACK;
415
416   adj_nbr_midchain_update_rewrite (
417     ai, gre_get_fixup (t->tunnel_dst.fp_proto, adj_get_link_type (ai)),
418     uword_to_pointer (t->flags, void *), af,
419     gre_build_rewrite (vnm, sw_if_index, adj_get_link_type (ai),
420                        &t->tunnel_dst.fp_addr));
421
422   gre_tunnel_stack (ai);
423 }
424
425 adj_walk_rc_t
426 mgre_mk_complete_walk (adj_index_t ai, void *data)
427 {
428   mgre_walk_ctx_t *ctx = data;
429   adj_flags_t af;
430
431   af = ADJ_FLAG_NONE;
432
433   /*
434    * the user has not requested that the load-balancing be based on
435    * a flow hash of the inner packet. so use the stacking to choose
436    * a path.
437    */
438   if (!(ctx->t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_INNER_HASH))
439     af |= ADJ_FLAG_MIDCHAIN_IP_STACK;
440
441   adj_nbr_midchain_update_rewrite (
442     ai, gre_get_fixup (ctx->t->tunnel_dst.fp_proto, adj_get_link_type (ai)),
443     uword_to_pointer (ctx->t->flags, void *), af,
444     gre_build_rewrite (vnet_get_main (), ctx->t->sw_if_index,
445                        adj_get_link_type (ai),
446                        &teib_entry_get_nh (ctx->ne)->fp_addr));
447
448   teib_entry_adj_stack (ctx->ne, ai);
449
450   return (ADJ_WALK_RC_CONTINUE);
451 }
452
453 adj_walk_rc_t
454 mgre_mk_incomplete_walk (adj_index_t ai, void *data)
455 {
456   gre_tunnel_t *t = data;
457
458   adj_nbr_midchain_update_rewrite (
459     ai, gre_get_fixup (t->tunnel_dst.fp_proto, adj_get_link_type (ai)), NULL,
460     ADJ_FLAG_NONE, NULL);
461
462   adj_midchain_delegate_unstack (ai);
463
464   return (ADJ_WALK_RC_CONTINUE);
465 }
466
467 void
468 mgre_update_adj (vnet_main_t *vnm, u32 sw_if_index, adj_index_t ai)
469 {
470   gre_main_t *gm = &gre_main;
471   ip_adjacency_t *adj;
472   teib_entry_t *ne;
473   gre_tunnel_t *t;
474   u32 ti;
475
476   adj = adj_get (ai);
477   ti = gm->tunnel_index_by_sw_if_index[sw_if_index];
478   t = pool_elt_at_index (gm->tunnels, ti);
479
480   ne = teib_entry_find_46 (sw_if_index, adj->ia_nh_proto,
481                            &adj->sub_type.nbr.next_hop);
482
483   if (NULL == ne)
484     {
485       // no TEIB entry to provide the next-hop
486       adj_nbr_midchain_update_rewrite (
487         ai, gre_get_fixup (t->tunnel_dst.fp_proto, adj_get_link_type (ai)),
488         uword_to_pointer (t->flags, void *), ADJ_FLAG_NONE, NULL);
489       return;
490     }
491
492   mgre_walk_ctx_t ctx = { .t = t, .ne = ne };
493   adj_nbr_walk_nh (sw_if_index, adj->ia_nh_proto, &adj->sub_type.nbr.next_hop,
494                    mgre_mk_complete_walk, &ctx);
495 }
496 #endif /* CLIB_MARCH_VARIANT */
497
498 typedef enum
499 {
500   GRE_ENCAP_NEXT_L2_MIDCHAIN,
501   GRE_ENCAP_N_NEXT,
502 } gre_encap_next_t;
503
504 /**
505  * @brief TX function. Only called for L2 payload including TEB or ERSPAN.
506  *        L3 traffic uses the adj-midchains.
507  */
508 static_always_inline u32
509 gre_encap_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
510                   vlib_frame_t *frame, gre_tunnel_type_t type)
511 {
512   gre_main_t *gm = &gre_main;
513   u32 *from, n_left_from;
514   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
515   u32 sw_if_index[2] = { ~0, ~0 };
516   const gre_tunnel_t *gt[2] = { 0 };
517   adj_index_t adj_index[2] = { ADJ_INDEX_INVALID, ADJ_INDEX_INVALID };
518
519   from = vlib_frame_vector_args (frame);
520   n_left_from = frame->n_vectors;
521   vlib_get_buffers (vm, from, bufs, n_left_from);
522
523   while (n_left_from >= 2)
524     {
525
526       if (PREDICT_FALSE (sw_if_index[0] !=
527                          vnet_buffer (b[0])->sw_if_index[VLIB_TX]))
528         {
529           const vnet_hw_interface_t *hi;
530           sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
531           hi = vnet_get_sup_hw_interface (gm->vnet_main, sw_if_index[0]);
532           gt[0] = &gm->tunnels[hi->dev_instance];
533           adj_index[0] = gt[0]->l2_adj_index;
534         }
535       if (PREDICT_FALSE (sw_if_index[1] !=
536                          vnet_buffer (b[1])->sw_if_index[VLIB_TX]))
537         {
538           const vnet_hw_interface_t *hi;
539           sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_TX];
540           hi = vnet_get_sup_hw_interface (gm->vnet_main, sw_if_index[1]);
541           gt[1] = &gm->tunnels[hi->dev_instance];
542           adj_index[1] = gt[1]->l2_adj_index;
543         }
544
545       vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = adj_index[0];
546       vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = adj_index[1];
547
548       if (type == GRE_TUNNEL_TYPE_ERSPAN)
549         {
550           /* Encap GRE seq# and ERSPAN type II header */
551           erspan_t2_t *h0;
552           u32 seq_num;
553           u64 hdr;
554           vlib_buffer_advance (b[0], -sizeof (erspan_t2_t));
555           h0 = vlib_buffer_get_current (b[0]);
556           seq_num = clib_atomic_fetch_add (&gt[0]->gre_sn->seq_num, 1);
557           hdr = clib_host_to_net_u64 (ERSPAN_HDR2);
558           h0->seq_num = clib_host_to_net_u32 (seq_num);
559           h0->t2_u64 = hdr;
560           h0->t2.cos_en_t_session |= clib_host_to_net_u16 (gt[0]->session_id);
561         }
562       if (type == GRE_TUNNEL_TYPE_ERSPAN)
563         {
564           /* Encap GRE seq# and ERSPAN type II header */
565           erspan_t2_t *h0;
566           u32 seq_num;
567           u64 hdr;
568           vlib_buffer_advance (b[1], -sizeof (erspan_t2_t));
569           h0 = vlib_buffer_get_current (b[1]);
570           seq_num = clib_atomic_fetch_add (&gt[1]->gre_sn->seq_num, 1);
571           hdr = clib_host_to_net_u64 (ERSPAN_HDR2);
572           h0->seq_num = clib_host_to_net_u32 (seq_num);
573           h0->t2_u64 = hdr;
574           h0->t2.cos_en_t_session |= clib_host_to_net_u16 (gt[1]->session_id);
575         }
576
577       if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
578         {
579           gre_tx_trace_t *tr = vlib_add_trace (vm, node, b[0], sizeof (*tr));
580           tr->tunnel_id = gt[0] - gm->tunnels;
581           tr->src = gt[0]->tunnel_src;
582           tr->dst = gt[0]->tunnel_dst.fp_addr;
583           tr->length = vlib_buffer_length_in_chain (vm, b[0]);
584         }
585       if (PREDICT_FALSE (b[1]->flags & VLIB_BUFFER_IS_TRACED))
586         {
587           gre_tx_trace_t *tr = vlib_add_trace (vm, node, b[1], sizeof (*tr));
588           tr->tunnel_id = gt[1] - gm->tunnels;
589           tr->src = gt[1]->tunnel_src;
590           tr->dst = gt[1]->tunnel_dst.fp_addr;
591           tr->length = vlib_buffer_length_in_chain (vm, b[1]);
592         }
593
594       b += 2;
595       n_left_from -= 2;
596     }
597
598   while (n_left_from >= 1)
599     {
600
601       if (PREDICT_FALSE (sw_if_index[0] !=
602                          vnet_buffer (b[0])->sw_if_index[VLIB_TX]))
603         {
604           const vnet_hw_interface_t *hi;
605           sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
606           hi = vnet_get_sup_hw_interface (gm->vnet_main, sw_if_index[0]);
607           gt[0] = &gm->tunnels[hi->dev_instance];
608           adj_index[0] = gt[0]->l2_adj_index;
609         }
610
611       vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = adj_index[0];
612
613       if (type == GRE_TUNNEL_TYPE_ERSPAN)
614         {
615           /* Encap GRE seq# and ERSPAN type II header */
616           erspan_t2_t *h0;
617           u32 seq_num;
618           u64 hdr;
619           ASSERT (gt[0]->type == GRE_TUNNEL_TYPE_ERSPAN);
620           vlib_buffer_advance (b[0], -sizeof (erspan_t2_t));
621           h0 = vlib_buffer_get_current (b[0]);
622           seq_num = clib_atomic_fetch_add (&gt[0]->gre_sn->seq_num, 1);
623           hdr = clib_host_to_net_u64 (ERSPAN_HDR2);
624           h0->seq_num = clib_host_to_net_u32 (seq_num);
625           h0->t2_u64 = hdr;
626           h0->t2.cos_en_t_session |= clib_host_to_net_u16 (gt[0]->session_id);
627         }
628
629       if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
630         {
631           gre_tx_trace_t *tr = vlib_add_trace (vm, node, b[0], sizeof (*tr));
632           tr->tunnel_id = gt[0] - gm->tunnels;
633           tr->src = gt[0]->tunnel_src;
634           tr->dst = gt[0]->tunnel_dst.fp_addr;
635           tr->length = vlib_buffer_length_in_chain (vm, b[0]);
636         }
637
638       b += 1;
639       n_left_from -= 1;
640     }
641
642   vlib_buffer_enqueue_to_single_next (
643     vm, node, from, GRE_ENCAP_NEXT_L2_MIDCHAIN, frame->n_vectors);
644
645   vlib_node_increment_counter (vm, node->node_index, GRE_ERROR_PKTS_ENCAP,
646                                frame->n_vectors);
647
648   return frame->n_vectors;
649 }
650
651 static char *gre_error_strings[] = {
652 #define gre_error(n, s) s,
653 #include "error.def"
654 #undef gre_error
655 };
656
657 VLIB_NODE_FN (gre_teb_encap_node)
658 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
659 {
660   return (gre_encap_inline (vm, node, frame, GRE_TUNNEL_TYPE_TEB));
661 }
662
663 VLIB_NODE_FN (gre_erspan_encap_node)
664 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
665 {
666   return (gre_encap_inline (vm, node, frame, GRE_TUNNEL_TYPE_ERSPAN));
667 }
668
669 /* *INDENT-OFF* */
670 VLIB_REGISTER_NODE (gre_teb_encap_node) =
671 {
672   .name = "gre-teb-encap",
673   .vector_size = sizeof (u32),
674   .format_trace = format_gre_tx_trace,
675   .type = VLIB_NODE_TYPE_INTERNAL,
676   .n_errors = GRE_N_ERROR,
677   .error_strings = gre_error_strings,
678   .n_next_nodes = GRE_ENCAP_N_NEXT,
679   .next_nodes = {
680     [GRE_ENCAP_NEXT_L2_MIDCHAIN] = "adj-l2-midchain",
681   },
682 };
683 VLIB_REGISTER_NODE (gre_erspan_encap_node) =
684 {
685   .name = "gre-erspan-encap",
686   .vector_size = sizeof (u32),
687   .format_trace = format_gre_tx_trace,
688   .type = VLIB_NODE_TYPE_INTERNAL,
689   .n_errors = GRE_N_ERROR,
690   .error_strings = gre_error_strings,
691   .n_next_nodes = GRE_ENCAP_N_NEXT,
692   .next_nodes = {
693     [GRE_ENCAP_NEXT_L2_MIDCHAIN] = "adj-l2-midchain",
694   },
695 };
696 /* *INDENT-ON* */
697
698 #ifndef CLIB_MARCH_VARIANT
699 static u8 *
700 format_gre_tunnel_name (u8 *s, va_list *args)
701 {
702   u32 dev_instance = va_arg (*args, u32);
703   gre_main_t *gm = &gre_main;
704   gre_tunnel_t *t;
705
706   if (dev_instance >= vec_len (gm->tunnels))
707     return format (s, "<improperly-referenced>");
708
709   t = pool_elt_at_index (gm->tunnels, dev_instance);
710   return format (s, "gre%d", t->user_instance);
711 }
712
713 static u8 *
714 format_gre_device (u8 *s, va_list *args)
715 {
716   u32 dev_instance = va_arg (*args, u32);
717   CLIB_UNUSED (int verbose) = va_arg (*args, int);
718
719   s = format (s, "GRE tunnel: id %d\n", dev_instance);
720   return s;
721 }
722
723 static int
724 gre_tunnel_desc (u32 sw_if_index, ip46_address_t *src, ip46_address_t *dst,
725                  u8 *is_l2)
726 {
727   gre_main_t *gm = &gre_main;
728   gre_tunnel_t *t;
729   u32 ti;
730
731   ti = gm->tunnel_index_by_sw_if_index[sw_if_index];
732
733   if (~0 == ti)
734     /* not one of ours */
735     return -1;
736
737   t = pool_elt_at_index (gm->tunnels, ti);
738
739   *src = t->tunnel_src;
740   *dst = t->tunnel_dst.fp_addr;
741   *is_l2 = t->type == GRE_TUNNEL_TYPE_TEB;
742
743   return (0);
744 }
745
746 /* *INDENT-OFF* */
747 VNET_DEVICE_CLASS (gre_device_class) = {
748   .name = "GRE tunnel device",
749   .format_device_name = format_gre_tunnel_name,
750   .format_device = format_gre_device,
751   .format_tx_trace = format_gre_tx_trace,
752   .admin_up_down_function = gre_interface_admin_up_down,
753   .ip_tun_desc = gre_tunnel_desc,
754 #ifdef SOON
755   .clear counter = 0;
756 #endif
757 }
758 ;
759
760 VNET_HW_INTERFACE_CLASS (gre_hw_interface_class) = {
761   .name = "GRE",
762   .format_header = format_gre_header_with_length,
763   .unformat_header = unformat_gre_header,
764   .build_rewrite = gre_build_rewrite,
765   .update_adjacency = gre_update_adj,
766   .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
767 };
768
769 VNET_HW_INTERFACE_CLASS (mgre_hw_interface_class) = {
770   .name = "mGRE",
771   .format_header = format_gre_header_with_length,
772   .unformat_header = unformat_gre_header,
773   .build_rewrite = gre_build_rewrite,
774   .update_adjacency = mgre_update_adj,
775   .flags = VNET_HW_INTERFACE_CLASS_FLAG_NBMA,
776 };
777 /* *INDENT-ON* */
778 #endif /* CLIB_MARCH_VARIANT */
779
780 static void
781 add_protocol (gre_main_t *gm, gre_protocol_t protocol, char *protocol_name)
782 {
783   gre_protocol_info_t *pi;
784   u32 i;
785
786   vec_add2 (gm->protocol_infos, pi, 1);
787   i = pi - gm->protocol_infos;
788
789   pi->name = protocol_name;
790   pi->protocol = protocol;
791   pi->next_index = pi->node_index = ~0;
792
793   hash_set (gm->protocol_info_by_protocol, protocol, i);
794   hash_set_mem (gm->protocol_info_by_name, pi->name, i);
795 }
796
797 static clib_error_t *
798 gre_init (vlib_main_t *vm)
799 {
800   gre_main_t *gm = &gre_main;
801   clib_error_t *error;
802   ip_main_t *im = &ip_main;
803   ip_protocol_info_t *pi;
804
805   clib_memset (gm, 0, sizeof (gm[0]));
806   gm->vlib_main = vm;
807   gm->vnet_main = vnet_get_main ();
808
809   if ((error = vlib_call_init_function (vm, ip_main_init)))
810     return error;
811
812   if ((error = vlib_call_init_function (vm, ip4_lookup_init)))
813     return error;
814
815   if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
816     return error;
817
818   /* Set up the ip packet generator */
819   pi = ip_get_protocol_info (im, IP_PROTOCOL_GRE);
820   pi->format_header = format_gre_header;
821   pi->unformat_pg_edit = unformat_pg_gre_header;
822
823   gm->protocol_info_by_name = hash_create_string (0, sizeof (uword));
824   gm->protocol_info_by_protocol = hash_create (0, sizeof (uword));
825   gm->tunnel_by_key4 =
826     hash_create_mem (0, sizeof (gre_tunnel_key4_t), sizeof (uword));
827   gm->tunnel_by_key6 =
828     hash_create_mem (0, sizeof (gre_tunnel_key6_t), sizeof (uword));
829   gm->seq_num_by_key =
830     hash_create_mem (0, sizeof (gre_sn_key_t), sizeof (uword));
831
832 #define _(n, s) add_protocol (gm, GRE_PROTOCOL_##s, #s);
833   foreach_gre_protocol
834 #undef _
835     return vlib_call_init_function (vm, gre_input_init);
836 }
837
838 VLIB_INIT_FUNCTION (gre_init);
839
840 /*
841  * fd.io coding-style-patch-verification: ON
842  *
843  * Local Variables:
844  * eval: (c-set-style "gnu")
845  * End:
846  */