Fix issue with gre protocol registration when running multithreaded
[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   ip4_address_t src;
43   ip4_address_t dst;
44 } gre_rx_trace_t;
45
46 u8 * format_gre_rx_trace (u8 * s, va_list * args)
47 {
48   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
49   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
50   gre_rx_trace_t * t = va_arg (*args, gre_rx_trace_t *);
51     
52   s = format (s, "GRE: tunnel %d len %d src %U dst %U",
53               t->tunnel_id, clib_net_to_host_u16(t->length),
54               format_ip4_address, &t->src.as_u8,
55               format_ip4_address, &t->dst.as_u8);
56   return s;
57 }
58
59 static uword
60 gre_input (vlib_main_t * vm,
61            vlib_node_runtime_t * node,
62            vlib_frame_t * from_frame)
63 {
64   gre_main_t * gm = &gre_main;
65   __attribute__((unused)) u32 n_left_from, next_index, * from, * to_next;
66   u64 cached_tunnel_key = (u64) ~0;
67   u32 cached_tunnel_sw_if_index = 0, tunnel_sw_if_index = 0;
68
69   u32 cpu_index = os_get_cpu_number();
70   u32 len;
71   vnet_interface_main_t *im = &gm->vnet_main->interface_main;
72
73   from = vlib_frame_vector_args (from_frame);
74   n_left_from = from_frame->n_vectors;
75
76   next_index = node->cached_next_index;
77
78   while (n_left_from > 0)
79     {
80       u32 n_left_to_next;
81
82       vlib_get_next_frame (vm, node, next_index,
83                            to_next, n_left_to_next);
84
85       while (n_left_from >= 4 && n_left_to_next >= 2)
86         {
87           u32 bi0, bi1;
88           vlib_buffer_t * b0, * b1;
89           gre_header_t * h0, * h1;
90           u16 version0, version1;
91           int verr0, verr1;
92           u32 i0, i1, next0, next1, protocol0, protocol1;
93           ip4_header_t *ip0, *ip1;
94
95           /* Prefetch next iteration. */
96           {
97             vlib_buffer_t * p2, * p3;
98
99             p2 = vlib_get_buffer (vm, from[2]);
100             p3 = vlib_get_buffer (vm, from[3]);
101
102             vlib_prefetch_buffer_header (p2, LOAD);
103             vlib_prefetch_buffer_header (p3, LOAD);
104
105             CLIB_PREFETCH (p2->data, sizeof (h0[0]), LOAD);
106             CLIB_PREFETCH (p3->data, sizeof (h1[0]), LOAD);
107           }
108
109           bi0 = from[0];
110           bi1 = from[1];
111           to_next[0] = bi0;
112           to_next[1] = bi1;
113           from += 2;
114           to_next += 2;
115           n_left_to_next -= 2;
116           n_left_from -= 2;
117
118           b0 = vlib_get_buffer (vm, bi0);
119           b1 = vlib_get_buffer (vm, bi1);
120
121           /* ip4_local hands us the ip header, not the gre header */
122           ip0 = vlib_buffer_get_current (b0);
123           ip1 = vlib_buffer_get_current (b1);
124
125           /* Save src + dst ip4 address, e.g. for mpls-o-gre */
126           vnet_buffer(b0)->gre.src = ip0->src_address.as_u32;
127           vnet_buffer(b0)->gre.dst = ip0->dst_address.as_u32;
128           vnet_buffer(b1)->gre.src = ip1->src_address.as_u32;
129           vnet_buffer(b1)->gre.dst = ip1->dst_address.as_u32;
130
131           vlib_buffer_advance (b0, sizeof (*ip0));
132           vlib_buffer_advance (b1, sizeof (*ip1));
133
134           h0 = vlib_buffer_get_current (b0);
135           h1 = vlib_buffer_get_current (b1);
136
137           /* Index sparse array with network byte order. */
138           protocol0 = h0->protocol;
139           protocol1 = h1->protocol;
140           sparse_vec_index2 (gm->next_by_protocol, protocol0, protocol1,
141                              &i0, &i1);
142           next0 = vec_elt(gm->next_by_protocol, i0);
143           next1 = vec_elt(gm->next_by_protocol, i1);
144
145           b0->error = node->errors[i0 == SPARSE_VEC_INVALID_INDEX ? GRE_ERROR_UNKNOWN_PROTOCOL : GRE_ERROR_NONE];
146           b1->error = node->errors[i1 == SPARSE_VEC_INVALID_INDEX ? GRE_ERROR_UNKNOWN_PROTOCOL : GRE_ERROR_NONE];
147           
148           version0 = clib_net_to_host_u16 (h0->flags_and_version);
149           verr0 =  version0 & GRE_VERSION_MASK;
150           version1 = clib_net_to_host_u16 (h1->flags_and_version);
151           verr1 =  version1 & GRE_VERSION_MASK;
152
153           b0->error = verr0 ? node->errors[GRE_ERROR_UNSUPPORTED_VERSION]
154               : b0->error;
155           next0 = verr0 ? GRE_INPUT_NEXT_DROP : next0;
156           b1->error = verr1 ? node->errors[GRE_ERROR_UNSUPPORTED_VERSION]
157               : b1->error;
158           next1 = verr1 ? GRE_INPUT_NEXT_DROP : next1;
159
160
161           /* RPF check for ip4/ip6 input */
162           if (PREDICT_TRUE(next0 == GRE_INPUT_NEXT_IP4_INPUT
163                            || next0 == GRE_INPUT_NEXT_IP6_INPUT
164                            || next0 == GRE_INPUT_NEXT_ETHERNET_INPUT
165                            || next0 == GRE_INPUT_NEXT_MPLS_INPUT))
166             {
167               u64 key = ((u64)(vnet_buffer(b0)->gre.dst) << 32) |
168                          (u64)(vnet_buffer(b0)->gre.src);
169
170               if (cached_tunnel_key != key)
171                 {
172                   vnet_hw_interface_t * hi;
173                   gre_tunnel_t * t;
174                   uword * p;
175
176                   p = hash_get (gm->tunnel_by_key, key);
177                   if (!p)
178                     {
179                       next0 = GRE_INPUT_NEXT_DROP;
180                       b0->error = node->errors[GRE_ERROR_NO_SUCH_TUNNEL];
181                       goto drop0;
182                     }
183                   t = pool_elt_at_index (gm->tunnels, p[0]);
184                   hi = vnet_get_hw_interface (gm->vnet_main,
185                             t->hw_if_index);
186                   tunnel_sw_if_index = hi->sw_if_index;
187
188                   cached_tunnel_sw_if_index = tunnel_sw_if_index;
189                 }
190               else
191                 {
192                   tunnel_sw_if_index = cached_tunnel_sw_if_index;
193                 }
194             }
195           else
196             {
197                 next0 = GRE_INPUT_NEXT_DROP;
198                 goto drop0;
199             }
200           len = vlib_buffer_length_in_chain (vm, b0);
201           vlib_increment_combined_counter (im->combined_sw_if_counters
202                                            + VNET_INTERFACE_COUNTER_RX,
203                                            cpu_index,
204                                            tunnel_sw_if_index,
205                                            1 /* packets */,
206                                            len /* bytes */);
207
208           vnet_buffer(b0)->sw_if_index[VLIB_RX] = tunnel_sw_if_index;
209
210 drop0:
211           if (PREDICT_TRUE(next1 == GRE_INPUT_NEXT_IP4_INPUT
212                            || next1 == GRE_INPUT_NEXT_IP6_INPUT
213                            || next1 == GRE_INPUT_NEXT_ETHERNET_INPUT
214                            || next1 == GRE_INPUT_NEXT_MPLS_INPUT))
215             {
216               u64 key = ((u64)(vnet_buffer(b1)->gre.dst) << 32) |
217                          (u64)(vnet_buffer(b1)->gre.src);
218
219               if (cached_tunnel_key != key)
220                 {
221                   vnet_hw_interface_t * hi;
222                   gre_tunnel_t * t;
223                   uword * p;
224
225                   p = hash_get (gm->tunnel_by_key, key);
226                   if (!p)
227                     {
228                       next1 = GRE_INPUT_NEXT_DROP;
229                       b1->error = node->errors[GRE_ERROR_NO_SUCH_TUNNEL];
230                       goto drop1;
231                     }
232                   t = pool_elt_at_index (gm->tunnels, p[0]);
233                   hi = vnet_get_hw_interface (gm->vnet_main,
234                             t->hw_if_index);
235                   tunnel_sw_if_index = hi->sw_if_index;
236
237                   cached_tunnel_sw_if_index = tunnel_sw_if_index;
238                 }
239               else
240                 {
241                   tunnel_sw_if_index = cached_tunnel_sw_if_index;
242                 }
243             }
244           else
245             {
246                 next1 = GRE_INPUT_NEXT_DROP;
247                 goto drop1;
248             }
249           len = vlib_buffer_length_in_chain (vm, b1);
250           vlib_increment_combined_counter (im->combined_sw_if_counters
251                                            + VNET_INTERFACE_COUNTER_RX,
252                                            cpu_index,
253                                            tunnel_sw_if_index,
254                                            1 /* packets */,
255                                            len /* bytes */);
256
257           vnet_buffer(b1)->sw_if_index[VLIB_RX] = tunnel_sw_if_index;
258
259 drop1:
260           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
261             {
262               gre_rx_trace_t *tr = vlib_add_trace (vm, node,
263                                                    b0, sizeof (*tr));
264               tr->tunnel_id = tunnel_sw_if_index;
265               tr->length = ip0->length;
266               tr->src.as_u32 = ip0->src_address.as_u32;
267               tr->dst.as_u32 = ip0->dst_address.as_u32;
268             }
269
270           if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
271             {
272               gre_rx_trace_t *tr = vlib_add_trace (vm, node,
273                                                    b1, sizeof (*tr));
274               tr->tunnel_id = tunnel_sw_if_index;
275               tr->length = ip1->length;
276               tr->src.as_u32 = ip1->src_address.as_u32;
277               tr->dst.as_u32 = ip1->dst_address.as_u32;
278             }
279
280           vlib_buffer_advance (b0, sizeof (*h0));
281           vlib_buffer_advance (b1, sizeof (*h1));
282
283           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
284                                            to_next, n_left_to_next,
285                                            bi0, bi1, next0, next1);
286         }
287     
288       while (n_left_from > 0 && n_left_to_next > 0)
289         {
290           u32 bi0;
291           vlib_buffer_t * b0;
292           gre_header_t * h0;
293           ip4_header_t * ip0;
294           u16 version0;
295           int verr0;
296           u32 i0, next0;
297
298           bi0 = from[0];
299           to_next[0] = bi0;
300           from += 1;
301           to_next += 1;
302           n_left_from -= 1;
303           n_left_to_next -= 1;
304
305           b0 = vlib_get_buffer (vm, bi0);
306           ip0 = vlib_buffer_get_current (b0);
307
308           vnet_buffer(b0)->gre.src = ip0->src_address.as_u32;
309           vnet_buffer(b0)->gre.dst = ip0->dst_address.as_u32;
310
311           vlib_buffer_advance (b0, sizeof (*ip0));
312
313           h0 = vlib_buffer_get_current (b0);
314
315           i0 = sparse_vec_index (gm->next_by_protocol, h0->protocol);
316           next0 = vec_elt(gm->next_by_protocol, i0);
317
318           b0->error = 
319               node->errors[i0 == SPARSE_VEC_INVALID_INDEX 
320                            ? GRE_ERROR_UNKNOWN_PROTOCOL : GRE_ERROR_NONE];
321           
322           version0 = clib_net_to_host_u16 (h0->flags_and_version);
323           verr0 =  version0 & GRE_VERSION_MASK;
324           b0->error = verr0 ? node->errors[GRE_ERROR_UNSUPPORTED_VERSION] 
325               : b0->error;
326           next0 = verr0 ? GRE_INPUT_NEXT_DROP : next0;
327
328
329           /* For IP payload we need to find source interface
330              so we can increase counters and help forward node to
331              pick right FIB */
332           /* RPF check for ip4/ip6 input */
333           if (PREDICT_TRUE(next0 == GRE_INPUT_NEXT_IP4_INPUT
334                            || next0 == GRE_INPUT_NEXT_IP6_INPUT
335                            || next0 == GRE_INPUT_NEXT_ETHERNET_INPUT
336                            || next0 == GRE_INPUT_NEXT_MPLS_INPUT))
337             {
338               u64 key = ((u64)(vnet_buffer(b0)->gre.dst) << 32) |
339                          (u64)(vnet_buffer(b0)->gre.src);
340
341               if (cached_tunnel_key != key)
342                 {
343                   vnet_hw_interface_t * hi;
344                   gre_tunnel_t * t;
345                   uword * p;
346
347                   p = hash_get (gm->tunnel_by_key, key);
348                   if (!p)
349                     {
350                       next0 = GRE_INPUT_NEXT_DROP;
351                       b0->error = node->errors[GRE_ERROR_NO_SUCH_TUNNEL];
352                       goto drop;
353                     }
354                   t = pool_elt_at_index (gm->tunnels, p[0]);
355                   hi = vnet_get_hw_interface (gm->vnet_main,
356                             t->hw_if_index);
357                   tunnel_sw_if_index = hi->sw_if_index;
358
359                   cached_tunnel_sw_if_index = tunnel_sw_if_index;
360                 }
361               else
362                 {
363                   tunnel_sw_if_index = cached_tunnel_sw_if_index;
364                 }
365             }
366           else
367             {
368                 next0 = GRE_INPUT_NEXT_DROP;
369                 goto drop;
370             }
371           len = vlib_buffer_length_in_chain (vm, b0);
372           vlib_increment_combined_counter (im->combined_sw_if_counters
373                                            + VNET_INTERFACE_COUNTER_RX,
374                                            cpu_index,
375                                            tunnel_sw_if_index,
376                                            1 /* packets */,
377                                            len /* bytes */);
378
379           vnet_buffer(b0)->sw_if_index[VLIB_RX] = tunnel_sw_if_index;
380
381 drop:
382           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) 
383             {
384               gre_rx_trace_t *tr = vlib_add_trace (vm, node, 
385                                                    b0, sizeof (*tr));
386               tr->tunnel_id = tunnel_sw_if_index;
387               tr->length = ip0->length;
388               tr->src.as_u32 = ip0->src_address.as_u32;
389               tr->dst.as_u32 = ip0->dst_address.as_u32;
390             }
391
392           vlib_buffer_advance (b0, sizeof (*h0));
393
394           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
395                                            to_next, n_left_to_next,
396                                            bi0, next0);
397         }
398
399       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
400     }
401   vlib_node_increment_counter (vm, gre_input_node.index,
402                                GRE_ERROR_PKTS_DECAP, from_frame->n_vectors);
403   return from_frame->n_vectors;
404 }
405
406 static char * gre_error_strings[] = {
407 #define gre_error(n,s) s,
408 #include "error.def"
409 #undef gre_error
410 };
411
412 VLIB_REGISTER_NODE (gre_input_node) = {
413   .function = gre_input,
414   .name = "gre-input",
415   /* Takes a vector of packets. */
416   .vector_size = sizeof (u32),
417
418   .n_errors = GRE_N_ERROR,
419   .error_strings = gre_error_strings,
420
421   .n_next_nodes = GRE_INPUT_N_NEXT,
422   .next_nodes = {
423 #define _(s,n) [GRE_INPUT_NEXT_##s] = n,
424     foreach_gre_input_next
425 #undef _
426   },
427
428   .format_buffer = format_gre_header_with_length,
429   .format_trace = format_gre_rx_trace,
430   .unformat_buffer = unformat_gre_header,
431 };
432
433 VLIB_NODE_FUNCTION_MULTIARCH (gre_input_node, gre_input)
434
435 void
436 gre_register_input_protocol (vlib_main_t * vm,
437                              gre_protocol_t protocol,
438                              u32 node_index)
439 {
440   gre_main_t * em = &gre_main;
441   gre_protocol_info_t * pi;
442   u16 * n;
443
444   {
445     clib_error_t * error = vlib_call_init_function (vm, gre_input_init);
446     if (error)
447       clib_error_report (error);
448   }
449
450   pi = gre_get_protocol_info (em, protocol);
451   pi->node_index = node_index;
452   pi->next_index = vlib_node_add_next (vm, 
453                                        gre_input_node.index,
454                                        node_index);
455
456   /* Setup gre protocol -> next index sparse vector mapping. */
457   n = sparse_vec_validate (em->next_by_protocol,
458                            clib_host_to_net_u16 (protocol));
459   n[0] = pi->next_index;
460 }
461
462 static void
463 gre_setup_node (vlib_main_t * vm, u32 node_index)
464 {
465   vlib_node_t * n = vlib_get_node (vm, node_index);
466   pg_node_t * pn = pg_get_node (node_index);
467
468   n->format_buffer = format_gre_header_with_length;
469   n->unformat_buffer = unformat_gre_header;
470   pn->unformat_edit = unformat_pg_gre_header;
471 }
472
473 static clib_error_t * gre_input_init (vlib_main_t * vm)
474 {
475   gre_main_t * gm = &gre_main;
476   vlib_node_t *ethernet_input, *ip4_input, *ip6_input, *mpls_unicast_input;
477
478   {
479     clib_error_t * error; 
480     error = vlib_call_init_function (vm, gre_init);
481     if (error)
482       clib_error_report (error);
483   }
484
485   gre_setup_node (vm, gre_input_node.index);
486
487   gm->next_by_protocol = sparse_vec_new
488     (/* elt bytes */ sizeof (gm->next_by_protocol[0]),
489      /* bits in index */ BITS (((gre_header_t *) 0)->protocol));
490
491   /* These could be moved to the supported protocol input node defn's */
492   ethernet_input = vlib_get_node_by_name (vm, (u8 *)"ethernet-input");
493   ASSERT(ethernet_input);
494   ip4_input = vlib_get_node_by_name (vm, (u8 *)"ip4-input");
495   ASSERT(ip4_input);
496   ip6_input = vlib_get_node_by_name (vm, (u8 *)"ip6-input");
497   ASSERT(ip6_input);
498   mpls_unicast_input = vlib_get_node_by_name (vm, (u8 *)"mpls-input");
499   ASSERT(mpls_unicast_input);
500
501   gre_register_input_protocol (vm, GRE_PROTOCOL_teb,
502                                ethernet_input->index);
503
504   gre_register_input_protocol (vm, GRE_PROTOCOL_ip4, 
505                                ip4_input->index);
506
507   gre_register_input_protocol (vm, GRE_PROTOCOL_ip6, 
508                                ip6_input->index);
509
510   gre_register_input_protocol (vm, GRE_PROTOCOL_mpls_unicast,
511                                mpls_unicast_input->index);
512
513   ip4_register_protocol (IP_PROTOCOL_GRE, gre_input_node.index);
514
515   return 0;
516 }
517
518 VLIB_INIT_FUNCTION (gre_input_init);
519