7223b017df76a31ea9ecb1010e60bafb1a3026c3
[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   gre_tunnel_key_t cached_tunnel_key;
77
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_key.gtk_v4, 0xff,
86             sizeof (cached_tunnel_key.gtk_v4));
87   else
88     memset (&cached_tunnel_key.gtk_v6, 0xff,
89             sizeof (cached_tunnel_key.gtk_v6));
90
91   from = vlib_frame_vector_args (from_frame);
92   n_left_from = from_frame->n_vectors;
93
94   next_index = node->cached_next_index;
95
96   while (n_left_from > 0)
97     {
98       u32 n_left_to_next;
99
100       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
101
102       while (n_left_from >= 4 && n_left_to_next >= 2)
103         {
104           u32 bi0, bi1;
105           vlib_buffer_t *b0, *b1;
106           gre_header_t *h0, *h1;
107           u16 version0, version1;
108           int verr0, verr1;
109           u32 i0, i1, next0, next1, protocol0, protocol1;
110           ip4_header_t *ip4_0, *ip4_1;
111           ip6_header_t *ip6_0, *ip6_1;
112           gre_tunnel_key_t key0, key1;
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
146               vlib_buffer_advance (b0, sizeof (*ip4_0));
147               vlib_buffer_advance (b1, sizeof (*ip4_1));
148             }
149           else
150             {
151               /* ip6_local hands us the ip header, not the gre header */
152               ip6_0 = vlib_buffer_get_current (b0);
153               ip6_1 = vlib_buffer_get_current (b1);
154
155               vlib_buffer_advance (b0, sizeof (*ip6_0));
156               vlib_buffer_advance (b1, sizeof (*ip6_1));
157             }
158
159           h0 = vlib_buffer_get_current (b0);
160           h1 = vlib_buffer_get_current (b1);
161
162           /* Index sparse array with network byte order. */
163           protocol0 = h0->protocol;
164           protocol1 = h1->protocol;
165           sparse_vec_index2 (gm->next_by_protocol, protocol0, protocol1,
166                              &i0, &i1);
167           next0 = vec_elt (gm->next_by_protocol, i0);
168           next1 = vec_elt (gm->next_by_protocol, i1);
169
170           b0->error =
171             node->errors[i0 ==
172                          SPARSE_VEC_INVALID_INDEX ? GRE_ERROR_UNKNOWN_PROTOCOL
173                          : GRE_ERROR_NONE];
174           b1->error =
175             node->errors[i1 ==
176                          SPARSE_VEC_INVALID_INDEX ? GRE_ERROR_UNKNOWN_PROTOCOL
177                          : GRE_ERROR_NONE];
178
179           version0 = clib_net_to_host_u16 (h0->flags_and_version);
180           verr0 = version0 & GRE_VERSION_MASK;
181           version1 = clib_net_to_host_u16 (h1->flags_and_version);
182           verr1 = version1 & GRE_VERSION_MASK;
183
184           b0->error = verr0 ? node->errors[GRE_ERROR_UNSUPPORTED_VERSION]
185             : b0->error;
186           next0 = verr0 ? GRE_INPUT_NEXT_DROP : next0;
187           b1->error = verr1 ? node->errors[GRE_ERROR_UNSUPPORTED_VERSION]
188             : b1->error;
189           next1 = verr1 ? GRE_INPUT_NEXT_DROP : next1;
190
191
192           /* RPF check for ip4/ip6 input */
193           if (PREDICT_TRUE (next0 == GRE_INPUT_NEXT_IP4_INPUT
194                             || next0 == GRE_INPUT_NEXT_IP6_INPUT
195                             || next0 == GRE_INPUT_NEXT_ETHERNET_INPUT
196                             || next0 == GRE_INPUT_NEXT_MPLS_INPUT))
197             {
198               if (is_ipv6)
199                 {
200                   gre_mk_key6 (&ip6_0->dst_address,
201                                &ip6_0->src_address,
202                                vnet_buffer (b0)->ip.fib_index, &key0.gtk_v6);
203                 }
204               else
205                 {
206                   gre_mk_key4 (&ip4_0->dst_address,
207                                &ip4_0->src_address,
208                                vnet_buffer (b0)->ip.fib_index, &key0.gtk_v4);
209                 }
210
211               if ((!is_ipv6 && !gre_match_key4 (&cached_tunnel_key.gtk_v4,
212                                                 &key0.gtk_v4)) ||
213                   (is_ipv6 && !gre_match_key6 (&cached_tunnel_key.gtk_v6,
214                                                &key0.gtk_v6)))
215                 {
216                   gre_tunnel_t *t;
217                   uword *p;
218
219                   if (!is_ipv6)
220                     {
221                       p = hash_get_mem (gm->tunnel_by_key4, &key0.gtk_v4);
222                     }
223                   else
224                     {
225                       p = hash_get_mem (gm->tunnel_by_key6, &key0.gtk_v6);
226                     }
227                   if (!p)
228                     {
229                       next0 = GRE_INPUT_NEXT_DROP;
230                       b0->error = node->errors[GRE_ERROR_NO_SUCH_TUNNEL];
231                       goto drop0;
232                     }
233                   t = pool_elt_at_index (gm->tunnels, p[0]);
234                   tunnel_sw_if_index = t->sw_if_index;
235
236                   cached_tunnel_sw_if_index = tunnel_sw_if_index;
237                   if (!is_ipv6)
238                     {
239                       cached_tunnel_key.gtk_v4 = key0.gtk_v4;
240                     }
241                   else
242                     {
243                       cached_tunnel_key.gtk_v6 = key0.gtk_v6;
244                     }
245                 }
246               else
247                 {
248                   tunnel_sw_if_index = cached_tunnel_sw_if_index;
249                 }
250             }
251           else
252             {
253               next0 = GRE_INPUT_NEXT_DROP;
254               goto drop0;
255             }
256           len = vlib_buffer_length_in_chain (vm, b0);
257           vlib_increment_combined_counter (im->combined_sw_if_counters
258                                            + VNET_INTERFACE_COUNTER_RX,
259                                            thread_index,
260                                            tunnel_sw_if_index,
261                                            1 /* packets */ ,
262                                            len /* bytes */ );
263
264           vnet_buffer (b0)->sw_if_index[VLIB_RX] = tunnel_sw_if_index;
265
266         drop0:
267           if (PREDICT_TRUE (next1 == GRE_INPUT_NEXT_IP4_INPUT
268                             || next1 == GRE_INPUT_NEXT_IP6_INPUT
269                             || next1 == GRE_INPUT_NEXT_ETHERNET_INPUT
270                             || next1 == GRE_INPUT_NEXT_MPLS_INPUT))
271             {
272               if (is_ipv6)
273                 {
274                   gre_mk_key6 (&ip6_1->dst_address,
275                                &ip6_1->src_address,
276                                vnet_buffer (b1)->ip.fib_index, &key1.gtk_v6);
277                 }
278               else
279                 {
280                   gre_mk_key4 (&ip4_1->dst_address,
281                                &ip4_1->src_address,
282                                vnet_buffer (b1)->ip.fib_index, &key1.gtk_v4);
283                 }
284
285               if ((!is_ipv6 && !gre_match_key4 (&cached_tunnel_key.gtk_v4,
286                                                 &key1.gtk_v4)) ||
287                   (is_ipv6 && !gre_match_key6 (&cached_tunnel_key.gtk_v6,
288                                                &key1.gtk_v6)))
289                 {
290                   gre_tunnel_t *t;
291                   uword *p;
292
293                   if (!is_ipv6)
294                     {
295                       p = hash_get_mem (gm->tunnel_by_key4, &key1.gtk_v4);
296                     }
297                   else
298                     {
299                       p = hash_get_mem (gm->tunnel_by_key6, &key1.gtk_v6);
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                   tunnel_sw_if_index = t->sw_if_index;
309
310                   cached_tunnel_sw_if_index = tunnel_sw_if_index;
311                   if (!is_ipv6)
312                     {
313                       cached_tunnel_key.gtk_v4 = key1.gtk_v4;
314                     }
315                   else
316                     {
317                       cached_tunnel_key.gtk_v6 = key1.gtk_v6;
318                     }
319                 }
320               else
321                 {
322                   tunnel_sw_if_index = cached_tunnel_sw_if_index;
323                 }
324             }
325           else
326             {
327               next1 = GRE_INPUT_NEXT_DROP;
328               goto drop1;
329             }
330           len = vlib_buffer_length_in_chain (vm, b1);
331           vlib_increment_combined_counter (im->combined_sw_if_counters
332                                            + VNET_INTERFACE_COUNTER_RX,
333                                            thread_index,
334                                            tunnel_sw_if_index,
335                                            1 /* packets */ ,
336                                            len /* bytes */ );
337
338           vnet_buffer (b1)->sw_if_index[VLIB_RX] = tunnel_sw_if_index;
339
340         drop1:
341           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
342             {
343               gre_rx_trace_t *tr = vlib_add_trace (vm, node,
344                                                    b0, sizeof (*tr));
345               tr->tunnel_id = tunnel_sw_if_index;
346               if (!is_ipv6)
347                 {
348                   tr->length = ip4_0->length;
349                   tr->src.ip4.as_u32 = ip4_0->src_address.as_u32;
350                   tr->dst.ip4.as_u32 = ip4_0->dst_address.as_u32;
351                 }
352               else
353                 {
354                   tr->length = ip6_0->payload_length;
355                   tr->src.ip6.as_u64[0] = ip6_0->src_address.as_u64[0];
356                   tr->src.ip6.as_u64[1] = ip6_0->src_address.as_u64[1];
357                   tr->dst.ip6.as_u64[0] = ip6_0->dst_address.as_u64[0];
358                   tr->dst.ip6.as_u64[1] = ip6_0->dst_address.as_u64[1];
359                 }
360             }
361
362           if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
363             {
364               gre_rx_trace_t *tr = vlib_add_trace (vm, node,
365                                                    b1, sizeof (*tr));
366               tr->tunnel_id = tunnel_sw_if_index;
367               if (!is_ipv6)
368                 {
369                   tr->length = ip4_1->length;
370                   tr->src.ip4.as_u32 = ip4_1->src_address.as_u32;
371                   tr->dst.ip4.as_u32 = ip4_1->dst_address.as_u32;
372                 }
373               else
374                 {
375                   tr->length = ip6_1->payload_length;
376                   tr->src.ip6.as_u64[0] = ip6_1->src_address.as_u64[0];
377                   tr->src.ip6.as_u64[1] = ip6_1->src_address.as_u64[1];
378                   tr->dst.ip6.as_u64[0] = ip6_1->dst_address.as_u64[0];
379                   tr->dst.ip6.as_u64[1] = ip6_1->dst_address.as_u64[1];
380                 }
381             }
382
383           vlib_buffer_advance (b0, sizeof (*h0));
384           vlib_buffer_advance (b1, sizeof (*h1));
385
386           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
387                                            to_next, n_left_to_next,
388                                            bi0, bi1, next0, next1);
389         }
390
391       while (n_left_from > 0 && n_left_to_next > 0)
392         {
393           u32 bi0;
394           vlib_buffer_t *b0;
395           gre_header_t *h0;
396           ip4_header_t *ip4_0;
397           ip6_header_t *ip6_0;
398           u16 version0;
399           int verr0;
400           u32 i0, next0;
401           gre_tunnel_key_t key0;
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               vlib_buffer_advance (b0, sizeof (*ip4_0));
417             }
418           else
419             {
420               vlib_buffer_advance (b0, sizeof (*ip6_0));
421             }
422
423           h0 = vlib_buffer_get_current (b0);
424
425           i0 = sparse_vec_index (gm->next_by_protocol, h0->protocol);
426           next0 = vec_elt (gm->next_by_protocol, i0);
427
428           b0->error =
429             node->errors[i0 == SPARSE_VEC_INVALID_INDEX
430                          ? GRE_ERROR_UNKNOWN_PROTOCOL : GRE_ERROR_NONE];
431
432           version0 = clib_net_to_host_u16 (h0->flags_and_version);
433           verr0 = version0 & GRE_VERSION_MASK;
434           b0->error = verr0 ? node->errors[GRE_ERROR_UNSUPPORTED_VERSION]
435             : b0->error;
436           next0 = verr0 ? GRE_INPUT_NEXT_DROP : next0;
437
438
439           /* For IP payload we need to find source interface
440              so we can increase counters and help forward node to
441              pick right FIB */
442           /* RPF check for ip4/ip6 input */
443           if (PREDICT_TRUE (next0 == GRE_INPUT_NEXT_IP4_INPUT
444                             || next0 == GRE_INPUT_NEXT_IP6_INPUT
445                             || next0 == GRE_INPUT_NEXT_ETHERNET_INPUT
446                             || next0 == GRE_INPUT_NEXT_MPLS_INPUT))
447             {
448               if (is_ipv6)
449                 {
450                   gre_mk_key6 (&ip6_0->dst_address,
451                                &ip6_0->src_address,
452                                vnet_buffer (b0)->ip.fib_index, &key0.gtk_v6);
453                 }
454               else
455                 {
456                   gre_mk_key4 (&ip4_0->dst_address,
457                                &ip4_0->src_address,
458                                vnet_buffer (b0)->ip.fib_index, &key0.gtk_v4);
459                 }
460
461               if ((!is_ipv6 && !gre_match_key4 (&cached_tunnel_key.gtk_v4,
462                                                 &key0.gtk_v4)) ||
463                   (is_ipv6 && !gre_match_key6 (&cached_tunnel_key.gtk_v6,
464                                                &key0.gtk_v6)))
465                 {
466                   gre_tunnel_t *t;
467                   uword *p;
468
469                   if (!is_ipv6)
470                     {
471                       p = hash_get_mem (gm->tunnel_by_key4, &key0.gtk_v4);
472                     }
473                   else
474                     {
475                       p = hash_get_mem (gm->tunnel_by_key6, &key0.gtk_v6);
476                     }
477                   if (!p)
478                     {
479                       next0 = GRE_INPUT_NEXT_DROP;
480                       b0->error = node->errors[GRE_ERROR_NO_SUCH_TUNNEL];
481                       goto drop;
482                     }
483                   t = pool_elt_at_index (gm->tunnels, p[0]);
484                   tunnel_sw_if_index = t->sw_if_index;
485
486                   cached_tunnel_sw_if_index = tunnel_sw_if_index;
487                   if (!is_ipv6)
488                     {
489                       cached_tunnel_key.gtk_v4 = key0.gtk_v4;
490                     }
491                   else
492                     {
493                       cached_tunnel_key.gtk_v6 = key0.gtk_v6;
494                     }
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  */