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