GRE: fix single loop decap and add test
[vpp.git] / src / vnet / gre / node.c
1 /*
2  * node.c: gre packet processing
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 <vlib/vlib.h>
19 #include <vnet/pg/pg.h>
20 #include <vnet/gre/gre.h>
21 #include <vnet/mpls/mpls.h>
22 #include <vppinfra/sparse_vec.h>
23
24 #define foreach_gre_input_next                  \
25 _(PUNT, "error-punt")                           \
26 _(DROP, "error-drop")                           \
27 _(ETHERNET_INPUT, "ethernet-input")             \
28 _(IP4_INPUT, "ip4-input")                       \
29 _(IP6_INPUT, "ip6-input")                       \
30 _(MPLS_INPUT, "mpls-input")
31
32 typedef enum
33 {
34 #define _(s,n) GRE_INPUT_NEXT_##s,
35   foreach_gre_input_next
36 #undef _
37     GRE_INPUT_N_NEXT,
38 } gre_input_next_t;
39
40 typedef struct
41 {
42   u32 tunnel_id;
43   u32 length;
44   ip46_address_t src;
45   ip46_address_t dst;
46   u8 is_ipv6;
47 } gre_rx_trace_t;
48
49 u8 *
50 format_gre_rx_trace (u8 * s, va_list * args)
51 {
52   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
53   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
54   gre_rx_trace_t *t = va_arg (*args, gre_rx_trace_t *);
55
56   s = format (s, "GRE: tunnel %d len %d src %U dst %U",
57               t->tunnel_id, clib_net_to_host_u16 (t->length),
58               format_ip46_address, &t->src, IP46_TYPE_ANY,
59               format_ip46_address, &t->dst, IP46_TYPE_ANY);
60   return s;
61 }
62
63 typedef struct
64 {
65   /* Sparse vector mapping gre protocol in network byte order
66      to next index. */
67   u16 *next_by_protocol;
68 } gre_input_runtime_t;
69
70 always_inline uword
71 gre_input (vlib_main_t * vm,
72            vlib_node_runtime_t * node, vlib_frame_t * from_frame, u8 is_ipv6)
73 {
74   gre_main_t *gm = &gre_main;
75   __attribute__ ((unused)) u32 n_left_from, next_index, *from, *to_next;
76   u64 cached_tunnel_key4;
77   u64 cached_tunnel_key6[4];
78   u32 cached_tunnel_sw_if_index = 0, tunnel_sw_if_index = 0;
79
80   u32 thread_index = vlib_get_thread_index ();
81   u32 len;
82   vnet_interface_main_t *im = &gm->vnet_main->interface_main;
83
84   if (!is_ipv6)
85     memset (&cached_tunnel_key4, 0xff, sizeof (cached_tunnel_key4));
86   else
87     memset (&cached_tunnel_key6, 0xff, sizeof (cached_tunnel_key6));
88
89   from = vlib_frame_vector_args (from_frame);
90   n_left_from = from_frame->n_vectors;
91
92   next_index = node->cached_next_index;
93
94   while (n_left_from > 0)
95     {
96       u32 n_left_to_next;
97
98       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
99
100       while (n_left_from >= 4 && n_left_to_next >= 2)
101         {
102           u32 bi0, bi1;
103           vlib_buffer_t *b0, *b1;
104           gre_header_t *h0, *h1;
105           u16 version0, version1;
106           int verr0, verr1;
107           u32 i0, i1, next0, next1, protocol0, protocol1;
108           ip4_header_t *ip4_0, *ip4_1;
109           ip6_header_t *ip6_0, *ip6_1;
110           u32 ip4_tun_src0, ip4_tun_dst0;
111           u32 ip4_tun_src1, ip4_tun_dst1;
112           u64 ip6_tun_src0[2], ip6_tun_dst0[2];
113           u64 ip6_tun_src1[2], ip6_tun_dst1[2];
114
115           /* Prefetch next iteration. */
116           {
117             vlib_buffer_t *p2, *p3;
118
119             p2 = vlib_get_buffer (vm, from[2]);
120             p3 = vlib_get_buffer (vm, from[3]);
121
122             vlib_prefetch_buffer_header (p2, LOAD);
123             vlib_prefetch_buffer_header (p3, LOAD);
124
125             CLIB_PREFETCH (p2->data, sizeof (h0[0]), LOAD);
126             CLIB_PREFETCH (p3->data, sizeof (h1[0]), LOAD);
127           }
128
129           bi0 = from[0];
130           bi1 = from[1];
131           to_next[0] = bi0;
132           to_next[1] = bi1;
133           from += 2;
134           to_next += 2;
135           n_left_to_next -= 2;
136           n_left_from -= 2;
137
138           b0 = vlib_get_buffer (vm, bi0);
139           b1 = vlib_get_buffer (vm, bi1);
140
141           if (!is_ipv6)
142             {
143               /* ip4_local hands us the ip header, not the gre header */
144               ip4_0 = vlib_buffer_get_current (b0);
145               ip4_1 = vlib_buffer_get_current (b1);
146               /* Save src + dst ip4 address, e.g. for mpls-o-gre */
147               ip4_tun_src0 = ip4_0->src_address.as_u32;
148               ip4_tun_dst0 = ip4_0->dst_address.as_u32;
149               ip4_tun_src1 = ip4_1->src_address.as_u32;
150               ip4_tun_dst1 = ip4_1->dst_address.as_u32;
151
152               vlib_buffer_advance (b0, sizeof (*ip4_0));
153               vlib_buffer_advance (b1, sizeof (*ip4_1));
154             }
155           else
156             {
157               /* ip6_local hands us the ip header, not the gre header */
158               ip6_0 = vlib_buffer_get_current (b0);
159               ip6_1 = vlib_buffer_get_current (b1);
160               /* Save src + dst ip6 address, e.g. for mpls-o-gre */
161               ip6_tun_src0[0] = ip6_0->src_address.as_u64[0];
162               ip6_tun_src0[1] = ip6_0->src_address.as_u64[1];
163               ip6_tun_dst0[0] = ip6_0->dst_address.as_u64[0];
164               ip6_tun_dst0[1] = ip6_0->dst_address.as_u64[1];
165               ip6_tun_src1[0] = ip6_1->src_address.as_u64[0];
166               ip6_tun_src1[1] = ip6_1->src_address.as_u64[1];
167               ip6_tun_dst1[0] = ip6_1->dst_address.as_u64[0];
168               ip6_tun_dst1[1] = ip6_1->dst_address.as_u64[1];
169
170               vlib_buffer_advance (b0, sizeof (*ip6_0));
171               vlib_buffer_advance (b1, sizeof (*ip6_1));
172             }
173
174           h0 = vlib_buffer_get_current (b0);
175           h1 = vlib_buffer_get_current (b1);
176
177           /* Index sparse array with network byte order. */
178           protocol0 = h0->protocol;
179           protocol1 = h1->protocol;
180           sparse_vec_index2 (gm->next_by_protocol, protocol0, protocol1,
181                              &i0, &i1);
182           next0 = vec_elt (gm->next_by_protocol, i0);
183           next1 = vec_elt (gm->next_by_protocol, i1);
184
185           b0->error =
186             node->errors[i0 ==
187                          SPARSE_VEC_INVALID_INDEX ? GRE_ERROR_UNKNOWN_PROTOCOL
188                          : GRE_ERROR_NONE];
189           b1->error =
190             node->errors[i1 ==
191                          SPARSE_VEC_INVALID_INDEX ? GRE_ERROR_UNKNOWN_PROTOCOL
192                          : GRE_ERROR_NONE];
193
194           version0 = clib_net_to_host_u16 (h0->flags_and_version);
195           verr0 = version0 & GRE_VERSION_MASK;
196           version1 = clib_net_to_host_u16 (h1->flags_and_version);
197           verr1 = version1 & GRE_VERSION_MASK;
198
199           b0->error = verr0 ? node->errors[GRE_ERROR_UNSUPPORTED_VERSION]
200             : b0->error;
201           next0 = verr0 ? GRE_INPUT_NEXT_DROP : next0;
202           b1->error = verr1 ? node->errors[GRE_ERROR_UNSUPPORTED_VERSION]
203             : b1->error;
204           next1 = verr1 ? GRE_INPUT_NEXT_DROP : next1;
205
206
207           /* RPF check for ip4/ip6 input */
208           if (PREDICT_TRUE (next0 == GRE_INPUT_NEXT_IP4_INPUT
209                             || next0 == GRE_INPUT_NEXT_IP6_INPUT
210                             || next0 == GRE_INPUT_NEXT_ETHERNET_INPUT
211                             || next0 == GRE_INPUT_NEXT_MPLS_INPUT))
212             {
213
214               u64 key4, key6[4];
215               if (!is_ipv6)
216                 {
217                   key4 = ((u64) (ip4_tun_dst0) << 32) | (u64) (ip4_tun_src0);
218                 }
219               else
220                 {
221                   key6[0] = ip6_tun_dst0[0];
222                   key6[1] = ip6_tun_dst0[1];
223                   key6[2] = ip6_tun_src0[0];
224                   key6[3] = ip6_tun_src0[1];
225                 }
226
227               if ((!is_ipv6 && cached_tunnel_key4 != key4) ||
228                   (is_ipv6 && cached_tunnel_key6[0] != key6[0] &&
229                    cached_tunnel_key6[1] != key6[1] &&
230                    cached_tunnel_key6[2] != key6[2] &&
231                    cached_tunnel_key6[3] != key6[3]))
232                 {
233                   vnet_hw_interface_t *hi;
234                   gre_tunnel_t *t;
235                   uword *p;
236
237                   if (!is_ipv6)
238                     p = hash_get (gm->tunnel_by_key4, key4);
239                   else
240                     p = hash_get_mem (gm->tunnel_by_key6, key6);
241                   if (!p)
242                     {
243                       next0 = GRE_INPUT_NEXT_DROP;
244                       b0->error = node->errors[GRE_ERROR_NO_SUCH_TUNNEL];
245                       goto drop0;
246                     }
247                   t = pool_elt_at_index (gm->tunnels, p[0]);
248                   hi = vnet_get_hw_interface (gm->vnet_main, t->hw_if_index);
249                   tunnel_sw_if_index = hi->sw_if_index;
250
251                   cached_tunnel_sw_if_index = tunnel_sw_if_index;
252                 }
253               else
254                 {
255                   tunnel_sw_if_index = cached_tunnel_sw_if_index;
256                 }
257             }
258           else
259             {
260               next0 = GRE_INPUT_NEXT_DROP;
261               goto drop0;
262             }
263           len = vlib_buffer_length_in_chain (vm, b0);
264           vlib_increment_combined_counter (im->combined_sw_if_counters
265                                            + VNET_INTERFACE_COUNTER_RX,
266                                            thread_index,
267                                            tunnel_sw_if_index,
268                                            1 /* packets */ ,
269                                            len /* bytes */ );
270
271           vnet_buffer (b0)->sw_if_index[VLIB_RX] = tunnel_sw_if_index;
272
273         drop0:
274           if (PREDICT_TRUE (next1 == GRE_INPUT_NEXT_IP4_INPUT
275                             || next1 == GRE_INPUT_NEXT_IP6_INPUT
276                             || next1 == GRE_INPUT_NEXT_ETHERNET_INPUT
277                             || next1 == GRE_INPUT_NEXT_MPLS_INPUT))
278             {
279               u64 key4, key6[4];
280               if (!is_ipv6)
281                 {
282                   key4 = ((u64) (ip4_tun_dst1) << 32) | (u64) (ip4_tun_src1);
283                 }
284               else
285                 {
286                   key6[0] = ip6_tun_dst1[0];
287                   key6[1] = ip6_tun_dst1[1];
288                   key6[2] = ip6_tun_src1[0];
289                   key6[3] = ip6_tun_src1[1];
290                 }
291
292               if ((!is_ipv6 && cached_tunnel_key4 != key4) ||
293                   (is_ipv6 && cached_tunnel_key6[0] != key6[0] &&
294                    cached_tunnel_key6[1] != key6[1] &&
295                    cached_tunnel_key6[2] != key6[2] &&
296                    cached_tunnel_key6[3] != key6[3]))
297                 {
298                   vnet_hw_interface_t *hi;
299                   gre_tunnel_t *t;
300                   uword *p;
301
302                   if (!is_ipv6)
303                     p = hash_get (gm->tunnel_by_key4, key4);
304                   else
305                     p = hash_get_mem (gm->tunnel_by_key6, key6);
306
307                   if (!p)
308                     {
309                       next1 = GRE_INPUT_NEXT_DROP;
310                       b1->error = node->errors[GRE_ERROR_NO_SUCH_TUNNEL];
311                       goto drop1;
312                     }
313                   t = pool_elt_at_index (gm->tunnels, p[0]);
314                   hi = vnet_get_hw_interface (gm->vnet_main, t->hw_if_index);
315                   tunnel_sw_if_index = hi->sw_if_index;
316
317                   cached_tunnel_sw_if_index = tunnel_sw_if_index;
318                 }
319               else
320                 {
321                   tunnel_sw_if_index = cached_tunnel_sw_if_index;
322                 }
323             }
324           else
325             {
326               next1 = GRE_INPUT_NEXT_DROP;
327               goto drop1;
328             }
329           len = vlib_buffer_length_in_chain (vm, b1);
330           vlib_increment_combined_counter (im->combined_sw_if_counters
331                                            + VNET_INTERFACE_COUNTER_RX,
332                                            thread_index,
333                                            tunnel_sw_if_index,
334                                            1 /* packets */ ,
335                                            len /* bytes */ );
336
337           vnet_buffer (b1)->sw_if_index[VLIB_RX] = tunnel_sw_if_index;
338
339         drop1:
340           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
341             {
342               gre_rx_trace_t *tr = vlib_add_trace (vm, node,
343                                                    b0, sizeof (*tr));
344               tr->tunnel_id = tunnel_sw_if_index;
345               if (!is_ipv6)
346                 {
347                   tr->length = ip4_0->length;
348                   tr->src.ip4.as_u32 = ip4_0->src_address.as_u32;
349                   tr->dst.ip4.as_u32 = ip4_0->dst_address.as_u32;
350                 }
351               else
352                 {
353                   tr->length = ip6_0->payload_length;
354                   tr->src.ip6.as_u64[0] = ip6_0->src_address.as_u64[0];
355                   tr->src.ip6.as_u64[1] = ip6_0->src_address.as_u64[1];
356                   tr->dst.ip6.as_u64[0] = ip6_0->dst_address.as_u64[0];
357                   tr->dst.ip6.as_u64[1] = ip6_0->dst_address.as_u64[1];
358                 }
359             }
360
361           if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
362             {
363               gre_rx_trace_t *tr = vlib_add_trace (vm, node,
364                                                    b1, sizeof (*tr));
365               tr->tunnel_id = tunnel_sw_if_index;
366               if (!is_ipv6)
367                 {
368                   tr->length = ip4_1->length;
369                   tr->src.ip4.as_u32 = ip4_1->src_address.as_u32;
370                   tr->dst.ip4.as_u32 = ip4_1->dst_address.as_u32;
371                 }
372               else
373                 {
374                   tr->length = ip6_1->payload_length;
375                   tr->src.ip6.as_u64[0] = ip6_1->src_address.as_u64[0];
376                   tr->src.ip6.as_u64[1] = ip6_1->src_address.as_u64[1];
377                   tr->dst.ip6.as_u64[0] = ip6_1->dst_address.as_u64[0];
378                   tr->dst.ip6.as_u64[1] = ip6_1->dst_address.as_u64[1];
379                 }
380             }
381
382           vlib_buffer_advance (b0, sizeof (*h0));
383           vlib_buffer_advance (b1, sizeof (*h1));
384
385           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
386                                            to_next, n_left_to_next,
387                                            bi0, bi1, next0, next1);
388         }
389
390       while (n_left_from > 0 && n_left_to_next > 0)
391         {
392           u32 bi0;
393           vlib_buffer_t *b0;
394           gre_header_t *h0;
395           ip4_header_t *ip4_0;
396           ip6_header_t *ip6_0;
397           u16 version0;
398           int verr0;
399           u32 i0, next0;
400           u32 ip4_tun_src0, ip4_tun_dst0;
401           u64 ip6_tun_src0[2], ip6_tun_dst0[2];
402
403           bi0 = from[0];
404           to_next[0] = bi0;
405           from += 1;
406           to_next += 1;
407           n_left_from -= 1;
408           n_left_to_next -= 1;
409
410           b0 = vlib_get_buffer (vm, bi0);
411           ip4_0 = vlib_buffer_get_current (b0);
412           ip6_0 = (void *) ip4_0;
413
414           if (!is_ipv6)
415             {
416               ip4_tun_src0 = ip4_0->src_address.as_u32;
417               ip4_tun_dst0 = ip4_0->dst_address.as_u32;
418
419               vlib_buffer_advance (b0, sizeof (*ip4_0));
420             }
421           else
422             {
423               ip6_tun_src0[0] = ip6_0->src_address.as_u64[0];
424               ip6_tun_src0[1] = ip6_0->src_address.as_u64[1];
425               ip6_tun_dst0[0] = ip6_0->dst_address.as_u64[0];
426               ip6_tun_dst0[1] = ip6_0->dst_address.as_u64[1];
427
428               vlib_buffer_advance (b0, sizeof (*ip6_0));
429             }
430
431           h0 = vlib_buffer_get_current (b0);
432
433           i0 = sparse_vec_index (gm->next_by_protocol, h0->protocol);
434           next0 = vec_elt (gm->next_by_protocol, i0);
435
436           b0->error =
437             node->errors[i0 == SPARSE_VEC_INVALID_INDEX
438                          ? GRE_ERROR_UNKNOWN_PROTOCOL : GRE_ERROR_NONE];
439
440           version0 = clib_net_to_host_u16 (h0->flags_and_version);
441           verr0 = version0 & GRE_VERSION_MASK;
442           b0->error = verr0 ? node->errors[GRE_ERROR_UNSUPPORTED_VERSION]
443             : b0->error;
444           next0 = verr0 ? GRE_INPUT_NEXT_DROP : next0;
445
446
447           /* For IP payload we need to find source interface
448              so we can increase counters and help forward node to
449              pick right FIB */
450           /* RPF check for ip4/ip6 input */
451           if (PREDICT_TRUE (next0 == GRE_INPUT_NEXT_IP4_INPUT
452                             || next0 == GRE_INPUT_NEXT_IP6_INPUT
453                             || next0 == GRE_INPUT_NEXT_ETHERNET_INPUT
454                             || next0 == GRE_INPUT_NEXT_MPLS_INPUT))
455             {
456               u64 key4, key6[4];
457               if (!is_ipv6)
458                 {
459                   key4 = ((u64) (ip4_tun_dst0) << 32) | (u64) (ip4_tun_src0);
460                 }
461               else
462                 {
463                   key6[0] = ip6_tun_dst0[0];
464                   key6[1] = ip6_tun_dst0[1];
465                   key6[2] = ip6_tun_src0[0];
466                   key6[3] = ip6_tun_src0[1];
467                 }
468
469               if ((!is_ipv6 && cached_tunnel_key4 != key4) ||
470                   (is_ipv6 && cached_tunnel_key6[0] != key6[0] &&
471                    cached_tunnel_key6[1] != key6[1] &&
472                    cached_tunnel_key6[2] != key6[2] &&
473                    cached_tunnel_key6[3] != key6[3]))
474                 {
475                   vnet_hw_interface_t *hi;
476                   gre_tunnel_t *t;
477                   uword *p;
478
479                   if (!is_ipv6)
480                     p = hash_get (gm->tunnel_by_key4, key4);
481                   else
482                     p = hash_get_mem (gm->tunnel_by_key6, key6);
483
484                   if (!p)
485                     {
486                       next0 = GRE_INPUT_NEXT_DROP;
487                       b0->error = node->errors[GRE_ERROR_NO_SUCH_TUNNEL];
488                       goto drop;
489                     }
490                   t = pool_elt_at_index (gm->tunnels, p[0]);
491                   hi = vnet_get_hw_interface (gm->vnet_main, t->hw_if_index);
492                   tunnel_sw_if_index = hi->sw_if_index;
493
494                   cached_tunnel_sw_if_index = tunnel_sw_if_index;
495                 }
496               else
497                 {
498                   tunnel_sw_if_index = cached_tunnel_sw_if_index;
499                 }
500             }
501           else
502             {
503               next0 = GRE_INPUT_NEXT_DROP;
504               goto drop;
505             }
506           len = vlib_buffer_length_in_chain (vm, b0);
507           vlib_increment_combined_counter (im->combined_sw_if_counters
508                                            + VNET_INTERFACE_COUNTER_RX,
509                                            thread_index,
510                                            tunnel_sw_if_index,
511                                            1 /* packets */ ,
512                                            len /* bytes */ );
513
514           vnet_buffer (b0)->sw_if_index[VLIB_RX] = tunnel_sw_if_index;
515
516         drop:
517           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
518             {
519               gre_rx_trace_t *tr = vlib_add_trace (vm, node,
520                                                    b0, sizeof (*tr));
521               tr->tunnel_id = tunnel_sw_if_index;
522               if (!is_ipv6)
523                 {
524                   tr->length = ip4_0->length;
525                   tr->src.ip4.as_u32 = ip4_0->src_address.as_u32;
526                   tr->dst.ip4.as_u32 = ip4_0->dst_address.as_u32;
527                 }
528               else
529                 {
530                   tr->length = ip6_0->payload_length;
531                   tr->src.ip6.as_u64[0] = ip6_0->src_address.as_u64[0];
532                   tr->src.ip6.as_u64[1] = ip6_0->src_address.as_u64[1];
533                   tr->dst.ip6.as_u64[0] = ip6_0->dst_address.as_u64[0];
534                   tr->dst.ip6.as_u64[1] = ip6_0->dst_address.as_u64[1];
535                 }
536             }
537
538           vlib_buffer_advance (b0, sizeof (*h0));
539
540           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
541                                            to_next, n_left_to_next,
542                                            bi0, next0);
543         }
544
545       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
546     }
547   vlib_node_increment_counter (vm,
548                                !is_ipv6 ? gre4_input_node.index :
549                                gre6_input_node.index, GRE_ERROR_PKTS_DECAP,
550                                from_frame->n_vectors);
551   return from_frame->n_vectors;
552 }
553
554 static uword
555 gre4_input (vlib_main_t * vm,
556             vlib_node_runtime_t * node, vlib_frame_t * from_frame)
557 {
558   return gre_input (vm, node, from_frame, /* is_ip6 */ 0);
559 }
560
561 static uword
562 gre6_input (vlib_main_t * vm,
563             vlib_node_runtime_t * node, vlib_frame_t * from_frame)
564 {
565   return gre_input (vm, node, from_frame, /* is_ip6 */ 1);
566 }
567
568 static char *gre_error_strings[] = {
569 #define gre_error(n,s) s,
570 #include "error.def"
571 #undef gre_error
572 };
573
574 /* *INDENT-OFF* */
575 VLIB_REGISTER_NODE (gre4_input_node) = {
576   .function = gre4_input,
577   .name = "gre4-input",
578   /* Takes a vector of packets. */
579   .vector_size = sizeof (u32),
580
581   .n_errors = GRE_N_ERROR,
582   .error_strings = gre_error_strings,
583
584   .n_next_nodes = GRE_INPUT_N_NEXT,
585   .next_nodes = {
586 #define _(s,n) [GRE_INPUT_NEXT_##s] = n,
587     foreach_gre_input_next
588 #undef _
589   },
590
591   .format_buffer = format_gre_header_with_length,
592   .format_trace = format_gre_rx_trace,
593   .unformat_buffer = unformat_gre_header,
594 };
595 /* *INDENT-ON* */
596
597 /* *INDENT-OFF* */
598 VLIB_REGISTER_NODE (gre6_input_node) = {
599   .function = gre6_input,
600   .name = "gre6-input",
601   /* Takes a vector of packets. */
602   .vector_size = sizeof (u32),
603
604   .runtime_data_bytes = sizeof (gre_input_runtime_t),
605
606   .n_errors = GRE_N_ERROR,
607   .error_strings = gre_error_strings,
608
609   .n_next_nodes = GRE_INPUT_N_NEXT,
610   .next_nodes = {
611 #define _(s,n) [GRE_INPUT_NEXT_##s] = n,
612     foreach_gre_input_next
613 #undef _
614   },
615
616   .format_buffer = format_gre_header_with_length,
617   .format_trace = format_gre_rx_trace,
618   .unformat_buffer = unformat_gre_header,
619 };
620 /* *INDENT-ON* */
621
622 VLIB_NODE_FUNCTION_MULTIARCH (gre4_input_node, gre4_input)
623 VLIB_NODE_FUNCTION_MULTIARCH (gre6_input_node, gre6_input)
624      void
625        gre_register_input_protocol (vlib_main_t * vm,
626                                     gre_protocol_t protocol, u32 node_index)
627 {
628   gre_main_t *em = &gre_main;
629   gre_protocol_info_t *pi;
630   u16 *n;
631   u32 i;
632
633   {
634     clib_error_t *error = vlib_call_init_function (vm, gre_input_init);
635     if (error)
636       clib_error_report (error);
637   }
638
639   pi = gre_get_protocol_info (em, protocol);
640   pi->node_index = node_index;
641   pi->next_index = vlib_node_add_next (vm, gre4_input_node.index, node_index);
642   i = vlib_node_add_next (vm, gre6_input_node.index, node_index);
643   ASSERT (i == pi->next_index);
644
645   /* Setup gre protocol -> next index sparse vector mapping. */
646   n = sparse_vec_validate (em->next_by_protocol,
647                            clib_host_to_net_u16 (protocol));
648   n[0] = pi->next_index;
649 }
650
651 static void
652 gre_setup_node (vlib_main_t * vm, u32 node_index)
653 {
654   vlib_node_t *n = vlib_get_node (vm, node_index);
655   pg_node_t *pn = pg_get_node (node_index);
656
657   n->format_buffer = format_gre_header_with_length;
658   n->unformat_buffer = unformat_gre_header;
659   pn->unformat_edit = unformat_pg_gre_header;
660 }
661
662 static clib_error_t *
663 gre_input_init (vlib_main_t * vm)
664 {
665   gre_main_t *gm = &gre_main;
666   vlib_node_t *ethernet_input, *ip4_input, *ip6_input, *mpls_unicast_input;
667
668   {
669     clib_error_t *error;
670     error = vlib_call_init_function (vm, gre_init);
671     if (error)
672       clib_error_report (error);
673   }
674
675   gre_setup_node (vm, gre4_input_node.index);
676   gre_setup_node (vm, gre6_input_node.index);
677
678   gm->next_by_protocol = sparse_vec_new
679     ( /* elt bytes */ sizeof (gm->next_by_protocol[0]),
680      /* bits in index */ BITS (((gre_header_t *) 0)->protocol));
681
682   /* These could be moved to the supported protocol input node defn's */
683   ethernet_input = vlib_get_node_by_name (vm, (u8 *) "ethernet-input");
684   ASSERT (ethernet_input);
685   ip4_input = vlib_get_node_by_name (vm, (u8 *) "ip4-input");
686   ASSERT (ip4_input);
687   ip6_input = vlib_get_node_by_name (vm, (u8 *) "ip6-input");
688   ASSERT (ip6_input);
689   mpls_unicast_input = vlib_get_node_by_name (vm, (u8 *) "mpls-input");
690   ASSERT (mpls_unicast_input);
691
692   gre_register_input_protocol (vm, GRE_PROTOCOL_teb, ethernet_input->index);
693
694   gre_register_input_protocol (vm, GRE_PROTOCOL_ip4, ip4_input->index);
695
696   gre_register_input_protocol (vm, GRE_PROTOCOL_ip6, ip6_input->index);
697
698   gre_register_input_protocol (vm, GRE_PROTOCOL_mpls_unicast,
699                                mpls_unicast_input->index);
700
701   ip4_register_protocol (IP_PROTOCOL_GRE, gre4_input_node.index);
702   ip6_register_protocol (IP_PROTOCOL_GRE, gre6_input_node.index);
703
704   return 0;
705 }
706
707 VLIB_INIT_FUNCTION (gre_input_init);
708
709 /*
710  * fd.io coding-style-patch-verification: ON
711  *
712  * Local Variables:
713  * eval: (c-set-style "gnu")
714  * End:
715  */