c11 safe string handling support
[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 = vm->thread_index;
81   u32 len;
82   vnet_interface_main_t *im = &gm->vnet_main->interface_main;
83
84   if (!is_ipv6)
85     clib_memset (&cached_tunnel_key.gtk_v4, 0xff,
86                  sizeof (cached_tunnel_key.gtk_v4));
87   else
88     clib_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).next_index;
168           next1 = vec_elt (gm->next_by_protocol, i1).next_index;
169           u8 ttype0 = vec_elt (gm->next_by_protocol, i0).tunnel_type;
170           u8 ttype1 = vec_elt (gm->next_by_protocol, i1).tunnel_type;
171
172           b0->error =
173             node->errors[i0 ==
174                          SPARSE_VEC_INVALID_INDEX ? GRE_ERROR_UNKNOWN_PROTOCOL
175                          : GRE_ERROR_NONE];
176           b1->error =
177             node->errors[i1 ==
178                          SPARSE_VEC_INVALID_INDEX ? GRE_ERROR_UNKNOWN_PROTOCOL
179                          : GRE_ERROR_NONE];
180
181           version0 = clib_net_to_host_u16 (h0->flags_and_version);
182           verr0 = version0 & GRE_VERSION_MASK;
183           version1 = clib_net_to_host_u16 (h1->flags_and_version);
184           verr1 = version1 & GRE_VERSION_MASK;
185
186           b0->error = verr0 ? node->errors[GRE_ERROR_UNSUPPORTED_VERSION]
187             : b0->error;
188           next0 = verr0 ? GRE_INPUT_NEXT_DROP : next0;
189           b1->error = verr1 ? node->errors[GRE_ERROR_UNSUPPORTED_VERSION]
190             : b1->error;
191           next1 = verr1 ? GRE_INPUT_NEXT_DROP : next1;
192
193
194           /* RPF check for ip4/ip6 input */
195           if (PREDICT_TRUE (next0 > GRE_INPUT_NEXT_DROP))
196             {
197               if (is_ipv6)
198                 {
199                   gre_mk_key6 (&ip6_0->dst_address,
200                                &ip6_0->src_address,
201                                vnet_buffer (b0)->ip.fib_index,
202                                ttype0, 0, &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,
209                                ttype0, 0, &key0.gtk_v4);
210                 }
211
212               if ((!is_ipv6 && !gre_match_key4 (&cached_tunnel_key.gtk_v4,
213                                                 &key0.gtk_v4)) ||
214                   (is_ipv6 && !gre_match_key6 (&cached_tunnel_key.gtk_v6,
215                                                &key0.gtk_v6)))
216                 {
217                   gre_tunnel_t *t;
218                   uword *p;
219
220                   if (!is_ipv6)
221                     {
222                       p = hash_get_mem (gm->tunnel_by_key4, &key0.gtk_v4);
223                     }
224                   else
225                     {
226                       p = hash_get_mem (gm->tunnel_by_key6, &key0.gtk_v6);
227                     }
228                   if (!p)
229                     {
230                       next0 = GRE_INPUT_NEXT_DROP;
231                       b0->error = node->errors[GRE_ERROR_NO_SUCH_TUNNEL];
232                       goto drop0;
233                     }
234                   t = pool_elt_at_index (gm->tunnels, p[0]);
235                   tunnel_sw_if_index = t->sw_if_index;
236
237                   cached_tunnel_sw_if_index = tunnel_sw_if_index;
238                   if (!is_ipv6)
239                     {
240                       cached_tunnel_key.gtk_v4 = key0.gtk_v4;
241                     }
242                   else
243                     {
244                       cached_tunnel_key.gtk_v6 = key0.gtk_v6;
245                     }
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_DROP))
269             {
270               if (is_ipv6)
271                 {
272                   gre_mk_key6 (&ip6_1->dst_address,
273                                &ip6_1->src_address,
274                                vnet_buffer (b1)->ip.fib_index,
275                                ttype1, 0, &key1.gtk_v6);
276                 }
277               else
278                 {
279                   gre_mk_key4 (ip4_1->dst_address,
280                                ip4_1->src_address,
281                                vnet_buffer (b1)->ip.fib_index,
282                                ttype1, 0, &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).next_index;
427           u8 ttype0 = vec_elt (gm->next_by_protocol, i0).tunnel_type;
428
429           b0->error =
430             node->errors[i0 == SPARSE_VEC_INVALID_INDEX
431                          ? GRE_ERROR_UNKNOWN_PROTOCOL : GRE_ERROR_NONE];
432
433           version0 = clib_net_to_host_u16 (h0->flags_and_version);
434           verr0 = version0 & GRE_VERSION_MASK;
435           b0->error = verr0 ? node->errors[GRE_ERROR_UNSUPPORTED_VERSION]
436             : b0->error;
437           next0 = verr0 ? GRE_INPUT_NEXT_DROP : next0;
438
439
440           /* For IP payload we need to find source interface
441              so we can increase counters and help forward node to
442              pick right FIB */
443           /* RPF check for ip4/ip6 input */
444           if (PREDICT_TRUE (next0 > GRE_INPUT_NEXT_DROP))
445             {
446               if (is_ipv6)
447                 {
448                   gre_mk_key6 (&ip6_0->dst_address,
449                                &ip6_0->src_address,
450                                vnet_buffer (b0)->ip.fib_index,
451                                ttype0, 0, &key0.gtk_v6);
452                 }
453               else
454                 {
455                   gre_mk_key4 (ip4_0->dst_address,
456                                ip4_0->src_address,
457                                vnet_buffer (b0)->ip.fib_index,
458                                ttype0, 0, &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
596 VLIB_REGISTER_NODE (gre6_input_node) = {
597   .function = gre6_input,
598   .name = "gre6-input",
599   /* Takes a vector of packets. */
600   .vector_size = sizeof (u32),
601
602   .runtime_data_bytes = sizeof (gre_input_runtime_t),
603
604   .n_errors = GRE_N_ERROR,
605   .error_strings = gre_error_strings,
606
607   .n_next_nodes = GRE_INPUT_N_NEXT,
608   .next_nodes = {
609 #define _(s,n) [GRE_INPUT_NEXT_##s] = n,
610     foreach_gre_input_next
611 #undef _
612   },
613
614   .format_buffer = format_gre_header_with_length,
615   .format_trace = format_gre_rx_trace,
616   .unformat_buffer = unformat_gre_header,
617 };
618
619 VLIB_NODE_FUNCTION_MULTIARCH (gre4_input_node, gre4_input)
620 VLIB_NODE_FUNCTION_MULTIARCH (gre6_input_node, gre6_input)
621 /* *INDENT-ON* */
622
623 void
624 gre_register_input_protocol (vlib_main_t * vm,
625                              gre_protocol_t protocol, u32 node_index,
626                              gre_tunnel_type_t tunnel_type)
627 {
628   gre_main_t *em = &gre_main;
629   gre_protocol_info_t *pi;
630   next_info_t *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->tunnel_type = tunnel_type;
642   pi->next_index = vlib_node_add_next (vm, gre4_input_node.index, node_index);
643   i = vlib_node_add_next (vm, gre6_input_node.index, node_index);
644   ASSERT (i == pi->next_index);
645
646   /* Setup gre protocol -> next index sparse vector mapping. */
647   n = sparse_vec_validate (em->next_by_protocol,
648                            clib_host_to_net_u16 (protocol));
649   n->next_index = pi->next_index;
650   n->tunnel_type = tunnel_type;
651 }
652
653 static void
654 gre_setup_node (vlib_main_t * vm, u32 node_index)
655 {
656   vlib_node_t *n = vlib_get_node (vm, node_index);
657   pg_node_t *pn = pg_get_node (node_index);
658
659   n->format_buffer = format_gre_header_with_length;
660   n->unformat_buffer = unformat_gre_header;
661   pn->unformat_edit = unformat_pg_gre_header;
662 }
663
664 static clib_error_t *
665 gre_input_init (vlib_main_t * vm)
666 {
667   gre_main_t *gm = &gre_main;
668   vlib_node_t *ethernet_input, *ip4_input, *ip6_input, *mpls_unicast_input;
669
670   {
671     clib_error_t *error;
672     error = vlib_call_init_function (vm, gre_init);
673     if (error)
674       clib_error_report (error);
675   }
676
677   gre_setup_node (vm, gre4_input_node.index);
678   gre_setup_node (vm, gre6_input_node.index);
679
680   gm->next_by_protocol = sparse_vec_new
681     ( /* elt bytes */ sizeof (gm->next_by_protocol[0]),
682      /* bits in index */ BITS (((gre_header_t *) 0)->protocol));
683
684   /* These could be moved to the supported protocol input node defn's */
685   ethernet_input = vlib_get_node_by_name (vm, (u8 *) "ethernet-input");
686   ASSERT (ethernet_input);
687   ip4_input = vlib_get_node_by_name (vm, (u8 *) "ip4-input");
688   ASSERT (ip4_input);
689   ip6_input = vlib_get_node_by_name (vm, (u8 *) "ip6-input");
690   ASSERT (ip6_input);
691   mpls_unicast_input = vlib_get_node_by_name (vm, (u8 *) "mpls-input");
692   ASSERT (mpls_unicast_input);
693
694   gre_register_input_protocol (vm, GRE_PROTOCOL_teb,
695                                ethernet_input->index, GRE_TUNNEL_TYPE_TEB);
696
697   gre_register_input_protocol (vm, GRE_PROTOCOL_ip4,
698                                ip4_input->index, GRE_TUNNEL_TYPE_L3);
699
700   gre_register_input_protocol (vm, GRE_PROTOCOL_ip6,
701                                ip6_input->index, GRE_TUNNEL_TYPE_L3);
702
703   gre_register_input_protocol (vm, GRE_PROTOCOL_mpls_unicast,
704                                mpls_unicast_input->index, GRE_TUNNEL_TYPE_L3);
705
706   ip4_register_protocol (IP_PROTOCOL_GRE, gre4_input_node.index);
707   ip6_register_protocol (IP_PROTOCOL_GRE, gre6_input_node.index);
708
709   return 0;
710 }
711
712 VLIB_INIT_FUNCTION (gre_input_init);
713
714 /*
715  * fd.io coding-style-patch-verification: ON
716  *
717  * Local Variables:
718  * eval: (c-set-style "gnu")
719  * End:
720  */